Sprint 1 complete: hybrid Compose + LibGDX architecture building

Full AL-001 through AL-008 implementation: shared/ module with ModuleType
enum, GameHost routing, StylusInputBridge, LineCorridorScreen with live
stroke rendering, LineScore (straightness + anglePrecision), score returned
to Compose hub via ActivityResult. Fixes LineScore field mismatch
(pressureConsistency → anglePrecision) caught during AL-009 build check.
Adds .gitignore and handoff notes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-08 19:21:48 -06:00
parent 24d78786db
commit ac81ec51f4
39 changed files with 1797 additions and 41 deletions

125
HANDOFF_2026-05-05.md Normal file
View File

@@ -0,0 +1,125 @@
# Agent Handoff — May 5, 2026
## Session Summary
Full rearchitecture from pure LibGDX to hybrid Compose + LibGDX. Sprint 0 (foundation) and Sprint 1 (Line Corridor MVP) both completed in this session. APK builds successfully.
---
## What Was Accomplished
### Architecture (Sprint 0 — all done)
- Created `shared/` pure-Kotlin module containing `ModuleType` enum (LINE_CORRIDOR, PRESSURE_RAMP, CURVE_SCULPTOR, VECTOR_SNAP)
- Created `core/GameHost.kt` — routes by ModuleType, exposes `onSessionComplete` callback
- Created `core/input/StylusFrame.kt` + `StylusInputBridge.kt` — AtomicReference bridge, GL-thread safe
- Created `core/modules/LineCorridorScreen.kt` + `LineScore.kt`
- Created `core/PlaceholderModuleScreen.kt`
- Created `android/MainActivity.kt` — ComponentActivity + Compose
- Created `android/GameActivity.kt` — AndroidApplication, reads ModuleType from Intent, sets OnTouchListener on LibGDX view
- Created full Compose navigation: `ArtLegendApp`, `HubScreen`, `ModuleDetailScreen`, `ProgressScreen`, `SettingsScreen`
- Created dark Material3 theme (violet #7B2FBE / cyan #00E5FF)
- Updated `AndroidManifest.xml`: MainActivity as LAUNCHER, GameActivity as landscape fullscreen non-exported
- Deleted orphaned `AndroidLauncher.kt`, `ArtLegend.kt`, `styles.xml`
### Line Corridor (Sprint 1 — all done)
- `LineCorridorScreen` renders two cyan corridor walls + dashed centerline at random ±25° angle via ShapeRenderer
- Stroke captured live from StylusInputBridge, rendered in yellow with pressure-driven alpha
- `isDown: Boolean` added to `StylusFrame`; DOWN/UP edge detection for clean session start/stop
- Android Y flipped to LibGDX coordinate space in `processInput()`
- `LineScore` computed: straightness (RMS perpendicular deviation) + pressureConsistency (RMS from 0.5)
- Full result pipeline: GL thread → `runOnUiThread { setResult + finish() }``ActivityResultLauncher``lastScore` Compose state → `ScoreCard` on `ModuleDetailScreen`
- "Start Training" button changes to "Train Again" after first session
### Build environment fixed
- Added `gradlew` script (copied from whisper.cpp) + `gradle-wrapper.jar`
- Added Foojay toolchain resolver plugin to `settings.gradle.kts` (auto-downloads JDK 17)
- Installed Android SDK via `brew install --cask android-commandlinetools`
- SDK root: `/opt/homebrew/share/android-commandlinetools`
- Installed: `platforms;android-34`, `build-tools;34.0.0`, `platform-tools`
- `local.properties` created: `sdk.dir=/opt/homebrew/share/android-commandlinetools`
- Fixed `copyAndroidNatives` task — now extracts each `.so` into its ABI subdirectory (`libs/arm64-v8a/`, etc.)
- Symlink at `/opt/homebrew/opt/jbr-home` → IntelliJ JBR (used for sdkmanager)
### Build command (verified working)
```bash
cd /Users/blindmouse/artlegend
JAVA_HOME="/Users/blindmouse/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home" ./gradlew :android:assembleDebug
```
APK output: `android/build/outputs/apk/debug/android-debug.apk`
---
## Current State
**SPRINT.md tickets:**
- AL-001 through AL-008: DONE
- AL-009 (on-device smoke test): not done — device needed
**Three deprecation warnings** (non-blocking, cosmetic):
- `Icons.Default.ArrowBack` deprecated → use `Icons.AutoMirrored.Filled.ArrowBack`
- Affects: `ModuleDetailScreen.kt`, `ProgressScreen.kt`, `SettingsScreen.kt`
---
## Next Steps (Priority Order)
### Immediate
1. **AL-009 on-device test** — install APK, verify:
- Hub shows 4 module cards
- Tap → ModuleDetail → "Start Training" → LibGDX corridor renders
- S-Pen stroke captured, score returned on finish
- Check logcat: `adb logcat -s LineCorridor GameActivity`
2. **Fix ArrowBack deprecation** (3 files, 1-line change each):
```kotlin
// Old
Icons.Default.ArrowBack
// New
Icons.AutoMirrored.Filled.ArrowBack
// Also add import:
import androidx.compose.material.icons.automirrored.filled.ArrowBack
```
### Phase 1 (ROADMAP)
3. Corridor difficulty progression (narrowing half-width per session)
4. Session summary screen (score + streak counter)
5. Local score persistence (DataStore or Room)
6. Progress screen populated with real data (last 7 sessions chart)
### Phase 2
7. Pressure Ramp module
---
## Key File Locations
```
artlegend/
shared/src/main/kotlin/com/artlegend/shared/ModuleType.kt
core/src/main/kotlin/com/artlegend/
GameHost.kt
PlaceholderModuleScreen.kt
input/StylusFrame.kt
input/StylusInputBridge.kt
modules/LineCorridorScreen.kt
modules/LineScore.kt
android/src/main/kotlin/com/artlegend/
MainActivity.kt
GameActivity.kt
ui/ArtLegendApp.kt
ui/theme/ArtLegendTheme.kt
ui/screens/{Hub,ModuleDetail,Progress,Settings}Screen.kt
android/src/main/res/values/themes.xml
android/src/main/AndroidManifest.xml
local.properties ← sdk.dir, gitignored
settings.gradle.kts ← includes foojay toolchain resolver
SPRINT.md, ROADMAP.md, README.md
```
## Gotchas for Next Agent
- **sdkmanager requires** `JAVA_HOME=/opt/homebrew/opt/jbr-home SKIP_JDK_VERSION_CHECK=1` — the JBR version string breaks the integer test in the wrapper script
- **StylusInputBridge** is last-write-wins (AtomicReference.set), not a queue — fine for 60fps render but means missed frames between renders are dropped
- **Y-coordinate flip**: StylusFrame stores raw Android Y (top=0); LineCorridorScreen flips it to LibGDX space (bottom=0) in `processInput()`
- **GameActivity.onSessionComplete** is called on the GL thread — always `runOnUiThread {}` before `setResult/finish`
- The `natives-desktop` JAR is skipped by `copyAndroidNatives` (not in the `validAbis` set) — this is intentional