MontessoriArc

Calm Coloring MVP Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Build the v1 Calm Coloring app — a two-screen (template gallery + tap-to-fill canvas) Compose Multiplatform app for Android and iOS, matching the reviewed UI mockup exactly, with print and a watermarked social-share flow.

Architecture: Single shared composeApp module (Kotlin Multiplatform + Compose Multiplatform, Skia-backed on both platforms). All UI, state, hit-testing, and navigation live in commonMain. Only PDF generation and the OS share sheet are expect/actual — everything else, including the shareable-image snapshot, is common code using GraphicsLayer.toImageBitmap(). Templates are hand-authored SVGs converted to Compose Path objects at build time; each region also gets a sampled hit-testing polygon so tap detection needs no platform-specific point-in-path API.

Tech Stack: Kotlin Multiplatform, Compose Multiplatform (Material 3), Navigation 3 (androidx.navigation3, common since CMP 1.10+), svg-to-compose (build-time Gradle task), androidx.lifecycle.ViewModel (KMP artifact), kotlin.test for common unit tests, Compose UI test (androidx.compose.ui.test.junit4) for one Android instrumented test.

Spec: calm-coloring-app-PRD.md (product requirements, §5–§9 especially) and design/calm-coloring-ui-mockup.html (approved interactive UI reference — exact palette, copy, and interaction to match).

Global Constraints


File Structure

BabyApp/
├── settings.gradle.kts
├── build.gradle.kts
├── gradle/libs.versions.toml
├── svg/                                                  # Task 2 — hand-authored source art
│   ├── sunny-day.svg, little-house.svg, apple-tree.svg, sleepy-cat.svg,
│   │   little-fish.svg, garden-flower.svg, sailboat.svg, balloon-ride.svg
├── iosApp/                                               # Task 0 — Xcode wrapper (KMP wizard output)
└── composeApp/
    ├── build.gradle.kts                                  # Task 0, 2
    └── src/
        ├── commonMain/kotlin/com/calmcoloring/app/
        │   ├── App.kt                                    # Task 5
        │   ├── theme/Color.kt, Type.kt, Theme.kt          # Task 1
        │   ├── content/generated/*.kt                     # Task 2 — svg-to-compose output, not hand-edited
        │   ├── content/TemplateCatalog.kt                 # Task 2
        │   ├── model/Template.kt, RegionSpec.kt            # Task 2
        │   ├── geometry/PointInPolygon.kt, PathSampling.kt # Task 3
        │   ├── ui/canvas/RegionCanvas.kt                   # Task 3
        │   ├── ui/coloring/ColoringViewModel.kt, ColoringScreen.kt  # Task 4
        │   ├── ui/gallery/GalleryScreen.kt                 # Task 5
        │   ├── navigation/Routes.kt                        # Task 5
        │   ├── platform/Printer.kt (expect)                # Task 6
        │   ├── ui/share/ParentGate.kt                      # Task 7
        │   ├── ui/share/ShareViewModel.kt, ShareSheet.kt   # Task 8
        │   └── platform/Sharer.kt (expect)                 # Task 8
        ├── commonTest/kotlin/com/calmcoloring/app/
        │   ├── geometry/PointInPolygonTest.kt              # Task 3
        │   ├── ui/coloring/ColoringViewModelTest.kt        # Task 4
        │   └── ui/share/ParentGateTest.kt                  # Task 7
        ├── androidMain/kotlin/com/calmcoloring/app/
        │   ├── MainActivity.kt                             # Task 0, revisited Task 9
        │   ├── platform/Printer.android.kt                 # Task 6
        │   └── platform/Sharer.android.kt                  # Task 8
        ├── androidInstrumentedTest/kotlin/com/calmcoloring/app/
        │   └── ui/coloring/ColoringScreenTest.kt           # Task 9
        └── iosMain/kotlin/com/calmcoloring/app/
            ├── MainViewController.kt                       # Task 0
            ├── platform/Printer.ios.kt                      # Task 6
            └── platform/Sharer.ios.kt                       # Task 8

Task 0: Toolchain Verification & Project Scaffold

Files:

Interfaces:


Task 1: Design Tokens (Theme)

Files:

Interfaces:


Task 2: Template Content Pipeline (SVG → Compose Path + hit polygon)

Files:

Interfaces:


Task 3: Core Interaction — RegionCanvas (hit-test + spring fill)

Files:

Interfaces:


Task 4: Coloring Screen (state, topbar, palette, reset)

Files:

Interfaces:


Files:

Interfaces:


Task 6: Print / Export (platform-native PDF from the same vector paths)

Files:

Interfaces:


Task 7: Parental Gate (resolves the mockup review’s open question)

Files:

Interfaces:

Decision made here (resolving the open question from the mockup): yes, gate it. A simple on-device arithmetic check — no network call, no data collection, nothing that conflicts with PRD §8 — is the lightest version of the “parental gate” pattern App/Play Store kids policies expect before any share/export flow leaves a children’s app. Print is not gated (it stays on-device, matching PRD §5.4); only the three share targets are.


Task 8: Share Sheet (watermark + WhatsApp/Instagram/More)

Files:

Interfaces:


Task 9: Testing, Performance & Store-Readiness Pass

Files:

Interfaces:


Self-Review

Spec coverage:

Placeholder scan: no TBD/TODO markers; the two “verify against current X” notes (Task 0 Step 1 CMP version check, Task 6 Step 3 iOS cinterop signatures) are explicit verification steps with a concrete action, not unresolved decisions — both are called out because PRD §6 and §11 themselves flag these as items needing a final check immediately before/during build, not because the plan is unsure what to build.

Type consistency: Template/RegionSpec (Task 2) → consumed identically in RegionCanvas (Task 3), ColoringViewModel/ColoringScreen (Task 4), GalleryScreen/App.kt (Task 5). ColoringViewModel.fills/selectedColor/onRegionTapped/reset (Task 4) match every call site in Task 4’s own ColoringScreen — no other task calls into ColoringViewModel directly. ImageBitmap produced by ColoringScreen’s graphicsLayer.toImageBitmap() (Task 4) flows unchanged into printArtwork (Task 6) and ShareSheet/shareArtwork (Task 8) — one snapshot mechanism, no duplicate capture path. ShareTarget (Task 8) is defined once and consumed by both Sharer.kt and ShareSheet.kt.


Plan complete and saved to docs/superpowers/plans/2026-09-13-calm-coloring-mvp.md. Two execution options:

1. Subagent-Driven (recommended) — I dispatch a fresh subagent per task, review between tasks, fast iteration.

2. Inline Execution — Execute tasks in this session using executing-plans, batch execution with checkpoints.

Which approach?