Section 11
Engineering considerations
The Flutter colouring engine is the highest technical risk in the project. Everything in this section exists to manage that risk.
11.1 — Rendering approach
Use a single CustomPainter per canvas surface. Do not create one widget per region. The painter draws layers in order:
1. Unfilled region outlines (cached as a single Picture)
2. Filled regions (incrementally added; cached as a Picture per ~256 regions)
3. Region number labels (clipped to the current viewport)
4. Selection highlights and feedback
Filled‑region caches are rebuilt only when a layer crosses 256 new fills. The outline picture is built once on artwork open.
11.2 — Hit testing
screen tap
→ InteractiveViewer matrix-inverse → canvas coords
→ spatial-index lookup (grid of N × N cells over the canvas)
→ for each candidate region:
cheap bounds reject
precise Path.contains() test
→ on hit: check selected colour
→ if correct: set bit, schedule paint, persist
→ if wrong: gentle haptic + 80ms pulse on the correct colour swatch
A 32 × 32 grid spatial index is sufficient for MVP and trivial to build at artwork open. Upgrade to an R‑tree only if profiling demands it.
11.3 — Local‑first behaviour
- Artwork bundles persist under the app‑support directory and survive restarts.
- Progress writes are local‑first; the sync queue retries with exponential backoff.
- The app is fully playable offline for any artwork already downloaded.
- No interaction is blocked on a network round‑trip during colouring.
11.4 — Backend security
- Catalogue reads enforced by RLS (
is_published = true). - Premium downloads gated through a server‑side function — never by the client.
- Signed URLs expire in 15 minutes; the function re‑issues on demand for resumed downloads.
- Receipt validation is exclusively server‑side via Apple ASSN v2 and Google Play API.
- Admin endpoints check a role claim and run with the service role.
- Rate limits on download‑URL and sync‑progress functions.
11.5 — Children’s product considerations
- Age‑appropriate or no behavioural ads when
profiles.child_mode = true. - Parental gate (long‑press + arithmetic challenge) on purchases and external links.
- Privacy compliance (COPPA, UK Children’s Code, App Store / Google Play family policies).
- Clear in‑app reporting flow on every artwork detail screen.
- Safe account model — display name optional, no public profiles.
11.6 — Performance budget
| Metric | Target (mid‑range Android, ~2024 baseline) |
|---|---|
| Cold start to library | ≤ 1.8 s |
| Artwork open (cached) | ≤ 600 ms |
| Steady‑state frame time | ≤ 16 ms during pan / zoom |
| Tap → fill latency | ≤ 50 ms |
| Memory (large artwork loaded) | ≤ 220 MB resident |