|
|
||
|---|---|---|
| .forgejo/workflows | ||
| project | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| README.md | ||
| SPEC.md | ||
| SPEC_M2.md | ||
| SPEC_M3.md | ||
🌙 WonderTales — Android Milestone 2
A living illustrated companion for children — an offline-first Android app built with Kotlin and Jetpack Compose that combines story exploration, AAC (Augmentative and Alternative Communication) support, audio narration, adaptive intelligence, and parental controls.
Current Milestone: M2 — Quiet Intelligence Milestone 2 adds behavior-aware prompting, LLM-powered story variation, session analytics, and parent transparency. See SPEC_M2.md for the full M2 specification.
✨ Features
📖 Story World
- 6 hand-crafted scenes: Forest Glade, Oak Grove, Moon Clearing, Starry Path, Pip's Hill, Sunny Meadow — each with unique visual themes (colors, objects, characters)
- 3 companion characters: Luna (moon rabbit), Oak (wise tree), Pip (curious fox) — each with greetings, dialogue, and associated AAC tiles
- 60+ interactive objects (10 per scene) — tap, drag, or speak to them for narration reactions
- Scene navigation via visible exits (doors/paths)
📚 Story Library
- 10 starter stories: classic fables (Lion & Mouse, Fox & Grapes, Tortoise & Hare, Boy Who Cried Wolf) + original companion tales (Luna's Moon Garden, Oak's Lost Acorn, Pip's First Adventure, A Quiet Walk, Two Paths, The Helpful Friend)
- Branching narrative: choose-your-path story nodes with AAC tile labels
- Audio narration via TTS (Text-to-Speech) per node
- Story variation engine (M2): on 2nd+ visit, story text varies via approved LLM templates
🗣️ AAC Tile Board
- 25 default tiles across 6 categories: People, Places, Actions, Emotions, Needs, Choices
- Visual tiles with category-colored backgrounds, icons, and labels (minimum 80dp touch targets)
- Tap to speak via TTS with phrase expansion
- Category tabs for filtering
- Context-aware: tiles adapt based on current scene or story
🎯 Contextual AAC (M3)
- Scene-tile mappings: each scene exposes its 4–7 most relevant tiles with scene-specific reactions
- Story-node tile mappings: story nodes offer tile choices for in-context expression
- Contextual Tile Tray: bottom tray in WorldScene shows top-4 relevant tiles
- Story Tile Overlay: horizontal tile chips above story choice buttons
- Tile expansions: context-aware phrase expansions — tiles say different things depending on scene, story, or general context
- Tile set import/export: backup, share, or restore custom tile sets as JSON
🧠 Adaptive Intelligence (M2)
- Session tracking: every tap, scene entry/exit, story advance, and tile tap is logged as an
InteractionEvent - Hesitation detection: fires when child stays >15s without interaction
- Behavior inference engine (every 30s): computes 5 behavioral scores — curiosity, comfort, hesitation, frustration, seeking
- Behavior-driven prompt engine: decision tree checks rate limits (max 3/session, 2min interval, 10/day) and triggers light prompts, story branches, or communication bridges based on behavior
- LLM narration generation: parent-approved templates with mustache-style placeholders (
{{childName}},{{sceneName}},{{behavior}}) generate scene/character/story variants - Safety filter: blocks urgency, fear, block-listed topics, and over-long outputs
- Graceful offline fallback: all tracking and prompts work offline; LLM falls back to scripted content
👨👩👦 Parent Studio (PIN-protected)
- People Manager: add/edit people (name, relation, photo, voice note)
- Places Manager: add/edit places (name, description, photo)
- Tile Mapper: map custom tiles to phrases, assign colors and categories
- Story Editor: simple text editor for custom stories with choices
- Profile Settings: child name, age group, input mode (tap/tile/speech/mixed), AAC layout
- Content Review: activity log of what was explored
- Prompt Review (M2): chronological list of all prompt decisions with trigger, reason, LLM input/output
- Template Manager (M2): CRUD for narration templates with preview and approval toggles
- Behavior Log (M2): visual timeline of 5 behavior scores with raw event list
- Expansion Manager (M3): edit context-specific tile expansions per tile
- Mapping Editor (M3): two tabs — scene mappings and story mappings with relevance sliders
- Tile Import/Export (M3): export/import tile sets as JSON
🏗️ Architecture
Tech Stack
| Component | Technology |
|---|---|
| Language | Kotlin 1.9.22 |
| UI Framework | Jetpack Compose (BOM 2024.02.00) + Material3 |
| Navigation | Jetpack Navigation Compose |
| Persistence | Room (SQLite) + DataStore Preferences |
| Dependency Injection | Hilt (2.50) |
| Audio | Android MediaPlayer + TextToSpeech (TTS) |
| Async | Kotlin Coroutines + Flow |
| LLM Client | Retrofit + OkHttp (interface + mock implementation) |
| Build | Gradle 8.4 + Android Gradle Plugin 8.2.2 |
Module Structure
com.wondertales/
├── MainActivity.kt # @AndroidEntryPoint, sets up Compose
├── WonderTalesApp.kt # @HiltAndroidApp Application class
├── WonderTalesAppContent.kt # Scaffold + BottomNavBar + NavHost
├── data/
│ ├── model/ # Data classes: Scene, Character, Story, Tile, etc.
│ ├── local/db/ # Room entities, DAOs, Database class
│ ├── repository/ # Repository implementations
│ ├── SeedData.kt # M1 seed data (scenes, stories, tiles, characters)
│ └── AacSeedData.kt # M3 seed data (scene-tile mappings, expansions)
├── ui/
│ ├── theme/ # Color, Typography, Shape (WonderTalesTheme)
│ ├── screens/
│ │ ├── world/ # WorldScreen — scene navigation, objects, characters
│ │ ├── stories/ # StoriesScreen + StoryReaderScreen
│ │ ├── talk/ # TalkScreen (contextual AAC tile board)
│ │ ├── quests/ # QuestsScreen
│ │ └── parent/ # All Parent Studio screens (M1, M2, M3)
│ ├── components/ # Reusable: TileButton, CharacterAvatar, etc.
│ │ ├── aac/ # ContextualTileTray, StoryTileOverlay (M3)
│ │ └── prompts/ # PromptBanner composable (M2)
│ └── navigation/ # NavHost, routes, BottomNavBar, ParentNav
├── audio/ # AudioManager, NarrationEngine, TTS wrapper
├── analytics/ # SessionTracker, BehaviorEngine, InteractionEvent (M2)
├── llm/ # LLMClient, PromptEngine, NarrationGenerator,
│ # SafetyFilter, TemplateRepository, MockLLMClient,
│ # StoryVariationEngine, NarrationTemplate (M2)
├── prompts/ # PromptScheduler, PromptDecision, RateLimits (M2)
├── aac/ # SceneTileMapping, TileExpansion, TileSet, etc. (M3)
├── viewmodel/ # WorldViewModel, TalkViewModel, StoryViewModel,
│ # ParentViewModel
└── di/ # AppModule, DatabaseModule (Hilt providers)
Data Flow
UI (Composable) → ViewModel → Repository → Room DAO / DataStore
↕
SeedData (pre-populated)
UI Events → SessionTracker → BehaviorEngine (30s) → PromptScheduler → PromptBanner
↕
LLMClient / MockLLMClient ← PromptEngine ← TemplateRepository
Navigation
Bottom navigation with 5 destinations: World (home) → Stories → Talk (AAC) → Quests → Parent (PIN-gated).
WonderTalesNavHost uses Jetpack Navigation Compose with routes for each screen. The Parent Studio has its own sub-navigation graph (parentNavGraph) managing all parent screens. Talk screen accepts optional sceneId and storyId context parameters.
🚀 Build & Setup
Prerequisites
- Android Studio Hedgehog (2023.1.1) or later
- JDK 17
- Android SDK 34
- Gradle 8.4 (wrapper included)
Clone & Build
# Clone the repository
git clone <repository-url>
cd wondertales/project
# Build the project
./gradlew assembleDebug
# Run on emulator/device
./gradlew installDebug
Open in Android Studio
- File → Open → select
wondertales/projectdirectory - Wait for Gradle sync (downloads dependencies automatically)
- Select a device/emulator (API 24+)
- Click Run ▶️
LLM API Key (M2 — Optional)
To enable live LLM narration generation instead of mock responses:
- Add your API key in the app via the Parent Studio (Template Manager → Settings)
- The app stores the key in encrypted DataStore
- Without an API key, the app uses
MockLLMClientwhich generates contextual text locally
Security: No hardcoded API keys in source. API keys are loaded from DataStore at runtime.
Configuration
- minSdk: 24 (Android 7.0)
- targetSdk: 34 (Android 14)
- compileSdk: 34
- Fully offline-capable; no internet required for core features
- LLM features degrade gracefully to scripted content when offline
📦 Dependencies
| Dependency | Version | Purpose |
|---|---|---|
| AndroidX Core KTX | 1.12.0 | Core Android utilities |
| Lifecycle Runtime KTX | 2.7.0 | ViewModel + lifecycle scope |
| Activity Compose | 1.8.2 | Compose integration with Activity |
| Compose BOM | 2024.02.00 | UI framework |
| Material3 | (BOM) | Material Design 3 components |
| Navigation Compose | 2.7.7 | Screen navigation |
| ViewModel Compose | 2.7.0 | ViewModel in Compose |
| Room Runtime/Compiler/KTX | 2.6.1 | Local SQLite database |
| DataStore Preferences | 1.0.0 | Key-value settings storage |
| Hilt Android/Compiler | 2.50 | Dependency injection |
| Hilt Navigation Compose | 1.1.0 | Hilt + Nav integration |
| Material Icons Extended | (BOM) | Icon library |
| JUnit | 4.13.2 | Unit testing |
| Espresso | 3.5.1 | UI testing |
🗺️ Project Structure
wondertales/
├── SPEC.md # Milestone 1 full specification
├── SPEC_M2.md # Milestone 2 full specification
├── SPEC_M3.md # Milestone 3 full specification
├── README.md # This file
├── project/
│ ├── build.gradle.kts # Root build file (AGP 8.2.2, Kotlin 1.9.22, Hilt 2.50)
│ ├── settings.gradle.kts # RootProject: "WonderTales"
│ ├── gradle.properties # JVM args, AndroidX, Jetifier
│ ├── gradlew / gradlew.bat # Gradle wrapper
│ ├── gradle/wrapper/ # Wrapper config (Gradle 8.4)
│ ├── local.properties # SDK path (local, not committed)
│ └── app/
│ ├── build.gradle.kts # App-level build config
│ └── src/
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/com/wondertales/ # Source code (see module structure above)
│ │ └── res/ # Resources (drawables, mipmaps, values)
│ ├── test/ # Unit tests
│ └── androidTest/ # Instrumentation tests
🎯 Milestone Tracking
Milestone 1 — Core App (Complete)
- Project setup with Gradle, Hilt, Room, Navigation Compose
- Theme: warm palette (cream, terracotta, sage, lavender, gold)
- 6 world scenes with 60+ interactive objects and 3 characters
- 10 stories with branching narrative nodes
- 25 AAC tiles across 6 categories with TTS
- Audio system with MediaPlayer + TTS
- Parent Studio with PIN, people/places/tile/story editors
- Fully offline, fully local
- Seed data for all content
Milestone 2 — Quiet Intelligence (Current)
InteractionEventtracking for all UI interactionsSessionTrackerwith hesitation detection (15s idle)BehaviorEngine: 5-score inference (curiosity, comfort, hesitation, frustration, seeking)PromptScheduler: decision tree with rate limits (3/session, 2min interval, 10/day)PromptBanner: subtle, dismissible, auto-hide after 10sLLMClientinterface +MockLLMClientfor offline fallbackPromptEngine: template-based prompt assembly with mustache placeholdersNarrationGenerator: manages LLM calls with caching per template+contextSafetyFilter: block list, tone/length checksTemplateRepository: 14 parent-approved narration templates (scene, story, greeting, prompt, social)StoryVariationEngine: variant requests on 2nd+ story visit- Parent Studio: PromptReview, TemplateManager, BehaviorLog screens
- Hilt modules wired for all M2 dependencies
Milestone 3 — Contextual AAC (Partial/Planned)
- Domain models:
SceneTileMapping,StoryNodeTileMapping,TileExpansion,TileSet - Room entities and DAOs for all M3 tables
- Repositories:
TileMappingRepository,TileExpansionRepository,TileSetRepository ContextualTileTraycomposable (WorldScreen bottom tray)StoryTileOverlaycomposable (StoryReaderScreen tile chips)- Context-aware TalkScreen (accepts
sceneId/storyId) - Parent Studio screens: MappingEditor, ExpansionManager, TileImportScreen
- Seed data: 35+ scene-tile mappings, 15+ story-node mappings, 25+ expansions
- Full integration with WorldViewModel/StoryViewModel (partial)
- Automated tests for contextual resolution
🧪 Testing
# Run unit tests
./gradlew test
# Run instrumented tests (requires device/emulator)
./gradlew connectedAndroidTest
Test Coverage
- Unit tests: Repository logic, behavior engine computation, prompt decision tree, safety filter
- Instrumentation tests: UI flows (navigation, tile board, story reader, parent studio)
📐 Design Language
- Palette: Warm, low-saturation tones. Soft cream (
#FFF8F0), warm terracotta (#D4846A), sage green (#8FAE8D), soft lavender (#B8A9C9), golden yellow (#E8C547) - Typography: Rounded, friendly fonts. Large text for young readers
- Shapes: Rounded corners (16dp+), soft shadows, card-based layouts
- Accessibility: Minimum 48dp touch targets, high contrast mode option, always-visible audio feedback
- Per-scene theming: Each scene has its own background color (HomeCream, GardenGreen, ForestDarkGreen, VillageBrown, BedtimeBlue)
📄 License
This project is an educational/demonstration Android application.
🤝 Contributing
Contributions are welcome! Please ensure:
- All features work fully offline (no required network calls)
- LLM features degrade gracefully
- Content is child-appropriate and passes the safety filter
- Code follows the existing architecture (MVVM with Clean-ish layers)