Merge savya: Spine mascot on main menu

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Savya Bikram Shah
2026-05-27 13:42:31 +05:45

View File

@@ -562,6 +562,14 @@ public readonly struct ArtworkSavedSignal {
## 9. Feature Responsibilities
### `MainMenu`
- Lives in `MainMenu.unity`. Two main entry buttons: **Play** (→ `ColorBook` scene) and **Art Book** (→ `ArtBook` scene).
- Hosts a **Spine character mascot** (via `SkeletonGraphic` for Canvas). The mascot has multiple authored animations — idle loop, wave, react-to-button, victory dance.
- `MenuMascotPresenter` (pure C#) drives the mascot from code: subscribes to button hover / click events and the model's idle timer, calls `IMenuMascotView.Play(animName, loop)`.
- View is setter-only. Spine-Unity's `SkeletonGraphic.AnimationState.SetAnimation(track, name, loop)` is encapsulated behind `IMenuMascotView`.
- Mascot's skeleton + atlas ship via Addressables (see §10).
### `DrawingCatalog`
- Loads the catalog manifest (list of available template IDs).
@@ -642,11 +650,12 @@ Mirror the Bus Game pattern via `IAssetProviderService`.
| Asset | Why |
|---|---|
| `DrawingTemplate` ScriptableObject (per drawing) | Many; load on demand. |
| Shape piece sprites | Only needed when active. |
| Region sprites + polygon paths | Heavy; loaded per drawing. |
| `ShapeSO` assets | Reused across drawings; load once per drawing batch. |
| Region sprites | Heavy; loaded per drawing. |
| Paper backgrounds | Per template, sometimes shared. |
| Color palette SOs | Swap per theme. |
| Audio clips (tap, snap, complete, sparkle) | Shared SFX bank. |
| Spine mascot (`SkeletonDataAsset` + atlas) | Heavy textures; load with `MainMenu` scene, release on scene exit. |
### What does NOT use Addressables
@@ -661,9 +670,11 @@ Mirror the Bus Game pattern via `IAssetProviderService`.
Drawings_Animals (label: drawing, animals)
Drawings_Vehicles (label: drawing, vehicles)
Drawings_Shapes (label: drawing, shapes)
Shapes_Library (label: shape) — reusable ShapeSO assets
Palettes (label: palette)
Audio_UI (label: sfx, ui)
Audio_Coloring (label: sfx, coloring)
Spine_MainMenu (label: spine, menu) — mascot skeleton + atlas
```
### Lifecycle
@@ -1275,12 +1286,13 @@ Toddler-mode error UI:
## 30. Setup Checklist (new dev, day one)
1. Open `Colorbook.sln` at the repo root.
2. Open `Assets/Darkmatter/Scenes/Boot.unity` (currently the only scene wired).
3. Inspect the `RootLifetimeScope` GameObject — confirm its `serviceModules[]` list references the child installer MonoBehaviours (`AudioServiceModule`, `CameraServiceModule`, `InputServiceModule`, etc.).
4. Hit Play from `Boot.unity`. Other scenes (`MainMenu`, `ColorBook`, `ArtBook`) don't exist yet — they're listed in §6 / §4c as planned work.
5. When new scene scopes land, the same rule applies: never start a scene mid-flow, always enter from `Boot.unity` so the root scope exists.
6. When drawings are authored: duplicate the template folder under `Content/Gameplay/Drawings/<theme>/<id>/`, edit `Template.asset` (pieces + regions), add to the appropriate Addressables group.
7. Run `Tests > EditMode` and `Tests > PlayMode` before pushing (test infra not set up yet — see §16).
2. Verify required Unity packages are installed (check `Packages/manifest.json`): VContainer, UniTask, Addressables, Input System, URP, **Spine-Unity runtime** (`com.esotericsoftware.spine.spine-unity`) for the main-menu mascot, DOTween (for snap/return tweens).
3. Open `Assets/Darkmatter/Scenes/Boot.unity` (currently the only scene wired).
4. Inspect the `RootLifetimeScope` GameObject — confirm its `serviceModules[]` list references the child installer MonoBehaviours (`AudioServiceModule`, `CameraServiceModule`, `InputServiceModule`, etc.).
5. Hit Play from `Boot.unity`. Other scenes (`MainMenu`, `ColorBook`, `ArtBook`) don't exist yet — they're listed in §6 / §4c as planned work.
6. When new scene scopes land, the same rule applies: never start a scene mid-flow, always enter from `Boot.unity` so the root scope exists.
7. When drawings are authored: duplicate the template folder under `Content/Gameplay/Drawings/<theme>/<id>/`, edit `Template.asset` (pieces + regions), add to the appropriate Addressables group.
8. Run `Tests > EditMode` and `Tests > PlayMode` before pushing (test infra not set up yet — see §16).
---
@@ -1302,6 +1314,7 @@ Toddler-mode error UI:
| `HistoryController` | Features | `Features.History` |
| `ColorBookFlowController` | Features | `Features.ColorBookFlow` |
| `GalleryPresenter`, `GalleryGridView` | Features | `Features.ArtBook` |
| `MenuMascotView`, `MenuMascotPresenter` | Features | `Features.MainMenu` |
| `ColorBookLifetimeScope`, `AppBoot` | App | `Darkmatter.App` |
If a class's natural home doesn't match its asmdef, the architecture is bent — fix the placement, don't add a reference.
@@ -1554,6 +1567,73 @@ public interface IFsmState { void Enter(); void Exit(); }
---
### 32.3b Feature — `MainMenu` *(planned)*
Lives in `MainMenu.unity`. Hosts the **Play** / **Art Book** entry buttons plus the **Spine character mascot**.
#### `IMenuMascotView` *(UI contract)*
Setter-only view interface. Hides Spine-Unity's API behind a tiny surface.
```csharp
public interface IMenuMascotView {
event Action<string> AnimationComplete; // fires when a non-looping anim ends
void Play(string animName, bool loop);
void SetSkin(string skinName); // optional — character variants
}
```
#### `MenuMascotView : MonoBehaviour, IMenuMascotView` *(UI)*
Concrete view. Wraps a `SkeletonGraphic` component (Spine-Unity's Canvas-compatible renderer).
```csharp
public sealed class MenuMascotView : MonoBehaviour, IMenuMascotView {
[SerializeField] private SkeletonGraphic _skeleton; // Spine UI component
public event Action<string> AnimationComplete;
public void Play(string animName, bool loop) {
var track = _skeleton.AnimationState.SetAnimation(0, animName, loop);
track.Complete += _ => AnimationComplete?.Invoke(animName);
}
public void SetSkin(string skinName) {
_skeleton.Skeleton.SetSkin(skinName);
_skeleton.Skeleton.SetSlotsToSetupPose();
_skeleton.AnimationState.Apply(_skeleton.Skeleton);
}
}
```
- `SkeletonGraphic` lives on a child of `MainMenuCanvas`. It's a `Graphic`, so it interacts with `CanvasRenderer` just like an `Image`.
- The Spine asset (`SkeletonDataAsset`) is loaded via Addressables, assigned at scene setup, and released on scene exit.
#### `MenuMascotPresenter` *(UI)* — `IStartable, IDisposable`
Pure C#. Subscribes to button events + idle timer, drives the view.
```csharp
// fields: IMenuMascotView _view, MainMenuModel _model, IInputReader _input
public sealed class MenuMascotPresenter : IStartable, IDisposable {
public void Start() {
_view.Play("idle", loop: true);
_model.PlayButtonHovered += () => _view.Play("hover_play", loop: false);
_model.ArtBookButtonHovered += () => _view.Play("hover_artbook", loop: false);
_view.AnimationComplete += OnAnimationComplete;
}
private void OnAnimationComplete(string anim) {
if (anim != "idle") _view.Play("idle", loop: true); // always return to idle
}
}
```
- Mascot reactions are pure presenter logic — the view never decides what to play.
- If you want randomized idle variants, add an idle timer in the model + a list of clip names.
#### `MainMenuModel` *(Repository)*
Holds menu state — current selected skin, fires hover/click events from button presenters.
#### `MainMenuModule : MonoBehaviour, IServiceModule` *(Installers)*
Registers the view (`RegisterInstance<IMenuMascotView>(_view)`), the presenter as a startable entry point, and the model.
> **Package dependency:** [Spine-Unity runtime](http://esotericsoftware.com/spine-unity) (`com.esotericsoftware.spine.spine-unity`). Add to `Packages/manifest.json`. The `SkeletonGraphic` component lives in `Spine.Unity` namespace.
---
### 32.4 Feature — `DrawingCatalog` *(planned)*
#### `DrawingCatalogController` *(Systems)*
@@ -1984,6 +2064,8 @@ Implemented as `MonoBehaviour` per feature/service so scopes can drag them in th
| `CaptureController` | Feature | Capture+save orchestration | capture svc, gallery, bus |
| `ColorBookFlowController` | Feature | Scene FSM | bus, catalog, builder, coloring, capture, progression |
| `GalleryPresenter` | Feature | Art book listing | gallery, share, view, bus |
| `MenuMascotView` | Feature | Spine mascot UI (SkeletonGraphic wrapper) | — |
| `MenuMascotPresenter` | Feature | Drives mascot animations from model events | view, model |
| `BoundedUndoStack` | Lib | Capped undo store | — |
| `EventBus` | Lib | Pub/sub | — |
| `Fsm<TState>` | Lib | Generic FSM | — |