│ MainMenu.unity │ Spine mascot looping idle. Single "Play" button.
│ │ Tap → SetLastOpened(null) → load Colorbook
└────────┬────────┘
│ Scenes.LoadAsync("Colorbook")
▼
┌─────────────────┐ ◀─────────────────────────┐
│ Colorbook.unity │ Catalog grid of drawings. │ (back from Gameplay returns here;
│ │ Each cell shows: cached │ catalog cells refresh with cached
│ │ user thumbnail if any, │ thumbnails written during gameplay)
│ │ else DefaultThumbnail. │
│ │ Tap cell → │
│ │ Progression.SetLastOpened(id) → load Gameplay
└────────┬────────┘ │
│ Scenes.LoadAsync("Gameplay") │
▼ │
┌─────────────────┐ │
│ Gameplay.unity │ Active drawing experience │
│ │ │
│ Reads Progression.LastOpenedTemplateId │
│ Reads Progression.GetProgress(id) → null, │
│ Building, or Coloring │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ GameplayState.Building │ │
│ │ • Pieces in tray, drag → snap │ │
│ │ • Pre-snapped pieces auto-locked │ │
│ │ if resuming │ │
│ │ • Back tap → save partial state ─┼────┤
│ │ + load Colorbook │ │
│ └────────────────┬─────────────────────┘ │
│ │ ShapeAssembledSignal │
│ │ (save phase + thumb) │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ GameplayState.Coloring │ │
│ │ • Tap color → tap region → paint │ │
│ │ • Undo / Redo any time │ │
│ │ • Autosave (debounced 500 ms) │ │
│ │ • Save tap → capture + native ─┼────┐
│ │ Photos save + cache thumb │ │
│ │ • Next tap → save + mark complete │ │
│ │ + advance to next drawing ──────┼─┐ │
│ │ • Back tap → save + load Colorbook─┼────┤
│ └──────────────────────────────────────┘ │ │
│ │ │
└────────────────────────────────────────────┼──┘
│
┌──────────────────────────┘
│ AdvanceToNextDrawing:
│ Catalog.NextUnseen(currentId) → reload Gameplay
└─ stays in Gameplay.unity, no scene transition
```
The user views their captured drawings inside the phone's native **Photos** app — there is no in-app gallery viewer. Capture and gallery-save are two independent services:`ICaptureService` produces PNG bytes; `IGalleryService` is a thin shim over a native plugin that writes those bytes into the device's photo library.
The user views captured drawings inside the phone's native **Photos** app — there is no in-app gallery viewer. `ICaptureService` produces PNG bytes; `IGalleryService` is a thin shim over a native plugin that writes those bytes into the device's photo library. The Save System (§13) decides *when* to capture and save.
---
@@ -255,24 +302,30 @@ New asmdefs follow the same convention: `Services.Capture`, `Services.Gallery`,
## 6. Scenes & Lifetime Scopes
Four scenes, each with its own scope. Root scope persists across all scene changes.
| `Colorbook.unity` | `ColorbookLifetimeScope` | ⚠️ planned | `ColorbookFlow` + `DrawingCatalog`. Catalog grid where the player picks a drawing. |
| `Gameplay.unity` | `GameplayLifetimeScope` | ⚠️ scene exists, scope empty | `ShapeBuilder` + `Coloring` + `History` + `Capture` (the feature wrapper) + `GameplayFlow`. The active drawing experience. |
Only `Boot.unity` exists today; the two scene scope classes haven't been written yet either (only `RootLifetimeScope` exists in [App/LifetimeScopes/](Assets/Darkmatter/Code/App/LifetimeScopes/)).
Only `Boot.unity` and an empty `Gameplay.unity` exist today; the four scene scope classes need full implementation (only `RootLifetimeScope` is functional).
Scopes nest: `Root → (MainMenu | ColorBook)`. Services resolved from the root parent. Scene scopes only register their own features. There is **no in-app gallery** — captured drawings go to the phone's native Photos app via the gallery service.
Scopes nest: `Root → (MainMenu | Colorbook | Gameplay)`. Services and cross-scene features (Progression, DrawingTemplate) resolve from the root parent. Scene scopes only register their own features.
**No in-app gallery** — captured drawings go to the phone's native Photos app via `IGalleryService`. The catalog grid in `Colorbook.unity` shows the user's progress by reading cached thumbnails from `IProgressionSystem`.
### Boot chain (planned)
No `AppBoot` class exists yet — today `RootLifetimeScope` only registers services and stops there. When `AppBoot` is added (as an `IAsyncStartable` registered via `builder.RegisterEntryPoint<AppBoot>()`), it should run once, in order:
No `AppBoot` class exists yet — today `RootLifetimeScope` only registers services and stops. When `AppBoot` is added (as an `IAsyncStartable` registered via `RootLifetimeScope`), it should run once, in order:
2.`IProgressionSystem.LoadAsync()` — hydrate per-template state from PlayerPrefs.
3.`IDrawingTemplateCatalog.InitializeAsync()` — batch-load all `DrawingTemplateSO`s by Addressables label.
4.Optional: preload UI sounds, palette assets.
5.`ISceneService.LoadAsync(MainMenu)`.
Failures show a child-friendly retry screen; never crash.
@@ -563,54 +616,55 @@ public readonly struct PaperSavedSignal {
### `ShapeBuilder`
- Listens to `DrawingSelectedSignal`.
- Loads template, instantiates the single piece prefab once per `ShapeSO` in the template, parents under the HUD tray panel (`ColorBookSceneRefs.TrayPanel`). Each instance is `Assign(shape)`ed to its `ShapeSO`.
-`SlotMarker`s in the drawing's per-drawing prefab (under `ColorBookSceneRefs.SlotsParent`) provide target poses + matching`ShapeSO` refs.
-Each piece has`IBeginDragHandler` / `IDragHandler` / `IEndDragHandler` plus a per-piece `ShapePieceFsm`. Drag updates `RectTransform.anchoredPosition` directly from `PointerEventData`, converted to canvas-local via `RectTransformUtility.ScreenPointToLocalPointInRectangle`.
-On entering preview radius of the matching slot: reactive `Lerp` of `anchoredPosition` / `sizeDelta` / `localRotation` toward `SlotMarker`'s `RectTransform`. Drives off pointer distance, not time.
- On `OnEndDrag` inside snap radius: piece reparents to `ColorBookSceneRefs.PiecesParent`, DOTween ease-out to exact slot pose, disable input. Otherwise DOTween back to tray slot.
- Fires `ShapeAssembledSignal` when all pieces locked.
- Listens to `DrawingSelectedSignal` (raised by the Colorbook scene before scene change; resume reads `LastOpenedTemplateId` in Gameplay scope startup).
- Loads the per-drawing prefab via `IDrawingTemplateCatalog`, instantiates it under `GameplaySceneRefs.PaperRoot`. The prefab carries the `SlotMarker`s at their authored poses.
-Spawns one **`ShapePiece` MonoBehaviour** per `ShapeSO` in the template via `Instantiate(piecePrefab, tray)` and calls `piece.Setup(shape, slot, cfg, sfx, bus, trayPos, preSnapped)`. If `progress.Phase == ShapeBuilding`, pieces in `progress.SnappedPieces`are pre-snapped (start locked).
-`ShapePiece` is a single MB handling all three behaviors inline: drag (Unity UI`IBeginDrag / IDrag / IEndDrag`), reactive preview lerp when within `cfg.PreviewRadius`, snap (PrimeTween — `Tween.UIAnchoredPosition` / `UISizeDelta` / `LocalRotation`) on release inside `cfg.SnapRadius`, otherwise tween back to tray. No FSM, no factory — just the MB.
-Publishes `PieceSnappedSignal(pieceId)` on lock. Controller counts against expected; fires `ShapeAssembledSignal(templateId)` when all locked.
### `Coloring`
- Listens to `ShapeAssembledSignal`.
- Spawns one UI `Image` per `ColorRegionDTO` under `ColorBookSceneRefs.RegionsParent`. Each region's `Image.alphaHitTestMinimumThreshold = 0.5f` so taps on transparent pixels pass through to the next region.
- Spawns one UI `Image` per `ColorRegionDTO` under `GameplaySceneRefs.RegionsParent`. Each region's `Image.alphaHitTestMinimumThreshold = 0.5f` so taps on transparent pixels pass through to the next region below.
- Each region has `IPointerClickHandler`. On click → `ColoringController.PaintRegion(view)`.
- Listens to palette selection (current color held in `ColoringStateRepository`).
- Controller builds `PaintRegionCommand(regionId, oldColor, newColor)` and pushes to `IUndoStack`.
-Command sets `Image.color` on undo/redo.
-Fires `ColorAppliedSignal` for SFX / sparkle effects.
- Controller builds `PaintRegionCommand(regionId, oldColor, newColor)` and pushes to `IUndoStack`. Command sets `Image.color` on Execute/Undo.
-Publishes `ColorAppliedSignal` for SFX / sparkle effects.
-**Resume:** if `progress.RegionColors` is non-empty, spawned regions are initialized with those saved colors instead of `region.InitialColor`.
- **Autosave hook:** after each `PaintRegion`, debounces 500 ms then calls `GameplayFlowController.AutosaveAsync` so the colors hit disk without thumbnail re-render. See §13.
### `History`
- Owns the scoped `IUndoStack` for the current ColorBook session.
- Cleared on `DrawingSelectedSignal` (new drawing = fresh history).
- Capped at 20 entries (memory + cognitive simplicity).
- UI: two big arrow buttons; disabled state when `CanUndo / CanRedo` is false.
- Owns the scoped `IUndoStack` for the current Gameplay session.
- Cleared on Gameplay scope startup (new drawing = fresh history).
- Capped at 20 entries.
- UI: two big arrow buttons; disabled state when `CanUndo` / `CanRedo` is false.
### `Capture`
-Bound to the "Save" button (and triggered silently by "Next").
-`CaptureController.SaveAsync(templateId)`:
1.`_capture.CaptureAsync()` → PNG bytes (one-shot `CaptureCamera.Render()` into a temp RT)
2. Publish `PaperCapturedSignal(templateId)`
3.`_gallery.SaveToDeviceAsync(bytes, "Color Book")` → native plugin writes into phone's Photos
4. Publish `PaperSavedSignal(templateId)`
- HUD shows a brief "Saved to Photos" toast on `PaperSavedSignal`.
-`CaptureController` is the only place that orchestrates capture-then-save. Other features never call `IGalleryService` directly.
-Wraps `ICaptureService.CaptureAsync()` (one-shot `CaptureCamera.Render()` into a temp RT, ReadPixels, EncodeToPNG). Returns raw PNG bytes.
-The **Capture feature does NOT decide what to do with the bytes** — `GameplayFlowController` calls it, then routes to gallery + thumbnail cache depending on the trigger. See §13.
### `Progression`
-Tracks completed template IDs and the in-progress draft.
-On "Next" button: silently runs `CaptureController.SaveAsync`, marks current as completed, calls `IDrawingTemplateCatalog.NextUnseen()`.
-Persists JSON via `Libs.PlayerPrefs` (`ProtectedPlayerPrefs`).
-Single source of truth for per-template user state. Implements `IProgressionSystem`, persists `DrawingProgress` records via `Libs.PlayerPrefs` (single JSON blob under `PlayerPrefsKeys.Progression`).
-Internally stores thumbnails per template as PNG files in `Application.persistentDataPath/thumbs/{safeId}.png` (large blobs don't belong in PlayerPrefs).
-`ProgressionRepository` does the IO; `ProgressionSystem` keeps an in-memory cache and exposes a clean API.
- Built as a small FSM (`Catalog → Building → Coloring → Done`).
- The orchestrator for the catalog scene.
-On scope start: calls `_drawingCatalog.InitializeAsync()` to populate the visible-IDs list.
-Subscribes to `DrawingSelectedSignal`:`_progression.SetLastOpened(id)`+`_scenes.LoadAsync(Gameplay)`.
### `GameplayFlow` (in `Gameplay.unity`)
- The orchestrator for the active drawing scene.
- On scope start: reads `_progression.LastOpenedTemplateId`, fetches its `DrawingProgress`, enters either Building (no progress / Phase==ShapeBuilding) or Coloring (Phase==Coloring) state.
- Handles all save points (§13): Back button, ShapeAssembled transition, Save button, Next button, app lifecycle pause/quit.
- Uses `Libs.FSM` (StateMachine) for `Building` ↔ `Coloring` runtime states.
---
@@ -740,6 +794,92 @@ Notes:
---
## 12b. Save System
Everything the user does that affects their drawing state must end up persisted. `GameplayFlowController` is the **single owner** of all save calls — feature controllers expose getters; the flow controller assembles the `DrawingProgress` record and hands it to `IProgressionSystem`.
### What is saved
| Field on `DrawingProgress` | Meaning |
|---|---|
| `templateId` | Which drawing this record is about |
| `phase` | `ShapeBuilding` or `Coloring` — where to resume |
| `snappedPieces` | Pieces locked into slots (relevant in ShapeBuilding) |
| `regionColors` | Per-region color (relevant in Coloring) |
| `hasThumbnail` | Whether a thumbnail PNG exists on disk for catalog display |
| `hasBeenCompleted` | Flipped true on first Next; never flips back |
| `completionCount` | Number of times Next was pressed (optional stats) |
| `updatedUtcIso` / `firstCompletedUtcIso` | Timestamps (ISO 8601 strings for JsonUtility) |
| **ShapeAssembledSignal** (Building → Coloring transition) | `Coloring` | all | empty | **yes** (bare-assembled paper) | no |
| **Each paint** (debounced 500 ms) | `Coloring` | all | current | no | no |
| **Save button** | `Coloring` | all | current | **yes** | **yes** |
| **Next button** | `Coloring` | all | current | **yes** | **yes** |
| **Back button (during Building)** | `ShapeBuilding` | current | empty | no | no |
| **Back button (during Coloring)** | `Coloring` | all | current | **yes** | no |
| **OnApplicationPause(true) / OnApplicationQuit** | current phase | current | current | no | no |
Two design principles drive the matrix:
- **Thumbnail capture is expensive** (render + ReadPixels + PNG encode). Skip it on partial-assembly saves and per-paint autosaves. Only generate a thumbnail when the user takes an explicit save-style action.
- **Defensive saves never block UX.** App pause/quit saves whatever is in memory without capturing — fast path, no awaitable IO holding up shutdown.
### `Next` adds two extras
- Flips `hasBeenCompleted = true` (preserves first `firstCompletedUtcIso`); increments `completionCount`.
- Plays completion animation, then calls `AdvanceToNextDrawing` → `Catalog.NextUnseen(currentId)` → reload Gameplay scope for the new drawing.
### Storage layout
| What | Where |
|---|---|
| `DrawingProgress` records + `lastOpened` | One JSON blob in `ProtectedPlayerPrefs[PlayerPrefsKeys.Progression]` (see `ProgressionRootDto`) |
| Thumbnail PNGs | `Application.persistentDataPath/thumbs/{safeId}.png` (one file per template that has a thumbnail) |
`safeId` replaces `/` and `\` with `_` so `animals/elephant` becomes `animals_elephant.png`.
### Resume / load decision
On Gameplay scope startup:
```csharp
varid=_progression.LastOpenedTemplateId;
varprogress=_progression.GetProgress(id);// null if untouched
fsm.Go(Building);// spawn pieces in tray, pre-snap any in progress.snappedPieces
}else{
fsm.Go(Coloring);// skip ShapeBuilder; auto-snap pieces; spawn regions with progress.regionColors
}
```
### Catalog cells reflect saves automatically
The Colorbook scene reloads on Back. Its presenter calls `_progression.GetCachedThumbnailAsync(id)` per cell → returns the most recent save's PNG. Drawings the user touched display their progress; untouched drawings fall back to `IDrawingTemplate.DefaultThumbnail`. No live-update plumbing needed — re-entry is the refresh.
| `Features/Progression/Installers/ProgressionFeatureModule.cs` | Registers `IProgressionSystem` as Singleton in Root scope |
### Single rule
> Only `GameplayFlowController` calls `_progression.SaveProgressAsync(...)`. Feature controllers expose getters; they never touch the tracker themselves. This means there is exactly one place to audit when save behavior changes.
---
## 13. Communication Rules
| Use case | Mechanism |
@@ -1145,44 +1285,109 @@ Same shape repeats for every feature's UI.
## 26. ShapeBuilder — Snap Algorithm
All math is in canvas-local space — `anchoredPosition`, `sizeDelta`, `localRotation`. No world coords.
All math is in canvas-local space — `anchoredPosition`, `sizeDelta`, `localRotation`. No world coords. Behavior lives inline in `ShapePiece : MonoBehaviour` — no FSM, no factory, no state classes. Three behaviors expressed across three Unity drag handlers.
### `OnDrag` — reactive preview lerp
```csharp
// In ShapePieceFsm.OnDragEnd (state: Dragging or Preview):
1.**Reparent** the piece from `TrayPanel` (HUD canvas) to `ColorBookSceneRefs.PiecesParent` (PaperCanvas) so it'll be included in capture. `worldPositionStays: false` because we want the new `anchoredPosition` to be relative to the new parent, not the world.
2.**Three simultaneous tweens** — position, size, rotation. Use `DOAnchorPos`, `DOSizeDelta`, `DOLocalRotateQuaternion`. They start together so the piece visually snaps as one motion.
1.**Reparent on lock** — `Lock()` calls `RectTransform.SetParent(_slot.RectTransform.parent, false)`. The piece moves from the HUD-side tray to the per-drawing slot parent so it travels with the paper and gets included in the captured PNG.
2.**Three parallel PrimeTween calls** — position, size, rotation. Tweens start together so the piece visually snaps as one motion. Zero allocations per tween.
3.**`SnapRadius` is in canvas units** (from `ShapeBuilderConfig`, e.g. 80–120), not world units. Same `CanvasScaler` reference resolution across devices = same hit feel.
4.**Preview hover sound fires once per drag**, on the boundary cross into the preview radius. `_inPreview` flag resets on `OnBeginDrag`.
Controller listens for `PieceSnappedSignal`, counts against expected piece count, fires `ShapeAssembledSignal` when complete.
### Pre-snapped resume
If the user closes the app mid-assembly (or after completing the drawing), the saved `DrawingProgress.snappedPieces` lists which pieces were locked. On resume, the controller passes `preSnapped: true` to `Setup` for those, and `ShapePiece.SnapInstantly()` puts them straight into their slots — no tween, no input. The user can keep snapping the remaining pieces.
Controller listens for `PieceSnappedSignal`, counts against expected piece count, fires `ShapeAssembledSignal` when complete → `GameplayFlowController` captures bare-assembled thumbnail, transitions to Coloring (see §13).
The single MonoBehaviour that handles drag, reactive preview lerp, snap (PrimeTween), and return-to-tray. Spawned by the controller; `Setup` binds dependencies and starting pose.
publicUniTaskBuildAsync(stringtemplateId);// load template, spawn pieces in tray
publicvoidReset();// clear, unsubscribe
}
// sub: DrawingSelectedSignal
// pub: ShapeAssembledSignal
```
- **Internal:** counts `PieceSnappedSignal` against expected piece count.
- **Slot discovery:** after a drawing's per-drawing prefab is instantiated under `ColorBookSceneRefs.PaperRoot`, the controller queries `GetComponentsInChildren<SlotMarker>()` to discover all slots in the loaded drawing. Each slot's `_shape` field tells which `ShapeSO` it expects; matching pieces are spawned in the tray.
- Drag handlers run inline in this MB — no separate FSM class.
-`Snap()` is a PrimeTween triple (`Tween.UIAnchoredPosition` / `UISizeDelta` / `LocalRotation`); `SnapInstantly()` is the resume path that puts a pre-snapped piece directly into its slot pose without animation.
-`ReturnToTray()` builds a PrimeTween `Sequence` of three parallel tweens.
Authored per drawing — designer places one in the per-drawing prefab at each slot location with the `RectTransform` set to the target pose and `_shape` field assigned to the matching `ShapeSO`. The `RectTransform` itself **is** the target pose.
- Handlers forward to `ShapePieceFsm` (`OnDragBegin / OnDrag(localPos) / OnDragEnd`).
-`OnDrag` converts `PointerEventData.position` to canvas-local via `RectTransformUtility.ScreenPointToLocalPointInRectangle` against the piece's parent rect.
- No collider, no Physics2D anywhere.
- **Identity follows the SO** — change `_shape` in inspector and the visual + ID update on the next `OnValidate`. At runtime, `Assign(...)` is the only mutation path.
**Matching is by `ShapeSO` reference equality** — the controller pairs each `ShapePiece.Shape` with the `SlotMarker.Shape` of the same SO asset.
#### `ShapePieceFsm` *(Systems)*
Per-piece state machine using `Libs.FSM`. States: `InTray → Dragging → Preview → (Snapped | Returning)`.
#### `ShapeBuilderConfig : ScriptableObject` *(Static data — ✅ exists)*
publicfloatSnapGraceMultiplier;// (currently unused — grace zone removed)
publicfloatPreviewRadius;// ~2× SnapRadius
publicfloatSnapDuration;// 0.25s
publicfloatReturnDuration;// 0.25s
publicAnimationCurvePreviewCurve;// easing for the reactive lerp
publicVector2DragSizeDelta(ShapeSOshape);
}
```
- **Preview-state update**: reactive lerp of `anchoredPosition / sizeDelta / localRotation` toward `_targetSlot`'s pose, driven by `1 - dist/PreviewRadius`. No DOTween while previewing — it's per-frame.
- **Snapped enter**: DOTween ease-out to exact slot pose (~0.2s), disable drag, fire `PieceSnappedSignal`.
- **Returning enter**: DOTween back to tray slot (`anchoredPosition` from `TrayLayout`).
#### `SlotMarker : MonoBehaviour` *(UI)*
The outline `Image` under `ColorBookSceneRefs.SlotsParent` showing where a piece should snap. Authored per drawing — designer places one in the per-drawing prefab at each slot location, with its `RectTransform` set to the target pose and `_shape` field assigned to the matching `ShapeSO`.
Spawns pieces for the selected template, tracks snap progress, fires `ShapeAssembledSignal` when complete. **Replaces the old `ShapePieceFactory` — spawning is now a 5-line inline loop, not a separate class.**
```csharp
publicsealedclassSlotMarker:MonoBehaviour{
[SerializeField]privateShapeSO_shape;// which shape fits here
- **Slot discovery:** after the per-drawing prefab is instantiated, `GetComponentsInChildren<SlotMarker>(includeInactive: true)` finds all slots. Each slot's `_shape` tells which `ShapeSO` it expects.
- **Pre-snap on resume:** if `preSnappedIds.Contains(shape.Id)`, the spawned `ShapePiece` is initialized with `preSnapped: true` → `SnapInstantly()` lands it in the slot at scope start.
- **Snapped count:** subscribes to `PieceSnappedSignal`, counts against expected, fires `ShapeAssembledSignal` when count == `template.Pieces.Count`.
#### `TrayPanel : MonoBehaviour` *(UI)*
HUD-side panel (on `HUDCanvas`) where pieces start out. Has a `HorizontalLayoutGroup` + `ContentSizeFitter`. Provides spawn anchors via `RectTransform Slot(int index)` for the controller.
#### `ShapePieceFactory` *(Systems)*
Pool of `ShapePieceUI` GameObjects (one prefab) + their associated FSMs. Reused across template loads.
#### `TrayLayout` *(Systems — planned)*
Tiny stateless helper. Given (`index`, `total`), returns the tray slot's `anchoredPosition`. Either uses a `HorizontalLayoutGroup`'s computed positions or a hand-rolled even spacing across the tray's width.
```csharp
publicsealedclassShapePieceFactory{
// Instantiates the single piece prefab under `parent`, calls Assign(shape) on it,
// and wires up its FSM with the matching SlotMarker.
- One prefab in `Content/Gameplay/Prefabs/ShapePiece.prefab` is instantiated repeatedly. Visual identity comes from the `ShapeSO` passed to `Assign`.
#### `ShapeBuilderInputBinder` *(Systems)*
With UI handlers on the piece itself, an explicit input binder isn't strictly needed — drag events route via the EventSystem. Keep this class only if you need to listen for "any tap outside any piece" (e.g. to dismiss a preview). Otherwise skip.
#### Removed / not needed
- **`ShapePieceFsm`** — was a per-piece state machine. Replaced by inline drag handlers + a single `_locked` bool on `ShapePiece`.
- **`ShapePieceFactory`** — was a wrapper around `Instantiate` + FSM wiring. Replaced by a 5-line inline loop in `ShapeBuilderController.BuildAsync`.
- **Five state classes** (`InTray`, `Dragging`, `Preview`, `Snapped`, `Returning`) — gone. Their behavior maps to: `_locked = false` (idle/dragging/preview all share the same handlers), `_inPreview` flag (preview boundary detection), `Snap()` method, `ReturnToTray()` method.
- **`ShapeBuilderInputBinder`** — never needed; UI handlers on the piece are sufficient.
---
@@ -1855,16 +2091,27 @@ public sealed class ColoringStateRepository {
Builds and pushes `PaintRegionCommand` instances; spawns `ColorRegionView` per region.
Spawns each region as a UI `Image` under `_paper.RegionsParent`. No `Physics2D`.
Spawns each region as a UI `Image` under `_refs.RegionsParent`. No `Physics2D`.
**Autosave integration:** after each successful `PaintRegion`, the controller calls a debounced `GameplayFlowController.ScheduleAutosave()` so the flow can write the new color state to `IProgressionSystem` 500 ms later (no thumbnail, cheap). The flow controller cancels and resets the timer on each paint — only the last paint in a burst triggers the write.
If you add a class not in this table, add it here in the same PR. This table is the cheap mental-model index — keep it honest. See §31b for the full path-by-path inventory.
> Today only these rows are real on disk: `RootLifetimeScope` (App), `AddressableAssetProviderService`, `AudioService`/`SfxPlayer`, `CameraService`, `SceneService`, `InputReaderSO`, `FirebaseAnalyticsSystem` (Services), `UndoStack` + `HistoryServiceModule` (Features.History), plus `Libs.*` entries (`EventBus`, `StateMachine`, `IServiceModule`, PlayerPrefs lib, UI toggles). Everything else is the target.
> **What's real on disk today (2026-05):** All Service classes (`AddressableAssetProviderService`, `AudioService`/`SfxPlayer`, `CameraService`, `SceneService`, `InputReaderSO`, `FirebaseAnalyticsSystem`, stub `CaptureService`, stub `GalleryService`), all Lib classes, `ShapePiece` + `SlotMarker` + `ShapeBuilderConfig`, `UndoStack` + `HistoryServiceModule`, `ProgressionSystem` + `ProgressionRepository` (stubs), `AddressableDrawingTemplateCatalog` + module, `DrawingCatalogController` + presenter + view, `ColorbookFlowController` (partial — needs constructor injection wired). Empty / planned: `MainMenu` feature, `GameplayFlow` feature, `Coloring` feature, `MainMenu`/`Colorbook`/`Gameplay` scene scopes, all scenes except `Boot.unity`.
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.