17 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
89 changed files with 5955 additions and 146 deletions

View File

@@ -1,8 +1,29 @@
<!-- file: CHANGELOG.md --> <!-- file: CHANGELOG.md -->
<!-- version: 12 --> <!-- version: 14 -->
# Changelog # 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 ## 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. - Gouvernance documentaire renforcée : catégories `ideas/studies/architecture/rules`, immutabilité des deltas, conventions de statuts et workflow de session/version.

View File

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

View File

@@ -1,5 +1,5 @@
<!-- file: README.md --> <!-- file: README.md -->
<!-- version: 25 --> <!-- version: 40 -->
# games.sasedev # games.sasedev
@@ -14,6 +14,7 @@ Workspace expérimental puis productif pour des jeux multiplateformes principale
- assets hors des crates sous `assets/` ; - assets hors des crates sous `assets/` ;
- `assets/common/` pour les ressources mutualisées et un répertoire par jeu pour les ressources spécifiques ; - `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 ; - 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 ; - 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 ; - runner Desktop natif SDL3 par défaut, avec variante Tauri uniquement si un besoin futur la justifie ;
- documentation sous `docs/` ; - documentation sous `docs/` ;
@@ -23,9 +24,9 @@ Workspace expérimental puis productif pour des jeux multiplateformes principale
## Baseline ## Baseline
Version stable de référence : `0.1.0`. Version stable de référence : `0.3.0`.
Version candidate en cours de conception : `0.2.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. 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,5 +1,5 @@
<!-- file: ROADMAP.md --> <!-- file: ROADMAP.md -->
<!-- version: 19 --> <!-- version: 21 -->
# Roadmap # Roadmap
@@ -26,11 +26,31 @@ Le détail historique des prereleases `0.1.0-*` reste dans `deltas/0.1.0/` et `h
- (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` — 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` — inventorier et réserver les capabilities déjà justifiées sans les implémenter prématurément.
- ( ) `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` — définir les couches, les dépendances autorisées et la frontière entre kernel, capability, plateforme, provider, système de jeu et service.
- ( ) `0.2.0` — établir la matrice plateformes et les archétypes de jeux utilisés pour challenger l'architecture. - (x) `0.2.0` — établir la matrice plateformes et les archétypes de jeux utilisés pour challenger l'architecture.
- ( ) `0.2.0`définir le modèle de composition statique, le manifest produit/jeu et l'architecture cible des crates. - (x) `0.2.0`retenir la composition Rust statique comme direction de référence.
- ( ) `0.2.0`définir la trajectoire d'implémentation progressive des versions suivantes seulement après revue de la conception. - (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` — 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` — 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 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. - (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 --> <!-- file: RULES.md -->
<!-- version: 4 --> <!-- version: 5 -->
# Index normatif games.sasedev # Index normatif games.sasedev
@@ -17,8 +17,9 @@ Les règles détaillées sont maintenues sous `docs/rules/` et sont cumulatives
6. [`docs/rules/VERSION_WORKFLOW.md`](docs/rules/VERSION_WORKFLOW.md) — SemVer, niveaux de maturité, fixes, deltas et livraisons ; 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 ; 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 contrat des prompts de reprise ; 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/RULES_SERVER_HOSTING.md`](docs/rules/RULES_SERVER_HOSTING.md) — contraintes durables de portabilité et préférence d'auto-hébergement. 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 ## 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

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

