From b31ffa74f56e36a6dffea75d526ed1cdadbbe5ea Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Thu, 17 Sep 2026 00:29:56 +0200 Subject: [PATCH] 0.1.0-1-alpha.2-fix.3 --- Android/game-reflex-poc/build.gradle | 4 +- Android/game-snake-poc/build.gradle | 4 +- Cargo.toml | 4 +- crates/apps/game-reflex-poc-tauri/Cargo.toml | 3 +- .../frontend/ts/bridge.ts | 6 +- .../game-reflex-poc-tauri/frontend/ts/game.ts | 5 +- .../frontend/ts/logging.ts | 120 +++++++++++++----- .../game-reflex-poc-tauri/frontend/ts/main.ts | 23 +++- .../apps/game-reflex-poc-tauri/package.json | 2 +- crates/apps/game-reflex-poc-tauri/src/lib.rs | 4 +- .../apps/game-reflex-poc-tauri/src/runtime.rs | 13 +- .../apps/game-reflex-poc-tauri/src/tauri.rs | 79 +++++++++++- .../game-reflex-poc-tauri/tauri.conf.json | 2 +- .../apps/game-reflex-poc-wasm/src/runtime.rs | 8 +- deltas/0.1.0/1-alpha.2.fix.3.md | 98 ++++++++++++++ docs/development/008-WASM_TAURI_POC.md | 26 +++- docs/rules/RULES_PROJECT.md | 5 +- 17 files changed, 349 insertions(+), 57 deletions(-) create mode 100644 deltas/0.1.0/1-alpha.2.fix.3.md diff --git a/Android/game-reflex-poc/build.gradle b/Android/game-reflex-poc/build.gradle index 071e7e8..860e6d6 100644 --- a/Android/game-reflex-poc/build.gradle +++ b/Android/game-reflex-poc/build.gradle @@ -1,5 +1,5 @@ // file: Android/game-reflex-poc/build.gradle -// version: 13 +// version: 14 plugins { id 'com.android.application' @@ -18,7 +18,7 @@ android { minSdk 21 targetSdk 36 versionCode 1 - versionName '0.1.0-1-alpha.2.fix.2' + versionName '0.1.0-1-alpha.2.fix.3' } compileOptions { diff --git a/Android/game-snake-poc/build.gradle b/Android/game-snake-poc/build.gradle index 8f2c86b..ff5aca5 100644 --- a/Android/game-snake-poc/build.gradle +++ b/Android/game-snake-poc/build.gradle @@ -1,5 +1,5 @@ // file: Android/game-snake-poc/build.gradle -// version: 13 +// version: 14 plugins { id 'com.android.application' @@ -18,7 +18,7 @@ android { minSdk 21 targetSdk 36 versionCode 1 - versionName '0.1.0-1-alpha.2.fix.2' + versionName '0.1.0-1-alpha.2.fix.3' } compileOptions { diff --git a/Cargo.toml b/Cargo.toml index 32fe687..a29010a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ # file: Cargo.toml -# version: 30 +# version: 31 [workspace] resolver = "3" @@ -19,7 +19,7 @@ members = [ ] [workspace.package] -version = "0.1.0-1-alpha.2.fix.2" +version = "0.1.0-1-alpha.2.fix.3" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/games" diff --git a/crates/apps/game-reflex-poc-tauri/Cargo.toml b/crates/apps/game-reflex-poc-tauri/Cargo.toml index 78c4ad8..9ebe1e3 100644 --- a/crates/apps/game-reflex-poc-tauri/Cargo.toml +++ b/crates/apps/game-reflex-poc-tauri/Cargo.toml @@ -1,5 +1,5 @@ # file: crates/apps/game-reflex-poc-tauri/Cargo.toml -# version: 3 +# version: 4 [package] name = "game-reflex-poc-tauri" @@ -23,6 +23,7 @@ path = "src/main.rs" tauri-build.workspace = true [dependencies] +game-logging-lib = { path = "../../common/game-logging-lib" } engine-v1-platform-api = { path = "../../engines/engine-v1-platform-api" } tauri.workspace = true tauri-plugin-tracing.workspace = true diff --git a/crates/apps/game-reflex-poc-tauri/frontend/ts/bridge.ts b/crates/apps/game-reflex-poc-tauri/frontend/ts/bridge.ts index db4ddc3..fecab02 100644 --- a/crates/apps/game-reflex-poc-tauri/frontend/ts/bridge.ts +++ b/crates/apps/game-reflex-poc-tauri/frontend/ts/bridge.ts @@ -1,5 +1,5 @@ // file: crates/apps/game-reflex-poc-tauri/frontend/ts/bridge.ts -// version: 1 +// version: 2 import { invoke } from "@tauri-apps/api/core"; @@ -10,3 +10,7 @@ export async function getRuntimeLabel(): Promise { export async function notifyFrontendReady(): Promise { await invoke("frontend_ready"); } + +export async function closeMainWindow(): Promise { + await invoke("close_main_window"); +} diff --git a/crates/apps/game-reflex-poc-tauri/frontend/ts/game.ts b/crates/apps/game-reflex-poc-tauri/frontend/ts/game.ts index da999d4..d7eec0f 100644 --- a/crates/apps/game-reflex-poc-tauri/frontend/ts/game.ts +++ b/crates/apps/game-reflex-poc-tauri/frontend/ts/game.ts @@ -1,5 +1,5 @@ // file: crates/apps/game-reflex-poc-tauri/frontend/ts/game.ts -// version: 1 +// version: 2 import init, { ReflexWasmGame } from "../wasm/game_reflex_poc_wasm.js"; import { tracingDebug, tracingTrace } from "./logging"; @@ -37,7 +37,7 @@ function render(game: ReflexWasmGame, canvas: HTMLCanvasElement, context: Canvas score.value = `Score : ${game.score()}`; } -export async function startGame(canvas: HTMLCanvasElement, score: HTMLOutputElement): Promise { +export async function startGame(canvas: HTMLCanvasElement, score: HTMLOutputElement): Promise { await init(); await tracingDebug("Reflex WASM module initialized"); const context = canvas.getContext("2d"); @@ -64,4 +64,5 @@ export async function startGame(canvas: HTMLCanvasElement, score: HTMLOutputElem } render(game, canvas, context, score); window.requestAnimationFrame(frame); + return game; } diff --git a/crates/apps/game-reflex-poc-tauri/frontend/ts/logging.ts b/crates/apps/game-reflex-poc-tauri/frontend/ts/logging.ts index 14ffc95..10d59f6 100644 --- a/crates/apps/game-reflex-poc-tauri/frontend/ts/logging.ts +++ b/crates/apps/game-reflex-poc-tauri/frontend/ts/logging.ts @@ -1,38 +1,98 @@ // file: crates/apps/game-reflex-poc-tauri/frontend/ts/logging.ts -// version: 1 +// version: 2 -import { attachConsole, debug, error, info, trace, warn } from "@fltsci/tauri-plugin-tracing"; +import { attachConsole } from "@fltsci/tauri-plugin-tracing"; +import { invoke } from "@tauri-apps/api/core"; -let detachRustConsole: (() => void) | null = null; +export type FrontendLogLevel = "trace" | "debug" | "info" | "warn" | "error"; +export type FrontendLogTarget = "frontend" | "main"; -export async function initializeTracing(): Promise { - detachRustConsole = await attachConsole(); - await info("Reflex Tauri frontend tracing initialized", "games::tauri::reflex::frontend"); -} +type ConsoleMethod = (...items: unknown[]) => void; -export async function tracingTrace(message: string): Promise { - await trace(message, "games::tauri::reflex::frontend"); -} +const originalConsole = { + trace: console.trace.bind(console), + debug: console.debug.bind(console), + info: console.info.bind(console), + warn: console.warn.bind(console), + error: console.error.bind(console), +}; -export async function tracingDebug(message: string): Promise { - await debug(message, "games::tauri::reflex::frontend"); -} - -export async function tracingInfo(message: string): Promise { - await info(message, "games::tauri::reflex::frontend"); -} - -export async function tracingWarn(message: string): Promise { - await warn(message, "games::tauri::reflex::frontend"); -} - -export async function tracingError(message: string): Promise { - await error(message, "games::tauri::reflex::frontend"); -} - -export function detachTracingConsole(): void { - if (detachRustConsole !== null) { - detachRustConsole(); - detachRustConsole = null; +function stringifyItem(item: unknown): string { + if (item instanceof Error) { + return item.stack ?? item.message; + } + if (typeof item === "string") { + return item; + } + try { + const serialized = JSON.stringify(item); + return serialized ?? String(item); + } catch { + return String(item); } } + +function formatMessage(items: unknown[]): string { + return items.map(item => stringifyItem(item)).join(" "); +} + +async function sendFrontendLog(level: FrontendLogLevel, targetId: FrontendLogTarget, message: string): Promise { + await invoke("emit_frontend_log", { + payload: { + level, + targetId, + message, + }, + }); +} + +function originalConsoleFor(level: FrontendLogLevel): ConsoleMethod { + return level === "trace" + ? originalConsole.trace + : level === "debug" + ? originalConsole.debug + : level === "info" + ? originalConsole.info + : level === "warn" + ? originalConsole.warn + : originalConsole.error; +} + +export async function initializeTracing(): Promise { + await attachConsole(); + await emitFrontendLog("info", "main", "Reflex Tauri frontend tracing initialized"); +} + +export async function emitFrontendLog(level: FrontendLogLevel, targetId: FrontendLogTarget, ...items: unknown[]): Promise { + const message = formatMessage(items); + originalConsoleFor(level)(message); + await sendFrontendLog(level, targetId, message); +} + +function emitDetached(level: FrontendLogLevel, targetId: FrontendLogTarget, items: unknown[]): void { + const message = formatMessage(items); + originalConsoleFor(level)(message); + void sendFrontendLog(level, targetId, message).catch(caughtError => { + originalConsole.error("Reflex frontend logging bridge failed", caughtError); + }); +} + +export function tracingTrace(...items: unknown[]): void { + emitDetached("trace", "frontend", items); +} + +export function tracingDebug(...items: unknown[]): void { + emitDetached("debug", "frontend", items); +} + +export function tracingInfo(...items: unknown[]): void { + emitDetached("info", "frontend", items); +} + +export function tracingWarn(...items: unknown[]): void { + emitDetached("warn", "frontend", items); +} + +export function tracingError(...items: unknown[]): void { + emitDetached("error", "frontend", items); +} diff --git a/crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts b/crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts index 1b9e37d..ea091bb 100644 --- a/crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts +++ b/crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts @@ -1,7 +1,7 @@ // file: crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts -// version: 1 +// version: 2 -import { getRuntimeLabel, notifyFrontendReady } from "./bridge"; +import { closeMainWindow, getRuntimeLabel, notifyFrontendReady } from "./bridge"; import { startGame } from "./game"; import { initializeTracing, tracingError, tracingInfo } from "./logging"; @@ -14,12 +14,23 @@ async function main(): Promise { throw new Error("Reflex Tauri frontend DOM is incomplete"); } runtime.value = await getRuntimeLabel(); - await startGame(canvas, score); + const game = await startGame(canvas, score); + window.addEventListener("keydown", event => { + if (event.key !== "Escape" || event.repeat) { + return; + } + event.preventDefault(); + const shouldExit = game.quit_requested_escape(); + tracingInfo(`quit requested source=escape decision=${shouldExit ? "exit" : "continue"}`); + if (shouldExit) { + void closeMainWindow().catch(caughtError => tracingError("Tauri close command failed", caughtError)); + } + }); await notifyFrontendReady(); - await tracingInfo("Reflex Tauri frontend started"); + tracingInfo("Reflex Tauri frontend started"); } -void main().catch(async caughtError => { +void main().catch(caughtError => { const message = caughtError instanceof Error ? caughtError.stack ?? caughtError.message : String(caughtError); - await tracingError(`Reflex Tauri frontend startup failed: ${message}`); + tracingError(`Reflex Tauri frontend startup failed: ${message}`); }); diff --git a/crates/apps/game-reflex-poc-tauri/package.json b/crates/apps/game-reflex-poc-tauri/package.json index f588f97..1d1e315 100644 --- a/crates/apps/game-reflex-poc-tauri/package.json +++ b/crates/apps/game-reflex-poc-tauri/package.json @@ -1,7 +1,7 @@ { "name": "game-reflex-poc-tauri", "private": true, - "version": "0.1.0-1-alpha.2.fix.2", + "version": "0.1.0-1-alpha.2.fix.3", "type": "module", "scripts": { "dev": "vite", diff --git a/crates/apps/game-reflex-poc-tauri/src/lib.rs b/crates/apps/game-reflex-poc-tauri/src/lib.rs index 25bb0fd..1a86de5 100644 --- a/crates/apps/game-reflex-poc-tauri/src/lib.rs +++ b/crates/apps/game-reflex-poc-tauri/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/apps/game-reflex-poc-tauri/src/lib.rs -// version: 2 +// version: 3 //! Tauri desktop application facade for the Reflex WebAssembly POC. @@ -15,5 +15,7 @@ pub use self::tauri::run; /// Records that the Vite/TypeScript frontend reached its ready state. pub(crate) use self::runtime::record_frontend_ready; +/// Records one accepted native window close request. +pub(crate) use self::runtime::record_window_close; /// Returns the runtime label exposed by the Tauri bridge. pub(crate) use self::runtime::runtime_label; diff --git a/crates/apps/game-reflex-poc-tauri/src/runtime.rs b/crates/apps/game-reflex-poc-tauri/src/runtime.rs index a06cf46..fe8f3f7 100644 --- a/crates/apps/game-reflex-poc-tauri/src/runtime.rs +++ b/crates/apps/game-reflex-poc-tauri/src/runtime.rs @@ -1,5 +1,5 @@ // file: crates/apps/game-reflex-poc-tauri/src/runtime.rs -// version: 1 +// version: 2 /// Stable label for the current Tauri/WASM runtime combination. pub(crate) fn runtime_label() -> &'static str { @@ -16,3 +16,14 @@ pub(crate) fn record_frontend_ready() { ); return; } + +/// Records one accepted native window close request. +pub(crate) fn record_window_close(source: &str) { + tracing::info!( + target: "games::tauri::reflex", + action = "window_close", + source = source, + "Reflex Tauri window close accepted" + ); + return; +} diff --git a/crates/apps/game-reflex-poc-tauri/src/tauri.rs b/crates/apps/game-reflex-poc-tauri/src/tauri.rs index fa67764..5091e98 100644 --- a/crates/apps/game-reflex-poc-tauri/src/tauri.rs +++ b/crates/apps/game-reflex-poc-tauri/src/tauri.rs @@ -1,5 +1,15 @@ // file: crates/apps/game-reflex-poc-tauri/src/tauri.rs -// version: 1 +// version: 2 + +//! Tauri runtime assembly and Web/Rust commands for the Reflex POC. + +#[derive(serde::Deserialize)] +#[serde(rename_all = "camelCase")] +struct FrontendLogPayload { + level: String, + target_id: String, + message: String, +} #[tauri::command] fn get_runtime_label() -> String { @@ -12,6 +22,47 @@ fn frontend_ready() { return; } +#[tauri::command] +fn emit_frontend_log(payload: FrontendLogPayload) -> std::result::Result<(), String> { + let target_id = payload.target_id.trim(); + if target_id != "frontend" && target_id != "main" { + return std::result::Result::Err("unsupported frontend log target".to_string()); + } + let message = payload.message.as_str(); + return match payload.level.trim().to_ascii_lowercase().as_str() { + "trace" => { + tracing::trace!(target: "games::tauri::reflex::frontend", action = "frontend_log", target_id = target_id, "{message}"); + std::result::Result::Ok(()) + }, + "debug" => { + tracing::debug!(target: "games::tauri::reflex::frontend", action = "frontend_log", target_id = target_id, "{message}"); + std::result::Result::Ok(()) + }, + "info" => { + tracing::info!(target: "games::tauri::reflex::frontend", action = "frontend_log", target_id = target_id, "{message}"); + std::result::Result::Ok(()) + }, + "warn" => { + tracing::warn!(target: "games::tauri::reflex::frontend", action = "frontend_log", target_id = target_id, "{message}"); + std::result::Result::Ok(()) + }, + "error" => { + tracing::error!(target: "games::tauri::reflex::frontend", action = "frontend_log", target_id = target_id, "{message}"); + std::result::Result::Ok(()) + }, + _ => std::result::Result::Err("unsupported frontend log level".to_string()), + }; +} + +#[tauri::command] +fn close_main_window(window: tauri::WebviewWindow) -> std::result::Result<(), String> { + crate::record_window_close("game_quit_decision"); + return match window.close() { + std::result::Result::Ok(()) => std::result::Result::Ok(()), + std::result::Result::Err(error) => std::result::Result::Err(error.to_string()), + }; +} + fn configure_plugins(builder: tauri::Builder) -> tauri::Builder { let tracing_plugin = tauri_plugin_tracing::Builder::new().build::(); return builder.plugin(tracing_plugin); @@ -19,11 +70,16 @@ fn configure_plugins(builder: tauri::Builder) -> tauri::Builder) -> tauri::Builder { - return builder.invoke_handler(tauri::generate_handler![get_runtime_label, frontend_ready]); + return builder.invoke_handler(tauri::generate_handler![get_runtime_label, frontend_ready, emit_frontend_log, close_main_window]); } /// Runs the Reflex Tauri desktop application. pub fn run() -> std::result::Result<(), String> { + let logging_guard = game_logging_lib::init_console_tracing(); + let _logging_guard = match logging_guard { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()), + }; tracing::info!( target: "games::tauri::reflex", action = "runtime_start", @@ -33,7 +89,22 @@ pub fn run() -> std::result::Result<(), String> { let builder = configure_plugins(builder); let builder = configure_commands(builder); return match builder.run(tauri::generate_context!()) { - std::result::Result::Ok(()) => std::result::Result::Ok(()), - std::result::Result::Err(error) => std::result::Result::Err(error.to_string()), + std::result::Result::Ok(()) => { + tracing::info!( + target: "games::tauri::reflex", + action = "runtime_stop", + "Reflex Tauri runtime stopped" + ); + std::result::Result::Ok(()) + }, + std::result::Result::Err(error) => { + tracing::error!( + target: "games::tauri::reflex", + action = "runtime_error", + error = error.to_string(), + "Reflex Tauri runtime failed" + ); + std::result::Result::Err(error.to_string()) + }, }; } diff --git a/crates/apps/game-reflex-poc-tauri/tauri.conf.json b/crates/apps/game-reflex-poc-tauri/tauri.conf.json index 686e829..3d7d0f9 100644 --- a/crates/apps/game-reflex-poc-tauri/tauri.conf.json +++ b/crates/apps/game-reflex-poc-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Reflex POC Tauri", - "version": "0.1.0-1-alpha.2.fix.2", + "version": "0.1.0-1-alpha.2.fix.3", "identifier": "com.sasedev.games.reflex.tauri", "build": { "beforeDevCommand": { diff --git a/crates/apps/game-reflex-poc-wasm/src/runtime.rs b/crates/apps/game-reflex-poc-wasm/src/runtime.rs index ce909fd..1621a2f 100644 --- a/crates/apps/game-reflex-poc-wasm/src/runtime.rs +++ b/crates/apps/game-reflex-poc-wasm/src/runtime.rs @@ -1,5 +1,5 @@ // file: crates/apps/game-reflex-poc-wasm/src/runtime.rs -// version: 1 +// version: 2 /// WebAssembly-owned Reflex game state consumed by the Tauri WebView. #[wasm_bindgen::prelude::wasm_bindgen] @@ -33,6 +33,12 @@ impl ReflexWasmGame { return; } + /// Routes the Escape key through the shared game's quit policy. + pub fn quit_requested_escape(&mut self) -> bool { + let request = engine_v1_common::QuitRequest::new(engine_v1_common::QuitSource::Escape); + return engine_v1_common::EngineGame::quit_requested(&mut self.state, request) == engine_v1_common::QuitDecision::Exit; + } + /// Returns the current gameplay score. pub fn score(&self) -> u32 { return self.state.score().min(u32::MAX as u64) as u32; diff --git a/deltas/0.1.0/1-alpha.2.fix.3.md b/deltas/0.1.0/1-alpha.2.fix.3.md new file mode 100644 index 0000000..b429be6 --- /dev/null +++ b/deltas/0.1.0/1-alpha.2.fix.3.md @@ -0,0 +1,98 @@ + + + +# Delta 0.1.0-1-alpha.2.fix.3 + +## Base + +Base déclarée : `0.1.0-1-alpha.2.fix.2`, gates techniques propres et smoke Tauri fonctionnel. + +Deux défauts fonctionnels restent ouverts : + +- aucun événement `tracing` n'est visible dans le terminal ; +- `Escape` ne produit aucune action dans la variante Tauri. + +## Logging + +La variante Tauri dépend désormais de `game-logging-lib` et initialise : + +```text +game_logging_lib::init_console_tracing() +``` + +avant le premier événement `tracing`. + +Le frontend utilise son wrapper TypeScript : + +```text +module TS +-> logging.ts +-> invoke("emit_frontend_log") +-> tauri.rs +-> tracing +-> game-logging-lib subscriber +-> terminal +``` + +Le plugin `tauri-plugin-tracing` reste installé et `attachConsole()` conserve la direction Rust vers console WebView. + +## Escape + +La crate WASM expose : + +```text +quit_requested_escape() -> bool +``` + +Cette méthode appelle le contrat moteur : + +```text +EngineGame::quit_requested(QuitRequest::new(QuitSource::Escape)) +``` + +Le frontend invoque `close_main_window` seulement si la décision vaut `Exit`. + +## Validation + +```bash +cargo fmt --all +cargo fmt --all -- --check + +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android deltas history + +cargo check --workspace +cargo clippy --workspace --all-targets --all-features -- -D warnings + +cargo test -p game-logging-lib --all-targets --all-features +cargo test -p game-reflex-poc --all-targets --all-features +cargo test -p game-reflex-poc-wasm --all-targets --all-features +``` + +## Gate WASM + +```bash +python3 scripts/build_reflex_tauri_wasm.py +``` + +## Smoke Tauri + +```bash +cd crates/apps/game-reflex-poc-tauri +cargo tauri dev +``` + +Des événements Rust et frontend doivent apparaître dans le terminal, notamment le démarrage du runtime et le ready frontend. + +Presser ensuite `Escape`. + +Attendus : + +- événement frontend indiquant `source=escape` et la décision ; +- événement Rust `window close accepted` ; +- fermeture de la fenêtre ; +- retour propre au shell. + +## Transition + +Si les gates et le smoke passent, `0.1.0-1-alpha.2.fix.3` valide le POC Tauri/WASM avec logging visible et politique de sortie commune. diff --git a/docs/development/008-WASM_TAURI_POC.md b/docs/development/008-WASM_TAURI_POC.md index ce80b89..2b32954 100644 --- a/docs/development/008-WASM_TAURI_POC.md +++ b/docs/development/008-WASM_TAURI_POC.md @@ -1,5 +1,5 @@ - + # POC WebAssembly embarqué dans Tauri @@ -145,3 +145,27 @@ Le logging est unifié avec `tracing` : - capability `tracing:default`. Les événements frontend utiles sont donc remontés dans le même système de traces que le backend Rust. + +## Logging fix.3 + +Le plugin Tauri ne remplace pas l'initialisation du subscriber `tracing`. + +`game-logging-lib::init_console_tracing()` installe le subscriber console avant le premier événement Tauri. + +Le frontend possède un wrapper TypeScript unique qui invoque `emit_frontend_log`; Rust valide le niveau et la cible puis réémet l'événement avec `tracing`. + +`attachConsole()` reste activé pour rendre également les événements Rust observables dans la console WebView. + +## Escape fix.3 + +`Escape` suit désormais le contrat moteur commun : + +```text +keydown Escape +-> ReflexWasmGame::quit_requested_escape() +-> EngineGame::quit_requested(QuitSource::Escape) +-> QuitDecision +-> close_main_window uniquement si Exit +``` + +Une future politique de pause/confirmation pourra retourner `Continue` sans modifier le bridge Tauri. diff --git a/docs/rules/RULES_PROJECT.md b/docs/rules/RULES_PROJECT.md index 8147c6d..9331cd5 100644 --- a/docs/rules/RULES_PROJECT.md +++ b/docs/rules/RULES_PROJECT.md @@ -1,5 +1,5 @@ - + # Règles spécifiques games.sasedev @@ -67,3 +67,6 @@ - **GAME-PLATFORM-009** — Une adaptation WebAssembly réutilisable est une crate dédiée distincte de la crate Tauri. - **GAME-PLATFORM-010** — Dans une app Tauri, `lib.rs` reste une façade/reexport ; `tauri.rs` assemble Tauri et expose les commandes qui délèguent aux modules propriétaires. - **GAME-PLATFORM-011** — Les traces frontend Tauri passent par `@fltsci/tauri-plugin-tracing` vers `tauri-plugin-tracing`/`tracing`; les `console.*` applicatifs directs sont interdits hors fallback interne. + +- **GAME-PLATFORM-012** — Le plugin tracing Tauri ne remplace pas l'initialisation du subscriber Rust ; une app Tauri initialise le runtime de logging partagé avant son premier événement `tracing`. +- **GAME-PLATFORM-013** — Les demandes de sortie Tauri sont évaluées par la politique `EngineGame::quit_requested` avant toute fermeture native.