38 Commits

Author SHA1 Message Date
778da67e22 0.3.0 2026-09-20 15:32:00 +02:00
a9620ef84c 0.3.0-3-rc.1 2026-09-20 15:25:55 +02:00
45c31d4721 0.3.0-2-beta.2.fix.2 2026-09-20 15:07:25 +02:00
54121215b4 0.3.0-2-beta.2.fix.1 2026-09-20 14:52:37 +02:00
fca477eb23 0.3.0-2-beta.2 2026-09-20 14:30:55 +02:00
ff1ec09d68 0.3.0-2-beta.1 2026-09-20 14:20:07 +02:00
3e1153eb8c 0.3.0-0-pre.5-fix.1 2026-09-20 14:03:04 +02:00
7f0635ec9d 0.3.0-0-pre.5 2026-09-20 13:58:13 +02:00
86b8af3b61 0.3.0-0-pre.4-fix.3 2026-09-20 13:40:19 +02:00
023825b89b 0.3.0-0-pre.4-fix.2 2026-09-20 13:33:39 +02:00
f433e99a12 0.3.0-0-pre.4-fix.1 2026-09-20 13:26:07 +02:00
c4b68b8a60 0.3.0-0-pre.4 2026-09-20 13:14:40 +02:00
c7ccf57723 0.3.0-0-pre.3 2026-09-20 07:03:34 +02:00
a6a59222d6 0.3.0-0-pre.2 2026-09-20 06:53:40 +02:00
6f37fea9ed 0.3.0-0-pre.1-fix.2 2026-09-20 06:43:07 +02:00
d16648c34c 0.3.0-0-pre.1-fix.1 2026-09-20 06:28:37 +02:00
54079accb5 0.3.0-0-pre.1 2026-09-20 06:15:50 +02:00
74be610697 0.2.0 2026-09-19 06:07:25 +02:00
0ef2d3872b 0.2.0-3-rc.1 2026-09-19 05:38:40 +02:00
930b005481 0.2.0-0-pre.8.fix.1 2026-09-19 05:34:12 +02:00
cfa9a1ce21 0.2.0-0-pre.8 2026-09-19 05:15:01 +02:00
090cc67c06 0.2.0-0-pre.7 2026-09-18 23:30:16 +02:00
f2eb58c712 0.2.0-0-pre.6-fix.1 2026-09-18 23:16:45 +02:00
ec93eaebb2 0.2.0-0-pre.6 2026-09-18 22:57:26 +02:00
130150a751 0.2.0-0-pre.5-fix.1 2026-09-18 20:23:47 +02:00
8bfeb4b9f8 0.2.0-0-pre.5 2026-09-18 20:06:00 +02:00
aa9c68e4c7 0.2.0-0-pre.4-fix.2 2026-09-18 15:11:40 +02:00
504cc02712 0.2.0-0-pre.4-fix.1 2026-09-18 15:06:30 +02:00
a8ab312a3a 0.2.0-0-pre.4 2026-09-18 15:03:33 +02:00
2a0cf4dd2b 0.2.0-0-pre.3-fix.1 2026-09-18 14:52:14 +02:00
5f75c3ad1a 0.2.0-0-pre.3 2026-09-18 14:46:05 +02:00
514425383b 0.2.0-0-pre.2-fix.3 2026-09-18 14:39:04 +02:00
13d089a5db 0.2.0-0-pre.2-fix.2 2026-09-18 14:16:41 +02:00
4b71d87ca3 0.2.0-0-pre.2-fix.1 2026-09-18 14:14:04 +02:00
ffedb4f16e 0.2.0-0-pre.2 2026-09-18 14:04:12 +02:00
63dcb2af4e 0.2.0-0-pre.1-fix.2 2026-09-18 13:32:09 +02:00
df4a06fac3 0.2.0-0-pre.1-fix.1 2026-09-18 00:58:14 +02:00
de63a8c57b 0.2.0-0-pre.1 2026-09-18 00:39:10 +02:00
154 changed files with 12914 additions and 221 deletions

View File