View File

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

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 --> <!-- file: docs/000-README.md -->
<!-- version: 21 --> <!-- version: 27 -->
# Documentation games.sasedev # Documentation games.sasedev
@@ -12,6 +12,11 @@
- [`ideas/000-README.md`](ideas/000-README.md) — rôle des idées non engagées et règles de maturation. - [`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. - [`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
- [`architecture/001-WORKSPACE_ARCHITECTURE.md`](architecture/001-WORKSPACE_ARCHITECTURE.md) — workspace, générations de moteur, jeux, runners, assets et Android. - [`architecture/001-WORKSPACE_ARCHITECTURE.md`](architecture/001-WORKSPACE_ARCHITECTURE.md) — workspace, générations de moteur, jeux, runners, assets et Android.
@@ -51,7 +56,7 @@
## Règles ## Règles
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 et [`rules/RULES_SERVER_HOSTING.md`](rules/RULES_SERVER_HOSTING.md) pour la portabilité d'auto-hébergement. 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 ## Validation
@@ -63,11 +68,15 @@ Voir [`../RULES.md`](../RULES.md), notamment [`rules/RULES_DOCUMENTATION.md`](ru
- [`testing/001-TEST_ARCHITECTURE.md`](testing/001-TEST_ARCHITECTURE.md) — séparation `unit_tests/` / `tests/`, tests ciblés et tracing de test. - [`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/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/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/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/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/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/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/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é ## Historique validé

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/001-WORKSPACE_ARCHITECTURE.md --> <!-- file: docs/architecture/001-WORKSPACE_ARCHITECTURE.md -->
<!-- version: 5 --> <!-- version: 7 -->
# Architecture du workspace # Architecture du workspace
@@ -22,7 +22,8 @@ games.sasedev/
│ ├── game-reflex-poc-desktop/ │ ├── game-reflex-poc-desktop/
│ ├── game-snake-poc-desktop/ │ ├── game-snake-poc-desktop/
│ ├── game-reflex-poc-tauri/ │ ├── game-reflex-poc-tauri/
── game-reflex-poc-wasm/ ── game-reflex-poc-wasm/
│ └── game-snake-poc-wasm/
├── assets/ ├── assets/
│ ├── common/ │ ├── common/
│ ├── game-reflex-poc/ │ ├── game-reflex-poc/
@@ -31,6 +32,8 @@ games.sasedev/
│ ├── common/ │ ├── common/
│ ├── game-reflex-poc/ │ ├── game-reflex-poc/
│ └── game-snake-poc/ │ └── game-snake-poc/
├── Web/
│ └── game-snake-poc/
├── docs/ ├── docs/
├── deltas/ ├── deltas/
├── prompts/ ├── 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. 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` ; `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.
- un binaire natif Tauri qui héberge la WebView locale.
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`. 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.
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.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/004-INPUT_AND_CONTROLS.md --> <!-- file: docs/architecture/004-INPUT_AND_CONTROLS.md -->
<!-- version: 7 --> <!-- version: 9 -->
# Abstraction des entrées et contrôles # 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. 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 ## Requête de sortie
La plateforme ne décide plus directement de terminer un jeu. Elle traduit l'événement physique en `QuitRequest` : 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 --> <!-- file: docs/architecture/005-ASSET_ARCHITECTURE.md -->
<!-- version: 3 --> <!-- version: 4 -->
# Architecture des assets # Architecture des assets
@@ -92,3 +92,16 @@ assets/game/...
``` ```
Les répertoires `build/generated/` restent des artefacts jetables. 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 --> <!-- file: docs/architecture/010-RUNTIME_PROVENANCE.md -->
<!-- version: 1 --> <!-- version: 2 -->
# Provenance d'environnement d'exécution # 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. 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. 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

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/015-PLATFORM_POC_ARCHITECTURE.md --> <!-- file: docs/architecture/015-PLATFORM_POC_ARCHITECTURE.md -->
<!-- version: 1 --> <!-- version: 2 -->
# Architecture des POC plateforme et réseau # Architecture des POC plateforme et réseau
@@ -11,12 +11,12 @@ Snake est le jeu-sonde principal.
## POC plateforme prioritaires ## POC plateforme prioritaires
Première vague : Première vague, réordonnée à partir du résultat réel de `0.3.0` :
- Tauri Android + Snake ; - Web navigateur direct + Snake — validé par `0.3.0` ;
- Web navigateur direct + Snake ; - Tauri Android + Snake — prochain host prévu par `0.3.1` ;
- Tauri Desktop + Snake ; - Tauri Desktop + Snake — prévu ensuite pour éprouver la factorisation WebView ;
- build Android multi-ABI avec outils natifs. - 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. Plateformes supplémentaires lorsque l'environnement existe : Windows SDL natif, macOS SDL natif et iOS SDL natif.
@@ -38,6 +38,8 @@ Un POC sert à identifier duplication, adapters manquants, capability réellemen
Une abstraction n'est pas extraite avant observation d'un besoin concret. 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 ## 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`. Les résultats des POC `0.3.x` déterminent les choix techniques conservés pour la trajectoire Uroburas `0.4.x`.

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 --> <!-- file: docs/development/003-TRACING_AND_DIAGNOSTICS.md -->
<!-- version: 1 --> <!-- version: 2 -->
# Tracing et diagnostics # Tracing et diagnostics
@@ -21,3 +21,9 @@ Les runners Desktop initialisent ce socle. Les futures intégrations Android pou
## Évolution ## É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. 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.

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,5 +1,5 @@
<!-- file: docs/rules/FILE_CONTRACTS.md --> <!-- file: docs/rules/FILE_CONTRACTS.md -->
<!-- version: 6 --> <!-- version: 8 -->
# Contrats des fichiers principaux # Contrats des fichiers principaux
@@ -11,6 +11,7 @@
- `docs/rules/` contient les règles durables. - `docs/rules/` contient les règles durables.
- `docs/ideas/000-README.md` est le point d'entrée des idées et variantes non engagées. - `docs/ideas/000-README.md` est le point d'entrée des idées 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/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/architecture/` contient les décisions et descriptions d'architecture retenues.
- `docs/objectives/` décrit les objectifs et la stratégie produit/technique. - `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/games/` classe les familles de jeux, leurs contrôles et leurs évolutions.
@@ -25,7 +26,8 @@
- `scripts/` contient des audits en lecture seule et des outils du dépôt. - `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. - `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. - `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 ## Tauri

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 --> <!-- file: docs/rules/RULES_COMMANDS.md -->
<!-- version: 9 --> <!-- version: 13 -->
# Règles d'exécution des commandes # Règles d'exécution des commandes
@@ -16,18 +16,20 @@
- **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-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-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-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 ## 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-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 immédiatement le formatage et constitue la gate canonique de conformité rustfmt. - **CMD-RUST-002** — `cargo fmt --all -- --check` suit 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-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** — `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-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 dun delta et doivent couvrir toutes les crates directement ou transitivement affectées lorsque cela est raisonnablement déterminable. - **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 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-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-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-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-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` 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-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-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.
@@ -56,29 +58,35 @@
- **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-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-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-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 ## 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-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-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-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-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-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 ## 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-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-002** — La transition alpha vers beta exécute une suite Cargo workspace complète en plus des tests ciblés.
- **CMD-BETA-003** — Si la version touche le périmètre Tauri, au moins un build de packaging beta 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. - **CMD-BETA-004** — Les APK Debug servent à la validation multi-appareils beta ; la signature de publication appartient à la phase RC/stable.
## RC et release ## 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-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-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-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-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. - **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.
@@ -92,7 +100,7 @@
## Outils de build et scripts d'audit ## 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-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** — Un script Python ne pilote pas le build d'un produit, d'une plateforme ou d'un package distribué. - **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-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-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. - **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,5 +1,5 @@
<!-- file: docs/rules/RULES_DOCUMENTATION.md --> <!-- file: docs/rules/RULES_DOCUMENTATION.md -->
<!-- version: 6 --> <!-- version: 8 -->
# Règles de documentation # Règles de documentation
@@ -28,6 +28,7 @@
- **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-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-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-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 ## Nomenclature documentaire
@@ -40,6 +41,14 @@
- **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-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`. - **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 ## 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-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]`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_PROJECT.md --> <!-- file: docs/rules/RULES_PROJECT.md -->
<!-- version: 11 --> <!-- version: 16 -->
# Règles spécifiques games.sasedev # 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-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-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-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 ## 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-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-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-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 ## 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-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-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-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-009** — Une adaptation WebAssembly réutilisable est une crate dédiée distincte de la crate Tauri.
- **GAME-PLATFORM-010** — Dans une app Tauri, `lib.rs` reste une façade/reexport ; `tauri.rs` assemble Tauri et expose les commandes qui délèguent aux modules propriétaires. - **GAME-PLATFORM-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.
@@ -82,6 +85,12 @@
- **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-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-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-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 ## Version d'en-tête des fichiers

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_SESSION_PLANNING.md --> <!-- file: docs/rules/RULES_SESSION_PLANNING.md -->
<!-- version: 1 --> <!-- version: 5 -->
# Règles de cadrage des versions, sessions et prompts # Règles de cadrage des versions, sessions et prompts
@@ -13,6 +13,11 @@ Ces règles imposent un découpage suffisamment petit pour qu'une version puisse
- **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-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-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-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 ## Taille des tranches
@@ -21,12 +26,14 @@ Ces règles imposent un découpage suffisamment petit pour qu'une version puisse
- **SESSION-012** — Plusieurs micro-tranches sans valeur de validation indépendante peuvent être regroupées. - **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-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-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 ## Une version par session
- **SESSION-020** — Une session de développement vise une version complète, de son cadrage jusqu'à sa release ou à sa candidate de publication selon le scope décidé. - **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 session ne doit pas être planifiée de façon à s'arrêter normalement au milieu d'une version. - **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 version suivante au lieu de prolonger indéfiniment la session. - **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 ## Dernières tranches
@@ -43,6 +50,7 @@ Ces règles imposent un découpage suffisamment petit pour qu'une version puisse
- **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-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-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-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 ## Relation avec VERSION_WORKFLOW

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_VALIDATION_MATRIX.md --> <!-- file: docs/rules/RULES_VALIDATION_MATRIX.md -->
<!-- version: 2 --> <!-- version: 4 -->
# Matrice normative des commandes et validations # Matrice normative des commandes et validations
@@ -13,30 +13,46 @@ Les commandes ciblées restent la norme pendant l'implémentation ; les gates wo
## Matrice ## Matrice
| ID | Commande / action | Dépend de | Déclencheur principal | Phase minimale typique | | ID | Commande / action | Dépend de | Déclencheur principal | Phase minimale typique |
|-----------|------------------------------------------------------------------------------------|-------------------------------------|--------------------------------------------|------------------------| |-----------|------------------------------------------------------------------------------------|---------------------------------|----------------------------------------------------|------------------------|
| `CMD-001` | `cargo fmt --all` | — | source Rust modifié | `pre` | | `CMD-001` | `cargo fmt --all` | — | Rust ou dépendance Cargo modifiée | `pre` |
| `CMD-002` | `cargo fmt --all -- --check` | `CMD-001` si formatage requis | source Rust modifié | `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/workspace/règles Rust | `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/règles/docs | `pre` | | `CMD-011` | `python3 scripts/audit_markdown_tables.py ...` | — | Markdown concerné | `pre` |
| `CMD-012` | `python3 scripts/audit_distribution_layout.py` | — | layout/build/distribution | `pre` | | `CMD-012` | `python3 scripts/audit_distribution_layout.py` | — | layout/build/distribution concerné | `pre` |
| `CMD-020` | `cargo check -p <crate>` | `CMD-002`, `CMD-010` | crate Rust ciblée | `pre` | | `CMD-020` | `cargo check -p <crate>` | audits applicables | diagnostic ciblé facultatif | `pre` |
| `CMD-021` | `cargo test -p <crate> --all-targets --all-features` | `CMD-020` | comportement/API crate | `pre` | | `CMD-021` | `cargo test -p <crate> --all-targets --all-features` | `CMD-023`, `CMD-024` | comportement/API crate | `pre` |
| `CMD-022` | tests des crates consommatrices impactées | `CMD-021` | API publique/contrat partagé modifié | `pre` | | `CMD-022` | tests ciblés des crates consommatrices impactées | `CMD-021` | API publique/contrat partagé modifié | `pre` |
| `CMD-023` | `cargo check --workspace` | audits applicables | changement transverse / gate globale | selon portée | | `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` | gate complète | alpha/beta/RC | | `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` | changement transverse / frontière de phase | beta/RC | | `CMD-025` | `cargo test --workspace --all-targets --all-features` | `CMD-024` | gate rare planifiée / portée transverse incertaine | selon plan |
| `CMD-030` | build Desktop `--release` ciblé | gates Rust applicables | runner/distribution Desktop touché | beta | | `CMD-026` | `cargo tree -p <crate> --edges normal` ou variante ciblée | — | dépendances/features modifiées ou diagnostic | selon portée |
| `CMD-031` | smoke Desktop release | `CMD-030` | runtime Desktop touché | beta | | `CMD-030` | build Desktop `--release` ciblé | gates Rust applicables | runner/distribution Desktop touché | beta |
| `CMD-040` | `cargo tauri build` | gates Rust/frontend applicables | périmètre Tauri touché | beta | | `CMD-031` | smoke Desktop release | `CMD-030` | runtime Desktop touché | beta |
| `CMD-041` | smoke Tauri release | `CMD-040` | runtime Tauri touché | beta | | `CMD-040` | `(cd <tauri-app> && cargo tauri dev)` | gates Rust/frontend applicables | smoke interactif Tauri | `pre`/beta |
| `CMD-050` | build Rust Android ABI ciblé | gates Rust applicables | Android/JNI/backend natif touché | pre/beta | | `CMD-041` | `(cd <tauri-app> && cargo tauri build)` | gates Rust/frontend applicables | packaging Tauri final/prefinal | beta/RC |
| `CMD-051` | Gradle `assembleDebug` application ciblée | `CMD-050` lorsque Rust natif change | Android/app/manifest/Java touché | pre/beta | | `CMD-042` | build Rust `wasm32-unknown-unknown` + `wasm-bindgen --target web` | gates Rust de l'adapter | adapter WASM/Web direct touché | `pre` |
| `CMD-052` | install + smoke AVD | `CMD-051` | Android concerné | beta | | `CMD-043` | `(cd Web/<game> && npm install && npm run build)` | `CMD-042` si frontend avec WASM | frontend Web direct touché | `pre` |
| `CMD-053` | install + smoke appareil réel | `CMD-051` | Android concerné | beta/RC | | `CMD-044` | smoke navigateur du host Web direct | `CMD-043` | Canvas/input/responsive Web touchés | `pre`/beta |
| `CMD-060` | `cargo clean --dry-run --verbose` | — | contrôle disque / préparation nettoyage | maintenance | | `CMD-050` | build Rust Android ABI ciblé | gates Rust applicables | Android/JNI/backend natif touché | pre/beta |
| `CMD-061` | `cargo clean` | décision explicite de nettoyage | accumulation disque / jalon de cycle | maintenance | | `CMD-051` | `(cd Android && ./gradlew :<app>:assembleDebug)` | `CMD-050` si Rust natif change | Android/app/manifest/Java touché | pre/beta |
| `CMD-062` | `cargo clean -p <package>` ou nettoyage par `--release` / `--profile` / `--target` | — | nettoyage ciblé suffisant | maintenance | | `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 ## Dépendances entre crates

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/VERSION_WORKFLOW.md --> <!-- file: docs/rules/VERSION_WORKFLOW.md -->
<!-- version: 3 --> <!-- version: 6 -->
# Versionnement, maturité et livraisons # Versionnement, maturité et livraisons
@@ -98,9 +98,16 @@ La promotion `rc` puis stable d'une version de conception exige une validation h
## Prompt de la version suivante ## Prompt de la version suivante
- **VER-PROMPT-001** — Le prompt de démarrage de la version suivante n'est pas créé à un numéro arbitraire de RC. - **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** — Sa génération devient recommandée après validation de la première RC dont le périmètre est effectivement gelé. - **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-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 ## Phases de développement
@@ -111,10 +118,10 @@ 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-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 découpage prévisionnel. - **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-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-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. - **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-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-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-008** — Chaque tranche ferme son propre scope, produit son delta et ses validations proportionnelles avant l'ouverture de la tranche suivante.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/studies/000-README.md --> <!-- file: docs/studies/000-README.md -->
<!-- version: 8 --> <!-- version: 9 -->
# Études # Études
@@ -53,3 +53,7 @@ Ces documents étudient les POC à réaliser ; ils ne lancent encore aucune impl
- [`020-UROBURAS_CRATE_DECOMPOSITION_STUDY.md`](020-UROBURAS_CRATE_DECOMPOSITION_STUDY.md) — proposition de familles de crates et dépendances sans monolithe jeu. - [`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. - [`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. - [`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,354 @@
<!-- file: docs/studies/023-V0_3_0_PLATFORM_POC_AUDIT.md -->
<!-- version: 2 -->
# 0.3.0 — audit de baseline et cadrage du premier POC plateforme
## Statut
Étude de cadrage pour `0.3.0-0-pre.1`.
Elle décrit l'état observé de la stable `0.2.0`, les requirements réellement nécessaires à Snake, le premier POC retenu et le sizing corrigé. Elle ne transforme pas encore les extractions candidates en architecture durable.
## Base inspectée
Base déclarée : tag stable `v0.2.0`, fourni sous forme d'archive `games-v0.2.0.zip`.
L'intégrité ZIP est propre. L'archive est fournie explicitement comme téléchargement du tag stable `v0.2.0` et constitue donc la baseline autoritaire de ce tag conformément à `CMD-GIT-003`. L'absence de `.git` dans une archive de tag est normale et ne constitue pas une validation manquante ; les contrôles Git locaux ne s'appliquent que lorsqu'un checkout Git est effectivement fourni.
La version workspace observée avant modification est `0.2.0`.
## Audits officiels exécutés sur la baseline
Les audits en lecture seule suivants passent sur la baseline telle que livrée :
```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)
```
Ces résultats valident uniquement les contrôles mécaniques réellement couverts par les scripts. La revue manuelle des règles a détecté des écarts supplémentaires.
## Écarts de baseline détectés
### README de version obsolète
`README.md` annonce encore `0.1.0` comme stable et `0.2.0` comme candidate alors que l'archive est la stable `0.2.0`.
Correction dans `0-pre.1` : afficher `0.2.0` comme stable de référence et `0.3.0-0-pre.1` comme version de développement.
### ROADMAP stable non fermé
`ROADMAP.md` conserve quatre lignes `( )` sous `0.2.0`. Cela contredit `DOC-RMAP-010`, qui interdit du scope encore planifié sous une version stable clôturée.
La revue du contenu `0.2.0` montre que :
- layering et dépendances ont été couverts par les études puis l'architecture consolidée ;
- matrice plateforme et pressure tests ont été produits ;
- la composition Rust statique a été retenue ;
- le manifest produit/jeu et l'architecture physique définitive des crates ne sont volontairement pas figés ;
- la trajectoire `0.3.x` puis `0.4.x` a été définie.
Correction dans `0-pre.1` : fermer les lignes réellement livrées et marquer explicitement le manifest/shape physique définitif comme reporté.
### Effet de bord de la gate d'audit Python
Le ZIP `v0.2.0` ne contient aucun `__pycache__` ni fichier `.pyc`. En revanche, l'exécution de `scripts/audit_rust_workspace_rules.py` sur la baseline crée `scripts/__pycache__/audit_rust_general_rules.cpython-313.pyc` : `audit_rust_export_completeness.py` importe `audit_rust_general_rules.py` dans un sous-processus Python standard.
Cela contredit l'intention de `CMD-GEN-006`, selon laquelle les audits sont des contrôles en lecture seule. Correction dans `0-pre.1` : le wrapper exécute désormais ses trois sous-audits avec l'interpréteur courant et `-B`, ce qui supprime cet effet de bord sans modifier les audits eux-mêmes. Une réexécution complète confirme qu'aucun cache Python n'est créé.
### Règle RC encore spécifique à 0.1.0
`CMD-RC-001` parle encore du gel fonctionnel de `0.1.0`. La règle est générale et doit viser la version courante.
Correction dans `0-pre.1` : formulation générique.
### Build Python historique et cohérence normative
La revue des règles révèle une contradiction dans `0.2.0` : `CMD-BUILD-002` interdisait globalement quun script Python pilote un build, tandis que `CMD-BUILD-004` demandait précisément aux POC `0.3.x` de remplacer les orchestrateurs Python encore présents. La baseline conserve effectivement deux chemins historiques qui les utilisent.
Deux scripts historiques pilotent encore des builds :
- `scripts/build_reflex_tauri_wasm.py` ;
- `scripts/build_android_rust.py`.
Le premier est encore appelé par les hooks Tauri Reflex. Le second orchestre `cargo ndk`, l'extraction SDL3 depuis l'AAR et le staging `jniLibs`.
Ils appartiennent à la baseline validée `0.1.0`, mais un POC `0.3.x` ne doit pas les reprendre comme mécanisme de build. `CMD-BUILD-002` est rendue cohérente avec cette migration : les deux orchestrateurs sont explicitement tolérés uniquement comme baseline gelée jusquà la réactivation du chemin concerné. `CMD-WEB-003` qualifie également le script Tauri/WASM comme historique. Les remplacements sont réalisés lorsque le chemin concerné devient actif : Web direct en `0.3.0`, Tauri Android/Desktop dans les versions correspondantes et Android natif multi-ABI dans sa tranche dédiée.
## Contraintes de l'environnement courant
L'environnement d'inspection dispose de :
```text
Python 3.13.5
Node.js v22.16.0
npm 10.9.2
OpenJDK 21
```
Il ne dispose pas de :
```text
cargo
rustc
rustup
gradle
wasm-bindgen
cargo-ndk
Tauri CLI
```
L'archive ne contient pas de Gradle Wrapper et ne vend pas l'AAR SDL3, conformément à la baseline Android actuelle.
Conséquence : seuls les audits statiques et inspections de fichiers sont exécutables ici. Les builds, tests et smokes restent à exécuter par l'utilisateur conformément à `CMD-BUILD-005`.
## Inventaire Snake et hosts existants
### Gameplay Snake
`game-snake-poc` possède déjà :
- un état déterministe indépendant de SDL, Android, Tauri et Web ;
- des directions sémantiques `Left/Right/Up/Down` via `InputState` ;
- une cadence de déplacement interne ;
- collision mur/corps ;
- score et nourriture ;
- rendu sous forme de `EngineScene` normalisée.
Le jeu ne consomme aucun symbole de `engine-v1-platform-api`, bien que cette dépendance soit encore déclarée dans son manifest. La même déclaration inutilisée existe dans `game-reflex-poc`. Cette dette est à nettoyer avant le premier adapter Web.
### Desktop SDL3
`engine-v1-sdl` fournit déjà :
- fenêtre redimensionnable ;
- clavier directionnel ;
- pointeur normalisé ;
- swipe tactile/souris ;
- quit par fermeture, Escape et Back plateforme ;
- rendu de rectangles normalisés ;
- boucle fixed-step de 16 ms utilisée par les runners.
Le runner Snake Desktop compose correctement gameplay, SDL, logging et capacité plateforme désactivée. Il reste la baseline de non-régression pour `0.3.0`.
### Android SDL3 / Java / JNI
La baseline possède :
- `SaseGameActivity` commune dérivée de `SDLActivity` ;
- un bridge JNI versionné ;
- un `cdylib` Rust commun sélectionnant Reflex ou Snake par feature ;
- tactile transporté par SDL3 ;
- observation Back Android 16 non consommatrice ;
- staging Gradle des assets ;
- configuration NDK centralisée.
Le chemin build Rust Android reste toutefois orchestré par Python et n'est pas réutilisé par le premier POC `0.3.0`.
### Référence Tauri/WASM Reflex
La référence Reflex valide déjà plusieurs conventions utiles :
- crate WASM distincte de la crate Tauri ;
- `lib.rs` Tauri limité à la façade/réexport ;
- `tauri.rs` propriétaire de l'assemblage et des commandes ;
- frontend Vite/TypeScript dans la crate Tauri ;
- tracing frontend relayé vers Rust ;
- canvas redimensionné selon le viewport et le device pixel ratio.
Les APIs WASM et le frontend restent cependant Reflex-specific. Elles sont des références à adapter, pas du code générique à copier aveuglément.
## Graphe de dépendances local observé
```text
engine-v1-common
engine-v1-platform-api
engine-v1-sdl
-> engine-v1-common
game-snake-poc
-> engine-v1-common
-> engine-v1-platform-api [déclarée, non utilisée]
game-reflex-poc
-> engine-v1-common
-> engine-v1-platform-api [déclarée, non utilisée]
game-snake-poc-desktop
-> game-snake-poc
-> engine-v1-common
-> engine-v1-platform-api
-> engine-v1-sdl
-> game-logging-lib
game-android-entrypoint
-> engine-v1-common
-> engine-v1-sdl
-> game-logging-lib
-> game-snake-poc / game-reflex-poc via features
game-reflex-poc-wasm
-> engine-v1-common
-> game-reflex-poc
game-reflex-poc-tauri Rust
-> engine-v1-platform-api
-> game-logging-lib
frontend Reflex Tauri
-> bindings générés game-reflex-poc-wasm
game-assets-lib
-> aucun consommateur runtime actuel
```
Le graphe confirme que gameplay Snake et host peuvent être séparés sans créer un nouveau moteur.
## Requirements du premier POC Snake
| Besoin | Baseline réelle | Décision 0.3.0 |
|--------------------------------|-------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|
| Input clavier | SDL oui ; Web Snake absent | adapter clavier Web vers `GameAction` |
| Boutons directionnels tactiles | absent | quatre contrôles virtuels Web vers `GameAction` |
| Viewport / resize | SDL oui ; Reflex Web oui | réutiliser le principe canvas responsive sans coupler Snake à Tauri |
| Lifecycle | quit minimal ; pas de lifecycle Web générique | pause des ticks sur `visibilitychange`, reprise contrôlée, sortie/navigation host-specific |
| Runtime provenance | type présent mais non consommé | instancier une provenance Browser/WASM et refléter le profil d'input réellement utilisé |
| Assets | sources + resolver/staging présents ; aucun runtime ne charge actuellement les JSON | valider le packaging/chargement de `common` et `game` dans le POC Web |
| Logging | tracing natif ; bridge Tauri Reflex | logging Web local distinct de Tauri, sans dupliquer la logique gameplay |
| WASM bridge | Reflex-specific | créer un adapter Snake dédié ; n'extraire un bridge générique qu'après duplication réellement observée |
| Tauri bridge | Reflex Desktop uniquement | hors scope `0.3.0` |
| Android packaging | SDL/Java/JNI existant | hors scope `0.3.0` |
| Multi-ABI | script historique supportant plusieurs ABI | hors scope `0.3.0`, remplacement natif prévu plus tard |
## Duplications et extractions candidates
Duplications déjà visibles :
- runners Desktop Reflex/Snake très proches ;
- activities Android spécifiques volontairement minimales ;
- future exposition de `EngineScene` en WASM susceptible de répéter l'adapter Reflex ;
- shell frontend Canvas/input susceptible d'être commun au Web direct et à Tauri.
Décision : ne pas extraire un runner générique, un bridge WASM générique ou un shell Web commun dans `pre.1`. Le premier second consommateur réel décide de l'extraction.
## Choix du premier POC
Le premier POC de `0.3.0` est :
```text
Web navigateur direct + Snake
```
Le choix initial Tauri Android est reporté au second host, actuellement `0.3.1`.
Raisons :
- le Web direct exerce déjà WASM, keyboard/touch, resize, lifecycle, assets et provenance ;
- la référence Reflex fournit un précédent WASM/Canvas sans imposer Tauri ;
- Tauri Android ajouterait simultanément un nouveau gameplay WASM, un nouveau host mobile Tauri, le lifecycle mobile, le packaging Android Tauri et les plugins ;
- la baseline Web obtenue devient ensuite un point de comparaison et de réutilisation pour Tauri Android ;
- ce découpage réduit le risque de créer trop tôt une abstraction Tauri/Web commune sur la seule base de Reflex.
## Scope corrigé de 0.3.0
Inclus :
- correction des écarts de baseline détectés en `pre.1` ;
- nettoyage host-neutral de Snake ;
- maintien du runner Desktop SDL3 ;
- adapter WASM Snake dédié ;
- frontend Web direct Vite/TypeScript minimal ;
- clavier + boutons directionnels tactiles ;
- canvas responsive ;
- lifecycle navigateur minimal ;
- logging Web ;
- chargement d'assets de preuve ;
- provenance Browser/WASM ;
- build Web avec outils natifs ;
- audit de duplication et décisions d'extraction après POC.
Exclus :
- Tauri Android ;
- Tauri Desktop Snake ;
- remplacement du build Android natif multi-ABI ;
- publicité, billing, auth ou leaderboard ;
- réseau realtime ;
- WebTransport/QUIC ;
- logique Uroburas ;
- ECS, physique ou nouveau moteur.
## Sizing corrigé
Le forecast initial est réduit et réordonné afin que `0.3.0` reste une version de session unique.
### `0-pre.1` — audit, règles, requirements et sizing
- audit complet de la baseline ;
- correction des incohérences documentaires/règles détectées ;
- choix Web direct ;
- forecast corrigé ;
- aucune implémentation gameplay/host lourde.
### `0-pre.2` — Snake portability baseline
- supprimer les dépendances de plateforme inutiles des crates jeu concernées ;
- confirmer les actions sémantiques nécessaires à Snake ;
- conserver Desktop SDL3 comme non-régression ;
- préciser le contrat minimal attendu par l'adapter WASM.
### `0-pre.3` — adapter Snake WASM + build natif Web
- crate WASM Snake dédiée ;
- exposition input/update/scene strictement nécessaire ;
- procédure Cargo + `wasm-bindgen` reproductible sans Python ;
- tests ciblés de l'adapter lorsqu'ils sont possibles hors navigateur.
### `0-pre.4` — POC navigateur direct de bout en bout
- frontend Vite/TypeScript ;
- rendu Canvas ;
- clavier ;
- boutons tactiles ;
- resize ;
- visibility lifecycle ;
- logging ;
- assets ;
- provenance ;
- build et smoke navigateur réels côté utilisateur.
### `0-pre.5` — uniquement si le POC révèle un défaut réel
Cette tranche n'est pas créée artificiellement. Elle corrige une frontière, une duplication ou un bug observé.
### `2-beta.1` — validation large du scope retenu
Alpha n'est pas planifiée par défaut. Si `pre.4` est fonctionnellement complet, la beta valide le workspace affecté, le build Web de production et le smoke du POC.
### `3-rc.1` — candidate gelée
Documentation durable, commandes reproductibles, décisions d'extraction/report, ROADMAP et préparation de la version suivante. Aucun nouveau scope.
### `0.3.0` — promotion mécanique
Aucune nouvelle fonctionnalité.
## Critères de sortie de 0.3.0
`0.3.0` peut être clôturée lorsque :
- Snake Desktop SDL3 reste fonctionnel ;
- Snake fonctionne réellement dans un navigateur direct ;
- clavier et boutons tactiles produisent les mêmes actions sémantiques ;
- resize et visibility lifecycle ont été exercés ;
- assets et provenance sont observables ;
- le chemin Web ne dépend d'aucun script Python de build ;
- les duplications avec Reflex/Tauri sont documentées ;
- seules les abstractions prouvées nécessaires ont été extraites ;
- les validations applicables ont été exécutées par l'utilisateur ;
- aucune logique Uroburas ni réseau realtime n'a été introduite.

View File

@@ -0,0 +1,67 @@
<!-- file: docs/testing/004-V0_3_0_RC_VALIDATION_MATRIX.md -->
<!-- version: 1 -->
# Matrice RC 0.3.0 — Snake Web direct
## Objet
La RC `0.3.0` gèle le premier POC Snake Web direct. Elle ne crée aucune fonctionnalité et vérifie que l'état validé en beta reste reproductible avant promotion mécanique vers la stable.
## Gate statique et 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
```
## 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`.
Critères :
- Canvas au ratio attendu ;
- clavier et contrôles pointer/tactiles ;
- SimpleBar ;
- assets `snake / engine-v1` ;
- provenance Web/WASM cohérente ;
- resize ;
- pause/reprise sans rattrapage massif ;
- aucune erreur runtime bloquante.
## Artefacts et dépôt
Les artefacts Rust/WASM/Vite restent sous `../builds/sasedev-games/`. Aucun `node_modules`, `dist`, cache WASM ou artefact Cargo n'est livré dans le dépôt.
## Promotion
La promotion vers `0.3.0` est mécanique lorsque `3-rc.1` est validée sans défaut nécessitant une modification fonctionnelle. Tout correctif de release reste limité par `VER-RC-*`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/001-VALIDATION_GATES.md --> <!-- file: docs/validation/001-VALIDATION_GATES.md -->
<!-- version: 5 --> <!-- version: 8 -->
# Gates de validation # Gates de validation
@@ -24,7 +24,7 @@ Les audits et gates de compilation restent ensuite :
```bash ```bash
python3 scripts/audit_rust_workspace_rules.py 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_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history
cargo check --workspace cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings cargo clippy --workspace --all-targets --all-features -- -D warnings
``` ```
@@ -58,4 +58,47 @@ Si une commande échoue, ne pas avancer de prerelease. Produire un correctif du
Le build Android n'est pas encore une gate : le projet Gradle exécutable et l'intégration SDL3/NDK restent planifiés pour une prerelease dédiée. Dès leur introduction, les tâches ciblées par module sont documentées avant d'être rendues obligatoires. Le build Android n'est pas encore une gate : le projet Gradle exécutable et l'intégration SDL3/NDK restent planifiés pour une prerelease dédiée. Dès leur introduction, les tâches ciblées par module sont documentées avant d'être rendues obligatoires.
La cible Web suit la même règle : aucune gate Web n'est inventée avant l'existence de son build réel. Le host navigateur direct Snake possède désormais une gate réelle. Lorsqu'il est touché, construire d'abord l'adapter WASM et ses bindings hors dépôt, puis le frontend :
```bash
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown
wasm-bindgen ../builds/sasedev-games/target/wasm32-unknown-unknown/debug/game_snake_poc_wasm.wasm \
--target web \
--out-dir ../builds/sasedev-games/game-snake-poc-web/wasm \
--out-name game_snake_poc_wasm
cd Web/game-snake-poc
npm install
npm run build
```
Le smoke direct utilise ensuite `npm run dev` et `http://127.0.0.1:1434/main.html`. Pour le POC Snake feature-complete, vérifier aussi : assets `common` + `game` chargés avant le statut `Prêt`, provenance `Web/Wasm/Browser` visible et mise à jour par l'input, pause sans rattrapage lors d'un masquage d'onglet, reprise propre, resize sans tick artificiel, SimpleBar, clavier et contrôles pointer/tactiles.
Lorsque `0-pre.5` touche la frontière plateforme du bridge WASM, exécuter également `cargo test -p engine-v1-platform-api`, `cargo test -p game-snake-poc-wasm`, puis un smoke `cargo run -p game-snake-poc-desktop` pour confirmer la non-régression SDL3. Les frontends Tauri restent pilotés par leurs hooks Tauri et ne reprennent pas cette gate manuelle.
## Gate beta du POC Snake Web
À lentrée en `2-beta.1`, le scope `0.3.0` est feature-complete. La gate de frontière de phase ajoute aux audits/check/Clippy la suite Cargo workspace complète :
```bash
cargo test --workspace --all-targets --all-features
```
Le témoin Desktop Snake est construit et fumé en release :
```bash
cargo build -p game-snake-poc-desktop --release
../builds/sasedev-games/target/release/game-snake-poc-desktop
```
Le host Web beta utilise également un module WASM release avant le build Vite :
```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)
```
Le smoke production ouvre `http://127.0.0.1:4174/main.html` et vérifie les mêmes contrats fonctionnels que le smoke `vite dev` : Canvas, inputs, SimpleBar, assets, provenance, lifecycle et resize. Le smoke `vite dev` déjà validé reste utile après un correctif touchant le plugin de dev, mais nest pas requis à chaque beta si aucun chemin dev na changé.

View File

@@ -0,0 +1,29 @@
<!-- file: history/0.3.0/0-pre.1.fix.1.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.1.fix.1
## Statut
Correctif de cadrage validé par l'utilisateur le 2026-09-20 avant ouverture de `0-pre.1.fix.2`.
## Validation utilisateur
Les commandes exécutées ont validé :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 171 file(s))
Distribution layout audit: clean (19 required path(s), 1 forbidden path(s) absent)
cargo fmt --all -- --check: clean
cargo check --workspace: clean
```
## Contenu accepté
- création de `docs/plans/` et du plan vivant `0.3.0` ;
- prévision souple des tranches jusqu'à la stable ;
- contrat explicite des archives issues d'un tag comme baseline autoritaire sans `.git` ;
- règle de session dimensionnée pour fermer au minimum la version concrète ouverte.

View File

@@ -0,0 +1,29 @@
<!-- file: history/0.3.0/0-pre.1.fix.2.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.1.fix.2
## Statut
Dernier correctif de cadrage `0-pre.1` validé par l'utilisateur le 2026-09-20 avant ouverture de `0-pre.2`.
## Validation utilisateur
Les commandes exécutées ont validé :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 172 file(s))
Distribution layout audit: clean (19 required path(s), 1 forbidden path(s) absent)
cargo fmt --all -- --check: clean
cargo check --workspace: clean
```
## Contenu accepté
- shell Web HTML/Vite/TypeScript explicite autour du Canvas/WASM ;
- Bootstrap 5 retenu comme baseline de présentation du premier POC Snake Web ;
- séparation durable frontend / Canvas-WASM / gameplay ;
- tranche prévisionnelle explicite de consolidation documentaire, `CHANGELOG.md`, `ROADMAP.md`, history et prompt suivant avant RC.

38
history/0.3.0/0-pre.2.md Normal file
View File

@@ -0,0 +1,38 @@
<!-- file: history/0.3.0/0-pre.2.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.2
## Statut
Baseline Snake portable validée par l'utilisateur le 2026-09-20 avant ouverture de `0-pre.3`.
## Validation utilisateur
La validation a été exécutée après `cargo clean` et reformatage canonique. Les gates suivantes ont passé :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 175 file(s))
Distribution layout audit: clean (19 required path(s), 1 forbidden path(s) absent)
cargo fmt --all -- --check: clean
cargo check --workspace: clean
cargo clippy --workspace --all-targets --all-features -- -D warnings: clean
cargo test -p game-snake-poc: 5 passed, 0 failed
cargo test -p game-reflex-poc: 4 passed, 0 failed
```
Les graphes de dépendances validés sont :
```text
game-snake-poc -> engine-v1-common
game-reflex-poc -> engine-v1-common
```
Aucune des deux crates de gameplay ne tire donc `engine-v1-platform-api` après le nettoyage `0-pre.2`.
## Suite
`0-pre.3` introduit l'adapter WASM Snake minimal sans frontend Vite/Bootstrap, conformément au plan actif.

43
history/0.3.0/0-pre.3.md Normal file
View File

@@ -0,0 +1,43 @@
<!-- file: history/0.3.0/0-pre.3.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.3
## Statut
Adapter Snake WASM validé par l'utilisateur le 2026-09-20 avant ouverture de `0-pre.4`.
## Validation utilisateur
Les gates suivantes ont passé sur `0.3.0-0-pre.3` :
```text
cargo fmt --all: clean
cargo fmt --all -- --check: clean
cargo check --workspace: clean
cargo clippy -p game-snake-poc-wasm --all-targets --all-features -- -D warnings: clean
cargo test -p game-snake-poc-wasm: 2 passed, 0 failed
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown: clean
wasm-bindgen --target web: clean
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 178 file(s))
Distribution layout audit: clean (20 required path(s), 1 forbidden path(s) absent)
```
Le graphe de dépendances validé de `game-snake-poc-wasm` contient uniquement les dépendances fonctionnelles attendues :
```text
game-snake-poc-wasm
├── engine-v1-common
├── game-snake-poc
│ └── engine-v1-common
└── wasm-bindgen
```
Aucune dépendance SDL3, Tauri ou `engine-v1-platform-api` n'est présente dans l'adapter WASM Snake.
## Suite
`0-pre.4` introduit le host navigateur direct Vite/TypeScript avec shell HTML Bootstrap 5, Canvas et contrôles clavier/tactiles.

View File

@@ -0,0 +1,46 @@
<!-- file: history/0.3.0/0-pre.4.fix.1.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.4.fix.1
## Statut
Validation partielle le 2026-09-20 : les gates Rust/WASM et les audits sont propres, mais `npm run build` échoue encore sur deux erreurs TypeScript strictes. La tranche déclenche `0-pre.4.fix.2`.
## Validation utilisateur
Les validations suivantes ont passé sur `0.3.0-0-pre.4.fix.1` :
```text
cargo fmt --all: clean
cargo fmt --all -- --check: clean
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 183 file(s))
Distribution layout audit: clean (27 required path(s), 1 forbidden path(s) absent)
cargo check --workspace: clean
cargo clippy --workspace --all-targets --all-features -- -D warnings: clean
cargo test -p game-snake-poc-wasm: 2 passed, 0 failed
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown: clean
wasm-bindgen --target web: clean
cargo tree -p game-snake-poc-wasm --edges normal: expected dependencies only
npm install: 5 packages added, 49 packages audited, 0 vulnerability
```
`npm install` a aussi signalé que le script d'installation de `@parcel/watcher@2.6.0` n'était pas encore couvert par `allowScripts`. Ce warning n'a pas interrompu l'installation et n'est pas traité comme l'échec de cette tranche.
## Défauts observés
`npm run build` a échoué avec deux erreurs :
```text
TS7016: Could not find a declaration file for module '@snake-wasm'.
TS2345: CanvasRenderingContext2D | null is not assignable to CanvasRenderingContext2D.
```
Le premier défaut vient du mapping TypeScript vers le fichier JavaScript généré par `wasm-bindgen` au lieu de sa déclaration `.d.ts`. Le second vient du narrowing du résultat de `canvas.getContext("2d")` qui n'est pas conservé jusque dans le callback de frame sous la configuration TypeScript courante.
## Suite
`0-pre.4.fix.2` corrige strictement ces deux erreurs puis rejoue `npm run build` et le smoke navigateur avant ouverture de `0-pre.5`.

View File

@@ -0,0 +1,52 @@
<!-- file: history/0.3.0/0-pre.4.fix.2.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.4.fix.2
## Statut
Validation technique réussie le 2026-09-20 pour les gates Rust/WASM et le build frontend production. Le smoke navigateur confirme aussi le ratio Canvas corrigé, mais le comportement SimpleBar reste incorrect ou absent et déclenche `0-pre.4.fix.3`.
## Validation utilisateur
Les validations suivantes ont passé sur `0.3.0-0-pre.4.fix.2` :
```text
cargo fmt --all: clean
cargo fmt --all -- --check: clean
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 185 file(s))
Distribution layout audit: clean (27 required path(s), 1 forbidden path(s) absent)
cargo check --workspace: clean
cargo clippy --workspace --all-targets --all-features -- -D warnings: clean
cargo test -p game-snake-poc-wasm: 2 passed, 0 failed
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown: clean
wasm-bindgen --target web: clean
cargo tree -p game-snake-poc-wasm --edges normal: expected dependencies only
npm install: 49 packages audited, 0 vulnerability
npm run build: clean
npm run dev: Vite started on 127.0.0.1:1434
manual smoke: page displayed correctly
manual smoke: Canvas height/ratio correct
```
Le build Vite production a généré `main.html`, les fonts, le WASM, le CSS et le JavaScript sous `../builds/sasedev-games/game-snake-poc-web/dist/`.
`npm install` continue de signaler le warning non bloquant relatif au script d'installation de `@parcel/watcher@2.6.0`; aucune vulnérabilité npm n'est signalée.
## Défaut restant
Le scroll personnalisé SimpleBar n'est pas observé comme attendu pendant le smoke. La comparaison avec les apps `ksp-app-*-desk` confirme un écart structurel :
- KSP borne la hauteur via `app-main`;
- `data-simplebar` est attaché à `app-content app-scrollable h-100`;
- cette zone centrale porte explicitement `height: 100%` et `max-height: 100%`;
- le point d'entrée TypeScript importe `resize-observer-polyfill` et `simplebar`, puis installe le polyfill global avant l'initialisation applicative.
Le frontend Snake avait placé `data-simplebar` directement sur `app-main` et la zone `app-content` utilisait seulement `min-height: 100%`.
## Suite
`0-pre.4.fix.3` aligne la structure HTML/Sass sur le shell KSP sans modifier le gameplay, le bridge WASM, le Canvas ni les contrôles.

View File

@@ -0,0 +1,29 @@
<!-- file: history/0.3.0/0-pre.4.fix.3.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.4.fix.3
## Statut
Correctif SimpleBar validé par l'utilisateur le 2026-09-20. La tranche `0-pre.4` est fermée et `0-pre.5` peut ouvrir l'intégration plateforme complète.
## Validation utilisateur
La sortie fournie sur `0.3.0-0-pre.4.fix.3` confirme au minimum :
```text
npm install: 49 packages audités, 0 vulnérabilité
npm run build: clean
npm run dev: Vite démarré sur 127.0.0.1:1434
cargo tree -p game-snake-poc-wasm --edges normal: dépendances attendues
manual smoke: page et Canvas corrects
manual smoke: comportement SimpleBar conforme au shell KSP-derived
```
Le build Vite production a généré `main.html`, fonts, WASM, CSS et JavaScript sous `../builds/sasedev-games/game-snake-poc-web/dist/`.
Le warning npm non bloquant relatif au script d'installation de `@parcel/watcher@2.6.0` reste présent et n'a pas empêché le build.
## Suite
`0-pre.5` ferme lifecycle/resize, assets, logging et provenance runtime du host Web, puis vérifie la non-régression du runner Snake Desktop SDL3.

50
history/0.3.0/0-pre.4.md Normal file
View File

@@ -0,0 +1,50 @@
<!-- file: history/0.3.0/0-pre.4.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.4
## Statut
Candidate Web fonctionnelle en smoke navigateur mais non validée comme tranche fermée le 2026-09-20 : la gate `npm run build` a échoué et a déclenché `0-pre.4.fix.1`.
## Validation utilisateur
Les validations suivantes ont passé sur `0.3.0-0-pre.4` :
```text
cargo fmt --all: clean
cargo fmt --all -- --check: clean
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 181 file(s))
Distribution layout audit: clean (26 required path(s), 1 forbidden path(s) absent)
cargo check --workspace: clean
cargo clippy -p game-snake-poc-wasm --all-targets --all-features -- -D warnings: clean
cargo test -p game-snake-poc-wasm: 2 passed, 0 failed
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown: clean
wasm-bindgen --target web: clean
npm install: 43 packages added, 0 vulnerability
npm run dev: Vite started on 127.0.0.1:1434
manual smoke: keyboard controls clean
manual smoke: on-page pointer controls clean
```
La page de smoke est volontairement `http://127.0.0.1:1434/main.html`; l'absence d'`index.html` rend la racine `/` non navigable et n'est pas considérée comme un défaut de cette tranche.
## Défauts observés
`npm run build` a échoué sous TypeScript 7 avec :
```text
TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration.
```
Deux écarts visuels/structurels ont aussi été confirmés pendant le smoke :
- SimpleBar et `resize-observer-polyfill` avaient été omis à tort alors qu'ils appartiennent au shell Web KSP-derived et doivent porter le scroll de la zone centrale entre header et footer fixes ;
- le Canvas carré déformait la grille Snake `12 × 20`, produisant des cellules visuellement écrasées en hauteur.
## Suite
`0-pre.4.fix.1` corrige ces trois points puis rejoue la gate frontend avant ouverture de `0-pre.5`.

