diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..345666f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,43 @@ +# AGENTS.md + +Jeu d'entraînement aux tables de multiplication — Kotlin Multiplatform + Compose Multiplatform (Android, iOS, desktop JVM). UI, commits et docs sont en français. + +## Commandes + +```bash +./gradlew :sharedUI:jvmTest # tous les tests +./gradlew :sharedUI:jvmTest --tests "com.livrets.game.GameEngineTest" # une seule classe de test +./gradlew :desktopApp:run # app desktop (fenêtre 480×800) +./gradlew :androidApp:installDebug # appareil/émulateur connecté +./gradlew :androidApp:assembleDebug # APK debug +``` + +- Les tests vivent dans `sharedUI/src/commonTest` et ne s'exécutent que sur la cible JVM. +- Aucun lint/formatter/CI n'est configuré : la vérification passe par `:sharedUI:jvmTest` + compilation des modules touchés. +- iOS se construit via Xcode uniquement (`iosApp/iosApp.xcodeproj`, scheme `iosApp`) — pas de module Gradle pour l'app iOS ; `:sharedUI` produit le framework statique `SharedUI`. + +## Architecture + +- `sharedUI/` — toute l'app : `game/` (logique pure : `GameEngine`, `QuestionGenerator`, `GameConfig`…), `data/` (persistance JSON via kotlinx.serialization + okio), `ui/` (écrans Compose), `theme/`, `games/` (abstraction Play Jeux), `App.kt` (navigation par sealed interface `Screen`). +- `androidApp/` — hôte Android ; impl réelle Play Jeux dans `PlayGamesServices.kt`. +- `desktopApp/` — hôte JVM (`com.livrets.desktop.MainKt`) ; données dans `~/.livrets/`. +- `iosApp/` — hôte SwiftUI. + +Câblage à connaître : + +- IO fichiers : `expect val systemFileSystem` (okio) dans `sharedUI/src/commonMain/kotlin/com/livrets/data/SystemFileSystem.kt`, avec actuals android/jvm/ios ; les tests utilisent okio `FakeFileSystem`. +- Play Jeux : interface `GamesServices` (commonMain), défaut `NoopGamesServices`, injectée par `androidApp` ; tout échec (hors connexion, pas de config console) est silencieux par design — le jeu reste jouable. +- La logique testable est extraite de l'UI en commonMain/commonTest (ex. `ui/GameKeyMapping.kt`), plutôt que testée via l'UI. + +## Conventions + +- Commits : conventional commits en français (`feat:`, `docs:`, `fix:`). +- Nouvelle fonctionnalité : spec puis plan dans `docs/superpowers/specs/` et `docs/superpowers/plans/`, nommés `YYYY-MM-DD-[-design].md`. `docs/superpowers/` est committé ; `.superpowers/` est un répertoire de travail local (gitigné). +- Dépendances : uniquement via le version catalog `gradle/libs.versions.toml`. Chaîne : Kotlin 2.4.x, AGP 9.x, Compose Multiplatform 1.12, JVM 17 partout. + +## Pièges + +- Le build Android release échoue volontairement sans `androidApp/keystore.properties` (gitigné) — ne pas « corriger ». Publication et signature : voir README. +- Compose Multiplatform 1.12 ne distingue pas l'auto-répétition (`KeyEventType` n'a pas de repeat) : une touche maintenue répète ses événements ; les gardes (`MAX_ENTRY_LENGTH`, états hors `Playing` ignorés) en dépendent. Les chiffres sont mappés positionnellement (AZERTY sans Shift). +- Icônes launcher (Android/iOS/desktop) : régénérées depuis les SVG de `docs/branding/` via `docs/branding/generate-icons.sh` (prérequis : rsvg-convert, magick, python3). Ne pas éditer les PNG générés à la main. +- À chaque release Android : incrémenter `versionCode` dans `androidApp/build.gradle.kts`.