# ArtLegend — Current Sprint **Sprint goal:** Hybrid architecture end-to-end. Compose hub → LibGDX `LineCorridorScreen` with live stylus pressure data. --- ## Tickets ### AL-001 — shared/ module compiles [DONE] - `shared/build.gradle.kts` created (pure Kotlin JVM) - `ModuleType.kt` created with LINE_CORRIDOR, PRESSURE_RAMP, CURVE_SCULPTOR, VECTOR_SNAP - `settings.gradle.kts` updated to include `"shared"` ### AL-002 — core/ restructured [DONE] - `GameHost.kt` replaces `ArtLegend.kt` — accepts `ModuleType`, routes to correct Screen - `PlaceholderModuleScreen.kt` — stub Screen for unimplemented modules - `input/StylusFrame.kt` — data class (x, y, pressure, tiltRad, orientRad, isStylus) - `input/StylusInputBridge.kt` — AtomicReference bridge (GL-thread safe) - `modules/LineCorridorScreen.kt` — skeleton (dark background, reads bridge) - `core/build.gradle.kts` updated with `:shared` dependency ### AL-003 — Compose added to android/ [DONE] - `android/build.gradle.kts` updated: `buildFeatures { compose = true }`, Compose BOM 2024.09.00, navigation-compose, activity-compose, lifecycle - `gradle.properties` updated with compose versions ### AL-004 — MainActivity + Compose hub [DONE] - `MainActivity.kt` created — ComponentActivity, sets Compose content - `ui/theme/ArtLegendTheme.kt` — dark Material3 theme, violet/cyan accents - `ui/ArtLegendApp.kt` — NavHost with 4 routes (hub, detail/{moduleType}, progress, settings) - `ui/screens/HubScreen.kt` — LazyVerticalGrid of 4 module cards - `ui/screens/ModuleDetailScreen.kt` — module info + "Start Training" button - `ui/screens/ProgressScreen.kt` — stub - `ui/screens/SettingsScreen.kt` — stub - `res/values/themes.xml` — Theme.ArtLegend (Material3) + Theme.ArtLegend.Fullscreen - `AndroidManifest.xml` updated — MainActivity as LAUNCHER, GameActivity registered ### AL-005 — GameActivity + stylus bridge [DONE] - `GameActivity.kt` created — AndroidApplication, reads ModuleType from Intent - Stylus OnTouchListener set on LibGDX view post-initialization - `handleStylusEvent()` extracts pressure/tilt/orient, posts StylusFrame to bridge - Logs `pressure` + `isStylus` to logcat for verification ### AL-006 — LineCorridorScreen renders corridor [DONE] - ShapeRenderer corridor: two cyan walls + dashed centerline at random ±25° angle - Stroke captured per-frame from StylusInputBridge; yellow alpha stroke rendered live - `isDown` field added to StylusFrame; DOWN/UP edges detected for clean start/stop - Y-coordinate flipped (Android top-left → LibGDX bottom-left) ### AL-007 — Score calculation [DONE] - `LineScore(straightness, pressureConsistency, overall)` data class in core/modules - RMS perpendicular deviation from centerline → straightness (0..1) - RMS pressure deviation from 0.5 target → pressureConsistency (0..1) - overall = straightness×0.6 + pressureConsistency×0.4 - Score logged to logcat on stylus lift ### AL-008 — Score returned to hub [DONE] - `GameHost.onSessionComplete: ((LineScore) -> Unit)?` wired by GameActivity - GL thread score callback → `runOnUiThread { setResult + finish() }` - `MainActivity.gameResultLauncher` (ActivityResultContracts.StartActivityForResult) - `lastScore: LineScore?` state flows through ArtLegendApp → ModuleDetailScreen - ScoreCard shows Overall / Line / Pressure % on return; button changes to "Train Again" ### AL-009 — End-to-end smoke test [TODO] - `./gradlew :android:assembleDebug` passes - App launches to Compose hub showing 4 module cards - Tap card → ModuleDetail with "Start Training" button - Tap "Start Training" → LibGDX renders dark background with corridor - Stylus pressure values visible in logcat --- ## Blocked _Nothing blocked currently._ ## Out of Scope This Sprint - Local score persistence (Phase 1) - Difficulty progression - In-app purchases - Cloud sync