View File

@@ -0,0 +1,59 @@
<!-- file: history/0.3.0/0-pre.5.fix.1.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.5.fix.1
## Statut
Intégration plateforme du POC Snake Web validée par l'utilisateur le 2026-09-20. Aucun défaut structurel supplémentaire n'est identifié ; `0-pre.6` conditionnelle est omise et la version peut entrer en `2-beta.1`.
## Validation utilisateur
Les gates suivantes ont passé sur `0.3.0-0-pre.5.fix.1` :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 191 file(s))
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
cargo fmt --all -- --check: clean
cargo check --workspace: clean
cargo clippy --workspace --all-targets --all-features -- -D warnings: clean
cargo test -p engine-v1-platform-api --all-targets --all-features: 3 passed, 0 failed
cargo test -p game-snake-poc-wasm --all-targets --all-features: 4 passed, 0 failed
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown: clean
wasm-bindgen --target web: clean
cargo tree -p game-snake-poc-wasm --edges normal: frontière attendue
npm install: 64 packages audités, 0 vulnérabilité
npm run build: clean, 30 modules transformés, 2 assets copiés
npm run dev: Vite démarré sur 127.0.0.1:1434
```
Le warning npm non bloquant relatif au script d'installation de `@parcel/watcher@2.6.0` reste présent.
## Smoke Web accepté
Le navigateur confirme :
```text
Provenance: web / browser / wasm / desktop / keyboard-mouse
Assets: snake / engine-v1
controls: clavier et contrôles souris fonctionnels
```
Le chargement des assets est donc réparé en dev et le bridge expose la provenance attendue. Les tests lifecycle/resize plus larges restent repris dans la gate beta afin de consolider le comportement feature-complete.
## Non-régression Desktop SDL3
Le smoke `cargo run -p game-snake-poc-desktop` passe :
```text
desktop SDL3 runner started game="snake"
SDL3 runtime started title=Snake POC width=405 height=720
SDL3 runtime stopped frames=411
```
## Suite
La tranche conditionnelle `0-pre.6` est omise. `2-beta.1` ouvre une validation large sans nouveau scope fonctionnel.

51
history/0.3.0/0-pre.5.md Normal file
View File

@@ -0,0 +1,51 @@
<!-- file: history/0.3.0/0-pre.5.md -->
<!-- version: 1 -->
# Historique 0.3.0-0-pre.5
## Statut
Validation technique partielle fournie par l'utilisateur le 2026-09-20. Les gates Rust/WASM et le build Vite passent, mais le smoke navigateur est bloqué par le chargement des assets runtime ; `0-pre.5` nécessite donc `0-pre.5.fix.1`.
## Validations réussies
La sortie utilisateur confirme :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 189 file(s))
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
cargo fmt --all -- --check: clean
cargo check --workspace: clean
cargo clippy --workspace --all-targets --all-features -- -D warnings: clean
cargo test -p engine-v1-platform-api --all-targets --all-features: 3 passed
cargo test -p game-snake-poc-wasm --all-targets --all-features: 4 passed
cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown: clean
wasm-bindgen --target web: clean
cargo tree -p game-snake-poc-wasm --edges normal: frontière attendue
npm install: 64 packages audités, 0 vulnérabilité
npm run build: clean, 30 modules transformés, 2 assets collectés
npm run dev: Vite démarré sur 127.0.0.1:1434
```
Le warning npm relatif au script d'installation de `@parcel/watcher@2.6.0` reste non bloquant.
Le smoke `cargo run -p game-snake-poc-desktop` n'a pas été exécuté dans cette tentative, le smoke Web étant déjà bloqué par les assets.
## Défaut observé
Le shell démarre, mais les sondes visibles restent :
```text
Provenance: web / browser / wasm / unknown / unknown
Assets: chargement…
Impossible de démarrer Snake : fetchJson@http://127.0.0.1:1434/ts/assets.ts:4:9
```
Le build production copie les deux assets, mais le serveur de développement ne les expose pas aux routes attendues par `fetchJson()`. Les targets de `vite-plugin-static-copy` partent de chemins absolus sans suppression explicite du préfixe source.
## Suite
`0-pre.5.fix.1` impose `rename: { stripBase: true }` aux deux targets afin de rendre les routes runtime identiques en `vite dev` et dans `dist/`, puis rejoue le smoke assets/provenance/lifecycle avant toute entrée en beta.

