bill 2b208aff7e Sprint 2 head-start: Room persistence, ProgressViewModel, ProgressScreen
- Room DB (ArtLegendDatabase, SessionDao, SessionEntity) wired up
- SessionRepository saves scores and queries last 7 sessions per module
- ProgressViewModel exposes sessions as StateFlow
- ProgressScreen replaced with real bar chart + session history list
- MainActivity now persists each game result to Room on return
- build.gradle.kts + gradle.properties: KSP and Room 2.6.1 added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 22:53:42 -06:00

ArtLegend

S-Pen mastery training for digital artists — gamified, modular, precision-first.

ArtLegend is an Android training app that turns S-Pen skill-building into a structured game. Each module isolates one drawing skill (pressure control, line confidence, curve accuracy, vector precision) and drills it with real-time feedback, scoring, and progressive difficulty.


Vision

Most artists know what they want to draw but lack the muscle memory to execute it. ArtLegend bridges that gap by making practice deliberate, measurable, and satisfying.

Each module isolates a specific physical skill. The first is Corridor Scroll — a Guitar Hero-style scrolling corridor the player must track with their stylus, training spatial accuracy and confident stroke coverage across all angles and speeds. Later modules build toward exercises where the player's accumulated strokes form actual drawings, so the skills trained are directly transferable to real artwork.

The long-term goal: a modular curriculum where artists buy skill packs, track their growth over weeks, and build real hand-eye coordination for professional digital work.


Module List

See MODULES.md for full gameplay design, scoring rules, and difficulty variables for each module.

Module Skill Trained Status
Corridor Scroll Sustained stroke control inside a scrolling, direction-changing corridor In Progress
Stroke-to-Drawing Guided strokes that compose a picture; teaches deliberate mark-making Planned
Pressure Ramp Dynamic stroke weight control against a target pressure curve Planned
Curve Sculptor Smooth bezier curve shaping Planned
Vector Snap Precision endpoint targeting Planned

Architecture

MainActivity (ComponentActivity + Compose)
  └── Navigation: Hub → ModuleDetail → Progress → Settings
        |
        | Intent (puts ModuleType enum name)
        v
GameActivity (AndroidApplication / LibGDX)
  └── GameHost : Game() → routes to correct Screen by ModuleType
        └── LineCorridorScreen (first real module)
              └── StylusInputBridge (AtomicReference — bridges UI thread → GL thread)

Key Design Decisions

  • Compose for navigation/UI — Hub, progress, settings, and module-detail screens benefit from standard Android UI patterns (adaptive layout, accessibility, back stack).
  • LibGDX for game rendering — Frame-accurate rendering, direct OpenGL access, and fine-grained input timing for each training module.
  • Separate Activities — Clean boundary: MainActivity owns Compose state; GameActivity owns the LibGDX lifecycle. Intent extras carry the ModuleType.
  • shared/ module — Zero-dependency pure-Kotlin module that holds the ModuleType enum. Both Compose and LibGDX layers depend on it; neither depends on the other.
  • StylusInputBridgeAtomicReference<StylusFrame?> lets the UI thread post stylus data (pressure, tilt, orientation) without locking the GL thread.

Tech Stack

Layer Technology
UI / Navigation Compose Multiplatform, Material3, Navigation Compose
Game rendering LibGDX 1.12.1 (OpenGL ES)
Language Kotlin 1.9.23
Build Gradle 8.x (Kotlin DSL)
Min SDK 26 (Android 8.0)
Target SDK 34 (Android 14)
Primary device Samsung Galaxy Tab S-series with S-Pen

Build Instructions

Prerequisites

  • Android Studio Hedgehog or later
  • Android SDK 34
  • JDK 17

Build debug APK

./gradlew :android:assembleDebug

Install on device

./gradlew :android:installDebug

Verify compilation

./gradlew :shared:compileKotlin
./gradlew :core:compileKotlin
./gradlew :android:compileDebugKotlin

Stylus Setup

ArtLegend reads S-Pen input via Android's MotionEvent API in GameActivity:

// Captured per frame in GameActivity.handleStylusEvent()
val pressure    = event.pressure                          // 0.0  1.0
val tiltRad     = event.getAxisValue(MotionEvent.AXIS_TILT)
val orientRad   = event.getAxisValue(MotionEvent.AXIS_ORIENTATION)
val isStylus    = event.getToolType(0) == TOOL_TYPE_STYLUS

The StylusInputBridge (an AtomicReference<StylusFrame?>) carries this data thread-safely into the LibGDX GL thread where each module's render() can consume it without locking.

The bridge posts every touch event but does not queue them — only the latest frame is visible to the GL thread. This matches the rendering cadence (60 fps) without unbounded buffering.


How to Add a New Module

  1. Add an entry to ModuleType in shared/src/main/kotlin/com/artlegend/shared/ModuleType.kt
  2. Create core/src/main/kotlin/com/artlegend/modules/YourModuleScreen.kt implementing Screen
  3. Add a when branch in GameHost.create() routing to your new screen
  4. Add a ModuleCard entry in HubScreen.kt (title + description)
  5. Add a description string in ModuleDetailScreen.kt's when block

Business / Licensing Model

ArtLegend is designed around a modular content model:

  • Free core: Line Corridor + basic progress tracking
  • Skill packs (one-time purchase): Additional modules sold individually or as bundles (e.g., "Ink Fundamentals Pack" = Pressure Ramp + Curve Sculptor)
  • Pro subscription: Unlocks all current + future modules, cloud sync, detailed analytics
  • Institutional licensing: Studio / school licenses for group training dashboards

The ModuleType enum is the extension point — new modules ship as app updates and are unlocked via in-app purchase entitlements checked before launching GameActivity.

Description
Stylus training action game — pressure, path, and speed exercises with partner white-label support
Readme 449 KiB
Languages
Kotlin 100%