drawing/engine.ts | Imperative canvas engine — the facade and orchestrator (ADR-0004). Owns the <canvas>, the paper coordinate space, all pointer tracking (with the WebKit pen quirks and edge-swipe guards), and the whole public API; delegates ops/undo/simplification/export to the sibling modules below. Components connect via callbacks (onDrawSound, onUndoStateChange, etc.) and direct calls (setColor, setStrokeWidth, clearCanvas). |
drawing/strokeOps.ts | The engine's op vocabulary (StrokeOp, StrokeGroupCommand) and the single renderOp() renderer every surface shares, so live drawing and undo/resize/export replay are bit-identical (ADR-0033). |
drawing/undoHistory.ts | Undo history: the baseline raster + bounded command log + cumulative keyframes (ADR-0033/0035). Deliberately module-level so the drawing survives the engine's teardown/init across client-side navigation (ADR-0004). |
drawing/commandSimplify.ts | Commit-time simplification orchestration (ADR-0036): regroups a multi-touch command's interleaved ops per finger, splits continuous same-style runs, and reduces each through strokeSimplify.ts. Owns the tunables + the dev-sweep seam. Unit-tested. |
drawing/emptyScan.ts | Cheap blank-canvas detection on a small CPU-side scratch canvas (keeps willReadFrequently off the main canvas). |
drawing/exportDrawing.ts | Composes the shareable PNG (paper white + texture + strokes rebuilt from history + coloring-page overlay) and owns the paper-texture loader. |
drawing/strokeMath.ts | Pure gesture math (edge-swipe guards, pointer-resume detection, stroke speed) factored out of the engine for unit testing. |
drawing/strokeSimplify.ts | Pure stroke-simplification geometry (ADR-0036): RDP, corner/bulge analysis, and the sample/spline reconstruction pipelines run at commit. Unit-tested; commandSimplify.ts owns the tunables. |
drawing/paperView.ts | Pure paper-view geometry (ADR-0050): the upright contain-fit + center transform (matrix/inverse forms) that presents the rotation-locked "paper" — the space ops are recorded in — inside a rotated viewport. The engine owns the paper state and applies the view; DrawingCanvas.svelte reuses viewMatrix to position the overlay wrapper. |
drawing/overlay.ts | Manages the coloring-book overlay image rendered behind the drawing layer. |
drawing/saveOnDelete.ts | Saves the current drawing to the gallery before clearing, when the setting is enabled. |
drawing/screenshot.ts | Persists canvas PNGs (exported via engine.exportCanvasBlob): on native, saves to the photo library; on web, triggers a download. saveScreenshot also plays the polaroid animation. |
state/canvas.svelte.ts | Thin $state object bridging the imperative engine's callbacks (canUndo, canvasEmpty) into Svelte reactivity. |
state/colors.svelte.ts | Active color selection and the full palette. |
state/strokeWidth.svelte.ts | Stroke width levels and eraser size multiplier. |
state/tool.svelte.ts | Active tool (pen vs. eraser). |
state/settings.svelte.ts | User-configurable toggles (sounds, save-on-delete, screenshot button, coloring books, etc.) plus the appearance setting (light/dark/system), persisted via storage.ts. |
state/appearance.svelte.ts | Reactive resolved theme ('light' | 'dark'): the appearance setting combined with the live OS preference. For the few JS consumers of the resolved value (Notch Band paper color, export paper fill); CSS reads the app.css tokens instead. |
state/layout.svelte.ts | Viewport and orientation state. |
state/fullscreen.svelte.ts | Immersive-fullscreen support + active state and the toggle action, backing the Fullscreen Toggle button. Android web only; dismisses the mobile URL bar. |
state/network.svelte.ts | Online/offline state via @capacitor/network. Controls AI button visibility on native. |
state/install.svelte.ts | PWA install state (ADR-0039). Captures Chromium's beforeinstallprompt for one-tap install, falls back to iOS/Android guided hints; drives the Install Banner and the Parent Center Setup Guide section. Web-only; inert in the native shell. |
state/coloringBook.svelte.ts | Selected coloring book and page. |
state/books.ts | Static catalog of available coloring books and pages. |
actions/dragToClear.ts | Svelte action that implements the drag-to-clear gesture (pointer tracking, threshold detection, animations). Keeps all gesture logic out of the component. |
actions/modalDialog.svelte.ts | Svelte action wrapping the native <dialog> element with open/close state management. |
components/ | Svelte UI components. Each component owns its scoped styles. |
ai/styles.ts | AI style presets (names, prompts, icons) for the image-generation picker. |
api.ts | Single helper (apiUrl) that prefixes paths with __NATIVE_API_BASE__ on native, or leaves them relative on web. |
audio/drawingSound.ts | Plays pencil-scratch audio while drawing via Web Audio: MP3s are decoded once into AudioBuffers, each stroke plays a looping AudioBufferSourceNode through a GainNode, and pointer speed modulates the gain (ramped to avoid clicks). |
colorRing.ts | Computes the selection-ring color for palette swatches (slightly darker than the swatch, or lighter for very dark colors). |
hexPickerLayout.ts | The color picker's 9×9 palette (9 hue families × 9 shades) and its two static honeycomb arrangements — portrait (families as rows) and the landscape transpose (families as columns). ColorPicker.svelte renders both grids; CSS media queries pick one per orientation and trim positionally so the constrained axis drops shades, never hues (ADR-0048). |
platform.ts | isNative() and getPlatform() — reads the Capacitor global without importing @capacitor/core, so the module is safe to evaluate during SSR. |
theme.ts | Light/dark/system appearance plumbing: stamps data-theme on <html> (absent = system, so the prefers-color-scheme CSS in app.css drives it), keeps the theme-color meta on the resolved theme, and watches OS switches in system mode. The setting itself lives in state/settings.svelte.ts; the pre-paint stamp in app.html mirrors this convention. |
storage.ts | Dual-layer storage: synchronous reads from localStorage (fast, no async flash); on native, every write is also mirrored to Capacitor Preferences for durability. hydrateDurableStorage() restores settings on app launch. |
secureStorage.ts | Named client-held secrets (BYO Gemini key, admin session token): Keychain/Keystore via @aparajita/capacitor-secure-storage on native, AES-GCM-encrypted IndexedDB on web. |
orientation.ts | Device orientation detection utilities. |
pwa/updates.ts | Checks for PWA service worker updates and auto-applies them (with a reload) only while the canvas is blank; otherwise the update activates on next launch. |
server/ai/provider.ts | Server-only: the provider-agnostic AI seam (ADR-0047) — the AiImageProvider interface (prompt + drawing in; image | refusal | error out) and the active-provider export. The only AI module routes may import. |
server/ai/gemini.ts | Server-only: the Gemini AiImageProvider adapter — the sole runtime importer of @google/genai. Owns the model ids, the toddler-safety systemInstruction + safetySettings, and the call itself. |
server/ai/geminiSafety.ts | Server-only: pure classifier splitting a Gemini response/error into image vs safety refusal vs empty (ADR-0023). Standalone dependency-free module because the asset scripts import it via --experimental-strip-types. |
server/tokens.ts | Server-only: validates and manages AI access tokens (stored in Netlify Blobs). |
server/admin.ts | Server-only: admin auth core (secret check, derived session token, invite building) shared by the /admin page actions and the /api/admin/* endpoints. |
server/rateLimit.ts | Server-only: per-token rate limiting for the image generation endpoint. |
icons/ | SVG icon assets. npm run gen:icons generates components/icon-names.d.ts from them — the typed IconName union used by <Icon>. <Icon> inlines the raw SVG via {@html} (so the icon name lives only in a data-icon attribute, not the SVG), which means dynamic icons carry a hydration caveat — see .claude/rules/svelte.md. |
releases.json | Auto-generated from releases/*.md by npm run gen:releases; consumed by the What's New section in Parent Center (drill-in header "Updates"; dated release cards, no version numbers). |