52
history/0.3.0/2-beta.1.md Normal file
View File

@@ -0,0 +1,52 @@
<!-- file: history/0.3.0/2-beta.1.md -->
<!-- version: 1 -->
# Historique 0.3.0-2-beta.1
## Statut
Gate beta feature-complete validée par l'utilisateur le 2026-09-20. Aucun défaut fonctionnel ou de packaging n'est remonté ; la version peut entrer dans la consolidation `2-beta.2`.
## Gate workspace
Les validations suivantes passent :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 193 file(s))
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
cargo fmt --all -- --check: clean
cargo check --workspace: clean
cargo clippy --workspace --all-targets --all-features -- -D warnings: clean
cargo test --workspace --all-targets --all-features: 34 passed, 0 failed
```
## Desktop Snake release
Le build release passe et le smoke SDL3 se ferme proprement :
```text
desktop SDL3 runner started game="snake"
SDL3 runtime started title=Snake POC width=405 height=720
SDL3 runtime stopped frames=144
```
## Web/WASM release
Le module Snake WASM release compile, `wasm-bindgen --target web` termine sans erreur, puis le frontend passe :
```text
npm install: 64 packages audités, 0 vulnérabilité
npm run build: clean, 30 modules transformés, 2 assets copiés
npm run preview: Vite démarré sur 127.0.0.1:4174
```
Le warning npm non bloquant relatif au script d'installation de `@parcel/watcher@2.6.0` reste présent.
L'utilisateur accepte le résultat de la gate beta sans défaut supplémentaire remonté.
## Suite
`0.3.0-2-beta.2` consolide documentation durable, roadmap, historique, matrice RC et prompt `0.3.1`, sans nouveau comportement.

View File

@@ -0,0 +1,38 @@
<!-- file: history/0.3.0/2-beta.2.fix.1.md -->
<!-- version: 1 -->
# Historique 0.3.0-2-beta.2.fix.1
## Statut
Revue humaine effectuée le 2026-09-20. Le niveau de détail du prompt `0.3.1` est jugé globalement satisfaisant, mais la politique de commandes doit encore être précisée avant RC ; `2-beta.2.fix.2` est donc ouvert.
## Résultat de revue
Éléments acceptés :
```text
prompt de reprise autonome sans reproduire toute la documentation KSP
timing du prompt suivant / RC / CHANGELOG / ROADMAP clarifié
rôle de deltas/ et history/ clarifié
politique README.md / USAGE.md jugée adaptée
fix strictement documentaire sans bump des versions runtime confirmé
```
Précisions demandées avant RC :
```text
cargo fmt/check workspace/Clippy strict obligatoires dès que Rust ou ses dépendances changent
audits Python sélectionnés selon les fichiers touchés
tests cargo ciblés privilégiés
test workspace complet limité à quelques jalons planifiés ou aux portées transverses incertaines
cargo tree uniquement lors de changements/diagnostics de dépendances
commandes nécessitant cd exécutées dans un sous-shell
Tauri : npm seulement pour gérer les dépendances ; smoke via cargo tauri dev ; packaging final via cargo tauri build
```
Aucune sortie d'audit ou de build spécifique à `2-beta.2.fix.1` n'a été fournie dans cette revue ; aucune gate mécanique supplémentaire n'est donc déclarée PASS ici.
## Suite
`2-beta.2.fix.2` formalise ces règles et met à jour le prompt `0.3.1` sans toucher aux versions techniques.

View File

@@ -0,0 +1,35 @@
<!-- file: history/0.3.0/2-beta.2.fix.2.md -->
<!-- version: 1 -->
# Historique 0.3.0-2-beta.2.fix.2
## Statut
Correctif documentaire validé par l'utilisateur le 2026-09-20. Le workflow de commandes et le prompt `0.3.1` sont acceptés ; la RC `0.3.0-3-rc.1` peut être ouverte.
## Validation utilisateur
La gate proportionnelle au scope strictement documentaire a été exécutée :
```text
python3 scripts/audit_markdown_tables.py docs prompts deltas history
Markdown table audit: clean (5 table(s), 189 file(s))
```
Aucune gate Cargo, npm, Gradle, Tauri, distribution ou smoke n'était applicable à ce correctif, qui ne modifiait ni code, ni dépendance, ni manifeste runtime/build.
## Décision
Les règles suivantes sont considérées consolidées pour la suite :
```text
fmt/check/Clippy workspace lorsque Rust ou ses dépendances changent
tests Cargo ciblés par défaut
test workspace complet seulement aux jalons planifiés ou portées incertaines
cargo tree uniquement pour dépendances/features ou diagnostic explicite
audits Python sélectionnés selon les fichiers touchés
sous-shell obligatoire pour les commandes avec changement de répertoire
Tauri : npm pour dépendances, cargo tauri dev pour smoke, cargo tauri build pour packaging final
```
Le prompt `prompts/003-V0_3_1_START_PROMPT.md` est jugé suffisamment autonome pour la transmission.

51
history/0.3.0/2-beta.2.md Normal file
View File

@@ -0,0 +1,51 @@
<!-- file: history/0.3.0/2-beta.2.md -->
<!-- version: 1 -->
# Historique 0.3.0-2-beta.2
## Statut
Consolidation `2-beta.2` validée par l'utilisateur le 2026-09-20. Les audits, le check workspace et le build frontend de production passent ; aucun défaut mécanique n'est remonté.
Une revue humaine du prompt `0.3.1` relève toutefois qu'il est trop court pour servir de contrat de reprise suffisamment autonome. La correction appartient à `2-beta.2` puisqu'elle concerne la consolidation/transmission et ouvre `2-beta.2.fix.1`.
## Gate documentaire et workspace
Les validations suivantes passent :
```text
cargo fmt --all -- --check: clean
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 198 file(s))
Distribution layout audit: clean (31 required path(s), 1 forbidden path(s) absent)
cargo check --workspace: clean
```
## Frontend
Le package Web Snake est confirmé cohérent avec le jalon beta :
```text
npm install: 64 packages audités, 0 vulnérabilité
npm run build: clean
Vite: 30 modules transformés
vite-plugin-static-copy: 2 items copiés
```
Le warning npm non bloquant relatif au script d'installation de `@parcel/watcher@2.6.0` reste présent.
## Revue humaine
Le contenu de consolidation est accepté mécaniquement, mais le prompt `prompts/003-V0_3_1_START_PROMPT.md` doit être enrichi avant la RC afin de rappeler de manière autonome :
- le timing du prompt suivant, du `CHANGELOG.md` et du `ROADMAP.md` ;
- le rôle respectif de `deltas/` et `history/` ;
- où se trouvent les définitions de commandes et leur matrice ;
- la politique `README.md` / `USAGE.md` des crates et applications ;
- le workflow de validation/fix et la condition de fin de session.
## Suite
`0.3.0-2-beta.2.fix.1` corrige uniquement la transmission documentaire et les règles associées. Aucun changement code/build/runtime n'est attendu.

41
history/0.3.0/3-rc.1.md Normal file
View File

@@ -0,0 +1,41 @@
<!-- file: history/0.3.0/3-rc.1.md -->
<!-- version: 1 -->
# Historique 0.3.0-3-rc.1
## Statut
Validé par l'utilisateur le 2026-09-20 puis retenu pour promotion mécanique vers `0.3.0`.
## Gate workspace
La gate RC complète a passé :
- `cargo fmt --all` ;
- `cargo fmt --all -- --check` ;
- audits Rust général, exports, workspace, Markdown et distribution propres ;
- `cargo check --workspace` ;
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` ;
- `cargo test --workspace --all-targets --all-features` avec 34 tests réussis et aucun échec.
## Desktop Snake release
`game-snake-poc-desktop` a été construit en `--release`, exécuté avec SDL3 puis arrêté proprement.
Le runtime observé s'est terminé après 926 frames.
## Web / WASM release
`game-snake-poc-wasm` a été construit en `--release` pour `wasm32-unknown-unknown`, puis traité avec `wasm-bindgen --target web`.
Le frontend `game-snake-poc-web` a ensuite passé :
- `npm install` sans vulnérabilité signalée ;
- `npm run build` ;
- démarrage de `npm run preview` sur `http://127.0.0.1:4174/`.
Le build Vite a copié les deux assets canoniques et produit le bundle WASM/CSS/JavaScript de release.
## Conclusion
La RC conserve le scope gelé de `0.3.0`. Aucun défaut fonctionnel, de compilation ou de packaging nécessitant un `.fix.N` n'a été remonté après la gate RC ; la promotion stable peut donc rester mécanique.

