WonderTales — children story app with AAC support, Kotlin/Jetpack Compose
Find a file
hermes d7089e7a31
All checks were successful
Build Android / build (push) Successful in 2m34s
ci: re-run via runner pickup verification
2026-09-26 20:07:06 -07:00
.forgejo/workflows fix(ci): self-contained workflow — drop unreachable JS actions 2026-09-16 08:55:31 -07:00
project test: add AacDatabaseTest covering AAC DAOs and seed data 2026-09-14 09:19:14 -07:00
.gitignore gitignore: exclude GSD infrastructure directories 2026-09-14 09:19:14 -07:00
.pre-commit-config.yaml chore(pre-commit): document #12 evaluation — hooks already cover this repo 2026-09-14 09:19:14 -07:00
README.md fix: apply pre-commit auto-fixes to existing files (trailing whitespace) 2026-09-14 09:19:14 -07:00
SPEC.md init: Kimi swarm project setup 2026-05-07 21:22:23 -07:00
SPEC_M2.md init: Kimi swarm project setup 2026-05-07 21:22:23 -07:00
SPEC_M3.md init: Kimi swarm project setup 2026-05-07 21:22:23 -07:00

🌙 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

  1. File → Open → select wondertales/project directory
  2. Wait for Gradle sync (downloads dependencies automatically)
  3. Select a device/emulator (API 24+)
  4. Click Run ▶️

LLM API Key (M2 — Optional)

To enable live LLM narration generation instead of mock responses:

  1. Add your API key in the app via the Parent Studio (Template Manager → Settings)
  2. The app stores the key in encrypted DataStore
  3. Without an API key, the app uses MockLLMClient which 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)

  • InteractionEvent tracking for all UI interactions
  • SessionTracker with 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 10s
  • LLMClient interface + MockLLMClient for offline fallback
  • PromptEngine: template-based prompt assembly with mustache placeholders
  • NarrationGenerator: manages LLM calls with caching per template+context
  • SafetyFilter: block list, tone/length checks
  • TemplateRepository: 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
  • ContextualTileTray composable (WorldScreen bottom tray)
  • StoryTileOverlay composable (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)