Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 76a955bd3d | |||
| e5a4d7fe44 | |||
| d8e7951a04 | |||
| c806490212 | |||
| a36b666d22 | |||
| 4f677dbc77 | |||
| e4b657d0d3 | |||
| 1835464bb3 | |||
| bded27c944 | |||
| 51371c1b24 | |||
| ba718ce4ec |
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,8 +1,28 @@
|
||||
<!-- file: CHANGELOG.md -->
|
||||
<!-- version: 14 -->
|
||||
<!-- version: 16 -->
|
||||
|
||||
# Changelog
|
||||
|
||||
## 0.3.1 — 2026-09-21
|
||||
|
||||
- publication stable du second host Snake sous Tauri Android, conservé comme POC de référence et non comme voie de production Android ;
|
||||
- validation du gameplay partagé via `game-snake-poc-wasm`, du Canvas, des contrôles tactiles, des assets, du lifecycle mobile/WebView, du tracing et de la provenance runtime ;
|
||||
- validation d’un APK Debug universal autonome contenant `arm64-v8a` et `x86_64`, installé et lancé sur Galaxy S9+ ARM64 réel et AVD API 36 x86_64 ;
|
||||
- validation finale de `0.3.1-3-rc.1` sans défaut nécessitant un correctif RC, puis promotion mécanique vers la stable ;
|
||||
- maintien de `0.3.2` en différé et préparation de `0.3.3` pour Android SDL3 natif multi-ABI, APK universal de test, AAB de distribution et évaluation du `minSdk`.
|
||||
|
||||
Les détails des phases `pre`, `beta`, `rc` et de leurs correctifs restent dans `deltas/0.3.1/` et `history/0.3.1/`.
|
||||
|
||||
## 0.3.1-3-rc.1 — 2026-09-21
|
||||
|
||||
- gel fonctionnel du POC Snake Tauri Android de référence après validation beta du workspace complet et du packaging Android autonome ;
|
||||
- APK Debug universal construit avec les cibles Rust `aarch64-linux-android` et `x86_64-linux-android`, puis installé et lancé avec succès sur Galaxy S9+ ARM64 et AVD API 36 x86_64 ;
|
||||
- host Tauri conservé comme POC comparatif : la voie Android productive reste SDL3 natif/Java/JNI ;
|
||||
- absence d’extraction Web/Tauri supplémentaire et absence d’AAB Tauri volontaire : les choix de distribution Android productive sont reportés au POC SDL3 natif ;
|
||||
- `0.3.2` Tauri Desktop reste différée faute de bénéfice produit/monétisation démontré ; la prochaine version active préparée est `0.3.3`, Android SDL3 natif multi-ABI, avec AAB et compatibilité Android ancienne à évaluer.
|
||||
|
||||
La RC n’ouvre aucun nouveau scope. Seuls les correctifs de publication autorisés par `VER-RC-*` peuvent produire un `3-rc.1.fix.N`.
|
||||
|
||||
## 0.3.0 — 2026-09-20
|
||||
|
||||
- publication stable du premier POC Snake Web direct, construit autour du gameplay Rust partagé, d'un adapter WASM dédié et d'un host navigateur Vite/TypeScript ;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# file: Cargo.toml
|
||||
# version: 69
|
||||
# version: 80
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
@@ -17,10 +17,11 @@ members = [
|
||||
"crates/apps/game-reflex-poc-tauri",
|
||||
"crates/apps/game-reflex-poc-wasm",
|
||||
"crates/apps/game-snake-poc-wasm",
|
||||
"crates/apps/game-snake-poc-tauri",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/games"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: README.md -->
|
||||
<!-- version: 40 -->
|
||||
<!-- version: 51 -->
|
||||
|
||||
# games.sasedev
|
||||
|
||||
@@ -14,6 +14,7 @@ Workspace expérimental puis productif pour des jeux multiplateformes principale
|
||||
- assets hors des crates sous `assets/` ;
|
||||
- `assets/common/` pour les ressources mutualisées et un répertoire par jeu pour les ressources spécifiques ;
|
||||
- frontend Android sous `Android/`, en Java, avec une partie commune et une partie spécifique par jeu ;
|
||||
- Android de production orienté SDL3 natif/Java/JNI ; Tauri Android reste un POC de référence et non un template de jeu ;
|
||||
- hosts navigateur directs sous `Web/`, avec frontend Vite/TypeScript séparé des adapters Rust/WASM ;
|
||||
- monétisation optionnelle et spécifique à chaque plateforme/distribution ;
|
||||
- runner Desktop natif SDL3 par défaut, avec variante Tauri uniquement si un besoin futur la justifie ;
|
||||
@@ -24,9 +25,11 @@ Workspace expérimental puis productif pour des jeux multiplateformes principale
|
||||
|
||||
## Baseline
|
||||
|
||||
Version stable de référence : `0.3.0`.
|
||||
Version stable de référence : `0.3.1`.
|
||||
|
||||
Version suivante planifiée : `0.3.1` (non démarrée).
|
||||
Version suivante active planifiée : `0.3.3` (non démarrée). `0.3.2` reste différée.
|
||||
|
||||
La stable `0.3.1` conserve Snake Tauri Android comme POC de référence validé sur AVD x86_64 et appareil ARM64 réel. La prochaine version active `0.3.3` est centrée sur Android SDL3 natif multi-ABI, le packaging Gradle/AAB et l’évaluation explicite de la compatibilité avec des versions Android plus anciennes.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
10
ROADMAP.md
10
ROADMAP.md
@@ -1,5 +1,5 @@
|
||||
<!-- file: ROADMAP.md -->
|
||||
<!-- version: 21 -->
|
||||
<!-- version: 25 -->
|
||||
|
||||
# Roadmap
|
||||
|
||||
@@ -44,11 +44,11 @@ Le détail historique des prereleases `0.1.0-*` reste dans `deltas/0.1.0/` et `h
|
||||
- (x) `0.3.0` — utiliser uniquement Cargo, `wasm-bindgen` et Vite/npm pour le chemin de build Web ; aucun script Python ne pilote ce build.
|
||||
- (x) `0.3.0` — documenter les duplications observées et conserver les adapters Web/WASM spécifiques tant qu’un second consommateur ne justifie pas une extraction commune.
|
||||
|
||||
## Série 0.3.x — trajectoire actuelle après 0.3.0
|
||||
## Série 0.3.x — trajectoire actuelle après 0.3.1
|
||||
|
||||
- ( ) `0.3.1` — second host Snake : Tauri Android, en réutilisant la baseline Web/WASM validée et en remplaçant toute orchestration Python du chemin touché.
|
||||
- ( ) `0.3.2` — Tauri Desktop + Snake et factorisation WebView uniquement lorsque deux consommateurs réels justifient l'extraction.
|
||||
- ( ) `0.3.3` — Android SDL natif multi-ABI avec Cargo/Gradle natifs, sans script Python de build.
|
||||
- (x) `0.3.1` — Snake Tauri Android livré comme POC de référence réutilisant la baseline Web/WASM ; la production Android reste orientée SDL3 natif.
|
||||
- (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 SDL3 natif multi-ABI avec Cargo/Gradle natifs, APK universal pour tests, AAB comme cible de distribution et évaluation du `minSdk`/support d’anciennes versions Android, 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.
|
||||
- ( ) `0.3.6` — consolidation des POC plateforme/réseau et préparation de la baseline `0.4.x`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: Web/game-snake-poc/frontend/ts/provenance.ts
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
import type { SnakeWasmGame } from "@snake-wasm";
|
||||
import { webInfo } from "./logging";
|
||||
@@ -83,7 +83,7 @@ export class BrowserRuntimeProvenance {
|
||||
|
||||
private synchronize(): void {
|
||||
const profile = inputProfile(this.keyboardMouseObserved, this.touchObserved);
|
||||
if (!this.game.configure_runtime_provenance(this.deviceClass, profile)) {
|
||||
if (!this.game.configure_runtime_provenance("web", "browser", this.deviceClass, profile)) {
|
||||
throw new Error("La provenance navigateur n'a pas pu être configurée dans le bridge WASM.");
|
||||
}
|
||||
this.output.value = displayLabel(this.game);
|
||||
|
||||
34
crates/apps/game-snake-poc-tauri/Cargo.toml
Normal file
34
crates/apps/game-snake-poc-tauri/Cargo.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
# file: crates/apps/game-snake-poc-tauri/Cargo.toml
|
||||
# version: 1
|
||||
|
||||
[package]
|
||||
name = "game-snake-poc-tauri"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
authors.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "game_snake_poc_tauri_lib"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[[bin]]
|
||||
name = "game-snake-poc-tauri"
|
||||
path = "src/main.rs"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build.workspace = true
|
||||
|
||||
[dependencies]
|
||||
engine-v1-platform-api = { path = "../../engines/engine-v1-platform-api" }
|
||||
game-logging-lib = { path = "../../common/game-logging-lib" }
|
||||
serde.workspace = true
|
||||
tauri.workspace = true
|
||||
tauri-plugin-tracing.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
45
crates/apps/game-snake-poc-tauri/README.md
Normal file
45
crates/apps/game-snake-poc-tauri/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
<!-- file: crates/apps/game-snake-poc-tauri/README.md -->
|
||||
<!-- version: 9 -->
|
||||
|
||||
# game-snake-poc-tauri
|
||||
|
||||
Host Tauri Android de référence du POC Snake. Cette application réutilise le gameplay Rust de `game-snake-poc` et l'unique adapter WebAssembly `game-snake-poc-wasm` ; elle ne possède aucune règle de jeu.
|
||||
|
||||
## Responsabilités
|
||||
|
||||
La crate possède uniquement la frontière Tauri : initialisation du logging Rust, assemblage/plugins/commandes Tauri, contrat minimal de provenance native et frontend Vite/TypeScript exécuté dans la WebView Android.
|
||||
|
||||
L'organisation Rust suit le modèle des applications Desk KSP :
|
||||
|
||||
- `src/lib.rs` reste une façade et réexporte les éléments partagés au crate-root ;
|
||||
- `src/tauri.rs` assemble Tauri et fait déléguer les commandes aux modules propriétaires ;
|
||||
- `src/runtime.rs` possède le petit contrat runtime/provenance ;
|
||||
- `frontend/` contient le host WebView et consomme les bindings générés de `game-snake-poc-wasm`.
|
||||
|
||||
À partir de `0.3.1-0-pre.3`, le frontend fournit aussi le Canvas, la boucle fixed-step, les contrôles clavier/touch et le chargement des assets canoniques. `0-pre.4` ajoute la suspension/reprise explicite, le suivi de visibilité et le resize/orientation.
|
||||
|
||||
## Statut du POC
|
||||
|
||||
Ce host est conservé comme **POC de référence** et non comme template de production Android. La voie de jeu Android privilégiée reste SDL3 natif/Java/JNI, qui couvre déjà les besoins principaux avec une chaîne de build plus directe.
|
||||
|
||||
Tauri Android reste utile pour comparer une WebView/WASM à la voie native et pour tester ultérieurement des besoins spécifiques, par exemple la saisie texte. Une future distribution Tauri Desktop est une décision séparée, conditionnée à un bénéfice produit concret tel qu’une monétisation WebView exploitable.
|
||||
|
||||
## Build
|
||||
|
||||
Les hooks `beforeDevCommand` et `beforeBuildCommand` de Tauri possèdent le build WASM et Vite. Aucun orchestrateur Python n'est utilisé. Les bindings WASM, la distribution Vite, les caches, `node_modules/` et le projet Android généré restent hors des sources livrées ou dans des chemins générés ignorés.
|
||||
|
||||
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.
|
||||
|
||||
Le premier smoke ARM64 réel a mis en évidence un abort natif pendant un teardown déclenché par Back : `FORTIFY: pthread_mutex_lock called on a destroyed mutex`. Après correction du tunnel HMR afin que HTTP et WebSocket partagent tous deux `1436`, le smoke `0-pre.4.fix.1` ne l'a pas reproduit. La beta a ensuite validé la construction d'un APK autonome universal et son installation/lancement sur ARM64 réel et AVD x86_64. La RC conserve le teardown/Back dans ses smokes finaux sans ajouter de handler ad hoc ni patcher le scaffold généré.
|
||||
|
||||
## 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.
|
||||
119
crates/apps/game-snake-poc-tauri/USAGE.md
Normal file
119
crates/apps/game-snake-poc-tauri/USAGE.md
Normal file
@@ -0,0 +1,119 @@
|
||||
<!-- file: crates/apps/game-snake-poc-tauri/USAGE.md -->
|
||||
<!-- version: 9 -->
|
||||
|
||||
# Utilisation — Snake Tauri Android
|
||||
|
||||
## Prérequis locaux
|
||||
|
||||
Le host utilise Cargo/Rust, `cargo tauri`, Node/npm, `wasm-bindgen`, Java et le SDK Android. Le dépôt attend `ANDROID_HOME` vers le SDK Android et des NDK side-by-side sous `$ANDROID_HOME/ndk/<version>`.
|
||||
|
||||
`NDK_HOME` n'est pas un prérequis utilisateur du projet. Tauri sélectionne la version NDK side-by-side appropriée sous `$ANDROID_HOME/ndk/<version>` et peut injecter lui-même `NDK_HOME` dans ses sous-processus Android. Une variable globale ne doit donc pas être ajoutée uniquement pour satisfaire la documentation générique de Tauri.
|
||||
|
||||
Pour `0.3.1`, le JDK Android de référence est **JDK 17**. Le template Tauri 2.11.x utilisé par le projet génère Gradle `8.14.3` avec Android Gradle Plugin `8.11.0` : AGP 8.11 exige au minimum JDK 17 et Gradle 8.14.x ne peut pas s'exécuter sur Java 25. JDK 17 fournit donc la baseline reproductible commune aux deux contraintes.
|
||||
|
||||
Le Java 25 global de la machine de validation peut rester installé. En revanche, le JBR de l'Android Studio actuellement installé est lui aussi Java 25 et ne doit donc pas être utilisé pour cette gate malgré la recommandation générique de Tauri d'utiliser le JBR d'Android Studio. Le Gradle global installé sur la machine n'est pas utilisé par `gen/android/gradlew` et n'est pas un prérequis du projet.
|
||||
|
||||
Avant une commande Tauri Android, sélectionner explicitement un JDK 17 installé et vérifier la version :
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/chemin/vers/jdk-17
|
||||
"$JAVA_HOME/bin/java" -version
|
||||
```
|
||||
|
||||
Ne pas modifier `gen/android` pour contourner une incompatibilité de JDK.
|
||||
|
||||
Pour les cibles actuellement disponibles, `aarch64-linux-android` permet le smoke sur l'appareil ARM64 et `x86_64-linux-android` celui des AVD x86_64. Les autres ABI restent disponibles pour les validations multi-ABI ultérieures mais ne sont pas nécessaires au smoke courant.
|
||||
|
||||
## Initialisation locale
|
||||
|
||||
Installer les dépendances frontend dans la crate :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && npm install)
|
||||
```
|
||||
|
||||
Initialiser une fois le projet Android généré par Tauri :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android init)
|
||||
```
|
||||
|
||||
Le répertoire `gen/` produit par Tauri est généré et ignoré ; il n'appartient pas aux deltas et ne doit pas être patché par des scripts propres au jeu.
|
||||
|
||||
Si ce répertoire a été créé ou modifié par `0-pre.2.fix.1`, il est pollué par la tentative abandonnée de migration Gradle 9. Il faut alors le régénérer intégralement avec la CLI Tauri officielle, sous JDK 17 :
|
||||
|
||||
```bash
|
||||
rm -rf crates/apps/game-snake-poc-tauri/gen/android
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android init)
|
||||
```
|
||||
|
||||
L'audit de distribution vérifie désormais un `gen/android` présent et refuse un wrapper/AGP qui ne correspondent pas au template Tauri 2.11.x attendu.
|
||||
|
||||
## Smoke Android de développement
|
||||
|
||||
Lancer ensuite :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
|
||||
```
|
||||
|
||||
Choisir l'appareil réel ou l'AVD voulu lorsque la CLI le demande. Le frontend doit afficher le Canvas Snake, les compteurs score/longueur, les contrôles directionnels et les assets `snake / engine-v1`. La provenance doit évoluer depuis `android / tauri-webview / wasm / <device> / unknown` vers un profil d'entrée observé (`touch`, `keyboard-mouse` ou `mixed`) après utilisation des contrôles. Les événements de démarrage doivent apparaître dans le tracing/logcat.
|
||||
|
||||
Ne pas utiliser `npm run dev` ou `npm run build` comme gate manuelle : ces scripts sont des hooks internes possédés par Tauri. `cargo tauri android build` reste réservé au jalon de packaging prévu par le plan, sauf diagnostic explicite.
|
||||
|
||||
### Appareil Android réel via USB
|
||||
|
||||
Sur un appareil physique, Tauri remplace automatiquement le host `localhost` du `devUrl` par une adresse réseau. Pour la gate de référence, le chemin reproductible retenu évite le LAN et utilise le tunnel USB ADB sur le même port HTTP/WebSocket Vite :
|
||||
|
||||
```bash
|
||||
adb -s <serial> reverse --remove-all
|
||||
adb -s <serial> reverse tcp:1436 tcp:1436
|
||||
adb -s <serial> reverse --list
|
||||
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev --host 127.0.0.1)
|
||||
```
|
||||
|
||||
Le `serial` vient de `adb devices -l` et ne doit jamais être enregistré dans les sources. La configuration Vite utilise le port `1436` pour HTTP et WebSocket afin que le même tunnel transporte aussi le HMR. Un port HMR séparé n'appartient pas au contrat de ce POC.
|
||||
|
||||
Pour vérifier l'ABI réelle avant le smoke :
|
||||
|
||||
```bash
|
||||
adb -s <serial> shell getprop ro.product.cpu.abi
|
||||
adb -s <serial> shell getprop ro.product.cpu.abilist
|
||||
```
|
||||
|
||||
`arm64-v8a` correspond à la cible Rust `aarch64-linux-android`, tandis que les AVD utilisés jusqu'ici sont `x86_64-linux-android`.
|
||||
|
||||
## 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.
|
||||
|
||||
Sur le Galaxy S9+ ARM64 utilisé pour la validation réelle, chargement, WASM, Canvas, assets et touch fonctionnent via le tunnel USB. Un premier smoke a observé un abort natif `FORTIFY: pthread_mutex_lock called on a destroyed mutex` pendant Back/teardown ; après passage de HTTP et HMR sur le même tunnel `1436`, le smoke `0-pre.4.fix.1` ne l'a pas reproduit. La beta a ensuite construit un APK autonome universal et l'a installé/lancé sur le Galaxy S9+ ARM64 ainsi que sur l'AVD x86_64. La RC revalide ces chemins sans modifier `gen/android`.
|
||||
|
||||
## Packaging beta Android
|
||||
|
||||
À partir de `0.3.1-2-beta.1`, le packaging de validation utilise un APK Debug autonome contenant les deux ABI réellement testées par ce POC : `arm64-v8a` pour l'appareil physique et `x86_64` pour l'AVD. Le build reste possédé par Tauri ; son hook `beforeBuildCommand` construit le WASM release, génère les bindings, exécute TypeScript/Vite et copie les assets.
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/usr/lib/jvm/temurin-17-jdk-amd64
|
||||
(cd crates/apps/game-snake-poc-tauri && \
|
||||
cargo tauri android build --debug --apk --target aarch64 --target x86_64)
|
||||
```
|
||||
|
||||
Ne pas lancer `npm run build` séparément pour cette gate. Tauri affiche le chemin de l'APK produit ; les outputs sous `gen/android/**/build/` sont générés et ignorés. Vérifier ensuite que l'APK contient les bibliothèques `arm64-v8a` et `x86_64`, puis installer ce même APK successivement sur l'AVD et l'appareil réel avec `adb install -r`.
|
||||
|
||||
Le package autonome ne doit dépendre ni de Vite, ni du port `1436`, ni d'un tunnel ADB. La beta a validé sa construction et son installation/lancement sur les deux architectures de référence. La RC reprend les contrôles fonctionnels lifecycle/Back sur l'état gelé. Aucun AAB Tauri n'est requis : le futur packaging AAB appartient à la voie Android SDL3 native.
|
||||
|
||||
9
crates/apps/game-snake-poc-tauri/build.rs
Normal file
9
crates/apps/game-snake-poc-tauri/build.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/build.rs
|
||||
// version: 3
|
||||
|
||||
//! Build-time integration for the Snake Tauri host.
|
||||
|
||||
fn main() {
|
||||
tauri_build::build();
|
||||
return;
|
||||
}
|
||||
12
crates/apps/game-snake-poc-tauri/capabilities/default.json
Normal file
12
crates/apps/game-snake-poc-tauri/capabilities/default.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Default capability for the Snake Tauri Android POC",
|
||||
"windows": [
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"tracing:default"
|
||||
]
|
||||
}
|
||||
235
crates/apps/game-snake-poc-tauri/frontend/css/main.css
Normal file
235
crates/apps/game-snake-poc-tauri/frontend/css/main.css
Normal file
@@ -0,0 +1,235 @@
|
||||
/* file: crates/apps/game-snake-poc-tauri/frontend/css/main.css */
|
||||
/* version: 2 */
|
||||
|
||||
:root {
|
||||
font-family: system-ui, sans-serif;
|
||||
color-scheme: dark;
|
||||
background: #101418;
|
||||
color: #f4f7f8;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
min-width: 320px;
|
||||
min-height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
padding: max(0.75rem, env(safe-area-inset-top)) max(0.75rem, env(safe-area-inset-right)) max(0.75rem, env(safe-area-inset-bottom))
|
||||
max(0.75rem, env(safe-area-inset-left));
|
||||
background: #101418;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
.app-header,
|
||||
.app-footer,
|
||||
.game-panel,
|
||||
.control-panel {
|
||||
border: 1px solid #50606b;
|
||||
border-radius: 0.75rem;
|
||||
background: #161c21;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 0.15rem;
|
||||
color: #9fb0ba;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 0;
|
||||
font-size: clamp(1.25rem, 6vw, 1.85rem);
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 0.35rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.status-badge,
|
||||
.game-summary output {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 2rem;
|
||||
padding: 0.35rem 0.65rem;
|
||||
border-radius: 999px;
|
||||
background: #29343c;
|
||||
color: #f4f7f8;
|
||||
font-size: 0.85rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
body[data-runtime-state="ready"] .status-badge {
|
||||
background: #1d5f3d;
|
||||
}
|
||||
|
||||
body[data-runtime-state="error"] .status-badge {
|
||||
background: #7a2630;
|
||||
}
|
||||
|
||||
.app-main {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 0.75rem;
|
||||
margin-block: 0.75rem;
|
||||
}
|
||||
|
||||
.game-panel,
|
||||
.control-panel {
|
||||
min-width: 0;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.game-summary {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.game-stage {
|
||||
width: min(100%, 21rem);
|
||||
max-height: 58vh;
|
||||
margin-inline: auto;
|
||||
aspect-ratio: 3 / 5;
|
||||
overflow: hidden;
|
||||
border: 1px solid #6d7f8a;
|
||||
border-radius: 0.45rem;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
#game {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
touch-action: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#game:focus-visible {
|
||||
box-shadow: inset 0 0 0 3px #8fbfff;
|
||||
}
|
||||
|
||||
.control-panel > div:first-child p {
|
||||
margin-bottom: 0.75rem;
|
||||
color: #b9c4ca;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.direction-pad {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(3.75rem, 5rem));
|
||||
grid-template-rows: repeat(2, minmax(3.3rem, 4.2rem));
|
||||
gap: 0.45rem;
|
||||
justify-content: center;
|
||||
margin-inline: auto;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.direction-pad button {
|
||||
border: 1px solid #7892a1;
|
||||
border-radius: 0.6rem;
|
||||
background: #202b32;
|
||||
color: #f4f7f8;
|
||||
font-size: 1.45rem;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
.direction-pad button:active {
|
||||
background: #355365;
|
||||
}
|
||||
|
||||
.direction-up {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.direction-left {
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.direction-down {
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.direction-right {
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.runtime-details {
|
||||
margin: 0.9rem 0 0;
|
||||
padding-top: 0.8rem;
|
||||
border-top: 1px solid #3a474f;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.runtime-details div {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
gap: 0.75rem;
|
||||
margin-top: 0.45rem;
|
||||
}
|
||||
|
||||
.runtime-details dt {
|
||||
color: #a9b6bd;
|
||||
}
|
||||
|
||||
.runtime-details dd {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
overflow-wrap: anywhere;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.startup-error {
|
||||
margin: 0.9rem 0 0;
|
||||
padding: 0.65rem;
|
||||
border: 1px solid #b34b57;
|
||||
border-radius: 0.5rem;
|
||||
background: #51232a;
|
||||
}
|
||||
|
||||
.app-footer {
|
||||
padding: 0.55rem 0.75rem;
|
||||
color: #a9b6bd;
|
||||
font-size: 0.75rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 760px) {
|
||||
.app-main {
|
||||
grid-template-columns: minmax(18rem, 1fr) minmax(17rem, 22rem);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.game-stage {
|
||||
width: min(100%, 24rem);
|
||||
max-height: 70vh;
|
||||
}
|
||||
}
|
||||
59
crates/apps/game-snake-poc-tauri/frontend/main.html
Normal file
59
crates/apps/game-snake-poc-tauri/frontend/main.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!-- file: crates/apps/game-snake-poc-tauri/frontend/main.html -->
|
||||
<!-- version: 2 -->
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||
<meta name="theme-color" content="#101418" />
|
||||
<title>Snake POC — Tauri Android</title>
|
||||
</head>
|
||||
<body>
|
||||
<header class="app-header">
|
||||
<div>
|
||||
<p class="eyebrow">games.sasedev</p>
|
||||
<h1>Snake — Tauri Android</h1>
|
||||
</div>
|
||||
<span id="runtime-status" class="status-badge" role="status" aria-live="polite">Initialisation…</span>
|
||||
</header>
|
||||
|
||||
<main class="app-main">
|
||||
<section class="game-panel" aria-label="Partie Snake">
|
||||
<div class="game-summary">
|
||||
<output id="score">Score : 0</output>
|
||||
<output id="length">Longueur : 0</output>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
<aside class="control-panel" aria-label="Contrôles et runtime">
|
||||
<div>
|
||||
<h2>Contrôles</h2>
|
||||
<p>Flèches, WASD/ZQSD ou boutons tactiles.</p>
|
||||
</div>
|
||||
<div class="direction-pad" aria-label="Contrôles directionnels tactiles">
|
||||
<button class="direction-up" type="button" data-direction="up" aria-label="Haut">↑</button>
|
||||
<button class="direction-left" type="button" data-direction="left" aria-label="Gauche">←</button>
|
||||
<button class="direction-down" type="button" data-direction="down" aria-label="Bas">↓</button>
|
||||
<button class="direction-right" type="button" data-direction="right" aria-label="Droite">→</button>
|
||||
</div>
|
||||
<dl class="runtime-details">
|
||||
<div>
|
||||
<dt>Provenance</dt>
|
||||
<dd><output id="runtime-provenance">android / tauri-webview / wasm / unknown / unknown</output></dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Assets</dt>
|
||||
<dd><output id="asset-status">chargement…</output></dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p id="startup-error" class="startup-error" role="alert" hidden></p>
|
||||
</aside>
|
||||
</main>
|
||||
|
||||
<footer class="app-footer">POC de référence Tauri Android — gameplay Rust partagé</footer>
|
||||
<script type="module" src="/ts/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
54
crates/apps/game-snake-poc-tauri/frontend/ts/assets.ts
Normal file
54
crates/apps/game-snake-poc-tauri/frontend/ts/assets.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/assets.ts
|
||||
// version: 1
|
||||
|
||||
export interface SnakeTauriAssets {
|
||||
engineGeneration: number;
|
||||
game: string;
|
||||
gameKind: string;
|
||||
}
|
||||
|
||||
interface CommonRuntimeAsset {
|
||||
schema: number;
|
||||
scope: string;
|
||||
engine_generation: number;
|
||||
}
|
||||
|
||||
interface GameRuntimeAsset {
|
||||
schema: number;
|
||||
game: string;
|
||||
kind: string;
|
||||
}
|
||||
|
||||
async function fetchJson<T>(relativePath: string): Promise<T> {
|
||||
const response = await fetch(new URL(relativePath, document.baseURI));
|
||||
if (!response.ok) {
|
||||
throw new Error(`Asset runtime indisponible (${response.status}) : ${relativePath}`);
|
||||
}
|
||||
return (await response.json()) as T;
|
||||
}
|
||||
|
||||
function validateCommonRuntime(asset: CommonRuntimeAsset): void {
|
||||
if (asset.schema !== 1 || asset.scope !== "common" || asset.engine_generation !== 1) {
|
||||
throw new Error("Asset common://data/runtime.json invalide pour le POC Tauri Snake.");
|
||||
}
|
||||
}
|
||||
|
||||
function validateGameRuntime(asset: GameRuntimeAsset): void {
|
||||
if (asset.schema !== 1 || asset.game !== "game-snake-poc" || asset.kind !== "snake") {
|
||||
throw new Error("Asset game://data/game.json invalide pour le POC Tauri Snake.");
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadSnakeTauriAssets(): Promise<SnakeTauriAssets> {
|
||||
const [commonRuntime, gameRuntime] = await Promise.all([
|
||||
fetchJson<CommonRuntimeAsset>("./common/data/runtime.json"),
|
||||
fetchJson<GameRuntimeAsset>("./game/data/game.json"),
|
||||
]);
|
||||
validateCommonRuntime(commonRuntime);
|
||||
validateGameRuntime(gameRuntime);
|
||||
return {
|
||||
engineGeneration: commonRuntime.engine_generation,
|
||||
game: gameRuntime.game,
|
||||
gameKind: gameRuntime.kind,
|
||||
};
|
||||
}
|
||||
20
crates/apps/game-snake-poc-tauri/frontend/ts/bridge.ts
Normal file
20
crates/apps/game-snake-poc-tauri/frontend/ts/bridge.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/bridge.ts
|
||||
// version: 1
|
||||
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
export interface RuntimeDescriptor {
|
||||
deviceClass: string;
|
||||
executionModel: string;
|
||||
inputProfile: string;
|
||||
platformFamily: string;
|
||||
runtimeHost: string;
|
||||
}
|
||||
|
||||
export async function getRuntimeDescriptor(): Promise<RuntimeDescriptor> {
|
||||
return await invoke<RuntimeDescriptor>("get_runtime_descriptor");
|
||||
}
|
||||
|
||||
export async function reportFrontendReady(): Promise<void> {
|
||||
await invoke("frontend_ready");
|
||||
}
|
||||
182
crates/apps/game-snake-poc-tauri/frontend/ts/game.ts
Normal file
182
crates/apps/game-snake-poc-tauri/frontend/ts/game.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/game.ts
|
||||
// version: 2
|
||||
|
||||
import init, { SnakeWasmGame } from "@snake-wasm";
|
||||
import type { RuntimeDescriptor } from "./bridge";
|
||||
import { frontendInfo } from "./logging";
|
||||
import { TauriRuntimeProvenance, type SnakeInputSource } from "./provenance";
|
||||
|
||||
const FRAME_MILLIS = 16;
|
||||
const MAX_FRAME_ELAPSED_MILLIS = 250;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
function color(red: number, green: number, blue: number): string {
|
||||
return `rgb(${red} ${green} ${blue})`;
|
||||
}
|
||||
|
||||
function resizeCanvas(canvas: HTMLCanvasElement): void {
|
||||
const ratio = window.devicePixelRatio || 1;
|
||||
const width = Math.max(1, Math.floor(canvas.clientWidth * ratio));
|
||||
const height = Math.max(1, Math.floor(canvas.clientHeight * ratio));
|
||||
if (canvas.width !== width || canvas.height !== height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
function render(
|
||||
game: SnakeWasmGame,
|
||||
canvas: HTMLCanvasElement,
|
||||
context: CanvasRenderingContext2D,
|
||||
score: HTMLOutputElement,
|
||||
length: HTMLOutputElement,
|
||||
): void {
|
||||
resizeCanvas(canvas);
|
||||
context.fillStyle = color(game.background_red(), game.background_green(), game.background_blue());
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
const count = game.rectangle_count();
|
||||
for (let index = 0; index < count; index += 1) {
|
||||
context.fillStyle = color(game.rectangle_red(index), game.rectangle_green(index), game.rectangle_blue(index));
|
||||
context.fillRect(
|
||||
game.rectangle_x(index) * canvas.width,
|
||||
game.rectangle_y(index) * canvas.height,
|
||||
game.rectangle_width(index) * canvas.width,
|
||||
game.rectangle_height(index) * canvas.height,
|
||||
);
|
||||
}
|
||||
score.value = `Score : ${game.score()}`;
|
||||
length.value = `Longueur : ${game.length()}`;
|
||||
}
|
||||
|
||||
function queueDirection(game: SnakeWasmGame, direction: SnakeDirection): void {
|
||||
switch (direction) {
|
||||
case "left":
|
||||
game.left();
|
||||
return;
|
||||
case "right":
|
||||
game.right();
|
||||
return;
|
||||
case "up":
|
||||
game.up();
|
||||
return;
|
||||
case "down":
|
||||
game.down();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export async function startGame(
|
||||
canvas: HTMLCanvasElement,
|
||||
score: HTMLOutputElement,
|
||||
length: HTMLOutputElement,
|
||||
provenanceOutput: HTMLOutputElement,
|
||||
descriptor: RuntimeDescriptor,
|
||||
): Promise<SnakeTauriSession> {
|
||||
await init();
|
||||
frontendInfo("Snake Tauri WASM initialized");
|
||||
const context = canvas.getContext("2d");
|
||||
if (context === null) {
|
||||
throw new Error("Le contexte Canvas 2D est indisponible.");
|
||||
}
|
||||
const renderingContext: CanvasRenderingContext2D = context;
|
||||
const game = new SnakeWasmGame();
|
||||
const provenance = new TauriRuntimeProvenance(game, provenanceOutput, descriptor);
|
||||
let previous = performance.now();
|
||||
let accumulator = 0;
|
||||
let animationFrame: number | null = null;
|
||||
let running = false;
|
||||
let disposed = false;
|
||||
|
||||
function renderNow(): void {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
render(game, canvas, renderingContext, score, length);
|
||||
}
|
||||
|
||||
function schedule(): void {
|
||||
if (!running || disposed || animationFrame !== null) {
|
||||
return;
|
||||
}
|
||||
animationFrame = window.requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
function frame(now: number): void {
|
||||
animationFrame = null;
|
||||
if (!running || disposed) {
|
||||
return;
|
||||
}
|
||||
const elapsed = Math.min(Math.max(0, now - previous), MAX_FRAME_ELAPSED_MILLIS);
|
||||
previous = now;
|
||||
accumulator += elapsed;
|
||||
while (accumulator >= FRAME_MILLIS) {
|
||||
game.tick();
|
||||
accumulator -= FRAME_MILLIS;
|
||||
}
|
||||
renderNow();
|
||||
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();
|
||||
resume();
|
||||
return {
|
||||
queueDirection(direction: SnakeDirection, source: SnakeInputSource): void {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
provenance.recordInput(source);
|
||||
queueDirection(game, direction);
|
||||
},
|
||||
pause,
|
||||
resume,
|
||||
renderNow,
|
||||
refreshDeviceClass(): void {
|
||||
if (!disposed) {
|
||||
provenance.refreshDeviceClass();
|
||||
}
|
||||
},
|
||||
dispose(): void {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
pause();
|
||||
disposed = true;
|
||||
game.free();
|
||||
frontendInfo("Snake Tauri runtime disposed");
|
||||
},
|
||||
};
|
||||
}
|
||||
57
crates/apps/game-snake-poc-tauri/frontend/ts/input.ts
Normal file
57
crates/apps/game-snake-poc-tauri/frontend/ts/input.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/input.ts
|
||||
// version: 1
|
||||
|
||||
import type { SnakeDirection, SnakeTauriSession } from "./game";
|
||||
|
||||
const KEY_DIRECTIONS: Readonly<Record<string, SnakeDirection>> = {
|
||||
arrowleft: "left",
|
||||
a: "left",
|
||||
q: "left",
|
||||
arrowright: "right",
|
||||
d: "right",
|
||||
arrowup: "up",
|
||||
w: "up",
|
||||
z: "up",
|
||||
arrowdown: "down",
|
||||
s: "down",
|
||||
};
|
||||
|
||||
function buttonDirection(button: HTMLButtonElement): SnakeDirection | null {
|
||||
const direction = button.dataset.direction;
|
||||
if (direction === "left" || direction === "right" || direction === "up" || direction === "down") {
|
||||
return direction;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function bindInputs(session: SnakeTauriSession, buttons: readonly HTMLButtonElement[]): void {
|
||||
window.addEventListener("keydown", event => {
|
||||
if (event.repeat) {
|
||||
return;
|
||||
}
|
||||
const direction = KEY_DIRECTIONS[event.key.toLowerCase()];
|
||||
if (direction === undefined) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
session.queueDirection(direction, "keyboard-mouse");
|
||||
});
|
||||
|
||||
for (const button of buttons) {
|
||||
const direction = buttonDirection(button);
|
||||
if (direction === null) {
|
||||
continue;
|
||||
}
|
||||
button.addEventListener("pointerdown", event => {
|
||||
event.preventDefault();
|
||||
const source = event.pointerType === "touch" ? "touch" : "keyboard-mouse";
|
||||
session.queueDirection(direction, source);
|
||||
});
|
||||
button.addEventListener("click", event => {
|
||||
if (event.detail !== 0) {
|
||||
return;
|
||||
}
|
||||
session.queueDirection(direction, "keyboard-mouse");
|
||||
});
|
||||
}
|
||||
}
|
||||
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();
|
||||
},
|
||||
};
|
||||
}
|
||||
16
crates/apps/game-snake-poc-tauri/frontend/ts/logging.ts
Normal file
16
crates/apps/game-snake-poc-tauri/frontend/ts/logging.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/logging.ts
|
||||
// version: 1
|
||||
|
||||
import { attachConsole, error, info } from "@fltsci/tauri-plugin-tracing";
|
||||
|
||||
export async function initializeFrontendTracing(): Promise<void> {
|
||||
await attachConsole();
|
||||
}
|
||||
|
||||
export function frontendInfo(message: string): void {
|
||||
info(message);
|
||||
}
|
||||
|
||||
export function frontendError(message: string): void {
|
||||
error(message);
|
||||
}
|
||||
65
crates/apps/game-snake-poc-tauri/frontend/ts/main.ts
Normal file
65
crates/apps/game-snake-poc-tauri/frontend/ts/main.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/main.ts
|
||||
// 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 {
|
||||
const element = document.getElementById(identifier);
|
||||
if (element === null) {
|
||||
throw new Error(`Élément frontend requis absent : ${identifier}`);
|
||||
}
|
||||
return element as T;
|
||||
}
|
||||
|
||||
async function bootstrap(): Promise<void> {
|
||||
await initializeFrontendTracing();
|
||||
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");
|
||||
const assets = requiredElement<HTMLOutputElement>("asset-status");
|
||||
const status = requiredElement<HTMLSpanElement>("runtime-status");
|
||||
const error = requiredElement<HTMLParagraphElement>("startup-error");
|
||||
const buttons = Array.from(document.querySelectorAll<HTMLButtonElement>("[data-direction]"));
|
||||
|
||||
status.textContent = "Chargement assets…";
|
||||
const assetMetadata = await loadSnakeTauriAssets();
|
||||
assets.value = `${assetMetadata.gameKind} / engine-v${assetMetadata.engineGeneration}`;
|
||||
frontendInfo(`Snake Tauri assets ready: ${assetMetadata.game} / ${assets.value}`);
|
||||
|
||||
status.textContent = "Chargement WASM…";
|
||||
const session = await startGame(canvas, score, length, provenance, descriptor);
|
||||
bindInputs(session, buttons);
|
||||
bindTauriLifecycle(session, stage);
|
||||
|
||||
document.body.dataset.runtimeState = "ready";
|
||||
status.textContent = "Prêt";
|
||||
error.hidden = true;
|
||||
canvas.focus();
|
||||
await reportFrontendReady();
|
||||
frontendInfo(`Snake Tauri frontend ready: ${provenance.value}`);
|
||||
}
|
||||
|
||||
void bootstrap().catch(reason => {
|
||||
const message = reason instanceof Error ? reason.stack ?? reason.message : String(reason);
|
||||
document.body.dataset.runtimeState = "error";
|
||||
const status = document.getElementById("runtime-status");
|
||||
const error = document.getElementById("startup-error");
|
||||
if (status !== null) {
|
||||
status.textContent = "Erreur";
|
||||
}
|
||||
if (error !== null) {
|
||||
error.textContent = `Impossible de démarrer Snake : ${message}`;
|
||||
error.hidden = false;
|
||||
}
|
||||
frontendError(`Snake Tauri frontend bootstrap failed: ${message}`);
|
||||
});
|
||||
97
crates/apps/game-snake-poc-tauri/frontend/ts/provenance.ts
Normal file
97
crates/apps/game-snake-poc-tauri/frontend/ts/provenance.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/frontend/ts/provenance.ts
|
||||
// version: 1
|
||||
|
||||
import type { SnakeWasmGame } from "@snake-wasm";
|
||||
import type { RuntimeDescriptor } from "./bridge";
|
||||
import { frontendInfo } from "./logging";
|
||||
|
||||
export type SnakeInputSource = "keyboard-mouse" | "touch";
|
||||
|
||||
type DeviceClass = "desktop" | "phone" | "tablet" | "unknown";
|
||||
type InputProfile = "keyboard-mouse" | "mixed" | "touch" | "unknown";
|
||||
|
||||
function detectedDeviceClass(): DeviceClass {
|
||||
const coarsePointer = window.matchMedia("(pointer: coarse)").matches;
|
||||
const finePointer = window.matchMedia("(pointer: fine)").matches;
|
||||
if (!coarsePointer || finePointer) {
|
||||
return "desktop";
|
||||
}
|
||||
const shortEdge = Math.min(window.screen.width, window.screen.height);
|
||||
if (!Number.isFinite(shortEdge) || shortEdge <= 0) {
|
||||
return "unknown";
|
||||
}
|
||||
return shortEdge < 768 ? "phone" : "tablet";
|
||||
}
|
||||
|
||||
function inputProfile(keyboardMouseObserved: boolean, touchObserved: boolean): InputProfile {
|
||||
if (keyboardMouseObserved && touchObserved) {
|
||||
return "mixed";
|
||||
}
|
||||
if (keyboardMouseObserved) {
|
||||
return "keyboard-mouse";
|
||||
}
|
||||
if (touchObserved) {
|
||||
return "touch";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
function displayLabel(game: SnakeWasmGame): string {
|
||||
return [
|
||||
game.provenance_platform_family(),
|
||||
game.provenance_runtime_host(),
|
||||
game.provenance_execution_model(),
|
||||
game.provenance_device_class(),
|
||||
game.provenance_input_profile(),
|
||||
].join(" / ");
|
||||
}
|
||||
|
||||
export class TauriRuntimeProvenance {
|
||||
private keyboardMouseObserved = false;
|
||||
private touchObserved = false;
|
||||
private deviceClass: DeviceClass = detectedDeviceClass();
|
||||
|
||||
public constructor(
|
||||
private readonly game: SnakeWasmGame,
|
||||
private readonly output: HTMLOutputElement,
|
||||
private readonly descriptor: RuntimeDescriptor,
|
||||
) {
|
||||
if (descriptor.executionModel !== "wasm") {
|
||||
throw new Error(`Modèle d'exécution Tauri inattendu : ${descriptor.executionModel}`);
|
||||
}
|
||||
this.synchronize();
|
||||
}
|
||||
|
||||
public recordInput(source: SnakeInputSource): void {
|
||||
if (source === "touch") {
|
||||
if (this.touchObserved) {
|
||||
return;
|
||||
}
|
||||
this.touchObserved = true;
|
||||
} else {
|
||||
if (this.keyboardMouseObserved) {
|
||||
return;
|
||||
}
|
||||
this.keyboardMouseObserved = true;
|
||||
}
|
||||
this.synchronize();
|
||||
}
|
||||
|
||||
public refreshDeviceClass(): void {
|
||||
const nextDeviceClass = detectedDeviceClass();
|
||||
if (nextDeviceClass === this.deviceClass) {
|
||||
return;
|
||||
}
|
||||
this.deviceClass = nextDeviceClass;
|
||||
this.synchronize();
|
||||
}
|
||||
|
||||
private synchronize(): void {
|
||||
const profile = inputProfile(this.keyboardMouseObserved, this.touchObserved);
|
||||
if (!this.game.configure_runtime_provenance(this.descriptor.platformFamily, this.descriptor.runtimeHost, this.deviceClass, profile)) {
|
||||
throw new Error("La provenance Tauri Android n'a pas pu être configurée dans le bridge WASM.");
|
||||
}
|
||||
this.output.value = displayLabel(this.game);
|
||||
frontendInfo(`Snake Tauri provenance: ${this.output.value}`);
|
||||
}
|
||||
}
|
||||
BIN
crates/apps/game-snake-poc-tauri/icons/icon.png
Normal file
BIN
crates/apps/game-snake-poc-tauri/icons/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 242 B |
22
crates/apps/game-snake-poc-tauri/package.json
Normal file
22
crates/apps/game-snake-poc-tauri/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "game-snake-poc-tauri",
|
||||
"private": true,
|
||||
"version": "0.3.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"wasm:dev": "cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown && wasm-bindgen ../../../../builds/sasedev-games/target/wasm32-unknown-unknown/debug/game_snake_poc_wasm.wasm --target web --out-dir ../../../../builds/sasedev-games/game-snake-poc-tauri/wasm --out-name game_snake_poc_wasm",
|
||||
"wasm:build": "cargo build -p game-snake-poc-wasm --release --target wasm32-unknown-unknown && wasm-bindgen ../../../../builds/sasedev-games/target/wasm32-unknown-unknown/release/game_snake_poc_wasm.wasm --target web --out-dir ../../../../builds/sasedev-games/game-snake-poc-tauri/wasm --out-name game_snake_poc_wasm",
|
||||
"dev": "npm run wasm:dev && vite",
|
||||
"build": "npm run wasm:build && tsc && vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fltsci/tauri-plugin-tracing": "^0.3",
|
||||
"@tauri-apps/api": "^2.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^26.1",
|
||||
"typescript": "^7.0",
|
||||
"vite": "^8.2",
|
||||
"vite-plugin-static-copy": "^4.1"
|
||||
}
|
||||
}
|
||||
21
crates/apps/game-snake-poc-tauri/src/lib.rs
Normal file
21
crates/apps/game-snake-poc-tauri/src/lib.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/src/lib.rs
|
||||
// version: 1
|
||||
|
||||
//! Tauri Android application facade for the Snake WebAssembly POC.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
mod runtime;
|
||||
mod tauri;
|
||||
|
||||
/// Runs the Snake Tauri application.
|
||||
pub use self::tauri::run;
|
||||
|
||||
/// Runtime descriptor exposed by the native Tauri bridge.
|
||||
pub(crate) use self::runtime::RuntimeDescriptorDto;
|
||||
/// Records that the Tauri frontend completed its minimal startup sequence.
|
||||
pub(crate) use self::runtime::record_frontend_ready;
|
||||
/// Returns the canonical runtime descriptor for the Android WebView host.
|
||||
pub(crate) use self::runtime::runtime_descriptor;
|
||||
20
crates/apps/game-snake-poc-tauri/src/main.rs
Normal file
20
crates/apps/game-snake-poc-tauri/src/main.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/src/main.rs
|
||||
// version: 1
|
||||
|
||||
//! Binary entry point for host-side Snake Tauri checks.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() -> std::process::ExitCode {
|
||||
let result = game_snake_poc_tauri_lib::run();
|
||||
return match result {
|
||||
std::result::Result::Ok(()) => std::process::ExitCode::SUCCESS,
|
||||
std::result::Result::Err(error) => {
|
||||
eprintln!("Snake Tauri application error: {error}");
|
||||
std::process::ExitCode::FAILURE
|
||||
},
|
||||
};
|
||||
}
|
||||
87
crates/apps/game-snake-poc-tauri/src/runtime.rs
Normal file
87
crates/apps/game-snake-poc-tauri/src/runtime.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/src/runtime.rs
|
||||
// version: 1
|
||||
|
||||
/// Stable runtime dimensions exposed to the Tauri frontend.
|
||||
#[derive(Clone, Debug, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct RuntimeDescriptorDto {
|
||||
device_class: String,
|
||||
execution_model: String,
|
||||
input_profile: String,
|
||||
platform_family: String,
|
||||
runtime_host: String,
|
||||
}
|
||||
|
||||
/// Returns the canonical runtime descriptor for the Android WebView host.
|
||||
pub(crate) fn runtime_descriptor() -> RuntimeDescriptorDto {
|
||||
let provenance = engine_v1_platform_api::RuntimeProvenance::new(
|
||||
engine_v1_platform_api::DeviceClass::Unknown,
|
||||
engine_v1_platform_api::ExecutionModel::Wasm,
|
||||
engine_v1_platform_api::InputProfile::Unknown,
|
||||
engine_v1_platform_api::PlatformFamily::Android,
|
||||
engine_v1_platform_api::RuntimeHost::TauriWebView,
|
||||
);
|
||||
return RuntimeDescriptorDto {
|
||||
device_class: device_class_label(provenance.device_class()).to_string(),
|
||||
execution_model: execution_model_label(provenance.execution_model()).to_string(),
|
||||
input_profile: input_profile_label(provenance.input_profile()).to_string(),
|
||||
platform_family: platform_family_label(provenance.platform_family()).to_string(),
|
||||
runtime_host: runtime_host_label(provenance.runtime_host()).to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Records that the Tauri frontend completed its minimal startup sequence.
|
||||
pub(crate) fn record_frontend_ready() {
|
||||
let descriptor = crate::runtime_descriptor();
|
||||
tracing::info!(
|
||||
target: "games::tauri::snake",
|
||||
action = "frontend_ready",
|
||||
platform_family = descriptor.platform_family,
|
||||
runtime_host = descriptor.runtime_host,
|
||||
execution_model = descriptor.execution_model,
|
||||
"Snake Tauri frontend ready"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
fn device_class_label(value: engine_v1_platform_api::DeviceClass) -> &'static str {
|
||||
return match value {
|
||||
engine_v1_platform_api::DeviceClass::Desktop => "desktop",
|
||||
engine_v1_platform_api::DeviceClass::Phone => "phone",
|
||||
engine_v1_platform_api::DeviceClass::Tablet => "tablet",
|
||||
engine_v1_platform_api::DeviceClass::Unknown => "unknown",
|
||||
};
|
||||
}
|
||||
|
||||
fn execution_model_label(value: engine_v1_platform_api::ExecutionModel) -> &'static str {
|
||||
return match value {
|
||||
engine_v1_platform_api::ExecutionModel::Native => "native",
|
||||
engine_v1_platform_api::ExecutionModel::Wasm => "wasm",
|
||||
};
|
||||
}
|
||||
|
||||
fn input_profile_label(value: engine_v1_platform_api::InputProfile) -> &'static str {
|
||||
return match value {
|
||||
engine_v1_platform_api::InputProfile::Gamepad => "gamepad",
|
||||
engine_v1_platform_api::InputProfile::KeyboardMouse => "keyboard-mouse",
|
||||
engine_v1_platform_api::InputProfile::Mixed => "mixed",
|
||||
engine_v1_platform_api::InputProfile::Touch => "touch",
|
||||
engine_v1_platform_api::InputProfile::Unknown => "unknown",
|
||||
};
|
||||
}
|
||||
|
||||
fn platform_family_label(value: engine_v1_platform_api::PlatformFamily) -> &'static str {
|
||||
return match value {
|
||||
engine_v1_platform_api::PlatformFamily::Android => "android",
|
||||
engine_v1_platform_api::PlatformFamily::Desktop => "desktop",
|
||||
engine_v1_platform_api::PlatformFamily::Web => "web",
|
||||
};
|
||||
}
|
||||
|
||||
fn runtime_host_label(value: engine_v1_platform_api::RuntimeHost) -> &'static str {
|
||||
return match value {
|
||||
engine_v1_platform_api::RuntimeHost::Browser => "browser",
|
||||
engine_v1_platform_api::RuntimeHost::Native => "native",
|
||||
engine_v1_platform_api::RuntimeHost::TauriWebView => "tauri-webview",
|
||||
};
|
||||
}
|
||||
85
crates/apps/game-snake-poc-tauri/src/tauri.rs
Normal file
85
crates/apps/game-snake-poc-tauri/src/tauri.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/src/tauri.rs
|
||||
// version: 2
|
||||
|
||||
//! Tauri runtime assembly and Web/Rust commands for the Snake Android POC.
|
||||
|
||||
#[tauri::command]
|
||||
fn get_runtime_descriptor() -> crate::RuntimeDescriptorDto {
|
||||
return crate::runtime_descriptor();
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn frontend_ready() {
|
||||
crate::record_frontend_ready();
|
||||
return;
|
||||
}
|
||||
|
||||
fn configure_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
||||
let tracing_plugin = tauri_plugin_tracing::Builder::new().build::<tauri::Wry>();
|
||||
return builder.plugin(tracing_plugin);
|
||||
}
|
||||
|
||||
#[allow(clippy::question_mark_used)] // Tauri generates the question-mark operator internally for command dispatch.
|
||||
fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
||||
return builder.invoke_handler(tauri::generate_handler![get_runtime_descriptor, frontend_ready]);
|
||||
}
|
||||
|
||||
fn run_runtime() -> 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::snake",
|
||||
action = "runtime_start",
|
||||
platform_family = "android",
|
||||
runtime_host = "tauri-webview",
|
||||
execution_model = "wasm",
|
||||
"Starting Snake Tauri Android runtime"
|
||||
);
|
||||
let builder = tauri::Builder::default();
|
||||
let builder = configure_plugins(builder);
|
||||
let builder = configure_commands(builder);
|
||||
return match builder.run(tauri::generate_context!()) {
|
||||
std::result::Result::Ok(()) => {
|
||||
tracing::info!(
|
||||
target: "games::tauri::snake",
|
||||
action = "runtime_stop",
|
||||
"Snake Tauri runtime stopped"
|
||||
);
|
||||
std::result::Result::Ok(())
|
||||
},
|
||||
std::result::Result::Err(error) => {
|
||||
tracing::error!(
|
||||
target: "games::tauri::snake",
|
||||
action = "runtime_error",
|
||||
error = error.to_string(),
|
||||
"Snake Tauri runtime failed"
|
||||
);
|
||||
std::result::Result::Err(error.to_string())
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Runs the Snake Tauri application on a desktop host.
|
||||
#[cfg(not(mobile))]
|
||||
pub fn run() -> std::result::Result<(), String> {
|
||||
return run_runtime();
|
||||
}
|
||||
|
||||
/// Runs the Snake Tauri application from Tauri's mobile entry point.
|
||||
#[cfg(mobile)]
|
||||
#[tauri::mobile_entry_point]
|
||||
pub fn run() {
|
||||
let result = run_runtime();
|
||||
if let std::result::Result::Err(error) = result {
|
||||
tracing::error!(
|
||||
target: "games::tauri::snake",
|
||||
action = "mobile_entrypoint_error",
|
||||
error = error.as_str(),
|
||||
"Snake Tauri mobile entry point terminated after a runtime error"
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
41
crates/apps/game-snake-poc-tauri/tauri.conf.json
Normal file
41
crates/apps/game-snake-poc-tauri/tauri.conf.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Snake POC Tauri",
|
||||
"identifier": "com.sasedev.games.snake.tauri",
|
||||
"build": {
|
||||
"beforeDevCommand": {
|
||||
"script": "npm run dev",
|
||||
"cwd": "."
|
||||
},
|
||||
"devUrl": "http://localhost:1436",
|
||||
"beforeBuildCommand": {
|
||||
"script": "npm run build",
|
||||
"cwd": "."
|
||||
},
|
||||
"frontendDist": "../../../../builds/sasedev-games/game-snake-poc-tauri/dist"
|
||||
},
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"label": "main",
|
||||
"url": "main.html",
|
||||
"title": "Snake POC Tauri",
|
||||
"width": 405,
|
||||
"height": 720,
|
||||
"minWidth": 320,
|
||||
"minHeight": 480,
|
||||
"resizable": true,
|
||||
"center": true
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": false,
|
||||
"icon": [
|
||||
"icons/icon.png"
|
||||
]
|
||||
}
|
||||
}
|
||||
36
crates/apps/game-snake-poc-tauri/tsconfig.json
Normal file
36
crates/apps/game-snake-poc-tauri/tsconfig.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": [
|
||||
"ES2022",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"types": [
|
||||
"vite/client",
|
||||
"node"
|
||||
],
|
||||
"paths": {
|
||||
"@snake-wasm": [
|
||||
"../../../../builds/sasedev-games/game-snake-poc-tauri/wasm/game_snake_poc_wasm.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"frontend",
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
84
crates/apps/game-snake-poc-tauri/vite.config.ts
Normal file
84
crates/apps/game-snake-poc-tauri/vite.config.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/vite.config.ts
|
||||
// version: 3
|
||||
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { resolve } from "node:path";
|
||||
import { defineConfig, normalizePath } from "vite";
|
||||
import { viteStaticCopy } from "vite-plugin-static-copy";
|
||||
|
||||
const appRoot = fileURLToPath(new URL(".", import.meta.url));
|
||||
const repositoryRoot = normalizePath(resolve(appRoot, "../../.."));
|
||||
const frontendRoot = normalizePath(resolve(appRoot, "frontend"));
|
||||
const externalBuildRoot = normalizePath(resolve(repositoryRoot, "../builds/sasedev-games/game-snake-poc-tauri"));
|
||||
const wasmRoot = normalizePath(resolve(externalBuildRoot, "wasm"));
|
||||
const wasmModule = normalizePath(resolve(wasmRoot, "game_snake_poc_wasm.js"));
|
||||
const frontendDist = normalizePath(resolve(externalBuildRoot, "dist"));
|
||||
const viteCacheDir = normalizePath(resolve(externalBuildRoot, "vite-cache"));
|
||||
const commonRuntimeAsset = normalizePath(resolve(repositoryRoot, "assets/common/data/runtime.json"));
|
||||
const gameRuntimeAsset = normalizePath(resolve(repositoryRoot, "assets/game-snake-poc/data/game.json"));
|
||||
const devHost = process.env.TAURI_DEV_HOST;
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
{ src: commonRuntimeAsset, dest: "common/data", rename: { stripBase: true } },
|
||||
{ src: gameRuntimeAsset, dest: "game/data", rename: { stripBase: true } },
|
||||
],
|
||||
}),
|
||||
],
|
||||
base: "./",
|
||||
cacheDir: viteCacheDir,
|
||||
clearScreen: false,
|
||||
root: frontendRoot,
|
||||
publicDir: false,
|
||||
input: {
|
||||
main: normalizePath(resolve(frontendRoot, "main.html")),
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"@snake-wasm": wasmModule,
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: frontendDist,
|
||||
emptyOutDir: true,
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
cssCodeSplit: true,
|
||||
rolldownOptions: {
|
||||
output: {
|
||||
entryFileNames: "js/[name]-[hash].js",
|
||||
chunkFileNames: "js/chunks/[name]-[hash].js",
|
||||
assetFileNames: assetInfo => {
|
||||
const originalName = assetInfo.names[0] ?? "";
|
||||
const extension = originalName.substring(originalName.lastIndexOf(".") + 1).toLowerCase();
|
||||
if (extension === "css") {
|
||||
return "css/[name]-[hash][extname]";
|
||||
}
|
||||
if (extension === "wasm") {
|
||||
return "wasm/[name]-[hash][extname]";
|
||||
}
|
||||
return "otherassets/[name][extname]";
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 1436,
|
||||
strictPort: true,
|
||||
host: devHost || false,
|
||||
fs: {
|
||||
allow: [appRoot, repositoryRoot, externalBuildRoot],
|
||||
},
|
||||
ws: {
|
||||
protocol: "ws",
|
||||
host: devHost || "127.0.0.1",
|
||||
port: 1436,
|
||||
clientPort: 1436,
|
||||
},
|
||||
watch: {
|
||||
ignored: ["**/src/**"],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/apps/game-snake-poc-wasm/src/runtime.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
const FIXED_STEP_MILLIS: u64 = 16;
|
||||
|
||||
@@ -31,8 +31,16 @@ impl SnakeWasmGame {
|
||||
};
|
||||
}
|
||||
|
||||
/// Updates browser-observed device and input dimensions while preserving Web/WASM/Browser provenance.
|
||||
pub fn configure_runtime_provenance(&mut self, device_class: &str, input_profile: &str) -> bool {
|
||||
/// Updates host-observed runtime provenance while preserving WebAssembly execution.
|
||||
pub fn configure_runtime_provenance(&mut self, platform_family: &str, runtime_host: &str, device_class: &str, input_profile: &str) -> bool {
|
||||
let platform_family = match parse_platform_family(platform_family) {
|
||||
Some(value) => value,
|
||||
None => return false,
|
||||
};
|
||||
let runtime_host = match parse_runtime_host(runtime_host) {
|
||||
Some(value) => value,
|
||||
None => return false,
|
||||
};
|
||||
let device_class = match parse_device_class(device_class) {
|
||||
Some(value) => value,
|
||||
None => return false,
|
||||
@@ -45,8 +53,8 @@ impl SnakeWasmGame {
|
||||
device_class,
|
||||
engine_v1_platform_api::ExecutionModel::Wasm,
|
||||
input_profile,
|
||||
engine_v1_platform_api::PlatformFamily::Web,
|
||||
engine_v1_platform_api::RuntimeHost::Browser,
|
||||
platform_family,
|
||||
runtime_host,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -236,6 +244,24 @@ impl SnakeWasmGame {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_platform_family(label: &str) -> Option<engine_v1_platform_api::PlatformFamily> {
|
||||
return match label {
|
||||
"android" => Some(engine_v1_platform_api::PlatformFamily::Android),
|
||||
"desktop" => Some(engine_v1_platform_api::PlatformFamily::Desktop),
|
||||
"web" => Some(engine_v1_platform_api::PlatformFamily::Web),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_runtime_host(label: &str) -> Option<engine_v1_platform_api::RuntimeHost> {
|
||||
return match label {
|
||||
"browser" => Some(engine_v1_platform_api::RuntimeHost::Browser),
|
||||
"native" => Some(engine_v1_platform_api::RuntimeHost::Native),
|
||||
"tauri-webview" => Some(engine_v1_platform_api::RuntimeHost::TauriWebView),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_device_class(label: &str) -> Option<engine_v1_platform_api::DeviceClass> {
|
||||
return match label {
|
||||
"desktop" => Some(engine_v1_platform_api::DeviceClass::Desktop),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/apps/game-snake-poc-wasm/unit_tests/runtime.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
#[test]
|
||||
fn direction_is_queued_without_advancing_simulation() {
|
||||
@@ -34,7 +34,7 @@ fn browser_runtime_provenance_preserves_static_and_observed_dimensions() {
|
||||
assert_eq!(game.provenance_runtime_host(), "browser");
|
||||
assert_eq!(game.provenance_device_class(), "unknown");
|
||||
assert_eq!(game.provenance_input_profile(), "unknown");
|
||||
assert!(game.configure_runtime_provenance("phone", "touch"));
|
||||
assert!(game.configure_runtime_provenance("web", "browser", "phone", "touch"));
|
||||
assert_eq!(game.provenance_device_class(), "phone");
|
||||
assert_eq!(game.provenance_input_profile(), "touch");
|
||||
assert_eq!(game.provenance_platform_family(), "web");
|
||||
@@ -45,8 +45,19 @@ fn browser_runtime_provenance_preserves_static_and_observed_dimensions() {
|
||||
#[test]
|
||||
fn invalid_runtime_provenance_labels_are_rejected_without_mutation() {
|
||||
let mut game = crate::SnakeWasmGame::new();
|
||||
assert!(game.configure_runtime_provenance("desktop", "keyboard-mouse"));
|
||||
assert!(!game.configure_runtime_provenance("console", "telepathy"));
|
||||
assert!(game.configure_runtime_provenance("web", "browser", "desktop", "keyboard-mouse"));
|
||||
assert!(!game.configure_runtime_provenance("console", "spaceship", "console", "telepathy"));
|
||||
assert_eq!(game.provenance_device_class(), "desktop");
|
||||
assert_eq!(game.provenance_input_profile(), "keyboard-mouse");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tauri_android_runtime_provenance_is_supported_by_the_shared_adapter() {
|
||||
let mut game = crate::SnakeWasmGame::new();
|
||||
assert!(game.configure_runtime_provenance("android", "tauri-webview", "phone", "touch"));
|
||||
assert_eq!(game.provenance_platform_family(), "android");
|
||||
assert_eq!(game.provenance_runtime_host(), "tauri-webview");
|
||||
assert_eq!(game.provenance_execution_model(), "wasm");
|
||||
assert_eq!(game.provenance_device_class(), "phone");
|
||||
assert_eq!(game.provenance_input_profile(), "touch");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/engines/engine-v1-platform-api/src/environment.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
/// Broad physical device class relevant to interaction and score provenance.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -56,7 +56,7 @@ pub enum RuntimeHost {
|
||||
Browser,
|
||||
/// Native process managed directly by the operating system.
|
||||
Native,
|
||||
/// Tauri desktop WebView host.
|
||||
/// Tauri WebView host on a supported native platform.
|
||||
TauriWebView,
|
||||
}
|
||||
|
||||
|
||||
146
deltas/0.3.1/0-pre.1.md
Normal file
146
deltas/0.3.1/0-pre.1.md
Normal file
@@ -0,0 +1,146 @@
|
||||
<!-- file: deltas/0.3.1/0-pre.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-0-pre.1
|
||||
|
||||
## Base
|
||||
|
||||
Base autoritaire : archive téléchargée depuis le tag `v0.3.0` et fournie pour la reprise.
|
||||
|
||||
L'archive a été testée et inspectée avant modification. Sa version workspace est `0.3.0`. Elle ne contient pas `.git`, conformément au contrat des archives taggées ; aucun état Git inaccessible n'est inventé.
|
||||
|
||||
## Objet
|
||||
|
||||
Ouvrir `0.3.1` par son gate obligatoire de cadrage : audit de baseline, revue complète des règles, inventaire de réutilisation Web/WASM, référence Tauri existante, exigences Tauri Android, sizing et planification.
|
||||
|
||||
Aucun scaffold `game-snake-poc-tauri`, aucun frontend Tauri Snake et aucun changement de gameplay n'est introduit dans cette tranche.
|
||||
|
||||
## Version
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.3.0
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.3.1-0-pre.1
|
||||
```
|
||||
|
||||
Les versions npm des produits existants ne changent pas : cette tranche n'est pas une release de leurs frontends et `VER-TAURI-003`/`VER-TAURI-004` interdisent une synchronisation npm cérémonielle à chaque prerelease Cargo.
|
||||
|
||||
## Audit de baseline
|
||||
|
||||
Avant modification :
|
||||
|
||||
```text
|
||||
unzip -t : no errors
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
games.sasedev workspace audit: clean
|
||||
Markdown table audit: clean (5 table(s), 197 file(s))
|
||||
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
|
||||
```
|
||||
|
||||
L'archive ne contient aucun lockfile interdit, `node_modules/`, `dist/`, `target/` ou binding WASM généré.
|
||||
|
||||
Le détail est conservé dans `docs/studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md`.
|
||||
|
||||
## Corrections documentaires et normatives
|
||||
|
||||
Cette tranche :
|
||||
|
||||
- ferme l'index du plan `0.3.0` et ouvre le plan actif `0.3.1` ;
|
||||
- ajoute l'étude de cadrage et le plan vivant `0.3.1` ;
|
||||
- distingue explicitement les commandes Tauri Desktop des commandes Tauri Android ;
|
||||
- ajoute `cargo tauri android init`, `cargo tauri android dev` et `cargo tauri android build` à la matrice normative ;
|
||||
- corrige le prompt de reprise pour utiliser les commandes Android de Tauri au lieu des commandes Desktop ;
|
||||
- clarifie la différence entre la famille conceptuelle Mobile et le contrat V1 concret `PlatformFamily::Android` ;
|
||||
- distingue une sortie applicative Tauri soumise à `EngineGame::quit_requested` du Back système Android, qui reste une navigation système ;
|
||||
- documente la provenance attendue `Android / Wasm / TauriWebView`.
|
||||
|
||||
## Réutilisation retenue
|
||||
|
||||
Le second host doit :
|
||||
|
||||
- conserver `game-snake-poc` comme gameplay unique ;
|
||||
- réutiliser `game-snake-poc-wasm` plutôt que créer un second adapter ;
|
||||
- généraliser seulement la provenance de host actuellement figée sur Web/Browser ;
|
||||
- réutiliser sélectivement Canvas/input/assets/shell du host Web ;
|
||||
- adapter lifecycle et tracing au WebView Tauri Android ;
|
||||
- suivre l'organisation Tauri `lib.rs` façade + `tauri.rs` assemblage + modules propriétaires ;
|
||||
- ne pas reprendre l'orchestrateur Python historique du POC Reflex.
|
||||
|
||||
## Référence KSP
|
||||
|
||||
L'archive KSP demandée est visible dans la bibliothèque, mais son export binaire vers l'environnement de génération a été refusé par le service de bibliothèque. Aucun audit intégral fictif de cette archive n'est donc déclaré.
|
||||
|
||||
Les extraits indexés accessibles confirment néanmoins une organisation Desk avec `tauri.rs` pour l'assemblage/lifecycle et des modules propriétaires séparés tels que `app_state.rs`, `route_runtime.rs` et `frontend_logging.rs`. Les règles locales games.sasedev restent normatives.
|
||||
|
||||
## Forecast
|
||||
|
||||
```text
|
||||
0-pre.1 audit / règles / requirements / environnement / plan
|
||||
0-pre.2 scaffold Tauri Android + pipeline natif + bridge Snake WASM minimal
|
||||
0-pre.3 Canvas / input / assets / shell
|
||||
0-pre.4 lifecycle / provenance / tracing / Back + smoke mobile
|
||||
0-pre.5 conditionnel : extraction commune réellement justifiée
|
||||
2-beta.1 validation large + packaging Android
|
||||
2-beta.2 consolidation documentaire conditionnelle
|
||||
3-rc.1 candidate gelée
|
||||
0.3.1 release mécanique
|
||||
```
|
||||
|
||||
## Validations exécutées dans l'environnement de génération
|
||||
|
||||
Après constitution de l'état livré, exécuter :
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Aucun Cargo build/test/smoke final n'est attribué au générateur.
|
||||
|
||||
## Validation utilisateur demandée
|
||||
|
||||
Le manifest workspace change de version et les règles de commandes/validation sont modifiées. La gate utilisateur est :
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Aucun test workspace complet n'est imposé par `pre.1` : aucun code, comportement ni graphe de dépendances n'est modifié. Il reste réservé à un jalon planifié ou à une portée transverse non bornable.
|
||||
|
||||
Fournir également l'inventaire d'environnement qui conditionne `0-pre.2` :
|
||||
|
||||
```bash
|
||||
rustc --version
|
||||
cargo --version
|
||||
cargo tauri --version
|
||||
rustup target list --installed
|
||||
node --version
|
||||
npm --version
|
||||
wasm-bindgen --version
|
||||
java -version
|
||||
printf 'JAVA_HOME=%s\nANDROID_HOME=%s\nNDK_HOME=%s\n' "$JAVA_HOME" "$ANDROID_HOME" "$NDK_HOME"
|
||||
adb version
|
||||
adb devices -l
|
||||
emulator -list-avds
|
||||
```
|
||||
|
||||
Cette seconde série est un inventaire de prérequis, pas une gate déclarée réussie à l'avance.
|
||||
|
||||
## Suite après validation
|
||||
|
||||
Si la gate est propre et le cadrage accepté, passer à `0.3.1-0-pre.2` pour créer le host Tauri Android minimal. Toute absence d'outil indispensable ou incohérence de règle découverte par la gate produit d'abord un `0-pre.1.fix.N` borné.
|
||||
181
deltas/0.3.1/0-pre.2.fix.1.md
Normal file
181
deltas/0.3.1/0-pre.2.fix.1.md
Normal file
@@ -0,0 +1,181 @@
|
||||
<!-- file: deltas/0.3.1/0-pre.2.fix.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-0-pre.2.fix.1
|
||||
|
||||
## Base requise
|
||||
|
||||
`0.3.1-0-pre.2`.
|
||||
|
||||
Le delta `0-pre.2.md` reste immuable. La gate utilisateur du 2026-09-20 est consignée dans `history/0.3.1/0-pre.2.md`.
|
||||
|
||||
## Objectif
|
||||
|
||||
Corriger uniquement les défauts qui empêchent la gate de `0-pre.2` :
|
||||
|
||||
- warning `missing_docs` du build script, bloquant sous Clippy `-D warnings` ;
|
||||
- résultat ignoré par le wrapper `tauri::mobile_entry_point` Android ;
|
||||
- incompatibilité du wrapper Gradle `8.14.3` généré par Tauri CLI `2.11.3` avec Java 25.
|
||||
|
||||
Le scope fonctionnel de `0-pre.2` ne change pas. Canvas, contrôles, assets et lifecycle restent réservés aux tranches suivantes.
|
||||
|
||||
## Version technique
|
||||
|
||||
Le correctif touche du code Rust et le chemin de build Tauri/Android. La version workspace passe donc à :
|
||||
|
||||
```text
|
||||
0.3.1-0-pre.2.fix.1
|
||||
```
|
||||
|
||||
La version frontend locale de `package.json` reste `0.1.0` conformément à `VER-TAURI-003` et `VER-TAURI-004`.
|
||||
|
||||
## Correction Rust
|
||||
|
||||
`build.rs` possède désormais une rustdoc de crate et reste conforme aux règles Rust du workspace.
|
||||
|
||||
Le point d'entrée est séparé en deux niveaux :
|
||||
|
||||
- `run_runtime() -> Result<(), String>` possède l'exécution réelle ;
|
||||
- le host non mobile conserve `run() -> Result<(), String>` ;
|
||||
- le host mobile expose `#[tauri::mobile_entry_point] pub fn run()` et traite explicitement l'erreur éventuelle au lieu de laisser le macro ignorer un `Result` `must_use`.
|
||||
|
||||
Le comportement fonctionnel Tauri n'est pas modifié.
|
||||
|
||||
## Correction Gradle 9
|
||||
|
||||
Le log utilisateur confirme que Tauri sélectionne lui-même le NDK installé sous `$ANDROID_HOME/ndk/30.0.14904198` puis injecte `NDK_HOME` dans son sous-processus. `NDK_HOME` n'est donc pas ajouté comme prérequis utilisateur.
|
||||
|
||||
Le défaut réel est :
|
||||
|
||||
```text
|
||||
Tauri CLI 2.11.3 -> gen/android/gradlew -> Gradle 8.14.3 -> Java 25
|
||||
Unsupported class file major version 69
|
||||
```
|
||||
|
||||
Le Gradle global de la machine n'est pas consommé par ce chemin ; modifier uniquement le `PATH` ne corrige donc pas le wrapper Tauri.
|
||||
|
||||
Le fix ajoute `crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs`. Avant chaque hook `dev`/`build`, ce script adapte idempotemment le projet généré `gen/android` vers la combinaison déjà adoptée par la migration Android upstream de Tauri :
|
||||
|
||||
```text
|
||||
Gradle 9.6.1
|
||||
Android Gradle Plugin 9.3.1
|
||||
Kotlin Gradle Plugin 2.2.10
|
||||
```
|
||||
|
||||
Il adapte aussi les ruptures Gradle 9 pertinentes du scaffold Tauri `2.11.x` :
|
||||
|
||||
- `Project.exec` devient `ExecOperations` dans `BuildTask.kt` ;
|
||||
- les tâches Rust ciblées utilisent `tasks.register` et reçoivent explicitement `projectDir` ;
|
||||
- le DSL Android/Kotlin de l'application est aligné sur le template Gradle 9 upstream ;
|
||||
- les propriétés de compatibilité AGP 9 sont ajoutées ;
|
||||
- les anciennes propriétés Android devenues des defaults sont retirées.
|
||||
|
||||
Le script est local à la crate Tauri et ne modifie ni le Gradle global ni le cache Cargo.
|
||||
|
||||
## Bridge généré par tauri-build
|
||||
|
||||
`tauri-build 2.6.3` régénère `gen/android/app/tauri.build.gradle.kts` pendant la compilation Rust, donc un patch effectué uniquement avant Cargo serait écrasé.
|
||||
|
||||
`build.rs` applique par conséquent, immédiatement après `tauri_build::build()`, la migration :
|
||||
|
||||
```text
|
||||
val implementation by configurations
|
||||
```
|
||||
|
||||
vers :
|
||||
|
||||
```text
|
||||
val implementation = configurations.getByName("implementation")
|
||||
```
|
||||
|
||||
lorsque le fichier Android généré existe. Le build script reste un no-op pour ce point lors des checks hôte sans `gen/android`.
|
||||
|
||||
## Hooks Tauri
|
||||
|
||||
`package.json` conserve Tauri comme propriétaire du pipeline :
|
||||
|
||||
```text
|
||||
cargo tauri android dev
|
||||
-> beforeDevCommand
|
||||
-> npm run dev
|
||||
-> android:prepare
|
||||
-> WASM
|
||||
-> Vite
|
||||
```
|
||||
|
||||
et de même pour `beforeBuildCommand`.
|
||||
|
||||
`npm run dev` et `npm run build` ne deviennent pas des gates manuelles.
|
||||
|
||||
## Documentation et garde-fous
|
||||
|
||||
- `USAGE.md` retire `NDK_HOME` des prérequis utilisateur et explique la migration Gradle 9 ;
|
||||
- le plan vivant enregistre le défaut et le fix sans ouvrir `0-pre.3` ;
|
||||
- `audit_distribution_layout.py` exige désormais le hook Gradle, ses versions épinglées, la migration `ExecOperations` et le bridge `tauri-build` compatible Gradle 9 ;
|
||||
- le test synthétique du script Node a été exécuté deux fois sur le même fixture pour vérifier son idempotence.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs
|
||||
history/0.3.1/0-pre.2.md
|
||||
deltas/0.3.1/0-pre.2.fix.1.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
README.md
|
||||
crates/apps/game-snake-poc-tauri/README.md
|
||||
crates/apps/game-snake-poc-tauri/USAGE.md
|
||||
crates/apps/game-snake-poc-tauri/build.rs
|
||||
crates/apps/game-snake-poc-tauri/package.json
|
||||
crates/apps/game-snake-poc-tauri/src/tauri.rs
|
||||
docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md
|
||||
scripts/audit_distribution_layout.py
|
||||
```
|
||||
|
||||
## Suppressions
|
||||
|
||||
Aucune.
|
||||
|
||||
## Validation générateur
|
||||
|
||||
Les contrôles statiques applicables sont exécutés sur l'état livré. Les commandes Cargo/npm/Tauri/Gradle restent à exécuter côté utilisateur conformément à `CMD-GEN-007` et `CMD-BUILD-005`.
|
||||
|
||||
## Gate utilisateur
|
||||
|
||||
Depuis la racine :
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Le build Web direct était déjà propre dans la gate `0-pre.2` et aucune de ses sources n'est modifiée par ce fix ; il n'est pas nécessaire de répéter sa gate pour ce correctif borné.
|
||||
|
||||
Le projet Android généré existe déjà chez l'utilisateur. Ne pas rejouer `cargo tauri android init`. Relancer directement :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
|
||||
```
|
||||
|
||||
Le hook doit afficher avant le build Android :
|
||||
|
||||
```text
|
||||
Prepared Tauri Android Gradle 9.6.1 / AGP 9.3.1 / Kotlin 2.2.10.
|
||||
```
|
||||
|
||||
Puis le wrapper doit utiliser Gradle 9.6.1 au lieu de 8.14.3. Le smoke reste celui de `0-pre.2` : démarrage sur l'appareil/AVD, bridge Rust, chargement WASM, provenance `android / tauri-webview / wasm / unknown / unknown` et tracing sans erreur bloquante.
|
||||
|
||||
## Suite
|
||||
|
||||
Si cette gate est propre, `0-pre.2` est considéré réparé et la progression reprend sur `0.3.1-0-pre.3` conformément au plan vivant.
|
||||
2
deltas/0.3.1/0-pre.2.fix.2.delete.txt
Normal file
2
deltas/0.3.1/0-pre.2.fix.2.delete.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs
|
||||
history/0.3.1/0-pre.2.md
|
||||
122
deltas/0.3.1/0-pre.2.fix.2.md
Normal file
122
deltas/0.3.1/0-pre.2.fix.2.md
Normal file
@@ -0,0 +1,122 @@
|
||||
<!-- file: deltas/0.3.1/0-pre.2.fix.2.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-0-pre.2.fix.2
|
||||
|
||||
## Base
|
||||
|
||||
Base déclarée : `0.3.1-0-pre.2.fix.1`.
|
||||
|
||||
## Objet
|
||||
|
||||
Ce fix retire la migration Gradle 9 locale introduite par `fix.1`, revient au chemin Android officiellement généré par Tauri 2 stable et corrige l'audit workspace pour qu'il n'analyse pas le contenu généré sous `gen/` comme du code source du dépôt.
|
||||
|
||||
Il corrige également une violation documentaire de `fix.1` : `history/0.3.1/0-pre.2.md` avait été créé alors que `0-pre.2` n'était pas accepté. Aucune entrée `history/` n'est conservée pour ce jalon tant que sa gate n'est pas verte.
|
||||
|
||||
## Cause confirmée
|
||||
|
||||
Le smoke `0-pre.2` a établi trois faits distincts :
|
||||
|
||||
- Tauri sélectionne correctement le NDK side-by-side sous `$ANDROID_HOME/ndk/<version>` ; l'absence de `NDK_HOME` utilisateur n'est pas la cause du défaut ;
|
||||
- le wrapper Android généré par Tauri CLI `2.11.3` utilise Gradle `8.14.3`, qui ne peut pas s'exécuter avec Java 25 ;
|
||||
- `cargo tauri android init` crée légitimement `gen/android/app/src/main/assets`, mais l'audit `GAME-ASSET-001` parcourait jusque-là les répertoires générés.
|
||||
|
||||
La dernière CLI Tauri 2 stable vérifiée pendant ce fix est `2.11.5`. Son template Android conserve Gradle `8.14.3` et AGP `8.11.0`. La migration Gradle 9 existe upstream mais n'est pas encore publiée dans la branche stable Tauri 2 ; la reproduire par patch local ferait du projet games.sasedev le mainteneur d'un fork implicite du template Tauri.
|
||||
|
||||
## Correction Tauri Android
|
||||
|
||||
Le host Snake ne modifie plus `gen/android` :
|
||||
|
||||
- suppression de `scripts/prepare-android-gradle.mjs` ;
|
||||
- suppression du hook `android:prepare` dans `package.json` ;
|
||||
- restauration des hooks Tauri vers le seul pipeline WASM/Vite ;
|
||||
- `build.rs` délègue uniquement à `tauri_build::build()` ;
|
||||
- l'audit de distribution interdit désormais la réintroduction d'un patch `gen/android` dans ces deux surfaces.
|
||||
|
||||
Pour Tauri 2 stable, le contrat local devient celui recommandé par Tauri : `JAVA_HOME` doit pointer vers un JDK compatible avec le wrapper généré, de préférence le JBR livré avec Android Studio. Le Java 25 global peut rester installé ; il ne doit simplement pas être le JDK utilisé par les commandes Android Tauri tant que le wrapper stable ne le supporte pas.
|
||||
|
||||
Le Gradle global installé sous `/opt/gradle` n'est pas utilisé par `gen/android/gradlew` et n'entre pas dans le contrat de build.
|
||||
|
||||
## Correction de l'audit workspace
|
||||
|
||||
`gen/` est déjà un chemin généré et ignoré par `.gitignore`. `audit_project_workspace_rules.py` exclut désormais ces arbres pour les contrôles qui portent sur la propriété du code source :
|
||||
|
||||
- `GAME-ASSET-001` n'interdit plus les `assets` créés par le projet Android Tauri généré ;
|
||||
- `GAME-ANDROID-001` n'interdit plus les éventuelles sources Java générées sous `gen/`.
|
||||
|
||||
Les assets et sources Java réellement versionnés hors des emplacements autorisés restent interdits.
|
||||
|
||||
## Historique
|
||||
|
||||
`history/0.3.1/0-pre.2.md` est supprimé. `DOC-HIST-002` et `DOC-HIST-003` imposent qu'une entrée d'historique ne soit créée qu'après acceptation effective du jalon. Le prochain delta ne recréera cette entrée que si la gate `0-pre.2.fix.2` est validée.
|
||||
|
||||
## Suppressions
|
||||
|
||||
Le manifest `deltas/0.3.1/0-pre.2.fix.2.delete.txt` supprime :
|
||||
|
||||
- `crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs` ;
|
||||
- `history/0.3.1/0-pre.2.md`.
|
||||
|
||||
Après extraction du delta à la racine du dépôt, appliquer les suppressions avec :
|
||||
|
||||
```bash
|
||||
while IFS= read -r path; do
|
||||
rm -f -- "$path"
|
||||
done < deltas/0.3.1/0-pre.2.fix.2.delete.txt
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
- `Cargo.toml` ;
|
||||
- `README.md` ;
|
||||
- `crates/apps/game-snake-poc-tauri/build.rs` ;
|
||||
- `crates/apps/game-snake-poc-tauri/package.json` ;
|
||||
- `crates/apps/game-snake-poc-tauri/README.md` ;
|
||||
- `crates/apps/game-snake-poc-tauri/USAGE.md` ;
|
||||
- `docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md` ;
|
||||
- `scripts/audit_project_workspace_rules.py` ;
|
||||
- `scripts/audit_distribution_layout.py`.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
- `deltas/0.3.1/0-pre.2.fix.2.md` ;
|
||||
- `deltas/0.3.1/0-pre.2.fix.2.delete.txt`.
|
||||
|
||||
## Validation statique du générateur
|
||||
|
||||
Le générateur peut exécuter les audits statiques et vérifier explicitement que les chemins générés Tauri ne déclenchent plus `GAME-ASSET-001` / `GAME-ANDROID-001`. Ces contrôles ne remplacent pas les gates build/runtime utilisateur.
|
||||
|
||||
## Gate utilisateur
|
||||
|
||||
Après application du delta et de son manifest de suppression :
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Avant le smoke Android, sélectionner le JBR d'Android Studio dans le shell. Exemple si Android Studio est sous `/opt/android-studio` :
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/opt/android-studio/jbr
|
||||
"$JAVA_HOME/bin/java" -version
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
|
||||
```
|
||||
|
||||
Si Android Studio se trouve ailleurs, remplacer `/opt/android-studio/jbr` par son chemin réel. Ne pas exécuter `npm run dev` directement et ne pas rejouer `cargo tauri android init` pour ce fix lorsque `gen/android` existe déjà.
|
||||
|
||||
## Critère d'acceptation
|
||||
|
||||
Le fix est accepté lorsque :
|
||||
|
||||
- les trois audits Python sont propres malgré la présence du `gen/android` local ;
|
||||
- Cargo/Clippy/tests ciblés sont propres ;
|
||||
- `cargo tauri android dev` n'échoue plus sur `Unsupported class file major version 69` ;
|
||||
- le host minimal atteint le smoke Android prévu par `0-pre.2`.
|
||||
128
deltas/0.3.1/0-pre.2.fix.3.md
Normal file
128
deltas/0.3.1/0-pre.2.fix.3.md
Normal file
@@ -0,0 +1,128 @@
|
||||
<!-- file: deltas/0.3.1/0-pre.2.fix.3.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-0-pre.2.fix.3
|
||||
|
||||
## Base
|
||||
|
||||
Base déclarée : `0.3.1-0-pre.2.fix.2`.
|
||||
|
||||
## Objet
|
||||
|
||||
Ce fix corrige la procédure Android après constat que le répertoire local `gen/android` avait été partiellement modifié par la tentative Gradle 9 abandonnée de `0-pre.2.fix.1`.
|
||||
|
||||
Aucun patch du projet Android généré n'est réintroduit. Le fix verrouille au contraire le contrat officiel Tauri 2.11.x et rend détectable tout `gen/android` local qui ne correspond plus à ce contrat.
|
||||
|
||||
## Diagnostic confirmé
|
||||
|
||||
Le smoke `0-pre.2.fix.2` a confirmé :
|
||||
|
||||
- les audits Python, Cargo, Clippy et les cinq tests `game-snake-poc-wasm` sont propres ;
|
||||
- le NDK side-by-side est détecté sans `NDK_HOME` utilisateur ;
|
||||
- le JBR de l'Android Studio local est Java 25, comme le Java global ;
|
||||
- `gen/android/gradle/wrapper/gradle-wrapper.properties` utilisait encore Gradle `9.6.1`, trace de `fix.1` ;
|
||||
- `buildSrc` restait partiellement au format Tauri 2.11.x et échouait donc sous Gradle 9 sur les appels `project.exec`/`exec`.
|
||||
|
||||
Le défaut n'est pas dans le host Rust/WASM : l'arbre Android généré local est incohérent et doit être régénéré.
|
||||
|
||||
## Toolchain Android retenu pour 0.3.1
|
||||
|
||||
Le projet conserve le template officiel Tauri 2.11.x :
|
||||
|
||||
```text
|
||||
Gradle 8.14.3
|
||||
Android Gradle Plugin 8.11.0
|
||||
Kotlin Gradle Plugin 1.9.25
|
||||
JDK de gate 17
|
||||
```
|
||||
|
||||
AGP 8.11 exige JDK 17 au minimum et Gradle 8.14.x prend en charge l'exécution jusqu'à Java 24, pas Java 25. JDK 17 est donc la baseline reproductible retenue pour cette version.
|
||||
|
||||
Le Java 25 global et le JBR 25 d'Android Studio restent installables mais ne sont pas utilisés pour `cargo tauri android init/dev/build` dans `0.3.1`.
|
||||
|
||||
## Régénération obligatoire du projet Android local
|
||||
|
||||
Toute machine ayant exécuté `0-pre.2.fix.1` doit supprimer uniquement l'arbre généré Android Snake puis le recréer officiellement :
|
||||
|
||||
```bash
|
||||
rm -rf crates/apps/game-snake-poc-tauri/gen/android
|
||||
export JAVA_HOME=/chemin/vers/jdk-17
|
||||
"$JAVA_HOME/bin/java" -version
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android init)
|
||||
```
|
||||
|
||||
Le répertoire `gen/android` est ignoré et n'appartient à aucun delta. Sa suppression n'est donc pas un changement source.
|
||||
|
||||
## Audit ajouté
|
||||
|
||||
`audit_distribution_layout.py` vérifie désormais un `gen/android` présent sans le considérer comme source versionnée. Pour la tranche courante, il doit contenir les marqueurs du template Tauri 2.11.x : Gradle `8.14.3`, AGP `8.11.0` et Kotlin Gradle Plugin `1.9.25`.
|
||||
|
||||
Un arbre incomplet ou divergent provoque `DIST-LAYOUT-041/042` avec instruction de le supprimer puis de relancer `cargo tauri android init` sous JDK 17.
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
- `Cargo.toml` ;
|
||||
- `README.md` ;
|
||||
- `crates/apps/game-snake-poc-tauri/README.md` ;
|
||||
- `crates/apps/game-snake-poc-tauri/USAGE.md` ;
|
||||
- `docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md` ;
|
||||
- `docs/validation/001-VALIDATION_GATES.md` ;
|
||||
- `scripts/audit_distribution_layout.py`.
|
||||
|
||||
## Fichier ajouté
|
||||
|
||||
- `deltas/0.3.1/0-pre.2.fix.3.md`.
|
||||
|
||||
## Gate utilisateur
|
||||
|
||||
Après application du delta, commencer par disposer d'un JDK 17. Vérifier les JDK déjà installés avant d'en installer un nouveau :
|
||||
|
||||
```bash
|
||||
find /usr/lib/jvm "$HOME/.jdks" "$HOME/.sdkman/candidates/java" -maxdepth 3 -type f -path '*/bin/java' 2>/dev/null
|
||||
```
|
||||
|
||||
Sélectionner ensuite le JDK 17 réel :
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/chemin/vers/jdk-17
|
||||
"$JAVA_HOME/bin/java" -version
|
||||
```
|
||||
|
||||
Nettoyer l'arbre Android pollué par `fix.1`, puis le régénérer avec Tauri :
|
||||
|
||||
```bash
|
||||
rm -rf crates/apps/game-snake-poc-tauri/gen/android
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android init)
|
||||
```
|
||||
|
||||
Rejouer ensuite la gate statique/build :
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Puis le smoke Android :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
|
||||
```
|
||||
|
||||
Ne pas exécuter `npm run dev` directement et ne modifier aucun fichier sous `gen/android` à la main.
|
||||
|
||||
## Critère d'acceptation
|
||||
|
||||
Le fix est accepté lorsque :
|
||||
|
||||
- les audits et gates Rust restent propres ;
|
||||
- `audit_distribution_layout.py` accepte le `gen/android` fraîchement généré ;
|
||||
- `gen/android/gradle/wrapper/gradle-wrapper.properties` référence Gradle `8.14.3` ;
|
||||
- la commande Android utilise JDK 17 ;
|
||||
- `cargo tauri android dev` assemble, installe et lance le host minimal sans erreur Gradle/Kotlin bloquante.
|
||||
161
deltas/0.3.1/0-pre.2.md
Normal file
161
deltas/0.3.1/0-pre.2.md
Normal file
@@ -0,0 +1,161 @@
|
||||
<!-- file: deltas/0.3.1/0-pre.2.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-0-pre.2
|
||||
|
||||
## Base requise
|
||||
|
||||
`0.3.1-0-pre.1`, validée par l'utilisateur le 2026-09-20.
|
||||
|
||||
## Objectif
|
||||
|
||||
Créer le host Tauri Android minimal de Snake sans dupliquer le gameplay, sans créer un second adapter WASM et sans réintroduire de build orchestré par Python.
|
||||
|
||||
Cette tranche vise le premier démarrage Android et la validation des frontières Tauri/WASM/tracing. Le Canvas, les contrôles, les assets et le lifecycle complet restent réservés à `0-pre.3` et `0-pre.4` conformément au plan vivant.
|
||||
|
||||
## Audit Tauri KSP direct
|
||||
|
||||
L'archive fournie `khadhroony-solana-project-v0.3.15.zip` a été extraite et les six crates `ksp-app-*-desk` ont été vérifiées directement. Elles possèdent toutes les frontières structurantes retenues pour games.sasedev :
|
||||
|
||||
```text
|
||||
src/lib.rs
|
||||
src/tauri.rs
|
||||
package.json
|
||||
vite.config.ts
|
||||
tauri.conf.json
|
||||
capabilities/default.json
|
||||
tauri-plugin-tracing côté Rust
|
||||
@fltsci/tauri-plugin-tracing côté frontend
|
||||
```
|
||||
|
||||
Le nouveau host Snake reprend cette organisation, avec un scope volontairement plus petit. Le Tauri Reflex historique reste seulement une référence de compatibilité : son orchestration Python n'est pas reproduite.
|
||||
|
||||
## Changements Rust et WASM
|
||||
|
||||
- passage du workspace à `0.3.1-0-pre.2` ;
|
||||
- ajout de `game-snake-poc-tauri` au workspace ;
|
||||
- création de la façade `src/lib.rs`, de l'assemblage `src/tauri.rs` et du module propriétaire `src/runtime.rs` ;
|
||||
- ajout du point d'entrée mobile `#[cfg_attr(mobile, tauri::mobile_entry_point)]` ;
|
||||
- initialisation du subscriber partagé via `game-logging-lib` avant le premier événement Rust ;
|
||||
- installation de `tauri-plugin-tracing` ;
|
||||
- généralisation minimale de `game-snake-poc-wasm::configure_runtime_provenance` afin que le même adapter accepte explicitement la famille et le host observés ;
|
||||
- conservation de `ExecutionModel::Wasm` dans l'adapter ;
|
||||
- adaptation du Web direct pour fournir explicitement `web / browser` ;
|
||||
- ajout d'un test ciblé `android / tauri-webview / wasm` ;
|
||||
- généralisation de la rustdoc `RuntimeHost::TauriWebView`, qui n'est plus décrite comme Desktop uniquement.
|
||||
|
||||
## Frontend et build Tauri
|
||||
|
||||
La nouvelle app contient :
|
||||
|
||||
- `package.json`, `tsconfig.json` et `vite.config.ts` ;
|
||||
- un frontend minimal sous `frontend/` ;
|
||||
- un bridge IPC vers le descriptor runtime Rust ;
|
||||
- le chargement des bindings produits depuis `game-snake-poc-wasm` ;
|
||||
- le tracing frontend via `@fltsci/tauri-plugin-tracing` ;
|
||||
- `tauri.conf.json` et `capabilities/default.json` ;
|
||||
- un icon POC cohérent avec le host Tauri historique ;
|
||||
- `README.md` et `USAGE.md` initiaux.
|
||||
|
||||
Les hooks Tauri exécutent eux-mêmes le build Cargo WASM, `wasm-bindgen` puis Vite. Les outputs restent sous `../builds/sasedev-games/`. Aucun script Python n'est impliqué dans ce chemin.
|
||||
|
||||
`cargo tauri android init` reste une opération locale de la gate : son répertoire `gen/` est généré et ignoré, donc il n'est pas distribué dans le delta.
|
||||
|
||||
## NDK et JDK
|
||||
|
||||
La machine de validation possède plusieurs NDK sous `$ANDROID_HOME/ndk/`; `NDK_HOME` n'est donc pas imposé globalement par le dépôt. Si la CLI Tauri exige une valeur explicite pendant `android init/dev`, utiliser ponctuellement le chemin exact de la version NDK concernée.
|
||||
|
||||
`JAVA_HOME` reste également facultatif tant que `java` est résolu correctement par la CLI dans l'environnement courant. Les deux variables deviennent des outils de diagnostic local, pas des invariants source du projet.
|
||||
|
||||
## Audit de distribution
|
||||
|
||||
`audit_distribution_layout.py` couvre désormais le host Tauri Snake minimal : fichiers requis, hooks Tauri, outputs WASM externes au dépôt, point d'entrée mobile, bridge tracing, provenance Android/TauriWebView et interdiction de Python/`console.*` dans le chemin touché.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/apps/game-snake-poc-tauri/Cargo.toml
|
||||
crates/apps/game-snake-poc-tauri/README.md
|
||||
crates/apps/game-snake-poc-tauri/USAGE.md
|
||||
crates/apps/game-snake-poc-tauri/build.rs
|
||||
crates/apps/game-snake-poc-tauri/capabilities/default.json
|
||||
crates/apps/game-snake-poc-tauri/frontend/css/main.css
|
||||
crates/apps/game-snake-poc-tauri/frontend/main.html
|
||||
crates/apps/game-snake-poc-tauri/frontend/ts/bridge.ts
|
||||
crates/apps/game-snake-poc-tauri/frontend/ts/logging.ts
|
||||
crates/apps/game-snake-poc-tauri/frontend/ts/main.ts
|
||||
crates/apps/game-snake-poc-tauri/icons/icon.png
|
||||
crates/apps/game-snake-poc-tauri/package.json
|
||||
crates/apps/game-snake-poc-tauri/src/lib.rs
|
||||
crates/apps/game-snake-poc-tauri/src/main.rs
|
||||
crates/apps/game-snake-poc-tauri/src/runtime.rs
|
||||
crates/apps/game-snake-poc-tauri/src/tauri.rs
|
||||
crates/apps/game-snake-poc-tauri/tauri.conf.json
|
||||
crates/apps/game-snake-poc-tauri/tsconfig.json
|
||||
crates/apps/game-snake-poc-tauri/vite.config.ts
|
||||
history/0.3.1/0-pre.1.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
README.md
|
||||
Web/game-snake-poc/frontend/ts/provenance.ts
|
||||
crates/apps/game-snake-poc-wasm/src/runtime.rs
|
||||
crates/apps/game-snake-poc-wasm/unit_tests/runtime.rs
|
||||
crates/engines/engine-v1-platform-api/src/environment.rs
|
||||
docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md
|
||||
scripts/audit_distribution_layout.py
|
||||
```
|
||||
|
||||
## Validation générateur
|
||||
|
||||
Les audits statiques applicables sont exécutés avant livraison. Aucun `cargo`, `npm`, `wasm-bindgen`, Gradle, Tauri Android ou smoke n'est déclaré validé par le générateur.
|
||||
|
||||
## Gate utilisateur
|
||||
|
||||
Appliquer d'abord la gate workspace :
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Comme l'API de provenance partagée est utilisée par le Web direct, reconstruire ses bindings et son frontend :
|
||||
|
||||
```bash
|
||||
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown
|
||||
wasm-bindgen ../builds/sasedev-games/target/wasm32-unknown-unknown/debug/game_snake_poc_wasm.wasm --target web --out-dir ../builds/sasedev-games/game-snake-poc-web/wasm --out-name game_snake_poc_wasm
|
||||
(cd Web/game-snake-poc && npm install && npm run build)
|
||||
```
|
||||
|
||||
Puis initialiser et lancer le nouveau host par Tauri, sans exécuter ses scripts npm de build directement :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && npm install)
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android init)
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
|
||||
```
|
||||
|
||||
Critères du smoke `android dev` :
|
||||
|
||||
- l'app démarre sur l'appareil/AVD choisi ;
|
||||
- le frontend affiche `android / tauri-webview / wasm / unknown / unknown` ;
|
||||
- le bridge Rust répond ;
|
||||
- le frontend charge `game-snake-poc-wasm` ;
|
||||
- les logs Rust et frontend atteignent le pipeline tracing/logcat ;
|
||||
- aucune erreur runtime bloquante n'est visible.
|
||||
|
||||
`cargo tauri android build` reste reporté au jalon de packaging prévu par le plan.
|
||||
|
||||
## Suite après validation
|
||||
|
||||
Si la gate est propre, passer automatiquement à `0.3.1-0-pre.3` pour intégrer le Canvas Snake, les inputs et les assets dans le WebView Tauri. Tout défaut source de `0-pre.2` produit d'abord un `0-pre.2.fix.N` borné.
|
||||
152
deltas/0.3.1/0-pre.3.md
Normal file
152
deltas/0.3.1/0-pre.3.md
Normal file
@@ -0,0 +1,152 @@
|
||||
<!-- file: deltas/0.3.1/0-pre.3.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-0-pre.3
|
||||
|
||||
## Base
|
||||
|
||||
Base déclarée : `0.3.1-0-pre.2.fix.3`, validée par l'utilisateur le 2026-09-20.
|
||||
|
||||
## Objet
|
||||
|
||||
Cette tranche transforme le host Tauri Android minimal en POC Snake visuellement jouable : Canvas, boucle de simulation fixed-step, contrôles clavier/touch, assets canoniques et shell responsive.
|
||||
|
||||
Elle enregistre aussi la décision issue du smoke précédent : Tauri Android est conservé comme POC de référence, mais la voie Android de production reste SDL3 natif tant qu'un besoin fonctionnel explicite ne justifie pas la WebView.
|
||||
|
||||
## Frontend Tauri Snake
|
||||
|
||||
Le host ajoute des modules propriétaires séparés :
|
||||
|
||||
```text
|
||||
frontend/ts/assets.ts validation des assets common/game
|
||||
frontend/ts/game.ts projection Canvas + fixed-step WASM
|
||||
frontend/ts/input.ts clavier + pointer/touch
|
||||
frontend/ts/provenance.ts device/input observés pour le host Tauri
|
||||
```
|
||||
|
||||
`main.ts` reste l'orchestrateur frontend et ne réimplémente aucune règle Snake. Le gameplay continue de résider dans `game-snake-poc` et le même `game-snake-poc-wasm` reste consommé par le navigateur direct et la WebView Tauri.
|
||||
|
||||
Le shell reste volontairement léger : CSS local, aucun Bootstrap/SimpleBar/ResizeObserver ajouté. Le Canvas conserve le ratio logique `3 / 5` du Snake et les boutons directionnels sont utilisables au tactile/pointer.
|
||||
|
||||
## Assets
|
||||
|
||||
`vite-plugin-static-copy` est ajouté au package Tauri pour exposer exactement les deux assets canoniques :
|
||||
|
||||
```text
|
||||
assets/common/data/runtime.json -> common/data/runtime.json
|
||||
assets/game-snake-poc/data/game.json -> game/data/game.json
|
||||
```
|
||||
|
||||
Les assets restent hors des crates Rust et aucun duplicat runtime n'est créé sous `frontend/` ou `gen/android`.
|
||||
|
||||
## Provenance
|
||||
|
||||
Le backend Rust fournit toujours les dimensions statiques `Android / TauriWebView / Wasm`. Le frontend observe désormais la classe de device et les sources d'input pour configurer l'adapter partagé avec `phone/tablet/desktop/unknown` et `touch/keyboard-mouse/mixed/unknown`.
|
||||
|
||||
La stabilisation lifecycle/background/foreground appartient encore à `0-pre.4`.
|
||||
|
||||
## Vite dev
|
||||
|
||||
La configuration WebSocket garde `server.ws`, mécanisme Vite 8 courant. Sur l'émulateur sans `TAURI_DEV_HOST`, le client HMR utilise le même port `1436` que le serveur dev/forwarding Tauri ; avec un host réseau explicite, le port HMR séparé `1437` reste utilisé.
|
||||
|
||||
Cette correction vise le warning HMR observé au smoke précédent mais n'est pas un critère fonctionnel du gameplay.
|
||||
|
||||
## Positionnement Tauri après le POC minimal
|
||||
|
||||
La documentation durable et la roadmap sont réconciliées :
|
||||
|
||||
- Tauri Android reste un POC de référence ;
|
||||
- SDL3 natif reste la cible Android productive par défaut ;
|
||||
- les futurs jeux ne reçoivent pas automatiquement une app Tauri Android ;
|
||||
- la saisie texte/WebView reste une hypothèse à comparer aux capacités SDL réelles ;
|
||||
- Tauri Desktop devient une évaluation conditionnelle, notamment selon la viabilité d'une monétisation publicitaire WebView.
|
||||
|
||||
Aucune extraction Web/Tauri commune n'est créée dans cette tranche. Le statut de POC de référence réduit au contraire la valeur d'une abstraction qui n'aurait pas au moins deux consommateurs durablement retenus.
|
||||
|
||||
## Historique créé
|
||||
|
||||
Conformément à `DOC-HIST-002/003`, la tranche crée :
|
||||
|
||||
```text
|
||||
history/0.3.1/0-pre.2.fix.3.md
|
||||
```
|
||||
|
||||
qui enregistre uniquement les validations réellement fournies pour le jalon précédent.
|
||||
|
||||
## Fichiers principaux modifiés
|
||||
|
||||
- `Cargo.toml` ;
|
||||
- `README.md` ;
|
||||
- `ROADMAP.md` ;
|
||||
- `docs/architecture/015-PLATFORM_POC_ARCHITECTURE.md` ;
|
||||
- `docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md` ;
|
||||
- `crates/apps/game-snake-poc-tauri/README.md` ;
|
||||
- `crates/apps/game-snake-poc-tauri/USAGE.md` ;
|
||||
- `crates/apps/game-snake-poc-tauri/frontend/main.html` ;
|
||||
- `crates/apps/game-snake-poc-tauri/frontend/css/main.css` ;
|
||||
- `crates/apps/game-snake-poc-tauri/frontend/ts/main.ts` ;
|
||||
- `crates/apps/game-snake-poc-tauri/package.json` ;
|
||||
- `crates/apps/game-snake-poc-tauri/vite.config.ts` ;
|
||||
- `scripts/audit_distribution_layout.py`.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
- `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/provenance.ts` ;
|
||||
- `history/0.3.1/0-pre.2.fix.3.md` ;
|
||||
- `deltas/0.3.1/0-pre.3.md`.
|
||||
|
||||
## Gate utilisateur
|
||||
|
||||
Conserver JDK 17 pour les commandes Tauri Android :
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/usr/lib/jvm/temurin-17-jdk-amd64
|
||||
"$JAVA_HOME/bin/java" -version
|
||||
```
|
||||
|
||||
Le package Tauri possède une nouvelle dépendance frontend ; mettre à jour ses dépendances sans lancer manuellement son build :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && npm install)
|
||||
```
|
||||
|
||||
Puis exécuter :
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Le smoke frontend reste possédé par Tauri :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev)
|
||||
```
|
||||
|
||||
Ne pas exécuter `npm run dev` ou `npm run build` manuellement.
|
||||
|
||||
## Critère d'acceptation
|
||||
|
||||
Sur l'AVD Android :
|
||||
|
||||
- le Canvas Snake est visible avec un ratio `3 / 5` ;
|
||||
- le Snake avance automatiquement ;
|
||||
- score et longueur sont visibles ;
|
||||
- les quatre boutons directionnels répondent au pointer/tactile ;
|
||||
- le clavier fonctionne lorsqu'il est disponible ;
|
||||
- `Assets` affiche `snake / engine-v1` ;
|
||||
- la provenance est `android / tauri-webview / wasm / <device> / <input>` et évolue après une entrée ;
|
||||
- aucune règle gameplay n'est dupliquée dans TypeScript ;
|
||||
- aucun fichier sous `gen/android` n'est modifié par le projet.
|
||||
|
||||
Le background/foreground, la reprise sans catch-up, la rotation consolidée et Back restent les objectifs explicites de `0-pre.4`.
|
||||
94
deltas/0.3.1/0-pre.4.fix.1.md
Normal file
94
deltas/0.3.1/0-pre.4.fix.1.md
Normal file
@@ -0,0 +1,94 @@
|
||||
<!-- file: deltas/0.3.1/0-pre.4.fix.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-0-pre.4.fix.1
|
||||
|
||||
## Base
|
||||
|
||||
Base déclarée : `0.3.1-0-pre.4`.
|
||||
|
||||
## Objet
|
||||
|
||||
Corriger le chemin de développement Tauri Android sur appareil réel après la gate ARM64 et formaliser la limite observée lors du teardown WebView/Activity, sans introduire de fork local de Tauri/Wry ni modifier le projet Android généré.
|
||||
|
||||
## Résultats de la gate `0-pre.4`
|
||||
|
||||
La gate workspace et le smoke AVD x86_64 sont propres : audits, formatage, `cargo check`, Clippy strict et les cinq tests `game-snake-poc-wasm` passent. Le lifecycle journalise correctement `runtime paused/resumed` et `visibility hidden/visible`.
|
||||
|
||||
Le smoke supplémentaire sur appareil Android ARM64 réel a confirmé :
|
||||
|
||||
- ABI Android `arm64-v8a` et cible Rust `aarch64-linux-android` ;
|
||||
- compilation du `cdylib` ARM64 ;
|
||||
- assemblage, streamed install et démarrage de `MainActivity` ;
|
||||
- chargement des assets ;
|
||||
- initialisation WASM ;
|
||||
- Canvas jouable et touch observé ;
|
||||
- provenance `android / tauri-webview / wasm / phone / touch` ;
|
||||
- pause lifecycle avant sortie.
|
||||
|
||||
Deux écarts ont été révélés.
|
||||
|
||||
Premièrement, le mode `dev` sur téléphone physique remplace automatiquement `localhost` par une adresse LAN. Le tunnel USB ADB `reverse tcp:1436 tcp:1436` associé à `cargo tauri android dev --host 127.0.0.1` rend le chargement HTTP reproductible sans dépendre du LAN.
|
||||
|
||||
Deuxièmement, le frontend utilisait encore un WebSocket HMR séparé sur le port `1437`. Le HTML/WASM se chargeait, mais Vite journalisait `failed to connect to websocket`. Ce défaut appartient au projet et est corrigé par ce fix : HTTP et WebSocket Vite partagent désormais le port `1436`, qui est le port tunnelé par ADB.
|
||||
|
||||
Enfin, le Back système sur le Galaxy S9+ de validation a provoqué pendant le teardown natif :
|
||||
|
||||
```text
|
||||
FORTIFY: pthread_mutex_lock called on a destroyed mutex
|
||||
```
|
||||
|
||||
L'abort arrive après `runtime paused` / `visibility hidden` et avant `pagehide` / `runtime disposed`. La gate résout Tauri `2.11.5` avec Wry `0.55.1`. Des versions Wry postérieures ont modifié le lifecycle Android et la synchronisation des request handlers, mais le projet ne force pas une version Wry incompatible derrière la pile Tauri stable ni ne patch `gen/android`. Ce crash reste une limite externe du POC à retester avec l'APK autonome de la beta.
|
||||
|
||||
## Changements
|
||||
|
||||
- version workspace : `0.3.1-0-pre.4.fix.1` ;
|
||||
- WebSocket Vite/HMR fixé sur le même host de développement et le même port `1436` que HTTP ;
|
||||
- suppression du port HMR séparé `1437` ;
|
||||
- procédure de smoke appareil réel documentée avec tunnel ADB USB et `--host 127.0.0.1` ;
|
||||
- correspondance ABI `arm64-v8a` / `aarch64-linux-android` documentée ;
|
||||
- crash Back/teardown réel enregistré comme limite du POC et non comme capacité validée ;
|
||||
- audit de distribution renforcé pour refuser le retour d'un second port WebSocket non tunnelé.
|
||||
|
||||
## Invariants
|
||||
|
||||
- aucun fichier sous `gen/android` n'est modifié ou livré ;
|
||||
- aucun handler `onBackButtonPress` n'est ajouté pour masquer le crash de teardown ;
|
||||
- aucune surcharge manuelle de Wry/Tauri n'est introduite ;
|
||||
- aucun gameplay ne quitte Rust/WASM ;
|
||||
- SDL3 natif reste la direction Android de production ;
|
||||
- l'APK autonome de `2-beta.1` doit distinguer un défaut du mode `dev` d'un défaut général de teardown Tauri/Wry/WebView.
|
||||
|
||||
## Gate utilisateur
|
||||
|
||||
Gate statique et Rust :
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Smoke appareil réel, avec le `<serial>` fourni par `adb devices -l` :
|
||||
|
||||
```bash
|
||||
adb -s <serial> reverse --remove-all
|
||||
adb -s <serial> reverse tcp:1436 tcp:1436
|
||||
adb -s <serial> reverse --list
|
||||
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev --host 127.0.0.1)
|
||||
```
|
||||
|
||||
Vérifier : Canvas/inputs/assets/WASM/provenance/lifecycle et absence de l'erreur Vite `failed to connect to websocket`. Tester Back une fois et conserver le résultat ; si l'abort natif documenté reste reproductible, il n'est pas contourné dans ce fix et sera retesté sur l'APK autonome en beta.
|
||||
|
||||
## Suite prévue
|
||||
|
||||
Aucune extraction `0-pre.5` n'est justifiée. Après validation de ce fix, passer directement à `0.3.1-2-beta.1` pour la gate large, le build WASM release, le packaging APK et les smokes package AVD + ARM64 réel.
|
||||
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.
|
||||
76
deltas/0.3.1/2-beta.1.md
Normal file
76
deltas/0.3.1/2-beta.1.md
Normal file
@@ -0,0 +1,76 @@
|
||||
<!-- file: deltas/0.3.1/2-beta.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-2-beta.1
|
||||
|
||||
## Objectif
|
||||
|
||||
Entrer en beta avec le POC Snake Tauri Android fonctionnel de bout en bout et exécuter la validation large ainsi que le premier packaging APK autonome, sans ajouter de fonctionnalité.
|
||||
|
||||
## Baseline acceptée
|
||||
|
||||
`0.3.1-0-pre.4.fix.1` est validée sur AVD x86_64 et appareil ARM64 réel. Les audits/check/Clippy/tests ciblés passent, HTTP et HMR partagent le tunnel `1436`, le frontend atteint `ready` et le touch est observé. L'abort natif Back vu pendant un smoke antérieur n'est pas reproduit lors de la gate `fix.1`; il reste à caractériser sur package autonome.
|
||||
|
||||
Aucune extraction `0-pre.5` n'est justifiée : Tauri Android reste un POC de référence et ne devient pas une voie de production.
|
||||
|
||||
## Changements
|
||||
|
||||
- passage de `workspace.package.version` à `0.3.1-2-beta.1` ;
|
||||
- passage du package frontend Tauri Snake au jalon `0.3.1-2-beta.1` conformément au workflow Tauri/frontend ;
|
||||
- ajout de l'historique validé `0-pre.4.fix.1` ;
|
||||
- réconciliation du plan et des gates avec la validation réelle ARM64 ;
|
||||
- ajout de la procédure de packaging beta APK Debug x86_64 + ARM64 ;
|
||||
- maintien explicite de l'absence d'AAB à ce jalon.
|
||||
|
||||
Aucun gameplay, adapter WASM, bridge Tauri, lifecycle, input, asset ou scaffold Android généré n'est modifié par cette tranche.
|
||||
|
||||
## Validation beta attendue
|
||||
|
||||
Depuis la racine :
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/usr/lib/jvm/temurin-17-jdk-amd64
|
||||
|
||||
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 Web deltas history
|
||||
python3 scripts/audit_distribution_layout.py
|
||||
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
cargo test --workspace --all-targets --all-features
|
||||
```
|
||||
|
||||
Installer/actualiser les dépendances frontend, puis laisser Tauri posséder entièrement le build WASM release + bindings + TypeScript/Vite :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && npm install)
|
||||
|
||||
(cd crates/apps/game-snake-poc-tauri && \
|
||||
cargo tauri android build --debug --apk --target aarch64 --target x86_64)
|
||||
```
|
||||
|
||||
Ne pas lancer `npm run build` séparément. Le build Tauri doit terminer en affichant le chemin de l'APK produit. Aucun AAB n'est requis pour cette beta.
|
||||
|
||||
## Contrôle de l'APK
|
||||
|
||||
À partir du chemin `<apk>` affiché par Tauri :
|
||||
|
||||
```bash
|
||||
unzip -l <apk> | grep -E 'lib/(arm64-v8a|x86_64)/libgame_snake_poc_tauri_lib\.so'
|
||||
```
|
||||
|
||||
Les deux ABI doivent être présentes. Le package est ensuite installé successivement sur l'AVD x86_64 et l'appareil ARM64 réel :
|
||||
|
||||
```bash
|
||||
adb -s <serial> install -r <apk>
|
||||
adb -s <serial> shell am start -n com.sasedev.games.snake.tauri/.MainActivity
|
||||
```
|
||||
|
||||
Le smoke autonome vérifie au minimum : Canvas, assets `snake / engine-v1`, WASM, contrôles, provenance, background/foreground, reprise sans rattrapage, rotation/resize si disponible et plusieurs sorties Back. Le package ne doit dépendre ni de Vite, ni du port `1436`, ni de `adb reverse`.
|
||||
|
||||
## Après validation
|
||||
|
||||
Si la gate beta et les deux smokes APK sont propres, `2-beta.2` reste omise sauf besoin documentaire substantiel. La tranche suivante est alors `0.3.1-3-rc.1`, avec gel fonctionnel, packaging RC et matrice finale x86_64 + ARM64.
|
||||
64
deltas/0.3.1/3-rc.1.md
Normal file
64
deltas/0.3.1/3-rc.1.md
Normal file
@@ -0,0 +1,64 @@
|
||||
<!-- file: deltas/0.3.1/3-rc.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1-3-rc.1
|
||||
|
||||
## Base requise
|
||||
|
||||
`0.3.1-2-beta.1`, validée le 2026-09-21.
|
||||
|
||||
## Objectif
|
||||
|
||||
Créer la candidate de publication `0.3.1` sans rouvrir le scope fonctionnel du POC Snake Tauri Android.
|
||||
|
||||
## Gel RC
|
||||
|
||||
Le scope `0.3.1` est gelé. Cette tranche n'ajoute :
|
||||
|
||||
- aucune fonctionnalité ;
|
||||
- aucun nouveau contrôle ;
|
||||
- aucun framework ou refactor Web/Tauri ;
|
||||
- aucune dépendance ;
|
||||
- aucun changement de gameplay ;
|
||||
- aucun AAB Tauri ;
|
||||
- aucun patch du scaffold `gen/android`.
|
||||
|
||||
Seuls les correctifs autorisés par `VER-RC-*` peuvent suivre sous `3-rc.1.fix.N`.
|
||||
|
||||
## Validation beta acquise
|
||||
|
||||
`2-beta.1` a validé :
|
||||
|
||||
- audits/check/Clippy workspace ;
|
||||
- `cargo test --workspace --all-targets --all-features` avec 35 tests réussis ;
|
||||
- build WASM/Vite possédé par Tauri ;
|
||||
- APK Debug universal ;
|
||||
- compilation Android `aarch64-linux-android` + `x86_64-linux-android` ;
|
||||
- installation/lancement du même APK sur Galaxy S9+ ARM64 et AVD API 36 x86_64.
|
||||
|
||||
Le contrôle mécanique `unzip -l` des deux entrées ABI n'a pas été transmis et reste dans la gate RC.
|
||||
|
||||
## Changements
|
||||
|
||||
- passage de `workspace.package.version` à `0.3.1-3-rc.1` ;
|
||||
- synchronisation du package frontend Tauri Snake à `0.3.1-3-rc.1` ;
|
||||
- entrée RC dans `CHANGELOG.md` ;
|
||||
- historique de la beta validée ;
|
||||
- consolidation du plan `0.3.1` avec omission de `2-beta.2` ;
|
||||
- création de `docs/testing/005-V0_3_1_RC_VALIDATION_MATRIX.md` ;
|
||||
- préparation de `prompts/004-V0_3_3_START_PROMPT.md`, puisque `0.3.2` reste différée ;
|
||||
- mise à jour de la roadmap pour réserver à `0.3.3` le pipeline SDL3 natif multi-ABI, l'AAB et l'évaluation du support d'anciennes versions Android.
|
||||
|
||||
## Validation RC
|
||||
|
||||
Appliquer intégralement :
|
||||
|
||||
```text
|
||||
docs/testing/005-V0_3_1_RC_VALIDATION_MATRIX.md
|
||||
```
|
||||
|
||||
La gate revalide le workspace complet, reconstruit l'APK autonome universal et le fume sur x86_64 + ARM64. Aucun `npm run build` manuel et aucun AAB ne sont requis.
|
||||
|
||||
## Après validation
|
||||
|
||||
Si la RC est propre, la promotion vers `0.3.1` est mécanique : versions stables, entrée stable du changelog, historique RC, clôture du plan et delta de release. Aucun nouveau comportement ne doit être introduit.
|
||||
56
deltas/0.3.1/rel.001.md
Normal file
56
deltas/0.3.1/rel.001.md
Normal file
@@ -0,0 +1,56 @@
|
||||
<!-- file: deltas/0.3.1/rel.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.3.1 — release stable
|
||||
|
||||
## Base
|
||||
|
||||
Base validée : `0.3.1-3-rc.1`.
|
||||
|
||||
## Objet
|
||||
|
||||
Promouvoir mécaniquement la candidate validée vers `0.3.1` sans introduire de nouveau comportement.
|
||||
|
||||
## Changements
|
||||
|
||||
La release stable :
|
||||
|
||||
- passe `workspace.package.version` de `0.3.1-3-rc.1` à `0.3.1` ;
|
||||
- passe le package frontend Tauri Snake de `0.3.1-3-rc.1` à `0.3.1` ;
|
||||
- positionne `README.md` sur la stable `0.3.1` et `0.3.3` comme prochaine version active planifiée, `0.3.2` restant différée ;
|
||||
- marque `0.3.1` comme terminée dans `ROADMAP.md` ;
|
||||
- ajoute l'entrée stable `0.3.1` dans `CHANGELOG.md` ;
|
||||
- enregistre la validation effective de la RC dans `history/0.3.1/3-rc.1.md` ;
|
||||
- clôt le plan `0.3.1` et confirme que l'AAB/compatibilité Android ancienne appartiennent au POC SDL3 natif `0.3.3`.
|
||||
|
||||
Le prompt `prompts/004-V0_3_3_START_PROMPT.md` est conservé tel que préparé et validé en RC.
|
||||
|
||||
## Frontière de release
|
||||
|
||||
Aucun changement de gameplay, de code Rust, de dépendance, de configuration exécutable, de frontend, de build Android, d'architecture ou de capability n'est introduit après la RC.
|
||||
|
||||
## Validation
|
||||
|
||||
La gate RC complète a déjà été validée sur un état fonctionnellement identique. La promotion stable ne requiert que les gates proportionnelles aux changements de versions et de documentation :
|
||||
|
||||
```bash
|
||||
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 check --workspace
|
||||
|
||||
(cd crates/apps/game-snake-poc-tauri && npm install)
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android build --debug --apk --target aarch64 --target x86_64)
|
||||
```
|
||||
|
||||
Le build Tauri reste la seule validation frontend de release : ne pas lancer `npm run build` manuellement. Les smokes AVD/ARM64, Clippy strict et la suite workspace complète ne sont pas répétés, car aucun code/runtime n'a changé depuis la RC validée.
|
||||
|
||||
## Publication
|
||||
|
||||
Après validation de ce delta :
|
||||
|
||||
- commit de release ;
|
||||
- tag stable `v0.3.1` ;
|
||||
- prochaine session ouverte uniquement à partir de la stable taggée `v0.3.1` et de `prompts/004-V0_3_3_START_PROMPT.md` ;
|
||||
- ne pas créer artificiellement `0.3.2` tant que son critère de réouverture n'est pas satisfait.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/000-README.md -->
|
||||
<!-- version: 27 -->
|
||||
<!-- version: 29 -->
|
||||
|
||||
# Documentation games.sasedev
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
## Plans
|
||||
|
||||
- [`plans/000-README.md`](plans/000-README.md) — plans vivants des versions ; le plan actif porte notamment le découpage prévisionnel souple des prereleases.
|
||||
- [`plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan actif de `0.3.0`, premier POC Snake Web direct.
|
||||
- [`plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan clôturé de `0.3.0`, premier POC Snake Web direct.
|
||||
- [`plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md`](plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md) — plan actif de `0.3.1`, second host Snake Tauri Android.
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -69,6 +70,7 @@ Voir [`../RULES.md`](../RULES.md), notamment [`rules/RULES_DOCUMENTATION.md`](ru
|
||||
- [`testing/002-BETA_VALIDATION_MATRIX.md`](testing/002-BETA_VALIDATION_MATRIX.md) — matrice beta Desktop SDL3, Tauri/WASM et Android multi-appareils.
|
||||
- [`testing/003-RC_VALIDATION_MATRIX.md`](testing/003-RC_VALIDATION_MATRIX.md) — matrice RC de reproductibilité, packaging final et promotion vers `0.1.0`.
|
||||
- [`testing/004-V0_3_0_RC_VALIDATION_MATRIX.md`](testing/004-V0_3_0_RC_VALIDATION_MATRIX.md) — gate RC spécifique au POC Snake Web direct et à son témoin Desktop SDL3.
|
||||
- [`testing/005-V0_3_1_RC_VALIDATION_MATRIX.md`](testing/005-V0_3_1_RC_VALIDATION_MATRIX.md) — gate RC du POC Snake Tauri Android de référence, incluant workspace complet et APK universal x86_64 + ARM64.
|
||||
- [`development/003-TRACING_AND_DIAGNOSTICS.md`](development/003-TRACING_AND_DIAGNOSTICS.md) — socle `tracing`, subscriber et appender communs.
|
||||
- [`development/004-SDL3_DESKTOP_PREREQUISITES.md`](development/004-SDL3_DESKTOP_PREREQUISITES.md) — prérequis SDL3 Desktop, stratégie de liaison système et vérification `pkg-config`.
|
||||
- [`development/005-DESKTOP_WINDOW_POLICY.md`](development/005-DESKTOP_WINDOW_POLICY.md) — taille initiale, redimensionnement et séparation future entre fenêtre physique et résolution virtuelle.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/010-RUNTIME_PROVENANCE.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Provenance d'environnement d'exécution
|
||||
|
||||
@@ -45,7 +45,7 @@ RuntimeHost = Native
|
||||
InputProfile = KeyboardMouse
|
||||
```
|
||||
|
||||
Le futur POC Tauri/WASM :
|
||||
Un host Tauri Desktop/WASM :
|
||||
|
||||
```text
|
||||
PlatformFamily = Desktop
|
||||
@@ -55,7 +55,17 @@ RuntimeHost = TauriWebView
|
||||
InputProfile = KeyboardMouse
|
||||
```
|
||||
|
||||
Une version Web dans un navigateur de téléphone pourra au contraire être `PlatformFamily = Web`, `DeviceClass = Phone`, `ExecutionModel = Wasm`, `RuntimeHost = Browser`, `InputProfile = Touch`.
|
||||
Le POC Tauri Android de `0.3.1` doit au contraire utiliser :
|
||||
|
||||
```text
|
||||
PlatformFamily = Android
|
||||
DeviceClass = Phone ou Tablet
|
||||
ExecutionModel = Wasm
|
||||
RuntimeHost = TauriWebView
|
||||
InputProfile = Touch ou Mixed selon les entrées réellement observées
|
||||
```
|
||||
|
||||
Une version Web dans un navigateur de téléphone pourra être `PlatformFamily = Web`, `DeviceClass = Phone`, `ExecutionModel = Wasm`, `RuntimeHost = Browser`, `InputProfile = Touch`.
|
||||
|
||||
## Classements et équité
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/015-PLATFORM_POC_ARCHITECTURE.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 5 -->
|
||||
|
||||
# Architecture des POC plateforme et réseau
|
||||
|
||||
@@ -14,12 +14,22 @@ Snake est le jeu-sonde principal.
|
||||
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 — prochain host prévu par `0.3.1` ;
|
||||
- Tauri Desktop + Snake — prévu ensuite pour éprouver la factorisation WebView ;
|
||||
- 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 — 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.
|
||||
|
||||
## Positionnement Tauri Android après `0.3.1`
|
||||
|
||||
Le host Tauri Android reste pertinent comme preuve de portabilité du gameplay Rust/WASM et comme banc d’essai WebView. Il n’est pas retenu comme distribution Android de jeu par défaut.
|
||||
|
||||
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.
|
||||
|
||||
Le smoke ARM64 réel de `0.3.1` renforce ce positionnement : le jeu et le touch fonctionnent, mais le mode développement impose un routage `devUrl`/ADB spécifique et le Back système a exposé un abort natif pendant le teardown WebView sur l'appareil de validation. Ce défaut ne justifie pas un fork local de Tauri/Wry pour un POC non retenu comme cible Android productive ; il reste une limite documentée à comparer au package autonome.
|
||||
|
||||
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
|
||||
|
||||
Avant le Mode 3, comparer au minimum WebSocket/tokio-tungstenite, WebTransport/QUIC, fallback automatique, charge, reconnect/resync, backpressure, snapshots/deltas et mobilité réseau.
|
||||
@@ -38,7 +48,7 @@ Un POC sert à identifier duplication, adapters manquants, capability réellemen
|
||||
|
||||
Une abstraction n'est pas extraite avant observation d'un besoin concret.
|
||||
|
||||
Le POC Web direct `0.3.0` n'a pas justifié d'extraire prématurément un adapter WASM commun entre Reflex et Snake : les deux adapters spécifiques restent acceptés. Le second host Snake doit d'abord fournir un second besoin réel avant toute factorisation.
|
||||
Le POC Web direct `0.3.0` n'a pas justifié d'extraire prématurément un adapter WASM commun entre Reflex et Snake : les deux adapters spécifiques restent acceptés. Le second host Snake fournit un second consommateur technique, mais son statut de POC Tauri Android de référence réduit encore l'intérêt d'une factorisation durable : une extraction n'est retenue que si elle reste utile à au moins deux hosts réellement conservés.
|
||||
|
||||
## Relation avec Uroburas
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/000-README.md -->
|
||||
<!-- version: 1 -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Plans de versions games.sasedev
|
||||
|
||||
@@ -11,4 +11,5 @@ Le `ROADMAP.md` reste la trajectoire macroscopique du projet ; les deltas décri
|
||||
|
||||
## Plans
|
||||
|
||||
- [`001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan actif de `0.3.0`, baseline Snake et premier POC Web direct.
|
||||
- [`001-V0_3_0_WEB_SNAKE_POC_PLAN.md`](001-V0_3_0_WEB_SNAKE_POC_PLAN.md) — plan clôturé de `0.3.0`, baseline Snake et premier POC Web direct.
|
||||
- [`002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md`](002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md) — plan actif de `0.3.1`, second host Snake Tauri Android.
|
||||
|
||||
207
docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md
Normal file
207
docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md
Normal file
@@ -0,0 +1,207 @@
|
||||
<!-- file: docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md -->
|
||||
<!-- version: 11 -->
|
||||
|
||||
# Plan v0.3.1 — second host Snake Tauri Android
|
||||
|
||||
## But de la version
|
||||
|
||||
`0.3.1` doit terminer un second host Snake réellement exécutable sous Tauri Android en réutilisant la baseline Web/WASM validée par `0.3.0`, puis conserver ce host comme POC de référence plutôt que comme voie de production des jeux Android.
|
||||
|
||||
La version ne doit ni déplacer le gameplay hors de `game-snake-poc`, ni créer un second adapter Snake, ni transformer immédiatement les similitudes Web/Tauri en framework générique.
|
||||
|
||||
Base stable : `0.3.0`.
|
||||
|
||||
Cadrage : [`../studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md`](../studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md).
|
||||
|
||||
## Décisions acquises
|
||||
|
||||
- la nouvelle crate sera `crates/apps/game-snake-poc-tauri` ;
|
||||
- `0.3.1` valide uniquement sa cible Android et en fait un POC de référence, pas une distribution jeu Android de production ;
|
||||
- `game-snake-poc` reste inchangé sauf défaut réellement découvert ;
|
||||
- `game-snake-poc-wasm` reste l'unique adapter Snake WASM et recevra seulement la généralisation de provenance nécessaire au second host ;
|
||||
- le frontend Tauri part du comportement réellement validé dans `Web/game-snake-poc`, avec adaptation de lifecycle et logging ;
|
||||
- `lib.rs` est une façade/reexport et `tauri.rs` reste l'assemblage Tauri ;
|
||||
- le tracing frontend utilise `@fltsci/tauri-plugin-tracing` ;
|
||||
- les hooks Tauri possèdent le build frontend/WASM ;
|
||||
- aucun nouveau chemin de build n'est piloté par Python ;
|
||||
- `README.md` et `USAGE.md` seront créés avec l'app : architecture pour le premier, prérequis/commandes/smokes pour le second ;
|
||||
- `cargo tauri android init/dev/build` sont les commandes mobiles de référence ;
|
||||
- SimpleBar et `resize-observer-polyfill` ne sont pas ajoutés au host Tauri sans besoin démontré ;
|
||||
- la voie Android de production reste le host natif SDL3/Java/JNI tant qu’un besoin fonctionnel démontré ne justifie pas Tauri ;
|
||||
- Tauri Android peut rester utile comme référence comparative, notamment pour évaluer plus tard les saisies texte/WebView, mais ce besoin n’est pas considéré comme acquis ;
|
||||
- une future variante Tauri Desktop reste conditionnée à un avantage explicite, notamment une monétisation WebView/publicitaire techniquement et contractuellement viable.
|
||||
|
||||
## Scope
|
||||
|
||||
La version couvre :
|
||||
|
||||
- création de la crate/app Tauri Snake ;
|
||||
- initialisation de la cible Android par Tauri ;
|
||||
- pipeline Rust/WASM + Vite/TypeScript possédé par Tauri sans Python ;
|
||||
- consommation de `game-snake-poc-wasm` ;
|
||||
- shell Canvas, contrôles touch et comportement responsive nécessaires au jeu ;
|
||||
- assets communs et spécifiques Snake ;
|
||||
- lifecycle mobile/WebView ;
|
||||
- provenance `Android / Wasm / TauriWebView` ;
|
||||
- tracing Rust/Tauri/frontend ;
|
||||
- politique de sortie/Back conforme au moteur ;
|
||||
- build/package et smoke sur AVD/appareil disponible aux jalons prévus ;
|
||||
- comparaison du code Web direct/Tauri après fonctionnement réel afin de décider s'il existe une extraction commune justifiée.
|
||||
|
||||
Hors scope : Tauri Desktop Snake comme cible validée, iOS, Android SDL3 multi-ABI additionnel, réseau realtime, Uroburas, intégration ads effective, billing, auth et leaderboard.
|
||||
|
||||
## Positionnement produit après validation du host minimal
|
||||
|
||||
Le smoke `0-pre.2.fix.3` a confirmé que Tauri Android fonctionne techniquement, mais aussi que son outillage ajoute une couche de complexité propre au host : combinaison JDK/Gradle imposée par la version Tauri, projet Android généré et chaîne WebView/WASM supplémentaire alors que le POC Android natif SDL3 fonctionne déjà.
|
||||
|
||||
Décision de `0-pre.3` :
|
||||
|
||||
- terminer `0.3.1` afin d’obtenir un POC Tauri Android jouable et documenté ;
|
||||
- conserver `game-snake-poc-tauri` comme POC de référence et banc de comparaison ;
|
||||
- ne pas utiliser Tauri Android comme template de nouvelles applications de jeu ;
|
||||
- privilégier SDL3 natif pour Android ;
|
||||
- ne rouvrir la question Tauri Android que pour un besoin concret que SDL3 ne couvre pas proprement, par exemple une saisie texte complexe après test réel des possibilités SDL ;
|
||||
- évaluer séparément Tauri Desktop seulement si la WebView apporte un avantage produit mesurable, notamment une voie publicitaire exploitable.
|
||||
|
||||
Cette décision ne réduit pas le critère de qualité de `0.3.1` : le POC de référence doit rester jouable, reproductible et suffisamment complet pour permettre une comparaison technique utile.
|
||||
|
||||
## Prévision souple
|
||||
|
||||
### `0-pre.1` — cadrage et règles
|
||||
|
||||
Audit complet de l'archive stable, règles, baseline Web/WASM, Tauri Reflex, références Desk KSP accessibles, environnement Android historique et commandes Tauri mobiles actuelles.
|
||||
|
||||
Livraison : étude `024`, présent plan, correction des règles Tauri Android, clarification `PlatformFamily`, index documentaires et ouverture de la version technique `0.3.1-0-pre.1`.
|
||||
|
||||
Aucun scaffold Tauri Snake n'est créé. Tranche validée par la gate utilisateur du 2026-09-20.
|
||||
|
||||
### `0-pre.2` — host Tauri Android minimal
|
||||
|
||||
Créer `game-snake-poc-tauri` avec :
|
||||
|
||||
- manifest Cargo/build script/config Tauri/capabilities ;
|
||||
- `lib.rs` façade, `tauri.rs` assemblage et modules propriétaires minimaux ;
|
||||
- point d'entrée `run()` mobile annoté `#[cfg_attr(mobile, tauri::mobile_entry_point)]` dans le module propriétaire puis réexporté par `lib.rs` ;
|
||||
- frontend Vite/TypeScript minimal ;
|
||||
- bridge tracing initialisé ;
|
||||
- hooks de build natifs, sans Python ;
|
||||
- cible Android initialisée via Tauri ;
|
||||
- chargement du même adapter `game-snake-poc-wasm` après généralisation minimale de provenance ;
|
||||
- `README.md` et `USAGE.md` initiaux.
|
||||
|
||||
La tranche vise un premier démarrage Tauri Android minimal, pas encore toute la finition input/lifecycle.
|
||||
|
||||
État candidat livré : crate `game-snake-poc-tauri`, bridge Rust/Tauri, hooks WASM/Vite sans Python, frontend minimal, tracing frontend/Rust et provenance partagée `Android / TauriWebView / Wasm`. L'initialisation générée `cargo tauri android init` reste volontairement locale et fait partie de la gate utilisateur, car `gen/` n'est pas un artefact source distribué.
|
||||
|
||||
Gate utilisateur : audits, Cargo workspace strict, test ciblé de l'adapter WASM, non-régression du build Web direct, `cargo tauri android init` puis `cargo tauri android dev` sur un AVD ou appareil disponible. `cargo tauri android build` reste reporté aux phases finales sauf besoin diagnostique.
|
||||
|
||||
Le premier smoke `0-pre.2` a révélé deux défauts bornés : `build.rs` échouait sous Clippy strict à cause de la rustdoc manquante, et Java 25 ne pouvait pas exécuter le wrapper Gradle `8.14.3` généré par Tauri CLI `2.11.3`. `0-pre.2.fix.1` a tenté de migrer localement le scaffold généré vers Gradle 9 ; cette approche est abandonnée à partir de `0-pre.2.fix.2` car la branche stable Tauri 2.11.x n'a pas encore publié cette migration et le projet ne doit pas maintenir un fork implicite des templates Android Tauri. `0-pre.2.fix.3` fixe JDK 17 comme baseline Android reproductible pour la chaîne officielle Gradle `8.14.3` + AGP `8.11.0` et impose la régénération de tout `gen/android` touché par la tentative `fix.1`. Le Gradle global de la machine ne fait pas partie du contrat reproductible.
|
||||
|
||||
### `0-pre.3` — shell Snake, Canvas, input et assets
|
||||
|
||||
Réutiliser sélectivement le host Web validé :
|
||||
|
||||
- rendu Canvas et session fixed-step ;
|
||||
- shell responsive pertinent ;
|
||||
- contrôles directionnels touch/pointer et clavier lorsque disponible ;
|
||||
- resize/orientation ;
|
||||
- assets canoniques communs + Snake ;
|
||||
- absence de dépendances Web-only inutiles.
|
||||
|
||||
Aucune extraction commune n'est réalisée uniquement pour éviter quelques fichiers similaires pendant la mise au point.
|
||||
|
||||
### `0-pre.4` — lifecycle, provenance, tracing et sortie mobile
|
||||
|
||||
Stabiliser :
|
||||
|
||||
- background/foreground et reprise sans rattrapage massif ;
|
||||
- rotation/resize ;
|
||||
- provenance `Android / Wasm / TauriWebView` + device/input observés ;
|
||||
- tracing Rust/Tauri/frontend ;
|
||||
- sorties applicatives conformes à `EngineGame::quit_requested` sans détourner le Back système Android ;
|
||||
- smokes AVD et, si disponible, appareil réel.
|
||||
|
||||
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.
|
||||
|
||||
La gate AVD `0-pre.4` est propre. Le smoke supplémentaire sur Galaxy S9+ ARM64 a confirmé compilation `aarch64-linux-android`, installation, Canvas, assets, WASM, touch et lifecycle visible/hidden via un tunnel ADB USB. Deux écarts ont été observés : le HMR utilisait encore un port WebSocket séparé, défaut local corrigé par `0-pre.4.fix.1`, et le Back système a déclenché un abort natif `FORTIFY: pthread_mutex_lock called on a destroyed mutex` pendant le teardown de l'Activity/WebView. Les logs placent cet abort après `visibility hidden` et avant `pagehide`, sans `runtime disposed`.
|
||||
|
||||
`0-pre.4.fix.1` ne tente pas de migrer manuellement Tauri/Wry ni de patcher `gen/android`. Il unifie HTTP et HMR sur le port `1436` et sa gate réelle ARM64 est validée : le frontend atteint `ready`, le touch est observé et l'erreur WebSocket Vite a disparu. Le Back n'a pas reproduit l'abort `FORTIFY` du smoke précédent et est allé jusqu'au détachement de la fenêtre ; le défaut reste néanmoins considéré comme potentiellement intermittent jusqu'au smoke de l'APK autonome `2-beta.1`.
|
||||
|
||||
### `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.
|
||||
|
||||
Une extraction possible doit rester bornée à une responsabilité clairement partagée, par exemple projection/rendu Canvas, mapping input Web ou helpers d'assets. Lifecycle et logging restent host-specific s'ils divergent réellement.
|
||||
|
||||
Si aucune extraction n'est justifiée, cette tranche est omise.
|
||||
|
||||
### `2-beta.1` — validation large et packaging Android
|
||||
|
||||
Tranche validée le 2026-09-21. Aucun `0-pre.5` n'était justifié : aucune extraction Web/Tauri ne conserve assez de valeur maintenant que le host Android Tauri est explicitement un POC de référence.
|
||||
|
||||
Résultats acquis :
|
||||
|
||||
- audits statiques, `cargo fmt`, `cargo check --workspace` et Clippy workspace strict propres ;
|
||||
- suite `cargo test --workspace --all-targets --all-features` propre avec 35 tests réussis et aucun échec ;
|
||||
- hook Tauri `beforeBuildCommand` : WASM release, `wasm-bindgen`, TypeScript/Vite et copie des assets réussis ;
|
||||
- APK Debug universal généré avec `aarch64-linux-android` et `x86_64-linux-android` ;
|
||||
- installation et lancement réussis sur Galaxy S9+ ARM64 réel puis AVD API 36 x86_64 ;
|
||||
- aucun serveur Vite, port `1436` ou tunnel ADB requis pour le package autonome.
|
||||
|
||||
Le contrôle `unzip` explicite des deux entrées ABI n'a pas été fourni dans la sortie utilisateur ; la RC le conserve donc comme contrôle mécanique, même si l'installation/lancement du même APK sur ARM64 et x86_64 exerce déjà les deux architectures en pratique.
|
||||
|
||||
### `2-beta.2` — omise
|
||||
|
||||
Aucune consolidation beta supplémentaire ne justifie une tranche autonome. Les documents durables nécessaires sont consolidés directement à l'ouverture de la RC.
|
||||
|
||||
### `3-rc.1` — candidate gelée — validée
|
||||
|
||||
Tranche validée le 2026-09-21. Gel fonctionnel strict, synchronisation des versions RC, `CHANGELOG.md`, historique beta, matrice RC spécifique `0.3.1` et préparation du prompt de la prochaine version active. Aucun nouveau framework, host, gameplay ou comportement.
|
||||
|
||||
La gate RC a revalidé le workspace complet, reconstruit l'APK autonome universal, vérifié explicitement les entrées `arm64-v8a` et `x86_64`, puis installé et lancé le même APK sur AVD API 36 x86_64 et Galaxy S9+ ARM64. Aucun correctif RC n'est nécessaire.
|
||||
|
||||
### `0.3.1` — release stable — publiée
|
||||
|
||||
Promotion mécanique de la RC validée : versions stables, changelog, historique RC et clôture du plan. Aucun ajout fonctionnel. L'AAB reste volontairement hors `0.3.1` et appartient à la prochaine voie Android SDL3 native `0.3.3`.
|
||||
|
||||
## Inventaire environnement requis avant `0-pre.2`
|
||||
|
||||
La gate `0-pre.1` doit recevoir au minimum :
|
||||
|
||||
```bash
|
||||
rustc --version
|
||||
cargo --version
|
||||
cargo tauri --version
|
||||
rustup target list --installed
|
||||
node --version
|
||||
npm --version
|
||||
wasm-bindgen --version
|
||||
java -version
|
||||
printf 'JAVA_HOME=%s\nANDROID_HOME=%s\n' "$JAVA_HOME" "$ANDROID_HOME"
|
||||
adb version
|
||||
adb devices -l
|
||||
emulator -list-avds
|
||||
```
|
||||
|
||||
L'absence d'un outil ne doit pas être masquée. Elle devient un prérequis concret de `0-pre.2` ou motive un fix borné de `0-pre.1`.
|
||||
|
||||
La gate `0-pre.1` validée le 2026-09-20 a confirmé Rust `1.94.1`, Tauri CLI `2.11.3`, Node `24.21.0`, npm `11.19.0`, wasm-bindgen `0.2.128`, OpenJDK `25.0.4.1`, `ANDROID_HOME=/home/sinus/DEV/AndroidSDK`, un appareil ARM64 réel et trois AVD disponibles. `JAVA_HOME` était vide et Java 25 était résolu depuis le `PATH`. Les smokes `0-pre.2` ont confirmé que Tauri sélectionne lui-même le NDK side-by-side sous `$ANDROID_HOME/ndk/<version>`. Le JBR de l'Android Studio local est également Java 25 ; il n'est donc pas compatible avec Gradle `8.14.3`. Pour `0.3.1`, `JAVA_HOME` doit pointer vers JDK 17 pendant `cargo tauri android init/dev/build`.
|
||||
|
||||
## Critères de fermeture de 0.3.1
|
||||
|
||||
La version peut entrer en RC lorsque :
|
||||
|
||||
- Snake est jouable dans le WebView Tauri Android sans gameplay dupliqué et le host est explicitement positionné comme POC de référence ;
|
||||
- le même adapter WASM sert Web direct et Tauri Android avec provenance exacte ;
|
||||
- lifecycle/input/assets/tracing/Back ont un comportement explicite et validé ;
|
||||
- le chemin de build ne dépend d'aucun orchestrateur Python ;
|
||||
- le packaging Tauri Android est reproductible ;
|
||||
- les smokes prévus sur cible Android ont été exécutés ;
|
||||
- aucune extraction commune non prouvée n'a été introduite ;
|
||||
- la documentation opérateur et architecture reflète l'état réel.
|
||||
|
||||
## Version suivante
|
||||
|
||||
`0.3.2` reste différée : aucune voie de monétisation Desktop/WebView suffisamment démontrée ne justifie son ouverture. La prochaine version active prévue est `0.3.3`, consacrée à Android SDL3 natif multi-ABI. Son `0-pre.1` devra notamment cadrer un AAB de distribution, distinguer compatibilité ABI et compatibilité de version Android, puis déterminer expérimentalement le `minSdk` réellement soutenable avant de promettre le support d’anciens appareils.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/rules/PROMPT_STRUCTURE.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Structure des prompts de reprise
|
||||
|
||||
@@ -24,7 +24,7 @@ Le prompt rappelle les invariants qui évitent les erreurs de workflow et renvoi
|
||||
## Commandes avec répertoire et Tauri
|
||||
|
||||
- **PROMPT-STR-016** — Le prompt rappelle que toute commande nécessitant un `cd` est englobée dans un sous-shell, par exemple `(cd <dir> && <commande>)`, afin de ne pas modifier le répertoire courant pour les commandes suivantes.
|
||||
- **PROMPT-STR-017** — Lorsqu'une version touche Tauri, le prompt rappelle que `npm` sert à gérer les dépendances frontend mais que les builds/smokes passent par Tauri : `(cd <tauri-app> && cargo tauri dev)` pour le smoke courant et `(cd <tauri-app> && cargo tauri build)` aux phases finales de packaging prévues. Les hooks Tauri possèdent Vite/TypeScript/WASM ; `npm run dev`/`npm run build` ne deviennent pas des gates manuelles Tauri.
|
||||
- **PROMPT-STR-017** — Lorsqu'une version touche Tauri, le prompt rappelle que `npm` sert à gérer les dépendances frontend mais que les builds/smokes passent par Tauri. Il utilise les commandes de la cible concernée : `(cd <tauri-app> && cargo tauri dev)` / `cargo tauri build` pour Desktop, ou `(cd <tauri-app> && cargo tauri android dev)` / `cargo tauri android build` pour Android. Les hooks Tauri possèdent Vite/TypeScript/WASM ; `npm run dev`/`npm run build` ne deviennent pas des gates manuelles Tauri.
|
||||
|
||||
## Documentation et traçabilité à rappeler
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/rules/RULES_COMMANDS.md -->
|
||||
<!-- version: 13 -->
|
||||
<!-- version: 14 -->
|
||||
|
||||
# Règles d'exécution des commandes
|
||||
|
||||
@@ -61,11 +61,14 @@
|
||||
- **CMD-WEB-003** — Le POC Tauri/WASM historique `0.1.0` utilise `scripts/build_reflex_tauri_wasm.py` ; ce script reste une référence de baseline mais ne doit pas être réutilisé comme orchestrateur par un POC `0.3.x`, conformément à `CMD-BUILD-004`.
|
||||
- **CMD-WEB-004** — Les fichiers produits par `wasm-bindgen` sont générés localement et ne sont pas commités.
|
||||
- **CMD-WEB-005** — Dans une app Tauri, `npm` sert uniquement à gérer les dépendances frontend lorsque nécessaire, par exemple `npm i <package>`, `npm i -D <package>` ou leur opération inverse. Les scripts `npm run dev`, `npm run build` ou équivalents ne sont pas des gates manuelles : Vite/TypeScript/WASM sont déclenchés par les hooks Tauri configurés.
|
||||
- **CMD-WEB-006** — Le smoke normal d'une app Tauri est lancé via `(cd <tauri-app> && cargo tauri dev)`. Cette commande possède le serveur Vite et les hooks frontend nécessaires.
|
||||
- **CMD-WEB-007** — Le packaging Tauri est validé dans les phases finales prévues par le plan via `(cd <tauri-app> && cargo tauri build)`, typiquement en beta préfinale, RC ou avant release selon le scope. Il n'est pas exécuté après chaque petit delta Tauri.
|
||||
- **CMD-WEB-006** — Le smoke normal d'une app Tauri Desktop est lancé via `(cd <tauri-app> && cargo tauri dev)`. Cette commande possède le serveur Vite et les hooks frontend nécessaires.
|
||||
- **CMD-WEB-007** — Le packaging Tauri Desktop est validé dans les phases finales prévues par le plan via `(cd <tauri-app> && cargo tauri build)`, typiquement en beta préfinale, RC ou avant release selon le scope. Il n'est pas exécuté après chaque petit delta Tauri.
|
||||
- **CMD-WEB-008** — Pour un host Web navigateur direct sous `Web/<game>/`, les commandes npm/Vite peuvent être exécutées directement, toujours dans un sous-shell lorsqu'un changement de répertoire est nécessaire, par exemple `(cd Web/<game> && npm install && npm run build)`.
|
||||
- **CMD-WEB-009** — Le build d'un host Web direct qui consomme un adapter `wasm-bindgen` exécute d'abord le build Rust/WASM et la génération des bindings hors dépôt, puis seulement le build TypeScript/Vite.
|
||||
- **CMD-WEB-010** — Un smoke navigateur manuel d'un host Web direct vérifie au minimum le chargement WASM, le Canvas, les entrées prévues par la tranche et le comportement responsive concerné.
|
||||
- **CMD-WEB-011** — Une cible Tauri Android existante est initialisée depuis sa crate avec `(cd <tauri-app> && cargo tauri android init)` lorsqu'elle ne possède pas encore le projet mobile généré requis ; cette initialisation n'est pas rejouée comme gate ordinaire.
|
||||
- **CMD-WEB-012** — Le smoke interactif d'une app Tauri Android utilise `(cd <tauri-app> && cargo tauri android dev)` ; il remplace `cargo tauri dev` pour cette cible mobile.
|
||||
- **CMD-WEB-013** — Le packaging Tauri Android utilise `(cd <tauri-app> && cargo tauri android build)` dans les phases finales prévues par le plan ; `--apk` ou `--aab` est ajouté uniquement lorsque le livrable visé le requiert.
|
||||
|
||||
## Git et fichiers générés
|
||||
|
||||
@@ -78,7 +81,7 @@
|
||||
|
||||
- **CMD-BETA-001** — À l'entrée en beta, `scripts/audit_distribution_layout.py` vérifie les frontières statiques nécessaires aux runners et packagings supportés.
|
||||
- **CMD-BETA-002** — La transition alpha vers beta exécute une suite Cargo workspace complète en plus des tests ciblés.
|
||||
- **CMD-BETA-003** — Si la version touche le périmètre Tauri, le plan réserve au moins une validation de packaging dans une phase finale appropriée via `(cd <tauri-app> && cargo tauri build)` ; les itérations et smokes courants utilisent `cargo tauri dev`.
|
||||
- **CMD-BETA-003** — Si la version touche le périmètre Tauri, le plan réserve au moins une validation de packaging dans une phase finale appropriée avec la commande Tauri correspondant à la cible : `cargo tauri build` pour Desktop ou `cargo tauri android build` pour Android. Les smokes utilisent de même `cargo tauri dev` ou `cargo tauri android dev` selon la cible.
|
||||
- **CMD-BETA-004** — Les APK Debug servent à la validation multi-appareils beta ; la signature de publication appartient à la phase RC/stable.
|
||||
|
||||
## RC et release
|
||||
@@ -86,7 +89,7 @@
|
||||
- **CMD-RC-001** — L'entrée en RC gèle le périmètre fonctionnel de la version courante ; seuls les correctifs, la reproductibilité des builds, le packaging, la documentation de livraison et les défauts de release sont admis.
|
||||
- **CMD-RC-002** — La validation d'une RC exécute `cargo test --workspace --all-targets --all-features` en plus des audits, du check et de Clippy strict.
|
||||
- **CMD-RC-003** — Les deux runners Desktop natifs sont construits en `--release` et font l'objet d'un smoke sur les binaires de release.
|
||||
- **CMD-RC-004** — Une RC Tauri est construite via `(cd <tauri-app> && cargo tauri build)` ; ses hooks possèdent toujours le build WASM et Vite/TypeScript. Les smokes interactifs restent lancés avec `(cd <tauri-app> && cargo tauri dev)`.
|
||||
- **CMD-RC-004** — Une RC Tauri est construite avec la commande de packaging correspondant à sa cible : `(cd <tauri-app> && cargo tauri build)` pour Desktop ou `(cd <tauri-app> && cargo tauri android build)` pour Android. Ses hooks possèdent toujours le build WASM et Vite/TypeScript ; les smokes utilisent la variante `dev` correspondante.
|
||||
- **CMD-RC-005** — Android RC revalide au minimum x86_64 sur AVD et ARM64 sur appareil réel avec les APK issus de l'état RC.
|
||||
- **CMD-RC-006** — Les secrets de signature, keystores et credentials de publication ne sont jamais commités. Leur présence est une condition externe de publication, pas une donnée du dépôt.
|
||||
- **CMD-RC-007** — Une RC n'est promue en stable que si aucun correctif `.fix.N` n'est nécessaire après la gate RC complète.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/rules/RULES_PROJECT.md -->
|
||||
<!-- version: 16 -->
|
||||
<!-- version: 17 -->
|
||||
|
||||
# Règles spécifiques games.sasedev
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
- **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.
|
||||
- **GAME-PLATFORM-013** — Les demandes de sortie applicatives Tauri sont évaluées par la politique `EngineGame::quit_requested` avant toute fermeture native contrôlée par l'application. Cette règle n'impose pas de consommer le Back système Android, qui reste régi par `GAME-PLATFORM-014`.
|
||||
|
||||
- **GAME-BUILD-001** — Les artefacts générés Cargo, Tauri, Vite et caches frontend sont placés hors de la racine du dépôt, sous `../builds/sasedev-games/`; un répertoire racine `builds/` dans le dépôt est interdit.
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
## Réservation de plateformes
|
||||
|
||||
- **GAME-PLATFORM-016** — Les familles de plateformes réservées sont Desktop, Mobile et Web. Desktop inclut potentiellement Linux, Windows et macOS ; Mobile inclut potentiellement Android et iOS.
|
||||
- **GAME-PLATFORM-016** — Les familles conceptuelles réservées sont Desktop, Mobile et Web. Desktop inclut potentiellement Linux, Windows et macOS ; Mobile inclut potentiellement Android et iOS. Le contrat runtime V1 reste volontairement plus concret : `PlatformFamily` expose actuellement `Android`, `Desktop` et `Web` ; un host Tauri Android utilise donc `PlatformFamily::Android` tant qu'aucune généralisation Mobile/iOS n'est justifiée.
|
||||
- **GAME-PLATFORM-017** — Téléphone, tablette et futures classes de device sont des dimensions distinctes de l'OS et du backend technique.
|
||||
- **GAME-PLATFORM-018** — SDL3 reste le backend natif de référence du POC, mais l'architecture de jeu ne doit pas assimiler une plateforme à SDL ni empêcher un adapter différent lorsque la plateforme l'exige.
|
||||
- **GAME-PLATFORM-019** — Une plateforme réservée n'est ni implémentée ni planifiée tant qu'une ligne ROADMAP ou un delta ne l'engage explicitement.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/rules/RULES_VALIDATION_MATRIX.md -->
|
||||
<!-- version: 4 -->
|
||||
<!-- version: 5 -->
|
||||
|
||||
# Matrice normative des commandes et validations
|
||||
|
||||
@@ -29,11 +29,14 @@ Les commandes ciblées restent la norme pendant l'implémentation ; les gates wo
|
||||
| `CMD-026` | `cargo tree -p <crate> --edges normal` ou variante ciblée | — | dépendances/features modifiées ou diagnostic | selon portée |
|
||||
| `CMD-030` | build Desktop `--release` ciblé | gates Rust applicables | runner/distribution Desktop touché | beta |
|
||||
| `CMD-031` | smoke Desktop release | `CMD-030` | runtime Desktop touché | beta |
|
||||
| `CMD-040` | `(cd <tauri-app> && cargo tauri dev)` | gates Rust/frontend applicables | smoke interactif Tauri | `pre`/beta |
|
||||
| `CMD-041` | `(cd <tauri-app> && cargo tauri build)` | gates Rust/frontend applicables | packaging Tauri final/prefinal | beta/RC |
|
||||
| `CMD-040` | `(cd <tauri-app> && cargo tauri dev)` | gates Rust/frontend applicables | smoke interactif Tauri Desktop | `pre`/beta |
|
||||
| `CMD-041` | `(cd <tauri-app> && cargo tauri build)` | gates Rust/frontend applicables | packaging Tauri Desktop final/prefinal | beta/RC |
|
||||
| `CMD-042` | build Rust `wasm32-unknown-unknown` + `wasm-bindgen --target web` | gates Rust de l'adapter | adapter WASM/Web direct touché | `pre` |
|
||||
| `CMD-043` | `(cd Web/<game> && npm install && npm run build)` | `CMD-042` si frontend avec WASM | frontend Web direct touché | `pre` |
|
||||
| `CMD-044` | smoke navigateur du host Web direct | `CMD-043` | Canvas/input/responsive Web touchés | `pre`/beta |
|
||||
| `CMD-045` | `(cd <tauri-app> && cargo tauri android init)` | environnement Android/Tauri | initialisation unique de la cible Tauri Android | `pre` |
|
||||
| `CMD-046` | `(cd <tauri-app> && cargo tauri android dev)` | gates Rust/frontend applicables | smoke interactif Tauri Android | `pre`/beta |
|
||||
| `CMD-047` | `(cd <tauri-app> && cargo tauri android build)` | gates Rust/frontend applicables | packaging Tauri Android final/prefinal | beta/RC |
|
||||
| `CMD-050` | build Rust Android ABI ciblé | gates Rust applicables | Android/JNI/backend natif touché | pre/beta |
|
||||
| `CMD-051` | `(cd Android && ./gradlew :<app>:assembleDebug)` | `CMD-050` si Rust natif change | Android/app/manifest/Java touché | pre/beta |
|
||||
| `CMD-052` | install + smoke AVD | `CMD-051` | Android concerné | beta |
|
||||
@@ -52,7 +55,7 @@ Dès que du Rust ou une dépendance Cargo change, la séquence minimale obligato
|
||||
|
||||
`CMD-026` est ajouté lorsqu'un graphe de dépendances/features a changé ou doit être diagnostiqué ; il est omis des validations ordinaires sans changement de dépendances.
|
||||
|
||||
Toute commande avec changement de répertoire utilise un sous-shell, comme le montrent `CMD-040`, `CMD-041`, `CMD-043` et `CMD-051`.
|
||||
Toute commande avec changement de répertoire utilise un sous-shell, comme le montrent `CMD-040`, `CMD-041`, `CMD-043`, `CMD-045` à `CMD-047` et `CMD-051`.
|
||||
|
||||
## Dépendances entre crates
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/studies/000-README.md -->
|
||||
<!-- version: 9 -->
|
||||
<!-- version: 10 -->
|
||||
|
||||
# Études
|
||||
|
||||
@@ -57,3 +57,7 @@ Ces documents étudient les POC à réaliser ; ils ne lancent encore aucune impl
|
||||
## Étude de cadrage 0.3.0
|
||||
|
||||
- [`023-V0_3_0_PLATFORM_POC_AUDIT.md`](023-V0_3_0_PLATFORM_POC_AUDIT.md) — audit réel de la baseline `0.2.0`, requirements Snake, graphe de dépendances, choix du premier POC et sizing corrigé de `0.3.0`.
|
||||
|
||||
## Étude de cadrage 0.3.1
|
||||
|
||||
- [`024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md`](024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md) — audit de la baseline `0.3.0`, réutilisation Web/WASM, référence Tauri existante, environnement Android et sizing du second host Snake.
|
||||
|
||||
223
docs/studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md
Normal file
223
docs/studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md
Normal file
@@ -0,0 +1,223 @@
|
||||
<!-- file: docs/studies/024-V0_3_1_TAURI_ANDROID_SNAKE_AUDIT.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Audit v0.3.1 — second host Snake Tauri Android
|
||||
|
||||
## Statut
|
||||
|
||||
Étude de cadrage `0.3.1-0-pre.1`.
|
||||
|
||||
Base autoritaire : archive téléchargée depuis le tag `v0.3.0` et fournie pour cette reprise.
|
||||
|
||||
Cette tranche reste un gate d'audit, requirements, sizing et planification. Aucun scaffold Tauri Android Snake, aucun frontend nouveau et aucun changement de gameplay n'y sont introduits.
|
||||
|
||||
## Intégrité de la baseline
|
||||
|
||||
L'archive `v0.3.0` a été extraite et testée avant modification.
|
||||
|
||||
Les contrôles statiques de baseline sont propres :
|
||||
|
||||
```text
|
||||
unzip -t : no errors
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
games.sasedev workspace audit: clean
|
||||
Markdown table audit: clean (5 table(s), 197 file(s))
|
||||
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
|
||||
```
|
||||
|
||||
La version technique racine est `0.3.0`. Aucun `Cargo.lock`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `node_modules/`, `dist/`, `target/` ou binding WASM généré n'est présent dans l'archive source.
|
||||
|
||||
L'absence de `.git` est normale pour cette archive taggée et ne permet ni ne requiert d'inventer un état Git.
|
||||
|
||||
## État fonctionnel hérité
|
||||
|
||||
La release `0.3.0` apporte déjà les briques nécessaires au second host :
|
||||
|
||||
- `game-snake-poc` porte le gameplay et reste indépendant du host ;
|
||||
- `game-snake-poc-wasm` expose le runtime Snake à WebAssembly ;
|
||||
- `Web/game-snake-poc` valide Canvas, clavier/pointer/touch, resize, lifecycle navigateur, assets, diagnostics frontend et provenance ;
|
||||
- le runner Desktop SDL3 reste le témoin natif de non-régression ;
|
||||
- les builds Web nouveaux utilisent Cargo, `wasm-bindgen` et Vite sans orchestration Python.
|
||||
|
||||
Le POC Tauri Reflex historique fournit en plus une référence de structure Tauri, mais il conserve des hooks Python gelés qui ne doivent pas être copiés dans un chemin `0.3.x`.
|
||||
|
||||
Son manifest contient déjà le triplet `crate-type = ["staticlib", "cdylib", "rlib"]`, compatible avec la préparation mobile Tauri. En revanche son `run()` reste un point d'entrée Desktop et n'est pas annoté `#[cfg_attr(mobile, tauri::mobile_entry_point)]`. La nouvelle app Snake doit donc reprendre la séparation de fichiers, pas ce détail Desktop : le `run()` possédé par `tauri.rs` devra être le point d'entrée mobile et être réexporté par la façade `lib.rs`.
|
||||
|
||||
Le manifest Reflex déclare aussi `engine-v1-platform-api`, alors que son code source Tauri ne le consomme pas directement. Cette dépendance ne doit pas être copiée par mimétisme dans la nouvelle app ; la provenance Snake appartient déjà à l'adapter WASM tant qu'aucune responsabilité backend Tauri ne justifie ce lien.
|
||||
|
||||
## Référence KSP Desk
|
||||
|
||||
L'archive de référence KSP `khadhroony-solana-project-v0.3.15.zip` est bien présente dans la bibliothèque du projet, mais son export binaire vers l'environnement de travail n'est pas autorisé par la bibliothèque. Son contenu intégral n'est donc pas présenté comme audité ici.
|
||||
|
||||
Les éléments KSP indexés accessibles confirment néanmoins la convention recherchée :
|
||||
|
||||
- `src/tauri.rs` concentre l'assemblage Tauri et le lifecycle de fenêtre ;
|
||||
- des modules propriétaires tels que `app_state.rs`, `route_runtime.rs` et `frontend_logging.rs` portent leur logique au lieu de gonfler `tauri.rs` ;
|
||||
- les diagnostics frontend sont routés vers des cibles `tracing` structurées.
|
||||
|
||||
Le modèle normatif de `games.sasedev` reste la source de vérité : `lib.rs` façade/reexports, `tauri.rs` assemblage et pont Web/Rust, modules propriétaires séparés.
|
||||
|
||||
## Réutilisation attendue du host Web
|
||||
|
||||
### Réutilisé sans changement de responsabilité
|
||||
|
||||
`game-snake-poc` reste inchangé comme source de vérité du gameplay.
|
||||
|
||||
Les assets canoniques sous `assets/common/` et `assets/game-snake-poc/` restent les mêmes ; le host Tauri doit les embarquer ou les copier au build, pas créer une seconde source.
|
||||
|
||||
Le contrat sémantique d'entrée du jeu reste le même. Les boutons tactiles et éventuelles entrées clavier du WebView convergent vers les mêmes actions Snake.
|
||||
|
||||
### Réutilisé avec adaptation de host
|
||||
|
||||
Le Canvas, la session fixed-step, la projection de scène et une grande partie du shell Vite/TypeScript du host Web sont des références directes pour le frontend Tauri.
|
||||
|
||||
La détection `DeviceClass` et `InputProfile` peut être reprise, mais les dimensions fixes de provenance changent :
|
||||
|
||||
```text
|
||||
Web direct = Web / Wasm / Browser
|
||||
Tauri Android = Android / Wasm / TauriWebView
|
||||
```
|
||||
|
||||
Le lifecycle navigateur `visibilitychange/pagehide/pageshow` n'est pas copié comme seul contrat mobile. Le host Tauri Android doit tester le comportement réel lors de pause/reprise, changement d'orientation, background/foreground et fermeture/navigation système.
|
||||
|
||||
Le logging frontend Web direct n'est pas réutilisé tel quel : Tauri doit utiliser le bridge `@fltsci/tauri-plugin-tracing` vers `tauri-plugin-tracing`/`tracing`.
|
||||
|
||||
### Dépendances frontend à ne pas copier mécaniquement
|
||||
|
||||
Bootstrap, Bootswatch, Font Awesome et Sass peuvent être repris si le shell Tauri conserve réellement la même UI.
|
||||
|
||||
SimpleBar et `resize-observer-polyfill` restent des dépendances du shell Web direct ; les règles interdisent de les faire devenir des dépendances Tauri par simple copie. Elles ne seront ajoutées que si le layout Android Tauri démontre leur nécessité.
|
||||
|
||||
## Point de friction principal : provenance de l'adapter WASM
|
||||
|
||||
`game-snake-poc-wasm` est réutilisable pour le gameplay et le rendu, mais son état `0.3.0` fixe actuellement `PlatformFamily::Web` et `RuntimeHost::Browser` dans son constructeur et dans `configure_runtime_provenance`.
|
||||
|
||||
Il ne peut donc pas décrire correctement un WebView Tauri Android sans modification minimale.
|
||||
|
||||
La direction retenue est de généraliser uniquement la configuration de provenance du host dans l'adapter existant, sans dupliquer le bridge et sans créer une abstraction WebView commune prématurée. Le même adapter doit pouvoir représenter au moins :
|
||||
|
||||
```text
|
||||
Web / Browser / Wasm
|
||||
Android / TauriWebView / Wasm
|
||||
```
|
||||
|
||||
Le nom `PlatformFamily::Android` est conservé. `Mobile` reste une famille conceptuelle d'architecture et ne justifie pas un renommage de l'API V1 ni l'introduction d'iOS dans `0.3.1`.
|
||||
|
||||
## Structure cible de l'application
|
||||
|
||||
Le second host sera une nouvelle crate :
|
||||
|
||||
```text
|
||||
crates/apps/game-snake-poc-tauri/
|
||||
```
|
||||
|
||||
La crate est génériquement nommée Tauri afin de pouvoir accueillir ultérieurement le host Desktop prévu en `0.3.2`, mais `0.3.1` n'en valide que la cible Android.
|
||||
|
||||
Structure minimale visée :
|
||||
|
||||
```text
|
||||
crates/apps/game-snake-poc-tauri/
|
||||
├── Cargo.toml
|
||||
├── build.rs
|
||||
├── tauri.conf.json
|
||||
├── capabilities/
|
||||
├── frontend/
|
||||
├── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── main.rs
|
||||
│ ├── runtime.rs
|
||||
│ └── tauri.rs
|
||||
├── README.md
|
||||
└── USAGE.md
|
||||
```
|
||||
|
||||
`lib.rs` reste une façade. `tauri.rs` assemble builder/plugins/commands et délègue aux modules propriétaires. Une responsabilité supplémentaire devient un module dédié plutôt qu'une collection de helpers dans `tauri.rs`.
|
||||
|
||||
Le `README.md` est requis pour expliquer frontières et architecture. `USAGE.md` est également retenu car le host Android Tauri possède des prérequis SDK/JDK/NDK, des commandes de device/AVD et des smokes non triviaux.
|
||||
|
||||
## Build et commandes Tauri Android
|
||||
|
||||
La revue des règles a trouvé un défaut de cible : les commandes Tauri existantes `cargo tauri dev/build` correspondent au chemin Desktop alors que le nouveau POC est mobile Android.
|
||||
|
||||
La règle est corrigée pour réserver à Android :
|
||||
|
||||
```text
|
||||
cargo tauri android init
|
||||
cargo tauri android dev
|
||||
cargo tauri android build
|
||||
```
|
||||
|
||||
Le projet mobile généré par Tauri est traité comme partie du host Android lorsqu'il est requis par l'outil ; son contenu exact sera créé par l'outil Tauri dans la tranche d'implémentation, pas fabriqué à la main pendant le cadrage.
|
||||
|
||||
Aucun nouveau script Python de build n'est autorisé. Le frontend Vite/TypeScript et la génération WASM doivent rester possédés par les hooks Tauri et les outils natifs Cargo/`wasm-bindgen`/Tauri.
|
||||
|
||||
## Environnement Android : confirmé et à reconfirmer
|
||||
|
||||
L'historique du dépôt prouve des validations récentes de l'autre chemin Android SDL3 : NDK, ADB, AVD API 36 et appareil ARM64 réel ont déjà été utilisés avec succès pendant `0.1.0`.
|
||||
|
||||
La release `0.3.0` prouve également l'usage récent de Cargo, `wasm32-unknown-unknown`, `wasm-bindgen`, Node/npm et Vite.
|
||||
|
||||
Ces validations historiques ne prouvent pas l'état présent du toolchain Tauri Android. Avant `0-pre.2`, l'utilisateur doit fournir un inventaire frais de :
|
||||
|
||||
- `cargo tauri --version` ;
|
||||
- targets Rust Android installés ;
|
||||
- Java/JDK et `JAVA_HOME` ;
|
||||
- `ANDROID_HOME` ;
|
||||
- NDK et `NDK_HOME` ;
|
||||
- `adb version` et devices visibles ;
|
||||
- AVD disponibles ;
|
||||
- Node/npm et `wasm-bindgen`.
|
||||
|
||||
Les prérequis Tauri 2 actuels pour Android comprennent Android Studio/tooling SDK, NDK, JDK et les targets Rust Android. Cette tranche ne suppose pas qu'ils sont tous encore configurés seulement parce que l'Android SDL3 historique fonctionnait.
|
||||
|
||||
## Risques à tester explicitement
|
||||
|
||||
- compatibilité réelle de `tauri-plugin-tracing` et du bridge frontend sur Android ; le package `0.3.x` est bien la référence actuelle du projet, mais le support mobile doit être prouvé par compilation/smoke plutôt que supposé ;
|
||||
- lifecycle background/foreground et suspension du WebView ;
|
||||
- distinction entre une sortie applicative Tauri, qui passe par `EngineGame::quit_requested`, et le Back système Android, qui ne doit pas être consommé artificiellement ;
|
||||
- propagation correcte des dimensions logiques et du `devicePixelRatio` après rotation/resize ;
|
||||
- chargement des assets embarqués sans dépendre du serveur Vite en build Android ;
|
||||
- pipeline WASM sans script Python ;
|
||||
- séparation claire entre Android SDL3 existant sous `Android/` et Tauri Android généré par la crate Tauri ;
|
||||
- absence de dépendances Web-only recopiées par inertie ;
|
||||
- output des builds et caches hors racine selon `GAME-BUILD-001`.
|
||||
|
||||
## Décisions de cadrage
|
||||
|
||||
Retenu pour `0.3.1` :
|
||||
|
||||
- une seule nouvelle app `game-snake-poc-tauri` ;
|
||||
- Android uniquement comme cible validée dans cette version ;
|
||||
- réutilisation du même `game-snake-poc-wasm` après généralisation minimale de provenance ;
|
||||
- réutilisation sélective du frontend Web ;
|
||||
- structure Rust Tauri conforme aux apps Desk : façade, assemblage, modules propriétaires ;
|
||||
- tracing Tauri de bout en bout ;
|
||||
- pas de nouveau framework commun tant qu'une duplication réelle entre Web direct et Tauri WebView n'est pas mesurée ;
|
||||
- aucun orchestrateur Python nouveau ou repris.
|
||||
|
||||
Reporté :
|
||||
|
||||
- Tauri Desktop Snake comme produit validé, vers `0.3.2` ;
|
||||
- abstraction WebView commune, sauf duplication réellement prouvée ;
|
||||
- iOS ;
|
||||
- Android SDL3 multi-ABI supplémentaire ;
|
||||
- ads, billing, auth, réseau realtime et Uroburas.
|
||||
|
||||
## Sizing
|
||||
|
||||
Le scope complet est trop risqué pour être comprimé dans une seule prerelease d'implémentation. Le découpage retenu est :
|
||||
|
||||
```text
|
||||
0-pre.1 audit / règles / requirements / environnement / plan
|
||||
0-pre.2 scaffold Tauri Android + pipeline natif + bridge minimal vers Snake WASM
|
||||
0-pre.3 Canvas / input / assets / shell réutilisé du Web
|
||||
0-pre.4 lifecycle / provenance / tracing / Back + smoke mobile
|
||||
0-pre.5 conditionnel : extraction commune seulement si duplication réelle
|
||||
2-beta.1 gate large + packaging Android + AVD/appareil selon disponibilité
|
||||
2-beta.2 consolidation documentaire si nécessaire
|
||||
3-rc.1 candidate gelée et reproductibilité
|
||||
0.3.1 promotion stable mécanique
|
||||
```
|
||||
|
||||
Une tranche peut être scindée si un défaut outillage réel l'impose. `0-pre.5` est supprimé s'il n'existe aucune extraction justifiée.
|
||||
96
docs/testing/005-V0_3_1_RC_VALIDATION_MATRIX.md
Normal file
96
docs/testing/005-V0_3_1_RC_VALIDATION_MATRIX.md
Normal file
@@ -0,0 +1,96 @@
|
||||
<!-- file: docs/testing/005-V0_3_1_RC_VALIDATION_MATRIX.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Matrice de validation RC 0.3.1
|
||||
|
||||
## Objectif
|
||||
|
||||
`0.3.1-3-rc.1` est une candidate gelée. Elle n'ajoute aucune fonctionnalité au POC Snake Tauri Android ; elle vérifie qu'un état reproductible peut être promu mécaniquement vers `0.3.1`.
|
||||
|
||||
Le host Tauri Android reste un POC de référence. La voie Android productive reste SDL3 natif/Java/JNI. Aucun AAB Tauri n'est requis pour cette RC.
|
||||
|
||||
## Gel fonctionnel
|
||||
|
||||
Pendant `3-rc.*`, seules les corrections autorisées par `VER-RC-*` sont admises. Tout nouveau gameplay, contrôle swipe, refactor Web/Tauri, framework commun, intégration publicitaire ou changement volontaire de comportement est hors scope.
|
||||
|
||||
## Gate workspace
|
||||
|
||||
Depuis la racine :
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/usr/lib/jvm/temurin-17-jdk-amd64
|
||||
|
||||
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 Web deltas history
|
||||
python3 scripts/audit_distribution_layout.py
|
||||
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
cargo test --workspace --all-targets --all-features
|
||||
```
|
||||
|
||||
Cette suite complète est volontairement répétée au jalon RC parce que la version technique et les métadonnées frontend sont promues vers la candidate.
|
||||
|
||||
## Packaging Android autonome
|
||||
|
||||
Installer/actualiser les dépendances frontend, puis laisser Tauri posséder le build WASM/Vite :
|
||||
|
||||
```bash
|
||||
(cd crates/apps/game-snake-poc-tauri && npm install)
|
||||
|
||||
(cd crates/apps/game-snake-poc-tauri && \
|
||||
cargo tauri android build --debug --apk --target aarch64 --target x86_64)
|
||||
```
|
||||
|
||||
Ne pas lancer `npm run build` manuellement. Le hook `beforeBuildCommand` doit construire le WASM release, générer les bindings, exécuter TypeScript/Vite et copier les assets.
|
||||
|
||||
Le package RC de validation reste un APK Debug universal car `0.3.1` ne constitue pas la voie Android de production et ne possède aucun secret/signing de store. L'AAB de production sera étudié dans la future version Android SDL3 native.
|
||||
|
||||
## Contrôle ABI
|
||||
|
||||
À partir du chemin `<apk>` affiché par Tauri :
|
||||
|
||||
```bash
|
||||
unzip -l <apk> | grep -E 'lib/(arm64-v8a|x86_64)/libgame_snake_poc_tauri_lib\.so'
|
||||
```
|
||||
|
||||
Les deux entrées doivent être présentes.
|
||||
|
||||
## Smoke AVD x86_64
|
||||
|
||||
Lancer l'AVD de référence dans un terminal séparé :
|
||||
|
||||
```bash
|
||||
emulator -avd sasedev_games_api36
|
||||
```
|
||||
|
||||
Puis :
|
||||
|
||||
```bash
|
||||
adb devices -l
|
||||
adb -s emulator-5554 install -r <apk>
|
||||
adb -s emulator-5554 shell am start -n com.sasedev.games.snake.tauri/.MainActivity
|
||||
```
|
||||
|
||||
Vérifier : démarrage, Canvas, assets, WASM, contrôles disponibles, lifecycle background/foreground, reprise sans rattrapage et Back sans crash.
|
||||
|
||||
## Smoke ARM64 réel
|
||||
|
||||
Avec le Galaxy S9+ ou un autre appareil ARM64 disponible :
|
||||
|
||||
```bash
|
||||
adb -s <serial> shell getprop ro.product.cpu.abi
|
||||
adb -s <serial> install -r <apk>
|
||||
adb -s <serial> shell am start -n com.sasedev.games.snake.tauri/.MainActivity
|
||||
```
|
||||
|
||||
Vérifier : provenance `android / tauri-webview / wasm / phone / touch`, contrôles tactiles, background/foreground, reprise sans rattrapage, rotation/resize si disponible et plusieurs Back. Aucun Vite, `adb reverse` ou port `1436` ne doit être nécessaire.
|
||||
|
||||
Le crash `FORTIFY: pthread_mutex_lock called on a destroyed mutex` observé une fois en dev reste un point de surveillance. Sa reproduction sur l'APK autonome RC bloque la promotion stable et impose un `3-rc.1.fix.N`; son absence pendant les smokes RC permet de clore ce risque comme non reproductible dans l'état candidat.
|
||||
|
||||
## Promotion stable
|
||||
|
||||
Si la gate RC est propre et qu'aucun correctif n'est nécessaire, la promotion vers `0.3.1` est mécanique : versions stables, entrée stable du `CHANGELOG.md`, historique RC, clôture du plan et delta de release. Aucun code fonctionnel ne doit changer.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/001-VALIDATION_GATES.md -->
|
||||
<!-- version: 8 -->
|
||||
<!-- version: 11 -->
|
||||
|
||||
# Gates de validation
|
||||
|
||||
@@ -56,7 +56,19 @@ Si une commande échoue, ne pas avancer de prerelease. Produire un correctif du
|
||||
|
||||
## Android et Web
|
||||
|
||||
Le build Android n'est pas encore une gate : le projet Gradle exécutable et l'intégration SDL3/NDK restent planifiés pour une prerelease dédiée. Dès leur introduction, les tâches ciblées par module sont documentées avant d'être rendues obligatoires.
|
||||
Le build Android SDL3 historique n'est pas encore une gate : le projet Gradle exécutable et l'intégration SDL3/NDK restent planifiés pour une prerelease dédiée. Dès leur introduction, les tâches ciblées par module sont documentées avant d'être rendues obligatoires.
|
||||
|
||||
Le host Tauri Android Snake possède en revanche une gate réelle à partir de `0.3.1-0-pre.2`. Pour Tauri 2.11.x, les commandes Android utilisent le projet `gen/android` généré par la CLI officielle, sans patch local. La baseline de validation est JDK 17 avec Gradle `8.14.3` et AGP `8.11.0`. Si `gen/android` provient d'une tentative de migration différente, le supprimer puis rejouer `cargo tauri android init` sous JDK 17 avant le smoke `cargo tauri android dev`.
|
||||
|
||||
Sur AVD, le smoke peut utiliser le forwarding ADB géré automatiquement par Tauri. Sur appareil physique, la gate de référence utilise un tunnel USB explicite sur le port unique `1436` afin d'éviter de dépendre du LAN et de transporter à la fois HTTP et HMR :
|
||||
|
||||
```bash
|
||||
adb -s <serial> reverse --remove-all
|
||||
adb -s <serial> reverse tcp:1436 tcp:1436
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android dev --host 127.0.0.1)
|
||||
```
|
||||
|
||||
La validation réelle de `0-pre.4` a confirmé le chemin ARM64 `aarch64-linux-android`. Un premier smoke a observé un abort natif lors du Back/teardown WebView ; après correction du tunnel HMR dans `0-pre.4.fix.1`, un nouveau smoke ARM64 n'a pas reproduit cet abort et est allé jusqu'au détachement de la fenêtre. Le risque reste à revalider sur l'APK autonome beta et ne doit pas être masqué par une modification du scaffold `gen/android`.
|
||||
|
||||
Le host navigateur direct Snake possède désormais une gate réelle. Lorsqu'il est touché, construire d'abord l'adapter WASM et ses bindings hors dépôt, puis le frontend :
|
||||
|
||||
@@ -73,7 +85,32 @@ npm run build
|
||||
|
||||
Le smoke direct utilise ensuite `npm run dev` et `http://127.0.0.1:1434/main.html`. Pour le POC Snake feature-complete, vérifier aussi : assets `common` + `game` chargés avant le statut `Prêt`, provenance `Web/Wasm/Browser` visible et mise à jour par l'input, pause sans rattrapage lors d'un masquage d'onglet, reprise propre, resize sans tick artificiel, SimpleBar, clavier et contrôles pointer/tactiles.
|
||||
|
||||
Lorsque `0-pre.5` touche la frontière plateforme du bridge WASM, exécuter également `cargo test -p engine-v1-platform-api`, `cargo test -p game-snake-poc-wasm`, puis un smoke `cargo run -p game-snake-poc-desktop` pour confirmer la non-régression SDL3. Les frontends Tauri restent pilotés par leurs hooks Tauri et ne reprennent pas cette gate manuelle.
|
||||
Si une future tranche touche de nouveau la frontière plateforme du bridge WASM, exécuter également `cargo test -p engine-v1-platform-api`, `cargo test -p game-snake-poc-wasm`, puis un smoke `cargo run -p game-snake-poc-desktop` pour confirmer la non-régression SDL3. Les frontends Tauri restent pilotés par leurs hooks Tauri et ne reprennent pas cette gate manuelle.
|
||||
|
||||
## Gate beta du POC Snake Tauri Android
|
||||
|
||||
À l'entrée en `0.3.1-2-beta.1`, la gate ajoute la suite Cargo workspace complète et un packaging Android autonome aux audits/check/Clippy habituels :
|
||||
|
||||
```bash
|
||||
cargo test --workspace --all-targets --all-features
|
||||
|
||||
export JAVA_HOME=/usr/lib/jvm/temurin-17-jdk-amd64
|
||||
(cd crates/apps/game-snake-poc-tauri && npm install)
|
||||
(cd crates/apps/game-snake-poc-tauri && \
|
||||
cargo tauri android build --debug --apk --target aarch64 --target x86_64)
|
||||
```
|
||||
|
||||
Le hook Tauri `beforeBuildCommand` possède le build WASM release, `wasm-bindgen`, TypeScript et Vite ; `npm run build` n'est donc pas une gate manuelle. Le build beta vise un APK Debug contenant `arm64-v8a` et `x86_64`; aucun AAB n'est requis à ce jalon.
|
||||
|
||||
Après packaging, utiliser le chemin d'APK affiché par Tauri, vérifier son contenu ABI, puis installer le même package sur l'AVD x86_64 et l'appareil ARM64 réel :
|
||||
|
||||
```bash
|
||||
unzip -l <apk> | grep -E 'lib/(arm64-v8a|x86_64)/libgame_snake_poc_tauri_lib\.so'
|
||||
adb -s <serial> install -r <apk>
|
||||
adb -s <serial> shell am start -n com.sasedev.games.snake.tauri/.MainActivity
|
||||
```
|
||||
|
||||
Le smoke autonome vérifie Canvas, assets, WASM, input, provenance, background/foreground, reprise sans rattrapage, resize/rotation si disponible et plusieurs sorties Back. Il ne doit utiliser ni serveur Vite ni `adb reverse`.
|
||||
|
||||
## Gate beta du POC Snake Web
|
||||
|
||||
|
||||
45
history/0.3.1/0-pre.1.md
Normal file
45
history/0.3.1/0-pre.1.md
Normal file
@@ -0,0 +1,45 @@
|
||||
<!-- file: history/0.3.1/0-pre.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Historique 0.3.1-0-pre.1
|
||||
|
||||
## Statut
|
||||
|
||||
Cadrage `0.3.1-0-pre.1` validé par l'utilisateur le 2026-09-20. Les audits, le formatage, le check workspace et Clippy strict passent ; aucun `.fix.N` n'est requis avant l'ouverture de `0-pre.2`.
|
||||
|
||||
## Gate utilisateur
|
||||
|
||||
La gate fournie dans le delta a été exécutée avec succès :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
games.sasedev workspace audit: clean
|
||||
Markdown table audit: clean (5 table(s), 210 file(s))
|
||||
Distribution layout audit: clean (31 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
|
||||
```
|
||||
|
||||
## Environnement confirmé
|
||||
|
||||
L'inventaire de transmission vers `0-pre.2` confirme :
|
||||
|
||||
- Rust/Cargo `1.94.1` ;
|
||||
- Tauri CLI `2.11.3` ;
|
||||
- cibles Rust `aarch64-linux-android`, `x86_64-linux-android`, `wasm32-unknown-unknown` et `x86_64-unknown-linux-gnu` ;
|
||||
- Node `24.21.0`, npm `11.19.0`, wasm-bindgen `0.2.128` ;
|
||||
- OpenJDK Temurin `25.0.4.1` disponible via `java` ;
|
||||
- `ANDROID_HOME=/home/sinus/DEV/AndroidSDK` ;
|
||||
- `JAVA_HOME` et `NDK_HOME` non définis globalement ;
|
||||
- Android Debug Bridge `37.0.1` ;
|
||||
- un Samsung SM-G965F réel connecté ;
|
||||
- AVD `Medium_Phone`, `Medium_Phone_API_36.0` et `sasedev_games_api36` disponibles.
|
||||
|
||||
Le projet ne transforme pas l'absence de `NDK_HOME` en défaut : l'installation locale conserve plusieurs NDK sous `$ANDROID_HOME/ndk/<version>`. Si une commande Tauri demande cette variable, elle sera définie ponctuellement vers une version exacte. De même, `JAVA_HOME` ne devient nécessaire que si la CLI ne résout pas le JDK disponible depuis l'environnement.
|
||||
|
||||
## Transmission vers 0-pre.2
|
||||
|
||||
L'archive complète `khadhroony-solana-project-v0.3.15.zip` est désormais disponible directement pour la tranche suivante. L'audit de ses six applications `ksp-app-*-desk` confirme le modèle retenu : façade `lib.rs`, assemblage `tauri.rs`, frontend Vite dans la crate, `tauri.conf.json`, capability dédiée et dépendances tracing Rust/TypeScript.
|
||||
64
history/0.3.1/0-pre.2.fix.3.md
Normal file
64
history/0.3.1/0-pre.2.fix.3.md
Normal file
@@ -0,0 +1,64 @@
|
||||
<!-- file: history/0.3.1/0-pre.2.fix.3.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Historique 0.3.1-0-pre.2.fix.3
|
||||
|
||||
## Statut
|
||||
|
||||
Correctif validé par l'utilisateur le 2026-09-20. Le host Tauri Android minimal est assemblé, installé et lancé sur l'AVD x86_64 avec le template Android officiel Tauri 2.11.x sous JDK 17.
|
||||
|
||||
Le frontend atteint son état `ready` avec la provenance `Android / TauriWebView / Wasm`. L'écran reste volontairement minimal à ce jalon : Canvas, contrôles et assets appartiennent à `0-pre.3`.
|
||||
|
||||
## Toolchain confirmée
|
||||
|
||||
La machine possède notamment Temurin 17, 21 et 25. La gate Android a sélectionné explicitement :
|
||||
|
||||
```text
|
||||
JAVA_HOME=/usr/lib/jvm/temurin-17-jdk-amd64
|
||||
OpenJDK 17.0.20.1
|
||||
NDK sélectionné par Tauri : 30.0.14904198
|
||||
Gradle wrapper généré : 8.14.3
|
||||
```
|
||||
|
||||
Le projet `gen/android` pollué par la tentative Gradle 9 de `0-pre.2.fix.1` a été supprimé puis régénéré uniquement avec `cargo tauri android init`. L'audit de distribution l'a accepté.
|
||||
|
||||
## Gate workspace
|
||||
|
||||
Les validations suivantes ont passé :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
games.sasedev workspace audit: clean
|
||||
Markdown table audit: clean (5 table(s), 217 file(s))
|
||||
Distribution layout audit: clean (42 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 l'adapter Snake WASM et le frontend Vite ;
|
||||
- construit le `cdylib` Android x86_64 ;
|
||||
- assemblé l'APK avec Gradle 8.14.3 ;
|
||||
- installé l'application par streamed install ;
|
||||
- lancé `com.sasedev.games.snake.tauri/.MainActivity` ;
|
||||
- démarré le runtime Rust avec `platform_family="android"`, `runtime_host="tauri-webview"`, `execution_model="wasm"` ;
|
||||
- atteint `Snake Tauri frontend ready`.
|
||||
|
||||
Les warnings Gradle/Kotlin/Tauri observés sont des dépréciations upstream non bloquantes.
|
||||
|
||||
Vite a aussi journalisé un échec de connexion WebSocket HMR. Ce défaut n'empêche ni le chargement du frontend ni l'état `ready` et n'est pas bloquant pour la fermeture du host minimal ; la configuration dev peut être ajustée dans la tranche frontend suivante.
|
||||
|
||||
## Décision produit issue du smoke
|
||||
|
||||
Le POC démontre la faisabilité de Tauri Android, mais aussi un coût d'outillage supplémentaire par rapport au host Android natif SDL3 déjà fonctionnel. La suite de `0.3.1` termine donc un POC jouable de référence, sans faire de Tauri Android la voie de production des futurs jeux.
|
||||
|
||||
## Suite
|
||||
|
||||
`0.3.1-0-pre.3` ajoute Canvas, boucle fixed-step, contrôles clavier/touch, assets et shell responsive afin de rendre le POC réellement comparable au host Web direct et au natif SDL3.
|
||||
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.
|
||||
62
history/0.3.1/0-pre.4.fix.1.md
Normal file
62
history/0.3.1/0-pre.4.fix.1.md
Normal file
@@ -0,0 +1,62 @@
|
||||
<!-- file: history/0.3.1/0-pre.4.fix.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Historique 0.3.1-0-pre.4.fix.1
|
||||
|
||||
## Statut
|
||||
|
||||
Correctif validé par l'utilisateur le 2026-09-21. Le POC Tauri Android est jouable sur l'AVD x86_64 et sur un Galaxy S9+ ARM64 réel ; HTTP et HMR utilisent désormais le même tunnel USB `1436` sur appareil physique.
|
||||
|
||||
Aucune extraction `0-pre.5` n'est justifiée. La version peut entrer en `2-beta.1` pour la validation large et le packaging APK autonome.
|
||||
|
||||
## Gate workspace
|
||||
|
||||
Les validations suivantes passent :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
games.sasedev workspace audit: clean
|
||||
Markdown table audit: clean (5 table(s), 222 file(s))
|
||||
Distribution layout audit: clean (48 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 ARM64 réel
|
||||
|
||||
Le téléphone expose `arm64-v8a`; Tauri sélectionne `aarch64-linux-android`, compile `libgame_snake_poc_tauri_lib.so`, assemble puis installe l'application avec succès.
|
||||
|
||||
La gate utilise :
|
||||
|
||||
```text
|
||||
adb reverse tcp:1436 tcp:1436
|
||||
cargo tauri android dev --host 127.0.0.1
|
||||
```
|
||||
|
||||
Les traces confirment :
|
||||
|
||||
```text
|
||||
Snake Tauri frontend bootstrap started
|
||||
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 runtime resumed
|
||||
Snake Tauri frontend ready
|
||||
Snake Tauri provenance: android / tauri-webview / wasm / phone / touch
|
||||
```
|
||||
|
||||
L'erreur Vite `failed to connect to websocket` observée avant le fix ne réapparaît pas.
|
||||
|
||||
## Back et teardown
|
||||
|
||||
Le premier smoke ARM64 de `0-pre.4` avait observé un abort `FORTIFY: pthread_mutex_lock called on a destroyed mutex` pendant le teardown. Le smoke `fix.1` ne le reproduit pas : après Back, les traces passent par `runtime paused`, `visibility hidden`, destruction de la surface EGL, `stopped(true)` puis `dispatchDetachedFromWindow`, sans crash observé avant l'arrêt volontaire de la commande.
|
||||
|
||||
Le défaut est donc traité comme un risque potentiellement intermittent plutôt que comme une régression reproductible du host. `2-beta.1` doit encore le retester sur un APK autonome, sans Vite ni tunnel ADB.
|
||||
|
||||
## Suite
|
||||
|
||||
`0.3.1-2-beta.1` exécute la suite Cargo workspace complète, package un APK Debug autonome contenant x86_64 et ARM64, puis le fume sur AVD et appareil réel.
|
||||
60
history/0.3.1/2-beta.1.md
Normal file
60
history/0.3.1/2-beta.1.md
Normal file
@@ -0,0 +1,60 @@
|
||||
<!-- file: history/0.3.1/2-beta.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Historique 0.3.1-2-beta.1
|
||||
|
||||
## Statut
|
||||
|
||||
Beta validée par l'utilisateur le 2026-09-21. La version peut entrer en `0.3.1-3-rc.1` sans `2-beta.2`.
|
||||
|
||||
## Gate workspace
|
||||
|
||||
Les audits Rust/workspace, Markdown et distribution sont propres. `cargo fmt`, `cargo check --workspace` et Clippy workspace strict passent.
|
||||
|
||||
La suite :
|
||||
|
||||
```text
|
||||
cargo test --workspace --all-targets --all-features
|
||||
```
|
||||
|
||||
termine avec 35 tests réussis et aucun échec sur les crates effectivement porteuses de tests.
|
||||
|
||||
## Build frontend et APK autonome
|
||||
|
||||
`npm install` termine sans vulnérabilité signalée. Le hook Tauri `beforeBuildCommand` exécute :
|
||||
|
||||
```text
|
||||
WASM release
|
||||
wasm-bindgen
|
||||
TypeScript
|
||||
Vite production
|
||||
static copy des deux familles d'assets
|
||||
```
|
||||
|
||||
Le build Android :
|
||||
|
||||
```text
|
||||
cargo tauri android build --debug --apk --target aarch64 --target x86_64
|
||||
```
|
||||
|
||||
compile les cibles `aarch64-linux-android` et `x86_64-linux-android`, puis produit :
|
||||
|
||||
```text
|
||||
gen/android/app/build/outputs/apk/universal/debug/app-universal-debug.apk
|
||||
```
|
||||
|
||||
Le contrôle `unzip -l` demandé par le delta n'apparaît pas dans la sortie transmise ; il reste donc explicitement dans la gate RC.
|
||||
|
||||
## Smoke ARM64 réel
|
||||
|
||||
L'APK universal est installé avec succès sur le Galaxy S9+ `arm64-v8a` puis `MainActivity` est lancée via ADB.
|
||||
|
||||
## Smoke x86_64 AVD
|
||||
|
||||
L'AVD `sasedev_games_api36` utilise une image `x86_64`. Le même APK universal est installé avec succès sur `emulator-5554`, puis `MainActivity` est lancée via ADB.
|
||||
|
||||
Ces deux installations/lancements valident le packaging autonome sur les deux architectures de référence sans serveur Vite ni tunnel ADB. Les contrôles lifecycle/Back détaillés restent repris dans la matrice RC afin de fermer explicitement le risque de teardown observé antérieurement en mode dev.
|
||||
|
||||
## Décision de phase
|
||||
|
||||
Aucun défaut beta ne justifie `2-beta.2`. Le scope fonctionnel est gelé et `3-rc.1` devient la tranche suivante.
|
||||
54
history/0.3.1/3-rc.1.md
Normal file
54
history/0.3.1/3-rc.1.md
Normal file
@@ -0,0 +1,54 @@
|
||||
<!-- file: history/0.3.1/3-rc.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Historique 0.3.1-3-rc.1
|
||||
|
||||
## Statut
|
||||
|
||||
RC validée par l'utilisateur le 2026-09-21 puis retenue pour promotion mécanique vers `0.3.1`.
|
||||
|
||||
## Gate workspace
|
||||
|
||||
La gate RC complète a passé :
|
||||
|
||||
- `cargo fmt --all` puis `cargo fmt --all -- --check` ;
|
||||
- audits Rust général, exports, workspace, Markdown et distribution propres ;
|
||||
- `cargo check --workspace` ;
|
||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` ;
|
||||
- `cargo test --workspace --all-targets --all-features` avec 35 tests réussis et aucun échec.
|
||||
|
||||
## Build frontend et packaging Android
|
||||
|
||||
`npm install` a terminé sans vulnérabilité signalée. Le build Tauri a exécuté son hook `beforeBuildCommand`, comprenant le build WASM release, `wasm-bindgen`, TypeScript, Vite production et la copie des assets.
|
||||
|
||||
La commande :
|
||||
|
||||
```text
|
||||
cargo tauri android build --debug --apk --target aarch64 --target x86_64
|
||||
```
|
||||
|
||||
a produit l'APK autonome universal :
|
||||
|
||||
```text
|
||||
gen/android/app/build/outputs/apk/universal/debug/app-universal-debug.apk
|
||||
```
|
||||
|
||||
Le contrôle `unzip -l` a confirmé les deux bibliothèques natives :
|
||||
|
||||
```text
|
||||
lib/arm64-v8a/libgame_snake_poc_tauri_lib.so
|
||||
lib/x86_64/libgame_snake_poc_tauri_lib.so
|
||||
```
|
||||
|
||||
## Smokes Android
|
||||
|
||||
Le même APK universal a été installé puis lancé avec succès :
|
||||
|
||||
- sur l'AVD `sasedev_games_api36` x86_64 ;
|
||||
- sur le Galaxy S9+ ARM64 réel.
|
||||
|
||||
Aucun défaut nécessitant un `3-rc.1.fix.N` n'a été remonté après ces smokes.
|
||||
|
||||
## Conclusion
|
||||
|
||||
La RC reste fonctionnellement identique au scope gelé de `0.3.1`. La promotion stable peut rester strictement mécanique.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: prompts/003-V0_3_1_START_PROMPT.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Prompt de démarrage `0.3.1` — second host Snake Tauri Android
|
||||
|
||||
@@ -281,13 +281,13 @@ Pour une application Tauri, `npm` sert seulement à gérer les dépendances fron
|
||||
Le smoke courant utilise :
|
||||
|
||||
```bash
|
||||
(cd <tauri-app> && cargo tauri dev)
|
||||
(cd <tauri-app> && cargo tauri android dev)
|
||||
```
|
||||
|
||||
Le packaging est réservé aux phases finales prévues par le plan :
|
||||
|
||||
```bash
|
||||
(cd <tauri-app> && cargo tauri build)
|
||||
(cd <tauri-app> && cargo tauri android build)
|
||||
```
|
||||
|
||||
Ne pas traiter le host Tauri comme le host navigateur direct de `0.3.0` : le mode de lancement, le packaging, les permissions et les smokes sont différents.
|
||||
@@ -417,7 +417,7 @@ Toute commande nécessitant un changement de répertoire est englobée dans un s
|
||||
(cd <répertoire> && <commande>)
|
||||
```
|
||||
|
||||
Pour Tauri, utiliser `cargo tauri dev` pour les smokes et réserver `cargo tauri build` aux phases finales de packaging ; `npm` n'est utilisé directement que pour gérer les dépendances frontend.
|
||||
Pour Tauri, utiliser `cargo tauri android dev` pour les smokes Android et réserver `cargo tauri android build` aux phases finales de packaging Android ; `npm` n'est utilisé directement que pour gérer les dépendances frontend.
|
||||
|
||||
## 13. Qui exécute quoi
|
||||
|
||||
@@ -429,8 +429,8 @@ Les validations de build/runtime restent côté utilisateur :
|
||||
cargo check workspace + Clippy workspace strict lorsqu'un delta touche Rust/dépendances
|
||||
tests cargo ciblés par défaut
|
||||
test workspace complet seulement aux jalons planifiés/portées incertaines
|
||||
(cd <tauri-app> && cargo tauri dev) pour les smokes Tauri
|
||||
(cd <tauri-app> && cargo tauri build) pour les validations finales de packaging Tauri
|
||||
(cd <tauri-app> && cargo tauri android dev) pour les smokes Tauri
|
||||
(cd <tauri-app> && cargo tauri android build) pour les validations finales de packaging Tauri
|
||||
Gradle/SDK/NDK lorsque le chemin Tauri les invoque
|
||||
installation émulateur/appareil
|
||||
smoke mobile
|
||||
@@ -482,8 +482,8 @@ Sinon omettre la tranche.
|
||||
### `2-beta.1` — validation large
|
||||
|
||||
- workspace complet ;
|
||||
- `(cd <tauri-app> && cargo tauri build)` pour le packaging Tauri Android ;
|
||||
- smoke via `(cd <tauri-app> && cargo tauri dev)` puis émulateur/appareil disponible ;
|
||||
- `(cd <tauri-app> && cargo tauri android build)` pour le packaging Tauri Android ;
|
||||
- smoke via `(cd <tauri-app> && cargo tauri android dev)` puis émulateur/appareil disponible ;
|
||||
- non-régression Web direct ;
|
||||
- non-régression Desktop SDL3 lorsque nécessaire ;
|
||||
- vérification dépendances/package/distribution.
|
||||
|
||||
287
prompts/004-V0_3_3_START_PROMPT.md
Normal file
287
prompts/004-V0_3_3_START_PROMPT.md
Normal file
@@ -0,0 +1,287 @@
|
||||
<!-- file: prompts/004-V0_3_3_START_PROMPT.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Prompt de démarrage `0.3.3` — Android SDL3 natif multi-ABI et packaging Gradle
|
||||
|
||||
## 1. Base exacte et version cible
|
||||
|
||||
Partir uniquement de la version stable/taggée :
|
||||
|
||||
```text
|
||||
v0.3.1
|
||||
```
|
||||
|
||||
Si ce prompt est lu avant la publication effective de `0.3.1`, ne pas ouvrir `0.3.3`. Terminer d'abord la RC puis la release stable `0.3.1`.
|
||||
|
||||
`0.3.2` est volontairement différée : ne pas créer de placeholder, de version vide ou de POC Tauri Desktop par cérémonial. Sa réouverture dépend d'un bénéfice produit concret, notamment une monétisation Desktop/WebView réellement démontrée.
|
||||
|
||||
Version cible active :
|
||||
|
||||
```text
|
||||
0.3.3
|
||||
```
|
||||
|
||||
Première tranche obligatoire :
|
||||
|
||||
```text
|
||||
0.3.3-0-pre.1
|
||||
```
|
||||
|
||||
`0-pre.1` est le gate de cadrage : audit, requirements, recherche ciblée, sizing, risques, matrice de validation et création du plan actif sous `docs/plans/`. Ne pas commencer directement par une réécriture Gradle.
|
||||
|
||||
## 2. Sources de vérité
|
||||
|
||||
Lire intégralement, dans cet ordre :
|
||||
|
||||
```text
|
||||
RULES.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
docs/000-README.md
|
||||
```
|
||||
|
||||
Puis au minimum :
|
||||
|
||||
```text
|
||||
docs/rules/RULES_GENERAL.md
|
||||
docs/rules/RULES_RUST.md
|
||||
docs/rules/RULES_PROJECT.md
|
||||
docs/rules/RULES_DOCUMENTATION.md
|
||||
docs/rules/FILE_CONTRACTS.md
|
||||
docs/rules/VERSION_WORKFLOW.md
|
||||
docs/rules/RULES_COMMANDS.md
|
||||
docs/rules/RULES_VALIDATION_MATRIX.md
|
||||
docs/rules/RULES_SESSION_PLANNING.md
|
||||
docs/rules/PROMPT_STRUCTURE.md
|
||||
```
|
||||
|
||||
Transmission plateforme/Android :
|
||||
|
||||
```text
|
||||
docs/plans/002-V0_3_1_TAURI_ANDROID_SNAKE_PLAN.md
|
||||
docs/architecture/002-ANDROID_ARCHITECTURE.md
|
||||
docs/architecture/003-SDL3_PLATFORM_ABSTRACTION.md
|
||||
docs/architecture/004-INPUT_AND_CONTROLS.md
|
||||
docs/architecture/005-ASSET_ARCHITECTURE.md
|
||||
docs/architecture/010-RUNTIME_PROVENANCE.md
|
||||
docs/architecture/015-PLATFORM_POC_ARCHITECTURE.md
|
||||
docs/development/006-ANDROID_RUST_NATIVE_BUILD.md
|
||||
docs/development/007-ANDROID_JNI_BRIDGE.md
|
||||
docs/testing/005-V0_3_1_RC_VALIDATION_MATRIX.md
|
||||
history/0.3.1/
|
||||
deltas/0.3.1/
|
||||
```
|
||||
|
||||
Auditer ensuite le code réellement concerné :
|
||||
|
||||
```text
|
||||
Android/
|
||||
crates/apps/game-android-entrypoint/
|
||||
crates/engines/engine-v1-sdl/
|
||||
crates/engines/engine-v1-platform-api/
|
||||
crates/games/game-reflex-poc/
|
||||
crates/games/game-snake-poc/
|
||||
assets/
|
||||
scripts/build_android_rust.py
|
||||
```
|
||||
|
||||
Le script Python historique est une source d'information sur le pipeline existant, pas la cible d'orchestration à conserver.
|
||||
|
||||
## 3. État hérité attendu
|
||||
|
||||
La stable `0.3.1` doit laisser :
|
||||
|
||||
- Desktop SDL3 natif fonctionnel ;
|
||||
- Android SDL3/Java/JNI historique déjà capable d'exécuter Reflex et Snake ;
|
||||
- `game-android-entrypoint` comme `cdylib` commun sélectionnant exactement un jeu ;
|
||||
- SDL3 AAR/Prefab et `cargo-ndk` déjà connus du dépôt ;
|
||||
- Tauri Android Snake conservé uniquement comme POC de référence ;
|
||||
- preuve qu'un même package Android peut couvrir ARM64 réel et x86_64 émulateur ;
|
||||
- décision produit : la voie Android de production est SDL3 native.
|
||||
|
||||
Ne pas réutiliser Tauri, WebView ou WASM dans le packaging Android natif uniquement parce qu'ils existent dans `0.3.1`.
|
||||
|
||||
## 4. Mission `0.3.3`
|
||||
|
||||
Transformer le chemin Android SDL3 natif historique en pipeline multi-ABI reproductible possédé par Cargo/Gradle, sans script Python de build, et préparer une distribution Android réellement adaptée aux futurs jeux.
|
||||
|
||||
Le résultat attendu doit permettre au minimum :
|
||||
|
||||
```text
|
||||
Gradle -> build Rust natif -> SDL3/JNI -> APK de test
|
||||
Gradle -> plusieurs ABI -> APK universal de test
|
||||
Gradle -> plusieurs ABI pertinentes -> AAB de distribution
|
||||
```
|
||||
|
||||
Le choix final des ABI et du `minSdk` doit être fondé sur les contraintes réellement vérifiées de SDL3, NDK, AGP, Rust et du code projet.
|
||||
|
||||
## 5. Multi-ABI et anciennes versions Android : deux sujets distincts
|
||||
|
||||
Ne pas confondre :
|
||||
|
||||
- **ABI CPU** : `arm64-v8a`, `x86_64`, éventuellement `armeabi-v7a` si elle reste techniquement et produitement justifiée ;
|
||||
- **version Android / API level** : `minSdk`, `targetSdk`, `compileSdk`.
|
||||
|
||||
`arm64-v8a` est la cible appareil productive minimale actuelle ; `x86_64` reste utile pour les AVD. Le support `armeabi-v7a` n'est pas automatiquement requis pour supporter un Android ancien : il doit être évalué séparément.
|
||||
|
||||
Le souhait produit est de supporter des versions Android anciennes lorsque cela reste raisonnable. `0-pre.1` doit donc vérifier la documentation officielle actuelle et le pipeline réel avant de fixer un `minSdk`; ne pas recopier aveuglément une valeur historique du dépôt.
|
||||
|
||||
## 6. Packaging attendu
|
||||
|
||||
Pour les tests locaux, viser un APK universal multi-ABI afin qu'un seul artefact puisse être installé sur les appareils/AVD couverts.
|
||||
|
||||
Pour la distribution future, privilégier un Android App Bundle :
|
||||
|
||||
```text
|
||||
app-release.aab
|
||||
```
|
||||
|
||||
contenant les ABI réellement retenues. La signature/keystore de publication reste hors dépôt et ne doit jamais être inventée ou embarquée dans les sources.
|
||||
|
||||
La version doit documenter clairement la différence entre :
|
||||
|
||||
```text
|
||||
APK universal -> sideload/tests
|
||||
AAB -> distribution store
|
||||
APK split ABI -> option technique, pas artefact par défaut sans besoin
|
||||
```
|
||||
|
||||
## 7. Architecture et ownership
|
||||
|
||||
Conserver les décisions suivantes :
|
||||
|
||||
- Rust porte gameplay et moteur ;
|
||||
- SDL3 porte la couche plateforme graphique/input native ;
|
||||
- Java reste la glue Android préférée ; Kotlin n'est pas introduit sans besoin démontré ;
|
||||
- le contrat JNI reste petit ;
|
||||
- `Android/common` porte le commun durable ;
|
||||
- chaque `Android/game-*` reste une application distincte ;
|
||||
- assets communs et spécifiques restent canoniques sous `assets/` et sont packagés sans duplication source ;
|
||||
- les bibliothèques `jniLibs` générées ne sont pas versionnées ;
|
||||
- aucun build Android productif ne dépend de Tauri.
|
||||
|
||||
## 8. Orchestration de build
|
||||
|
||||
La cible `0.3.3` est de supprimer le besoin de `scripts/build_android_rust.py` dans le chemin normal de build Android.
|
||||
|
||||
Le cadrage doit comparer les options propres disponibles dans Gradle/NDK/Cargo, par exemple l'invocation contrôlée de `cargo ndk` depuis des tâches Gradle, sans créer un nouveau script ad hoc dans un autre langage uniquement pour déplacer le problème.
|
||||
|
||||
Le résultat doit garantir :
|
||||
|
||||
- choix explicite des ABI ;
|
||||
- build Rust avec exactement une feature jeu ;
|
||||
- mise à disposition de `libgame_android_entrypoint.so` et `libSDL3.so` par ABI ;
|
||||
- dépendances de tâches Gradle correctes ;
|
||||
- rebuild incrémental raisonnable ;
|
||||
- erreurs visibles et déterministes ;
|
||||
- outputs générés hors sources versionnées.
|
||||
|
||||
## 9. Scope inclus
|
||||
|
||||
À cadrer puis implémenter progressivement :
|
||||
|
||||
- pipeline Gradle/Cargo natif multi-ABI ;
|
||||
- au minimum Snake comme jeu-sonde, puis Reflex si la factorisation commune le rend naturel dans la même version ;
|
||||
- APK universal de test ;
|
||||
- AAB de validation de distribution sans secrets ;
|
||||
- choix documenté des ABI ;
|
||||
- étude et validation du `minSdk` soutenable ;
|
||||
- smoke x86_64 AVD et ARM64 réel ;
|
||||
- si un AVD d'API plus ancienne compatible est disponible ou raisonnablement créable, smoke ciblé du plancher Android retenu ;
|
||||
- mise à jour des docs Android/Gradle/JNI/validation ;
|
||||
- suppression du script Python du chemin de build normal, puis suppression du fichier lui-même seulement si aucune autre responsabilité durable ne le justifie.
|
||||
|
||||
## 10. Hors scope
|
||||
|
||||
Ne pas intégrer dans `0.3.3` sans découverte bloquante :
|
||||
|
||||
- Tauri Desktop ;
|
||||
- nouvelles fonctionnalités de gameplay ;
|
||||
- réseau realtime ;
|
||||
- publicité AdMob effective ;
|
||||
- billing ;
|
||||
- authentification ;
|
||||
- Uroburas ;
|
||||
- iOS ;
|
||||
- migration vers Kotlin ;
|
||||
- moteur V2 ;
|
||||
- optimisation prématurée par ABI sans mesure.
|
||||
|
||||
L'AAB est un objectif de packaging, pas une ouverture du scope monétisation/store complet.
|
||||
|
||||
## 11. `0-pre.1` obligatoire
|
||||
|
||||
Avant tout développement lourd :
|
||||
|
||||
1. auditer les modules Gradle existants et leurs versions ;
|
||||
2. auditer `scripts/build_android_rust.py` et distinguer ce qu'il orchestre réellement ;
|
||||
3. vérifier la version SDL3/AAR réellement utilisée et sa documentation Android actuelle ;
|
||||
4. vérifier AGP/Gradle/JDK/NDK et les API Android requises ;
|
||||
5. inventorier les ABI installables/testables localement ;
|
||||
6. distinguer support OS ancien et support CPU 32 bits ;
|
||||
7. proposer le `minSdk` candidat avec justification et stratégie de test ;
|
||||
8. définir APK universal, AAB et éventuels splits ;
|
||||
9. définir les gates par jalon ;
|
||||
10. créer `docs/plans/003-V0_3_3_ANDROID_NATIVE_MULTI_ABI_PLAN.md` avec un forecast souple jusqu'à stable.
|
||||
|
||||
Si le scope ne tient pas raisonnablement dans une session/version, le découper dès `0-pre.1` plutôt que d'allonger artificiellement les prereleases.
|
||||
|
||||
## 12. Validation et responsabilité
|
||||
|
||||
Les audits statiques peuvent être exécutés par le générateur. Les builds Cargo/Gradle, tests et smokes finaux restent côté utilisateur conformément aux règles du dépôt et ne sont jamais déclarés réussis sans sortie réelle.
|
||||
|
||||
Dès qu'un fichier Rust/Cargo change, appliquer la gate Rust normale. Dès qu'Android/Gradle change, ajouter les tâches Gradle ciblées prévues par le plan. Les tests workspace complets restent réservés aux jalons larges/finalisation selon la matrice.
|
||||
|
||||
Les commandes nécessitant un changement de répertoire utilisent un sous-shell :
|
||||
|
||||
```bash
|
||||
(cd Android && <commande>)
|
||||
```
|
||||
|
||||
## 13. Documentation, deltas et historique
|
||||
|
||||
Chaque tranche produit `deltas/0.3.3/<jalon>.md` avec base, scope, fichiers et validations attendues.
|
||||
|
||||
`history/0.3.3/<jalon>.md` n'est créé que par la tranche suivante après validation effective du jalon précédent.
|
||||
|
||||
`CHANGELOG.md` reste normalement silencieux pendant pre/alpha/beta et est consolidé à partir de la première RC. `ROADMAP.md` reste macroscopique.
|
||||
|
||||
Les nouvelles responsabilités Android durables doivent être documentées au moment où elles deviennent réelles, pas repoussées intégralement à la fin.
|
||||
|
||||
## 14. Forecast initial non contraignant
|
||||
|
||||
Le `0-pre.1` doit réviser ce forecast à partir de l'audit :
|
||||
|
||||
```text
|
||||
0-pre.1 audit + requirements + choix ABI/API + plan
|
||||
0-pre.2 orchestration Gradle/Cargo native sur une ABI
|
||||
0-pre.3 multi-ABI + APK universal
|
||||
0-pre.4 AAB + compatibilité Android/minSdk + smokes
|
||||
2-beta.1 validation large et packaging final
|
||||
3-rc.1 gel et reproductibilité
|
||||
0.3.3 promotion mécanique stable
|
||||
```
|
||||
|
||||
Les numéros peuvent être regroupés/scindés selon les résultats réels. Une version doit néanmoins être menée jusqu'à stable dans la session autant que possible.
|
||||
|
||||
## 15. Première gate de reprise
|
||||
|
||||
Après lecture/audit et avant la livraison `0-pre.1`, relever au minimum :
|
||||
|
||||
```bash
|
||||
rustc --version
|
||||
cargo --version
|
||||
rustup target list --installed
|
||||
java -version
|
||||
printf 'JAVA_HOME=%s\nANDROID_HOME=%s\n' "$JAVA_HOME" "$ANDROID_HOME"
|
||||
adb version
|
||||
adb devices -l
|
||||
emulator -list-avds
|
||||
(cd Android && gradle --version)
|
||||
```
|
||||
|
||||
Compléter par les versions/chemins NDK, SDK, AGP, SDL3 AAR et `cargo ndk` réellement trouvés dans la baseline.
|
||||
|
||||
## 16. Critère de réussite
|
||||
|
||||
`0.3.3` réussit lorsque le build Android SDL3 natif n'a plus besoin d'un orchestrateur Python, qu'un artefact de test multi-ABI reproductible est produit, qu'un AAB de distribution peut être construit sans secrets embarqués, que le support Android/ABI est explicitement documenté et testé selon les moyens disponibles, et que Snake reste fonctionnel sans régression du moteur partagé.
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# file: scripts/audit_distribution_layout.py
|
||||
# version: 7
|
||||
# version: 14
|
||||
|
||||
"""Audit the static distribution layout expected by supported POCs."""
|
||||
|
||||
@@ -30,6 +30,23 @@ REQUIRED_PATHS = (
|
||||
"crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts",
|
||||
"crates/apps/game-reflex-poc-wasm/Cargo.toml",
|
||||
"crates/apps/game-snake-poc-wasm/Cargo.toml",
|
||||
"crates/apps/game-snake-poc-tauri/Cargo.toml",
|
||||
"crates/apps/game-snake-poc-tauri/README.md",
|
||||
"crates/apps/game-snake-poc-tauri/USAGE.md",
|
||||
"crates/apps/game-snake-poc-tauri/package.json",
|
||||
"crates/apps/game-snake-poc-tauri/tsconfig.json",
|
||||
"crates/apps/game-snake-poc-tauri/vite.config.ts",
|
||||
"crates/apps/game-snake-poc-tauri/tauri.conf.json",
|
||||
"crates/apps/game-snake-poc-tauri/capabilities/default.json",
|
||||
"crates/apps/game-snake-poc-tauri/icons/icon.png",
|
||||
"crates/apps/game-snake-poc-tauri/frontend/main.html",
|
||||
"crates/apps/game-snake-poc-tauri/frontend/css/main.css",
|
||||
"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",
|
||||
"Web/game-snake-poc/tsconfig.json",
|
||||
"Web/game-snake-poc/vite.config.ts",
|
||||
@@ -136,6 +153,155 @@ def audit_snake_web_integration(root: pathlib.Path) -> list[str]:
|
||||
violations.append(message)
|
||||
return violations
|
||||
|
||||
def audit_snake_tauri_android_integration(root: pathlib.Path) -> list[str]:
|
||||
"""Validate the playable Snake Tauri Android reference POC boundary."""
|
||||
|
||||
violations: list[str] = []
|
||||
app_root = root / "crates/apps/game-snake-poc-tauri"
|
||||
cargo_path = app_root / "Cargo.toml"
|
||||
package_path = app_root / "package.json"
|
||||
tauri_path = app_root / "tauri.conf.json"
|
||||
tauri_rust_path = app_root / "src/tauri.rs"
|
||||
build_script_path = app_root / "build.rs"
|
||||
html_path = app_root / "frontend/main.html"
|
||||
main_path = app_root / "frontend/ts/main.ts"
|
||||
assets_path = app_root / "frontend/ts/assets.ts"
|
||||
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"
|
||||
paths = (
|
||||
cargo_path,
|
||||
package_path,
|
||||
tauri_path,
|
||||
tauri_rust_path,
|
||||
build_script_path,
|
||||
html_path,
|
||||
main_path,
|
||||
assets_path,
|
||||
game_path,
|
||||
input_path,
|
||||
provenance_path,
|
||||
lifecycle_path,
|
||||
logging_path,
|
||||
vite_path,
|
||||
wasm_runtime_path,
|
||||
)
|
||||
if not all(path.exists() for path in paths):
|
||||
return violations
|
||||
|
||||
cargo = cargo_path.read_text(encoding="utf-8")
|
||||
package = package_path.read_text(encoding="utf-8")
|
||||
tauri = tauri_path.read_text(encoding="utf-8")
|
||||
tauri_rust = tauri_rust_path.read_text(encoding="utf-8")
|
||||
build_script = build_script_path.read_text(encoding="utf-8")
|
||||
html = html_path.read_text(encoding="utf-8")
|
||||
main = main_path.read_text(encoding="utf-8")
|
||||
assets = assets_path.read_text(encoding="utf-8")
|
||||
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")
|
||||
required_fragments = (
|
||||
(cargo, 'game-logging-lib = { path = "../../common/game-logging-lib" }', "DIST-LAYOUT-021: Snake Tauri host must use shared Rust logging"),
|
||||
(cargo, 'tauri-plugin-tracing.workspace = true', "DIST-LAYOUT-022: Snake Tauri host must enable the tracing plugin"),
|
||||
(package, '"wasm:dev": "cargo build -p game-snake-poc-wasm', "DIST-LAYOUT-023: Snake Tauri dev hook must build the shared Snake WASM adapter"),
|
||||
(package, 'wasm-bindgen ../../../../builds/sasedev-games/', "DIST-LAYOUT-024: Snake Tauri bindings must be generated outside the repository"),
|
||||
(package, '"dev": "npm run wasm:dev && vite"', "DIST-LAYOUT-036: Snake Tauri dev hook must leave Android generation to Tauri"),
|
||||
(package, '"build": "npm run wasm:build && tsc && vite build"', "DIST-LAYOUT-037: Snake Tauri build hook must leave Android generation to Tauri"),
|
||||
(package, '"vite-plugin-static-copy"', "DIST-LAYOUT-043: Snake Tauri package must declare static asset packaging"),
|
||||
(build_script, "tauri_build::build();", "DIST-LAYOUT-038: Snake Tauri build script must delegate Android integration to tauri-build"),
|
||||
(tauri, '"script": "npm run dev"', "DIST-LAYOUT-025: Tauri must own the frontend development hook"),
|
||||
(tauri, '"script": "npm run build"', "DIST-LAYOUT-026: Tauri must own the frontend production hook"),
|
||||
(tauri_rust, '#[tauri::mobile_entry_point]', "DIST-LAYOUT-027: Snake Tauri run entry point must support Tauri mobile"),
|
||||
(tauri_rust, 'tauri_plugin_tracing::Builder::new()', "DIST-LAYOUT-028: Snake Tauri runtime must install the tracing plugin"),
|
||||
(html, '<canvas id="game"', "DIST-LAYOUT-044: Snake Tauri reference POC must expose the Canvas"),
|
||||
(html, 'data-direction="up"', "DIST-LAYOUT-045: Snake Tauri reference POC must expose touch direction controls"),
|
||||
(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"),
|
||||
(game, 'game.rectangle_count()', "DIST-LAYOUT-052: Snake Tauri Canvas host must render the shared WASM scene"),
|
||||
(input_module, '"pointerdown"', "DIST-LAYOUT-053: Snake Tauri input must support pointer/touch controls"),
|
||||
(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"),
|
||||
(vite, 'host: devHost || "127.0.0.1"', "DIST-LAYOUT-068: Snake Tauri HMR must use a loopback-compatible host for ADB forwarding"),
|
||||
(vite, 'port: 1436,', "DIST-LAYOUT-069: Snake Tauri Vite WebSocket must share port 1436 with the dev server"),
|
||||
(vite, 'clientPort: 1436,', "DIST-LAYOUT-070: Snake Tauri HMR client must use forwarded port 1436"),
|
||||
(logging, '@fltsci/tauri-plugin-tracing', "DIST-LAYOUT-030: Snake Tauri frontend logs must use the tracing bridge"),
|
||||
(wasm_runtime, '"tauri-webview" => Some(engine_v1_platform_api::RuntimeHost::TauriWebView)', "DIST-LAYOUT-031: Snake WASM adapter must accept the Tauri WebView host"),
|
||||
(wasm_runtime, '"android" => Some(engine_v1_platform_api::PlatformFamily::Android)', "DIST-LAYOUT-032: Snake WASM adapter must accept Android provenance"),
|
||||
)
|
||||
for content, fragment, message in required_fragments:
|
||||
if fragment not in content:
|
||||
violations.append(message)
|
||||
forbidden_fragments = (
|
||||
(package, "python", "DIST-LAYOUT-033: Snake Tauri build hooks must not use Python"),
|
||||
(package, "android:prepare", "DIST-LAYOUT-039: Snake Tauri build hooks must not patch generated Android Gradle files"),
|
||||
(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"),
|
||||
(vite, "1437", "DIST-LAYOUT-071: Snake Tauri dev/HMR must not require a second unforwarded WebSocket port"),
|
||||
)
|
||||
for content, fragment, message in forbidden_fragments:
|
||||
if fragment in content.lower():
|
||||
violations.append(message)
|
||||
return violations
|
||||
|
||||
|
||||
def audit_snake_tauri_generated_android(root: pathlib.Path) -> list[str]:
|
||||
"""Reject a locally generated Snake Android tree that drifted from Tauri 2.11.x."""
|
||||
|
||||
violations: list[str] = []
|
||||
android_root = root / "crates/apps/game-snake-poc-tauri/gen/android"
|
||||
if not android_root.exists():
|
||||
return violations
|
||||
|
||||
wrapper_path = android_root / "gradle/wrapper/gradle-wrapper.properties"
|
||||
build_path = android_root / "build.gradle.kts"
|
||||
if not wrapper_path.exists() or not build_path.exists():
|
||||
violations.append(
|
||||
"DIST-LAYOUT-041: generated Snake Tauri Android tree is incomplete; remove gen/android and rerun cargo tauri android init"
|
||||
)
|
||||
return violations
|
||||
|
||||
wrapper = wrapper_path.read_text(encoding="utf-8")
|
||||
build = build_path.read_text(encoding="utf-8")
|
||||
expected_fragments = (
|
||||
(wrapper, "gradle-8.14.3-bin.zip", "Gradle 8.14.3"),
|
||||
(build, 'classpath("com.android.tools.build:gradle:8.11.0")', "Android Gradle Plugin 8.11.0"),
|
||||
(build, 'classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")', "Kotlin Gradle Plugin 1.9.25"),
|
||||
)
|
||||
for content, fragment, label in expected_fragments:
|
||||
if fragment not in content:
|
||||
violations.append(
|
||||
f"DIST-LAYOUT-042: generated Snake Tauri Android tree does not match Tauri 2.11.x {label}; "
|
||||
"remove gen/android and rerun cargo tauri android init under JDK 17"
|
||||
)
|
||||
return violations
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Validate that every static distribution boundary exists."""
|
||||
|
||||
@@ -154,6 +320,8 @@ def main() -> int:
|
||||
forbidden_present.append(relative)
|
||||
contract_violations.extend(audit_snake_web_shell(root))
|
||||
contract_violations.extend(audit_snake_web_integration(root))
|
||||
contract_violations.extend(audit_snake_tauri_android_integration(root))
|
||||
contract_violations.extend(audit_snake_tauri_generated_android(root))
|
||||
if missing:
|
||||
for relative in missing:
|
||||
print(f"DIST-LAYOUT-001: missing required path: {relative}", file=sys.stderr)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# file: scripts/audit_project_workspace_rules.py
|
||||
# version: 6
|
||||
# version: 7
|
||||
|
||||
"""Audit mechanically verifiable games.sasedev workspace boundaries."""
|
||||
|
||||
@@ -15,6 +15,13 @@ import tomllib
|
||||
SEMVER = re.compile(r"^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-(?:0-pre|1-alpha|2-beta|3-rc)\.[1-9][0-9]*(?:\.fix\.[1-9][0-9]*)?)?$", re.ASCII)
|
||||
|
||||
|
||||
def is_generated_path(path: pathlib.Path, root: pathlib.Path) -> bool:
|
||||
"""Return whether a path belongs to an ignored generated tree."""
|
||||
|
||||
relative = path.relative_to(root)
|
||||
return "gen" in relative.parts
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Run project-specific workspace audits."""
|
||||
|
||||
@@ -86,10 +93,14 @@ def main() -> int:
|
||||
errors.append(
|
||||
f"DOC-011: documentary directory entry point must use 000-README.md: {readme_path.relative_to(root).as_posix()}"
|
||||
)
|
||||
forbidden_assets = [path for path in (root / "crates").rglob("assets") if path.is_dir()]
|
||||
forbidden_assets = [
|
||||
path for path in (root / "crates").rglob("assets") if path.is_dir() and not is_generated_path(path, root)
|
||||
]
|
||||
for path in forbidden_assets:
|
||||
errors.append(f"GAME-ASSET-001: assets directory forbidden inside crates: {path.relative_to(root).as_posix()}")
|
||||
for java_path in sorted(root.rglob("*.java")):
|
||||
if is_generated_path(java_path, root):
|
||||
continue
|
||||
if not java_path.is_relative_to(root / "Android"):
|
||||
errors.append(f"GAME-ANDROID-001: Java source outside Android/: {java_path.relative_to(root).as_posix()}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user