View File

@@ -1,5 +1,5 @@
<!-- file: prompts/002-V0_3_X_START_PROMPT.md --> <!-- file: prompts/002-V0_3_X_START_PROMPT.md -->
<!-- version: 2 --> <!-- version: 4 -->
# Prompt de démarrage — `0.3.0` / série `0.3.x` POC plateforme et réseau # Prompt de démarrage — `0.3.0` / série `0.3.x` POC plateforme et réseau
@@ -12,7 +12,7 @@ Avant toute modification :
1. lire `RULES.md`, `ROADMAP.md`, `CHANGELOG.md` et `docs/000-README.md` ; 1. lire `RULES.md`, `ROADMAP.md`, `CHANGELOG.md` et `docs/000-README.md` ;
2. lire les règles de session, commandes et validation ; 2. lire les règles de session, commandes et validation ;
3. lire les architectures consolidées `012` à `016` ; 3. lire les architectures consolidées `012` à `016` ;
4. vérifier l'état Git/workspace ; 4. lorsque la base est une archive téléchargée depuis le tag fourni, la traiter comme snapshot autoritaire sans exiger `.git` ; vérifier sa cohérence workspace/version ;
5. exécuter les audits applicables à la base ; 5. exécuter les audits applicables à la base ;
6. confirmer la version workspace avant `0.3.0-0-pre.1`. 6. confirmer la version workspace avant `0.3.0-0-pre.1`.
@@ -128,7 +128,7 @@ Objectif :
- requirements ; - requirements ;
- graphe de dépendances ; - graphe de dépendances ;
- choix du premier POC ; - choix du premier POC ;
- forecast corrigé ; - plan actif sous `docs/plans/` avec forecast corrigé ;
- commandes prévues ; - commandes prévues ;
- critères de sortie. - critères de sortie.
@@ -150,65 +150,51 @@ Validation candidate :
- Desktop SDL toujours fonctionnel ; - Desktop SDL toujours fonctionnel ;
- dependency audit ciblé. - dependency audit ciblé.
### `0-pre.3` — adapters/capabilities minimaux ### `0-pre.3` — adaptation Snake WASM
Objectif candidat : Décision issue de `pre.1` :
- extraire uniquement ce que le premier POC prouve nécessaire ; - introduire la crate/adaptation WASM minimale de Snake ;
- éviter duplication bridge/frontend ; - générer les bindings avec `wasm-bindgen` ;
- préparer input/resize/lifecycle/runtime provenance ; - conserver le gameplay dans `game-snake-poc` ;
- documenter les duplications provisoires. - ne pas généraliser avant qu'un second consommateur ne le justifie.
Cette tranche peut être fusionnée avec `pre.2`. ### `0-pre.4` — frontend Web/Vite + shell Bootstrap 5
### `0-pre.4` — premier POC de bout en bout Décision issue de `pre.1` : le premier host est Web navigateur direct + Snake.
Préférence initiale : Le frontend doit fournir :
```text - un document HTML responsive piloté par Vite/TypeScript ;
Tauri Android + Snake - Bootstrap 5 comme baseline de présentation/layout et pour les contrôles UI ;
``` - un Canvas dédié au rendu du jeu ;
- clavier et boutons directionnels tactiles ;
- états de chargement/erreur utiles au POC.
Alternative si `pre.1` la juge plus rationnelle : Le framework HTML/CSS reste strictement côté frontend : Rust/WASM conserve le gameplay et l'état du jeu.
```text ### `0-pre.5` — intégration plateforme complète
Web navigateur direct + Snake
```
Le POC doit couvrir : Fermer les besoins de bout en bout du POC :
- build avec outil natif ; - resize/lifecycle ;
- lancement ;
- rendu ;
- contrôles ;
- resize/orientation selon host ;
- lifecycle ;
- logging ;
- assets ; - assets ;
- runtime provenance. - logging ;
- runtime provenance ;
- non-régression du runner Desktop SDL3.
Compiler seul ne suffit pas. Compiler seul ne suffit pas : le smoke navigateur fait partie de la validation.
### `0-pre.5` — corrections/généralisation issues du POC ### `0-pre.6` — correction/extraction conditionnelle
Créer seulement si le POC révèle un besoin réel : Créer seulement si les tranches précédentes révèlent un besoin réel :
- supprimer duplication avérée ; - supprimer duplication avérée ;
- corriger frontières mal placées ; - corriger frontières mal placées ;
- ajouter tests nécessaires ; - ajouter tests nécessaires ;
- documenter ce qui reste spécifique. - documenter ce qui reste spécifique.
### `1-alpha.1` — intégration éventuelle Sinon, omettre cette tranche.
À utiliser seulement si le volume de code nouveau justifie une phase distincte.
Objectif :
- stabiliser interfaces Snake/capabilities/host ;
- fermer les défauts structurels ;
- aucun nouveau scope.
Sinon, ne pas créer cette tranche artificiellement.
### `2-beta.1` — validation large ### `2-beta.1` — validation large
@@ -220,6 +206,18 @@ Objectif :
- documentation des commandes ; - documentation des commandes ;
- vérification qu'aucune abstraction spéculative n'a été ajoutée. - vérification qu'aucune abstraction spéculative n'a été ajoutée.
### `2-beta.2` — consolidation documentaire et transmission
Responsabilité obligatoire, même si sa numérotation finale glisse :
- réconcilier la documentation durable avec l'état validé ;
- mettre à jour `CHANGELOG.md` et `ROADMAP.md` ;
- mettre à jour l'historique applicable ;
- réconcilier le plan avec les deltas réellement livrés ;
- préparer et vérifier le prompt de la version/session suivante.
Cette tranche consolide la documentation ; elle ne reporte pas à la fin la documentation spécifique qui devait accompagner les tranches fonctionnelles.
### `3-rc.1` — candidate ### `3-rc.1` — candidate
Scope gelé. Scope gelé.

