Files
artlegend/HANDOFF_2026-05-05.md
bill ac81ec51f4 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>
2026-05-08 19:21:48 -06:00

5.6 KiB

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() }ActivityResultLauncherlastScore 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)

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):

    // Old
    Icons.Default.ArrowBack
    // New
    Icons.AutoMirrored.Filled.ArrowBack
    // Also add import:
    import androidx.compose.material.icons.automirrored.filled.ArrowBack
    

Phase 1 (ROADMAP)

  1. Corridor difficulty progression (narrowing half-width per session)
  2. Session summary screen (score + streak counter)
  3. Local score persistence (DataStore or Room)
  4. Progress screen populated with real data (last 7 sessions chart)

Phase 2

  1. 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