0.3.1-0-pre.4
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# file: Cargo.toml
|
||||
# version: 75
|
||||
# version: 76
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
@@ -21,7 +21,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.3.1-0-pre.3"
|
||||
version = "0.3.1-0-pre.4"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/games"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: README.md -->
|
||||
<!-- version: 46 -->
|
||||
<!-- version: 47 -->
|
||||
|
||||
# games.sasedev
|
||||
|
||||
@@ -27,7 +27,7 @@ Workspace expérimental puis productif pour des jeux multiplateformes principale
|
||||
|
||||
Version stable de référence : `0.3.0`.
|
||||
|
||||
Version de développement courante : `0.3.1-0-pre.3`.
|
||||
Version de développement courante : `0.3.1-0-pre.4`.
|
||||
|
||||
Les deux premiers jeux sont des POC structurels : `game-reflex-poc` et `game-snake-poc`. Ils existent d'abord pour valider les frontières du workspace, le moteur, les assets et le packaging multiplateforme.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: ROADMAP.md -->
|
||||
<!-- version: 22 -->
|
||||
<!-- version: 23 -->
|
||||
|
||||
# Roadmap
|
||||
|
||||
@@ -47,7 +47,7 @@ Le détail historique des prereleases `0.1.0-*` reste dans `deltas/0.1.0/` et `h
|
||||
## Série 0.3.x — trajectoire actuelle après 0.3.0
|
||||
|
||||
- ( ) `0.3.1` — terminer Snake Tauri Android comme POC de référence réutilisant la baseline Web/WASM ; la production Android reste orientée SDL3 natif.
|
||||
- ( ) `0.3.2` — évaluer Tauri Desktop + Snake seulement si la WebView apporte un avantage explicite, notamment une monétisation publicitaire viable ; factoriser uniquement entre consommateurs réellement retenus.
|
||||
- (d) `0.3.2` — Tauri Desktop + Snake est différé tant qu’une solution de monétisation desktop/WebView, notamment vidéo récompensée, n’est pas démontrée techniquement et contractuellement ; ne pas créer cette distribution seulement pour réutiliser le host Web.
|
||||
- ( ) `0.3.3` — Android SDL natif multi-ABI avec Cargo/Gradle natifs, sans script Python de build.
|
||||
- ( ) `0.3.4` — API de transport realtime + WebSocket/tokio-tungstenite baseline, sans serveur Uroburas Mode 3.
|
||||
- ( ) `0.3.5` — POC WebTransport/QUIC sur le même protocole, avec comparaison mesurée et fallback WebSocket.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/apps/game-snake-poc-tauri/README.md -->
|
||||
<!-- version: 5 -->
|
||||
<!-- version: 6 -->
|
||||
|
||||
# game-snake-poc-tauri
|
||||
|
||||
@@ -31,3 +31,13 @@ Les hooks `beforeDevCommand` et `beforeBuildCommand` de Tauri possèdent le buil
|
||||
Le host ne modifie pas le projet Android généré par Tauri. Pour `0.3.1`, la chaîne Tauri 2.11.x est conservée telle que générée : Gradle `8.14.3` et Android Gradle Plugin `8.11.0`. Le JDK Android de référence du projet est JDK 17, qui correspond au minimum et à la valeur par défaut documentés par AGP 8.11. Le Java 25 global et le JBR 25 de l'Android Studio actuellement installé ne doivent pas exécuter ce wrapper.
|
||||
|
||||
Voir [`USAGE.md`](USAGE.md) pour l'initialisation locale et les smokes Android.
|
||||
|
||||
## Lifecycle et Back Android
|
||||
|
||||
Le host suspend explicitement sa boucle `requestAnimationFrame` lorsque la WebView devient cachée et la reprend en réinitialisant son horloge locale. Une reprise après background ne doit donc pas simuler le temps passé hors écran. Resize et rotation passent par un `ResizeObserver` sur la zone de jeu et réévaluent aussi la provenance device.
|
||||
|
||||
Le POC reste mono-page et n’enregistre volontairement aucun handler Tauri `onBackButtonPress`. La politique `EngineGame::quit_requested` de Snake est actuellement la politique moteur par défaut `Exit`, cohérente avec le Back Android/Tauri naturel. Un futur jeu retournant `Continue` devra introduire une intégration Back explicite au lieu de modifier ce POC silencieusement.
|
||||
|
||||
## Limite ergonomique connue
|
||||
|
||||
Le D-pad tactile reste sous le Canvas dans ce POC et peut nécessiter un scroll sur petit écran. Des contrôles superposés ou des gestes swipe seraient techniquement possibles, mais ne sont pas introduits dans `0.3.1` : ils ne changent pas la conclusion d’architecture et appartiendraient à une UX produit réelle.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/apps/game-snake-poc-tauri/USAGE.md -->
|
||||
<!-- version: 5 -->
|
||||
<!-- version: 6 -->
|
||||
|
||||
# Utilisation — Snake Tauri Android
|
||||
|
||||
@@ -64,3 +64,16 @@ Ne pas utiliser `npm run dev` ou `npm run build` comme gate manuelle : ces scrip
|
||||
## Positionnement
|
||||
|
||||
`game-snake-poc-tauri` est un POC de référence. Il ne doit pas être utilisé comme base automatique des futurs jeux Android ; la cible Android productive reste SDL3 natif tant qu’un besoin concret ne justifie pas la WebView Tauri.
|
||||
|
||||
## Smoke lifecycle `0-pre.4`
|
||||
|
||||
Pendant `cargo tauri android dev` :
|
||||
|
||||
1. lancer une partie et effectuer au moins une entrée tactile ;
|
||||
2. mettre l’application en arrière-plan puis la ramener au premier plan ;
|
||||
3. vérifier que le serpent reprend sans accélération ni rattrapage de la durée passée en background ;
|
||||
4. faire pivoter/redimensionner l’émulateur si disponible et vérifier que le Canvas reste rendu ;
|
||||
5. utiliser Back Android : pour Snake, l’application doit suivre le comportement système de sortie, sans navigation Web interne ni interception spécifique ;
|
||||
6. vérifier dans logcat les traces `runtime paused`, `runtime resumed` et les événements `visibility hidden/visible`.
|
||||
|
||||
Le D-pad placé sous le Canvas est une limite ergonomique connue du POC de référence et n’est pas un critère bloquant de cette gate.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/apps/game-snake-poc-tauri/frontend/main.html -->
|
||||
<!-- version: 1 -->
|
||||
<!-- version: 2 -->
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
@@ -23,7 +23,7 @@
|
||||
<output id="score">Score : 0</output>
|
||||
<output id="length">Longueur : 0</output>
|
||||
</div>
|
||||
<div class="game-stage">
|
||||
<div id="game-stage" class="game-stage">
|
||||
<canvas id="game" width="360" height="600" tabindex="0" aria-label="Zone de jeu Snake"></canvas>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/game.ts
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
import init, { SnakeWasmGame } from "@snake-wasm";
|
||||
import type { RuntimeDescriptor } from "./bridge";
|
||||
@@ -13,6 +13,8 @@ export type SnakeDirection = "left" | "right" | "up" | "down";
|
||||
|
||||
export interface SnakeTauriSession {
|
||||
queueDirection(direction: SnakeDirection, source: SnakeInputSource): void;
|
||||
pause(): void;
|
||||
resume(): void;
|
||||
renderNow(): void;
|
||||
refreshDeviceClass(): void;
|
||||
dispose(): void;
|
||||
@@ -92,6 +94,7 @@ export async function startGame(
|
||||
let previous = performance.now();
|
||||
let accumulator = 0;
|
||||
let animationFrame: number | null = null;
|
||||
let running = false;
|
||||
let disposed = false;
|
||||
|
||||
function renderNow(): void {
|
||||
@@ -101,8 +104,16 @@ export async function startGame(
|
||||
render(game, canvas, renderingContext, score, length);
|
||||
}
|
||||
|
||||
function schedule(): void {
|
||||
if (!running || disposed || animationFrame !== null) {
|
||||
return;
|
||||
}
|
||||
animationFrame = window.requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
function frame(now: number): void {
|
||||
if (disposed) {
|
||||
animationFrame = null;
|
||||
if (!running || disposed) {
|
||||
return;
|
||||
}
|
||||
const elapsed = Math.min(Math.max(0, now - previous), MAX_FRAME_ELAPSED_MILLIS);
|
||||
@@ -113,11 +124,35 @@ export async function startGame(
|
||||
accumulator -= FRAME_MILLIS;
|
||||
}
|
||||
renderNow();
|
||||
animationFrame = window.requestAnimationFrame(frame);
|
||||
schedule();
|
||||
}
|
||||
|
||||
function pause(): void {
|
||||
if (!running || disposed) {
|
||||
return;
|
||||
}
|
||||
running = false;
|
||||
accumulator = 0;
|
||||
if (animationFrame !== null) {
|
||||
window.cancelAnimationFrame(animationFrame);
|
||||
animationFrame = null;
|
||||
}
|
||||
frontendInfo("Snake Tauri runtime paused");
|
||||
}
|
||||
|
||||
function resume(): void {
|
||||
if (running || disposed) {
|
||||
return;
|
||||
}
|
||||
previous = performance.now();
|
||||
accumulator = 0;
|
||||
running = true;
|
||||
schedule();
|
||||
frontendInfo("Snake Tauri runtime resumed");
|
||||
}
|
||||
|
||||
renderNow();
|
||||
animationFrame = window.requestAnimationFrame(frame);
|
||||
resume();
|
||||
return {
|
||||
queueDirection(direction: SnakeDirection, source: SnakeInputSource): void {
|
||||
if (disposed) {
|
||||
@@ -126,6 +161,8 @@ export async function startGame(
|
||||
provenance.recordInput(source);
|
||||
queueDirection(game, direction);
|
||||
},
|
||||
pause,
|
||||
resume,
|
||||
renderNow,
|
||||
refreshDeviceClass(): void {
|
||||
if (!disposed) {
|
||||
@@ -136,12 +173,10 @@ export async function startGame(
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
pause();
|
||||
disposed = true;
|
||||
if (animationFrame !== null) {
|
||||
window.cancelAnimationFrame(animationFrame);
|
||||
animationFrame = null;
|
||||
}
|
||||
game.free();
|
||||
frontendInfo("Snake Tauri runtime disposed");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
60
crates/apps/game-snake-poc-tauri/frontend/ts/lifecycle.ts
Normal file
60
crates/apps/game-snake-poc-tauri/frontend/ts/lifecycle.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/lifecycle.ts
|
||||
// version: 1
|
||||
|
||||
import type { SnakeTauriSession } from "./game";
|
||||
import { frontendInfo } from "./logging";
|
||||
|
||||
export interface SnakeTauriLifecycleBinding {
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export function bindTauriLifecycle(session: SnakeTauriSession, stage: HTMLElement): SnakeTauriLifecycleBinding {
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
session.refreshDeviceClass();
|
||||
session.renderNow();
|
||||
});
|
||||
|
||||
function synchronizeVisibility(): void {
|
||||
if (document.visibilityState === "hidden") {
|
||||
session.pause();
|
||||
frontendInfo("Snake Tauri lifecycle: visibility hidden");
|
||||
return;
|
||||
}
|
||||
session.resume();
|
||||
session.refreshDeviceClass();
|
||||
session.renderNow();
|
||||
frontendInfo("Snake Tauri lifecycle: visibility visible");
|
||||
}
|
||||
|
||||
function pageHide(event: PageTransitionEvent): void {
|
||||
if (event.persisted) {
|
||||
session.pause();
|
||||
} else {
|
||||
session.dispose();
|
||||
}
|
||||
frontendInfo(`Snake Tauri lifecycle: page hide persisted=${event.persisted}`);
|
||||
}
|
||||
|
||||
function pageShow(event: PageTransitionEvent): void {
|
||||
session.resume();
|
||||
session.refreshDeviceClass();
|
||||
session.renderNow();
|
||||
frontendInfo(`Snake Tauri lifecycle: page show persisted=${event.persisted}`);
|
||||
}
|
||||
|
||||
resizeObserver.observe(stage);
|
||||
document.addEventListener("visibilitychange", synchronizeVisibility);
|
||||
window.addEventListener("pagehide", pageHide);
|
||||
window.addEventListener("pageshow", pageShow);
|
||||
synchronizeVisibility();
|
||||
|
||||
return {
|
||||
dispose(): void {
|
||||
resizeObserver.disconnect();
|
||||
document.removeEventListener("visibilitychange", synchronizeVisibility);
|
||||
window.removeEventListener("pagehide", pageHide);
|
||||
window.removeEventListener("pageshow", pageShow);
|
||||
session.dispose();
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/main.ts
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
import "../css/main.css";
|
||||
import { loadSnakeTauriAssets } from "./assets";
|
||||
import { getRuntimeDescriptor, reportFrontendReady } from "./bridge";
|
||||
import { startGame } from "./game";
|
||||
import { bindInputs } from "./input";
|
||||
import { bindTauriLifecycle } from "./lifecycle";
|
||||
import { frontendError, frontendInfo, initializeFrontendTracing } from "./logging";
|
||||
|
||||
function requiredElement<T extends HTMLElement>(identifier: string): T {
|
||||
@@ -21,6 +22,7 @@ async function bootstrap(): Promise<void> {
|
||||
frontendInfo("Snake Tauri frontend bootstrap started");
|
||||
const descriptor = await getRuntimeDescriptor();
|
||||
const canvas = requiredElement<HTMLCanvasElement>("game");
|
||||
const stage = requiredElement<HTMLElement>("game-stage");
|
||||
const score = requiredElement<HTMLOutputElement>("score");
|
||||
const length = requiredElement<HTMLOutputElement>("length");
|
||||
const provenance = requiredElement<HTMLOutputElement>("runtime-provenance");
|
||||
@@ -37,11 +39,7 @@ async function bootstrap(): Promise<void> {
|
||||
status.textContent = "Chargement WASM…";
|
||||
const session = await startGame(canvas, score, length, provenance, descriptor);
|
||||
bindInputs(session, buttons);
|
||||
window.addEventListener("resize", () => {
|
||||
session.refreshDeviceClass();
|
||||
session.renderNow();
|
||||
});
|
||||
window.addEventListener("pagehide", () => session.dispose(), { once: true });
|
||||
bindTauriLifecycle(session, stage);
|
||||
|
||||
document.body.dataset.runtimeState = "ready";
|
||||
status.textContent = "Prêt";
|
||||
|
||||
54
deltas/0.3.1/0-pre.4.md
Normal file
54
deltas/0.3.1/0-pre.4.md
Normal file
@@ -0,0 +1,54 @@
|
||||
<!-- file: deltas/0.3.1/0-pre.4.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-0-pre.4
|
||||
|
||||
## Objet
|
||||
|
||||
Fermer le comportement runtime du POC Snake Tauri Android après validation du Canvas/input/assets de `0-pre.3`, sans élargir la cible vers une distribution Android de production.
|
||||
|
||||
## Changements
|
||||
|
||||
- version workspace : `0.3.1-0-pre.4` ;
|
||||
- historique de validation `0-pre.3` ajouté ;
|
||||
- nouvelle liaison lifecycle Tauri dédiée : `visibilitychange`, `pagehide`, `pageshow`, `ResizeObserver` ;
|
||||
- session Canvas dotée de `pause()` / `resume()` avec annulation du frame pending et remise à zéro de l'accumulateur ;
|
||||
- reprise sans simulation du temps passé en background ;
|
||||
- refresh de la provenance device lors des reprises et resize/rotation ;
|
||||
- tracing frontend des transitions lifecycle ;
|
||||
- Back Android volontairement non intercepté pour le Snake mono-page dont la politique moteur est `Exit` ;
|
||||
- limite ergonomique du D-pad sous le Canvas documentée sans ajouter swipe/overlay hors scope ;
|
||||
- Tauri Desktop marqué différé tant qu'une voie de monétisation WebView/desktop n'est pas démontrée.
|
||||
|
||||
## Invariants
|
||||
|
||||
- aucune logique gameplay n'entre dans TypeScript ;
|
||||
- `game-snake-poc-wasm` reste l'unique adapter WASM Snake ;
|
||||
- aucun fichier `gen/android` n'est versionné ou patché ;
|
||||
- aucun handler `onBackButtonPress` n'est installé par ce POC ;
|
||||
- aucun SDK publicitaire n'est déclaré comme compatible sans POC technique et vérification contractuelle ;
|
||||
- SDL3 natif reste la direction Android de production.
|
||||
|
||||
## Validation demandée
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/usr/lib/jvm/temurin-17-jdk-amd64
|
||||
|
||||
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 Web deltas history
|
||||
python3 scripts/audit_distribution_layout.py
|
||||
|
||||
cargo fmt --all
|
||||
cargo fmt --all -- --check
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
cargo test -p game-snake-poc-wasm --all-targets --all-features
|
||||
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
|
||||
```
|
||||
|
||||
Smoke manuel : entrée tactile, background/foreground sans rattrapage, rotation/resize, provenance `phone / touch`, traces lifecycle, puis Back Android naturel.
|
||||
|
||||
## Suite prévue
|
||||
|
||||
Si cette gate est propre, `0-pre.5` est omise sauf duplication durable nouvellement démontrée. La version passe à `0.3.1-2-beta.1` pour validation large et packaging du POC de référence.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/015-PLATFORM_POC_ARCHITECTURE.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Architecture des POC plateforme et réseau
|
||||
|
||||
@@ -15,7 +15,7 @@ Première vague, réordonnée à partir du résultat réel de `0.3.0` :
|
||||
|
||||
- Web navigateur direct + Snake — validé par `0.3.0` ;
|
||||
- Tauri Android + Snake — POC de référence terminé par `0.3.1`, conservé pour comparaison mais non retenu comme voie de production Android par défaut ;
|
||||
- Tauri Desktop + Snake — évaluation conditionnelle seulement si la WebView apporte un bénéfice produit explicite, notamment une voie de monétisation publicitaire viable ;
|
||||
- Tauri Desktop + Snake — différé tant qu’un bénéfice produit explicite n’est pas démontré, en particulier une voie de monétisation publicitaire/reward vidéo compatible avec une WebView desktop distribuée ;
|
||||
- build Android multi-ABI avec outils natifs — tranche dédiée après les POC WebView.
|
||||
|
||||
Plateformes supplémentaires lorsque l'environnement existe : Windows SDL natif, macOS SDL natif et iOS SDL natif.
|
||||
@@ -26,7 +26,7 @@ Le host Tauri Android reste pertinent comme preuve de portabilité du gameplay R
|
||||
|
||||
La baseline Android productive reste SDL3 natif avec wrapper Java/JNI : elle fournit déjà le rendu et les contrôles nécessaires avec moins de couches d’outillage. Tauri Android ne doit être rouvert pour un produit que lorsqu’un besoin concret apporte une valeur supérieure à ce coût, par exemple si les tests futurs démontrent un avantage net de la WebView pour une saisie texte ou une capacité UI difficile à obtenir proprement via SDL.
|
||||
|
||||
Cette décision n’interdit pas Tauri Desktop. Le Desktop reste une distribution distincte et optionnelle ; sa valeur doit être démontrée séparément, notamment au regard des possibilités de monétisation dans une WebView Desktop.
|
||||
Cette décision n’interdit pas Tauri Desktop. Le Desktop reste une distribution distincte et optionnelle ; sa valeur doit être démontrée séparément. À la clôture du POC Android, aucune solution de publicité ou reward vidéo dans une WebView Tauri Desktop n’est considérée comme validée. Une approche exigeant une URL Web publique, un chargement distant du jeu ou un SDK tiers spécifique doit faire l’objet d’un POC et d’une vérification contractuelle avant de rouvrir cette cible.
|
||||
|
||||
## POC réseau
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md -->
|
||||
<!-- version: 6 -->
|
||||
<!-- version: 7 -->
|
||||
|
||||
# Plan v0.3.1 — second host Snake Tauri Android
|
||||
|
||||
@@ -123,6 +123,8 @@ Stabiliser :
|
||||
|
||||
Cette tranche doit rendre le second host fonctionnel de bout en bout et suffisamment stable pour être conservé comme POC de référence.
|
||||
|
||||
État candidat `0-pre.4` : la boucle Tauri dispose maintenant de `pause/resume`, remet à zéro son accumulateur à la reprise, suit `visibilitychange`, `pagehide/pageshow` et `ResizeObserver`, et journalise les transitions via le tracing frontend. Le Back Android n’est pas intercepté : Snake conserve la politique moteur par défaut `Exit`, identique au comportement système Tauri du host mono-page. Le D-pad sous le Canvas est conservé comme limite ergonomique documentée plutôt que d’élargir cette version à un système swipe/overlay.
|
||||
|
||||
### `0-pre.5` — extraction conditionnelle
|
||||
|
||||
Créer uniquement si l'état `0-pre.4` montre une duplication réellement durable entre `Web/game-snake-poc` et le frontend Tauri **et** si l'extraction garde une valeur au-delà du seul POC Android de référence.
|
||||
|
||||
55
history/0.3.1/0-pre.3.md
Normal file
55
history/0.3.1/0-pre.3.md
Normal file
@@ -0,0 +1,55 @@
|
||||
<!-- file: history/0.3.1/0-pre.3.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Historique 0.3.1-0-pre.3
|
||||
|
||||
## Statut
|
||||
|
||||
Tranche validée par l'utilisateur le 2026-09-21 sur l'AVD Android x86_64. Le POC Tauri Android affiche et exécute réellement Snake via le Canvas et l'adapter WASM partagé.
|
||||
|
||||
## Gate workspace
|
||||
|
||||
Les validations suivantes ont passé :
|
||||
|
||||
```text
|
||||
OpenJDK Temurin 17.0.20.1 sélectionné par JAVA_HOME
|
||||
npm install : 0 vulnérabilité
|
||||
games.sasedev workspace audit: clean
|
||||
Markdown table audit: clean (5 table(s), 219 file(s))
|
||||
Distribution layout audit: clean (47 required path(s), 1 forbidden path(s) absent)
|
||||
cargo fmt --all: clean
|
||||
cargo fmt --all -- --check: clean
|
||||
cargo check --workspace: clean
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings: clean
|
||||
cargo test -p game-snake-poc-wasm --all-targets --all-features: 5 passed, 0 failed
|
||||
```
|
||||
|
||||
## Smoke Tauri Android
|
||||
|
||||
`cargo tauri android dev` a construit le WASM, collecté les deux assets canoniques, assemblé et installé l'APK puis lancé `com.sasedev.games.snake.tauri/.MainActivity`.
|
||||
|
||||
Les traces ont confirmé :
|
||||
|
||||
```text
|
||||
Snake Tauri assets ready: game-snake-poc / snake / engine-v1
|
||||
Snake Tauri WASM initialized
|
||||
Snake Tauri provenance: android / tauri-webview / wasm / phone / unknown
|
||||
Snake Tauri frontend ready
|
||||
Snake Tauri provenance: android / tauri-webview / wasm / phone / touch
|
||||
```
|
||||
|
||||
Le Canvas est visible, le serpent se déplace et les boutons tactiles modifient effectivement sa direction.
|
||||
|
||||
## Limite ergonomique observée
|
||||
|
||||
Sur le petit écran de l'AVD, les boutons directionnels sont placés sous le Canvas et nécessitent un scroll pour être atteints. Le contrôle fonctionne mais n'est pas adapté à un jeu final. Une UX produit pourrait utiliser des boutons superposés/transparents ou des gestes swipe ; cette optimisation n'est pas ajoutée à `0.3.1`, dont l'objectif reste le POC de référence.
|
||||
|
||||
## Décision plateforme confirmée
|
||||
|
||||
Le POC confirme que Tauri Android est techniquement viable mais apporte une chaîne supplémentaire JDK/Gradle/Tauri/WebView/WASM sans avantage actuellement démontré sur le host Android SDL3 natif. Les futurs jeux Android restent donc orientés SDL3/Java/JNI.
|
||||
|
||||
La variante Tauri Desktop est elle aussi différée tant qu'une solution de monétisation desktop/WebView, notamment reward vidéo, n'est pas démontrée. Les pistes nécessitant une URL Web publique ou un SDK tiers restent des hypothèses à valider, pas des capacités acquises.
|
||||
|
||||
## Suite
|
||||
|
||||
`0.3.1-0-pre.4` ferme le POC fonctionnel par la gestion explicite background/foreground, resize/rotation, tracing lifecycle et politique Back Android.
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# file: scripts/audit_distribution_layout.py
|
||||
# version: 12
|
||||
# version: 13
|
||||
|
||||
"""Audit the static distribution layout expected by supported POCs."""
|
||||
|
||||
@@ -44,6 +44,7 @@ REQUIRED_PATHS = (
|
||||
"crates/apps/game-snake-poc-tauri/frontend/ts/assets.ts",
|
||||
"crates/apps/game-snake-poc-tauri/frontend/ts/game.ts",
|
||||
"crates/apps/game-snake-poc-tauri/frontend/ts/input.ts",
|
||||
"crates/apps/game-snake-poc-tauri/frontend/ts/lifecycle.ts",
|
||||
"crates/apps/game-snake-poc-tauri/frontend/ts/main.ts",
|
||||
"crates/apps/game-snake-poc-tauri/frontend/ts/provenance.ts",
|
||||
"Web/game-snake-poc/package.json",
|
||||
@@ -168,6 +169,7 @@ def audit_snake_tauri_android_integration(root: pathlib.Path) -> list[str]:
|
||||
game_path = app_root / "frontend/ts/game.ts"
|
||||
input_path = app_root / "frontend/ts/input.ts"
|
||||
provenance_path = app_root / "frontend/ts/provenance.ts"
|
||||
lifecycle_path = app_root / "frontend/ts/lifecycle.ts"
|
||||
logging_path = app_root / "frontend/ts/logging.ts"
|
||||
vite_path = app_root / "vite.config.ts"
|
||||
wasm_runtime_path = root / "crates/apps/game-snake-poc-wasm/src/runtime.rs"
|
||||
@@ -183,6 +185,7 @@ def audit_snake_tauri_android_integration(root: pathlib.Path) -> list[str]:
|
||||
game_path,
|
||||
input_path,
|
||||
provenance_path,
|
||||
lifecycle_path,
|
||||
logging_path,
|
||||
vite_path,
|
||||
wasm_runtime_path,
|
||||
@@ -201,6 +204,7 @@ def audit_snake_tauri_android_integration(root: pathlib.Path) -> list[str]:
|
||||
game = game_path.read_text(encoding="utf-8")
|
||||
input_module = input_path.read_text(encoding="utf-8")
|
||||
provenance = provenance_path.read_text(encoding="utf-8")
|
||||
lifecycle = lifecycle_path.read_text(encoding="utf-8")
|
||||
logging = logging_path.read_text(encoding="utf-8")
|
||||
vite = vite_path.read_text(encoding="utf-8")
|
||||
wasm_runtime = wasm_runtime_path.read_text(encoding="utf-8")
|
||||
@@ -222,6 +226,7 @@ def audit_snake_tauri_android_integration(root: pathlib.Path) -> list[str]:
|
||||
(main, 'loadSnakeTauriAssets()', "DIST-LAYOUT-046: Snake Tauri startup must load canonical runtime assets"),
|
||||
(main, 'startGame(canvas, score, length, provenance, descriptor)', "DIST-LAYOUT-047: Snake Tauri startup must run the shared WASM game through Canvas"),
|
||||
(main, 'bindInputs(session, buttons)', "DIST-LAYOUT-048: Snake Tauri startup must bind host inputs"),
|
||||
(main, 'bindTauriLifecycle(session, stage)', "DIST-LAYOUT-059: Snake Tauri startup must bind WebView lifecycle"),
|
||||
(assets, './common/data/runtime.json', "DIST-LAYOUT-049: Snake Tauri asset probe must load common runtime metadata"),
|
||||
(assets, './game/data/game.json', "DIST-LAYOUT-050: Snake Tauri asset probe must load Snake metadata"),
|
||||
(game, 'window.requestAnimationFrame(frame)', "DIST-LAYOUT-051: Snake Tauri Canvas host must schedule its fixed-step session"),
|
||||
@@ -230,6 +235,13 @@ def audit_snake_tauri_android_integration(root: pathlib.Path) -> list[str]:
|
||||
(input_module, '"keydown"', "DIST-LAYOUT-054: Snake Tauri input must retain keyboard controls when available"),
|
||||
(provenance, '"touch"', "DIST-LAYOUT-055: Snake Tauri provenance must observe touch input"),
|
||||
(provenance, '"keyboard-mouse"', "DIST-LAYOUT-056: Snake Tauri provenance must observe keyboard/mouse input"),
|
||||
(lifecycle, '"visibilitychange"', "DIST-LAYOUT-060: Snake Tauri lifecycle must observe visibility changes"),
|
||||
(lifecycle, '"pagehide"', "DIST-LAYOUT-061: Snake Tauri lifecycle must observe pagehide"),
|
||||
(lifecycle, '"pageshow"', "DIST-LAYOUT-062: Snake Tauri lifecycle must observe pageshow"),
|
||||
(lifecycle, "ResizeObserver", "DIST-LAYOUT-063: Snake Tauri lifecycle must observe stage resize/orientation"),
|
||||
(game, "pause(): void;", "DIST-LAYOUT-064: Snake Tauri session must expose pause semantics"),
|
||||
(game, "resume(): void;", "DIST-LAYOUT-065: Snake Tauri session must expose resume semantics"),
|
||||
(game, "accumulator = 0;", "DIST-LAYOUT-066: Snake Tauri resume/pause must reset accumulated elapsed time"),
|
||||
(vite, 'dest: "common/data", rename: { stripBase: true }', "DIST-LAYOUT-057: Snake Tauri common assets must retain the common/data namespace"),
|
||||
(vite, 'dest: "game/data", rename: { stripBase: true }', "DIST-LAYOUT-058: Snake Tauri game assets must retain the game/data namespace"),
|
||||
(logging, '@fltsci/tauri-plugin-tracing', "DIST-LAYOUT-030: Snake Tauri frontend logs must use the tracing bridge"),
|
||||
@@ -245,6 +257,8 @@ def audit_snake_tauri_android_integration(root: pathlib.Path) -> list[str]:
|
||||
(build_script, "gen/android", "DIST-LAYOUT-040: Snake Tauri build script must not mutate generated Android Gradle files"),
|
||||
(tauri, "python", "DIST-LAYOUT-034: Snake Tauri configuration must not use Python build orchestration"),
|
||||
(main, "console.", "DIST-LAYOUT-035: Snake Tauri application frontend must not log directly through console.*"),
|
||||
(main, "onbackbuttonpress", "DIST-LAYOUT-067: Snake Tauri reference POC must leave Android Back to the system while Snake quit policy is Exit"),
|
||||
(lifecycle, "onbackbuttonpress", "DIST-LAYOUT-067: Snake Tauri reference POC must leave Android Back to the system while Snake quit policy is Exit"),
|
||||
)
|
||||
for content, fragment, message in forbidden_fragments:
|
||||
if fragment in content.lower():
|
||||
|
||||
Reference in New Issue
Block a user