View File

@@ -0,0 +1,593 @@
<!-- file: prompts/003-V0_3_1_START_PROMPT.md -->
<!-- version: 3 -->
# Prompt de démarrage `0.3.1` — second host Snake Tauri Android
## 1. Base exacte et autorité de la reprise
Partir uniquement de la version stable/taggée :
```text
v0.3.0
```
Si ce prompt est lu avant la publication effective de `0.3.0`, ne pas ouvrir `0.3.1`. Terminer d'abord la RC puis la release stable `0.3.0`.
Lorsqu'une archive est fournie comme téléchargement du tag `v0.3.0`, elle constitue la baseline autoritaire même si elle ne contient pas `.git`. Appliquer `CMD-GIT-003` et `CMD-GIT-004` : vérifier la cohérence interne des versions et des fichiers, ne pas inventer un état Git inaccessible.
Version cible :
```text
0.3.1
```
Première tranche obligatoire :
```text
0.3.1-0-pre.1
```
`0-pre.1` est un gate de lecture, audit, requirements, sizing, validation et planification. Ne pas commencer directement par le scaffold Android/Tauri ou par la copie du POC Reflex.
## 2. Sources de vérité — ordre de lecture obligatoire
Lire intégralement, dans cet ordre :
```text
RULES.md
ROADMAP.md
CHANGELOG.md
docs/000-README.md
```
Puis lire les règles directement pertinentes :
```text
docs/rules/RULES_GENERAL.md
docs/rules/RULES_RUST.md
docs/rules/RULES_PROJECT.md
docs/rules/RULES_DOCUMENTATION.md
docs/rules/FILE_CONTRACTS.md
docs/rules/VERSION_WORKFLOW.md
docs/rules/RULES_COMMANDS.md
docs/rules/RULES_VALIDATION_MATRIX.md
docs/rules/RULES_SESSION_PLANNING.md
docs/rules/PROMPT_STRUCTURE.md
```
Le prompt résume les garde-fous nécessaires à `0.3.1`; les règles restent normatives en cas de détail absent ici.
Lire ensuite la transmission `0.3.0` :
```text
docs/plans/001-V0_3_0_WEB_SNAKE_POC_PLAN.md
docs/architecture/015-PLATFORM_POC_ARCHITECTURE.md
docs/architecture/018-V0_3_0_WEB_SNAKE_BASELINE.md
docs/testing/004-V0_3_0_RC_VALIDATION_MATRIX.md
history/0.3.0/
deltas/0.3.0/
```
Enfin auditer les implémentations réellement concernées :
```text
crates/games/game-snake-poc/
crates/apps/game-snake-poc-wasm/
Web/game-snake-poc/
crates/apps/game-snake-poc-desktop/
crates/apps/game-reflex-poc-tauri/
crates/apps/game-reflex-poc-wasm/
Android/
assets/
```
Ne pas déduire l'état d'une crate depuis ce prompt lorsque le code stable `0.3.0` dit autre chose.
## 3. État hérité attendu de `0.3.0`
La stable `0.3.0` doit avoir validé au minimum :
```text
Snake gameplay indépendant des hosts
runner Desktop SDL3 fonctionnel
adapter Snake WASM dédié
host navigateur direct Vite/TypeScript
shell HTML Bootstrap 5 / Bootswatch / SimpleBar
Canvas respectant le ratio logique Snake
clavier + contrôles pointer/tactiles
lifecycle navigateur fixed-step sans catch-up massif
assets common/game packagés depuis assets/
logging frontend structuré
RuntimeProvenance Web / Browser / Wasm
build WASM release + wasm-bindgen
build Vite production + preview
```
Cette liste est un handoff attendu, pas une validation à réexécuter aveuglément au premier instant. Confirmer l'état réel de la stable puis définir les non-régressions nécessaires à `0.3.1`.
## 4. Mission de `0.3.1`
`0.3.1` doit produire le second host Snake : Tauri Android.
Le but est de vérifier que la baseline Web/WASM de `0.3.0` peut être réutilisée dans un WebView mobile Tauri sans recopier le gameplay, sans dupliquer inutilement le bridge WASM et sans créer un framework abstrait avant preuve d'un besoin partagé.
Résultat attendu :
```text
Snake exécutable dans un host Tauri Android
build Android piloté par les outils Tauri/Android natifs retenus
lifecycle mobile cohérent
input tactile et comportement WebView cohérents
assets accessibles dans le package final
logging Rust/Tauri/frontend cohérent
RuntimeProvenance distincte du navigateur direct
non-régression du host Web direct 0.3.0
non-régression Desktop SDL3 si une frontière partagée change
```
## 5. `0.3.1-0-pre.1` — cadrage obligatoire
Avant tout développement lourd, produire un audit réel de la stable `0.3.0` et de l'environnement disponible.
### 5.1 Baseline Snake
Auditer :
```text
game-snake-poc
game-snake-poc-wasm
Web/game-snake-poc
game-snake-poc-desktop
engine-v1-common
engine-v1-platform-api
assets communs et Snake
```
Identifier explicitement :
- ce qui est réutilisable tel quel ;
- ce qui est spécifique au navigateur direct ;
- ce qui appartient déjà à l'adapter WASM ;
- ce qui deviendrait réellement partagé entre navigateur et WebView Tauri ;
- toute duplication prouvée avant extraction.
### 5.2 Référence Tauri existante
Auditer intégralement :
```text
crates/apps/game-reflex-poc-tauri/
crates/apps/game-reflex-poc-wasm/
docs/development/008-WASM_TAURI_POC.md
```
Le POC Reflex est une référence technique de structure, de bridge Tauri, de frontend et de logging. Il n'est pas un template à copier aveuglément si sa baseline historique contredit les règles `0.3.x`.
Vérifier notamment :
```text
src/lib.rs comme façade/reexports
src/tauri.rs comme assemblage Tauri et pont Web/Rust
modules propriétaires séparés
tauri.conf.json / capabilities / permissions
hooks frontend Vite
tauri-plugin-tracing / @fltsci/tauri-plugin-tracing
organisation frontend HTML/Sass/TypeScript
```
### 5.3 Android existant
Auditer `Android/` et les documents Android existants pour distinguer :
```text
baseline Android SDL3/Java/JNI
host Tauri Android de 0.3.1
```
Ils peuvent partager des contraintes plateforme, SDK/NDK ou documentation, mais ne doivent pas être confondus ni couplés artificiellement.
### 5.4 Toolchains réelles
Inventorier ce qui est réellement disponible dans l'environnement utilisateur :
```text
Rust targets Android nécessaires
Tauri CLI/version réellement utilisée
Android SDK
Android NDK
Java/JDK
Gradle/tooling éventuellement piloté par Tauri
adb
émulateur/AVD éventuel
appareil réel éventuel
Node/npm
```
Ne pas déclarer un smoke appareil/émulateur possible avant de confirmer qu'une cible est effectivement accessible.
### 5.5 Sizing et plan
Créer ou réviser obligatoirement le plan de `0.3.1` sous :
```text
docs/plans/
```
Le plan doit contenir :
- objectif et scope ;
- décisions acquises ;
- risques/dépendances utiles ;
- hors-périmètre ;
- validations prévues ;
- découpage prévisionnel souple jusqu'à `0.3.1` stable ;
- tranche de validation large ;
- tranche de consolidation documentaire ;
- RC gelée ;
- release stable mécanique.
Si le sizing montre que Tauri Android complet ne tient pas raisonnablement dans une session, réduire ou scinder le scope avant l'implémentation lourde.
## 6. Contraintes architecturales gelées
Préserver les frontières suivantes :
```text
game-snake-poc
gameplay et règles de jeu
engine-v1-common
contrats moteur portables
engine-v1-platform-api
provenance/capabilities plateforme
game-snake-poc-wasm
adaptation WASM Snake
host Web direct / host Tauri
lifecycle, DOM/WebView, inputs physiques, packaging et UI
```
Règles spécifiques :
- `game-snake-poc` reste indépendant de Tauri, Android, DOM, Canvas et providers ;
- ne pas copier le gameplay dans TypeScript, Java ou le backend Tauri ;
- conserver `game-snake-poc-wasm` comme adapter WASM tant qu'un besoin réel ne justifie pas une extraction ;
- ne pas généraliser `Web/game-snake-poc` avant observation du second consommateur ;
- une extraction commune Web/WebView n'est autorisée que si deux consommateurs réels prouvent sa valeur ;
- `lib.rs` d'une app Tauri reste une façade/reexport ;
- `tauri.rs` assemble Tauri et délègue aux modules propriétaires ;
- les traces frontend Tauri utilisent le bridge tracing prévu par les règles, pas des `console.*` applicatifs dispersés ;
- ne pas réintroduire d'orchestrateur Python de build ;
- ne pas utiliser `scripts/build_reflex_tauri_wasm.py` pour le nouveau chemin `0.3.x` ;
- ne pas introduire réseau realtime, Uroburas, ads, billing ou leaderboard dans `0.3.1`.
## 7. Frontend Tauri et commandes Web
Le frontend Tauri peut reprendre les conventions de shell déjà éprouvées dans les applications Desk KSP et dans le POC existant lorsque cela reste pertinent :
```text
Vite
TypeScript
HTML/Sass
Bootstrap 5 / thème retenu
Font Awesome
SimpleBar + ResizeObserver si le layout le nécessite
```
Pour une application Tauri, `npm` sert seulement à gérer les dépendances frontend lorsqu'une dépendance doit être ajoutée/retirée (`npm i`, `npm i -D`, etc.). Ne pas utiliser `npm run dev` ou `npm run build` comme gates Tauri manuelles : les hooks Tauri possèdent Vite/TypeScript/WASM.
Le smoke courant utilise :
```bash
(cd <tauri-app> && cargo tauri dev)
```
Le packaging est réservé aux phases finales prévues par le plan :
```bash
(cd <tauri-app> && cargo tauri build)
```
Ne pas traiter le host Tauri comme le host navigateur direct de `0.3.0` : le mode de lancement, le packaging, les permissions et les smokes sont différents.
## 8. Provenance attendue
Le host Tauri Android doit produire une provenance distincte du navigateur direct.
`0-pre.1` doit auditer les enums/contrats réels de `engine-v1-platform-api` avant de fixer les valeurs exactes, mais préserver les dimensions :
```text
platform family
runtime host
execution model
device class
input profile
```
Ne pas ajouter une identification matérielle fine uniquement pour ce POC.
## 9. Documentation des crates/packages
Pendant `0-pre.1`, appliquer `DOC-CRATE-*` à tout composant créé ou finalisé.
La question doit être explicitement tranchée pour la nouvelle app Tauri :
```text
README.md ?
responsabilité / frontières / architecture locale / points d'entrée
USAGE.md ?
prérequis / commandes / installation / lancement / smoke opérateur
```
Ne pas créer des fichiers vides ou redondants. Si la documentation centrale couvre réellement un petit adapter, le plan peut documenter pourquoi un fichier local séparé n'apporte rien.
Lors de la consolidation finale, refaire cette revue pour chaque crate/package considéré durable dans `0.3.1`.
## 10. Deltas, history et état validé
Ne pas confondre :
```text
deltas/<X.Y.Z>/
décrit la livraison candidate
base requise
fichiers ajoutés/modifiés/supprimés
décisions
validations à exécuter
validations non exécutées
history/<X.Y.Z>/
décrit un jalon effectivement validé
résultats réellement fournis par l'utilisateur
défauts acceptés/corrigés
état transmis au jalon suivant
```
Une entrée `history/` n'est jamais pré-écrite pour le delta courant. Après validation utilisateur, le delta suivant ou son fix crée l'entrée historique du jalon accepté conformément à `DOC-HIST-*`.
Les anciens fichiers de `deltas/` et `history/` restent immuables sur le fond.
## 11. CHANGELOG, ROADMAP, plan et prompt suivant
Appliquer ces responsabilités sans les mélanger :
### Plan
`docs/plans/` porte le suivi fin et vivant de `0.3.1`. Il est créé/révisé en `0-pre.1` puis réconcilié lorsqu'un résultat réel modifie la trajectoire.
### ROADMAP
`ROADMAP.md` reste macroscopique. Le modifier lorsqu'un scope est ajouté, réalisé, reporté ou annulé ; ne pas ajouter une ligne pour chaque prerelease/fix.
### CHANGELOG
`CHANGELOG.md` est une synthèse de publication. Les `pre`, `alpha`, `beta` et fixes ne créent normalement pas d'entrée. Écrire la synthèse candidate à partir de la RC, puis la synthèse stable lors de la release.
### Prompt de la version suivante
Rédiger le prompt suivant pendant la consolidation finale de `0.3.1` lorsque la cible `0.3.2` est suffisamment connue. La première RC gelée vérifie/complète le prompt à partir de l'état réellement candidat à publication.
Ne jamais présenter dans ce prompt futur une validation RC/stable qui n'a pas encore été exécutée.
## 12. Commandes et matrice de validation
Ne pas inventer une procédure de commandes parallèle dans le prompt.
Sources normatives :
```text
docs/rules/RULES_COMMANDS.md
docs/rules/RULES_VALIDATION_MATRIX.md
```
`RULES_COMMANDS.md` définit quand utiliser les audits, Cargo, Web, Android, Tauri et les smokes.
`RULES_VALIDATION_MATRIX.md` définit les IDs `CMD-*`, leurs dépendances et leurs déclencheurs.
Chaque delta sélectionne les commandes proportionnelles à son scope. Une commande non exécutée n'est jamais déclarée PASS.
Les audits Python sont choisis selon les fichiers touchés : ne pas exécuter systématiquement les trois audits si un seul est pertinent.
Dès qu'un delta touche du code Rust, un manifeste Cargo, une feature ou une dépendance Rust, la base obligatoire est :
```bash
cargo fmt --all
cargo fmt --all -- --check
# audits Python applicables au scope
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
Les tests normaux sont ciblés :
```bash
cargo test -p <crate> --all-targets --all-features
```
Ajouter les tests ciblés des consommateurs uniquement lorsque leur contrat est affecté. `cargo test --workspace --all-targets --all-features` reste une gate rare, planifiée un petit nombre de fois dans la version/session (initiale si utile, préfinale/finale, ou portée transverse incertaine).
Ne lancer `cargo tree` que si les dépendances/features changent ou qu'un diagnostic de frontière le justifie. Ne pas le mettre automatiquement dans chaque log de validation.
Toute commande nécessitant un changement de répertoire est englobée dans un sous-shell :
```bash
(cd <répertoire> && <commande>)
```
Pour Tauri, utiliser `cargo tauri dev` pour les smokes et réserver `cargo tauri build` aux phases finales de packaging ; `npm` n'est utilisé directement que pour gérer les dépendances frontend.
## 13. Qui exécute quoi
Le générateur peut exécuter les audits statiques en lecture seule afin de préparer un delta.
Les validations de build/runtime restent côté utilisateur :
```text
cargo check workspace + Clippy workspace strict lorsqu'un delta touche Rust/dépendances
tests cargo ciblés par défaut
test workspace complet seulement aux jalons planifiés/portées incertaines
(cd <tauri-app> && cargo tauri dev) pour les smokes Tauri
(cd <tauri-app> && cargo tauri build) pour les validations finales de packaging Tauri
Gradle/SDK/NDK lorsque le chemin Tauri les invoque
installation émulateur/appareil
smoke mobile
smoke Web direct de non-régression
smoke Desktop SDL3 si requis
```
Ne jamais annoncer un build ou un smoke comme réussi uniquement parce que le code paraît correct.
Une gate utilisateur propre permet de passer automatiquement à la tranche planifiée suivante sauf instruction contraire. Une gate en échec reste normalement dans un `.fix.N` de la tranche courante.
## 14. Forecast initial souple
Le forecast suivant est une hypothèse à confirmer ou corriger en `0-pre.1`.
### `0-pre.1` — audit / requirements / sizing / plan
- audit stable `0.3.0` ;
- audit Reflex Tauri/WASM ;
- audit environnement Tauri Android ;
- matrice réutilisation vs duplication ;
- stratégie de build/smoke ;
- positionnement explicite des rares gates `cargo test --workspace --all-targets --all-features` dans le plan ;
- plan `0.3.1` ;
- décision README/USAGE attendue pour les nouveaux composants.
### `0-pre.2` — host Tauri Android Snake minimal
- nouvelle app Tauri Android au bon emplacement ;
- consommation de l'adapter WASM Snake existant ou adaptation minimale justifiée ;
- premier build natif reproductible ;
- aucune généralisation prématurée.
### `0-pre.3` — lifecycle / input / assets / provenance / logging
- lifecycle WebView/mobile ;
- tactile/input ;
- assets ;
- provenance ;
- tracing Rust/Tauri/frontend ;
- erreurs de runtime visibles et sûres.
### `0-pre.4` — extraction conditionnelle
Créer uniquement si le second host révèle une duplication partagée réelle entre navigateur direct et Tauri WebView.
Sinon omettre la tranche.
### `2-beta.1` — validation large
- workspace complet ;
- `(cd <tauri-app> && cargo tauri build)` pour le packaging Tauri Android ;
- smoke via `(cd <tauri-app> && cargo tauri dev)` puis émulateur/appareil disponible ;
- non-régression Web direct ;
- non-régression Desktop SDL3 lorsque nécessaire ;
- vérification dépendances/package/distribution.
### `2-beta.2` — consolidation documentaire
- documentation durable ;
- README/USAGE réellement nécessaires ;
- plan réconcilié ;
- history ;
- ROADMAP selon le scope réellement livré ;
- préparation du prompt `0.3.2` ;
- matière de CHANGELOG prête sans créer une entrée beta artificielle.
### `3-rc.1` — candidate gelée
- scope fonctionnel gelé ;
- entrée RC du `CHANGELOG.md` ;
- matrice RC ;
- reproductibilité packaging ;
- prompt `0.3.2` vérifié/complété ;
- seulement bugs/release blockers ensuite.
### `0.3.1` — stable
Release mécanique de la RC validée : versions finales, synthèse stable, delta/release et tag selon le workflow applicable.
La numérotation est révisable. Les responsabilités ne doivent pas être fusionnées uniquement pour raccourcir artificiellement la version.
## 15. Hors-périmètre explicite
Ne pas ouvrir dans `0.3.1` sans décision de replanification :
```text
Tauri Desktop Snake comme nouveau produit
refonte générale engine-v1
engine-v2
Android SDL3 multi-ABI supplémentaire
nouveau framework frontend générique
serveur realtime
WebSocket/WebTransport/QUIC gameplay
Uroburas
ads/billing
leaderboard/auth
refactor massif de Reflex
mise à niveau opportuniste des dépendances
```
Une dépendance peut être mise à jour uniquement si elle est nécessaire au chemin `0.3.1` et que le delta le documente.
## 16. Packaging et fichiers générés
Respecter :
```text
../builds/sasedev-games/
```
pour les sorties Cargo/Tauri/Vite et caches concernés.
Ne pas livrer :
```text
node_modules/
dist/
target/
bindings wasm générés
caches
secrets
lockfiles interdits par les règles du dépôt
```
Le ZIP d'un delta contient uniquement les fichiers ajoutés/modifiés par la tranche plus son document de delta, et les suppressions éventuelles utilisent le manifest contractuel prévu.
## 17. Première séquence de travail de la session
À l'ouverture de `0.3.1` :
1. vérifier que la base fournie correspond réellement à la stable `0.3.0` ;
2. lire les sources de vérité dans l'ordre indiqué ;
3. lire le dernier `history/0.3.0` et le delta/release stable ;
4. exécuter les audits statiques applicables à la baseline ;
5. auditer `game-reflex-poc-tauri` et le chemin Tauri Android disponible ;
6. auditer `game-snake-poc-wasm` et le host Web direct ;
7. inventorier SDK/NDK/Tauri/adb/AVD/appareil réellement accessibles ;
8. produire requirements, risques, hors-périmètre et sizing ;
9. créer le plan `0.3.1` sous `docs/plans/` ;
10. seulement ensuite ouvrir le premier delta de développement.
## 18. Condition de fin de session
La session est dimensionnée pour fermer `0.3.1` jusqu'à sa stable.
Une prerelease n'est pas une cible normale de fin de session. Si le sizing ou une contrainte externe rend l'objectif trop grand, reporter explicitement le scope non indispensable vers `0.3.2+` plutôt que prolonger indéfiniment `0.3.1`.
La stable doit arriver avec :
```text
scope validé
builds/smokes applicables validés
documentation durable réconciliée
history complet des jalons acceptés
ROADMAP cohérente
CHANGELOG RC/stable cohérent
prompt de la version suivante prêt et vérifié
delta/release mécanique sans nouveau scope
```

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# file: scripts/audit_distribution_layout.py # file: scripts/audit_distribution_layout.py
# version: 1 # version: 7
"""Audit the static distribution layout expected by the 0.1.0 beta.""" """Audit the static distribution layout expected by supported POCs."""
from __future__ import annotations from __future__ import annotations
@@ -29,6 +29,18 @@ REQUIRED_PATHS = (
"crates/apps/game-reflex-poc-tauri/frontend/index.html", "crates/apps/game-reflex-poc-tauri/frontend/index.html",
"crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts", "crates/apps/game-reflex-poc-tauri/frontend/ts/main.ts",
"crates/apps/game-reflex-poc-wasm/Cargo.toml", "crates/apps/game-reflex-poc-wasm/Cargo.toml",
"crates/apps/game-snake-poc-wasm/Cargo.toml",
"Web/game-snake-poc/package.json",
"Web/game-snake-poc/tsconfig.json",
"Web/game-snake-poc/vite.config.ts",
"Web/game-snake-poc/frontend/main.html",
"Web/game-snake-poc/frontend/sass/_simplebar.scss",
"Web/game-snake-poc/frontend/sass/main.scss",
"Web/game-snake-poc/frontend/ts/main.ts",
"Web/game-snake-poc/frontend/ts/assets.ts",
"Web/game-snake-poc/frontend/ts/lifecycle.ts",
"Web/game-snake-poc/frontend/ts/logging.ts",
"Web/game-snake-poc/frontend/ts/provenance.ts",
"Android/game-reflex-poc/build.gradle", "Android/game-reflex-poc/build.gradle",
"Android/game-snake-poc/build.gradle", "Android/game-snake-poc/build.gradle",
"scripts/build_android_rust.py", "scripts/build_android_rust.py",
@@ -39,6 +51,91 @@ REQUIRED_PATHS = (
) )
def audit_snake_web_shell(root: pathlib.Path) -> list[str]:
"""Validate the KSP-derived bounded SimpleBar shell contract."""
violations: list[str] = []
html_path = root / "Web/game-snake-poc/frontend/main.html"
app_scss_path = root / "Web/game-snake-poc/frontend/sass/_app.scss"
main_ts_path = root / "Web/game-snake-poc/frontend/ts/main.ts"
if not html_path.exists() or not app_scss_path.exists() or not main_ts_path.exists():
return violations
html = html_path.read_text(encoding="utf-8")
app_scss = app_scss_path.read_text(encoding="utf-8")
main_ts = main_ts_path.read_text(encoding="utf-8")
required_html = (
'<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>',
)
for fragment in required_html:
if fragment not in html:
violations.append(f"DIST-LAYOUT-003: Snake Web shell missing required HTML contract: {fragment}")
if '<main class="app-main container-fluid p-0" data-simplebar>' in html:
violations.append("DIST-LAYOUT-004: data-simplebar must be attached to the bounded app-content zone, not app-main")
required_scss = (
".app-scrollable {",
"height: 100%;",
"max-height: 100%;",
)
for fragment in required_scss:
if fragment not in app_scss:
violations.append(f"DIST-LAYOUT-005: Snake Web shell missing required Sass contract: {fragment}")
required_ts = (
'import ResizeObserver from "resize-observer-polyfill";',
'import "simplebar";',
').ResizeObserver = ResizeObserver;',
)
for fragment in required_ts:
if fragment not in main_ts:
violations.append(f"DIST-LAYOUT-006: Snake Web shell missing SimpleBar bootstrap contract: {fragment}")
return violations
def audit_snake_web_integration(root: pathlib.Path) -> list[str]:
"""Validate assets, lifecycle, logging and provenance wiring for the Snake Web POC."""
violations: list[str] = []
package_path = root / "Web/game-snake-poc/package.json"
vite_path = root / "Web/game-snake-poc/vite.config.ts"
main_path = root / "Web/game-snake-poc/frontend/ts/main.ts"
lifecycle_path = root / "Web/game-snake-poc/frontend/ts/lifecycle.ts"
provenance_path = root / "Web/game-snake-poc/frontend/ts/provenance.ts"
wasm_manifest_path = root / "crates/apps/game-snake-poc-wasm/Cargo.toml"
wasm_runtime_path = root / "crates/apps/game-snake-poc-wasm/src/runtime.rs"
if not all(path.exists() for path in (package_path, vite_path, main_path, lifecycle_path, provenance_path, wasm_manifest_path, wasm_runtime_path)):
return violations
package = package_path.read_text(encoding="utf-8")
vite = vite_path.read_text(encoding="utf-8")
main = main_path.read_text(encoding="utf-8")
lifecycle = lifecycle_path.read_text(encoding="utf-8")
provenance = provenance_path.read_text(encoding="utf-8")
wasm_manifest = wasm_manifest_path.read_text(encoding="utf-8")
wasm_runtime = wasm_runtime_path.read_text(encoding="utf-8")
required_fragments = (
(package, '"vite-plugin-static-copy"', "DIST-LAYOUT-007: Snake Web package must declare static asset packaging"),
(vite, 'dest: "common/data", rename: { stripBase: true }', "DIST-LAYOUT-008: common Web assets must retain the common/data namespace without absolute source prefixes"),
(vite, 'dest: "game/data", rename: { stripBase: true }', "DIST-LAYOUT-009: game Web assets must retain the game/data namespace without absolute source prefixes"),
(main, 'loadSnakeWebAssets()', "DIST-LAYOUT-010: Snake Web startup must load runtime asset probes"),
(main, 'bindBrowserLifecycle(session, stage)', "DIST-LAYOUT-011: Snake Web startup must bind browser lifecycle"),
(lifecycle, '"visibilitychange"', "DIST-LAYOUT-012: Snake Web lifecycle must observe visibility changes"),
(lifecycle, '"pagehide"', "DIST-LAYOUT-013: Snake Web lifecycle must observe pagehide"),
(lifecycle, 'ResizeObserver', "DIST-LAYOUT-014: Snake Web lifecycle must observe resize"),
(provenance, '"keyboard-mouse"', "DIST-LAYOUT-015: Snake Web provenance must distinguish keyboard/mouse input"),
(provenance, '"touch"', "DIST-LAYOUT-016: Snake Web provenance must distinguish touch input"),
(wasm_manifest, 'engine-v1-platform-api = { path = "../../engines/engine-v1-platform-api" }', "DIST-LAYOUT-017: Snake WASM adapter must consume the platform provenance API"),
(wasm_runtime, 'PlatformFamily::Web', "DIST-LAYOUT-018: Snake WASM provenance must declare Web platform family"),
(wasm_runtime, 'ExecutionModel::Wasm', "DIST-LAYOUT-019: Snake WASM provenance must declare WASM execution"),
(wasm_runtime, 'RuntimeHost::Browser', "DIST-LAYOUT-020: Snake WASM provenance must declare browser host"),
)
for content, fragment, message in required_fragments:
if fragment not in content:
violations.append(message)
return violations
def main() -> int: def main() -> int:
"""Validate that every static distribution boundary exists.""" """Validate that every static distribution boundary exists."""
@@ -48,12 +145,15 @@ def main() -> int:
root = pathlib.Path(arguments.root).resolve() root = pathlib.Path(arguments.root).resolve()
missing: list[str] = [] missing: list[str] = []
forbidden_present: list[str] = [] forbidden_present: list[str] = []
contract_violations: list[str] = []
for relative in REQUIRED_PATHS: for relative in REQUIRED_PATHS:
if not (root / relative).exists(): if not (root / relative).exists():
missing.append(relative) missing.append(relative)
for relative in FORBIDDEN_PATHS: for relative in FORBIDDEN_PATHS:
if (root / relative).exists(): if (root / relative).exists():
forbidden_present.append(relative) forbidden_present.append(relative)
contract_violations.extend(audit_snake_web_shell(root))
contract_violations.extend(audit_snake_web_integration(root))
if missing: if missing:
for relative in missing: for relative in missing:
print(f"DIST-LAYOUT-001: missing required path: {relative}", file=sys.stderr) print(f"DIST-LAYOUT-001: missing required path: {relative}", file=sys.stderr)
@@ -64,6 +164,11 @@ def main() -> int:
print(f"DIST-LAYOUT-002: generated path must stay outside repository: {relative}", file=sys.stderr) print(f"DIST-LAYOUT-002: generated path must stay outside repository: {relative}", file=sys.stderr)
print(f"Distribution layout audit: {len(forbidden_present)} violation(s)", file=sys.stderr) print(f"Distribution layout audit: {len(forbidden_present)} violation(s)", file=sys.stderr)
return 1 return 1
if contract_violations:
for violation in contract_violations:
print(violation, file=sys.stderr)
print(f"Distribution layout audit: {len(contract_violations)} violation(s)", file=sys.stderr)
return 1
print(f"Distribution layout audit: clean ({len(REQUIRED_PATHS)} required path(s), {len(FORBIDDEN_PATHS)} forbidden path(s) absent)") print(f"Distribution layout audit: clean ({len(REQUIRED_PATHS)} required path(s), {len(FORBIDDEN_PATHS)} forbidden path(s) absent)")
return 0 return 0

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# file: scripts/audit_project_workspace_rules.py # file: scripts/audit_project_workspace_rules.py
# version: 5 # version: 6
"""Audit mechanically verifiable games.sasedev workspace boundaries.""" """Audit mechanically verifiable games.sasedev workspace boundaries."""
@@ -92,6 +92,18 @@ def main() -> int:
for java_path in sorted(root.rglob("*.java")): for java_path in sorted(root.rglob("*.java")):
if not java_path.is_relative_to(root / "Android"): if not java_path.is_relative_to(root / "Android"):
errors.append(f"GAME-ANDROID-001: Java source outside Android/: {java_path.relative_to(root).as_posix()}") errors.append(f"GAME-ANDROID-001: Java source outside Android/: {java_path.relative_to(root).as_posix()}")
changelog_text = (root / "CHANGELOG.md").read_text(encoding="utf-8")
stable_versions = set(re.findall(r"^## ([0-9]+\.[0-9]+\.[0-9]+)(?: \u2014.*)?$", changelog_text, re.MULTILINE))
roadmap_text = (root / "ROADMAP.md").read_text(encoding="utf-8")
roadmap_sections = re.split(r"(?=^## )", roadmap_text, flags=re.MULTILINE)
for section in roadmap_sections:
heading = re.match(r"^## ([0-9]+\.[0-9]+\.[0-9]+)(?: \u2014.*)?$", section.splitlines()[0] if section.splitlines() else "")
if heading is None or heading.group(1) not in stable_versions:
continue
for line in section.splitlines()[1:]:
if line.startswith("- ( )"):
errors.append(f"DOC-RMAP-010: stable version {heading.group(1)} retains planned scope: {line}")
if errors: if errors:
for error in errors: for error in errors:
print(error, file=sys.stderr) print(error, file=sys.stderr)

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# file: scripts/audit_rust_workspace_rules.py # file: scripts/audit_rust_workspace_rules.py
# version: 1 # version: 2
"""Run all Rust normalization and games.sasedev workspace audits.""" """Run all Rust normalization and games.sasedev workspace audits."""
@@ -20,9 +20,9 @@ def main() -> int:
arguments = parser.parse_args() arguments = parser.parse_args()
script_dir = pathlib.Path(__file__).resolve().parent script_dir = pathlib.Path(__file__).resolve().parent
commands = [ commands = [
["python3", str(script_dir / "audit_rust_general_rules.py"), "--root", arguments.root], [sys.executable, "-B", str(script_dir / "audit_rust_general_rules.py"), "--root", arguments.root],
["python3", str(script_dir / "audit_rust_export_completeness.py"), "--root", arguments.root], [sys.executable, "-B", str(script_dir / "audit_rust_export_completeness.py"), "--root", arguments.root],
["python3", str(script_dir / "audit_project_workspace_rules.py"), "--root", arguments.root], [sys.executable, "-B", str(script_dir / "audit_project_workspace_rules.py"), "--root", arguments.root],
] ]
for command in commands: for command in commands:
completed = subprocess.run(command, check=False) completed = subprocess.run(command, check=False)