@@ -1,5 +1,5 @@
// file: Android/game-reflex-poc/build.gradle
// version: 24
// version: 45
plugins {
id 'com.android.application'
@@ -17,8 +17,8 @@ android {
applicationId 'com.sasedev.games.reflex'
minSdk 21
targetSdk 36
versionCode 1
versionName '0.1.0'
versionCode 2
versionName '0.2.0'
}
compileOptions {

View File

@@ -1,5 +1,5 @@
// file: Android/game-snake-poc/build.gradle
// version: 24
// version: 45
plugins {
id 'com.android.application'
@@ -17,8 +17,8 @@ android {
applicationId 'com.sasedev.games.snake'
minSdk 21
targetSdk 36
versionCode 1
versionName '0.1.0'
versionCode 2
versionName '0.2.0'
}
compileOptions {

View File

@@ -1,16 +1,48 @@
<!-- file: CHANGELOG.md -->
<!-- version: 8 -->
<!-- version: 14 -->
# Changelog
## 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 ;
- validation du shell Bootstrap 5/Bootswatch + SimpleBar, du Canvas au ratio logique `12 × 20`, des contrôles clavier/pointer, du lifecycle navigateur, des assets et de la provenance runtime ;
- validation de la non-régression Desktop SDL3 et des builds release Desktop et Web/WASM ;
- promotion mécanique de `0.3.0-3-rc.1` après gate workspace complète, 34 tests réussis et absence de défaut nécessitant un correctif RC ;
- préparation de `0.3.1` pour le second host Snake Tauri Android, sans ouvrir ce scope dans la release `0.3.0`.
Les détails des phases `pre`, `beta`, `rc` et de leurs correctifs restent dans `deltas/0.3.0/` et `history/0.3.0/`.
## 0.3.0-3-rc.1 — 2026-09-20
- gel fonctionnel du premier POC Snake Web direct après validation beta et consolidation documentaire ;
- gameplay Snake conservé dans `game-snake-poc`, avec adapter `game-snake-poc-wasm` dédié et host navigateur Vite/TypeScript séparé ;
- shell Web responsive fondé sur Bootstrap 5/Bootswatch, SimpleBar et Canvas au ratio logique du jeu, avec clavier et contrôles pointer/tactiles ;
- lifecycle navigateur fixed-step sans rattrapage massif, resize `devicePixelRatio`, assets `common/` + `game/`, logging frontend structuré et provenance `Web / Browser / Wasm` ;
- runner Desktop SDL3 maintenu comme témoin de non-régression et builds release Desktop/Web déjà exercés pendant la beta ;
- prompt `0.3.1` préparé pour le second host Snake Tauri Android, avec workflow de session, commandes et validations consolidés.
La RC n'ouvre aucun nouveau scope. Les détails des phases `pre`, `beta` et de leurs correctifs restent dans `deltas/0.3.0/` et `history/0.3.0/`.
## 0.2.0 — conception modulaire, POC et Uroburas
- Gouvernance documentaire renforcée : catégories `ideas/studies/architecture/rules`, immutabilité des deltas, conventions de statuts et workflow de session/version.
- Architecture durable séparant engine kernel, technical capabilities, game-systems, games, platform adapters, providers, server services et tooling.
- Trajectoire POC `0.3.x` définie avec Snake comme jeu-sonde pour SDL, Web/WASM, Tauri et transports realtime.
- Architecture réseau de référence : Actix Web/Maud/Fluent/Lettre pour Web/API, WebSocket/tokio-tungstenite baseline, WebTransport/QUIC candidat, gRPC/Tonic conditionnel server-to-server.
- Asset delivery auto-hébergé, compatible HTTP/2 et HTTP/3 selon disponibilité, avec séparation logique puis physique progressive.
- Cible d'exploitation préférée : Debian Stable, actuellement Debian 13 `trixie`, sans dépendance métier à une version précise.
- Spécification fonctionnelle et architecture cible initiales de Uroburas, avec ordre Mode 1 Challenge → Mode 3 Persistent Battle Royale → Mode 2 PvP Battles.
- Classification des besoins Uroburas afin d'éviter une crate jeu monolithique.
- Première trajectoire Uroburas réservant grid/tilemap toroïdale, obstacles, stages, vies, score, caméra, assets téléchargeables, auth, rewarded ads, Hall of Fame et échanges client/serveur sécurisés/versionnés.
## 0.1.0 — 2026-09-17
- validation de `0.1.0-3-rc.1.fix.1` avec gates Rust/audits complètes, builds et smokes Desktop release, Tauri/WASM, Android x86_64/API 36 et Android ARM64 réel ;
- stabilisation d'une première baseline POC multi-plateforme fondée sur un core de gameplay Rust réutilisé par des runners SDL3 Desktop/Android et un POC Tauri/WebView/WASM ;
- validation de l'abstraction d'input, du rendu 2D minimal, des assets, de la provenance runtime, du tracing commun et du lifecycle/Back Android ;
- clôture du cycle POC `0.1.0` sans ajout fonctionnel de dernière minute ;
- réservation de la direction `0.2.0` : petit kernel moteur, capabilities séparées, adaptateurs plateforme, providers, jeux et services/serveurs composés statiquement ;
- ajout d'un prompt de conception `0.2.0` afin que l'inventaire détaillé des fonctionnalités et la future architecture soient discutés avant toute implémentation majeure.
- réservation de la direction `0.2.0` pour concevoir progressivement le framework modulaire avant toute extension fonctionnelle majeure.
## 0.1.0-3-rc.1 — 2026-09-17
@@ -20,59 +52,4 @@
- entrée en phase RC centrée sur la reproductibilité des builds de release, les artefacts de distribution et la documentation de livraison ;
- ajout d'une matrice RC et d'une gate workspace complète avant promotion vers `0.1.0`.
## 0.1.0-2-beta.1 — 2026-09-17
- validation de `1-alpha.2.fix.5` avec Reflex exécuté dans Tauri/WebView/WASM via Vite + TypeScript ;
- validation du tracing unifié Rust/TypeScript et de la sortie `Escape` via le contrat moteur commun ;
- passage en phase beta, désormais centrée sur la stabilisation, le packaging et les tests multi-appareils ;
- ajout d'une matrice de validation Desktop SDL3, Tauri/WASM, Android AVD x86_64 et Android ARM64 réel ;
- ajout d'un audit en lecture seule des frontières statiques nécessaires aux distributions ;
- formalisation des gates de packaging Desktop natif, Tauri et Android beta.
## 0.1.0-1-alpha.1 — 2026-09-16
- validation de la fin de phase `0-pre.*` avec Snake jouable sur Desktop et Galaxy S9+ ARM64 ;
- stabilisation du contrat de sortie `QuitRequest` / `QuitDecision` introduit pendant les derniers correctifs `0-pre.11` ;
- introduction de `RuntimeProvenance` dans `engine-v1-platform-api` ;
- séparation explicite entre famille de plateforme, classe de device, exécution native/WASM, hôte runtime et profil d'entrée ;
- préparation des futurs leaderboards/Hall of Fame pour segmenter les scores selon l'environnement sans imposer de comparaison automatique ;
- planification d'un POC Web/WASM dans Tauri comme prochain jalon alpha.
## 0.1.0-0-pre.4 — 2026-09-16
- validation de `0-pre.3` enregistrée avec suite workspace complète et smokes Desktop propres ;
- déplacement des tests unitaires hors `src/` vers `unit_tests/` et formalisation de `tests/` pour intégration/environnement ;
- ajout dun audit empêchant le retour de corps de tests sous `src/` ;
- adoption des tests Cargo ciblés par défaut, la suite workspace complète devenant une gate lourde périodique ;
- `cargo fmt --all` devient obligatoire avant la gate lorsquun delta modifie du Rust, sans incrément den-tête pour les seules modifications rustfmt ;
- introduction de `game-logging-lib` avec `tracing`, `tracing-subscriber` et `tracing-appender` ;
- initialisation du tracing dans les runners Desktop et helper de tracing local pour les tests.
## 0.1.0-0-pre.3 — 2026-09-16
- validation utilisateur de `0.1.0-0-pre.2` avec formatage, audits, check, Clippy strict et tests workspace propres ;
- introduction de `EngineFrame`, `InputState`, `EngineGame` et `FixedStepRunner` comme première boucle moteur indépendante de SDL3 ;
- branchement des deux POC et des deux runners Desktop sur cette boucle commune ;
- introduction d'un état explicite `Available` / `Disabled` / `Unsupported` pour les services plateforme optionnels et d'une déclaration de capacités de monétisation ;
- documentation de la monétisation optionnelle par plateforme, y compris distinction Android, Web et Desktop ;
- documentation du binaire Desktop SDL3 comme défaut et d'une variante Tauri optionnelle sans duplication du gameplay ;
- formalisation de la validation Cargo par l'utilisateur, de l'enregistrement de la validation du delta précédent et du passage automatique au delta suivant ou à un `.fix.N` selon le résultat.
## 0.1.0-0-pre.2 — 2026-09-15
- intégration de l'architecture de référence dans une documentation thématique durable ;
- ajout des objectifs projet, classification des jeux, abstraction SDL3 multi-plateforme, contrôles, assets, évolution moteur, monétisation et services en ligne ;
- ajout d'une crate binaire Desktop par POC, chacune consommant exclusivement la crate lib du jeu correspondant ;
- ajout de la politique normative des commandes Cargo, audits, runners, Android, Web et Git ;
- mise à jour de l'index documentaire, des contrats de fichiers, de la roadmap et des gates.
## 0.1.0-0-pre.1 — 2026-09-15
- création du workspace Cargo multi-crates ;
- introduction de la génération `engine-v1` ;
- création de deux POC structurels Reflex et Snake ;
- séparation stricte des assets hors crates ;
- création de la structure Android Java commune et spécifique par jeu ;
- adaptation des règles et audits issus de l'expérience KSP ;
- adoption du cycle SemVer `pre -> alpha -> beta -> rc -> stable` avec correctifs `.fix.N` ;
- adoption des livraisons par archives delta.
Les détails des phases `pre`, `alpha`, `beta` et de leurs correctifs sont conservés dans `deltas/0.1.0/` et `history/0.1.0/`.

View File

@@ -1,5 +1,5 @@
# file: Cargo.toml
# version: 36
# version: 69
[workspace]
resolver = "3"
@@ -16,10 +16,11 @@ members = [
"crates/apps/game-android-entrypoint",
"crates/apps/game-reflex-poc-tauri",
"crates/apps/game-reflex-poc-wasm",
"crates/apps/game-snake-poc-wasm",
]
[workspace.package]
version = "0.1.0"
version = "0.3.0"
edition = "2024"
license = "MIT"
repository = "https://git.sasedev.com/Sasedev/games"

View File

@@ -1,5 +1,5 @@
<!-- file: README.md -->
<!-- version: 6 -->
<!-- version: 40 -->
# 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 ;
- 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 ;
- documentation sous `docs/` ;
@@ -23,7 +24,9 @@ Workspace expérimental puis productif pour des jeux multiplateformes principale
## Baseline
Version courante : `0.1.0-1-alpha.1`.
Version stable de référence : `0.3.0`.
Version suivante planifiée : `0.3.1` (non démarrée).
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.

View File

@@ -1,27 +1,56 @@
<!-- file: ROADMAP.md -->
<!-- version: 14 -->
<!-- version: 21 -->
# Roadmap
## Légende
- `( )` — planned ;
- `(x)` — completed ;
- `(d)` — deferred ;
- `(c)` — cancelled.
Les marqueurs qualifient une ligne de scope. Une même version peut donc apparaître plusieurs fois si une partie est livrée, une partie reportée et une autre annulée.
## 0.1.0 — Fondation POC
- [x] `0-pre.1` — squelette du workspace, règles, architecture, versions, assets, Java Android commun/spécifique et deux crates POC.
- [x] `0-pre.2` — consolidation documentaire issue de l'architecture de référence, runners Desktop par jeu et politique normative des commandes.
- [x] `0-pre.3` — première boucle moteur exécutable Desktop : temps, input abstrait, capacités de monétisation optionnelles et état de jeu minimal via les runners.
- [x] `0-pre.4` — architecture de tests hors `src/`, stratégie de tests ciblés et socle `tracing`/`tracing-subscriber`/`tracing-appender`.
- [x] `0-pre.5` — intégration SDL3 Desktop réelle et premier rendu POC Reflex.
- [x] `0-pre.6` — fondation Gradle Android, SDL3 AAR, Activity Java commune et politique de fenêtre Desktop redimensionnable.
- [x] `0-pre.7` — compilation Rust Android `cdylib`, point d'entrée SDL Android et premier lancement APK sur appareil/émulateur.
- [x] `0-pre.8` — bridge Java/JNI minimal et input tactile Android.
- [x] `0-pre.9` — assets communs + spécifiques empaquetés sans copie dans les crates.
- [x] `0-pre.10` — POC Reflex jouable Desktop + Android.
- [x] `0-pre.11` — POC Snake jouable et validation de la réutilisation du moteur.
- [x] `1-alpha.1` — première API moteur V1 volontairement stabilisée et provenance runtime/input pour les futures sessions et scores.
- [x] `1-alpha.2` — POC Web/WASM embarqué dans Tauri, sans site distant, et validation de la frontière des services Web/ads.
- [x] `2-beta.1` — stabilisation, packaging, tests multi-appareils.
- [x] `3-rc.1` — candidat de release du socle 0.1.0.
- [x] `0.1.0` — première baseline stable du framework POC.
- (x) `0.1.0` — squelette du workspace, règles, architecture, versions et assets.
- (x) `0.1.0` — moteur V1 POC, boucle de jeu, input abstrait et rendu SDL3 minimal.
- (x) `0.1.0` — Reflex et Snake jouables comme POC de réutilisation.
- (x) `0.1.0` — Desktop SDL3 natif, Android SDL3/Java/JNI et Tauri/WebView/WASM Reflex.
- (x) `0.1.0` — tracing commun, provenance runtime, packaging et validation multi-appareils.
Le détail historique des prereleases `0.1.0-*` reste dans `deltas/0.1.0/` et `history/0.1.0/`.
## 0.2.0 — Conception du framework modulaire
- [ ] `0.2.0`inventorier et réserver les capabilities utiles, définir les couches et dépendances autorisées, établir la matrice plateformes et les archétypes de jeux, définir la composition statique et l'architecture cible des crates, puis seulement planifier les implémentations progressives.
- (x) `0.2.0`fixer la gouvernance documentaire, la nomenclature et le cycle de maturation des idées et décisions.
- (x) `0.2.0` — inventorier et réserver les capabilities déjà justifiées sans les implémenter prématurément.
- (x) `0.2.0` — définir les couches, les dépendances autorisées et la frontière entre kernel, capability, plateforme, provider, système de jeu et service.
- (x) `0.2.0` — établir la matrice plateformes et les archétypes de jeux utilisés pour challenger l'architecture.
- (x) `0.2.0` — retenir la composition Rust statique comme direction de référence.
- (d) `0.2.0` — figer un manifest produit/jeu et l'architecture physique définitive des crates → target TBD après observation des POC `0.3.x`.
- (x) `0.2.0` — définir la trajectoire d'implémentation progressive `0.3.x` POC puis `0.4.x` Uroburas.
- (x) `0.2.0` — consolider les études acceptées en architecture/règles durables, notamment ownership, réseau, Uroburas et POC, puis fermer les points encore candidats.
- (x) `0.2.0` — formaliser la stratégie réseau : Actix Web pour le Web/API, asset delivery auto-hébergé H2/H3, WebSocket baseline et WebTransport/QUIC candidat.
- (x) `0.2.0` — préparer une trajectoire `0.3.x` dédiée aux POC plateforme/réseau avec Snake comme jeu-sonde.
- (x) `0.2.0` — préparer la trajectoire `0.4.x` Uroburas Mode 1 et le prompt de session associé après gel de la conception.
## 0.3.0 — Baseline Snake + premier POC Web direct
- (x) `0.3.0` — nettoyer la baseline Snake sans introduire de logique Uroburas et maintenir le runner Desktop SDL3 fonctionnel.
- (x) `0.3.0` — produire une adaptation WASM dédiée à Snake sans déplacer le gameplay hors de `game-snake-poc`.
- (x) `0.3.0` — réaliser un POC navigateur direct Snake couvrant clavier, boutons directionnels tactiles, resize, lifecycle, logging, assets et provenance runtime.
- (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 quun second consommateur ne justifie pas une extraction commune.
## Série 0.3.x — trajectoire actuelle après 0.3.0
- ( ) `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.
- ( ) `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`.
La numérotation `0.3.1+` reste révisable à partir des résultats réels ; les lignes ci-dessus décrivent le planning actuel, pas une obligation de créer des versions artificielles.

View File

@@ -1,5 +1,5 @@
<!-- file: RULES.md -->
<!-- version: 3 -->
<!-- version: 5 -->
# Index normatif games.sasedev
@@ -15,7 +15,11 @@ Les règles détaillées sont maintenues sous `docs/rules/` et sont cumulatives
4. [`docs/rules/RULES_DOCUMENTATION.md`](docs/rules/RULES_DOCUMENTATION.md) — règles Markdown et cycle documentaire ;
5. [`docs/rules/FILE_CONTRACTS.md`](docs/rules/FILE_CONTRACTS.md) — responsabilités des principales familles de fichiers ;
6. [`docs/rules/VERSION_WORKFLOW.md`](docs/rules/VERSION_WORKFLOW.md) — SemVer, niveaux de maturité, fixes, deltas et livraisons ;
7. [`docs/rules/RULES_COMMANDS.md`](docs/rules/RULES_COMMANDS.md) — politique dexécution des commandes Cargo, audits, runners, Android, Web et Git.
7. [`docs/rules/RULES_COMMANDS.md`](docs/rules/RULES_COMMANDS.md) — politique dexécution des commandes Cargo, audits, runners, Android, Web et Git ;
8. [`docs/rules/RULES_VALIDATION_MATRIX.md`](docs/rules/RULES_VALIDATION_MATRIX.md) — matrice évolutive des commandes, dépendances de validation et politiques de nettoyage ;
9. [`docs/rules/RULES_SESSION_PLANNING.md`](docs/rules/RULES_SESSION_PLANNING.md) — cadrage `pre.1`, dimensionnement des sessions et cycle de transmission ;
10. [`docs/rules/PROMPT_STRUCTURE.md`](docs/rules/PROMPT_STRUCTURE.md) — structure minimale des prompts de reprise et rappels de workflow obligatoires ;
11. [`docs/rules/RULES_SERVER_HOSTING.md`](docs/rules/RULES_SERVER_HOSTING.md) — contraintes durables de portabilité et préférence d'auto-hébergement.
## Hiérarchie

View File

@@ -0,0 +1,118 @@
<!-- file: Web/game-snake-poc/frontend/main.html -->
<!-- version: 4 -->
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0, viewport-fit=cover" name="viewport">
<meta content="#593196" name="theme-color">
<link rel="stylesheet" href="sass/main.scss">
<title>Snake POC — Web direct</title>
</head>
<body>
<header class="app-header">
<nav class="navbar h-100 py-0 bg-light text-dark">
<div class="container-fluid px-3 px-md-4 flex-nowrap">
<div class="navbar-brand d-flex align-items-center me-3 flex-nowrap min-w-0">
<span class="app-logo d-inline-flex align-items-center justify-content-center text-primary" aria-hidden="true">
<i class="fa-solid fa-gamepad"></i>
</span>
<span class="ps-2 fs-4 fw-semibold text-primary text-nowrap">Snake POC</span>
<span class="mx-2 fs-5 text-body-secondary d-none d-sm-inline" aria-hidden="true"></span>
<span class="fs-5 text-body text-nowrap d-none d-sm-inline">Web direct</span>
</div>
<div class="d-flex align-items-center gap-2 ms-auto">
<span class="badge text-bg-light border text-dark d-none d-md-inline">Rust/WASM</span>
<span id="runtime-status" class="badge text-bg-secondary" role="status" aria-live="polite">Initialisation…</span>
</div>
</div>
</nav>
</header>
<main class="app-main container-fluid p-0">
<div class="row g-0 h-100 flex-nowrap">
<section class="col app-content app-scrollable h-100" data-simplebar>
<div class="container-fluid px-3 px-md-4 py-3 py-md-4">
<div class="card app-shell-card mx-auto shadow-sm border-0">
<div class="card-body p-3 p-md-4">
<div class="d-flex align-items-start justify-content-between gap-3 flex-wrap mb-3">
<div>
<h1 class="h3 mb-1">Snake</h1>
<p class="text-body-secondary mb-0">Gameplay Rust portable, adapter WebAssembly et rendu Canvas piloté par TypeScript.</p>
</div>
<div class="d-flex gap-2 flex-wrap" aria-label="État de la partie">
<output id="score" class="badge text-bg-primary">Score : 0</output>
<output id="length" class="badge text-bg-info">Longueur : 0</output>
</div>
</div>
<div class="row g-3 g-lg-4 align-items-start">
<div class="col-12 col-lg-8">
<div class="card border-primary-subtle shadow-sm">
<div class="card-body p-2 p-sm-3">
<div class="game-stage">
<canvas id="game" width="640" height="640" tabindex="0" aria-label="Zone de jeu Snake"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-4">
<div class="card shadow-sm app-controls-card">
<div class="card-header d-flex align-items-center justify-content-between gap-2">
<span class="fw-semibold"><i class="fa-solid fa-keyboard me-2" aria-hidden="true"></i>Contrôles</span>
<span class="small text-body-secondary">clavier / tactile</span>
</div>
<div class="card-body">
<p class="small text-body-secondary">Utilisez les flèches, WASD, ZQSD ou les boutons directionnels.</p>
<div class="direction-pad mx-auto" aria-label="Contrôles directionnels tactiles">
<button class="btn btn-outline-primary direction-up" type="button" data-direction="up" aria-label="Haut">
<i class="fa-solid fa-arrow-up" aria-hidden="true"></i>
</button>
<button class="btn btn-outline-primary direction-left" type="button" data-direction="left" aria-label="Gauche">
<i class="fa-solid fa-arrow-left" aria-hidden="true"></i>
</button>
<button class="btn btn-outline-primary direction-down" type="button" data-direction="down" aria-label="Bas">
<i class="fa-solid fa-arrow-down" aria-hidden="true"></i>
</button>
<button class="btn btn-outline-primary direction-right" type="button" data-direction="right" aria-label="Droite">
<i class="fa-solid fa-arrow-right" aria-hidden="true"></i>
</button>
</div>
<dl class="runtime-details small border-top pt-3 mt-3 mb-0">
<div class="d-flex justify-content-between gap-3">
<dt class="text-body-secondary fw-normal">Provenance</dt>
<dd class="mb-2 text-end"><output id="runtime-provenance">web / browser / wasm / unknown / unknown</output></dd>
</div>
<div class="d-flex justify-content-between gap-3">
<dt class="text-body-secondary fw-normal">Assets</dt>
<dd class="mb-0 text-end"><output id="asset-status">chargement…</output></dd>
</div>
</dl>
<div class="alert alert-info small mt-3 mb-0" role="note">
Les entrées ne font pas avancer la simulation : elles sont consommées au prochain <code>tick()</code> WASM.
</div>
</div>
</div>
</div>
</div>
<p id="startup-error" class="alert alert-danger mt-3 mb-0" role="alert" hidden></p>
</div>
</div>
</div>
</section>
</div>
</main>
<footer class="app-footer bg-dark text-light">
<div class="container h-100 d-flex align-items-center justify-content-center">
<small>&copy; 2026 SASEDEV</small>
</div>
</footer>
<script type="module" src="ts/main.ts" defer></script>
</body>
</html>

View File

@@ -0,0 +1,165 @@
// file: Web/game-snake-poc/frontend/sass/_app.scss
// version: 4
$app-header-height: 72px;
$app-footer-height: 42px;
html,
body {
width: 100%;
min-width: 320px;
height: 100%;
}
body {
margin: 0;
overflow: hidden;
background: $gray-100;
overscroll-behavior: none;
}
.min-w-0 {
min-width: 0;
}
.app-header {
position: fixed;
inset: 0 0 auto;
height: $app-header-height;
z-index: 1020;
border-bottom: 2px solid rgba($primary, 0.3);
}
.app-footer {
position: fixed;
inset: auto 0 0;
height: $app-footer-height;
z-index: 1020;
border-top: 2px solid rgba($primary, 0.3);
}
.app-main {
position: relative;
width: 100%;
height: calc(100vh - $app-header-height - $app-footer-height);
margin-top: $app-header-height;
margin-bottom: $app-footer-height;
overflow: hidden;
}
.app-main > .row {
flex-wrap: nowrap;
min-width: 0;
}
.app-scrollable {
height: 100%;
max-height: 100%;
}
.app-content {
min-width: 0;
height: 100%;
max-height: 100%;
}
.app-logo {
width: 42px;
height: 42px;
font-size: 1.75rem;
}
.app-shell-card {
width: 100%;
max-width: 1180px;
min-width: 0;
}
.game-stage {
width: 100%;
max-width: 520px;
margin-inline: auto;
aspect-ratio: 3 / 5;
overflow: hidden;
background: $black;
border: 1px solid rgba($primary, 0.35);
}
#game {
display: block;
width: 100%;
height: 100%;
touch-action: none;
outline: none;
}
#game:focus-visible {
box-shadow: inset 0 0 0 3px rgba($primary, 0.85);
}
.app-controls-card {
min-width: 0;
}
.runtime-details dd {
min-width: 0;
overflow-wrap: anywhere;
}
.direction-pad {
display: grid;
grid-template-columns: repeat(3, minmax(64px, 88px));
grid-template-rows: repeat(2, minmax(56px, 72px));
gap: 0.5rem;
justify-content: center;
user-select: none;
}
.direction-pad .btn {
touch-action: manipulation;
font-size: 1.25rem;
}
.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;
}
@media (max-width: 575.98px) {
$mobile-header-height: 64px;
.app-header {
height: $mobile-header-height;
}
.app-main {
height: calc(100vh - $mobile-header-height - $app-footer-height);
margin-top: $mobile-header-height;
}
.app-logo {
width: 34px;
height: 34px;
font-size: 1.4rem;
}
.direction-pad {
width: 100%;
grid-template-columns: repeat(3, minmax(72px, 1fr));
}
}

View File

@@ -0,0 +1,160 @@
// file: Web/game-snake-poc/frontend/sass/_bootswatch.scss
// version: 1
// Pulse 5.3.8
// Bootswatch
// Variables
// Buttons
.btn {
&:focus,
&:active,
&:active:focus,
&.active:focus {
outline: none;
}
&-secondary {
color: $gray-900;
background-color: $white;
border-color: #ccc;
&:hover {
color: $gray-900;
background-color: $gray-300;
border-color: $gray-500;
}
&.disabled {
color: tint-color($gray-900, 5%);
background-color: $white;
border-color: tint-color(#ccc, 5%);
}
}
&-warning {
color: $white;
}
&-primary:focus {
box-shadow: 0 0 5px tint-color($primary, 10%);
}
&-secondary:focus {
box-shadow: 0 0 5px $gray-400;
}
&-success:focus {
box-shadow: 0 0 5px tint-color($success, 10%);
}
&-info:focus {
box-shadow: 0 0 5px tint-color($info, 10%);
}
&-warning:focus {
box-shadow: 0 0 5px tint-color($warning, 10%);
}
&-danger:focus {
box-shadow: 0 0 5px tint-color($danger, 10%);
}
&.disabled:focus {
box-shadow: none;
}
}
// Tables
.table .thead-dark th {
background-color: $secondary;
border-color: $table-border-color;
}
.table-primary,
.table-secondary,
.table-success,
.table-warning,
.table-danger,
.table-info,
.table-light {
--#{$prefix}table-color: #{$body-color};
}
// Forms
.form-control:focus {
box-shadow: 0 0 5px rgba(100, 65, 164, .4);
}
// Navs
.nav-tabs {
.nav-link,
.nav-link.active {
border-width: 0 0 1px;
}
.nav-link:hover,
.nav-link.active,
.nav-link.active:hover,
.nav-link.active:focus {
border-bottom: 1px solid $primary;
}
.nav-item+.nav-item {
margin-left: 0;
}
}
.breadcrumb {
&-item.active {
color: $gray-700;
}
}
// Indicators
.badge {
&.bg-light {
color: $dark;
}
}
// Progress bars
.progress {
height: 8px;
}
// Containers
.list-group {
&-item {
color: rgba(255, 255, 255, .8);
&.active,
&:hover,
&:focus {
color: $white;
}
&.active {
font-weight: 700;
&:hover {
background-color: $list-group-hover-bg;
}
}
&.disabled:hover {
color: $list-group-disabled-color;
}
}
}

View File

@@ -0,0 +1,19 @@
// file: Web/game-snake-poc/frontend/sass/_fontawesome.scss
// version: 1
//@use '@fortawesome/fontawesome-free/scss/variables' with (
// // customizing $font-path - make sure it points to where your webfonts are stored in your project
// $font-path: '../webfonts',
//);
@use '@fortawesome/fontawesome-free/scss/variables' with (
// use fonts from @fortawesome/fontawesome-free
$font-path: '@fortawesome/fontawesome-free/webfonts',
);
// load Font Awesome core
@use '@fortawesome/fontawesome-free/scss/fontawesome';
// load and make available Font Awesome helpers (mixins, functions, and variables)
@use '@fortawesome/fontawesome-free/scss/fa' as fa;
@use '@fortawesome/fontawesome-free/scss/brands' as fa-brands;
@use '@fortawesome/fontawesome-free/scss/regular' as fa-regular;
@use '@fortawesome/fontawesome-free/scss/solid' as fa-solid;

View File

@@ -0,0 +1,248 @@
// file: Web/game-snake-poc/frontend/sass/_simplebar.scss
// version: 1
/* Rtl support */
[data-simplebar] {
position: relative;
flex-direction: column;
flex-wrap: wrap;
justify-content: flex-start;
align-content: flex-start;
align-items: flex-start;
}
.simplebar-wrapper {
overflow: hidden;
width: inherit;
height: inherit;
max-width: inherit;
max-height: inherit;
}
.simplebar-mask {
direction: inherit;
position: absolute;
overflow: hidden;
padding: 0;
margin: 0;
left: 0;
top: 0;
bottom: 0;
right: 0;
width: auto !important;
height: auto !important;
// z-index: 0;
inset: 0;
}
.simplebar-offset {
direction: inherit !important;
box-sizing: inherit !important;
resize: none !important;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
padding: 0;
margin: 0;
-webkit-overflow-scrolling: touch;
inset: 0;
}
.simplebar-content-wrapper {
direction: inherit;
box-sizing: border-box !important;
position: relative;
display: block;
height: 100%;
width: auto;
max-width: 100%;
max-height: 100%;
overflow: auto;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
}
.simplebar-hide-scrollbar {
&::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
position: fixed;
left: 0;
visibility: hidden;
overflow-y: scroll;
scrollbar-width: none;
-ms-overflow-style: none;
}
.simplebar-content {
&:before {
content: ' ';
display: table;
}
&:after {
content: ' ';
display: table;
}
}
.simplebar-placeholder {
max-height: 100%;
max-width: 100%;
width: 100%;
pointer-events: none;
}
.simplebar-height-auto-observer-wrapper {
box-sizing: inherit !important;
height: 100%;
width: 100%;
max-width: 1px;
position: relative;
float: left;
max-height: 1px;
overflow: hidden;
// z-index: -1;
padding: 0;
margin: 0;
pointer-events: none;
flex-grow: inherit;
flex-shrink: 0;
flex-basis: 0;
}
.simplebar-height-auto-observer {
box-sizing: inherit;
display: block;
opacity: 0;
position: absolute;
top: 0;
left: 0;
height: 1000%;
width: 1000%;
min-height: 1px;
min-width: 1px;
overflow: hidden;
pointer-events: none;
// z-index: -1;
}
.simplebar-track {
// z-index: 1;
position: absolute;
right: 0;
bottom: 0;
pointer-events: none;
overflow: hidden;
}
[data-simplebar].simplebar-dragging {
pointer-events: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.simplebar-content {
pointer-events: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.simplebar-track {
pointer-events: all;
}
}
.simplebar-scrollbar {
position: absolute;
left: 0;
right: 0;
min-height: 10px;
&:before {
position: absolute;
content: '';
background: black;
border-radius: 7px;
left: 2px;
right: 2px;
opacity: 0;
transition: opacity 0.2s 0.5s linear;
top: 2px;
bottom: 2px;
}
}
.simplebar-scrollbar.simplebar-visible {
&:before {
opacity: 0.5;
transition-delay: 0s;
transition-duration: 0s;
}
}
.simplebar-track.simplebar-vertical {
top: 0;
width: 11px;
}
.simplebar-track.simplebar-horizontal {
left: 0;
height: 11px;
.simplebar-scrollbar {
right: auto;
left: 0;
top: 0;
bottom: 0;
min-height: 0;
min-width: 10px;
width: auto;
}
}
[data-simplebar-direction='rtl'] {
.simplebar-track.simplebar-vertical {
right: auto;
left: 0;
}
}
.simplebar-dummy-scrollbar-size {
direction: rtl;
position: fixed;
opacity: 0;
visibility: hidden;
height: 500px;
width: 500px;
overflow-y: hidden;
overflow-x: scroll;
-ms-overflow-style: scrollbar !important;
>div {
width: 200%;
height: 200%;
margin: 10px 0;
}
}
.simplebar-hover {
cursor: pointer;
}

View File

@@ -0,0 +1,95 @@
// file: Web/game-snake-poc/frontend/sass/_variables.scss
// version: 1
// Pulse 5.3.8
// Bootswatch
$theme: "pulse" !default;
//
// Color system
//
$white: #fff !default;
$gray-100: #fafafa !default;
$gray-200: #f9f8fc !default;
$gray-300: #ededed !default;
$gray-400: #cbc8d0 !default;
$gray-500: #adb5bd !default;
$gray-600: #868e96 !default;
$gray-700: #444 !default;
$gray-800: #343a40 !default;
$gray-900: #17141f !default;
$black: #000 !default;
$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #593196 !default;
$pink: #e83e8c !default;
$red: #fc3939 !default;
$orange: #fd7e14 !default;
$yellow: #efa31d !default;
$green: #13b955 !default;
$teal: #20c997 !default;
$cyan: #009cdc !default;
$primary: $purple !default;
$secondary: #a991d4 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-200 !default;
$dark: $gray-900 !default;
$min-contrast-ratio: 2.1 !default;
// Options
$enable-rounded: false !default;
// Body
$body-color: $gray-700 !default;
// Links
$link-hover-color: $primary !default;
// Tables
$table-color: initial !default;
$table-border-color: rgba(0, 0, 0, .05) !default;
// Forms
$input-focus-border-color: $primary !default;
// Dropdowns
$dropdown-link-hover-color: $white !default;
$dropdown-link-hover-bg: $primary !default;
// Navs
$nav-tabs-border-color: $gray-300 !default;
$nav-tabs-link-hover-border-color: $primary !default;
// Navbar
$navbar-padding-y: 1.2rem !default;
// Progress bars
$progress-bg: $gray-300 !default;
$progress-bar-bg: $primary !default;
// List group
$list-group-bg: $gray-900 !default;
$list-group-border-color: transparent !default;
$list-group-hover-bg: lighten($list-group-bg, 10%) !default;
$list-group-active-color: $white !default;
$list-group-active-bg: $list-group-bg !default;
$list-group-disabled-color: lighten($list-group-bg, 30%) !default;

View File

@@ -0,0 +1,10 @@
// file: Web/game-snake-poc/frontend/sass/main.scss
// version: 2
@import "bootstrap/scss/functions";
@import "variables";
@import "fontawesome";
@import "simplebar";
@import "bootstrap/scss/bootstrap";
@import "bootswatch";
@import "app";

View File

@@ -0,0 +1,54 @@
// file: Web/game-snake-poc/frontend/ts/assets.ts
// version: 1
export interface SnakeWebAssets {
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 Web 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 Web Snake.");
}
}
export async function loadSnakeWebAssets(): Promise<SnakeWebAssets> {
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,
};
}

View File

@@ -0,0 +1,179 @@
// file: Web/game-snake-poc/frontend/ts/game.ts
// version: 3
import init, { SnakeWasmGame } from "@snake-wasm";
import { webDebug, webInfo } from "./logging";
import { BrowserRuntimeProvenance, type SnakeInputSource } from "./provenance";
const FRAME_MILLIS = 16;
const MAX_FRAME_ELAPSED_MILLIS = 250;
export type SnakeDirection = "left" | "right" | "up" | "down";
export interface SnakeWebSession {
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,
): Promise<SnakeWebSession> {
await init();
webInfo("snake-web-runtime", "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 BrowserRuntimeProvenance(game, provenanceOutput);
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;
}
webDebug("snake-web-runtime", "runtime_paused");
}
function resume(): void {
if (running || disposed) {
return;
}
previous = performance.now();
accumulator = 0;
running = true;
schedule();
webDebug("snake-web-runtime", "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();
},
};
}

View File

@@ -0,0 +1,61 @@
// file: Web/game-snake-poc/frontend/ts/input.ts
// version: 2
import type { SnakeDirection, SnakeWebSession } from "./game";
import { webDebug } from "./logging";
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: SnakeWebSession, 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");
webDebug("snake-web-input", "direction", { direction, source: "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);
webDebug("snake-web-input", "direction", { direction, source });
});
button.addEventListener("click", event => {
if (event.detail !== 0) {
return;
}
session.queueDirection(direction, "keyboard-mouse");
webDebug("snake-web-input", "direction", { direction, source: "keyboard-mouse" });
});
}
}

View File

@@ -0,0 +1,58 @@
// file: Web/game-snake-poc/frontend/ts/lifecycle.ts
// version: 1
import type { SnakeWebSession } from "./game";
import { webDebug, webInfo } from "./logging";
export interface SnakeLifecycleBinding {
dispose(): void;
}
export function bindBrowserLifecycle(session: SnakeWebSession, stage: HTMLElement): SnakeLifecycleBinding {
const resizeObserver = new ResizeObserver(() => {
session.refreshDeviceClass();
session.renderNow();
});
function synchronizeVisibility(): void {
if (document.visibilityState === "hidden") {
session.pause();
webDebug("snake-web-lifecycle", "visibility_hidden");
return;
}
session.resume();
session.renderNow();
webDebug("snake-web-lifecycle", "visibility_visible");
}
function pageHide(event: PageTransitionEvent): void {
if (event.persisted) {
session.pause();
} else {
session.dispose();
}
webInfo("snake-web-lifecycle", "page_hide", { persisted: event.persisted });
}
function pageShow(event: PageTransitionEvent): void {
session.resume();
session.renderNow();
webInfo("snake-web-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();
},
};
}

View File

@@ -0,0 +1,45 @@
// file: Web/game-snake-poc/frontend/ts/logging.ts
// version: 1
export type WebLogLevel = "debug" | "info" | "warn" | "error";
export type WebLogFields = Readonly<Record<string, boolean | number | string | null>>;
type ConsoleMethod = (...items: unknown[]) => void;
function consoleMethod(level: WebLogLevel): ConsoleMethod {
if (level === "debug") {
return console.debug.bind(console);
}
if (level === "info") {
return console.info.bind(console);
}
if (level === "warn") {
return console.warn.bind(console);
}
return console.error.bind(console);
}
function emit(level: WebLogLevel, target: string, action: string, fields: WebLogFields = {}): void {
const event = {
target,
action,
...fields,
};
consoleMethod(level)(`[games.sasedev][${target}] ${action}`, event);
}
export function webDebug(target: string, action: string, fields: WebLogFields = {}): void {
emit("debug", target, action, fields);
}
export function webInfo(target: string, action: string, fields: WebLogFields = {}): void {
emit("info", target, action, fields);
}
export function webWarn(target: string, action: string, fields: WebLogFields = {}): void {
emit("warn", target, action, fields);
}
export function webError(target: string, action: string, fields: WebLogFields = {}): void {
emit("error", target, action, fields);
}

View File

@@ -0,0 +1,66 @@
// file: Web/game-snake-poc/frontend/ts/main.ts
// version: 3
import ResizeObserver from "resize-observer-polyfill";
import "simplebar";
import { loadSnakeWebAssets } from "./assets";
import { startGame } from "./game";
import { bindInputs } from "./input";
import { bindBrowserLifecycle } from "./lifecycle";
import { webError, webInfo } from "./logging";
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;
function requireElement<T extends Element>(selector: string): T {
const element = document.querySelector<T>(selector);
if (element === null) {
throw new Error(`Élément frontend requis absent : ${selector}`);
}
return element;
}
async function main(): Promise<void> {
const canvas = requireElement<HTMLCanvasElement>("#game");
const stage = requireElement<HTMLElement>(".game-stage");
const score = requireElement<HTMLOutputElement>("#score");
const length = requireElement<HTMLOutputElement>("#length");
const provenance = requireElement<HTMLOutputElement>("#runtime-provenance");
const assets = requireElement<HTMLOutputElement>("#asset-status");
const status = requireElement<HTMLSpanElement>("#runtime-status");
const error = requireElement<HTMLParagraphElement>("#startup-error");
const buttons = Array.from(document.querySelectorAll<HTMLButtonElement>("[data-direction]"));
status.textContent = "Chargement assets…";
const assetMetadata = await loadSnakeWebAssets();
assets.value = `${assetMetadata.gameKind} / engine-v${assetMetadata.engineGeneration}`;
webInfo("snake-web-assets", "runtime_assets_loaded", {
engineGeneration: assetMetadata.engineGeneration,
game: assetMetadata.game,
gameKind: assetMetadata.gameKind,
});
status.textContent = "Chargement WASM…";
const session = await startGame(canvas, score, length, provenance);
bindInputs(session, buttons);
bindBrowserLifecycle(session, stage);
status.className = "badge text-bg-success";
status.textContent = "Prêt";
error.hidden = true;
canvas.focus();
webInfo("snake-web-main", "runtime_ready");
}
void main().catch(caughtError => {
const status = document.querySelector<HTMLSpanElement>("#runtime-status");
const error = document.querySelector<HTMLParagraphElement>("#startup-error");
const message = caughtError instanceof Error ? caughtError.stack ?? caughtError.message : String(caughtError);
if (status !== null) {
status.className = "badge text-bg-danger";
status.textContent = "Erreur";
}
if (error !== null) {
error.textContent = `Impossible de démarrer Snake : ${message}`;
error.hidden = false;
}
webError("snake-web-main", "runtime_start_failed", { message });
});

View File

@@ -0,0 +1,98 @@
// file: Web/game-snake-poc/frontend/ts/provenance.ts
// version: 1
import type { SnakeWasmGame } from "@snake-wasm";
import { webInfo } 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 BrowserRuntimeProvenance {
private keyboardMouseObserved = false;
private touchObserved = false;
private deviceClass: DeviceClass = detectedDeviceClass();
public constructor(
private readonly game: SnakeWasmGame,
private readonly output: HTMLOutputElement,
) {
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.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);
webInfo("snake-web-provenance", "runtime_provenance", {
deviceClass: this.game.provenance_device_class(),
executionModel: this.game.provenance_execution_model(),
inputProfile: this.game.provenance_input_profile(),
platformFamily: this.game.provenance_platform_family(),
runtimeHost: this.game.provenance_runtime_host(),
});
}
}

View File

@@ -0,0 +1,25 @@
{
"name": "game-snake-poc-web",
"private": true,
"version": "0.3.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^7.3",
"bootstrap": "^5.3",
"resize-observer-polyfill": "^1.5",
"simplebar": "^6.3"
},
"devDependencies": {
"@types/bootstrap": "^5.2",
"@types/node": "^26.1",
"sass-embedded": "^1.102",
"typescript": "^7.0",
"vite": "^8.2",
"vite-plugin-static-copy": "^4.1"
}
}

View 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-web/wasm/game_snake_poc_wasm.d.ts"
]
}
},
"include": [
"frontend",
"vite.config.ts"
]
}

View File

@@ -0,0 +1,96 @@
// file: Web/game-snake-poc/vite.config.ts
// version: 3
import { NodePackageImporter } from "sass-embedded";
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-web"));
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"));
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 (["eot", "otf", "ttf", "woff", "woff2"].includes(extension)) {
return "fonts/[name]-[hash][extname]";
}
if (["png", "jpg", "jpeg", "gif", "svg", "webp", "ico"].includes(extension)) {
return "imgs/[name][extname]";
}
if (extension === "wasm") {
return "wasm/[name]-[hash][extname]";
}
return "otherassets/[name][extname]";
},
},
},
},
css: {
preprocessorOptions: {
scss: {
quietDeps: true,
silenceDeprecations: ["import", "color-functions", "global-builtin"],
verbose: false,
importers: [new NodePackageImporter()],
},
},
},
server: {
host: "127.0.0.1",
port: 1434,
strictPort: true,
fs: {
allow: [appRoot, repositoryRoot, externalBuildRoot],
},
},
preview: {
host: "127.0.0.1",
port: 4174,
strictPort: true,
},
});

View File

@@ -1,7 +1,6 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Reflex POC Tauri",
"version": "0.1.0",
"identifier": "com.sasedev.games.reflex.tauri",
"build": {
"beforeDevCommand": {
@@ -31,6 +30,8 @@
},
"bundle": {
"active": false,
"icon": ["icons/icon.png"]
"icon": [
"icons/icon.png"
]
}
}

View File

@@ -0,0 +1,23 @@
# file: crates/apps/game-snake-poc-wasm/Cargo.toml
# version: 2
[package]
name = "game-snake-poc-wasm"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
authors.workspace = true
publish.workspace = true
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
engine-v1-common = { path = "../../engines/engine-v1-common" }
engine-v1-platform-api = { path = "../../engines/engine-v1-platform-api" }
game-snake-poc = { path = "../../games/game-snake-poc" }
wasm-bindgen.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,13 @@
// file: crates/apps/game-snake-poc-wasm/src/lib.rs
// version: 1
//! WebAssembly adapter facade for the Snake POC.
#![forbid(unsafe_code)]
#![deny(unreachable_pub)]
#![warn(missing_docs)]
mod runtime;
/// Re-export of the Snake WebAssembly runtime adapter.
pub use self::runtime::SnakeWasmGame;

View File

@@ -0,0 +1,304 @@
// file: crates/apps/game-snake-poc-wasm/src/runtime.rs
// version: 2
const FIXED_STEP_MILLIS: u64 = 16;
/// WebAssembly-owned Snake game state consumed by the direct browser host.
#[wasm_bindgen::prelude::wasm_bindgen]
pub struct SnakeWasmGame {
pending_input: engine_v1_common::InputState,
provenance: engine_v1_platform_api::RuntimeProvenance,
runner: engine_v1_common::FixedStepRunner,
state: game_snake_poc::SnakeState,
}
#[wasm_bindgen::prelude::wasm_bindgen]
impl SnakeWasmGame {
/// Creates a fresh Snake POC session using the shared gameplay crate.
#[wasm_bindgen::prelude::wasm_bindgen(constructor)]
pub fn new() -> Self {
return Self {
pending_input: engine_v1_common::InputState::none(),
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::Web,
engine_v1_platform_api::RuntimeHost::Browser,
),
runner: engine_v1_common::FixedStepRunner::new(std::time::Duration::from_millis(FIXED_STEP_MILLIS)),
state: game_snake_poc::SnakeState::new(),
};
}
/// 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 {
let device_class = match parse_device_class(device_class) {
Some(value) => value,
None => return false,
};
let input_profile = match parse_input_profile(input_profile) {
Some(value) => value,
None => return false,
};
self.provenance = engine_v1_platform_api::RuntimeProvenance::new(
device_class,
engine_v1_platform_api::ExecutionModel::Wasm,
input_profile,
engine_v1_platform_api::PlatformFamily::Web,
engine_v1_platform_api::RuntimeHost::Browser,
);
return true;
}
/// Returns the current physical device class label.
pub fn provenance_device_class(&self) -> String {
return device_class_label(self.provenance.device_class()).to_string();
}
/// Returns the current execution model label.
pub fn provenance_execution_model(&self) -> String {
return execution_model_label(self.provenance.execution_model()).to_string();
}
/// Returns the current primary input profile label.
pub fn provenance_input_profile(&self) -> String {
return input_profile_label(self.provenance.input_profile()).to_string();
}
/// Returns the current platform family label.
pub fn provenance_platform_family(&self) -> String {
return platform_family_label(self.provenance.platform_family()).to_string();
}
/// Returns the current runtime host label.
pub fn provenance_runtime_host(&self) -> String {
return runtime_host_label(self.provenance.runtime_host()).to_string();
}
/// Queues a logical left direction for the next deterministic update.
pub fn left(&mut self) {
self.queue_direction(engine_v1_common::GameAction::Left);
return;
}
/// Queues a logical right direction for the next deterministic update.
pub fn right(&mut self) {
self.queue_direction(engine_v1_common::GameAction::Right);
return;
}
/// Queues a logical upward direction for the next deterministic update.
pub fn up(&mut self) {
self.queue_direction(engine_v1_common::GameAction::Up);
return;
}
/// Queues a logical downward direction for the next deterministic update.
pub fn down(&mut self) {
self.queue_direction(engine_v1_common::GameAction::Down);
return;
}
/// Advances one deterministic update and consumes the queued direction.
pub fn tick(&mut self) {
let input = self.pending_input;
self.pending_input = engine_v1_common::InputState::none();
self.runner.tick(&mut self.state, input);
return;
}
/// Returns the current gameplay score.
pub fn score(&self) -> u32 {
return self.state.score().min(u32::MAX as u64) as u32;
}
/// Returns the current Snake length.
pub fn length(&self) -> u32 {
return self.state.length().min(u32::MAX as usize) as u32;
}
/// Returns the current scene background red channel.
pub fn background_red(&self) -> u8 {
return self.scene().background().red();
}
/// Returns the current scene background green channel.
pub fn background_green(&self) -> u8 {
return self.scene().background().green();
}
/// Returns the current scene background blue channel.
pub fn background_blue(&self) -> u8 {
return self.scene().background().blue();
}
/// Returns the number of occupied rectangle slots in the current scene.
pub fn rectangle_count(&self) -> u32 {
let scene = self.scene();
let mut count = 0_u32;
for slot in scene.rectangles() {
if slot.is_some() {
count = count.saturating_add(1);
}
}
return count;
}
/// Returns one rectangle's normalized left coordinate or `-1.0` if absent.
pub fn rectangle_x(&self, index: u32) -> f32 {
return match self.rectangle(index) {
Some(rectangle) => rectangle.rect().x(),
None => -1.0,
};
}
/// Returns one rectangle's normalized top coordinate or `-1.0` if absent.
pub fn rectangle_y(&self, index: u32) -> f32 {
return match self.rectangle(index) {
Some(rectangle) => rectangle.rect().y(),
None => -1.0,
};
}
/// Returns one rectangle's normalized width or `0.0` if absent.
pub fn rectangle_width(&self, index: u32) -> f32 {
return match self.rectangle(index) {
Some(rectangle) => rectangle.rect().width(),
None => 0.0,
};
}
/// Returns one rectangle's normalized height or `0.0` if absent.
pub fn rectangle_height(&self, index: u32) -> f32 {
return match self.rectangle(index) {
Some(rectangle) => rectangle.rect().height(),
None => 0.0,
};
}
/// Returns one rectangle's red channel or zero if absent.
pub fn rectangle_red(&self, index: u32) -> u8 {
return match self.rectangle(index) {
Some(rectangle) => rectangle.color().red(),
None => 0,
};
}
/// Returns one rectangle's green channel or zero if absent.
pub fn rectangle_green(&self, index: u32) -> u8 {
return match self.rectangle(index) {
Some(rectangle) => rectangle.color().green(),
None => 0,
};
}
/// Returns one rectangle's blue channel or zero if absent.
pub fn rectangle_blue(&self, index: u32) -> u8 {
return match self.rectangle(index) {
Some(rectangle) => rectangle.color().blue(),
None => 0,
};
}
}
impl Default for SnakeWasmGame {
fn default() -> Self {
return Self::new();
}
}
impl SnakeWasmGame {
fn queue_direction(&mut self, action: engine_v1_common::GameAction) {
self.pending_input = engine_v1_common::InputState::none().with_action(action, true);
return;
}
fn scene(&self) -> engine_v1_common::EngineScene {
return engine_v1_common::EngineGame::scene(&self.state);
}
fn rectangle(&self, requested_index: u32) -> Option<engine_v1_common::RenderRect> {
let scene = self.scene();
let mut occupied_index = 0_u32;
for slot in scene.rectangles() {
match slot {
Some(rectangle) => {
if occupied_index == requested_index {
return Some(*rectangle);
}
occupied_index = occupied_index.saturating_add(1);
},
None => {},
}
}
return None;
}
}
fn parse_device_class(label: &str) -> Option<engine_v1_platform_api::DeviceClass> {
return match label {
"desktop" => Some(engine_v1_platform_api::DeviceClass::Desktop),
"phone" => Some(engine_v1_platform_api::DeviceClass::Phone),
"tablet" => Some(engine_v1_platform_api::DeviceClass::Tablet),
"unknown" => Some(engine_v1_platform_api::DeviceClass::Unknown),
_ => None,
};
}
fn parse_input_profile(label: &str) -> Option<engine_v1_platform_api::InputProfile> {
return match label {
"gamepad" => Some(engine_v1_platform_api::InputProfile::Gamepad),
"keyboard-mouse" => Some(engine_v1_platform_api::InputProfile::KeyboardMouse),
"mixed" => Some(engine_v1_platform_api::InputProfile::Mixed),
"touch" => Some(engine_v1_platform_api::InputProfile::Touch),
"unknown" => Some(engine_v1_platform_api::InputProfile::Unknown),
_ => None,
};
}
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",
};
}
#[cfg(test)]
#[path = "../unit_tests/runtime.rs"]
mod tests;

View File

@@ -0,0 +1,52 @@
// file: crates/apps/game-snake-poc-wasm/unit_tests/runtime.rs
// version: 2
#[test]
fn direction_is_queued_without_advancing_simulation() {
let mut game = crate::SnakeWasmGame::new();
let before_x = game.rectangle_x(1);
let before_y = game.rectangle_y(1);
game.up();
assert_eq!(game.rectangle_x(1), before_x);
assert_eq!(game.rectangle_y(1), before_y);
game.tick();
assert_eq!(game.rectangle_x(1), before_x);
assert!(game.rectangle_y(1) < before_y);
}
#[test]
fn scene_and_status_are_exposed_for_canvas_host() {
let game = crate::SnakeWasmGame::new();
assert_eq!(game.score(), 0);
assert_eq!(game.length(), 3);
assert_eq!(game.rectangle_count(), 4);
assert!(game.rectangle_width(0) > 0.0);
assert!(game.rectangle_height(0) > 0.0);
assert_eq!(game.rectangle_x(99), -1.0);
assert_eq!(game.rectangle_y(99), -1.0);
}
#[test]
fn browser_runtime_provenance_preserves_static_and_observed_dimensions() {
let mut game = crate::SnakeWasmGame::new();
assert_eq!(game.provenance_platform_family(), "web");
assert_eq!(game.provenance_execution_model(), "wasm");
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_eq!(game.provenance_device_class(), "phone");
assert_eq!(game.provenance_input_profile(), "touch");
assert_eq!(game.provenance_platform_family(), "web");
assert_eq!(game.provenance_execution_model(), "wasm");
assert_eq!(game.provenance_runtime_host(), "browser");
}
#[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_eq!(game.provenance_device_class(), "desktop");
assert_eq!(game.provenance_input_profile(), "keyboard-mouse");
}

View File

@@ -1,5 +1,5 @@
# file: crates/games/game-reflex-poc/Cargo.toml
# version: 3
# version: 4
[package]
name = "game-reflex-poc"
@@ -12,7 +12,6 @@ publish.workspace = true
[dependencies]
engine-v1-common = { path = "../../engines/engine-v1-common" }
engine-v1-platform-api = { path = "../../engines/engine-v1-platform-api" }
[dev-dependencies]
game-logging-lib = { path = "../../common/game-logging-lib" }

View File

@@ -1,5 +1,5 @@
# file: crates/games/game-snake-poc/Cargo.toml
# version: 3
# version: 4
[package]
name = "game-snake-poc"
@@ -12,7 +12,6 @@ publish.workspace = true
[dependencies]
engine-v1-common = { path = "../../engines/engine-v1-common" }
engine-v1-platform-api = { path = "../../engines/engine-v1-platform-api" }
[dev-dependencies]
game-logging-lib = { path = "../../common/game-logging-lib" }

View File

@@ -0,0 +1,3 @@
docs/ideas/README.md
docs/studies/README.md
history/README.md

View File

@@ -0,0 +1,121 @@
<!-- file: deltas/0.2.0/0-pre.1.fix.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.1.fix.1
## Base
Base déclarée : `0.2.0-0-pre.1`.
La prerelease précédente reste une candidate documentaire non validée. Ce fix corrige et complète les règles de gouvernance avant toute progression vers `0-pre.2`.
## Documentation et nomenclature
- adoption de `000-README.md` comme point d'entrée des répertoires documentaires multi-fichiers ;
- renommage de `docs/ideas/README.md`, `docs/studies/README.md` et `history/README.md` ;
- généralisation des marqueurs `( )`, `(x)`, `(d)`, `(c)` à toute liste durable de tâches ou d'état, pas seulement au ROADMAP ;
- conservation des listes descriptives simples sans marqueur artificiel.
## Plateformes
La conception réserve désormais explicitement :
- Desktop : Linux, Windows, macOS ;
- Mobile : Android, iOS ;
- Web : navigateur/WASM.
Téléphone et tablette restent des classes de device séparées de l'OS et du backend technique. SDL3 reste le backend natif de référence du POC sans devenir l'identité architecturale d'une plateforme.
## Tauri et versions
- `tauri.conf.json` n'embarque plus de version produit et laisse Tauri utiliser la version Cargo ;
- `package.json` n'est plus synchronisé à chaque `pre.N` / `.fix.N` et revient à la dernière version frontend significative `0.1.0` pendant cette phase documentaire ;
- Cargo reste la source canonique de version produit.
## Workflow RC et prompt suivant
- une RC est fonctionnellement gelée ;
- les bugfixes, corrections de tests, packaging, sécurité et défauts de release peuvent modifier du code sans retour automatique en beta ;
- une réouverture fonctionnelle de la RC nécessite de revenir à une phase de développement adaptée, normalement beta ;
- le prompt de la version suivante devient recommandé après validation de la première RC réellement gelée, puis peut être affiné jusqu'à la stable.
## Planification des versions de code
Le cycle conceptuel est :
```text
PLAN → IMPLEMENT → INTEGRATE → VALIDATE → CANDIDATE → RELEASE
```
Ces phases n'imposent pas une prerelease chacune. Une petite version peut combiner PLAN et première implémentation dans `pre.1`; une version lourde peut réserver `pre.1` à la décomposition.
## Matrice de validation
Ajout de `docs/rules/RULES_VALIDATION_MATRIX.md` avec :
- identifiants stables `CMD-*` ;
- dépendances entre commandes ;
- portée ciblée par crate ;
- propagation vers les consommateurs impactés ;
- gates Desktop, Tauri et Android ;
- règles beta/RC ;
- commandes de maintenance disque.
## Politique Cargo clean
Le besoin de contrôle disque est reconnu explicitement.
`cargo clean` complet peut être planifié périodiquement à un jalon de cycle afin d'éviter l'accumulation de dizaines ou centaines de Go sous `../builds/sasedev-games/target`.
Entre deux cleans complets, utiliser si pertinent :
```bash
cargo clean -p <package>
cargo clean --release
cargo clean --profile <profile>
cargo clean --target <triple>
cargo clean --dry-run --verbose
```
Il n'existe pas de contrat projet consistant à conserver automatiquement « uniquement la dernière génération utile » des artefacts Cargo : les nettoyages ciblés ou complets sont donc des opérations explicites.
## Suppressions nécessaires
Un overlay ZIP ne supprime pas les anciens fichiers. Après extraction du delta, appliquer :
```bash
while IFS= read -r path; do
rm -rf -- "$path"
done < deltas/0.2.0/0-pre.1.fix.1.delete.txt
```
## Validation automatique
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
La suppression de `version` dans `tauri.conf.json` modifie une configuration de build. Une vérification Tauri est donc recommandée avant validation définitive du fix :
```bash
(cd crates/apps/game-reflex-poc-tauri && cargo tauri build)
```
Aucun smoke gameplay supplémentaire n'est requis si le build Tauri est propre, car le gameplay et le runtime ne sont pas modifiés.
## Validation humaine
Relire prioritairement :
- `docs/rules/RULES_DOCUMENTATION.md` ;
- `docs/rules/RULES_COMMANDS.md` ;
- `docs/rules/RULES_VALIDATION_MATRIX.md` ;
- `docs/rules/VERSION_WORKFLOW.md` ;
- `docs/rules/FILE_CONTRACTS.md` ;
- `docs/architecture/003-SDL3_PLATFORM_ABSTRACTION.md` ;
- `docs/rules/RULES_PROJECT.md` ;
- `prompts/001-V0_2_0_START_PROMPT.md`.
Ce fix ne valide toujours pas le catalogue fonctionnel `0.2.0` : la progression vers `0-pre.2` dépend de la revue humaine de cette gouvernance.

View File

@@ -0,0 +1,63 @@
<!-- file: deltas/0.2.0/0-pre.1.fix.2.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.1.fix.2
## Base
Base déclarée : `0.2.0-0-pre.1.fix.1`.
## Objet
Ce fix formalise l'immuabilité des deltas, le contrat des manifests de suppression et l'incrément obligatoire des versions d'en-tête.
Les deltas déjà livrés ne sont pas modifiés.
## Deltas immuables
- un fichier `deltas/**/*.md` livré est immuable sur le fond ;
- seules les corrections non sémantiques de forme peuvent toucher le fichier existant ;
- toute correction de forme autorisée incrémente son en-tête `version` ;
- toute correction sémantique ou tout ajout produit un nouveau delta ou `.fix.N`.
## Manifests `*.delete.txt`
Les manifests de suppression sont désormais un contrat documenté :
- un chemin relatif à la racine par ligne ;
- aucune commande shell dans le manifest ;
- le delta Markdown associé décrit la raison de chaque groupe de suppressions ;
- le delta Markdown associé fournit la procédure d'application ;
- toute modification sémantique des suppressions passe par un nouveau delta/fix.
## Versions d'en-tête
Toute modification réelle d'un fichier versionné incrémente son en-tête `version`.
Les seuls changements qui n'imposent pas cet incrément sont les transformations purement mécaniques réalisées par un formatter officiel, sans autre modification réelle.
Un renommage qui modifie l'en-tête `file:` compte comme une modification réelle.
## Fichiers modifiés par ce fix
- `Cargo.toml` ;
- `Android/game-reflex-poc/build.gradle` ;
- `Android/game-snake-poc/build.gradle` ;
- `README.md` ;
- `docs/rules/RULES_DOCUMENTATION.md` ;
- `docs/rules/FILE_CONTRACTS.md` ;
- `docs/rules/VERSION_WORKFLOW.md` ;
- `docs/rules/RULES_PROJECT.md` ;
- `docs/rules/RULES_VALIDATION_MATRIX.md`.
Tous les fichiers ci-dessus qui possèdent un en-tête de version ont été incrémentés.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucun code Rust, Java ou TypeScript n'est modifié dans ce fix.

65
deltas/0.2.0/0-pre.1.md Normal file
View File

@@ -0,0 +1,65 @@
<!-- file: deltas/0.2.0/0-pre.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.1
## Base
Base déclarée : `0.1.0`.
## Objet
Première prerelease documentaire de `0.2.0`.
Cette tranche ne fige pas encore le catalogue complet des capabilities ni l'architecture cible du framework. Elle fixe d'abord la méthode de conception et de documentation qui sera utilisée pour les prereleases suivantes.
## Contenu
- passage de la version workspace et des métadonnées produit à `0.2.0-0-pre.1` ;
- correction de la version courante affichée dans `README.md` ;
- renforcement de `RULES_DOCUMENTATION.md` ;
- création des contrats `docs/ideas/` et `docs/studies/` ;
- adoption des marqueurs ROADMAP `( )`, `(x)`, `(d)`, `(c)` ;
- définition des reports et annulations partiels avec conservation de l'historique de planning ;
- migration du ROADMAP existant vers la nouvelle convention ;
- limitation du CHANGELOG aux jalons RC et stables ;
- migration ponctuelle du CHANGELOG `0.1.0`, les détails retirés restant dans `deltas/` et `history/` ;
- définition de la maturation des idées et capabilities ;
- formalisation de la validation humaine des versions documentaires ;
- réécriture du prompt `0.2.0` pour imposer une conception progressive par prereleases.
## Hors scope
Cette prerelease ne doit pas encore :
- produire le catalogue exhaustif des capabilities ;
- figer la matrice complète des plateformes ;
- figer l'architecture future des crates ;
- planifier définitivement les versions d'implémentation ;
- créer de nouvelles crates de capability ;
- modifier le gameplay ou les runtimes existants.
## Validation automatique
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke test n'est requise pour accepter le fond de cette prerelease : elle ne modifie aucun source Rust, Java, TypeScript ou contrat runtime. La cohérence de version des manifests doit toutefois être relue.
## Validation humaine
La prerelease n'est considérée validée qu'après revue explicite des documents, notamment :
- `docs/rules/RULES_DOCUMENTATION.md` ;
- `docs/rules/FILE_CONTRACTS.md` ;
- `docs/rules/VERSION_WORKFLOW.md` ;
- `ROADMAP.md` ;
- `CHANGELOG.md` ;
- `docs/ideas/000-README.md` ;
- `docs/studies/000-README.md` ;
- `prompts/001-V0_2_0_START_PROMPT.md`.
Les omissions, ambiguïtés ou règles contestées doivent être corrigées dans `0.2.0-0-pre.1.fix.N` si elles invalident cette candidate, ou traitées dans `0-pre.2` lorsqu'elles constituent la suite normale de conception.

View File

@@ -0,0 +1,80 @@
<!-- file: deltas/0.2.0/0-pre.2.fix.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.2.fix.1
## Base
Base déclarée : `0.2.0-0-pre.2`.
Le delta `0-pre.2.md` reste immuable.
## Objet
Corriger la présentation normative du tableau de plateformes et compléter l'étude des capacités serveur nécessaires au multijoueur temps réel.
## Tableau plateforme
`docs/studies/003-PLATFORM_CAPABILITY_STUDY.md` utilise désormais des marqueurs d'alignement Markdown explicites.
La convention documentaire est précisée :
- colonne textuelle : `:---` ;
- colonne numérique : `---:` ;
- valeur courte réellement destinée à être centrée : `:---:`.
Le tableau actuel de plateformes ne contenant que des valeurs textuelles, toutes ses colonnes sont alignées explicitement à gauche.
## Realtime multiplayer
L'inventaire serveur est complété afin de distinguer :
- API/Web non temps réel ;
- lobby/matchmaking/session control ;
- realtime data plane ;
- synchronisation client ;
- chat/presence.
Une étude dédiée couvre notamment :
- WebSocket/gateway ;
- tick serveur ;
- ingestion et sequencing des inputs ;
- état authoritative ;
- snapshots et deltas ;
- revisions/acks ;
- interpolation/prediction/reconciliation ;
- rollback lorsque nécessaire ;
- reconnect/resync ;
- rooms et session routing ;
- interest management ;
- backpressure ;
- persistence hors boucle temps réel ;
- observability ;
- scaling.
## Fichiers modifiés
- `Cargo.toml` ;
- `Android/game-reflex-poc/build.gradle` ;
- `Android/game-snake-poc/build.gradle` ;
- `README.md` ;
- `docs/rules/RULES_DOCUMENTATION.md` ;
- `docs/studies/000-README.md` ;
- `docs/studies/001-FUNCTIONAL_CAPABILITY_INVENTORY.md` ;
- `docs/studies/003-PLATFORM_CAPABILITY_STUDY.md` ;
- `docs/studies/004-GAME_ARCHETYPE_PRESSURE_TEST.md` ;
- `docs/studies/005-DEPENDENCY_AND_COMPOSITION_STUDY.md` ;
- `docs/studies/006-REALTIME_MULTIPLAYER_SERVER_STUDY.md`.
Tous les fichiers existants modifiés et possédant un en-tête `version` ont été incrémentés.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo/Gradle/smoke supplémentaire n'est requise : aucun code runtime ou configuration de build n'est modifié hors métadonnées de version.

View File

@@ -0,0 +1,43 @@
<!-- file: deltas/0.2.0/0-pre.2.fix.2.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.2.fix.2
## Base
Base déclarée : `0.2.0-0-pre.2.fix.1`.
Le delta `0-pre.2.fix.1.md` reste immuable.
## Objet
Correction strictement documentaire des erreurs détectées par `scripts/audit_markdown_tables.py`.
## Corrections
- alignement vertical complet du tableau de `docs/studies/003-PLATFORM_CAPABILITY_STUDY.md` ;
- conservation de l'alignement Markdown sémantique à gauche pour les colonnes textuelles ;
- suppression d'une double ligne vide interdite dans `docs/studies/005-DEPENDENCY_AND_COMPOSITION_STUDY.md`.
Aucun contenu fonctionnel ou architectural n'est ajouté ou modifié.
## Fichiers modifiés
- `Cargo.toml` ;
- `Android/game-reflex-poc/build.gradle` ;
- `Android/game-snake-poc/build.gradle` ;
- `README.md` ;
- `docs/studies/003-PLATFORM_CAPABILITY_STUDY.md` ;
- `docs/studies/005-DEPENDENCY_AND_COMPOSITION_STUDY.md`.
Les fichiers existants modifiés et possédant un en-tête `version` ont été incrémentés.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke n'est requise : ce fix ne touche ni code runtime ni configuration de build, hors métadonnées de version.

View File

@@ -0,0 +1,53 @@
<!-- file: deltas/0.2.0/0-pre.2.fix.3.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.2.fix.3
## Base
Base déclarée : `0.2.0-0-pre.2.fix.2`.
Les deltas précédents restent immuables.
## Objet
Corriger le format du tableau de plateformes selon la convention exacte déjà contrôlée par `scripts/audit_markdown_tables.py`, héritée des outils KSP.
## Convention corrigée
La convention est désormais documentée ainsi :
- toutes les lignes de contenu ont une largeur brute identique par colonne ;
- les cellules de contenu utilisent les espaces de padding nécessaires ;
- la cellule de la ligne séparatrice ne contient aucun espace ;
- elle est composée de tirets sur exactement toute la largeur brute de la colonne ;
- les marqueurs `:` éventuels remplacent des tirets et ne changent jamais cette largeur.
Exemple :
```markdown
| Colonne A | Colonne B |
|-----------|----------------|
| valeur | autre valeur |
```
## Fichiers modifiés
- `Cargo.toml` ;
- `Android/game-reflex-poc/build.gradle` ;
- `Android/game-snake-poc/build.gradle` ;
- `README.md` ;
- `docs/rules/RULES_DOCUMENTATION.md` ;
- `docs/studies/003-PLATFORM_CAPABILITY_STUDY.md`.
Tous les fichiers existants modifiés et possédant un en-tête `version` ont été incrémentés.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucun contenu fonctionnel n'est ajouté dans ce fix.

65
deltas/0.2.0/0-pre.2.md Normal file
View File

@@ -0,0 +1,65 @@
<!-- file: deltas/0.2.0/0-pre.2.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.2
## Base
Base déclarée : `0.2.0-0-pre.1.fix.2`.
## Objet
Étudier les fonctionnalités plausibles déjà justifiées et leur ownership architectural sans encore planifier les POC techniques ni le premier projet réel.
## Contenu
- enregistrement du jalon `0-pre.1.fix.2` validé dans `history/` ;
- inventaire fonctionnel initial ;
- distinction kernel / technical capability / game-system / platform adapter / provider / server service / tooling / game-specific ;
- étude des axes OS, device, execution model, host et backend ;
- pressure test par plusieurs archétypes de jeux ;
- étude des dépendances et de la composition statique ;
- conservation de macOS/iOS comme plateformes réservées ;
- absence volontaire de création de nouvelles crates.
## Hors scope
Cette prerelease ne :
- fige pas encore l'architecture normative ;
- ne crée pas le manifest produit définitif ;
- ne planifie pas encore le POC Tauri Android ;
- ne planifie pas le premier jeu réel ;
- n'implémente aucune capability ;
- ne crée aucune nouvelle crate runtime.
## Validation automatique
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo/Gradle/smoke n'est requise par le contenu fonctionnel de cette tranche : aucun code runtime ou build n'est modifié.
## Validation humaine
Relire en priorité :
- `docs/studies/001-FUNCTIONAL_CAPABILITY_INVENTORY.md` ;
- `docs/studies/002-LAYERING_AND_OWNERSHIP_STUDY.md` ;
- `docs/studies/003-PLATFORM_CAPABILITY_STUDY.md` ;
- `docs/studies/004-GAME_ARCHETYPE_PRESSURE_TEST.md` ;
- `docs/studies/005-DEPENDENCY_AND_COMPOSITION_STUDY.md`.
La revue doit notamment signaler :
- fonctionnalités manquantes ;
- fonctionnalités sur-réservées ;
- mauvais ownership ;
- dépendances trop fortes ;
- confusion entre capability et game-system ;
- limites plateforme oubliées.
Les décisions retenues seront seulement ensuite promues vers `docs/architecture/`.

View File

@@ -0,0 +1,39 @@
<!-- file: deltas/0.2.0/0-pre.3.fix.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.3.fix.1
## Base
Base déclarée : `0.2.0-0-pre.3`.
Le delta `0-pre.3.md` reste immuable.
## Objet
Correction strictement documentaire d'une double ligne vide interdite par `scripts/audit_markdown_tables.py`.
## Correction
- suppression de la double ligne vide dans `docs/studies/005-DEPENDENCY_AND_COMPOSITION_STUDY.md` ;
- aucun ajout fonctionnel ou architectural.
## Fichiers modifiés
- `Cargo.toml` ;
- `Android/game-reflex-poc/build.gradle` ;
- `Android/game-snake-poc/build.gradle` ;
- `README.md` ;
- `docs/studies/005-DEPENDENCY_AND_COMPOSITION_STUDY.md`.
Tous les fichiers existants modifiés et possédant un en-tête `version` ont été incrémentés.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke n'est requise.

66
deltas/0.2.0/0-pre.3.md Normal file
View File

@@ -0,0 +1,66 @@
<!-- file: deltas/0.2.0/0-pre.3.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.3
## Base
Base déclarée : `0.2.0-0-pre.2.fix.3`.
## Objet
Compléter l'étude fonctionnelle validée en `0-pre.2.fix.3` avec deux axes manquants : adversaires pilotés/bots et architecture Web/identité/hébergement multi-jeux.
## Bot / pseudo-IA
L'étude couvre :
- logique simple ;
- recherche/pathfinding ;
- modèles entraînés éventuels ;
- bot local ;
- bot serveur ;
- difficulté ;
- remplacement de joueur ;
- bots de tests/charge ;
- réutilisation des semantic actions ;
- séparation entre moteur d'exécution et stratégie propre au jeu.
Aucune dépendance ML n'est réservée comme obligatoire.
## Web / identité / hébergement
L'étude couvre :
- identité canonique `PlayerId` ;
- anonymous account ;
- credentials propres ;
- OAuth/OIDC ;
- Google/Apple ;
- Play Games/Game Center/Steam comme identities liées ;
- account linking/merge ;
- sessions/tokens ;
- portail initial `games.sasedev.com` ;
- pages/jeux sous portail commun ;
- migration future d'un jeu vers son propre domaine ;
- services logiques `www/auth/api/cdn/leaderboard/realtime/admin` ;
- services spécifiques par jeu ;
- multi-tenant logique ;
- modular monolith initial puis séparation motivée par besoin réel ;
- CORS/origins/OAuth redirects lors de la multiplication des domaines.
## Fichiers nouveaux
- `docs/studies/007-GAME_AI_AND_BOT_EXECUTION_STUDY.md` ;
- `docs/studies/008-WEB_IDENTITY_AND_GAME_HOSTING_STUDY.md` ;
- `history/0.2.0/0-pre.2.fix.3.md`.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo/Gradle/smoke n'est requise : aucune implémentation runtime ou configuration de build n'est modifiée.

View File

@@ -0,0 +1,66 @@
<!-- file: deltas/0.2.0/0-pre.4.fix.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.4.fix.1
## Base
Base déclarée : `0.2.0-0-pre.4`.
Le delta `0-pre.4.md` reste immuable.
## Objet
Recentrer tous les POC plateforme étudiés sur Snake comme jeu-sonde unique.
Le prochain jeu réel pressenti étant un super Snake, cette correction permet aux POC de plateforme de préparer directement ses besoins plutôt que de répartir l'effort entre Reflex et Snake.
## Décision d'étude
Les nouveaux POC plateforme utilisent Snake :
- Tauri Android + Snake ;
- Web navigateur direct + Snake ;
- Tauri Desktop + Snake ;
- builder Android multi-ABI centré sur Snake ;
- futurs POC Windows/macOS/iOS SDL avec Snake lorsque les environnements sont disponibles.
Reflex reste une référence technique historique pour les briques Tauri/WASM déjà construites, mais n'est plus le jeu principal des futurs POC plateforme.
## Raisons
Snake exerce davantage de besoins utiles pour le futur jeu réel :
- input continu ;
- clavier/swipe/touch ;
- grille ;
- plusieurs entités ;
- collision/obstacles ;
- état de jeu plus long ;
- resize/orientation ;
- virtual controls éventuels ;
- future extension multi-snake et multiplayer.
## Fichiers modifiés
- `Cargo.toml` ;
- `Android/game-reflex-poc/build.gradle` ;
- `Android/game-snake-poc/build.gradle` ;
- `README.md` ;
- `docs/studies/000-README.md` ;
- `docs/studies/009-PLATFORM_POC_CANDIDATES.md` ;
- `docs/studies/010-PLATFORM_POC_REUSE_AND_DELTA.md` ;
- `docs/studies/011-PLATFORM_POC_VALIDATION_MATRIX.md` ;
- `docs/studies/012-PLATFORM_POC_SEQUENCE.md`.
Tous les fichiers existants modifiés et possédant un en-tête `version` ont été incrémentés.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune implémentation runtime n'est ajoutée.

View File

@@ -0,0 +1,45 @@
<!-- file: deltas/0.2.0/0-pre.4.fix.2.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.4.fix.2
## Base
Base déclarée : `0.2.0-0-pre.4.fix.1`.
Le delta `0-pre.4.fix.1.md` reste immuable.
## Objet
Correction strictement documentaire de l'alignement du tableau de `docs/studies/011-PLATFORM_POC_VALIDATION_MATRIX.md`.
## Correction
Le tableau est reconstruit selon la convention contrôlée par `scripts/audit_markdown_tables.py` :
- largeur brute constante pour chaque colonne ;
- padding des lignes de contenu ;
- ligne séparatrice sans espaces ;
- nombre de tirets exactement égal à la largeur brute de chaque colonne.
Aucun contenu fonctionnel ou architectural n'est modifié.
## Fichiers modifiés
- `Cargo.toml` ;
- `Android/game-reflex-poc/build.gradle` ;
- `Android/game-snake-poc/build.gradle` ;
- `README.md` ;
- `docs/studies/011-PLATFORM_POC_VALIDATION_MATRIX.md`.
Tous les fichiers existants modifiés et possédant un en-tête `version` ont été incrémentés.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke n'est requise.

55
deltas/0.2.0/0-pre.4.md Normal file
View File

@@ -0,0 +1,55 @@
<!-- file: deltas/0.2.0/0-pre.4.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.4
## Base
Base déclarée : `0.2.0-0-pre.3.fix.1`.
## Objet
Définir les POC plateforme utiles avant toute implémentation de la série suivante.
## Études ajoutées
- candidats POC plateforme ;
- réutilisation du code existant ;
- matrice commune de validation ;
- séquence proposée pour une future série `0.3.x`.
## POC prioritaires étudiés
Première vague candidate :
- Tauri Android + Reflex ;
- Web navigateur direct + Reflex ;
- Tauri Desktop + Snake ;
- builder Android multi-ABI.
Deuxième vague lorsque l'environnement existe :
- Windows SDL natif ;
- macOS SDL natif ;
- iOS SDL natif.
Tauri iOS reste conditionnel aux résultats Tauri Android et à l'existence d'un besoin Apple réel.
## Principes
- réutiliser le gameplay existant ;
- minimiser le code spécifique ;
- mesurer la duplication ;
- ne pas extraire prématurément une abstraction avant d'avoir observé au moins un besoin réel ;
- comparer SDL natif, Web/WASM et Tauri/WebView ;
- ne pas implémenter les POC dans `0.2.0`.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo/Gradle/smoke n'est requise pour ce delta documentaire.

View File

@@ -0,0 +1,103 @@
<!-- file: deltas/0.2.0/0-pre.5.fix.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.5.fix.1
## Base
Base déclarée : `0.2.0-0-pre.5`.
Le delta `0-pre.5.md` reste immuable.
## Objet
Préciser la spécification fonctionnelle de Uroburas avant la phase de classification architecturale.
## Contenu embarqué et téléchargé
Le jeu peut embarquer les premières maps solo et leurs assets.
Il doit également permettre le téléchargement et la mise à jour séparée de maps, skins, sons, textures/sprites, rulesets et autres assets.
## Anatomie minimale
Un serpent valide contient au minimum :
1. tête ;
2. cou ;
3. une unité de corps ;
4. queue.
Seul le corps est extensible.
Un effet de rétrécissement ne peut pas réduire un serpent sous quatre unités hors règle de mort explicite.
## Sprites et rotations
La spec précise :
- réutilisation des sprites par rotation lorsque possible ;
- variantes dédiées pour les virages gauche/droite du corps ;
- contrat de skin compatible avec cette géométrie ;
- éditeur Web de skins possible d'abord pour les administrateurs puis, ultérieurement, pour les utilisateurs avec contraintes/modération.
## Première version réelle Uroburas
La priorité fonctionnelle est désormais explicitement :
1. Mode 1 — Challenge ;
2. Mode 3 — Persistent Battle Royale ;
3. Mode 2 — PvP Battles.
La première version réelle se concentre sur les moteurs nécessaires au Mode 1 :
- grille/tilemap toroïdale ;
- obstacles ;
- items ;
- vies ;
- temps ;
- stages ;
- caméra ;
- contrôles ;
- site Web ;
- auth ;
- rewarded ads ;
- Hall of Fame initial ;
- échange client/serveur authentifié/versionné/validable ;
- téléchargement de contenu.
## Contrôles Mobile/Tablet
La première approche privilégie des boutons directionnels affichés à l'écran, équivalents fonctionnels des contrôles clavier Desktop, plutôt qu'un contrôle principal par swipe.
## Rewarded ads
Outre la continuation après perte de toutes les vies, une rewarded ad peut être proposée pendant la transition de stage pour appliquer un bonus volontaire, par exemple doubler les points gagnés sur le stage terminé.
## Combat avancé
Feu, glace, poison, téléporteurs et protections restent décrits comme direction fonctionnelle, mais sont explicitement hors scope de la première version réelle centrée sur le Mode 1.
## Fichiers modifiés
- `Cargo.toml` ;
- `Android/game-reflex-poc/build.gradle` ;
- `Android/game-snake-poc/build.gradle` ;
- `README.md` ;
- `docs/studies/013-UROBURAS_FUNCTIONAL_SPEC.md` ;
- `docs/studies/014-UROBURAS_MODES_AND_SESSION_RULES.md` ;
- `docs/studies/015-UROBURAS_MAP_ASSET_AND_UGC_SPEC.md` ;
- `docs/studies/016-UROBURAS_COMBAT_ITEM_EFFECT_SPEC.md` ;
- `docs/studies/017-UROBURAS_SCORE_RESPAWN_AND_HALL_OF_FAME.md`.
Tous les fichiers existants modifiés et possédant un en-tête `version` ont été incrémentés.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke n'est requise pour ce fix documentaire.

43
deltas/0.2.0/0-pre.5.md Normal file
View File

@@ -0,0 +1,43 @@
<!-- file: deltas/0.2.0/0-pre.5.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.5
## Base
Base déclarée : `0.2.0-0-pre.4.fix.2`.
## Objet
Décrire fonctionnellement le prochain jeu réel, `Uroburas`, avant reclassification architecturale.
## Contenu
- client léger en contenu avec téléchargement de maps/assets ;
- Challenge solo/offline-capable ;
- PvP Battles authentifié avec maps, joueurs présélectionnés/aléatoires, équipes, bots et spectator ;
- Persistent Battle Royale authentifié ;
- règles spécialisables par map ;
- armes/protections avec effets différents tête/corps/queue ;
- score, vies, rewarded continue/rejoin ;
- éditeur de maps, skins/UGC ;
- Hall of Fame ;
- replay/streaming/video régénérée côté serveur.
## Règle de build
Les scripts Python restent autorisés pour audit et validation complémentaire mais ne pilotent pas les builds. Les builds utilisent les outils natifs appropriés, notamment Cargo, Gradle et Tauri CLI. Builds, tests unitaires/intégration et smoke tests restent exécutés côté utilisateur.
## Classification
Le mapping vers engine, capability, game-system, Uroburas-specific, platform, provider, server et tooling est réservé à la prerelease suivante.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo/Gradle/smoke n'est requise pour cette prerelease documentaire.

View File

@@ -0,0 +1,84 @@
<!-- file: deltas/0.2.0/0-pre.6.fix.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.6.fix.1
## Base
Base déclarée : `0.2.0-0-pre.6`.
Le delta `0-pre.6.md` reste immuable.
## Objet
Compléter la classification de `0-pre.6` avec la stratégie réseau/asset delivery récente et formaliser la discipline de dimensionnement des versions/sessions inspirée du workflow KSP.
## Workflow de version
`0-pre.1` devient obligatoirement la tranche de cadrage :
- audit de la base ;
- brainstorming/recherche de requirements ;
- sizing ;
- planification ;
- dépendances ;
- validations ;
- découpage prévisionnel.
Une version doit être dimensionnée pour être entièrement terminée dans une seule session.
Les tranches `pre/alpha/beta/rc` visent généralement des deltas de 15 à 30 minutes. Une tranche trop lourde est scindée avant exécution ; une tranche trop petite peut être regroupée avec une tranche cohérente.
La dernière tranche avant publication consolide validations, documentation durable, CHANGELOG, ROADMAP et prompt suivant. La release stable reste autant que possible mécanique.
## Réseau et asset delivery
La direction étudiée devient :
- Actix Web pour Web/API ;
- asset delivery auto-hébergé ;
- HTTP/2 baseline ;
- HTTP/3/QUIC pour les assets lorsque disponible ;
- H2/H3 sur un même hostname de préférence ;
- séparation logique initiale, séparation physique progressive ;
- WebSocket/tokio-tungstenite comme baseline realtime ;
- WebTransport/QUIC comme candidat à benchmarker ;
- fallback transport ;
- simulation indépendante du transport ;
- gRPC/Tonic réservé principalement aux frontières server-to-server justifiées.
## Classification
La capability réseau est décomposée conceptuellement en :
```text
HTTP client
realtime transport API
WebSocket implementation
WebTransport implementation
wire protocol
session protocol
reconnect/resync
```
Les crates Uroburas ne dépendent pas directement d'un transport concret.
## Reste de la 0.2.0
Après validation de cette tranche :
1. consolider les études acceptées dans `docs/architecture/` et les règles durables ;
2. réconcilier ROADMAP et décisions finales ;
3. produire la tranche de clôture documentaire ;
4. préparer le prompt de la session `0.3.x` consacrée aux POC ;
5. passer en RC puis stable sans rouvrir le scope.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke n'est requise : cette correction reste documentaire.

75
deltas/0.2.0/0-pre.6.md Normal file
View File

@@ -0,0 +1,75 @@
<!-- file: deltas/0.2.0/0-pre.6.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.6
## Base
Base déclarée : `0.2.0-0-pre.5.fix.1`.
## Objet
Classifier les fonctionnalités Uroburas avant toute implémentation afin d'éviter un monolithe dans les futures crates multiplateformes du jeu.
## Classification
Les responsabilités sont réparties entre :
- engine kernel ;
- technical capabilities ;
- game-systems réutilisables ;
- gameplay Uroburas-specific ;
- services serveur ;
- providers ;
- platform adapters ;
- tooling.
## Décomposition candidate
L'étude propose des familles de crates pour :
- capabilities ;
- game-systems ;
- Uroburas ;
- apps ;
- servers ;
- providers ;
- tools.
Aucune création massive de crates n'est imposée : l'extraction doit rester motivée par une frontière et une API réelles.
## Stack serveur de référence
Direction étudiée :
- Tokio ;
- Actix Web ;
- Maud ;
- tokio-tungstenite pour le realtime public ;
- tonic/gRPC conditionnel pour server-to-server ;
- Fluent/fluent-bundle ;
- Lettre.
Le client public reste orienté `HTTPS + WebSocket`.
## Ordre d'implémentation
Priorité :
1. fondations réutilisables ;
2. game-systems du Mode 1 ;
3. Uroburas Challenge ;
4. services Web V1 ;
5. intégration client/server Mode 1 ;
6. Mode 3 ;
7. Mode 2.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo/Gradle/smoke n'est requise : ce delta reste documentaire.

82
deltas/0.2.0/0-pre.7.md Normal file
View File

@@ -0,0 +1,82 @@
<!-- file: deltas/0.2.0/0-pre.7.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.7
## Base
Base déclarée : `0.2.0-0-pre.6.fix.1`.
Cette base est utilisée comme état de travail. Aucune entrée d'historique ne prétend que `0-pre.6.fix.1` a déjà passé une validation utilisateur non fournie.
## Objet
Promouvoir les décisions retenues des études `0.2.0` vers des documents durables d'architecture et de règles.
## Architecture consolidée
Documents ajoutés :
- architecture modulaire et ownership ;
- architecture réseau/serveur ;
- architecture cible Uroburas ;
- architecture des POC plateforme/réseau.
Les études restent comme justification et historique de conception ; les nouveaux documents portent les orientations durables.
## Règles consolidées
Deux règles durables sont ajoutées :
- cadrage des versions/sessions/prompts ;
- portabilité et auto-hébergement serveur.
La cible opérationnelle préférée est Debian Stable, actuellement Debian 13 `trixie`, sans dépendance métier à cette version.
Les choix futurs HAProxy/nginx/HTTP3 edge/storage restent explicitement hors gel `0.2.0`.
## Réseau durable
- Actix Web reste la référence Web/API ;
- Maud reste la référence HTML server-side ;
- Fluent/fluent-bundle porte la localisation ;
- Lettre porte l'email transactionnel ;
- WebSocket/tokio-tungstenite est la baseline realtime ;
- WebTransport/QUIC reste un candidat POC ;
- gRPC/Tonic est conditionnel aux frontières server-to-server ;
- asset delivery reste auto-hébergé et compatible H2/H3 selon disponibilité.
## Workflow durable
`pre.1` devient la tranche obligatoire de cadrage.
Une version est dimensionnée pour tenir dans une session.
Les tranches visent normalement 15 à 30 minutes et restent fonctionnellement complètes.
La fin de version consolide CHANGELOG, ROADMAP et le prompt suivant ; la stable reste mécanique.
## ROADMAP
Les lignes de scope `0.2.0` ne sont pas marquées comme complètes dans ce delta avant revue humaine de la consolidation.
## Suite attendue
Après validation de `0-pre.7` :
1. audit documentaire global ;
2. réconciliation finale studies/architecture/rules/ROADMAP ;
3. CHANGELOG de candidate ;
4. prompt de session `0.3.x` ;
5. RC documentaire ;
6. release stable mécanique.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo/Gradle/smoke n'est requise : `0.2.0` reste strictement documentaire hors métadonnées de version.

View File

@@ -0,0 +1,40 @@
<!-- file: deltas/0.2.0/0-pre.8.fix.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.8.fix.1
## Base
Base déclarée : `0.2.0-0-pre.8`.
Le delta `0-pre.8.md` reste immuable.
## Objet
Renforcer le prompt de démarrage `0.3.x` afin qu'il fournisse un véritable plan de session exploitable, inspiré du modèle KSP mais plus compact.
## Correction
Le prompt ajoute :
- mission bornée de `0.3.0` ;
- cadrage `0-pre.1` détaillé ;
- forecast souple tranche par tranche pour `0.3.0` ;
- objectifs et critères des phases pre/alpha/beta/rc candidates ;
- règles de fusion/scission/report ;
- forecast initial `0.3.0` à `0.3.6` ;
- dépendances entre versions ;
- ordre de préférence des premiers POC ;
- critères de fin explicites.
Le forecast n'est pas contractuel : `pre.1` doit le corriger immédiatement si le sizing réel le contredit.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo/Gradle/smoke n'est requise : ce fix est documentaire hors métadonnées de version.

58
deltas/0.2.0/0-pre.8.md Normal file
View File

@@ -0,0 +1,58 @@
<!-- file: deltas/0.2.0/0-pre.8.md -->
<!-- version: 1 -->
# Delta 0.2.0-0-pre.8
## Base
Base déclarée : `0.2.0-0-pre.7`.
`0-pre.7` a été validée par revue humaine et audits projet.
## Objet
Clore la phase de conception `0.2.0` avant RC.
## Réconciliation finale
Cette tranche :
- ferme les lignes durables `0.2.0` du ROADMAP ;
- ajoute le résumé `CHANGELOG` de `0.2.0` ;
- ajoute une baseline architecturale consolidée ;
- enregistre l'historique validé de `0-pre.7` ;
- prépare le prompt de session `0.3.x`.
## Prompt 0.3.x
Le prompt fixe :
- `pre.1` comme cadrage obligatoire ;
- Snake comme jeu-sonde ;
- POC Tauri Android/Web/Tauri Desktop/Android multi-ABI ;
- POC WebSocket vs WebTransport/QUIC ;
- builds via outils natifs ;
- utilisateur responsable des builds/tests/smoke ;
- Debian Stable comme cible opérationnelle préférée ;
- Uroburas réservé à `0.4.x`.
## Gel
Après validation de `0-pre.8`, le scope documentaire `0.2.0` est considéré complet.
La RC suivante est une candidate de publication :
- aucune nouvelle fonctionnalité ;
- aucune nouvelle orientation architecturale ;
- corrections seulement si nécessaires ;
- revue humaine finale.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke n'est requise : `0.2.0` reste documentaire hors métadonnées de version.

46
deltas/0.2.0/3-rc.1.md Normal file
View File

@@ -0,0 +1,46 @@
<!-- file: deltas/0.2.0/3-rc.1.md -->
<!-- version: 1 -->
# Delta 0.2.0-3-rc.1
## Base
Base déclarée : `0.2.0-0-pre.8.fix.1`.
Cette base a été validée par revue humaine et audits projet.
## Objet
Créer la candidate de publication `0.2.0`.
## Gel
Le scope `0.2.0` est gelé.
Cette RC n'ajoute :
- aucune nouvelle fonctionnalité ;
- aucune nouvelle orientation architecturale ;
- aucune nouvelle capability ;
- aucun nouveau POC.
Elle consolide uniquement :
- métadonnées de version ;
- CHANGELOG RC ;
- historique de la dernière prerelease validée ;
- checklist de revue RC.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke n'est requise : la version reste documentaire hors métadonnées.
## Après validation
Si cette RC est validée sans correction sémantique, la release `0.2.0` doit être mécanique.

42
deltas/0.2.0/rel.001.md Normal file
View File

@@ -0,0 +1,42 @@
<!-- file: deltas/0.2.0/rel.001.md -->
<!-- version: 1 -->
# Delta 0.2.0 — release stable
## Base
Base validée : `0.2.0-3-rc.1`.
## Objet
Promouvoir mécaniquement la candidate validée vers `0.2.0`.
## Changements
La release stable modifie uniquement :
- la version workspace ;
- les métadonnées Android correspondantes ;
- la version affichée dans le README ;
- l'en-tête CHANGELOG de candidate vers stable ;
- l'historique de validation de la RC.
Aucun nouveau scope fonctionnel, architectural ou documentaire n'est introduit.
## Validation
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucune gate Cargo, Gradle ou smoke supplémentaire n'est requise pour cette promotion documentaire/métadonnée.
## Publication
Après validation :
- commit de release ;
- tag stable `v0.2.0` ;
- ouverture de la session `0.3.0` à partir de `prompts/002-V0_3_X_START_PROMPT.md`.

View File

@@ -0,0 +1,85 @@
<!-- file: deltas/0.3.0/0-pre.1.fix.1.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.1.fix.1
## Base
Base requise : `0.3.0-0-pre.1`.
Ce correctif reste dans la responsabilité de cadrage de `0-pre.1`. Il ne modifie aucun gameplay, runtime, frontend ou packaging.
## Objet
Corriger deux omissions du cadrage initial :
- créer le plan vivant de `0.3.0` sous `docs/plans/`, avec le découpage prévisionnel souple de toute la progression de la version ;
- formaliser les règles associées, notamment la relation plan/ROADMAP/deltas, la cible d'au moins une version complète par session et le traitement des archives fournies depuis un tag.
## Version
La version workspace passe de `0.3.0-0-pre.1` à `0.3.0-0-pre.1.fix.1`.
## Plan de version
Ajout de :
- `docs/plans/000-README.md` ;
- `docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md`.
Le plan conserve le scope et les décisions du cadrage, puis suit une trajectoire souple : baseline Snake portable, adaptation WASM, frontend Web/Vite, intégration E2E, correction/extraction conditionnelle, beta, RC et stable.
La numérotation est prévisionnelle. Les tranches peuvent être scindées, fusionnées ou décalées en fonction des résultats réels sans forcer une fermeture artificielle.
## Règles ajoutées ou précisées
- `0-pre.1` crée ou révise obligatoirement le plan actif de la version sous `docs/plans/` ;
- le plan porte le découpage prévisionnel fin, `ROADMAP.md` reste macroscopique et les deltas enregistrent le livré réel ;
- une session de développement est planifiée pour livrer au minimum une version concrète complète ; une prerelease est une tranche interne, pas une cible normale de fin de session ;
- lorsqu'une archive est fournie comme téléchargement d'un tag du dépôt, elle est la baseline autoritaire de ce tag ; l'absence de `.git` est normale et n'est ni une anomalie ni une validation manquante ;
- les contrôles Git nécessitant `.git` ne s'appliquent qu'à un checkout local effectivement fourni.
Le prompt `002-V0_3_X_START_PROMPT.md` est aligné sur ces règles : il ne demande plus de vérifier un état Git inexistant dans une archive taggée et exige le plan actif dans le résultat de `pre.1`.
## Fichiers ajoutés
- `docs/plans/000-README.md` ;
- `docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md` ;
- `deltas/0.3.0/0-pre.1.fix.1.md`.
## Fichiers modifiés
- `Cargo.toml` ;
- `README.md` ;
- `docs/000-README.md` ;
- `docs/rules/FILE_CONTRACTS.md` ;
- `docs/rules/RULES_DOCUMENTATION.md` ;
- `docs/rules/RULES_SESSION_PLANNING.md` ;
- `docs/rules/VERSION_WORKFLOW.md` ;
- `docs/rules/RULES_COMMANDS.md` ;
- `prompts/002-V0_3_X_START_PROMPT.md`.
## Suppressions
Aucune.
## Validations applicables
Ce fix modifie uniquement le manifest de version et la documentation/règles. Les audits statiques sont exécutés lors de la préparation du delta.
Validation utilisateur demandée :
```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 deltas history
python3 scripts/audit_distribution_layout.py
cargo fmt --all -- --check
cargo check --workspace
```
Clippy/tests ne sont pas rendus nécessaires par ce fix documentaire lui-même ; ils restent ceux prévus par la progression de `0.3.0`.
## Suite
Après validation de ce fix, poursuivre `0.3.0` selon `docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md`, en commençant par `0-pre.2` et en visant la fermeture complète de `0.3.0` dans la session plutôt qu'un arrêt planifié sur une prerelease.

View File

@@ -0,0 +1,94 @@
<!-- file: deltas/0.3.0/0-pre.1.fix.2.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.1.fix.2
## Base
Base requise : `0.3.0-0-pre.1.fix.1`.
Ce correctif reste dans la responsabilité de cadrage de `0-pre.1`. Il ne modifie aucun gameplay, runtime, frontend ou packaging.
## Objet
Compléter le plan `0.3.0` sur deux responsabilités qui doivent être visibles dès le cadrage :
- le POC navigateur doit posséder un véritable shell Web HTML/Vite/TypeScript autour du Canvas/WASM, avec Bootstrap 5 comme baseline de présentation du premier POC Snake ;
- la prévision de version doit montrer explicitement la tranche finale de consolidation documentaire et de transmission avant RC/stable, au lieu de laisser cette responsabilité seulement implicite dans les règles générales.
## Version
La version workspace passe de `0.3.0-0-pre.1.fix.1` à `0.3.0-0-pre.1.fix.2`.
## Frontend Web
Le plan retient désormais explicitement pour `0-pre.4` :
- Vite/TypeScript comme host frontend ;
- un document HTML responsive ;
- Bootstrap 5 pour le layout, les états UI et les contrôles tactiles ;
- un Canvas dédié au rendu du jeu ;
- clavier et contrôles directionnels tactiles ;
- séparation stricte : Bootstrap/DOM restent côté frontend, le gameplay et l'état du jeu restent dans Rust/WASM.
La règle durable ne rend pas Bootstrap obligatoire pour tous les futurs hosts Web : elle impose la séparation shell Web / Canvas-WASM / gameplay. Bootstrap 5 est la décision concrète du POC `0.3.0`.
## Consolidation de fin de version
Le forecast `0.3.0` ajoute `2-beta.2` comme repère prévisionnel de consolidation :
- réconciliation de la documentation durable et du plan actif ;
- mise à jour de `CHANGELOG.md` ;
- mise à jour de `ROADMAP.md` ;
- mise à jour de l'historique applicable ;
- vérification des deltas réellement livrés ;
- préparation et vérification du prompt de la version/session suivante.
Le numéro reste souple : des fixes ou une beta supplémentaire peuvent le décaler. La responsabilité, elle, ne doit pas disparaître du plan.
La documentation fonctionnelle reste mise à jour au fil des tranches concernées ; cette consolidation finale sert à fermer la cohérence transversale et la transmission de session.
## Règles précisées
- `SESSION-009` exige que le forecast créé en `0-pre.1` rende explicitement visible une tranche de consolidation avant la candidate finale ;
- `GAME-PLATFORM-020` fixe la séparation durable du host Web : shell HTML/CSS/TypeScript autour du Canvas/WASM, sans fuite du framework de présentation dans gameplay/WASM ; Bootstrap 5 est la baseline du premier POC Snake.
Le prompt `002-V0_3_X_START_PROMPT.md` est aligné sur les décisions déjà prises par `pre.1` : Web direct en premier host, adaptation WASM dédiée, shell Bootstrap 5 et tranche `2-beta.2` de consolidation/transmission.
## Fichiers ajoutés
- `deltas/0.3.0/0-pre.1.fix.2.md`.
## Fichiers modifiés
- `Cargo.toml` ;
- `README.md` ;
- `docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md` ;
- `docs/rules/RULES_PROJECT.md` ;
- `docs/rules/RULES_SESSION_PLANNING.md` ;
- `prompts/002-V0_3_X_START_PROMPT.md`.
## Suppressions
Aucune.
## Validations applicables
Ce fix modifie uniquement la version workspace et le cadrage documentaire/normatif. Les audits statiques sont exécutés lors de la préparation du delta.
Validation utilisateur demandée :
```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 deltas history
python3 scripts/audit_distribution_layout.py
cargo fmt --all -- --check
cargo check --workspace
```
Aucun build Web n'est demandé par ce fix : Bootstrap 5 et le frontend Snake seront introduits seulement dans leur tranche d'implémentation.
## Suite
Après validation de ce fix, poursuivre `0.3.0` avec `0-pre.2` selon le plan actif. La session reste planifiée jusqu'à la stable `0.3.0`, avec consolidation documentaire/transmission explicitement réservée avant RC.

157
deltas/0.3.0/0-pre.1.md Normal file
View File

@@ -0,0 +1,157 @@
<!-- file: deltas/0.3.0/0-pre.1.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.1
## Base
Base déclarée : `0.2.0`.
L'archive de base a été inspectée avant modification. Sa version workspace est `0.2.0`. L'archive ne contient pas `.git`, donc le tag réel et la propreté Git ne peuvent pas être vérifiés dans l'environnement de génération.
## Objet
Ouvrir `0.3.0` par le cadrage obligatoire : audit réel de la baseline, revue des règles, requirements Snake, graphe de dépendances, choix du premier POC, sizing corrigé et préparation des validations.
Aucun gameplay, runtime SDL, Java/JNI, Tauri ou frontend existant n'est modifié dans cette tranche.
## Version
La version workspace passe de :
```text
0.2.0
```
à :
```text
0.3.0-0-pre.1
```
Les métadonnées Android restent à `0.2.0` dans cette tranche, car le chemin Android natif n'est ni modifié ni construit par le premier POC Web. Elles seront réévaluées dans la version qui réouvre effectivement ce produit Android.
## Audit de baseline
Les audits statiques officiels ont été exécutés avant modification et étaient propres :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (4 table(s), 158 file(s))
Distribution layout audit: clean (19 required path(s), 1 forbidden path(s) absent)
```
La revue manuelle a néanmoins détecté :
- README encore positionné sur `0.1.0` stable / `0.2.0` candidate ;
- quatre lignes `( )` sous la stable `0.2.0` dans ROADMAP, en violation de `DOC-RMAP-010` ;
- la gate `audit_rust_workspace_rules.py` qui créait un cache Python `.pyc` pendant son exécution, alors quun audit doit rester en lecture seule ;
- `CMD-RC-001` encore spécifique à `0.1.0` ;
- contradiction entre `CMD-BUILD-002` (interdiction globale) et `CMD-BUILD-004` (remplacement progressif en `0.3.x`), alors que deux orchestrateurs Python historiques existent encore ;
- `CMD-WEB-003` décrivant sans contexte le build Python Tauri/WASM historique ;
- dépendances `engine-v1-platform-api` déclarées mais non utilisées par les crates de jeu ;
- `RuntimeProvenance` défini mais non branché aux launchers ;
- `game-assets-lib` encore sans consommateur runtime ;
- deux orchestrateurs Python de build historiques à ne pas réutiliser dans les nouveaux POC.
Les détails et le graphe complet sont documentés dans `docs/studies/023-V0_3_0_PLATFORM_POC_AUDIT.md`.
## Corrections de règles et hygiène
Cette tranche :
- corrige le README de version ;
- ferme correctement le scope `0.2.0` dans ROADMAP ;
- distingue ce qui a été livré de ce qui est reporté ;
- rend `CMD-RC-001` générique à la version courante ;
- rend `CMD-BUILD-002` cohérente avec la migration `0.3.x` : les deux orchestrateurs Python historiques sont gelés jusquà réactivation de leur chemin, mais aucun nouveau chemin ne peut les reprendre ;
- qualifie explicitement `scripts/build_reflex_tauri_wasm.py` de mécanisme historique non réutilisable comme orchestration `0.3.x` ;
- renforce `audit_project_workspace_rules.py` pour détecter le scope `( )` restant sous une version stable présente dans CHANGELOG ;
- fait exécuter les sous-audits de `audit_rust_workspace_rules.py` avec linterpréteur courant et `-B`, afin que la gate standard reste effectivement en lecture seule malgré limport effectué dans laudit de complétude des exports.
## Premier POC retenu
Le premier host de `0.3.0` devient :
```text
Web navigateur direct + Snake
```
Tauri Android est reporté au second host, actuellement prévu en `0.3.1`.
Le but est de valider d'abord la frontière Web/WASM et les capabilities directement observables sans cumuler simultanément la généralisation Snake/WASM et la complexité d'un host mobile Tauri.
## Forecast corrigé
```text
0-pre.1 audit / règles / requirements / sizing
0-pre.2 Snake portability baseline
0-pre.3 adapter Snake WASM + build natif Web
0-pre.4 navigateur direct end-to-end
0-pre.5 seulement si un défaut réel est observé
2-beta.1 validation large
3-rc.1 candidate gelée
0.3.0 release mécanique
```
Aucune alpha n'est créée par cérémonial. Elle reste possible si le volume réel de stabilisation le justifie.
## Scope exclu de 0.3.0
- Tauri Android ;
- Tauri Desktop Snake ;
- Android multi-ABI natif ;
- réseau realtime ;
- WebTransport/QUIC ;
- Uroburas ;
- ads, billing, auth et leaderboard ;
- ECS ou nouveau moteur.
## Suppressions
Aucune suppression de fichier appartenant à la baseline `0.2.0` n'est nécessaire.
## Validations exécutées dans l'environnement de génération
Après constitution de l'état livré, les audits statiques suivants doivent être réexécutés et leur résultat est enregistré avant packaging :
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Aucun build/test/smoke n'est exécuté par le générateur, conformément à `CMD-GEN-007` et `CMD-BUILD-005`.
## Validation utilisateur demandée
Cette tranche ne modifie aucun source Rust/Java/TypeScript ni aucune configuration runtime. Elle ouvre toutefois une nouvelle version `0.3.0` et modifie le manifest workspace ; la gate utilisateur retient donc les audits statiques puis une gate Cargo workspace complète, conformément à la discipline des frontières de version :
```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 deltas history
python3 scripts/audit_distribution_layout.py
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets --all-features
```
Aucun build de distribution, smoke Desktop, Tauri ou Android n'est requis par `pre.1`, car aucun runtime ni packaging de ces hosts n'est modifié.
La revue humaine doit confirmer :
- le choix Web direct comme premier POC ;
- le scope corrigé de `0.3.0` ;
- le report de Tauri Android vers le second host ;
- le sizing `pre.2` à `pre.4` ;
- la fermeture correcte des lignes historiques `0.2.0`.
## Suite après validation
Si cette gate est propre et le cadrage accepté, passer automatiquement à `0.3.0-0-pre.2`.
`pre.2` doit rester une tranche bornée de portabilité Snake et de nettoyage de dépendances ; elle ne doit pas commencer le frontend Web complet.

102
deltas/0.3.0/0-pre.2.md Normal file
View File

@@ -0,0 +1,102 @@
<!-- file: deltas/0.3.0/0-pre.2.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.2
## Base
Base requise : `0.3.0-0-pre.1.fix.2`.
Les validations utilisateur de `0-pre.1.fix.1` et `0-pre.1.fix.2` sont consignées sous `history/0.3.0/` conformément au workflow documentaire.
## Objet
Fermer la baseline Snake portable avant l'introduction de l'adapter WASM :
- retirer des crates de gameplay les dépendances plateforme déclarées mais inutilisées ;
- confirmer que le gameplay Snake ne consomme que les contrats moteur indépendants de la plateforme ;
- documenter le contrat minimal que le futur host Web devra adapter sans introduire encore de code WASM ou frontend.
## Version
La version workspace passe de `0.3.0-0-pre.1.fix.2` à `0.3.0-0-pre.2`.
## Nettoyage des dépendances
`engine-v1-platform-api` est retiré de :
- `game-snake-poc` ;
- `game-reflex-poc`.
Ces deux crates n'utilisent aucun symbole de cette dépendance. Les launchers et adapters qui utilisent réellement des capacités plateforme conservent leur dépendance.
Ce nettoyage ne déplace aucune responsabilité et ne change aucun comportement de gameplay.
## Contrat Snake portable
La baseline confirmée pour Snake est :
- état et update via `EngineGame` ;
- entrée via `InputState` ;
- actions de gameplay utilisées : `Left`, `Right`, `Up`, `Down` ;
- rendu abstrait via `EngineScene` ;
- aucune dépendance SDL3, Web/DOM/Canvas ou `engine-v1-platform-api` dans `game-snake-poc`.
Le host reste responsable de traduire ses périphériques ou widgets en actions logiques. Le futur adapter WASM `0-pre.3` doit réutiliser cette frontière sans créer un modèle Web parallèle.
## Historique des validations précédentes
Ajout de :
- `history/0.3.0/0-pre.1.fix.1.md` ;
- `history/0.3.0/0-pre.1.fix.2.md`.
Ces fichiers enregistrent uniquement les résultats effectivement fournis par l'utilisateur : audits statiques, `cargo fmt --all -- --check` et `cargo check --workspace`. Aucun Clippy, test ou smoke non exécuté n'est déclaré validé.
## Fichiers ajoutés
- `deltas/0.3.0/0-pre.2.md` ;
- `history/0.3.0/0-pre.1.fix.1.md` ;
- `history/0.3.0/0-pre.1.fix.2.md`.
## Fichiers modifiés
- `Cargo.toml` ;
- `README.md` ;
- `crates/games/game-reflex-poc/Cargo.toml` ;
- `crates/games/game-snake-poc/Cargo.toml` ;
- `docs/architecture/004-INPUT_AND_CONTROLS.md` ;
- `docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md`.
## Suppressions
Aucune.
## Validations applicables
Audits statiques de préparation :
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Validation utilisateur demandée :
```bash
cargo fmt --all -- --check
cargo check --workspace
cargo clippy -p game-snake-poc --all-targets --all-features -- -D warnings
cargo clippy -p game-reflex-poc --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc
cargo test -p game-reflex-poc
cargo tree -p game-snake-poc --edges normal
cargo tree -p game-reflex-poc --edges normal
```
Les deux `cargo tree` doivent confirmer que les crates de gameplay ne tirent plus `engine-v1-platform-api`. Aucun smoke Desktop n'est requis : ni `engine-v1-sdl`, ni le mapping SDL, ni le runner Snake ne sont modifiés dans cette tranche.
## Suite
Après validation de `0-pre.2`, ouvrir `0-pre.3` pour l'adaptation WASM minimale de Snake conformément au plan actif. Aucun frontend Bootstrap/Vite n'est introduit avant `0-pre.4`.

118
deltas/0.3.0/0-pre.3.md Normal file
View File

@@ -0,0 +1,118 @@
<!-- file: deltas/0.3.0/0-pre.3.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.3
## Base
Base requise : `0.3.0-0-pre.2`.
La validation complète de `0-pre.2` est consignée dans `history/0.3.0/0-pre.2.md`.
## Objet
Introduire l'adapter WASM minimal de Snake avant tout frontend navigateur :
- ajouter `game-snake-poc-wasm` comme crate d'application dédiée ;
- réutiliser exclusivement `engine-v1-common` et `game-snake-poc` ;
- exposer à `wasm-bindgen` les directions logiques et la scène portable ;
- préserver la cadence de simulation en séparant événement d'entrée et `tick()` ;
- documenter un chemin Cargo + `wasm-bindgen` direct sans orchestrateur Python ;
- ne pas introduire Vite, Bootstrap, DOM, Tauri ou SDL3 dans cette tranche.
## Version
La version workspace passe de `0.3.0-0-pre.2` à `0.3.0-0-pre.3`.
## Adapter Snake WASM
La nouvelle crate `crates/apps/game-snake-poc-wasm` contient une façade `lib.rs` et un runtime propriétaire séparé.
`SnakeWasmGame` possède :
- un `SnakeState` issu de la crate de gameplay ;
- un `FixedStepRunner` à pas déterministe de 16 ms ;
- un `InputState` en attente pour la prochaine update.
Les appels `left()`, `right()`, `up()` et `down()` ne font pas avancer la simulation. Ils remplacent la direction logique en attente. `tick()` consomme ensuite cette entrée une fois, la remet à zéro et avance le runner d'une update. La cadence reste ainsi sous la responsabilité du futur host navigateur.
L'API expose également le score, la longueur, la couleur de fond et les rectangles normalisés de l'`EngineScene`. Le futur frontend `0-pre.4` peut donc dessiner le Canvas sans accéder à la structure interne de Snake.
## Frontières conservées
`game-snake-poc-wasm` ne dépend pas de :
- `engine-v1-platform-api` ;
- `engine-v1-sdl` ;
- Tauri ;
- DOM/Canvas Rust ;
- code frontend TypeScript.
La duplication limitée des getters de scène avec `game-reflex-poc-wasm` est volontairement conservée à ce stade. Une abstraction commune ne sera extraite que si les POC suivants démontrent un besoin partagé suffisamment stable.
## Documentation et audits
L'architecture du workspace mentionne désormais l'adapter Snake WASM et le contrat d'entrée précise la file directionnelle consommée par `tick()`.
L'audit de distribution exige maintenant `crates/apps/game-snake-poc-wasm/Cargo.toml`, portant le nombre de chemins requis de 19 à 20.
Le plan actif est réconcilié avec la livraison réelle de `0-pre.3`. `docs/development/009-SNAKE_WEB_WASM_BUILD.md` documente le build natif Cargo + `wasm-bindgen`, avec tous les artefacts générés sous `../builds/sasedev-games/`.
## Historique
Ajout de `history/0.3.0/0-pre.2.md` avec les résultats réellement fournis par l'utilisateur : audits, formatage, check workspace, Clippy workspace strict, tests Snake/Reflex et graphes de dépendances.
## Fichiers ajoutés
- `crates/apps/game-snake-poc-wasm/Cargo.toml` ;
- `crates/apps/game-snake-poc-wasm/src/lib.rs` ;
- `crates/apps/game-snake-poc-wasm/src/runtime.rs` ;
- `crates/apps/game-snake-poc-wasm/unit_tests/runtime.rs` ;
- `deltas/0.3.0/0-pre.3.md` ;
- `docs/development/009-SNAKE_WEB_WASM_BUILD.md` ;
- `history/0.3.0/0-pre.2.md`.
## Fichiers modifiés
- `Cargo.toml` ;
- `README.md` ;
- `docs/architecture/001-WORKSPACE_ARCHITECTURE.md` ;
- `docs/000-README.md` ;
- `docs/architecture/004-INPUT_AND_CONTROLS.md` ;
- `docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md` ;
- `scripts/audit_distribution_layout.py`.
## Suppressions
Aucune.
## Validations applicables
Audits statiques de préparation :
```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 deltas history
python3 scripts/audit_distribution_layout.py
```
Validation utilisateur demandée :
```bash
cargo fmt --all
cargo fmt --all -- --check
cargo check --workspace
cargo clippy -p game-snake-poc-wasm --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc-wasm
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
cargo tree -p game-snake-poc-wasm --edges normal
```
Le `cargo tree` doit rester limité à `engine-v1-common`, `game-snake-poc`, `wasm-bindgen` et leurs dépendances nécessaires ; aucune dépendance SDL3, Tauri ou `engine-v1-platform-api` ne doit apparaître.
La commande `wasm-bindgen` doit produire les bindings navigateur sans écrire d'artefact généré dans le dépôt. Aucun build Vite/Bootstrap et aucun smoke navigateur ne sont requis dans cette tranche, car le frontend appartient à `0-pre.4`.
## Suite
Après validation de `0-pre.3`, ouvrir `0-pre.4` pour le frontend Web direct Vite/TypeScript, son shell HTML Bootstrap 5, le Canvas et les contrôles clavier/tactiles.

View File

@@ -0,0 +1,56 @@
<!-- file: deltas/0.3.0/0-pre.4.fix.1.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.4.fix.1
## Objectif
Fermer les défauts découverts pendant la validation utilisateur de `0-pre.4` sans ouvrir le scope `0-pre.5`.
## Corrigé
- suppression de `compilerOptions.baseUrl`, retiré par TypeScript 7, tout en conservant le mapping `paths` et l'alias Vite `@snake-wasm` ;
- réintégration de `simplebar` et `resize-observer-polyfill` depuis le template KSP comme dépendances runtime du shell navigateur ;
- ajout du Sass SimpleBar KSP-derived et activation de `data-simplebar` sur `app-main` ;
- maintien du header et du footer fixes avec scroll interne de la zone centrale lorsque son contenu dépasse la hauteur disponible ;
- retrait des contraintes `h-100` internes qui empêchaient le contenu du shell de prendre sa hauteur naturelle ;
- correction du plateau Snake de `1 / 1` vers `3 / 5`, cohérente avec la grille logique `12 × 20`, afin de conserver des cellules visuellement carrées ;
- conservation du resize haute densité via `devicePixelRatio` à l'intérieur du ratio CSS corrigé ;
- correction de la documentation qui classait à tort SimpleBar et le polyfill parmi les dépendances propres à Tauri ;
- ajout d'une règle durable sur le scroll shell Web et extension de l'audit de distribution au Sass SimpleBar ;
- consignation sous `history/0.3.0/0-pre.4.md` des validations réussies et de l'échec `TS5102` ayant déclenché ce fix.
## Non modifié
- gameplay Snake ;
- adapter WASM et cadence `tick()` ;
- mappings clavier/pointer ;
- lifecycle complet, assets, logging et provenance prévus pour `0-pre.5` ;
- route de smoke : `http://127.0.0.1:1434/main.html`.
## Validation demandée
Depuis la racine :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo check --workspace
cargo clippy -p game-snake-poc-wasm --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc-wasm
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
npm run dev
```
Smoke navigateur sur `http://127.0.0.1:1434/main.html` : vérifier clavier, boutons pointer/tactiles, cellules non déformées, scroll SimpleBar lorsque nécessaire et fixation du header/footer.
## Suite
Après validation du fix, `0-pre.5` peut fermer lifecycle/resize, assets, logging, provenance runtime et non-régression Desktop SDL3 conformément au plan actif.

View File

@@ -0,0 +1,50 @@
<!-- file: deltas/0.3.0/0-pre.4.fix.2.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.4.fix.2
## Objectif
Fermer les deux erreurs TypeScript découvertes pendant la validation utilisateur de `0-pre.4.fix.1`, sans modifier le gameplay ni ouvrir le scope `0-pre.5`.
## Corrigé
- `tsconfig.json` résout désormais `@snake-wasm` vers `game_snake_poc_wasm.d.ts`, généré par `wasm-bindgen`, afin que TypeScript consomme les types réels du bridge sans déclaration manuelle dupliquée ;
- `vite.config.ts` conserve séparément l'alias runtime vers `game_snake_poc_wasm.js` ;
- après validation de `canvas.getContext("2d")`, `game.ts` capture le contexte dans une constante `CanvasRenderingContext2D` non nullable utilisée par le callback de frame ;
- consignation sous `history/0.3.0/0-pre.4.fix.1.md` de la gate réellement exécutée et des deux erreurs ayant déclenché ce fix ;
- réconciliation du plan actif avec ce second fix de `0-pre.4`.
## Non modifié
- gameplay Snake ;
- cadence et API du bridge WASM ;
- ratio Canvas `3 / 5` ;
- SimpleBar, header/footer fixes et shell Bootstrap ;
- mappings clavier/pointer ;
- lifecycle complet, assets, logging et provenance prévus pour `0-pre.5`.
## Validation demandée
Depuis la racine :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc-wasm
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
cargo tree -p game-snake-poc-wasm --edges normal
(cd Web/game-snake-poc && npm install && npm run build && npm run dev)
```
Smoke navigateur sur `http://127.0.0.1:1434/main.html` : vérifier chargement WASM, clavier, boutons pointer/tactiles, ratio du plateau et scroll SimpleBar lorsque nécessaire.
## Suite
Après validation du fix, `0-pre.5` peut fermer lifecycle/resize, assets, logging, provenance runtime et non-régression Desktop SDL3 conformément au plan actif.

View File

@@ -0,0 +1,64 @@
<!-- file: deltas/0.3.0/0-pre.4.fix.3.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.4.fix.3
## Objectif
Aligner le scroll SimpleBar du host Snake Web sur le shell réellement utilisé par les applications Desk KSP après validation réussie du build `0-pre.4.fix.2`.
## Diagnostic
La comparaison avec `ksp-app-*-desk` confirme que le package et le Sass SimpleBar étaient présents, mais que le conteneur n'était pas structuré comme la référence :
- KSP garde `app-main` comme conteneur de hauteur bornée et non scrollable ;
- un enfant `row h-100` porte la zone centrale ;
- `data-simplebar` est attaché à `app-content app-scrollable h-100` ;
- `app-scrollable` et `app-content` ont `height: 100%` / `max-height: 100%` ;
- `main.ts` importe `resize-observer-polyfill` puis `simplebar` et installe le polyfill global avant l'initialisation de l'application.
Le point d'entrée TypeScript Snake suit déjà ce dernier contrat ; le défaut se situe donc dans la structure HTML/Sass.
## Corrigé
- `data-simplebar` est déplacé de `app-main` vers `app-content app-scrollable h-100` ;
- ajout du conteneur `row g-0 h-100 flex-nowrap` comme dans le shell KSP ;
- `app-main` reste borné à la hauteur disponible entre header et footer ;
- `app-scrollable` et `app-content` portent explicitement `height: 100%` et `max-height: 100%` ;
- la règle `GAME-PLATFORM-023` pérennise ce contrat lorsque le shell KSP/SimpleBar est réutilisé ;
- `audit_distribution_layout.py` vérifie statiquement que `data-simplebar` reste sur la zone centrale et que le bootstrap TypeScript/Sass requis est présent ;
- la documentation frontend et le plan `0.3.0` sont réconciliés ;
- `history/0.3.0/0-pre.4.fix.2.md` consigne la validation réussie du build et le défaut visuel restant.
## Non modifié
- gameplay Snake ;
- bridge WASM et cadence ;
- ratio Canvas `3 / 5` ;
- mapping clavier/pointer ;
- dépendances npm ;
- lifecycle complet, assets, logging et provenance prévus pour `0-pre.5`.
## Validation demandée
Depuis la racine :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc-wasm
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 && npm run dev)
```
Smoke navigateur sur `http://127.0.0.1:1434/main.html` : réduire la hauteur de fenêtre ou utiliser un viewport assez bas pour forcer le dépassement vertical, puis vérifier que seule la zone centrale défile avec SimpleBar tandis que header et footer restent fixes. Vérifier aussi que Canvas, clavier et boutons pointer restent fonctionnels.
## Suite
Après validation du scroll SimpleBar, `0-pre.5` peut ouvrir l'intégration plateforme complète prévue par le plan actif.

60
deltas/0.3.0/0-pre.4.md Normal file
View File

@@ -0,0 +1,60 @@
<!-- file: deltas/0.3.0/0-pre.4.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.4
## Objectif
Introduire le premier host navigateur direct Snake sans élargir encore le scope vers le lifecycle complet, les assets runtime, le logging ou la provenance de `0-pre.5`.
## Livré
- création de `Web/game-snake-poc/`, package Vite/TypeScript autonome hors workspace Cargo ;
- reprise du template frontend des applications Desk KSP pour la structure `frontend/main.html`, `frontend/sass/`, `frontend/ts/` et le thème Bootstrap/Bootswatch Pulse ;
- reprise uniquement des dépendances npm KSP utiles au navigateur direct : Bootstrap 5, Font Awesome, `sass-embedded`, TypeScript, Vite et types associés ;
- exclusion volontaire des dépendances Tauri, SimpleBar et tracing spécifiques aux apps Desk ;
- consommation des bindings `game-snake-poc-wasm` générés sous `../builds/sasedev-games/game-snake-poc-web/wasm/` ;
- Canvas responsive prenant en compte `devicePixelRatio` ;
- rendu de l'`EngineScene` normalisée sans dupliquer le gameplay ;
- entrées clavier flèches, `WASD`, `ZQSD` et quatre boutons pointer/tactiles ;
- état de chargement, score, longueur et retour d'erreur dans le shell ;
- cache Vite et distribution frontend maintenus hors dépôt ;
- audit de distribution étendu au host Web direct ;
- enregistrement sous `history/0.3.0/0-pre.3.md` des validations utilisateur de `0-pre.3`.
## Hors périmètre
- lifecycle complet navigateur ;
- assets runtime du POC ;
- logging structuré Web ;
- `RuntimeProvenance` ;
- Tauri Snake ;
- Android ;
- extraction d'une abstraction Web commune non encore justifiée.
## Validation demandée
Depuis la racine :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo check --workspace
cargo clippy -p game-snake-poc-wasm --all-targets --all-features -- -D warnings
cargo test -p game-snake-poc-wasm
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
npm run dev
```
Smoke navigateur : ouvrir `http://127.0.0.1:1434/main.html`, puis vérifier le chargement WASM, le Canvas, les quatre familles d'entrées prévues et le comportement responsive Desktop/mobile.
## Suite
`0-pre.5` ferme l'intégration plateforme du POC : lifecycle/resize complet, assets, logging, provenance runtime et non-régression Desktop SDL3.

View File

@@ -0,0 +1,77 @@
<!-- file: deltas/0.3.0/0-pre.5.fix.1.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.5.fix.1
## Objectif
Corriger uniquement l'exposition des assets runtime du host Snake Web en développement, après validation partielle de `0-pre.5`.
## Défaut confirmé
`cargo`, WASM, `wasm-bindgen` et le build Vite passent. Sous `vite dev`, le frontend échoue néanmoins avant le démarrage du jeu lors de `fetchJson()` : les routes `common/data/runtime.json` et `game/data/game.json` ne sont pas servies comme attendu.
Les targets `vite-plugin-static-copy` utilisent des chemins source absolus. Le plugin conserve la structure source par défaut ; le `dest` seul ne constitue donc pas le contrat de route recherché.
## Correction
Les deux targets Vite utilisent désormais :
```text
rename: { stripBase: true }
```
Le contrat devient explicitement :
```text
assets/common/data/runtime.json -> /common/data/runtime.json
assets/game-snake-poc/data/game.json -> /game/data/game.json
```
Ces routes doivent être identiques sous `vite dev` et dans `dist/`. Aucun asset source n'est dupliqué sous `Web/`.
## Garde-fou
`audit_distribution_layout.py` exige désormais `stripBase: true` sur les deux targets, en plus des namespaces `common/data` et `game/data`.
## Historique
`history/0.3.0/0-pre.5.md` consigne la validation partielle fournie par l'utilisateur et le défaut runtime exact.
## Non modifié
- gameplay Snake ;
- adapter WASM/provenance ;
- lifecycle/resize ;
- logging frontend ;
- SimpleBar/Canvas ;
- runner Desktop SDL3 ;
- ROADMAP et CHANGELOG.
## Validation demandée
Depuis la racine :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p engine-v1-platform-api --all-targets --all-features
cargo test -p game-snake-poc-wasm --all-targets --all-features
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
cargo tree -p game-snake-poc-wasm --edges normal
(cd Web/game-snake-poc && npm install && npm run build && npm run dev)
```
Smoke sur `http://127.0.0.1:1434/main.html` :
1. `Assets` doit passer de `chargement…` à `snake / engine-v1` ;
2. Snake doit démarrer ;
3. la provenance doit quitter `unknown / unknown` dès qu'une classe/device et une entrée sont observées ;
4. revalider lifecycle/resize/SimpleBar/Canvas/contrôles ;
5. terminer par `cargo run -p game-snake-poc-desktop` pour la non-régression SDL3.

118
deltas/0.3.0/0-pre.5.md Normal file
View File

@@ -0,0 +1,118 @@
<!-- file: deltas/0.3.0/0-pre.5.md -->
<!-- version: 1 -->
# Delta 0.3.0-0-pre.5
## Objectif
Fermer l'intégration plateforme du premier POC Snake Web direct après validation de `0-pre.4.fix.3` : lifecycle/resize navigateur, assets runtime, logging frontend structuré, provenance `Web/Wasm/Browser` et non-régression du runner Desktop SDL3.
## État précédent validé
`0-pre.4.fix.3` a été accepté par l'utilisateur le 2026-09-20 : build Vite propre et smoke visuel/fonctionnel conforme, y compris Canvas portrait, contrôles et scroll SimpleBar du shell KSP-derived. Le résultat est consigné sous `history/0.3.0/0-pre.4.fix.3.md`.
## Lifecycle et resize
Le host Web ne laisse plus une boucle `requestAnimationFrame` implicite posséder tout le lifecycle :
- `SnakeWebSession` expose `pause`, `resume`, `renderNow`, `refreshDeviceClass` et `dispose` ;
- `visibilitychange` et `pagehide` suspendent les ticks ;
- la reprise réinitialise l'origine temporelle et l'accumulateur afin d'éviter un rattrapage massif après un onglet caché ;
- `pageshow` reprend et redessine ;
- `ResizeObserver` redessine le Canvas et rafraîchit la classe d'appareil sans faire avancer la simulation ;
- la destruction de page libère l'instance WASM.
Le fixed-step gameplay reste dans Rust/WASM et aucun événement lifecycle n'est ajouté à `game-snake-poc`.
## Assets Web
Le package Vite déclare `vite-plugin-static-copy` et package explicitement les deux assets-sondes depuis les sources canoniques :
```text
assets/common/data/runtime.json -> common/data/runtime.json
assets/game-snake-poc/data/game.json -> game/data/game.json
```
`frontend/ts/assets.ts` charge et valide les deux JSON avant le démarrage WASM. Le shell affiche ensuite un statut d'assets afin que le smoke confirme le chargement réel. Aucune copie source durable n'est créée sous `Web/`.
## Logging navigateur
`frontend/ts/logging.ts` centralise les diagnostics Web sous forme d'événements `level / target / action / fields` vers la console du navigateur.
Ce logging est spécifique au frontend navigateur direct :
- il ne dépend pas de Tauri ;
- il ne remplace pas `tracing` dans le code Rust ;
- les runners natifs continuent d'utiliser `game-logging-lib`.
## Provenance runtime
`game-snake-poc-wasm` dépend désormais de `engine-v1-platform-api` et conserve une `RuntimeProvenance` réelle.
Dimensions fixes :
```text
PlatformFamily = Web
ExecutionModel = Wasm
RuntimeHost = Browser
```
Le host renseigne ensuite la classe `Desktop/Phone/Tablet/Unknown` et le profil d'entrée `Unknown/KeyboardMouse/Touch/Mixed` selon les capacités et inputs observés. Ces dimensions sont exposées par le bridge WASM et affichées dans le shell.
La crate de gameplay `game-snake-poc` reste sans dépendance plateforme.
## Règles et documentation
- `GAME-ASSET-007` fixe le packaging Web `common/` + `game/` sans copie source ;
- `GAME-TRACE-005` distingue logging frontend navigateur et tracing Rust ;
- `GAME-PLATFORM-024` fixe pause/reprise sans catch-up massif ;
- `GAME-PLATFORM-025` fixe la provenance navigateur via `engine-v1-platform-api` ;
- l'architecture assets/provenance, la documentation tracing/frontend et les gates sont réconciliées ;
- `audit_distribution_layout.py` vérifie désormais les fichiers et branchements statiques de cette intégration.
## Non modifié
- règles de gameplay Snake ;
- runner Snake Desktop SDL3 ;
- moteur SDL3 ;
- Android/Tauri ;
- ROADMAP et CHANGELOG, réservés à la consolidation prévue par le plan.
## Validation demandée
Depuis la racine :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p engine-v1-platform-api --all-targets --all-features
cargo test -p game-snake-poc-wasm --all-targets --all-features
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
cargo tree -p game-snake-poc-wasm --edges normal
(cd Web/game-snake-poc && npm install && npm run build && npm run dev)
```
Smoke navigateur sur `http://127.0.0.1:1434/main.html` :
1. vérifier que `Assets` passe à `snake / engine-v1` avant le statut `Prêt` ;
2. vérifier que la provenance affiche `web / browser / wasm / ... / ...` ;
3. utiliser clavier/souris puis tactile si disponible et vérifier l'évolution du profil d'entrée (`keyboard-mouse`, `touch` ou `mixed`) ;
4. masquer l'onglet quelques secondes puis revenir : Snake ne doit pas accélérer pour rattraper le temps caché ;
5. redimensionner la fenêtre : Canvas et provenance device doivent rester cohérents sans saut de gameplay ;
6. revalider SimpleBar, clavier et contrôles pointer/tactiles.
Puis vérifier la non-régression Desktop :
```bash
cargo run -p game-snake-poc-desktop
```
## Suite
Si cette gate ne révèle ni duplication structurante ni défaut de frontière, la tranche conditionnelle `0-pre.6` est omise et la version peut entrer directement en `2-beta.1`. Sinon, `0-pre.6` ne traite que la correction/extraction prouvée par cette validation.

64
deltas/0.3.0/2-beta.1.md Normal file
View File

@@ -0,0 +1,64 @@
<!-- file: deltas/0.3.0/2-beta.1.md -->
<!-- version: 1 -->
# Delta 0.3.0-2-beta.1
## Objectif
Entrer en beta avec un scope `0.3.0` feature-complete et exécuter une validation large du POC Snake Web direct et de son témoin Desktop SDL3, sans introduire de nouveau comportement.
## Baseline acceptée
`0.3.0-0-pre.5.fix.1` est validée : audits, check/Clippy, tests plateforme/WASM, build WASM, build Vite, assets/provenance/inputs dans le navigateur et smoke Desktop SDL3 passent. Aucun défaut structurel ne justifie `0-pre.6`, qui est donc omise.
## Changements
- passage de la version workspace à `0.3.0-2-beta.1` ;
- passage du package frontend Snake Web au jalon `0.3.0-2-beta.1` ;
- ajout de l'historique validé `0-pre.5.fix.1` ;
- réconciliation du plan `0.3.0` avec l'omission de `0-pre.6` ;
- documentation de la gate beta release Web/Desktop.
Aucun gameplay, bridge WASM, runtime SDL3, shell HTML/TypeScript ou contrat d'asset n'est modifié par cette tranche.
## Validation attendue
Depuis la racine :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android 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
```
Build et smoke Desktop Snake release :
```bash
cargo build -p game-snake-poc-desktop --release
../builds/sasedev-games/target/release/game-snake-poc-desktop
```
Build WASM release et frontend production :
```bash
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-web/wasm \
--out-name game_snake_poc_wasm
(cd Web/game-snake-poc && npm install && npm run build && npm run preview)
```
Ouvrir `http://127.0.0.1:4174/main.html` puis vérifier : jeu visible, clavier/pointer, ratio Canvas, SimpleBar, assets `snake / engine-v1`, provenance cohérente, resize et pause/reprise sans rattrapage massif après masquage d'onglet.
## Après validation
Si cette gate beta est propre, la tranche suivante est `0.3.0-2-beta.2` pour la consolidation documentaire et la transmission : plan, documentation durable, `CHANGELOG.md`, `ROADMAP.md`, history et prompt de la version/session suivante.

View File

@@ -0,0 +1,67 @@
<!-- file: deltas/0.3.0/2-beta.2.fix.1.md -->
<!-- version: 1 -->
# Delta 0.3.0-2-beta.2.fix.1
## Base requise
`0.3.0-2-beta.2` validée mécaniquement par l'utilisateur le 2026-09-20.
## Objectif
Corriger la transmission documentaire de `2-beta.2` : rendre le prompt `0.3.1` suffisamment autonome pour limiter les rappels conversationnels et les fixes évitables, sans reproduire l'intégralité des règles KSP ni modifier le code/runtime.
## Changements
- enrichissement de `prompts/003-V0_3_1_START_PROMPT.md` avec ordre de lecture, handoff `0.3.0`, cadrage `pre.1`, invariants Tauri/Android/WASM, documentation, commandes, validations, forecast et condition de fin de session ;
- ajout de `docs/rules/PROMPT_STRUCTURE.md`, inspiré du principe KSP de prompt autonome mais volontairement plus compact ;
- ajout de règles explicites sur le rôle de `deltas/`/`history/`, le timing `ROADMAP`/`CHANGELOG`/prompt suivant et la séparation des validations utilisateur ;
- ajout d'une politique `DOC-CRATE-*` pour décider utilement de `README.md`/`USAGE.md` sans créer de fichiers cérémoniels ;
- clarification du cycle du prompt suivant : rédaction pendant la consolidation, vérification/complément à la première RC gelée ;
- clarification du versionnement des fixes strictement documentaires : le delta porte `.fix.1` mais `workspace.package.version` et les packages runtime restent `0.3.0-2-beta.2` ;
- ajout de `history/0.3.0/2-beta.2.md` avec les résultats réellement validés et le motif humain du fix ;
- réconciliation du plan `0.3.0` avec ce correctif de transmission.
`CHANGELOG.md` et `ROADMAP.md` ne sont pas modifiés : le fix ne change ni la publication candidate ni le scope produit.
## Fichiers ajoutés
```text
docs/rules/PROMPT_STRUCTURE.md
history/0.3.0/2-beta.2.md
deltas/0.3.0/2-beta.2.fix.1.md
```
## Fichiers modifiés
```text
RULES.md
docs/000-README.md
docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md
docs/rules/RULES_DOCUMENTATION.md
docs/rules/RULES_SESSION_PLANNING.md
docs/rules/VERSION_WORKFLOW.md
prompts/003-V0_3_1_START_PROMPT.md
```
## Fichiers supprimés
Aucun.
## Version technique
Ce correctif est strictement documentaire. Conformément à `VER-DOCFIX-001`, il ne modifie ni `workspace.package.version` ni la version du package Web : la version technique reste `0.3.0-2-beta.2`.
## Validation attendue
```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 build Cargo/npm ni smoke n'est requis pour ce fix : aucun fichier consommé par le build/runtime n'est modifié.
## Après validation
Si la revue humaine du prompt enrichi est satisfaisante, ouvrir `0.3.0-3-rc.1` et appliquer la matrice RC. La RC vérifie/complète le prompt `0.3.1`, écrit l'entrée RC du `CHANGELOG.md` et ne rouvre pas le scope fonctionnel.

View File

@@ -0,0 +1,66 @@
<!-- file: deltas/0.3.0/2-beta.2.fix.2.md -->
<!-- version: 1 -->
# Delta 0.3.0-2-beta.2.fix.2
## Base requise
`0.3.0-2-beta.2.fix.1`.
## Objectif
Finaliser la gouvernance des commandes et des validations transmise au prompt `0.3.1`, afin d'éviter les gates surdimensionnées, les logs pollués et les workflows Tauri incorrects.
Ce correctif est strictement documentaire. Il ne modifie aucun code, manifeste runtime, dépendance, configuration de build ni version technique.
## Décisions consolidées
- un fix strictement documentaire ne modifie aucune version Cargo/npm/Gradle/Tauri/Android ou autre version consommée par le runtime/build ;
- tout changement de code Rust, manifeste Cargo, feature ou dépendance Rust déclenche `cargo fmt --all`, `cargo fmt --all -- --check`, `cargo check --workspace` puis `cargo clippy --workspace --all-targets --all-features -- -D warnings` ;
- les audits Python sont sélectionnés selon les fichiers réellement touchés ;
- `cargo test -p <crate> --all-targets --all-features` est la stratégie normale ;
- `cargo test --workspace --all-targets --all-features` est réservé à un ou quelques jalons explicitement planifiés ou à une portée transverse incertaine ;
- `cargo tree` n'est exécuté que si les dépendances/features changent ou qu'un diagnostic de frontière le justifie ;
- toute commande nécessitant un changement de répertoire utilise `(cd <dir> && <commande>)` ;
- dans une app Tauri, npm sert à gérer les dépendances frontend ; les smokes passent par `cargo tauri dev` et le packaging final/prefinal par `cargo tauri build`, les hooks Tauri possédant Vite/TypeScript/WASM.
## Fichiers ajoutés
```text
history/0.3.0/2-beta.2.fix.1.md
deltas/0.3.0/2-beta.2.fix.2.md
```
## Fichiers modifiés
```text
docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md
docs/rules/PROMPT_STRUCTURE.md
docs/rules/RULES_COMMANDS.md
docs/rules/RULES_SESSION_PLANNING.md
docs/rules/RULES_VALIDATION_MATRIX.md
docs/rules/VERSION_WORKFLOW.md
prompts/003-V0_3_1_START_PROMPT.md
```
## Fichiers supprimés
Aucun.
## Version technique
Aucune version technique n'est modifiée. La workspace et le package Web restent `0.3.0-2-beta.2`.
## Validation attendue
Les seuls fichiers touchés sont Markdown. L'audit applicable est donc :
```bash
python3 scripts/audit_markdown_tables.py docs prompts deltas history
```
Aucun `cargo fmt`, `cargo check`, Clippy, test Cargo, `cargo tree`, audit de distribution, npm, Tauri ou smoke n'est requis pour ce correctif documentaire.
## Après validation
Si la revue humaine confirme ces règles, ouvrir `0.3.0-3-rc.1`. La RC appliquera la matrice finale, écrira l'entrée RC du `CHANGELOG.md` et vérifiera une dernière fois le prompt `0.3.1` sans rouvrir le scope fonctionnel.

45
deltas/0.3.0/2-beta.2.md Normal file
View File

@@ -0,0 +1,45 @@
<!-- file: deltas/0.3.0/2-beta.2.md -->
<!-- version: 1 -->
# Delta 0.3.0-2-beta.2
## Objectif
Consolider la version feature-complete après validation de `2-beta.1`, préparer le gel RC et transmettre un contexte autonome à `0.3.1`, sans modifier le comportement runtime.
## Baseline acceptée
`0.3.0-2-beta.1` est validée : audits, format/check/Clippy, 34 tests workspace, Desktop Snake release et Web/WASM release passent.
## Changements
- passage de la version workspace et du package Web à `0.3.0-2-beta.2` ;
- ajout de `history/0.3.0/2-beta.1.md` ;
- classement des lignes `0.3.0` réellement livrées dans `ROADMAP.md` ;
- ajout d'une baseline architecturale consolidée du POC Snake Web direct ;
- ajout d'une matrice RC spécifique à `0.3.0` ;
- réconciliation de l'étude `pre.1` avec le contrat autoritaire des archives de tag ;
- mise à jour du plan actif avec le résultat beta ;
- ajout du prompt `003-V0_3_1_START_PROMPT.md` pour le second host Snake Tauri Android.
`CHANGELOG.md` est revu mais ne reçoit pas d'entrée beta : `DOC-CHG-002` et `DOC-CHG-003` réservent la synthèse publiée aux RC et stables. La matière de la future entrée RC est consolidée dans les documents durables de cette tranche.
## Validation attendue
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
python3 scripts/audit_distribution_layout.py
cargo check --workspace
(cd Web/game-snake-poc && npm install && npm run build)
```
Aucun test/smoke complet n'est requis par ce delta documentaire + métadonnées : `2-beta.1` vient de valider les artefacts release, et aucun code/runtime n'est modifié.
## Après validation
Si cette consolidation est acceptée, produire `0.3.0-3-rc.1` : gel fonctionnel, entrée RC du `CHANGELOG.md`, historique `2-beta.2`, réexécution de la matrice RC et vérification finale du prompt `0.3.1`.

88
deltas/0.3.0/3-rc.1.md Normal file
View File

@@ -0,0 +1,88 @@
<!-- file: deltas/0.3.0/3-rc.1.md -->
<!-- version: 1 -->
# Delta 0.3.0-3-rc.1
## Base requise
`0.3.0-2-beta.2.fix.2`.
Cette base a été validée par revue humaine et audit Markdown proportionnel au correctif documentaire.
## Objectif
Créer la candidate de publication `0.3.0` sans rouvrir le scope fonctionnel.
## Gel RC
Le scope `0.3.0` est gelé. Cette tranche n'ajoute :
- aucune fonctionnalité ;
- aucune capability ;
- aucun refactor architectural ;
- aucune dépendance ;
- aucun changement de gameplay ou de runtime.
Seuls les correctifs autorisés par `VER-RC-*` pourront suivre sous `3-rc.1.fix.N`.
## Changements
- passage de `workspace.package.version` à `0.3.0-3-rc.1` ;
- passage du package Web Snake à `0.3.0-3-rc.1` ;
- affichage de la candidate courante dans `README.md` ;
- création de l'entrée RC `0.3.0-3-rc.1` dans `CHANGELOG.md` ;
- enregistrement de la validation `2-beta.2.fix.2` sous `history/0.3.0/` ;
- réconciliation du plan `0.3.0` avec l'ouverture de la RC ;
- revue finale de `prompts/003-V0_3_1_START_PROMPT.md` : aucune modification supplémentaire requise.
Les métadonnées Android historiques restent inchangées : `0.3.0` ne livre pas un nouveau host Android. Le package Tauri Reflex historique reste également hors scope.
## Validation RC
Appliquer `docs/testing/004-V0_3_0_RC_VALIDATION_MATRIX.md`.
### Gate workspace
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android 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
```
Le test workspace complet est volontairement exécuté à ce jalon RC final. Aucun `cargo tree` n'est requis puisque les dépendances/features ne changent pas.
### Desktop Snake release
```bash
cargo build -p game-snake-poc-desktop --release
../builds/sasedev-games/target/release/game-snake-poc-desktop
```
Critères : démarrage, rendu, contrôles et arrêt propre.
### Web/WASM release
```bash
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-web/wasm \
--out-name game_snake_poc_wasm
(cd Web/game-snake-poc && npm install && npm run build && npm run preview)
```
Ouvrir `http://127.0.0.1:4174/main.html` et confirmer Canvas, inputs, SimpleBar, assets, provenance, resize, lifecycle et absence d'erreur runtime bloquante.
## Après validation
Si la gate RC est propre et qu'aucun correctif n'est nécessaire, la promotion vers `0.3.0` est mécanique : versions stables, entrée stable du `CHANGELOG.md`, historique RC et delta de release, sans nouveau scope.

54
deltas/0.3.0/rel.001.md Normal file
View File

@@ -0,0 +1,54 @@
<!-- file: deltas/0.3.0/rel.001.md -->
<!-- version: 1 -->
# Delta 0.3.0 — release stable
## Base
Base validée : `0.3.0-3-rc.1`.
## Objet
Promouvoir mécaniquement la candidate validée vers `0.3.0` sans introduire de nouveau comportement.
## Changements
La release stable :
- passe `workspace.package.version` de `0.3.0-3-rc.1` à `0.3.0` ;
- passe le package frontend Web Snake de `0.3.0-3-rc.1` à `0.3.0` ;
- positionne `README.md` sur la stable `0.3.0` et indique `0.3.1` comme prochaine version planifiée mais non démarrée ;
- ajoute l'entrée stable `0.3.0` dans `CHANGELOG.md` ;
- enregistre la validation effective de la RC dans `history/0.3.0/3-rc.1.md` ;
- clôt le plan `0.3.0` et réconcilie la baseline architecturale avec l'état effectivement publié.
Les métadonnées Android et le package frontend Reflex/Tauri ne sont pas modifiés : ils n'appartiennent pas au chemin de distribution ajouté par `0.3.0`.
Le prompt `prompts/003-V0_3_1_START_PROMPT.md` est conservé tel que validé en RC.
## Frontière de release
Aucun changement de gameplay, de Rust source, de dépendance, de build frontend, 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 donc que les gates proportionnelles au changement de version et à la documentation :
```bash
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md CHANGELOG.md docs deltas history
cargo check --workspace
(cd Web/game-snake-poc && npm install && npm run build)
```
`cargo fmt`, Clippy, la suite workspace complète, `cargo tree`, l'audit de distribution et les smokes ne sont pas répétés : cette promotion ne touche ni code Rust, ni dépendance, ni layout de distribution, et ces gates ont déjà été validées sur `0.3.0-3-rc.1` fonctionnellement identique.
## Publication
Après validation de ce delta :
- commit de release ;
- tag stable `v0.3.0` ;
- prochaine session ouverte uniquement à partir de la stable taggée `v0.3.0` et de `prompts/003-V0_3_1_START_PROMPT.md`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/000-README.md -->
<!-- version: 18 -->
<!-- version: 27 -->
# Documentation games.sasedev
@@ -7,6 +7,16 @@
- [`objectives/001-PROJECT_OBJECTIVES.md`](objectives/001-PROJECT_OBJECTIVES.md) — finalité, principes structurants, stratégie de construction et vision du SDK.
## Idées et études
- [`ideas/000-README.md`](ideas/000-README.md) — rôle des idées non engagées et règles de maturation.
- [`studies/000-README.md`](studies/000-README.md) — rôle des études comparatives non normatives.
## 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.
## Architecture
- [`architecture/001-WORKSPACE_ARCHITECTURE.md`](architecture/001-WORKSPACE_ARCHITECTURE.md) — workspace, générations de moteur, jeux, runners, assets et Android.
@@ -17,6 +27,12 @@
- [`architecture/009-ENGINE_V1_RENDER_SCENE.md`](architecture/009-ENGINE_V1_RENDER_SCENE.md) — scène 2D portable, rectangles normalisés et backend SDL3.
- [`architecture/010-RUNTIME_PROVENANCE.md`](architecture/010-RUNTIME_PROVENANCE.md) — provenance plateforme/device/runtime/input pour sessions, scores et analytics.
- [`architecture/011-POST_0_1_0_DIRECTION.md`](architecture/011-POST_0_1_0_DIRECTION.md) — décisions de transition entre le POC stable 0.1.0 et la conception modulaire 0.2.0.
- [`architecture/012-MODULAR_LAYERING_AND_OWNERSHIP.md`](architecture/012-MODULAR_LAYERING_AND_OWNERSHIP.md) — architecture durable kernel/capabilities/game-systems/games/adapters/providers/services/tooling.
- [`architecture/013-NETWORK_AND_SERVER_ARCHITECTURE.md`](architecture/013-NETWORK_AND_SERVER_ARCHITECTURE.md) — Web/API, realtime, transports, asset delivery auto-hébergé et frontières serveur.
- [`architecture/014-UROBURAS_TARGET_ARCHITECTURE.md`](architecture/014-UROBURAS_TARGET_ARCHITECTURE.md) — ownership cible des besoins Uroburas et ordre Mode 1 → Mode 3 → Mode 2.
- [`architecture/015-PLATFORM_POC_ARCHITECTURE.md`](architecture/015-PLATFORM_POC_ARCHITECTURE.md) — rôle des POC `0.3.x`, Snake comme sonde et critères d'extraction.
- [`architecture/016-V0_2_0_CONSOLIDATED_BASELINE.md`](architecture/016-V0_2_0_CONSOLIDATED_BASELINE.md) — synthèse de la baseline destinée au gel RC `0.2.0`.
- [`architecture/017-V0_2_0_RC_REVIEW.md`](architecture/017-V0_2_0_RC_REVIEW.md) — checklist de cohérence et scope gelé de la candidate `0.2.0-3-rc.1`.
## Jeux
@@ -40,7 +56,7 @@
## Règles
Voir [`../RULES.md`](../RULES.md), notamment [`rules/RULES_COMMANDS.md`](rules/RULES_COMMANDS.md) pour la politique d'exécution des commandes.
Voir [`../RULES.md`](../RULES.md), notamment [`rules/RULES_DOCUMENTATION.md`](rules/RULES_DOCUMENTATION.md) pour la gouvernance documentaire, [`rules/RULES_COMMANDS.md`](rules/RULES_COMMANDS.md) pour la politique d'exécution, [`rules/RULES_VALIDATION_MATRIX.md`](rules/RULES_VALIDATION_MATRIX.md) pour la matrice des gates, [`rules/RULES_SESSION_PLANNING.md`](rules/RULES_SESSION_PLANNING.md) pour le cadrage des sessions, [`rules/PROMPT_STRUCTURE.md`](rules/PROMPT_STRUCTURE.md) pour le contrat des prompts de reprise et [`rules/RULES_SERVER_HOSTING.md`](rules/RULES_SERVER_HOSTING.md) pour la portabilité d'auto-hébergement.
## Validation
@@ -52,12 +68,16 @@ Voir [`../RULES.md`](../RULES.md), notamment [`rules/RULES_COMMANDS.md`](rules/R
- [`testing/001-TEST_ARCHITECTURE.md`](testing/001-TEST_ARCHITECTURE.md) — séparation `unit_tests/` / `tests/`, tests ciblés et tracing de test.
- [`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.
- [`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.
- [`development/006-ANDROID_RUST_NATIVE_BUILD.md`](development/006-ANDROID_RUST_NATIVE_BUILD.md) — build `cdylib` Rust Android, cargo-ndk, packaging `jniLibs` et symbole `SDL_main`.
- [`development/007-ANDROID_JNI_BRIDGE.md`](development/007-ANDROID_JNI_BRIDGE.md) — frontière Java/JNI minimale, version de contrat et séparation avec l'input SDL3.
- [`development/008-WASM_TAURI_POC.md`](development/008-WASM_TAURI_POC.md) — baseline historique Reflex Tauri/WebAssembly et génération WASM associée.
- [`development/009-SNAKE_WEB_WASM_BUILD.md`](development/009-SNAKE_WEB_WASM_BUILD.md) — build Cargo + `wasm-bindgen` natif de l'adapter Snake pour le navigateur direct.
- [`development/010-SNAKE_WEB_FRONTEND.md`](development/010-SNAKE_WEB_FRONTEND.md) — host Web direct Snake sous Vite/TypeScript, shell Bootstrap 5, Canvas, lifecycle, assets, provenance et contrôles clavier/tactiles.
## Historique validé
- [`../history/README.md`](../history/README.md) — convention et navigation de l'historique transitoire immuable des jalons validés.
- [`../history/000-README.md`](../history/000-README.md) — convention et navigation de l'historique transitoire immuable des jalons validés.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/001-WORKSPACE_ARCHITECTURE.md -->
<!-- version: 5 -->
<!-- version: 7 -->
# Architecture du workspace
@@ -22,7 +22,8 @@ games.sasedev/
│ ├── game-reflex-poc-desktop/
│ ├── game-snake-poc-desktop/
│ ├── game-reflex-poc-tauri/
── game-reflex-poc-wasm/
── game-reflex-poc-wasm/
│ └── game-snake-poc-wasm/
├── assets/
│ ├── common/
│ ├── game-reflex-poc/
@@ -31,6 +32,8 @@ games.sasedev/
│ ├── common/
│ ├── game-reflex-poc/
│ └── game-snake-poc/
├── Web/
│ └── game-snake-poc/
├── docs/
├── deltas/
├── prompts/
@@ -69,15 +72,12 @@ Le runtime devra conserver une distinction logique entre ressources communes et
Chaque crate de jeu reste une bibliothèque. Une crate binaire Desktop séparée sous `crates/apps/` la consomme pour permettre les itérations locales rapides. Cette séparation évite dintroduire `main`, des choix de plateforme ou du code de lancement dans le gameplay réutilisable.
## Variante Tauri / WebAssembly
## Adapters WebAssembly et variante Tauri
La variante Tauri est distincte du runner SDL3 natif.
Les adapters WASM sont distincts des runners SDL3 natifs et ne déplacent aucune règle de gameplay hors des crates de jeu.
`game-reflex-poc-tauri` porte deux faces du même launcher :
`game-reflex-poc-wasm` adapte le POC Reflex à `wasm-bindgen` pour le host Tauri/WebView existant. `game-snake-poc-wasm` adapte séparément Snake pour le premier host navigateur direct de `0.3.0`. Dans les deux cas, l'adapter expose l'état et la scène portable ; il ne possède pas les règles du jeu.
- une bibliothèque `wasm32-unknown-unknown` qui adapte `game-reflex-poc` à `wasm-bindgen` ;
- un binaire natif Tauri qui héberge la WebView locale.
`game-reflex-poc-tauri` reste le binaire natif Tauri qui héberge la WebView Reflex locale. Son frontend Vite/TypeScript pilote un Canvas et appelle l'adapter Reflex WASM. La crate Tauri suit le modèle des apps Desk KSP : façade `lib.rs`, pont `tauri.rs`, modules propriétaires séparés et frontend local à la crate.
Le frontend statique sous `Tauri/game-reflex-poc/frontend/` pilote un Canvas et appelle l'adaptateur WASM. Les règles Reflex restent exclusivement dans `game-reflex-poc`.
La crate Tauri suit le modèle des apps Desk KSP : façade `lib.rs`, pont `tauri.rs`, modules propriétaires séparés et frontend Vite/TypeScript local à la crate.
Le host Web Snake direct réside sous `Web/game-snake-poc/`. Ce package Vite/TypeScript consomme `game-snake-poc-wasm`, reprend la structure HTML/Sass/TypeScript et le thème Bootstrap/Bootswatch des applications Desk KSP sans dépendre de Tauri, traduit clavier/tactile vers les quatre directions logiques et dessine l'`EngineScene` dans un Canvas. Il reste extérieur au workspace Cargo et ne contient aucune règle de gameplay.

View File

@@ -15,17 +15,26 @@ Engine API
SDL3 boundary
┌───┼───────────────┐
│ │ │
Desktop Android Web
native SDL/JNI WASM/browser
Desktop Mobile Web
SDL native SDL/native WASM/browser
│ │
Linux/Windows/ Android/iOS
macOS
```
## Desktop
La famille Desktop réserve Linux, Windows et macOS. Leur support effectif dépend des backends, bibliothèques et contraintes de distribution disponibles au moment de l'implémentation.
Le runner Desktop est la cible d'itération la plus rapide. Il utilise la crate lib du jeu et, à terme, le runtime SDL3 natif. Les entrées disponibles peuvent inclure clavier, souris, trackpad, gamepad et joystick.
La cible Desktop sert à tester le gameplay, le rendu, la boucle de jeu, l'audio et les abstractions communes sans imposer un déploiement sur émulateur ou téléphone.
## Android
## Mobile
La famille Mobile réserve Android et iOS. Téléphone et tablette sont des classes de device et ne doivent pas être confondus avec l'OS ou le backend de rendu.
### Android
Android empaquette le jeu natif dans une application standard. La structure cible combine : SDL3 Android, une bibliothèque native Rust, la couche Java commune, les extensions Java spécifiques au jeu, les assets communs et spécifiques, puis les SDK Android requis.
@@ -33,6 +42,10 @@ Les fonctionnalités suivantes restent côté plateforme Android : lifecycle, JN
Le gameplay Rust ne doit pas dépendre des classes Java ni d'une régie publicitaire particulière.
### iOS
iOS est une cible réservée pour une évolution future. Aucun support de distribution iOS n'est exigé dans le POC actuel. L'architecture ne doit toutefois pas introduire une dépendance structurelle qui rendrait impossible un backend SDL/native ou un adapter iOS ultérieur.
## Web / WASM
La cible Web est prévue comme cible ultérieure. SDL3 peut être utilisé avec une chaîne Web adaptée, notamment Emscripten, tandis que le navigateur fournit ses propres contraintes de boucle d'événements, audio, stockage, permissions et interaction utilisateur.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/004-INPUT_AND_CONTROLS.md -->
<!-- version: 7 -->
<!-- version: 9 -->
# Abstraction des entrées et contrôles
@@ -97,6 +97,22 @@ Pour souris et tactile :
Reflex conserve son impulsion `Primary` sur `Down` et reste donc indépendant de la reconnaissance du swipe.
## Baseline Snake portable `0.3.0`
La crate `game-snake-poc` consomme uniquement le contrat générique `engine-v1-common` pour son gameplay. Elle ne dépend pas de `engine-v1-platform-api`, de SDL3, du DOM ou d'un type de périphérique concret.
Le contrat d'entrée Snake retenu pour le premier POC Web est volontairement minimal :
- `Left`, `Right`, `Up` et `Down` pilotent la direction ;
- le rejet d'un demi-tour opposé reste une règle du gameplay Snake ;
- `Primary`, `Secondary`, `Pause` et le pointeur normalisé ne sont pas requis par le gameplay Snake actuel ;
- le host traduit clavier, swipe ou boutons virtuels vers les mêmes actions directionnelles ;
- le rendu reste exposé par `EngineGame::scene` sous forme d'`EngineScene`, sans dépendance au Canvas ou à SDL3.
L'adapter WASM de `0-pre.3` adapte ce contrat existant plutôt que créer un second modèle d'entrée ou de rendu propre au Web. Il mémorise au plus une direction logique en attente ; `tick()` la consomme pour le prochain update puis remet l'entrée en attente à zéro. Un événement clavier ou tactile ne fait donc pas avancer la simulation à lui seul.
Le host Web reste responsable de transformer ses événements physiques ou widgets en appels `left`, `right`, `up` ou `down`, puis de piloter la cadence des `tick()`. Les besoins de provenance, monétisation ou autres services plateforme appartiennent au host/launcher et ne justifient pas une dépendance plateforme inutilisée dans la crate de gameplay.
## Requête de sortie
La plateforme ne décide plus directement de terminer un jeu. Elle traduit l'événement physique en `QuitRequest` :

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/005-ASSET_ARCHITECTURE.md -->
<!-- version: 3 -->
<!-- version: 4 -->
# Architecture des assets
@@ -92,3 +92,16 @@ assets/game/...
```
Les répertoires `build/generated/` restent des artefacts jetables.
## Web navigateur direct
Le POC Snake Web valide le même espace logique sans copier les sources dans `Web/`. Vite package explicitement les assets nécessaires depuis `assets/` vers :
```text
dist/common/data/runtime.json
dist/game/data/game.json
```
Le serveur Vite de développement expose les mêmes URL runtime. Le frontend charge donc `common://data/runtime.json` et `game://data/game.json` sous leurs chemins de distribution `./common/data/runtime.json` et `./game/data/game.json`, puis valide leur schéma avant de démarrer la session.
Cette première intégration ne transforme pas encore `game-assets-lib` en loader navigateur : la librairie Rust reste responsable de la validation/résolution de chemins physiques pour les hosts qui disposent d'un filesystem, tandis que Vite possède le packaging Web. Une abstraction commune ne sera extraite que si plusieurs hosts en ont réellement besoin.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/010-RUNTIME_PROVENANCE.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# Provenance d'environnement d'exécution
@@ -72,3 +72,17 @@ L'identité joueur reste orthogonale. Un score pourra appartenir à un utilisate
La provenance V1 décrit des catégories techniques générales. Elle ne requiert ni modèle précis de téléphone, ni identifiant matériel, ni adresse réseau.
Un besoin futur de diagnostic plus fin devra être ajouté explicitement plutôt que d'élargir silencieusement cette structure.
## POC Snake Web direct
À partir de `0.3.0-0-pre.5`, `game-snake-poc-wasm` consomme réellement `engine-v1-platform-api` et conserve une `RuntimeProvenance` pour la session navigateur. Les dimensions fixes du host sont :
```text
PlatformFamily = Web
ExecutionModel = Wasm
RuntimeHost = Browser
```
Le frontend observe la classe d'appareil à partir des capacités de pointeur et de la taille logique de l'écran sans collecter de modèle matériel. Le profil d'entrée commence à `Unknown`, devient `KeyboardMouse` ou `Touch` lors de l'utilisation réelle et passe à `Mixed` si les deux familles sont observées pendant la même session.
Cette provenance est affichée dans le shell et émise dans les diagnostics frontend afin de rendre le smoke vérifiable. Elle reste descriptive et ne modifie ni le gameplay ni le score.

View File

@@ -0,0 +1,56 @@
<!-- file: docs/architecture/012-MODULAR_LAYERING_AND_OWNERSHIP.md -->
<!-- version: 1 -->
# Architecture modulaire et ownership
## Décision
Le framework est structuré par responsabilité et non par jeu ou plateforme unique.
```text
game-specific
game-systems
technical capabilities
engine kernel contracts
```
La composition produit ajoute latéralement les platform adapters, providers, server contracts et tooling.
## Engine kernel
Le kernel contient uniquement les primitives nécessaires à tous les jeux consommateurs : lifecycle, update/render, temps, runtime events, provenance et contrats minimaux input/render.
Il ne contient pas de logique Snake, publicité, authentification, HTTP ou règles Uroburas.
## Technical capabilities
Les capabilities fournissent des mécanismes techniques réutilisables : input, rendu 2D, audio, assets/content, localisation, persistence, networking et logging/telemetry.
## Game-systems
Les game-systems portent des mécaniques réutilisables entre jeux lorsque leur API est réellement justifiée : grid/tilemap, collision, caméra gameplay, stages, score, vies/attempts, timed entities, pickups/inventory et status effects lorsque leur généralisation devient réelle.
## Game-specific
Une crate jeu conserve les règles propres au jeu, la composition des systèmes et les concepts qui n'ont pas encore de second consommateur crédible.
Une mécanique n'est pas extraite uniquement parce qu'elle pourrait théoriquement servir ailleurs.
## Adapters, providers et services
Les adapters traduisent un environnement local. Les providers encapsulent un service externe. Le gameplay ne dépend pas directement d'un adapter ou SDK provider concret.
Les services serveur possèdent leurs modèles métier et leurs contrats de transport dédiés. Actix, Tungstenite, Protobuf ou Maud ne remontent pas dans le gameplay.
## Tooling
Éditeurs, build tooling, audits et outils de publication restent séparés du runtime du jeu.
## Création de crates
Une nouvelle crate est justifiée par une frontière stable ou un besoin de réutilisation réel.
Le projet évite à la fois la crate jeu monolithique et l'explosion artificielle en une crate par concept minuscule.

View File

@@ -0,0 +1,85 @@
<!-- file: docs/architecture/013-NETWORK_AND_SERVER_ARCHITECTURE.md -->
<!-- version: 1 -->
# Architecture réseau et serveur
## Web/API
La stack serveur Web de référence est :
```text
Tokio
Actix Web
Maud
Fluent / fluent-bundle
Lettre
```
Actix Web porte le Web/API, l'authentification, les comptes, Hall of Fame, metadata de contenu, reward authority et administration initiale.
## Realtime
Le realtime est séparé du Web/API classique.
Baseline :
```text
Tokio
tokio-tungstenite
WebSocket
```
Candidat à évaluer :
```text
WebTransport
QUIC
```
La simulation authoritative ne dépend directement d'aucun de ces transports.
## Frontière de transport
```text
transport
wire codec
session protocol
synchronization
authoritative simulation
```
Le client utilise une realtime transport API. WebSocket reste le fallback de référence. WebTransport est évalué lorsqu'il apporte un bénéfice mesuré.
## gRPC
`tonic`/gRPC est réservé aux frontières server-to-server qui le justifient. Il n'est pas un transport obligatoire entre le client public et le serveur realtime.
## Asset delivery
Les assets sont auto-hébergés par défaut.
```text
assets.games.sasedev.com
HTTP/2
HTTP/3/QUIC si disponible
```
H2 et H3 peuvent coexister sur le même hostname avec fallback.
Content metadata/authorization et transfert lourd d'assets sont deux responsabilités distinctes.
## Déploiement progressif
Une seule machine peut initialement héberger plusieurs services logiques.
L'architecture permet ensuite de séparer Web/API, Assets, Realtime, Database et Media/replay, puis de multiplier les nœuds selon la charge.
## Portabilité d'exploitation
Debian Stable est la cible opérationnelle préférée.
Le choix futur d'un edge/reverse proxy HTTP/3, stockage ou composant d'infrastructure reste reporté aux POC correspondants et doit tenir compte de la disponibilité/maturité sur Debian Stable.

View File

@@ -0,0 +1,74 @@
<!-- file: docs/architecture/014-UROBURAS_TARGET_ARCHITECTURE.md -->
<!-- version: 1 -->
# Architecture cible Uroburas
## Principe
Uroburas n'est pas une crate monolithique.
La crate jeu conserve ce qui décrit réellement Uroburas ; les mécanismes réutilisables, services serveur, intégrations provider et tooling vivent dans leurs couches respectives.
## Première trajectoire
```text
Mode 1 — Challenge
Mode 3 — Persistent Battle Royale
Mode 2 — PvP Battles
```
La première version réelle stabilise d'abord les moteurs du Mode 1.
## Réutilisable hors Uroburas
À implémenter comme capabilities ou game-systems lorsque les frontières sont suffisamment claires :
- input abstrait ;
- virtual directional controls ;
- rendu sprite/rotation ;
- grid/tilemap toroïdale ;
- collision ;
- caméra ;
- stages ;
- vies/attempts ;
- score ;
- timed entities ;
- pickups ;
- assets/content download/cache ;
- localisation Fluent ;
- networking client.
## Uroburas-specific
Reste spécifique au jeu au départ :
- anatomie tête + cou + corps extensible + queue ;
- longueur minimale de quatre unités ;
- mouvement Snake ;
- géométrie du corps ;
- règles propres aux maps Uroburas ;
- règles de run Challenge ;
- modes Uroburas ;
- combat feu/glace/poison/protections/téléporteurs tant qu'aucun second jeu ne justifie leur généralisation.
## Serveur Mode 1
La première trajectoire serveur couvre PlayerId/auth, comptes, map/asset metadata, contenu téléchargeable, Hall of Fame, rewarded continue, rewarded stage multiplier, validation/idempotence et échanges HTTP sécurisés/versionnés.
Le realtime n'est pas requis pour le Mode 1.
## Mode 3 puis Mode 2
Le Mode 3 introduit authoritative simulation, realtime transport, bots, spectator, snapshots/deltas, interest management, rejoin cooldown et persistent world lifecycle.
Le Mode 2 réutilise ensuite ces briques pour les matches bornés, privés, matchmaking, équipes et règles de vie.
## Tooling
Le map editor démarre lorsque le format de map est suffisamment stable.
Le skin editor vient après stabilisation du contrat graphique des skins.
Ils restent séparés du runtime du jeu.

View File

@@ -0,0 +1,47 @@
<!-- file: docs/architecture/015-PLATFORM_POC_ARCHITECTURE.md -->
<!-- version: 2 -->
# Architecture des POC plateforme et réseau
## Rôle de la série 0.3.x
La série `0.3.x` doit éprouver les frontières décidées en `0.2.0` avant le développement Uroburas réel.
Snake est le jeu-sonde principal.
## POC plateforme prioritaires
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 ;
- 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.
## 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.
Le même protocole métier doit pouvoir être exercé sur plusieurs transports.
## Build
Les builds utilisent Cargo, Gradle, Tauri CLI et les toolchains plateforme.
Python reste limité aux audits, validations complémentaires et contrôles statiques.
## Critère d'extraction
Un POC sert à identifier duplication, adapters manquants, capability réellement réutilisable, frontières mal placées et coût de maintenance.
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.
## Relation avec Uroburas
Les résultats des POC `0.3.x` déterminent les choix techniques conservés pour la trajectoire Uroburas `0.4.x`.
Le POC ne doit pas réimplémenter le futur jeu ; il valide ses fondations.

View File

@@ -0,0 +1,70 @@
<!-- file: docs/architecture/016-V0_2_0_CONSOLIDATED_BASELINE.md -->
<!-- version: 1 -->
# Baseline architecturale consolidée 0.2.0
## Statut
Ce document synthétise la baseline documentaire destinée à être gelée par la RC `0.2.0`.
## Framework
Le projet retient une architecture modulaire distinguant :
- engine kernel ;
- technical capabilities ;
- game-systems ;
- game-specific ;
- platform adapters ;
- providers ;
- server services ;
- tooling.
## POC
La série `0.3.x` valide les choix plateforme/réseau avec Snake comme jeu-sonde.
## Uroburas
La série `0.4.x` démarre le jeu réel Uroburas, d'abord Mode 1 Challenge.
Ordre produit actuel :
```text
Mode 1
→ Mode 3
→ Mode 2
```
## Réseau
- Actix Web pour Web/API ;
- Maud pour HTML server-side ;
- Fluent pour i18n ;
- Lettre pour email ;
- WebSocket/tokio-tungstenite baseline realtime ;
- WebTransport/QUIC candidat POC ;
- gRPC/Tonic conditionnel server-to-server ;
- asset delivery auto-hébergé H2/H3 selon disponibilité.
## Exploitation
Debian Stable est la cible opérationnelle préférée.
Le code métier reste indépendant de la version de distribution.
Les composants d'infrastructure spécifiques restent hors du domaine et seront choisis lors de POC/déploiements dédiés.
## Workflow
- `pre.1` cadre chaque version ;
- une version tient dans une session ;
- les tranches visent généralement 1530 minutes ;
- les dernières tranches consolident documentation, ROADMAP, CHANGELOG et prompt suivant ;
- la stable reste mécanique.
## Gel
La RC suivante ne doit plus ajouter de nouveau scope.
Toute découverte fonctionnelle majeure après gel est reportée vers `0.3.x`, `0.4.x` ou une version ultérieure selon sa nature.

View File

@@ -0,0 +1,58 @@
<!-- file: docs/architecture/017-V0_2_0_RC_REVIEW.md -->
<!-- version: 1 -->
# Revue RC 0.2.0
## Statut
Candidate `0.2.0-3-rc.1`.
Le scope fonctionnel et architectural de `0.2.0` est gelé.
## Cohérence documentaire
La candidate relie :
- études exploratoires ;
- architecture durable ;
- règles normatives ;
- ROADMAP ;
- CHANGELOG ;
- prompt `0.3.x`.
Les études restent la justification historique ; les documents d'architecture et de règles portent les décisions durables.
## Décisions gelées
- architecture kernel / capabilities / game-systems / game-specific ;
- séparation adapters/providers/apps ;
- Snake comme sonde `0.3.x` ;
- Uroburas comme trajectoire `0.4.x` ;
- ordre Uroburas Mode 1 → Mode 3 → Mode 2 ;
- Actix Web / Maud / Fluent / Lettre comme références Web ;
- WebSocket/tokio-tungstenite baseline realtime ;
- WebTransport/QUIC candidat POC ;
- gRPC/Tonic conditionnel server-to-server ;
- asset delivery auto-hébergé, H2 baseline et H3 candidat ;
- Debian Stable comme cible opérationnelle préférée ;
- `pre.1` obligatoire de cadrage ;
- versions dimensionnées pour une session ;
- tranches visant généralement 15 à 30 minutes ;
- stable mécanique.
## Hors gel
Restent volontairement à valider plus tard par POC :
- ordre exact des versions `0.3.x` après `0.3.0` ;
- choix définitif WebSocket vs WebTransport ;
- choix edge/reverse proxy H3 ;
- détails de packaging/infrastructure par plateforme ;
- abstractions réellement extraites après observation de duplication ;
- décisions techniques propres à Uroburas au-delà du Mode 1 initial.
## Critère de publication
Si les audits RC sont propres et qu'aucune incohérence documentaire n'est détectée, `0.2.0` stable doit être une promotion mécanique de cette candidate.
Aucun nouveau scope ne doit être ajouté entre RC et stable.

View File

@@ -0,0 +1,91 @@
<!-- file: docs/architecture/018-V0_3_0_WEB_SNAKE_BASELINE.md -->
<!-- version: 2 -->
# Baseline consolidée 0.3.0 — Snake Web direct
## Statut
Ce document consolide la baseline stable `0.3.0` du premier POC plateforme de la série `0.3.x`. La RC `0.3.0-3-rc.1` a été validée sans correctif supplémentaire ; cet état sert désormais de base au second host Snake prévu en `0.3.1`.
## Chaîne validée
Le chemin Web direct retenu est :
```text
game-snake-poc
game-snake-poc-wasm
↓ wasm-bindgen --target web
Web/game-snake-poc
Vite / TypeScript / Bootstrap 5 / Canvas
```
`game-snake-poc` reste indépendant de SDL3, DOM, Canvas, Tauri et des APIs plateforme. `game-snake-poc-wasm` adapte la scène et les entrées au host Web et porte la provenance runtime ; le frontend gère DOM, lifecycle navigateur, rendu Canvas et shell UI.
## Input et cadence
Les entrées navigateur sont converties vers les quatre actions Snake `Left`, `Right`, `Up`, `Down`. Une entrée ne fait pas avancer directement la simulation : la direction est mise en attente puis consommée au prochain `tick()` WASM.
Le host valide clavier, contrôles pointer/tactiles, resize et pause/reprise sans rattrapage massif après masquage d'onglet.
## Shell Web
Le frontend reprend les conventions utiles des applications Desk KSP sans dépendre de Tauri :
- Vite + TypeScript ;
- Bootstrap 5 / Bootswatch Pulse ;
- Font Awesome ;
- Sass ;
- SimpleBar et `resize-observer-polyfill` ;
- header/footer fixes et zone centrale scrollable ;
- Canvas conservant le ratio logique Snake `12 × 20`.
Le frontend reste un host : il ne contient aucune règle de gameplay.
## Assets
Les assets sources restent hors des crates sous `assets/`. Le build Web conserve les namespaces logiques :
```text
assets/common/data/runtime.json → /common/data/runtime.json
assets/game-snake-poc/data/game.json → /game/data/game.json
```
Les mêmes routes sont valides en développement Vite et dans le bundle production.
## Provenance runtime
La session Web conserve `RuntimeProvenance` dans l'adapter WASM. Les dimensions fixes sont `Web / Browser / Wasm`; la classe d'appareil et le profil d'entrée sont renseignés à partir de l'environnement et des entrées réellement observées.
Le smoke validé expose notamment :
```text
web / browser / wasm / desktop / keyboard-mouse
```
## Build
Le chemin Web direct ne dépend d'aucun orchestrateur Python :
```text
Cargo
→ wasm-bindgen
→ Vite/npm
```
Les artefacts générés restent hors dépôt sous `../builds/sasedev-games/`.
## Résultat de l'extraction
`0.3.0` ne justifie pas encore une abstraction WASM commune entre Reflex et Snake. Les deux adapters spécifiques restent préférables à une factorisation spéculative.
Le prochain host Snake doit réutiliser cette baseline et fournir un second cas réel avant extraction d'une couche commune WebView/WASM.
## Témoin Desktop
Le runner `game-snake-poc-desktop` reste le témoin SDL3 natif. La beta puis la RC `0.3.0-3-rc.1` ont validé son build release et son smoke sans modification de gameplay ni de runtime SDL3.
## Suite
`0.3.1` doit éprouver Tauri Android + Snake. `0.3.2` peut ensuite tester Tauri Desktop et décider, sur deux consommateurs réels, si une factorisation WebView/frontend est justifiée.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/development/003-TRACING_AND_DIAGNOSTICS.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# Tracing et diagnostics
@@ -21,3 +21,9 @@ Les runners Desktop initialisent ce socle. Les futures intégrations Android pou
## Évolution
Les filtres par target/niveau, fichiers rotatifs, configuration utilisateur, traces Android et éventuelle télémétrie distante seront ajoutés uniquement lorsquun besoin concret les justifie.
## Host navigateur direct
Le navigateur direct ne possède ni backend Rust Tauri ni plugin de relayage. Son frontend utilise donc un module TypeScript unique de diagnostics structurés qui écrit dans la console du navigateur avec `target`, `action` et champs associés. Les modules applicatifs n'émettent pas leurs propres formats parallèles.
Cette sortie console est un mécanisme frontend. Elle ne remplace pas `tracing` dans le code Rust : les runners natifs continuent d'initialiser `game-logging-lib`, et un futur besoin de tracing Rust directement dans WebAssembly devra être introduit explicitement plutôt que d'être simulé par le frontend.

View File

@@ -0,0 +1,53 @@
<!-- file: docs/development/009-SNAKE_WEB_WASM_BUILD.md -->
<!-- version: 2 -->
# Build WASM du POC Snake Web direct
## Objectif
`game-snake-poc-wasm` fournit le bridge Rust/WASM du premier host navigateur direct. Cette tranche valide uniquement la production du module WebAssembly et de ses bindings JavaScript ; le frontend Vite/TypeScript et le shell Bootstrap 5 appartiennent à `0-pre.4`.
## Prérequis
À installer une fois si nécessaire :
```bash
rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli --locked
```
Le CLI `wasm-bindgen` utilisé doit rester compatible avec la version de la crate `wasm-bindgen` résolue par Cargo.
## Build Rust
Depuis la racine du dépôt :
```bash
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown
```
La configuration Cargo racine place l'artefact sous :
```text
../builds/sasedev-games/target/wasm32-unknown-unknown/debug/game_snake_poc_wasm.wasm
```
## Génération des bindings navigateur
Créer les bindings avec l'outil natif, sans orchestrateur Python :
```bash
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
```
Les fichiers générés restent intégralement hors du dépôt sous `../builds/sasedev-games/`. Ils ne sont ni commités ni copiés dans `crates/` par cette tranche.
## Frontière avec `0-pre.4`
`0-pre.3` s'arrête au module WASM et à ses bindings générés. Le frontend introduit en `0-pre.4` sous `Web/game-snake-poc/` les consomme ensuite via Vite/TypeScript ; il porte le document HTML Bootstrap 5, le Canvas, le clavier et les contrôles tactiles.
Le frontend reste responsable de la cadence d'appel à `tick()` et de la traduction des événements navigateur vers `left()`, `right()`, `up()` et `down()`.

View File

@@ -0,0 +1,165 @@
<!-- file: docs/development/010-SNAKE_WEB_FRONTEND.md -->
<!-- version: 5 -->
# Frontend du POC Snake Web direct
## Rôle
`Web/game-snake-poc/` est le premier host navigateur direct du projet. Il reste un package frontend autonome, extérieur au workspace Cargo, et consomme les bindings générés de `game-snake-poc-wasm`.
La séparation est volontaire :
```text
game-snake-poc
game-snake-poc-wasm
↓ wasm-bindgen
Web/game-snake-poc
HTML + Sass/Bootstrap 5 + TypeScript + Canvas
```
Le frontend ne réimplémente aucune règle de Snake. Il traduit uniquement les entrées navigateur, cadence les appels à `tick()` et dessine la scène portable exposée par le bridge WASM.
## Baseline frontend KSP
Le shell reprend volontairement la structure frontend utilisée par les applications Desk KSP :
```text
Web/game-snake-poc/
├── frontend/
│ ├── main.html
│ ├── sass/
│ │ ├── _app.scss
│ │ ├── _bootswatch.scss
│ │ ├── _fontawesome.scss
│ │ ├── _simplebar.scss
│ │ ├── _variables.scss
│ │ └── main.scss
│ └── ts/
│ ├── game.ts
│ ├── input.ts
│ └── main.ts
├── package.json
├── tsconfig.json
└── vite.config.ts
```
Les dépendances npm utiles sont alignées sur cette baseline : Bootstrap 5, Font Awesome, SimpleBar, `resize-observer-polyfill`, `sass-embedded`, TypeScript, Vite et les types nécessaires. Les dépendances réellement propres à Tauri et au tracing frontend KSP ne sont pas importées dans ce host navigateur direct. SimpleBar et le polyfill restent au contraire pertinents pour le shell Web lui-même.
Le thème reprend la baseline Bootstrap/Bootswatch Pulse des apps Desk KSP, avec un header, un footer et une carte de contenu adaptés au jeu. Cette réutilisation reste une convention de présentation du POC ; elle ne crée aucune dépendance entre les dépôts KSP et games.sasedev.
## Shell HTML et présentation
Le document `frontend/main.html` fournit :
- un header de statut inspiré du template Desk KSP ;
- un Canvas carré responsive pour le rendu du jeu ;
- les indicateurs de score, longueur et état de chargement ;
- quatre boutons directionnels tactiles ;
- une zone d'erreur de démarrage ;
- un footer léger commun au shell ;
- une zone centrale `app-content.app-scrollable.h-100[data-simplebar]` bornée par `app-main` entre le header et le footer fixes, suivant le même contrat de shell que les apps Desk KSP.
Bootstrap 5 et Font Awesome sont installés comme dépendances npm et intégrés au build Vite/Sass. Aucun CDN n'est nécessaire au POC local.
Le Sass spécifique reste limité au shell, au Canvas et au pavé directionnel. Le gameplay ne dépend ni de Bootstrap, ni de Font Awesome, ni du DOM.
## Entrées
Le frontend accepte :
- les flèches du clavier ;
- `WASD` ;
- `ZQSD` ;
- les quatre boutons directionnels tactiles/pointer.
Une entrée appelle uniquement `left()`, `right()`, `up()` ou `down()` sur `SnakeWasmGame`. La simulation continue d'avancer exclusivement via `tick()`.
## Rendu Canvas
Le frontend lit la couleur de fond et les rectangles normalisés exposés par `game-snake-poc-wasm`. Les coordonnées sont multipliées par la taille physique courante du Canvas.
La grille Snake fait `12 × 20` cellules. Le shell conserve donc un ratio CSS `3 / 5` pour le plateau : une cellule normalisée garde la même largeur et la même hauteur visuelles au lieu d'être écrasée verticalement dans un Canvas carré. Le Canvas suit ensuite cette taille CSS et le `devicePixelRatio` du navigateur.
Le header et le footer restent fixes. `app-main` borne la hauteur utile à `100vh - header - footer` et reste lui-même non scrollable. Comme dans les apps Desk KSP, un enfant `h-100` contient `app-content app-scrollable h-100` portant `data-simplebar`; cette zone possède explicitement `height: 100%` et `max-height: 100%`. Si le plateau portrait et les contrôles dépassent la hauteur disponible, SimpleBar porte donc le scroll de cette zone centrale sans déplacer le header ni le footer. Cette tranche couvre le resize visuel nécessaire au shell ; la gestion complète du lifecycle navigateur reste prévue par `0-pre.5`.
## Build
Depuis la racine du dépôt, construire d'abord l'adapter WASM et ses bindings :
```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
```
Puis installer et construire le frontend :
```bash
cd Web/game-snake-poc
npm install
npm run build
```
Vite place son cache et le `dist/` sous :
```text
../builds/sasedev-games/game-snake-poc-web/
```
Le dépôt ne reçoit donc ni bindings WASM générés, ni `dist/`, ni cache Vite.
## Smoke navigateur
Après génération du WASM :
```bash
cd Web/game-snake-poc
npm run dev
```
Ouvrir explicitement `http://127.0.0.1:1434/main.html` — le host utilise volontairement `main.html` et ne fournit pas d'`index.html` — puis vérifier :
1. le statut passe à `Prêt` sans erreur ;
2. Snake est visible dans le Canvas ;
3. les flèches clavier déplacent Snake ;
4. `WASD` et `ZQSD` produisent les mêmes directions ;
5. les quatre boutons tactiles/pointer fonctionnent ;
6. le plateau conserve son ratio portrait `3 / 5` et les cellules ne sont pas écrasées ;
7. lorsque le contenu dépasse la hauteur utile, seule la zone centrale défile via SimpleBar tandis que header et footer restent fixes ;
8. le shell KSP-derived et le Canvas restent utilisables sur une largeur mobile et Desktop ;
9. score et longueur restent visibles et évoluent avec l'état WASM.
## Lifecycle navigateur
`0-pre.5` ferme le lifecycle du POC. La boucle `requestAnimationFrame` est suspendue lorsque le document devient caché ou reçoit `pagehide`. La reprise sur `visibilitychange`/`pageshow` réinitialise l'origine temporelle et l'accumulateur afin de ne pas rattraper artificiellement les ticks perdus en arrière-plan.
Un `ResizeObserver` attaché à la zone de jeu redessine le Canvas et rafraîchit la classe d'appareil observée sans faire avancer la simulation. La destruction de page libère l'instance WASM.
## Assets runtime
Le package Vite utilise `vite-plugin-static-copy` pour exposer les deux assets de sonde depuis les sources canoniques :
```text
assets/common/data/runtime.json -> dist/common/data/runtime.json
assets/game-snake-poc/data/game.json -> dist/game/data/game.json
```
Les deux targets utilisent explicitement `rename: { stripBase: true }`. Ce point est nécessaire puisque les sources sont résolues en chemins absolus : seule la basename (`runtime.json` / `game.json`) doit être placée sous le `dest` canonique, sans conserver l'arborescence du chemin source. Le serveur Vite de développement expose ainsi les mêmes routes `/common/data/runtime.json` et `/game/data/game.json` que le build de production.
Le frontend charge et valide les deux JSON avant le démarrage WASM. Le statut visible `Assets` permet de confirmer le chargement pendant le smoke. Aucune copie source n'est ajoutée sous `Web/`.
## Logging frontend
`frontend/ts/logging.ts` centralise les diagnostics navigateur. Les événements sont structurés par niveau, target, action et champs, puis écrits dans la console. Ce module est volontairement distinct du bridge tracing Tauri : le host Web direct ne possède pas de backend Tauri à qui relayer ses événements.
Le Rust natif continue d'utiliser `tracing`/`game-logging-lib`; le frontend console ne remplace pas cette façade Rust.
## Provenance runtime
`game-snake-poc-wasm` dépend de `engine-v1-platform-api` uniquement au niveau adapter et conserve une `RuntimeProvenance`. Les dimensions `Web / Wasm / Browser` sont fixes ; le host renseigne la classe `Desktop`/`Phone`/`Tablet`/`Unknown` et le profil `Unknown`/`KeyboardMouse`/`Touch`/`Mixed` à partir des capacités et entrées réellement observées.
Le shell affiche ces cinq dimensions afin que le smoke puisse confirmer que la provenance évolue lorsqu'un clavier/souris ou un contrôle tactile est utilisé. Le gameplay `game-snake-poc` reste sans dépendance plateforme.

22
docs/ideas/000-README.md Normal file
View File

@@ -0,0 +1,22 @@
<!-- file: docs/ideas/000-README.md -->
<!-- version: 1 -->
# Idées
Ce répertoire accueille les idées, variantes et possibilités qui méritent d'être conservées sans devenir automatiquement des engagements du projet.
Une entrée ici peut concerner un jeu, une mécanique, une plateforme, un provider, un service ou un outil.
Sa présence signifie uniquement :
> idée identifiée et conservée pour discussion future.
Elle ne signifie pas :
- capability réservée ;
- architecture retenue ;
- fonctionnalité planifiée ;
- crate à créer ;
- engagement de version.
Lorsqu'une idée nécessite une analyse structurée, elle peut donner naissance à une étude sous `docs/studies/`. Le document d'idée peut alors référencer cette étude sans être supprimé afin de conserver son origine.

14
docs/plans/000-README.md Normal file
View File

@@ -0,0 +1,14 @@
<!-- file: docs/plans/000-README.md -->
<!-- version: 1 -->
# Plans de versions games.sasedev
Ce répertoire contient les plans vivants des versions concrètes.
Un plan est créé ou révisé pendant `0-pre.1`. Il conserve le scope, les décisions utiles, les validations et surtout le découpage prévisionnel souple des tranches jusqu'à la release. Il peut évoluer lorsque les audits ou validations imposent de scinder, fusionner, reporter ou corriger une tranche.
Le `ROADMAP.md` reste la trajectoire macroscopique du projet ; les deltas décrivent ce qui a réellement été livré. Le plan se situe entre les deux et sert au suivi de la version en cours.
## 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.

View File

@@ -0,0 +1,146 @@
<!-- file: docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md -->
<!-- version: 17 -->
# Plan v0.3.0 — baseline Snake et premier POC Web direct
## But de la version
`0.3.0` ouvre la série de POC `0.3.x`. La version doit rendre Snake suffisamment portable pour servir de jeu-sonde et valider un premier host de bout en bout : le navigateur Web direct.
La version doit rester assez petite pour être fermée dans la session qui l'ouvre. Si une tranche devient trop lourde, elle est scindée ; si le scope global ne tient plus, la partie non indispensable est reportée à une version suivante.
## Base et décisions acquises
Base stable : `0.2.0`.
Décisions issues du cadrage `0-pre.1` :
- Snake reste le jeu-sonde principal ;
- le premier host de `0.3.0` est Web navigateur direct ;
- Tauri Android est reporté à `0.3.1` ;
- le gameplay reste dans `game-snake-poc` ;
- le chemin Web utilise Cargo, `wasm-bindgen` et Vite/TypeScript, sans orchestrateur Python ;
- le host navigateur possède un shell HTML piloté par Vite/TypeScript, avec Bootstrap 5 pour le layout/les contrôles et un Canvas dédié au rendu du jeu ; Bootstrap ne porte aucune règle de gameplay ;
- aucune abstraction n'est extraite avant qu'un besoin partagé réel soit observé.
## Scope
La version couvre :
- nettoyage de la baseline Snake et de ses dépendances de plateforme ;
- adaptation WASM dédiée à Snake ;
- frontend Web avec shell HTML responsive, Bootstrap 5, Canvas, clavier et contrôles directionnels tactiles ;
- resize/lifecycle adaptés au navigateur ;
- branchement des assets, du logging et de la provenance runtime nécessaires au POC ;
- maintien du runner Desktop SDL3 comme témoin de non-régression ;
- documentation des duplications observées et des extractions réellement justifiées.
Hors périmètre : Tauri Android/Desktop Snake, Android natif multi-ABI, réseau realtime, WebTransport/QUIC, Uroburas, ads, billing, auth, leaderboard et nouveau moteur.
## Prévision souple
Les numéros ci-dessous sont des repères de progression, pas un contrat rigide. Une découverte peut insérer un fix, scinder une tranche ou décaler les numéros suivants sans forcer la fermeture.
### `0-pre.1` — cadrage
Audit de la baseline, requirements, choix du host Web, sizing et validations prévues. Le présent plan manquant à la livraison initiale est ajouté par `0-pre.1.fix.1`.
### `0-pre.1.fix.1` — plan et règles de suivi
Créer `docs/plans/`, formaliser le caractère vivant du plan, corriger le contrat des archives taggées et rendre explicite qu'une session est planifiée pour fermer au minimum la version concrète ouverte.
### `0-pre.2` — baseline Snake portable
Nettoyer les dépendances inutiles/spécifiques au launcher, stabiliser la frontière gameplay/input et confirmer les tests Snake ainsi que le runner Desktop SDL3.
Livraison candidate : `engine-v1-platform-api` est retiré des crates de gameplay Snake et Reflex où il n'est pas consommé ; les launchers qui utilisent réellement les capacités plateforme conservent leur dépendance. Le contrat Snake est fixé sur `EngineGame`, `InputState`, les quatre actions directionnelles et `EngineScene`, sans SDL3, DOM, Canvas ni API plateforme dans la crate de gameplay. Aucun adapter WASM n'est introduit avant `0-pre.3`.
Gate : audits statiques, `cargo check --workspace`, tests ciblés Snake et vérification du graphe de dépendances des crates de gameplay. Un smoke Desktop n'est requis que si le runtime SDL ou son mapping est modifié.
### `0-pre.3` — adaptation Snake WASM
Introduire `game-snake-poc-wasm`, adapter WASM minimal dédié à Snake. La crate possède `SnakeState`, le `FixedStepRunner` et une direction logique en attente consommée au prochain `tick()`. Elle expose à `wasm-bindgen` les quatre directions, le score, la longueur et la scène normalisée nécessaire au futur Canvas, sans SDL3, Tauri, DOM, frontend ni `engine-v1-platform-api`.
Livraison candidate : la crate est membre du workspace et la distribution statique vérifie sa présence. Le bridge reste volontairement spécifique à Snake ; aucune abstraction commune avec `game-reflex-poc-wasm` n'est extraite avant observation d'une duplication réellement problématique.
Gate : audits statiques, `cargo check --workspace`, Clippy ciblé, tests de l'adapter, build `wasm32-unknown-unknown`, génération `wasm-bindgen --target web` dans `../builds/sasedev-games/` et graphe de dépendances. Aucun build Vite/Bootstrap ni smoke navigateur n'est requis avant `0-pre.4`.
### `0-pre.4` — frontend Web/Vite, shell Bootstrap 5 et contrôles
Créer `Web/game-snake-poc/`, package Vite/TypeScript autonome consommant les bindings `game-snake-poc-wasm` générés hors dépôt. Le frontend reprend le template des applications Desk KSP pour sa structure HTML/Sass/TypeScript et ses dépendances npm pertinentes : Bootstrap 5, thème Bootswatch Pulse, Font Awesome, SimpleBar, `resize-observer-polyfill` et `sass-embedded`, sans dépendances Tauri. Le rendu reste dans un Canvas et les règles de gameplay restent dans Rust/WASM. Brancher flèches clavier, `WASD`/`ZQSD`, quatre boutons directionnels tactiles/pointer, chargement/erreur, score et longueur.
Livraison candidate : le shell utilise `frontend/main.html`, `frontend/sass/` et `frontend/ts/` sur le modèle KSP ; SimpleBar porte le scroll de la zone centrale `app-content.app-scrollable.h-100[data-simplebar]`, bornée par `app-main` entre header et footer fixes ; le Canvas conserve le ratio logique Snake `12 / 20`, suit sa taille CSS et le `devicePixelRatio`, le frontend cadence `tick()` sans avancer la simulation au moment d'une entrée et Vite écrit `dist/`/cache uniquement sous `../builds/sasedev-games/game-snake-poc-web/`. Aucun CDN, SDL3, Tauri ni duplication de gameplay n'est introduit. Le lifecycle complet, les assets, le logging et la provenance restent réservés à `0-pre.5`.
Gate : audits statiques, build WASM + `wasm-bindgen`, `npm run build` du package Web direct et smoke navigateur couvrant Canvas, clavier, contrôles tactiles/pointer et comportement responsive du shell.
Suivi `0-pre.4.fix.1` : la validation utilisateur de `0-pre.4` a confirmé le fonctionnement clavier/pointer sous `vite dev`, mais a révélé trois défauts de candidate : `baseUrl` supprimé par TypeScript 7, omission de SimpleBar/`resize-observer-polyfill` du template repris et Canvas carré incompatible avec la grille logique `12 × 20`. Le fix retire `baseUrl`, rétablit le scroll shell KSP-derived et passe le plateau au ratio `3 / 5` avant réexécution de la gate frontend.
Suivi `0-pre.4.fix.2` : la validation de `fix.1` a confirmé les gates Rust/WASM et les audits, mais `npm run build` a encore révélé deux erreurs TypeScript strictes : l'alias `@snake-wasm` résolvait le JavaScript généré sans sélectionner sa déclaration `.d.ts`, et le narrowing du contexte Canvas 2D n'était pas conservé dans le callback `requestAnimationFrame`. Le fix sépare explicitement la résolution de typage (`.d.ts`) de la résolution runtime Vite (`.js`) et capture le contexte 2D validé dans une constante non nullable.
Suivi `0-pre.4.fix.3` : la validation de `fix.2` confirme la gate Rust/WASM, le build Vite production et le ratio Canvas corrigé. Le smoke révèle toutefois que le scroll SimpleBar ne reproduit pas encore le comportement du shell KSP. La comparaison avec `ksp-app-*-desk` montre que `data-simplebar` doit porter sur la zone centrale `app-content app-scrollable h-100`, enfant d'un `app-main` borné, et non sur `app-main` lui-même. Le fix aligne la structure HTML/Sass sur ce contrat sans initialisation manuelle spécifique.
Validation `0-pre.4.fix.3` : le build Vite reste propre et le smoke utilisateur confirme le comportement attendu du shell, y compris le scroll SimpleBar, le Canvas portrait et les contrôles. `0-pre.4` est donc fermé et `0-pre.5` peut porter l'intégration plateforme complète.
### `0-pre.5` — intégration plateforme complète
Fermer resize/lifecycle, assets, logging et provenance runtime du POC ; vérifier que Desktop SDL reste intact.
Livraison candidate : le host suspend la simulation sur `visibilitychange`/`pagehide` et reprend sans rattrapage massif ; un `ResizeObserver` redessine sans tick artificiel. Vite package `assets/common/data/runtime.json` vers `common/data/runtime.json` et `assets/game-snake-poc/data/game.json` vers `game/data/game.json`, puis le frontend charge/valide ces deux sondes avant le démarrage. Les diagnostics navigateur passent par un module TypeScript structuré local. `game-snake-poc-wasm` consomme `engine-v1-platform-api` pour une provenance `Web/Wasm/Browser`, complétée par la classe d'appareil et le profil d'entrée réellement observés. Aucun de ces contrats ne fuit dans `game-snake-poc`.
Gate : audits statiques, `cargo check --workspace`, Clippy workspace strict, tests `engine-v1-platform-api` et `game-snake-poc-wasm`, build WASM + `wasm-bindgen`, build Vite, smoke navigateur couvrant assets/provenance/lifecycle/resize/inputs/SimpleBar, puis smoke `game-snake-poc-desktop` pour la non-régression SDL3.
Suivi `0-pre.5.fix.1` : la validation de `0-pre.5` confirme les gates Rust/WASM et le build Vite production, mais le smoke `vite dev` reste bloqué sur le chargement des assets. Les targets `vite-plugin-static-copy` utilisent des sources absolues sans `rename.stripBase`, ce qui ne garantit pas les routes runtime canoniques. Le fix impose `stripBase: true` aux deux targets afin que dev et build exposent exactement `/common/data/runtime.json` et `/game/data/game.json`.
Validation `0-pre.5.fix.1` : les audits, `cargo check`, Clippy workspace strict, les tests plateforme/WASM, le build WASM, `wasm-bindgen`, le build Vite et le smoke navigateur passent. Les assets affichent `snake / engine-v1`, la provenance observée est `web / browser / wasm / desktop / keyboard-mouse`, les contrôles clavier/souris fonctionnent et le runner Desktop SDL3 démarre puis s'arrête proprement après 411 frames. Aucun défaut structurel supplémentaire n'est identifié.
### `0-pre.6` — correction/extraction seulement si prouvée
Tranche conditionnelle. Elle n'existe que si les POC précédents révèlent une duplication réelle, une frontière mal placée ou un défaut nécessitant une correction structurante avant stabilisation. Sinon elle est omise.
Décision après `0-pre.5.fix.1` : aucun besoin d'extraction/correction structurante n'est observé ; `0-pre.6` est omise et la version entre directement en beta.
### `2-beta.1` — validation large
Scope feature-complete. La tranche ne crée aucun nouveau comportement : elle bascule la version workspace et le package Web au jalon `0.3.0-2-beta.1`, enregistre la validation de `0-pre.5.fix.1` et exécute la gate large de frontière de phase. Celle-ci comprend audits, formatage/check/Clippy, tests workspace complets, build + smoke Desktop Snake en release, build WASM Snake en release, `wasm-bindgen`, build Vite production et smoke du `dist` via `npm run preview`. Aucun nouveau scope.
Validation : la gate est acceptée par l'utilisateur. Les audits sont propres, les tests workspace totalisent 34 tests réussis sans échec, le binaire Desktop Snake release démarre et s'arrête proprement après 144 frames, et le bundle Web/WASM release est construit puis servi par `vite preview` sans défaut remonté.
### `2-beta.2` — consolidation documentaire et transmission
Réconcilier l'état réellement validé avec la documentation durable et le plan actif, mettre à jour `ROADMAP.md`, enregistrer `2-beta.1` dans l'historique et préparer le prompt de `0.3.1` à partir de cet état. La synthèse destinée au `CHANGELOG.md` est consolidée ici, mais l'entrée n'est écrite qu'en RC conformément à `DOC-CHG-002` et `DOC-CHG-003`.
Livraison candidate : synthèse durable de la baseline Web Snake `0.3.0`, matrice RC spécifique, roadmap `0.3.0` classée réalisée, audit `pre.1` réconcilié avec le contrat des archives taggées et prompt `003-V0_3_1_START_PROMPT.md`. Aucun code ni comportement runtime n'est modifié.
Cette tranche est une responsabilité obligatoire du cycle même si son numéro doit être décalé par des fixes ou une beta supplémentaire. La documentation spécifique à une fonctionnalité reste mise à jour dans la tranche qui introduit cette fonctionnalité ; `2-beta.2` réalise la consolidation transversale, elle ne sert pas à reporter toute la documentation en fin de version.
Gate : cohérence docs/plan/deltas/`CHANGELOG.md`/`ROADMAP.md`/history/prompt, audits documentaires, `cargo check --workspace` pour le bump de version et `npm run build` pour confirmer la version frontend.
Suivi `2-beta.2.fix.1` : la gate mécanique de `2-beta.2` passe, mais la revue humaine juge le prompt `0.3.1` trop synthétique pour éviter des rappels de workflow au cours de la prochaine session. Le fix enrichit ce prompt, formalise une structure durable de prompts, précise le timing prompt/RC/CHANGELOG/ROADMAP/history et introduit une politique non cérémonielle pour `README.md`/`USAGE.md`. Le fix est strictement documentaire et conserve donc la version technique `0.3.0-2-beta.2`.
Suivi `2-beta.2.fix.2` : la revue du prompt enrichi valide son niveau de contexte, mais précise la gouvernance des commandes afin d'éviter des validations trop larges ou répétitives. Le fix rend obligatoires `cargo fmt`, `cargo check --workspace` et Clippy workspace strict dès que Rust ou ses dépendances changent, garde les tests ciblés comme norme, réserve le test workspace complet à quelques jalons planifiés, limite `cargo tree` aux changements/diagnostics de dépendances, sélectionne les audits Python selon les fichiers touchés, impose les sous-shells pour les changements de répertoire et rappelle que Tauri possède Vite via `cargo tauri dev/build`. Ce correctif reste strictement documentaire et ne modifie aucune version technique.
Validation `2-beta.2.fix.2` : l'audit Markdown ciblé passe (`5` tables, `189` fichiers) et la revue utilisateur autorise l'ouverture de la RC. Aucune autre gate n'est attribuée à ce correctif strictement documentaire.
### `3-rc.1` — candidate gelée
Reproductibilité, validation finale de la candidate et derniers défauts strictement nécessaires à la publication. Le prompt suivant préparé pendant la consolidation est vérifié/complété si l'état RC apporte une information nouvelle. Aucun nouveau POC ni nouvelle capability.
Livraison candidate : passage des versions techniques au jalon `0.3.0-3-rc.1`, entrée RC du `CHANGELOG.md`, enregistrement de `2-beta.2.fix.2` dans `history/`, revue finale du prompt `0.3.1` et gel explicite du scope. Le prompt est jugé suffisamment complet et ne reçoit aucun changement sémantique supplémentaire dans cette tranche.
Gate RC : appliquer intégralement `docs/testing/004-V0_3_0_RC_VALIDATION_MATRIX.md`. Le test workspace complet est volontairement exécuté à ce jalon final ; aucun `cargo tree` n'est requis en l'absence de changement de dépendances.
Validation `3-rc.1` : les audits statiques, `cargo check --workspace`, Clippy workspace strict et la suite workspace complète passent avec 34 tests réussis. Le binaire Desktop Snake release démarre puis s'arrête proprement après 926 frames. Le build WASM release, `wasm-bindgen`, le build Vite production et `vite preview` passent également. Aucun défaut nécessitant un correctif RC n'est remonté.
### `0.3.0` — release stable
Promotion mécanique de l'état RC validé. La release ne change ni gameplay, ni architecture, ni dépendance ; elle fixe les versions stables, ajoute l'entrée stable du `CHANGELOG.md`, enregistre la validation RC sous `history/0.3.0/3-rc.1.md` et clôt le plan `0.3.0`. Le prompt `0.3.1` reste inchangé après sa revue RC.
## Suivi et ajustements
Le plan est révisé lorsqu'un résultat réel modifie la trajectoire. Un changement de numérotation n'est pas un problème ; une responsabilité importante ne doit en revanche pas être comprimée artificiellement pour respecter le forecast initial.
La session ne doit pas être planifiée pour s'arrêter à `pre.2`, `pre.4` ou beta : ces identifiants sont des tranches de la même version. Si `0.3.0` devient trop grande, le scope non indispensable est déplacé vers `0.3.1+` afin de préserver une version complète par session.
## Version suivante envisagée
`0.3.1` reste le candidat pour le second host Snake, Tauri Android, en réutilisant la baseline Web/WASM réellement validée par `0.3.0`.

View File

@@ -1,15 +1,18 @@
<!-- file: docs/rules/FILE_CONTRACTS.md -->
<!-- version: 5 -->
<!-- version: 8 -->
# Contrats des fichiers principaux
- `README.md` présente le dépôt et ses entrées principales.
- `RULES.md` indexe les règles normatives.
- `ROADMAP.md` suit les objectifs futurs et leur état.
- `CHANGELOG.md` conserve l'historique synthétique inversement chronologique.
- `ROADMAP.md` conserve le planning durable et son historique de scope via `( )`, `(x)`, `(d)` et `(c)`.
- `CHANGELOG.md` conserve une synthèse inversement chronologique à partir des jalons RC et stables.
- `docs/000-README.md` indexe la documentation détaillée.
- `docs/rules/` contient les règles durables.
- `docs/architecture/` contient les décisions et descriptions d'architecture.
- `docs/ideas/000-README.md` est le point d'entrée des ies et variantes non engagées.
- `docs/studies/000-README.md` est le point d'entrée des analyses comparatives non normatives préparant une décision.
- `docs/plans/000-README.md` est le point d'entrée des plans de versions ; chaque plan actif porte le découpage prévisionnel souple et les gates de sa version.
- `docs/architecture/` contient les décisions et descriptions d'architecture retenues.
- `docs/objectives/` décrit les objectifs et la stratégie produit/technique.
- `docs/games/` classe les familles de jeux, leurs contrôles et leurs évolutions.
- `docs/engine/` décrit lévolution fonctionnelle des générations de moteur.
@@ -23,7 +26,8 @@
- `scripts/` contient des audits en lecture seule et des outils du dépôt.
- `assets/` contient les ressources runtime communes et spécifiques aux jeux ; aucune ressource runtime n'est placée dans une crate Rust.
- `Android/` contient le projet Gradle multi-module et son code Java commun/spécifique.
- `crates/apps/` contient les exécutables de développement et launchers Rust, notamment les runners Desktop par jeu.
- `Web/` contient les hosts navigateur directs non-Tauri ; chaque `Web/<game>/` est un package frontend autonome consommant un adapter WASM versionné sous `crates/apps/`.
- `crates/apps/` contient les exécutables de développement et launchers Rust, notamment les runners Desktop par jeu et les adapters WASM.
## Tauri
@@ -32,3 +36,18 @@
- `crates/apps/<game>-tauri/src/tauri.rs` assemble Tauri et porte le pont Web/Rust.
- `crates/apps/<game>-wasm/` contient l'adaptation WebAssembly distincte.
- Les bindings JavaScript et modules `.wasm` générés restent ignorés par Git.
## Points d'entrée documentaires
- Le `README.md` racine du dépôt conserve son nom.
- Un README propre à une crate, un package ou un répertoire technique peut conserver `README.md` lorsque cet usage est naturel à son écosystème.
- Un répertoire documentaire conçu pour accumuler plusieurs fichiers Markdown utilise `000-README.md` comme point d'entrée.
- `history/000-README.md` est le point d'entrée de l'historique validé.
## Immutabilité et suppressions dans les deltas
- Les fichiers `deltas/**/*.md` livrés sont immuables sur le fond.
- Une correction de forme sans changement de sens peut modifier un delta existant uniquement en incrémentant son en-tête `version`.
- Toute correction sémantique ou tout ajout produit un nouveau delta ou `.fix.N`.
- Les fichiers `deltas/**/*.delete.txt` sont des manifests de suppression contractuels.
- Chaque manifest contient un chemin relatif par ligne et est expliqué dans le fichier Markdown du delta qui l'introduit.

View File

@@ -0,0 +1,70 @@
<!-- file: docs/rules/PROMPT_STRUCTURE.md -->
<!-- version: 2 -->
# Structure des prompts de reprise
## Objet
Un prompt de démarrage est un contrat opératoire autonome pour la version suivante. Il doit permettre de reprendre le travail sans dépendre de la mémoire conversationnelle, tout en évitant de recopier intégralement les règles du dépôt.
Le prompt rappelle les invariants qui évitent les erreurs de workflow et renvoie aux documents normatifs pour leur détail exact.
## Contenu minimal
- **PROMPT-STR-001** — Le prompt identifie la baseline exacte, la version cible et l'autorité de la base fournie. Une archive annoncée comme téléchargement d'un tag est traitée selon `CMD-GIT-003`/`CMD-GIT-004` sans exiger `.git`.
- **PROMPT-STR-002** — Le prompt fournit un ordre de lecture court des sources de vérité : `RULES.md`, `ROADMAP.md`, `CHANGELOG.md`, `docs/000-README.md`, règles directement pertinentes, plan/historique de la version précédente et documents d'architecture concernés.
- **PROMPT-STR-003** — Le prompt distingue explicitement l'état déjà validé hérité de la baseline des validations qui devront être exécutées dans la nouvelle version.
- **PROMPT-STR-004** — Le prompt décrit la mission, le résultat attendu, le scope inclus, le hors-périmètre et les invariants architecturaux gelés.
- **PROMPT-STR-005** — Le prompt rappelle que `0-pre.1` est le gate de cadrage : audit, requirements, sizing, risques, validations prévues et création/révision du plan sous `docs/plans/` avant développement lourd.
- **PROMPT-STR-006** — Le prompt contient un forecast souple jusqu'à la stable. Il réserve les responsabilités de développement, validation large, consolidation documentaire, préparation de publication/RC et release mécanique sans rendre les numéros immuables.
- **PROMPT-STR-007** — Le prompt rappelle où se trouve la définition des commandes : `docs/rules/RULES_COMMANDS.md` pour la politique d'exécution et `docs/rules/RULES_VALIDATION_MATRIX.md` pour les IDs, dépendances et déclencheurs. Il ne recopie que les commandes indispensables à la reprise ou au premier gate.
- **PROMPT-STR-008** — Le prompt rappelle la séparation utilisateur/générateur : les audits statiques peuvent être exécutés par le générateur, mais les builds, tests et smokes finaux restent côté utilisateur conformément à `CMD-BUILD-005` et ne sont jamais déclarés réussis sans sortie réelle.
- **PROMPT-STR-009** — Le prompt rappelle la cadence de validation sans recopier toute la matrice : audits Python sélectionnés selon les fichiers touchés ; `cargo fmt --all`, `cargo fmt --all -- --check`, `cargo check --workspace` et Clippy workspace strict obligatoires dès que du Rust ou une dépendance Cargo change ; tests `cargo test -p ...` ciblés par défaut ; test workspace complet réservé aux rares jalons planifiés ou aux changements transverses incertains ; `cargo tree` seulement lors d'un changement/diagnostic de dépendances.
## 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.
## Documentation et traçabilité à rappeler
- **PROMPT-STR-010** — Le prompt rappelle que `deltas/` décrit la livraison candidate et ses validations attendues, alors que `history/` enregistre uniquement le résultat d'un jalon effectivement accepté.
- **PROMPT-STR-011** — Le prompt rappelle qu'une entrée `history/<X.Y.Z>/<jalon>.md` est créée par le delta suivant ou le fix suivant après validation, jamais avant la validation qu'elle décrit.
- **PROMPT-STR-012** — Le prompt rappelle que `CHANGELOG.md` n'est normalement mis à jour qu'à partir de la RC puis à la stable ; les détails `pre`/`beta` restent dans `deltas/` et `history/`.
- **PROMPT-STR-013** — Le prompt rappelle que `ROADMAP.md` reste macroscopique et n'est modifié que lorsque le scope, son ordre ou son statut évolue réellement ; le plan de version porte le découpage fin.
- **PROMPT-STR-014** — Le prompt rappelle que la documentation propre à une fonctionnalité évolue avec la tranche qui l'introduit ; la consolidation finale réconcilie l'ensemble mais ne sert pas à repousser toute documentation à la fin.
- **PROMPT-STR-015** — Le prompt mentionne explicitement la politique `README.md`/`USAGE.md` lorsque la version crée ou finalise une crate, une application ou un package : appliquer `DOC-CRATE-*` et décider dans le plan quels fichiers ont une valeur durable réelle.
## README et USAGE dans une version
Le prompt ne doit pas imposer mécaniquement des fichiers vides. Il doit en revanche forcer la question au cadrage puis à la consolidation :
```text
nouvelle crate/package durable ?
-> README utile pour responsabilité/frontières/points d'entrée ?
API ou workflow de consommation non trivial ?
-> USAGE utile pour préconditions/commandes/exemples ?
simple adapter/POC déjà documenté durablement ailleurs ?
-> document supplémentaire non obligatoire s'il n'apporte rien
```
## Timing du prompt suivant
- **PROMPT-STR-020** — Le prompt de la version suivante est rédigé pendant la consolidation finale lorsque la cible suivante est suffisamment connue ; il n'est pas reporté à une future session.
- **PROMPT-STR-021** — La première RC gelée vérifie et complète ce prompt à partir de l'état réellement candidat à publication ; elle ne lui attribue pas de validations futures.
- **PROMPT-STR-022** — La stable ne doit normalement effectuer qu'une mise à jour mécanique de la base de départ ou des références devenues certaines depuis la RC.
## Versionnement, deltas et fixes
- **PROMPT-STR-030** — Le prompt rappelle le format SemVer applicable et le rôle des `.fix.N` lorsqu'une erreur est découverte dans une tranche déjà livrée.
- **PROMPT-STR-031** — Le prompt rappelle que chaque delta indique sa base requise, son scope, les fichiers touchés, les validations attendues et l'état connu du jalon précédent.
- **PROMPT-STR-032** — Une validation propre permet de poursuivre automatiquement vers la tranche planifiée suivante ; un échec reste dans un `.fix.N` de la tranche courante sauf décision explicite contraire.
- **PROMPT-STR-033** — Le prompt rappelle qu'une session est dimensionnée pour fermer au minimum une version concrète jusqu'à sa stable, pas pour s'arrêter volontairement sur une prerelease.
## Niveau de détail attendu
Le prompt doit être assez complet pour éviter les rappels conversationnels récurrents, mais il ne devient pas une duplication exhaustive de `docs/rules/`.
Une taille de quelques centaines de lignes est acceptable lorsqu'elle porte du contexte opérationnel réel. Les listes de toutes les règles Rust ou de toutes les commandes du dépôt restent dans leurs documents normatifs ; le prompt cite les règles et reproduit seulement les garde-fous susceptibles d'être oubliés dans la version ciblée.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_COMMANDS.md -->
<!-- version: 8 -->
<!-- version: 13 -->
# Règles d'exécution des commandes
@@ -16,21 +16,26 @@
- **CMD-GEN-009** — Lorsque l'utilisateur fournit une gate complète propre, le delta est considéré validé et le travail peut passer automatiquement au delta planifié suivant sauf instruction contraire.
- **CMD-GEN-010** — Si une gate échoue, la progression vers le delta suivant est suspendue ; le correctif est livré sous le suffixe `.fix.N` du delta courant, sauf décision explicite contraire.
- **CMD-GEN-011** — Les commandes d'audit Markdown couvrent également `history/` dès que cette arborescence existe.
- **CMD-GEN-012** — Les audits Python sont sélectionnés selon les fichiers réellement touchés : audit Rust/workspace pour le périmètre Rust/Cargo/workspace concerné, audit Markdown pour les fichiers Markdown concernés, audit de distribution pour les changements de layout/build/packaging. Ils ne sont pas tous exécutés par habitude sur chaque delta.
- **CMD-GEN-013** — Toute commande nécessitant un changement temporaire de répertoire est exécutée dans un sous-shell, par exemple `(cd Web/game-snake-poc && npm run build)`, afin de revenir automatiquement à la racine du workspace après la commande.
## Rust et Cargo
- **CMD-RUST-001** — Lorsquun delta a modifié au moins un fichier Rust, lutilisateur exécute `cargo fmt --all` au début de la validation afin dappliquer le formatage canonique; les changements purement produits par rustfmt constituent lunique exception à lincrément obligatoire de len-tête de version du fichier.
- **CMD-RUST-002** — `cargo fmt --all -- --check` suit immédiatement le formatage et constitue la gate canonique de conformité rustfmt.
- **CMD-RUST-003** — `cargo check --workspace` est la première gate de compilation globale après les audits statiques.
- **CMD-RUST-004** — `cargo clippy --workspace --all-targets --all-features -- -D warnings` est exécuté après un `cargo check --workspace` propre pour la gate complète.
- **CMD-RUST-005** — Les tests ciblés `cargo test -p <crate> --all-targets --all-features` sont la stratégie normale dun delta et doivent couvrir toutes les crates directement ou transitivement affectées lorsque cela est raisonnablement déterminable.
- **CMD-RUST-006** — `cargo test --workspace --all-targets --all-features` est une gate lourde réservée au démarrage dune nouvelle version `X.Y.Z`, à la fin dune phase/version, aux changements transverses importants ou lorsquil existe un doute raisonnable sur la portée des tests ciblés.
- **CMD-RUST-001** — Dès qu'un delta modifie du code Rust, un manifeste Cargo, une feature ou une dépendance Rust, l'utilisateur exécute `cargo fmt --all`; les changements purement produits par rustfmt constituent l'unique exception à l'incrément obligatoire de l'en-tête de version du fichier.
- **CMD-RUST-002** — `cargo fmt --all -- --check` suit le formatage et constitue la gate canonique de conformité rustfmt.
- **CMD-RUST-003** — Tout delta qui touche du code Rust ou ses dépendances exécute `cargo check --workspace` après les audits statiques applicables. Un `cargo check -p <crate>` peut servir de diagnostic rapide, mais ne remplace pas cette gate workspace.
- **CMD-RUST-004** — Tout delta qui touche du code Rust ou ses dépendances exécute ensuite `cargo clippy --workspace --all-targets --all-features -- -D warnings`. Cette gate n'est pas réservée aux seules phases finales.
- **CMD-RUST-005** — Les tests ciblés `cargo test -p <crate> --all-targets --all-features` sont la stratégie normale d'un delta et couvrent les crates directement affectées ainsi que les consommateurs dont le contrat est réellement impacté.
- **CMD-RUST-006** — `cargo test --workspace --all-targets --all-features` est une gate lourde exécutée seulement un petit nombre de fois explicitement prévues dans le plan de version/session, typiquement à une validation initiale si elle apporte une valeur réelle, à une validation préfinale/finale, lors d'un changement transverse important ou lorsqu'il existe un doute raisonnable sur la portée des tests ciblés. Elle n'est pas répétée à chaque delta.
- **CMD-RUST-007** — `cargo run -p <desktop-runner>` sert aux smokes manuels Desktop et n'est pas substitué aux tests automatisés.
- **CMD-RUST-008** — `cargo build` est utilisé lorsqu'un artefact exécutable ou une bibliothèque est réellement nécessaire ; il n'est pas lancé systématiquement en plus de `cargo check`.
- **CMD-RUST-009** — `cargo tree` et ses variantes sont des commandes de diagnostic de dépendances, pas des gates obligatoires de chaque delta.
- **CMD-RUST-009** — `cargo tree` et ses variantes ne sont exécutés que lorsqu'un delta modifie les dépendances/features, lorsqu'une frontière de dépendances doit être vérifiée ou lorsqu'un diagnostic explicite le justifie. Ils ne font pas partie de la validation automatique d'un delta sans changement de dépendances.
- **CMD-RUST-010** — `cargo update` n'est jamais exécuté opportunistement. Toute mise à jour de dépendance doit appartenir à une tranche explicitement consacrée aux dépendances ou être nécessaire à la fonctionnalité en cours.
- **CMD-RUST-011** — `cargo clean` n'est pas une gate et n'est pas utilisé en routine. Il n'est autorisé qu'en cas de diagnostic de build corrompu, de contrainte disque explicite ou de demande ciblée, avec justification.
- **CMD-RUST-012** — La suppression manuelle de `target/` ne remplace pas `cargo clean` et suit les mêmes restrictions.
- **CMD-RUST-011** — `cargo clean` est l'outil canonique de remise à zéro complète du cache de build Cargo et peut être utilisé périodiquement pour maîtriser la taille de `../builds/sasedev-games/target`.
- **CMD-RUST-012** — Un nettoyage complet n'est pas exécuté à chaque delta. Il est planifié à un jalon de cycle approprié, normalement au démarrage de la première prerelease de développement lorsque l'ancien cache doit être évacué, ou au plus tard avant la validation finale RC/stable si l'accumulation disque le justifie.
- **CMD-RUST-013** — Entre deux nettoyages complets, les variantes ciblées de `cargo clean` (`-p`, `--release`, `--profile`, `--target`) sont préférées lorsqu'elles répondent au besoin de libération d'espace sans supprimer tout le cache.
- **CMD-RUST-014** — `cargo clean --dry-run --verbose` peut être utilisé pour estimer l'impact d'un nettoyage avant suppression.
- **CMD-RUST-015** — La suppression manuelle de `target/` ne remplace pas `cargo clean` et n'est utilisée qu'en diagnostic exceptionnel.
## Runners Desktop
@@ -46,36 +51,56 @@
- **CMD-ANDROID-001** — Les commandes Gradle Android sont exécutées depuis `Android/` ou avec un chemin explicite vers le wrapper du projet.
- **CMD-ANDROID-002** — Les tâches ciblées par application sont préférées, par exemple `./gradlew :game-reflex-poc:assembleDebug`, lorsqu'elles existent.
- **CMD-ANDROID-003** — Un build Android global n'est pas exécuté si la tranche ne touche ni Android ni le contrat natif utilisé par Android.
- **CMD-ANDROID-004** — `gradle clean` ou `./gradlew clean` n'est pas une gate normale et suit la même politique restrictive que `cargo clean`.
- **CMD-ANDROID-004** — `gradle clean` ou `./gradlew clean` reste un nettoyage Android ciblé ; il n'est pas rendu obligatoire uniquement parce qu'un `cargo clean` est planifié.
- **CMD-ANDROID-005** — Les commandes Android réelles ne deviennent des gates qu'après introduction du wrapper Gradle, de l'AGP, du NDK, de SDL3 et des modules exécutables correspondants.
## Web
- **CMD-WEB-001** — Aucun gestionnaire de paquets JavaScript ni build Web n'est exécuté tant qu'un frontend Web réel n'a pas été introduit dans le dépôt.
- **CMD-WEB-002** — Lorsqu'une cible Web existe, ses commandes de build et test sont documentées avant d'être ajoutées aux gates.
- **CMD-WEB-003** — Le POC Tauri/WASM utilise `scripts/build_reflex_tauri_wasm.py` pour WASM et Vite/TypeScript pour le frontend local ; aucun site distant n'est requis.
- **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-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é.
## Git et fichiers générés
- **CMD-GIT-001** — Les commandes Git destructives (`reset --hard`, nettoyage forcé, réécriture non demandée) ne sont jamais utilisées pour remettre artificiellement le workspace en état.
- **CMD-GIT-002** — Les fichiers générés ne sont pas commités sauf contrat explicite du dépôt ou exigence de distribution.
- **CMD-WEB-005** — `npm run dev` et `npm run build` du frontend Tauri sont pilotés par les hooks Tauri ; ils ne constituent pas des gates manuelles indépendantes.
- **CMD-GIT-003** — Lorsqu'une archive fournie par l'utilisateur est déclarée comme téléchargement d'un tag du dépôt, cette archive est la baseline autoritaire de ce tag. L'absence de `.git` dans l'archive est normale et ne constitue ni une anomalie ni une validation manquante.
- **CMD-GIT-004** — Les contrôles nécessitant le répertoire `.git` s'appliquent uniquement à un checkout Git local lorsqu'il est effectivement fourni ; sur une archive taggée, on contrôle la cohérence interne des versions et fichiers sans inventer un état Git inaccessible.
## Beta et packaging
- **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** — Le build Tauri de packaging est lancé via `cargo tauri build`; ses hooks possèdent le build WASM et Vite/TypeScript.
- **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-004** — Les APK Debug servent à la validation multi-appareils beta ; la signature de publication appartient à la phase RC/stable.
## RC et release
- **CMD-RC-001** — L'entrée en RC gèle le périmètre fonctionnel de `0.1.0` ; seuls les correctifs, la reproductibilité des builds, le packaging, la documentation de livraison et les défauts de release sont admis.
- **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** — Le POC Tauri est construit uniquement via `cargo tauri build`; ses hooks possèdent toujours le build WASM et Vite/TypeScript.
- **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-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.
## Matrice de validation
- **CMD-MATRIX-001** — `docs/rules/RULES_VALIDATION_MATRIX.md` associe des identifiants stables aux commandes et décrit leurs dépendances.
- **CMD-MATRIX-002** — Lorsqu'une modification affecte une crate dont dépendent d'autres crates, les validations ciblées couvrent la crate modifiée et les consommateurs directement ou transitivement impactés selon la portée de l'API.
- **CMD-MATRIX-003** — La matrice évolue avec le workspace ; ajouter une nouvelle plateforme ou un nouveau type de build doit ajouter ou adapter les commandes concernées plutôt que créer une procédure informelle parallèle.
## Outils de build et scripts d'audit
- **CMD-BUILD-001** — Les scripts Python du dépôt sont autorisés pour les audits, audits complémentaires, validations et validations complémentaires.
- **CMD-BUILD-002** — À partir de `0.3.x`, aucun chemin de build nouveau ou modifié nest piloté par Python. Les orchestrateurs historiques `scripts/build_reflex_tauri_wasm.py` et `scripts/build_android_rust.py` restent tolérés uniquement comme mécanismes gelés de la baseline `0.1.0` jusquà la tranche qui réactive leur chemin ; ils ne sont ni copiés, ni généralisés, ni utilisés pour un nouveau POC.
- **CMD-BUILD-003** — Les builds utilisent l'outil natif approprié au périmètre : Cargo pour Rust, Gradle pour Android, Tauri CLI pour Tauri, ou l'outil officiellement retenu par la plateforme concernée.
- **CMD-BUILD-004** — Les POC `0.3.x` doivent remplacer toute orchestration de build Python restante par des procédures explicites, reproductibles et testées avec les outils natifs.
- **CMD-BUILD-005** — Les builds, tests unitaires, tests d'intégration et smoke tests de validation sont exécutés côté utilisateur ; les scripts d'audit peuvent vérifier statiquement leur préparation mais ne les simulent pas.

View File

@@ -1,8 +1,10 @@
<!-- file: docs/rules/RULES_DOCUMENTATION.md -->
<!-- version: 2 -->
<!-- version: 8 -->
# Règles de documentation
## Principes généraux
- **DOC-001** — La documentation structurée réside sous `docs/`.
- **DOC-002** — `docs/000-README.md` est l'entrée de navigation documentaire.
- **DOC-003** — Les documents normatifs résident sous `docs/rules/`.
@@ -10,12 +12,113 @@
- **DOC-005** — Les documents de validation résident sous `docs/validation/`.
- **DOC-006** — Les documents internes sont en français ; code, symboles et extraits techniques conservent leur langue naturelle.
- **DOC-007** — Les tableaux Markdown suivent le format contrôlé par `scripts/audit_markdown_tables.py`.
- **DOC-009** — Les cellules d'un tableau Markdown sont remplies avec des espaces afin que chaque colonne ait une largeur brute constante sur toutes les lignes de contenu.
- **DOC-010** — La ligne séparatrice ne contient aucun espace de padding : chaque cellule séparatrice remplit exactement la largeur brute de sa colonne avec des tirets, comme dans `|-----------|----------------|`.
- **DOC-011** — Les marqueurs Markdown d'alignement `:` ne sont utilisés que lorsqu'un alignement sémantique différent de l'alignement par défaut est nécessaire ; ils remplacent alors des tirets sans modifier la largeur brute exacte de la cellule séparatrice.
- **DOC-012** — Les tableaux d'un même document conservent une convention cohérente et doivent passer `scripts/audit_markdown_tables.py` avant livraison.
- **DOC-008** — Deux lignes blanches consécutives sont interdites hors blocs de code.
- **DOC-009** — Un fichier sous `deltas/<X.Y.Z>/` décrit exactement la tranche livrée, son état de base et ses commandes de validation ; il est immuable après livraison.
- **DOC-010** — L'historique transitoire validé réside sous `history/<X.Y.Z>/` avec un fichier immuable par jalon accepté.
- **DOC-011** — Une entrée `history/` n'est créée qu'après validation du jalon qu'elle décrit ; le résultat d'une validation future n'est jamais pré-écrit.
- **DOC-012** — Le delta suivant, ou le fix suivant lorsqu'il existe, crée l'entrée `history/` du dernier jalon définitivement validé si elle n'existe pas encore.
- **DOC-013** — `CHANGELOG.md` reste une synthèse destinée aux jalons significatifs et ne reproduit pas l'historique détaillé des `pre.*` et de leurs fixes.
- **DOC-014** — Après la structuration initiale de `0.1.0`, les `pre.*` et `.fix.*` ne modifient normalement pas `CHANGELOG.md`. Les entrées `alpha` et `beta` peuvent y apparaître uniquement lorsqu'elles correspondent à un jalon externe significatif ; `rc` et releases stables y sont les jalons privilégiés.
- **DOC-015** — `ROADMAP.md` n'est pas modifié mécaniquement à chaque delta ; il change uniquement lorsque le périmètre, l'ordre, les objectifs ou les jalons planifiés évoluent réellement.
- **DOC-016** — `history/` et `deltas/` ont des rôles distincts : `deltas/` décrit une livraison candidate et sa validation attendue ; `history/` enregistre le résultat accepté et durable.
## Catégories documentaires
- **DOC-CAT-001** — `docs/ideas/` contient des idées, variantes ou pistes non engagées. Une idée n'est ni une réservation architecturale, ni un engagement de roadmap, ni une exigence.
- **DOC-CAT-002** — `docs/studies/` contient des analyses construites destinées à comparer des solutions, évaluer une piste ou préparer une décision. Une étude reste non normative.
- **DOC-CAT-003** — `docs/architecture/` contient uniquement des orientations ou décisions architecturales retenues. Une possibilité encore ouverte reste dans `ideas/` ou `studies/`.
- **DOC-CAT-004** — `docs/rules/` contient les normes obligatoires du dépôt. Une décision d'architecture ne devient une règle que lorsqu'une contrainte durable et vérifiable doit être imposée.
- **DOC-CAT-005** — `docs/objectives/` décrit les objectifs produit et techniques ; il ne remplace ni la roadmap ni les règles.
- **DOC-CAT-006** — Les documents spécialisés existants (`games/`, `engine/`, `monetization/`, `services/`, `development/`, `testing/`, `validation/`) conservent leur rôle fonctionnel et ne servent pas de dépôt générique d'idées.
- **DOC-CAT-007** — Une information peut mûrir de `idea` vers `study`, puis vers une décision d'architecture ou une réservation de capability ; ce passage est explicite et n'est jamais déduit de la seule présence d'un texte.
- **DOC-CAT-008** — Une étude peut conclure à `retained`, `deferred`, `rejected` ou `needs-poc` sans créer automatiquement une capability, une crate ou une entrée de roadmap.
- **DOC-CAT-009** — `docs/plans/` contient les plans vivants des versions concrètes. Un plan détaille le scope, les décisions, les validations et surtout le découpage prévisionnel souple des prereleases ; il ne remplace ni `ROADMAP.md` ni les deltas.
## Nomenclature documentaire
- **DOC-NAME-001** — Les documents thématiques utilisent un préfixe numérique local à leur répertoire suivi d'un nom descriptif stable, par exemple `003-AUTH_OPTIONS.md`.
- **DOC-NAME-002** — La séquence numérique est indépendante dans chaque répertoire documentaire.
- **DOC-NAME-003** — Une fois un document livré, son numéro n'est pas renuméroté uniquement pour réordonner visuellement la documentation.
- **DOC-NAME-004** — Un statut n'est pas encodé dans le nom de fichier. Les changements de statut ne provoquent donc pas de renommage mécanique.
- **DOC-NAME-005** — Les noms de fichiers restent en anglais technique lorsqu'ils désignent un concept de projet ; le corps documentaire reste en français.
- **DOC-NAME-006** — Le `README.md` racine du dépôt conserve ce nom canonique. Les README imposés ou naturels à une crate/package peuvent également conserver `README.md`.
- **DOC-NAME-007** — Dans un répertoire documentaire destiné à contenir plusieurs fichiers Markdown, le point d'entrée porte le nom `000-README.md` afin d'être trié en premier.
- **DOC-NAME-008** — Un nouveau répertoire documentaire multi-fichiers ne crée pas de `README.md` concurrent à `000-README.md`.
## Documentation des crates, applications et packages
- **DOC-CRATE-001** — Toute nouvelle crate, application ou package frontend évalue explicitement pendant son cadrage puis sa consolidation finale si un `README.md` ou un `USAGE.md` apporte une information durable utile ; ces fichiers ne sont jamais créés uniquement pour satisfaire une cérémonie.
- **DOC-CRATE-002** — Un `README.md` local décrit la responsabilité, les frontières, les dépendances structurantes et les principaux points d'entrée lorsqu'un composant devient durable ou réutilisable et que ces informations ne sont pas suffisamment couvertes par une documentation centrale.
- **DOC-CRATE-003** — Un `USAGE.md` est ajouté lorsqu'une API, un binaire, une application ou un package possède un workflow de consommation/opérateur, des préconditions, des commandes, de la configuration ou des exemples suffisamment non triviaux pour mériter un guide stable.
- **DOC-CRATE-004** — Un adapter ou POC très petit peut rester documenté uniquement par les documents d'architecture/développement existants lorsque cela couvre réellement son contrat ; l'absence de `README.md`/`USAGE.md` doit alors être un choix de valeur documentaire, pas un oubli.
- **DOC-CRATE-005** — `README.md` et `USAGE.md` restent durables et ne contiennent pas de journal de release ; les changements de version appartiennent à `CHANGELOG.md`, `deltas/` et `history/`.
## Listes de tâches et d'état
- **DOC-TASK-001** — Toute liste Markdown qui représente durablement des tâches, objectifs ou éléments suivis utilise les marqueurs `( )`, `(x)`, `(d)` et `(c)` plutôt que les task lists Markdown `[ ]` / `[x]`.
- **DOC-TASK-002** — `( )` signifie `planned`, `(x)` signifie `completed`, `(d)` signifie `deferred` et `(c)` signifie `cancelled`.
- **DOC-TASK-003** — Une liste purement descriptive n'utilise pas artificiellement ces marqueurs.
- **DOC-TASK-004** — Les règles spécialisées d'un document peuvent préciser la sémantique ou la traçabilité des marqueurs sans introduire un autre alphabet de statuts.
## ROADMAP
- **DOC-RMAP-001** — `ROADMAP.md` décrit le planning durable : objectifs prévus, réalisés, reportés ou annulés. Il ne suit pas le détail des prereleases et fixes.
- **DOC-RMAP-002** — Le ROADMAP utilise les marqueurs de suivi canoniques définis par `DOC-TASK-*`.
- **DOC-RMAP-003** — Les statuts s'appliquent aux lignes de scope et non automatiquement à une version entière.
- **DOC-RMAP-004** — Une version peut être entièrement décrite par une seule ligne ou être ventilée en plusieurs lignes lorsque son scope a plusieurs devenirs.
- **DOC-RMAP-005** — Une même version peut apparaître sur plusieurs lignes lorsque des sous-ensembles de son scope ont des devenirs différents.
- **DOC-RMAP-006** — Une ligne `(x)` décrit uniquement ce qui a effectivement été livré dans la version concernée.
- **DOC-RMAP-007** — Lorsqu'une partie du scope est reportée, elle reçoit sa propre ligne `(d)`. La destination est indiquée par `→ <version>` lorsqu'elle est connue, sinon par `→ target TBD`.
- **DOC-RMAP-008** — Lorsqu'un élément reporté est replanifié dans une version cible, la nouvelle ligne peut indiquer `← deferred from <version>` afin d'assurer une traçabilité bidirectionnelle.
- **DOC-RMAP-009** — Lorsqu'une partie du scope est annulée, elle reçoit sa propre ligne `(c)` ; une annulation partielle n'annule pas les éléments effectivement livrés.
- **DOC-RMAP-010** — Une version stable clôturée ne conserve aucune ligne `( )` sous son numéro : tout scope initial doit être classé `(x)`, `(d)` ou `(c)`.
- **DOC-RMAP-011** — Les lignes `(d)` et `(c)` restent dans la roadmap comme historique du planning et ne sont pas supprimées pour réécrire rétroactivement le plan.
- **DOC-RMAP-012** — `ROADMAP.md` n'est pas modifié mécaniquement à chaque delta ; il change lorsque le périmètre, l'ordre, les objectifs ou le devenir d'un scope évoluent réellement.
## CHANGELOG
- **DOC-CHG-001** — `CHANGELOG.md` est une synthèse de publication, pas un journal de développement.
- **DOC-CHG-002** — Les `pre.*`, `alpha.*`, `beta.*` et leurs `.fix.*` ne créent normalement aucune entrée de changelog.
- **DOC-CHG-003** — Le changelog est mis à jour à partir des jalons `rc.*` et pour chaque release stable.
- **DOC-CHG-004** — Une entrée RC résume l'état candidat à publication ; l'entrée stable résume le résultat effectivement publié.
- **DOC-CHG-005** — Les détails intermédiaires de construction, corrections et validations restent dans `deltas/` et `history/`.
- **DOC-CHG-006** — Une ancienne entrée de changelog devenue incompatible avec cette politique peut être migrée une fois vers `deltas/` / `history/` existants sans prétendre que l'ancien historique n'a jamais existé.
## Deltas et historique
- **DOC-DELTA-001** — Un fichier sous `deltas/<X.Y.Z>/` décrit exactement la tranche livrée, son état de base et ses validations attendues ; il est immuable après livraison.
- **DOC-HIST-001** — L'historique transitoire validé réside sous `history/<X.Y.Z>/` avec un fichier immuable par jalon accepté.
- **DOC-HIST-002** — Une entrée `history/` n'est créée qu'après validation du jalon qu'elle décrit ; le résultat d'une validation future n'est jamais pré-écrit.
- **DOC-HIST-003** — Le delta suivant, ou le fix suivant lorsqu'il existe, crée l'entrée `history/` du dernier jalon définitivement validé si elle n'existe pas encore.
- **DOC-HIST-004** — `history/` et `deltas/` ont des rôles distincts : `deltas/` décrit une livraison candidate et sa validation attendue ; `history/` enregistre le résultat accepté et durable.
## Validation documentaire
- **DOC-VAL-001** — Une gate Markdown ou un audit syntaxique valide la forme des documents, jamais leur exactitude fonctionnelle, leur exhaustivité ni leur acceptation.
- **DOC-VAL-002** — Une prerelease principalement documentaire reste candidate tant que son contenu n'a pas été relu et accepté humainement.
- **DOC-VAL-003** — Une version de conception peut utiliser plusieurs `pre.N` successives uniquement pour permettre revue, correction, complément et maturation documentaire.
- **DOC-VAL-004** — Cargo, Gradle, packaging et smoke tests ne sont requis pour une prerelease documentaire que si le delta modifie du code, une configuration de build/runtime ou un contrat susceptible de les affecter.
- **DOC-VAL-005** — Le document de delta énumère les validations applicables ; l'absence volontaire d'une gate technique doit découler du scope réel, pas d'un raccourci.
- **DOC-VAL-006** — Une version documentaire n'est promue en `rc` ou stable qu'après validation explicite de son contenu, même si tous les audits automatisés sont propres.
## Maturation des idées et capabilities
- **DOC-MAT-001** — La chaîne de maturation conceptuelle de référence est `Idea → Study → Architectural decision → Reserved capability → Planned → Implemented`.
- **DOC-MAT-002** — Une branche peut s'arrêter en `Deferred` ou `Rejected` à n'importe quelle étape pertinente.
- **DOC-MAT-003** — `Reserved` signifie que le concept et sa place architecturale sont reconnus sans engagement d'implémentation ni de version.
- **DOC-MAT-004** — `Planned` signifie qu'une implémentation est affectée à une version ou un jalon de roadmap.
- **DOC-MAT-005** — `Experimental` signifie qu'un POC ou une implémentation d'évaluation existe ou est explicitement planifié ; ce statut ne remplace pas `Reserved` pour une simple possibilité.
- **DOC-MAT-006** — Une idée purement spéculative ne devient pas une capability réservée uniquement pour préserver une possibilité future.
## Immutabilité des deltas
- **DOC-DELTA-002** — Un fichier `deltas/**/*.md` livré est immuable sur le fond. Il ne reçoit jamais ultérieurement de nouveau scope, de nouvelle règle, de nouvelle validation, de nouveau résultat ou de nouvelle justification.
- **DOC-DELTA-003** — Une correction strictement non sémantique d'un delta livré est autorisée uniquement pour la forme : orthographe, typographie, alignement de tableau ou correction mécanique équivalente.
- **DOC-DELTA-004** — Toute correction autorisée par `DOC-DELTA-003` incrémente le numéro `version` d'en-tête du fichier corrigé.
- **DOC-DELTA-005** — Toute correction sémantique ou tout ajout produit un nouveau delta ou un nouveau `.fix.N` ; l'ancien delta reste inchangé.
- **DOC-DELTA-006** — Un fichier `deltas/**/*.delete.txt` fait partie du contrat de livraison et doit être documenté explicitement par le fichier Markdown du même delta.
- **DOC-DELTA-007** — Un manifest `*.delete.txt` contient uniquement des chemins relatifs à la racine, un par ligne. Le delta associé documente la raison des suppressions et la commande d'application.
## Versions d'en-tête
- **DOC-HEAD-001** — Tout fichier géré par le projet qui possède un en-tête `version` incrémente ce numéro lors de toute modification réelle de contenu.
- **DOC-HEAD-002** — Une modification réelle inclut ajout, suppression, déplacement, reformulation, changement de valeur de configuration, changement de contrat ou changement de chemin dans l'en-tête `file:`.
- **DOC-HEAD-003** — Une transformation purement mécanique par un formatter officiel du projet, telle que `cargo fmt`, ne déclenche pas à elle seule d'incrément de version.
- **DOC-HEAD-004** — Si un formatter est exécuté après une modification réelle du fichier, l'incrément reste requis à cause de la modification réelle.
- **DOC-HEAD-005** — Un nouveau fichier versionné commence normalement à `version: 1`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_PROJECT.md -->
<!-- version: 10 -->
<!-- version: 16 -->
# Règles spécifiques games.sasedev
@@ -13,6 +13,7 @@
- **GAME-WS-006** — Les dépendances tierces communes sont centralisées sous `[workspace.dependencies]` et consommées avec `workspace = true` lorsqu'elles sont partagées.
- **GAME-WS-007** — Un jeu est prioritairement une crate `lib`; lorsquun lancement Desktop est nécessaire, une crate `bin` séparée sous `crates/apps/` dépend de cette lib et ne duplique pas son gameplay.
- **GAME-WS-008** — Les runners Desktop sont nommés `<game>-desktop` et restent indépendants des frontends Android.
- **GAME-WS-009** — Les hosts Web navigateur directs résident sous `Web/<game>/`, hors du workspace Cargo ; ils consomment un adapter WASM dédié et ne contiennent ni crate Rust ni règle de gameplay.
## Générations du moteur
@@ -30,6 +31,7 @@
- **GAME-ASSET-004** — Chaque jeu peut posséder `assets/<game>/` pour ses ressources spécifiques.
- **GAME-ASSET-005** — Le packaging de chaque plateforme assemble les assets communs et spécifiques sans créer de copie source durable dans une crate.
- **GAME-ASSET-006** — Les chemins logiques d'assets doivent éviter les collisions entre espace commun et espace jeu.
- **GAME-ASSET-007** — Un host Web direct package les assets runtime communs et spécifiques depuis `assets/` vers les namespaces de distribution `common/` et `game/` sans créer de copie source durable sous `Web/`; le smoke doit charger au moins un asset de chaque namespace lorsqu'une tranche déclare l'intégration assets complète.
## Android
@@ -63,6 +65,7 @@
- **GAME-TRACE-002** — `tracing-subscriber` compose les subscribers applicatifs et de test ; une librairie métier ne configure pas silencieusement le subscriber global.
- **GAME-TRACE-003** — `tracing-appender` est utilisé lorsque lécriture non bloquante ou les fichiers de logs deviennent nécessaires ; le guard associé reste vivant pendant toute la durée utile.
- **GAME-TRACE-004** — La configuration de logging commune réside dans une crate transverse et ne doit pas être dupliquée par jeu.
- **GAME-TRACE-005** — Un host navigateur direct peut émettre ses diagnostics frontend dans la console du navigateur via un module TypeScript structuré dédié ; ce mécanisme ne remplace pas `tracing` dans le code Rust et ne doit pas importer le bridge tracing Tauri lorsqu'aucun host Tauri n'est présent.
- **GAME-PLATFORM-009** — Une adaptation WebAssembly réutilisable est une crate dédiée distincte de la crate Tauri.
- **GAME-PLATFORM-010** — Dans une app Tauri, `lib.rs` reste une façade/reexport ; `tauri.rs` assemble Tauri et expose les commandes qui délèguent aux modules propriétaires.
@@ -75,3 +78,22 @@
- **GAME-PLATFORM-014** — Pour une launcher Activity Android racine, Back reste une navigation système. Le projet ne doit pas enregistrer de callback consommant Back uniquement pour logger ou exécuter de la logique métier ; sur API 36+, un `PRIORITY_SYSTEM_NAVIGATION_OBSERVER` peut observer l'action sans bloquer le Back-to-home.
- **GAME-PLATFORM-015** — Les exécutables Android initialisent le subscriber partagé et envoient les événements `tracing` vers logcat ; `stderr` n'est pas la destination Android de référence.
## 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-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.
- **GAME-PLATFORM-020** — Un host Web navigateur possède un shell HTML/CSS/TypeScript explicite autour du Canvas/WASM. Le framework de présentation éventuel reste une dépendance frontend et ne fuit ni dans la crate de gameplay ni dans le bridge WASM ; pour le premier POC Snake `0.3.0`, Bootstrap 5 est la baseline de présentation retenue.
- **GAME-PLATFORM-021** — Les dépendances de présentation nécessaires au runtime Web versionné sont déclarées dans le package frontend et intégrées au build Vite ; un CDN externe n'est pas requis pour exécuter le POC local et ne devient une dépendance de distribution qu'après décision explicite.
- **GAME-PLATFORM-022** — SimpleBar et `resize-observer-polyfill` sont des dépendances de shell Web, pas des dépendances Tauri. Lorsqu'un host conserve header et footer fixes, la zone centrale bornée à la hauteur disponible peut les utiliser pour fournir un scroll interne personnalisé sans déplacer les éléments fixes.
- **GAME-PLATFORM-023** — Lorsqu'un host Web reprend le shell KSP avec SimpleBar, `app-main` borne la hauteur disponible et reste non scrollable ; `data-simplebar` appartient à l'enfant central `app-content app-scrollable h-100`, dont `height` et `max-height` valent `100%`. Le polyfill `ResizeObserver` est installé avant l'initialisation applicative et le package `simplebar` est importé par le point d'entrée TypeScript.
- **GAME-PLATFORM-024** — Un host navigateur à simulation fixed-step suspend ses ticks lorsque le document devient caché ou passe en `pagehide`, puis reprend avec une nouvelle origine temporelle sans rattrapage massif au retour ; le resize peut redessiner la scène sans avancer la simulation.
- **GAME-PLATFORM-025** — La provenance d'un host navigateur est construite via `engine-v1-platform-api` avec `PlatformFamily::Web`, `ExecutionModel::Wasm` et `RuntimeHost::Browser`; la classe d'appareil et le profil d'entrée restent des dimensions observées par le host, sans identification matérielle fine.
## Version d'en-tête des fichiers
- **GAME-FILE-001** — Toute modification réelle d'un fichier qui possède un en-tête `version` incrémente ce numéro.
- **GAME-FILE-002** — Les transformations purement mécaniques réalisées par les formatters officiels n'incrémentent pas à elles seules cet en-tête.
- **GAME-FILE-003** — Un changement du champ d'en-tête `file:` dû à un renommage est une modification réelle et incrémente la version.

View File

@@ -0,0 +1,31 @@
<!-- file: docs/rules/RULES_SERVER_HOSTING.md -->
<!-- version: 1 -->
# Règles de portabilité et d'auto-hébergement serveur
## Portabilité
- **HOST-001** — Le logiciel serveur Rust reste indépendant d'une version précise de distribution Linux au niveau métier.
- **HOST-002** — Les dépendances propres au déploiement, à `systemd`, au firewall, au reverse proxy, aux certificats et au layout filesystem restent hors du domaine métier.
- **HOST-003** — Une décision d'infrastructure ne doit pas contaminer les crates de gameplay ou les contrats réseau publics.
## Cible opérationnelle préférée
- **HOST-010** — La cible d'auto-hébergement de référence est Debian Stable.
- **HOST-011** — Debian 13 « trixie » est l'environnement courant de développement/test serveur, sans constituer une dépendance fonctionnelle à cette version.
- **HOST-012** — Les paquets des dépôts officiels Debian sont préférés.
- **HOST-013** — Les dépôts tiers sont évités par défaut et ne sont admis que pour un outil spécifique lorsque le besoin est justifié et la source suffisamment stable.
- **HOST-014** — Ubuntu LTS peut être évalué comme solution secondaire lorsqu'une contrainte technique matérielle rend Debian impraticable ; il n'est pas la cible par défaut.
## Choix futurs d'infrastructure
- **HOST-020** — Les choix futurs tels que HAProxy, nginx, serveur HTTP/3, stockage objet ou autres composants sont évalués au moment du POC/déploiement correspondant.
- **HOST-021** — Leur compatibilité avec Debian Stable, leur maturité, leur disponibilité sans dépôt tiers, leur maintenance et leur support de protocole font partie des critères.
- **HOST-022** — Aucun composant edge/reverse-proxy n'est figé par `0.2.0`.
## Auto-hébergement progressif
- **HOST-030** — Les services peuvent commencer sur une même machine avec séparation logique par service/hostname.
- **HOST-031** — La séparation physique sur plusieurs machines est motivée par charge, sécurité, isolation ou cycle de déploiement.
- **HOST-032** — L'architecture doit permettre de déplacer Web/API, assets, realtime, base de données et media/replay sans modifier les règles Uroburas.
- **HOST-033** — Un CDN tiers n'est pas une dépendance obligatoire ; l'asset delivery auto-hébergé et sa distribution progressive restent une trajectoire supportée.

View File

@@ -0,0 +1,57 @@
<!-- file: docs/rules/RULES_SESSION_PLANNING.md -->
<!-- version: 5 -->
# Règles de cadrage des versions, sessions et prompts
## Objet
Ces règles imposent un découpage suffisamment petit pour qu'une version puisse être développée complètement dans une seule session et reprise sans ambiguïté.
## `pre.1` — cadrage obligatoire
- **SESSION-001** — Toute nouvelle version commence par une `0-pre.1` de cadrage.
- **SESSION-002** — Cette tranche couvre au minimum l'audit de la base, le brainstorming/recherche de requirements, le sizing, les dépendances, les validations prévues et le découpage prévisionnel.
- **SESSION-003** — Une première implémentation peut être incluse dans `0-pre.1` uniquement si elle est petite, cohérente et n'empêche pas le cadrage d'être terminé.
- **SESSION-004** — Si le sizing montre que l'objectif global ne peut raisonnablement pas être terminé dans la session, il est scindé en plusieurs versions avant le développement lourd.
- **SESSION-005** — `0-pre.1` crée ou révise obligatoirement le plan de la version sous `docs/plans/`. Ce plan est un livrable du cadrage, pas une note optionnelle.
- **SESSION-006** — Le plan de version contient au minimum l'objectif et le scope, les décisions acquises, les dépendances/risques utiles, les validations attendues, les hors-périmètre et une prévision souple des tranches jusqu'à la release stable.
- **SESSION-007** — La prévision du plan n'est pas un calendrier figé : une tranche peut être scindée, fusionnée, déplacée ou complétée par un fix lorsque les résultats réels le justifient. Le plan actif est alors réconcilié et le delta explique le changement.
- **SESSION-008** — `ROADMAP.md` reste macroscopique, le plan porte le découpage prévisionnel fin de la version et les deltas enregistrent ce qui a réellement été livré.
- **SESSION-009** — Le forecast créé en `0-pre.1` rend explicitement visible une tranche de consolidation avant la candidate finale ; cette tranche couvre au minimum la réconciliation de la documentation durable, `CHANGELOG.md`, `ROADMAP.md`, l'historique applicable et le prompt de la version/session suivante, même si son numéro exact reste prévisionnel.
## Taille des tranches
- **SESSION-010** — Une tranche `pre.N`, `alpha.N`, `beta.N`, `rc.N` ou `fix.N` vise normalement un delta correspondant à environ 15 à 30 minutes de travail effectif.
- **SESSION-011** — Une tranche clairement plus lourde est scindée avant exécution.
- **SESSION-012** — Plusieurs micro-tranches sans valeur de validation indépendante peuvent être regroupées.
- **SESSION-013** — Le découpage suit des unités fonctionnelles complètes et validables ; une fonctionnalité ne doit pas être volontairement coupée au milieu uniquement pour respecter un numéro de prerelease.
- **SESSION-014** — Chaque tranche livre son delta et ses validations proportionnelles avant la tranche suivante.
- **SESSION-015** — Le plan créé en `0-pre.1` identifie explicitement le ou les rares jalons où `cargo test --workspace --all-targets --all-features` apporte une valeur globale (initial si nécessaire, préfinal/final ou changement transverse). Les autres tranches privilégient les tests `cargo test -p ...` ciblés.
## Une version par session
- **SESSION-020** — Une session de développement est dimensionnée pour livrer au minimum une version concrète complète, de son cadrage jusqu'à sa release stable.
- **SESSION-021** — Une prerelease est une tranche interne de progression et ne constitue pas une cible normale de fin de session ; la session ne doit pas être planifiée pour s'arrêter au milieu de la version ouverte.
- **SESSION-022** — Si de nouvelles informations rendent la version trop grande, le scope restant est replanifié explicitement vers une ou plusieurs versions suivantes au lieu de prolonger indéfiniment la version courante.
- **SESSION-023** — Le découpage prévisionnel doit donc permettre de suivre toute la progression de la version dans la même session, tout en restant assez souple pour insérer des fixes ou déplacer du scope sans forcer artificiellement la fermeture.
## Dernières tranches
- **SESSION-030** — Les dernières tranches consolident les validations, la documentation durable, `CHANGELOG.md`, `ROADMAP.md`, l'historique applicable et le prompt de la prochaine session.
- **SESSION-031** — La release stable reste autant que possible mécanique et n'introduit pas de nouveau scope fonctionnel ou architectural.
## Prompt de prochaine session
- **PROMPT-001** — Le prompt suivant est préparé à partir d'un état réellement validé ; il ne prétend jamais qu'une validation future a déjà été exécutée.
- **PROMPT-002** — Le prompt indique la base exacte, la version cible, l'objectif, le scope inclus/exclus, les décisions gelées, les points ouverts et les validations attendues.
- **PROMPT-003** — Le prompt distingue explicitement les résultats déjà validés des commandes à exécuter dans la nouvelle session.
- **PROMPT-004** — Le prompt donne une trajectoire prévisionnelle des tranches sans rendre cette prévision immuable.
- **PROMPT-005** — Le prompt rappelle les invariants essentiels mais renvoie aux RULES pour les détails normatifs au lieu de les recopier intégralement.
- **PROMPT-006** — Le prompt contient suffisamment de contexte pour reprendre la version sans dépendre de la mémoire conversationnelle ni relire toute l'histoire du dépôt.
- **PROMPT-007** — Le prompt précise la condition de fin de session et les livrables attendus.
- **PROMPT-008** — Si `pre.1` invalide le sizing prévu par le prompt, le nouveau découpage est documenté immédiatement avant le développement lourd.
- **PROMPT-009** — Tout nouveau prompt de version applique `docs/rules/PROMPT_STRUCTURE.md`; le présent document fixe le cycle de session tandis que `PROMPT_STRUCTURE.md` fixe le contenu opératoire à rappeler.
## Relation avec VERSION_WORKFLOW
`VERSION_WORKFLOW.md` définit le cycle SemVer et la maturation. Le présent document précise comment dimensionner et transmettre une session de travail.

View File

@@ -0,0 +1,93 @@
<!-- file: docs/rules/RULES_VALIDATION_MATRIX.md -->
<!-- version: 4 -->
# Matrice normative des commandes et validations
## Principes
La matrice associe un identifiant stable à chaque famille de commandes. Le delta sélectionne les commandes applicables selon les fichiers touchés, leurs dépendances et la phase de maturité.
Une commande dépendante n'est exécutée que lorsque ses prérequis applicables sont propres.
Les commandes ciblées restent la norme pendant l'implémentation ; les gates workspace et les smokes de distribution deviennent plus larges à mesure que la version approche de beta/RC.
## Matrice
| ID | Commande / action | Dépend de | Déclencheur principal | Phase minimale typique |
|-----------|------------------------------------------------------------------------------------|---------------------------------|----------------------------------------------------|------------------------|
| `CMD-001` | `cargo fmt --all` | — | Rust ou dépendance Cargo modifiée | `pre` |
| `CMD-002` | `cargo fmt --all -- --check` | `CMD-001` | Rust ou dépendance Cargo modifiée | `pre` |
| `CMD-010` | `python3 scripts/audit_rust_workspace_rules.py` | — | Rust/Cargo/workspace/règles Rust concernés | `pre` |
| `CMD-011` | `python3 scripts/audit_markdown_tables.py ...` | — | Markdown concerné | `pre` |
| `CMD-012` | `python3 scripts/audit_distribution_layout.py` | — | layout/build/distribution concerné | `pre` |
| `CMD-020` | `cargo check -p <crate>` | audits applicables | diagnostic ciblé facultatif | `pre` |
| `CMD-021` | `cargo test -p <crate> --all-targets --all-features` | `CMD-023`, `CMD-024` | comportement/API crate | `pre` |
| `CMD-022` | tests ciblés des crates consommatrices impactées | `CMD-021` | API publique/contrat partagé modifié | `pre` |
| `CMD-023` | `cargo check --workspace` | `CMD-002`, audits applicables | Rust ou dépendance Cargo modifiée | `pre` |
| `CMD-024` | `cargo clippy --workspace --all-targets --all-features -- -D warnings` | `CMD-023` | Rust ou dépendance Cargo modifiée | `pre` |
| `CMD-025` | `cargo test --workspace --all-targets --all-features` | `CMD-024` | gate rare planifiée / portée transverse incertaine | selon plan |
| `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-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-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 |
| `CMD-053` | install + smoke appareil réel | `CMD-051` | Android concerné | beta/RC |
| `CMD-060` | `cargo clean --dry-run --verbose` | — | contrôle disque / préparation nettoyage | maintenance |
| `CMD-061` | `cargo clean` | décision explicite de nettoyage | accumulation disque / jalon de cycle | maintenance |
| `CMD-062` | `cargo clean -p <package>` ou nettoyage par `--release` / `--profile` / `--target` | — | nettoyage ciblé suffisant | maintenance |
## Sélection proportionnelle
Les audits `CMD-010` à `CMD-012` sont sélectionnés selon les fichiers touchés ; ils ne forment pas un trio obligatoire.
Dès que du Rust ou une dépendance Cargo change, la séquence minimale obligatoire est `CMD-001``CMD-002` → audits applicables → `CMD-023``CMD-024`. Les tests `CMD-021`/`CMD-022` restent ciblés par défaut.
`CMD-025` est planifié seulement à un ou quelques jalons de la version/session, par exemple un état initial lorsqu'une baseline globale doit être confirmée, une validation préfinale/finale, ou un changement dont la portée transverse ne peut pas être bornée avec confiance.
`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`.
## Dépendances entre crates
Lorsqu'une crate `A` change :
1. exécuter les validations ciblées de `A` ;
2. déterminer les consommateurs dont le contrat est affecté ;
3. exécuter les validations ciblées des consommateurs concernés ;
4. passer aux gates workspace lorsque la portée ne peut plus être bornée raisonnablement ou lorsqu'une frontière de maturité l'exige.
Une modification interne sans changement de contrat ne force pas mécaniquement tous les consommateurs transitifs à être retestés.
Une modification d'API publique, de représentation partagée, de feature structurante ou de comportement contractuel élargit la portée des tests.
## Nettoyage Cargo et contrôle disque
Le projet utilise `../builds/sasedev-games/target` comme `target-dir`. Cette zone peut accumuler plusieurs profils, triples cibles, artefacts incrémentaux et anciennes variantes au cours d'un cycle de développement.
La politique est donc double :
- utiliser `CMD-062` lorsqu'un nettoyage ciblé suffit ;
- utiliser `CMD-061` périodiquement afin d'éviter une croissance non bornée du répertoire de build.
Le nettoyage complet est normalement positionné au début d'un nouveau cycle de développement lorsque l'on souhaite évacuer les artefacts de la version précédente, ou avant une validation finale RC/stable lorsqu'un rebuild propre est recherché et que l'espace disque le justifie.
Le delta ou le plan de version indique quel jalon de nettoyage est retenu. Il n'est pas nécessaire d'exécuter `cargo clean` à chaque prerelease.
## Vérification des versions d'en-tête
Avant livraison d'un delta :
1. fichier modifié réellement et déjà versionné → en-tête incrémenté ;
2. fichier uniquement reformaté mécaniquement → en-tête inchangé ;
3. nouveau fichier versionné → `version: 1` sauf règle spécialisée ;
4. renommage modifiant `file:` → en-tête incrémenté ;
5. delta antérieur → aucun ajout sémantique rétroactif.
Cette vérification fait partie de la revue de livraison même lorsqu'aucun audit automatisé ne dispose encore de la version précédente pour comparer.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/VERSION_WORKFLOW.md -->
<!-- version: 1 -->
<!-- version: 6 -->
# Versionnement, maturité et livraisons
@@ -73,3 +73,72 @@ deltas/0.1.0/1-alpha.1.md
deltas/0.1.0/3-rc.2.md
deltas/0.1.0/rel.md
```
## Versions principalement documentaires
Une version de conception suit le même SemVer que les autres versions et peut utiliser plusieurs `0-pre.N` pour permettre une revue humaine progressive.
Les audits Markdown et de règles valident la cohérence mécanique mais ne valent jamais acceptation du fond documentaire. Une prerelease documentaire reste candidate jusqu'à revue explicite de son contenu.
Les gates techniques sont proportionnelles aux fichiers touchés :
- un delta uniquement documentaire exécute les audits documentaires applicables ;
- une modification Rust déclenche les gates Rust prévues par les règles ;
- une modification Android/Gradle déclenche les gates Android concernées ;
- une modification Tauri/frontend/build déclenche les gates correspondantes.
La promotion `rc` puis stable d'une version de conception exige une validation humaine explicite du contenu consolidé.
## Travail en RC
- **VER-RC-001** — Une RC est fonctionnellement gelée. Les nouvelles fonctionnalités, nouvelles capabilities, refactors architecturaux non indispensables et changements volontaires de comportement sont interdits.
- **VER-RC-002** — Les modifications de code restent autorisées en RC lorsqu'elles corrigent un bug, un test erroné, un défaut de packaging, un problème de sécurité, une incompatibilité de release ou un défaut strictement nécessaire à la publication.
- **VER-RC-003** — Un correctif conforme à `VER-RC-002` produit `3-rc.N.fix.M` et n'impose pas un retour automatique en beta.
- **VER-RC-004** — Si le périmètre fonctionnel est rouvert pendant une RC, la candidate est abandonnée et le développement revient à une phase adaptée, normalement beta, avant une nouvelle RC.
## Prompt de la version suivante
- **VER-PROMPT-001** — Le prompt de démarrage de la version suivante est rédigé pendant la consolidation finale lorsque la cible suivante est suffisamment connue ; il ne dépend pas d'une future session pour exister.
- **VER-PROMPT-002** — La première RC dont le périmètre est effectivement gelé vérifie et complète ce prompt à partir de l'état réellement candidat à publication.
- **VER-PROMPT-003** — Le prompt peut être complété pendant les fixes RC ou la release stable, mais ne doit pas contenir de résultats futurs présentés comme déjà validés.
- **VER-PROMPT-004** — La structure et les rappels opératoires obligatoires du prompt sont définis par `docs/rules/PROMPT_STRUCTURE.md`.
## Correctifs strictement documentaires
- **VER-DOCFIX-001** — Un `.fix.N` limité à la documentation, aux prompts, aux deltas, à `history/` ou aux règles non consommées par le build/runtime ne modifie aucune version technique : ni `workspace.package.version`/`Cargo.toml`, ni `package.json`, ni Gradle/Android, ni `tauri.conf.json`, ni autre métadonnée de version consommée par un build ou une distribution. L'identité du correctif est portée uniquement par le delta et son archive.
- **VER-DOCFIX-002** — Une prerelease non-fix (`pre.N`, `alpha.N`, `beta.N`, `rc.N`) synchronise sa version technique selon le workflow de phase même lorsque son contenu est principalement documentaire.
- **VER-DOCFIX-003** — Dès qu'un correctif touche du code, une configuration exécutable, un manifeste consommé par le build/runtime ou un artefact distribué, la version technique suit l'identifiant `.fix.N`.
## Phases de développement
Une version suit conceptuellement :
```text
PLAN → IMPLEMENT → INTEGRATE → VALIDATE → CANDIDATE → RELEASE
```
- **VER-PHASE-001** — Ces phases structurent le travail mais n'imposent pas une prerelease distincte pour chacune.
- **VER-PHASE-002** — `0-pre.1` est obligatoirement la tranche de cadrage de la version : audit de la base, brainstorming/recherche de requirements, sizing, planification, dépendances, validations attendues et création/révision du plan actif sous `docs/plans/` avec son découpage prévisionnel souple.
- **VER-PHASE-003** — `0-pre.1` peut aussi contenir une première implémentation strictement bornée si le cadrage montre qu'elle tient naturellement dans la même tranche, mais le cadrage ne doit jamais être sauté.
- **VER-PHASE-004** — Une version doit être dimensionnée pour que l'ensemble de son développement puisse être terminé dans une seule session de travail. Si ce n'est pas réaliste, son objectif est découpé en plusieurs versions/sessions avant le développement lourd.
- **VER-PHASE-005** — Le plan établi en `0-pre.1` est vivant : il peut regrouper, scinder, reporter ou reclasser des tranches lorsque l'information réelle le justifie, sans réécrire les deltas déjà livrés. Il reste la référence de suivi prévisionnel de la version jusqu'à sa clôture.
- **VER-PHASE-006** — Une tranche `pre.N`, `alpha.N`, `beta.N`, `rc.N` ou leur fix vise normalement un delta réalisable en environ 15 à 30 minutes. Une tranche sensiblement plus lourde est découpée avant exécution ; une tranche trop petite peut être regroupée avec une tranche adjacente cohérente.
- **VER-PHASE-007** — Le découpage privilégie des unités fonctionnelles complètes et validables, pas des coupures arbitraires au milieu d'une fonctionnalité.
- **VER-PHASE-008** — Chaque tranche ferme son propre scope, produit son delta et ses validations proportionnelles avant l'ouverture de la tranche suivante.
- **VER-PHASE-009** — Alpha, beta et RC sont utilisées proportionnellement au risque et à la maturité ; elles ne sont pas créées uniquement pour satisfaire une séquence cérémonielle.
- **VER-PHASE-010** — La dernière tranche de développement avant la candidate de publication est réservée à la consolidation : validations finales, documentation durable, `CHANGELOG.md`, `ROADMAP.md`, historique applicable et préparation du prompt de la version/session suivante.
- **VER-PHASE-011** — La release stable est autant que possible mécanique : elle ne doit pas introduire une nouvelle fonctionnalité, une nouvelle décision architecturale ou un nouveau scope non validé dans une candidate précédente.
## Versions Tauri/frontend
- **VER-TAURI-001** — Pour une app Tauri Rust du workspace, la version produit canonique est la version Cargo.
- **VER-TAURI-002** — `tauri.conf.json` omet `version` lorsque Tauri peut hériter de la version `Cargo.toml`.
- **VER-TAURI-003** — La `version` de `package.json` décrit le package frontend local et n'est pas synchronisée à chaque `pre.N` ou `.fix.N`.
- **VER-TAURI-004** — Tant que le frontend n'est pas publié comme package npm, sa version est mise à jour uniquement aux jalons significatifs retenus par le projet, au minimum lorsque cela est nécessaire pour alpha, beta, RC ou stable.
## Corrections des deltas déjà livrés
- **VER-DELTA-001** — Un delta livré n'est jamais enrichi après coup.
- **VER-DELTA-002** — Une correction purement orthographique, typographique, d'alignement ou de forme sans changement de sens peut être appliquée au fichier delta existant si son en-tête `version` est incrémenté.
- **VER-DELTA-003** — Une correction qui change le sens, le scope, les validations, les suppressions ou les décisions produit un nouveau `.fix.N`.
- **VER-DELTA-004** — Les manifests `*.delete.txt` sont toujours décrits dans le delta Markdown qui les introduit.

View File

@@ -0,0 +1,59 @@
<!-- file: docs/studies/000-README.md -->
<!-- version: 9 -->
# Études
Ce répertoire accueille les analyses construites qui comparent des solutions, évaluent une piste ou préparent une décision.
Une étude reste non normative. Elle peut conclure notamment à :
- `retained` ;
- `deferred` ;
- `rejected` ;
- `needs-poc`.
Une conclusion `retained` ne crée pas à elle seule une règle, une capability ou une entrée de roadmap. La décision résultante doit être portée explicitement dans le document architectural ou normatif approprié.
Les études conservent les alternatives et raisons utiles à la compréhension future, y compris lorsqu'une piste est rejetée.
## Études 0.2.0
- [`001-FUNCTIONAL_CAPABILITY_INVENTORY.md`](001-FUNCTIONAL_CAPABILITY_INVENTORY.md) — inventaire fonctionnel initial sans engagement d'implémentation.
- [`002-LAYERING_AND_OWNERSHIP_STUDY.md`](002-LAYERING_AND_OWNERSHIP_STUDY.md) — étude du découpage kernel, capability, game-system, plateforme, provider, service et jeu.
- [`003-PLATFORM_CAPABILITY_STUDY.md`](003-PLATFORM_CAPABILITY_STUDY.md) — axes plateforme/device/host/backend et disponibilité des capacités.
- [`004-GAME_ARCHETYPE_PRESSURE_TEST.md`](004-GAME_ARCHETYPE_PRESSURE_TEST.md) — vérification du modèle par plusieurs familles de jeux.
- [`005-DEPENDENCY_AND_COMPOSITION_STUDY.md`](005-DEPENDENCY_AND_COMPOSITION_STUDY.md) — dépendances autorisées et composition statique envisagée.
- [`006-REALTIME_MULTIPLAYER_SERVER_STUDY.md`](006-REALTIME_MULTIPLAYER_SERVER_STUDY.md) — transport, session, synchronisation, autorité, resync et scaling du multijoueur temps réel.
- [`007-GAME_AI_AND_BOT_EXECUTION_STUDY.md`](007-GAME_AI_AND_BOT_EXECUTION_STUDY.md) — adversaires pilotés par logique, bot local, bot serveur et frontières avec l'IA générative/ML.
- [`008-WEB_IDENTITY_AND_GAME_HOSTING_STUDY.md`](008-WEB_IDENTITY_AND_GAME_HOSTING_STUDY.md) — identité canonique, providers externes, hébergement global puis sites/services propres à chaque jeu.
Ces études sont des propositions à relire. Elles ne deviennent pas automatiquement des décisions d'architecture.
## Études POC plateforme
- [`009-PLATFORM_POC_CANDIDATES.md`](009-PLATFORM_POC_CANDIDATES.md) — inventaire des POC plateforme focalisés sur Snake comme jeu-sonde unique.
- [`010-PLATFORM_POC_REUSE_AND_DELTA.md`](010-PLATFORM_POC_REUSE_AND_DELTA.md) — code réutilisable, modifications minimales et frontières à tester.
- [`011-PLATFORM_POC_VALIDATION_MATRIX.md`](011-PLATFORM_POC_VALIDATION_MATRIX.md) — critères comparables de build, runtime, input, packaging et intégration plateforme.
- [`012-PLATFORM_POC_SEQUENCE.md`](012-PLATFORM_POC_SEQUENCE.md) — ordre proposé des POC pour une future série `0.3.x`.
Ces documents étudient les POC à réaliser ; ils ne lancent encore aucune implémentation.
## Étude du prochain jeu réel
- [`013-UROBURAS_FUNCTIONAL_SPEC.md`](013-UROBURAS_FUNCTIONAL_SPEC.md) — spécification fonctionnelle initiale de Uroburas.
- [`014-UROBURAS_MODES_AND_SESSION_RULES.md`](014-UROBURAS_MODES_AND_SESSION_RULES.md) — Challenge, PvP Battles et Persistent Battle Royale.
- [`015-UROBURAS_MAP_ASSET_AND_UGC_SPEC.md`](015-UROBURAS_MAP_ASSET_AND_UGC_SPEC.md) — maps/assets téléchargés, règles de map, éditeur et UGC.
- [`016-UROBURAS_COMBAT_ITEM_EFFECT_SPEC.md`](016-UROBURAS_COMBAT_ITEM_EFFECT_SPEC.md) — armes, protections et interactions tête/corps/queue.
- [`017-UROBURAS_SCORE_RESPAWN_AND_HALL_OF_FAME.md`](017-UROBURAS_SCORE_RESPAWN_AND_HALL_OF_FAME.md) — score, vies, rewarded continue/rejoin et classements.
- [`018-UROBURAS_SERVER_MEDIA_AND_OBSERVATION_SPEC.md`](018-UROBURAS_SERVER_MEDIA_AND_OBSERVATION_SPEC.md) — spectator, bots, replay, streaming et vidéo régénérée.
## Classification Uroburas avant implémentation
- [`019-UROBURAS_FUNCTIONAL_OWNERSHIP_CLASSIFICATION.md`](019-UROBURAS_FUNCTIONAL_OWNERSHIP_CLASSIFICATION.md) — mapping des fonctionnalités vers kernel, capabilities, game-systems, Uroburas, server, provider, platform et tooling.
- [`020-UROBURAS_CRATE_DECOMPOSITION_STUDY.md`](020-UROBURAS_CRATE_DECOMPOSITION_STUDY.md) — proposition de familles de crates et dépendances sans monolithe jeu.
- [`021-UROBURAS_SERVER_REFERENCE_STACK.md`](021-UROBURAS_SERVER_REFERENCE_STACK.md) — stack serveur de référence Actix/Tokio/tokio-tungstenite/Maud/Fluent/Lettre et gRPC/Tonic conditionnel.
- [`022-UROBURAS_IMPLEMENTATION_DEPENDENCY_ORDER.md`](022-UROBURAS_IMPLEMENTATION_DEPENDENCY_ORDER.md) — ordre d'implémentation recommandé pour le Mode 1 avant les modes multijoueurs.
## É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`.

View File

@@ -0,0 +1,488 @@
<!-- file: docs/studies/001-FUNCTIONAL_CAPABILITY_INVENTORY.md -->
<!-- version: 3 -->
# Inventaire fonctionnel initial
## Statut
Étude non normative pour `0.2.0-0-pre.2`.
Le but est d'identifier les besoins plausibles déjà justifiés par les jeux et plateformes envisagés. La présence d'une entrée ne signifie ni crate à créer, ni API figée, ni version d'implémentation engagée.
## Principe de classement
Chaque besoin doit finir dans l'une des familles suivantes :
- **kernel** — primitive minimale nécessaire au fonctionnement générique du moteur ;
- **technical capability** — service technique réutilisable exposé au jeu ;
- **game-system** — mécanique de gameplay réutilisable entre plusieurs jeux ;
- **platform adapter** — implémentation d'un contrat pour un OS, host ou backend ;
- **provider** — intégration d'un service externe interchangeable ;
- **server service** — autorité ou service distant partagé ;
- **tooling** — construction, génération, validation ou distribution ;
- **game-specific** — règle propre à un jeu qui ne doit pas être généralisée prématurément.
## Kernel candidat
Le kernel doit rester volontairement petit.
Candidats déjà justifiés :
- lifecycle générique `start / update / render / stop` ;
- horloge monotone et temps de frame ;
- fixed-step ou scheduling déterministe lorsque requis ;
- abstraction d'événements/runtime sans dépendance directe au jeu ;
- contexte runtime/provenance déjà introduit en `0.1.0` ;
- contrats minimaux nécessaires pour connecter input et rendu ;
- politique de quit/lifecycle indépendante de SDL/Android/Tauri.
À challenger avant décision :
- scene stack ;
- scheduler générique ;
- ECS ;
- task graph ;
- event bus généraliste.
Ces éléments ne doivent pas être réservés uniquement parce qu'ils sont courants dans d'autres moteurs.
## Technical capabilities candidates
### Input
Besoins identifiés :
- actions sémantiques indépendantes des touches physiques ;
- clavier ;
- souris/pointer ;
- tactile ;
- gestes ;
- contrôles virtuels affichés ;
- gamepad ;
- bindings configurables ;
- profils par produit et plateforme ;
- multi-player local avec plusieurs périphériques lorsque le jeu le demande.
Le jeu consomme des actions telles que `MoveUp`, `PrimaryAction` ou `Pause`, pas `KeyW` ou `SwipeUp`.
### Rendering
Besoins identifiés :
- dessin 2D ;
- sprites ;
- textures ;
- texte ;
- viewport/résolution virtuelle ;
- caméra 2D pour cartes plus grandes que l'écran ;
- couches/z-order ;
- animation sprite-sheet ;
- primitives simples de debug.
La 3D n'est pas réservée à ce stade.
### Audio
Besoins identifiés :
- effets sonores ;
- musique ;
- volume/mute ;
- lifecycle audio mobile ;
- éventuellement groupes/bus simples.
La voix temps réel reste une idée/étude future liée à un cas de jeu concret.
### Assets
Besoins identifiés :
- assets embarqués ;
- assets communs et propres au jeu ;
- résolution logique des chemins ;
- variantes par densité/résolution si nécessaire ;
- téléchargement/cache d'assets distants pour certains jeux futurs ;
- intégrité/version d'asset lorsqu'un CDN sera réellement introduit.
### Persistence locale
Besoins identifiés :
- préférences ;
- save-game ;
- progression locale ;
- cache ;
- journal/outbox pour online-optional à terme.
Les garanties exactes de transaction, migration et chiffrement seront étudiées quand un jeu les exigera.
### Networking client
Besoins identifiés :
- HTTP(S) ;
- WebSocket ;
- reconnexion ;
- timeout/backoff ;
- protocole versionné côté jeu/service ;
- état de connectivité ;
- séparation transport/protocole.
WebRTC et gRPC restent des solutions à étudier pour des usages précis et ne sont pas imposés au framework général.
### Logging/diagnostics
Besoins identifiés :
- `tracing` commun ;
- domaines par crate/sous-système ;
- niveau maximal déterminé par produit/build ;
- filtrage runtime dans la limite de ce qui a été compilé ;
- logs Android/logcat, Desktop et Tauri ;
- métriques/telemetry ultérieures sans les confondre avec le logging.
### Identity/auth client
Besoins identifiés :
- joueur anonyme ;
- compte requis ;
- upgrade anonyme vers compte ;
- identité canonique propre au backend ;
- liaison d'identités externes ;
- session/token ;
- déconnexion et changement de compte.
Google, Play Games, Apple, Steam ou autres sont des providers, pas l'identité canonique du moteur.
### Monetization client
Besoins identifiés :
- rewarded ad ;
- interstitial éventuel selon jeu ;
- disponibilité/cooldown ;
- résultat `completed / skipped / failed / unavailable` ;
- absence complète de monétisation sur certaines plateformes/produits ;
- achats intégrés futurs si un jeu en a besoin.
Les régies spécifiques restent des providers.
## Game-systems candidats
### Score et objectifs
- score ;
- combo/multiplicateur ;
- chronomètre ;
- objectifs ;
- calcul de résultat final.
Le calcul exact reste contrôlé par le jeu.
### Lives / attempts
- nombre de vies ou tentatives ;
- consommation/restauration ;
- politique de game-over ;
- recharge éventuelle.
### Energy / stamina
- réserve courante/maximale ;
- coût d'action ;
- recharge temporelle ;
- recharge par reward/ad/inventory ;
- politique offline éventuelle.
### Progression / XP / levels
- expérience ;
- niveaux ;
- seuils ;
- progression débloquée ;
- récompenses de niveau.
La notion de « level » de progression ne doit pas être confondue avec une map/stage.
### Inventory / items
- item type/id ;
- quantité ;
- capacité ;
- acquisition/consommation ;
- metadata de gameplay ;
- sérialisation.
Équipement, crafting, rareté ou économie ne sont pas imposés au noyau inventaire tant qu'un jeu ne les exige pas.
### Grid / tile map
Besoins identifiés par Snake, Sokoban et aventure puzzle :
- coordonnées de grille ;
- taille de cellule ;
- occupancy ;
- tile map ;
- couches ;
- obstacles ;
- wrap/no-wrap ;
- spawn zones ;
- chargement de map.
### Collision 2D
Plusieurs niveaux possibles :
- collision grille/cellule ;
- AABB ;
- formes simples ;
- collision continue/physique avancée.
Seules les collisions réellement nécessaires seront implémentées. Un moteur physique généraliste n'est pas réservé à ce stade.
### Game AI / bot control
Besoins identifiés :
- adversaire piloté par règles déterministes ;
- bot local embarqué ;
- bot serveur pour parties online ;
- difficulté configurable ;
- décision basée sur un état de jeu réduit ou complet ;
- budget de calcul/tick ;
- reproductibilité éventuelle par seed ;
- remplacement d'un joueur déconnecté dans certains jeux ;
- simulation de charge ou de joueurs synthétiques pour tests.
Le terme « IA » ne signifie pas nécessairement machine learning. Un bot peut être une simple machine à états, un arbre de décision, du pathfinding, une recherche minimax/MCTS ou une stratégie spécialisée.
Le modèle doit permettre d'exécuter la logique côté client ou côté serveur selon le jeu sans dupliquer les règles métier.
### Determinism / seeded challenge
Besoins identifiés par Reflex compétitif et potentiellement puzzles/races :
- seed ;
- ruleset versionné ;
- génération reproductible ;
- horodatage relatif ;
- replay ou validation partielle ultérieure.
### Puzzle systems
Systèmes potentiellement réutilisables, mais à ne créer qu'après second consommateur ou besoin clair :
- Sokoban-like push blocks ;
- pipe/plumber connectivity ;
- laser/mirror ray routing ;
- switches/doors ;
- collect-and-unlock.
### Navigation/map progression
Pour aventure/puzzle :
- stages/maps ;
- transitions ;
- checkpoints ;
- unlock graph.
À distinguer du `Progression/XP`.
### Racing systems
Candidats si un projet racing est lancé :
- checkpoints ;
- laps ;
- start grid ;
- race timer ;
- classement en course ;
- ghost/replay ;
- synchronisation multiplayer.
La physique de véhicule reste hors du framework général tant qu'elle n'est pas justifiée.
### Combat systems
Candidats pour fighting/hack'n slash/MMORPG :
- health/damage ;
- cooldown ;
- hit/hurt boxes ;
- status effects ;
- abilities ;
- target selection.
Ils ne sont pas réservés comme API aujourd'hui ; ils identifient seulement une pression architecturale future.
## Platform adapters candidates
Les adapters implémentent les contrats techniques sans contenir la logique de jeu.
Cibles déjà identifiées ou réservées :
- SDL3 native Desktop ;
- SDL3 Android ;
- Web/WASM ;
- Tauri Desktop host ;
- Tauri Android host expérimental futur ;
- macOS natif réservé ;
- iOS natif réservé.
L'OS, la classe de device, l'execution model et le host restent des dimensions distinctes.
## Providers candidates
Providers externes déjà justifiés par les objectifs :
- ads : AdMob, puis autres régies si besoin ;
- identity : Google/OAuth, Play Games, Apple/Steam ultérieurement selon plateforme ;
- leaderboard : backend propre et/ou provider plateforme ;
- cloud storage : backend propre ;
- assets/CDN : provider de stockage/CDN ;
- paiement/IAP : stores plateforme ;
- crypto reward/wallet : provider isolé uniquement pour un projet PKE concerné.
Aucun provider ne doit remonter dans le kernel.
## Server services candidates
### Portail Web / sites de jeux
Besoins identifiés :
- portail global `games.sasedev.com` ;
- pages/catalogue des jeux ;
- profil joueur global ;
- pages de leaderboard ;
- pages d'aide/support ;
- pages légales et confidentialité ;
- landing pages spécifiques par jeu ;
- possibilité qu'un jeu migre ensuite vers son propre domaine ;
- conservation de l'identité centrale malgré la séparation du site ;
- APIs partagées et APIs spécifiques par jeu ;
- séparation possible entre `www`, `auth`, `api`, `cdn`, `leaderboard`, `realtime`, `admin` et services propres au jeu.
Le découpage DNS/deployment ne doit pas imposer le découpage interne initial. Une architecture modulaire peut commencer déployée ensemble puis être séparée.
### Services Web non temps réel
Besoins identifiés :
- auth/identity ;
- profile ;
- save/progression cloud ;
- leaderboard ;
- inventory/economy authoritative lorsqu'une valeur partagée existe ;
- configuration/rulesets distants ;
- asset metadata/CDN orchestration ;
- administration/modération selon besoins ;
- anti-cheat/validation de résultats ;
- reward authority pour tout jeu avec valeur monétaire ou crypto.
Ces services peuvent être exposés en HTTP(S) et ne doivent pas être placés dans la boucle temps réel uniquement parce qu'un jeu possède aussi un mode multijoueur.
### Lobby / matchmaking / session control
Besoins identifiés :
- création et découverte de partie ;
- invitation/join/leave ;
- matchmaking ;
- allocation d'une room/session ;
- roster de joueurs ;
- ready/start/end ;
- reprise de session ;
- spectator policy éventuelle ;
- routing vers l'instance realtime responsable.
Le control plane d'une partie peut être séparé du data plane temps réel.
### Realtime multiplayer server
Capacités à étudier explicitement :
- endpoint/gateway WebSocket ou transport realtime équivalent ;
- authentification et attachement d'une connexion à une session ;
- ingestion d'inputs/commands client plutôt que confiance dans un état client arbitraire ;
- tick ou cadence serveur ;
- simulation/état authoritative lorsque le jeu l'exige ;
- ordre des messages, sequence numbers et déduplication ;
- acknowledgement lorsque nécessaire ;
- snapshots complets ;
- deltas/patches entre snapshots ;
- version/revision de l'état ;
- interest management pour ne diffuser qu'un sous-ensemble pertinent du monde ;
- broadcast/multicast par room ;
- backpressure et limites de file ;
- détection de timeout/heartbeat ;
- disconnect/reconnect ;
- reprise et resynchronisation après trou de messages ;
- late join ;
- spectator éventuel ;
- historique court/replay buffer lorsque nécessaire ;
- validation anti-cheat des inputs/actions ;
- séparation entre données persistantes et état éphémère de session ;
- métriques, logs, traces et health du service temps réel ;
- horizontal scaling, room placement et transfert/rehydration éventuel d'une session.
### Synchronisation client associée
Les capacités client correspondantes peuvent inclure :
- buffer d'inputs ;
- interpolation ;
- extrapolation limitée ;
- client-side prediction ;
- reconciliation ;
- rollback pour les genres qui le justifient ;
- clock/tick synchronization ;
- snapshot application ;
- delta application ;
- reconnect/resync state machine.
Toutes ne sont pas nécessaires pour tous les jeux. Par exemple Snake à faible fréquence, racing et fighting n'ont pas les mêmes exigences de latence ni la même stratégie de synchronisation.
### Chat et présence
À séparer du gameplay realtime :
- présence online/offline ;
- chat lobby ;
- chat de partie ;
- modération ;
- rate limiting ;
- historique selon produit.
Le déploiement peut commencer comme modular monolith, mais les responsabilités doivent rester séparables afin que le service realtime puisse évoluer indépendamment du Web/API classique.
## Tooling candidates
Besoins identifiés :
- build Android multi-ABI ;
- orchestration Desktop/Tauri/Web ;
- packaging ;
- génération de manifests produit ;
- validation de dépendances/capabilities ;
- génération de configuration logging ;
- génération/validation assets ;
- outils de map/level seulement lorsqu'un jeu concret en a besoin.
## Hors réservation actuelle
Ne sont pas réservés comme capacités du framework à ce stade :
- rendu 3D ;
- moteur physique 3D ;
- VR/AR ;
- voice chat ;
- procedural world massif ;
- scripting embarqué généraliste ;
- plugin runtime dynamique par `.so`/`.dll` ;
- marketplace générique ;
- NFT.
Ces sujets peuvent devenir des idées/études si un futur projet les justifie.

Some files were not shown because too many files have changed in this diff Show More