FTUE (Tutorial) Migration — Implementation Plan¶
Inline autonomous execution. Spec:
docs/superpowers/specs/2026-06-30-ftue-migration-design.md. Verify each phase viaUnity_RunCommand(compile + headless asserts); commit per task; keep the ledger at.superpowers/sdd/ftue-progress.mdcurrent. Web reference:game.jsTUTORIAL/buildTutorialMap/tutorialDriver(lines ~712–971, 1712–1762, 5044–5117).
Goal: web-faithful 7-stage FTUE — pre-built tutorial layouts as SOs, configurable step/condition system, tutorial message panel in InGameView, grants + guided loadout swap, graduating into the raid.
Global constraints¶
- Web-faithful values/behaviour; rect-based layouts; no hardcoded map data (all in SOs).
- Only Views touch uGUI;
TutorialConditionspure C#;TutorialControllerthe only new DI seam. - Tutorial mobs: base HP (no raid sponge / power-scale).
PopulateTutorialis a parallel path — leavePopulate(raids) untouched. - Don't break existing saves (migration keeps
done=true).
Phases (each = a commit unit; verify before commit)¶
Phase 0 — Save + SO data classes (no logic)¶
Infrastructure/SaveService.cs: replaceTutorialStubwith real{int stage=1; bool done=false; bool lobbyDone; bool firstRaidShown}; migration keeps existing savesdone=true.Config/Tutorial/:StepCondition.cs(+ConditionType,WhenConditionenums),TutorialLoot.cs(+TutorialLootKind),TutorialStep.cs,TutorialStageDef.cs(SO),TutorialSet.cs(SO). Pure data +[Serializable]; mirror the web fields (spec §3.1).Infrastructure/ProjectInstaller.cs: bindTutorialSet(serialized field, likeBiomeSet).- Verify: compile;
ScriptableObject.CreateInstance<TutorialStageDef>()+ set fields round-trips.
Phase 1 — Conditions (pure, testable)¶
Domain/TutorialConditions.cs:Eval(StepCondition, ITutorialCtx) -> boolandEval(WhenCondition, GameConfig) -> bool. Define a tinyITutorialCtxread-interface (gold, latches, mobsCleared, chestsOpened, hasKey, gateOpen, bossDown, hasItem(name), hasStarterKit) so it's unit-pure.- Verify: headless truth-table — each
ConditionTypereturns the expected bool from a stub ctx;anyOfORs;Neveralways false; eachWhenConditionreads the right toggle.
Phase 2 — Fixed-layout map + authored placement¶
World/MapGenerator.cs:public MapData BuildFromLayout(TutorialStageDef def)— border + walls/bushes rects + vault room/gate +PlayerSpawn+Portalsfrom extracts +Vault; thenBuildChunks.World/EnemyController.cs: scripted-AI flagsIsTutorial,Hold,Scan/ScanDir,Patrol(Vector3[]),DropsKey; a held mob holds post+facing until recruited/spotted; base-HP path when tutorial.World/Chest.cs:FixedLoot(List) that bypasses the roller when set. World/MapPopulator.cs:PopulateTutorial(MapData, TutorialStageDef, Transform player)— place authored enemies (flags + facing), chests (fixed loot), grounds, vault prize;startHurt; base scale.- Verify:
BuildFromLayouton a stub def → expected W/H, spawn tile floor, vault gate solid-when-closed, portal count == extracts;PopulateTutorialplaces N enemies/chests headlessly.
Phase 3 — Runtime driver + action hooks¶
World/TutorialState.cs: stage def,StageNumber,StepIdx, latches, fired-hints set,CoachText,ChestsOpened; bound per-raid in tutorial mode (RaidInstaller, optional).World/TutorialController.cs(DI): per-frame latch set + hint fire + step advance (withwhen-skip) +CoachText;CanExtractfromdef.canExtract; applysystemsto RaidController + HUD.- Hooks:
PlayerControllerbackstab crit →Backstabbed; heal-complete →Healed;Chestopen →RaidState.ChestsOpened++;RaidStategetsChestsOpened. - Verify: compile; a headless driver tick advances
StepIdxwhen a stubbed condition latches; awhen-false step auto-skips.
Phase 4 — HUD message panel + systems toggles¶
UI/InGame/InGameViewModel.cs:TutorialText,TutorialVisible.UI/InGame/InGameView.cs: serializedtutorialPanel/tutorialText;Rendertoggles + sets it.UI/InGame/InGameViewController.cs: readTutorialState.CoachText(optional inject) into the VM; hide goals during tutorial.World/RaidController.cs: skip timer/storm when the active tutorial stage'ssystems.timer/stormis false;MapController/HUD minimap suppressed whensystems.minimapfalse.- Prefab wiring (headless): add
panel_tutorialtoInGameView.prefab, wire refs. - Verify: instantiate
InGameView,RenderwithTutorialVisible=true→ panel active + text set.
Phase 5 — Bootstrap + lobby flow + guided swap¶
Tester/RaidBootstrap.cs:!save.tutorial.done→BuildFromLayout(TutorialSet[stage-1])+PopulateTutorial+ spawnTutorialController; else procedural raid. PassCanExtractto the portal.Tester/MetaHud.cs: tutorial result card (Stage N Cleared / Retry; gear never lost); on win applygrants+save.tutorial.stage++(+doneafter last); guided swap after stage 6 — reusable spotlight component on the loadout + "Descend" gate until the Whisper Dagger is equipped.- Verify: play-mode smoke — tutorial boots into stage 1 (no timer/minimap), coach shows step 1.
Phase 6 — Author content (SO assets)¶
- 6
ItemDefassets (Worn Knife, Whisper Dagger, Oak Bow, Leaf Cuirass, Ironwood Vest, Fawn Boots) — web-exact stats/perks (game.js:727–732). - 7
TutorialStageDefassets + 1TutorialSet— web-faithful layouts/steps/grants/hints (game.js:750–909). - Author headlessly (Unity_RunCommand creating + populating the SOs) or via a small authoring command.
- Verify:
TutorialSetresolves 7 stages; each stage'sBuildFromLayoutproduces a valid map; steps non-empty; grants resolve to ItemDefs.
Phase 7 — End-to-end validation¶
- Play-mode per-stage smoke (or headless build checks for all 7); fix issues; final compile + console clean.
Verification harness¶
This project has no test runner — all verification is Unity_RunCommand (compile + instantiate/assert)
+ play-mode smoke, as used for the HUD. Pure TutorialConditions gets headless truth-table asserts.
Notes¶
- Read the relevant Unity source at each phase before editing (ItemDef/GearItem, EnemyController, Chest, PlayerController heal/backstab sites, RaidController timer, MetaHud loadout, EnemyDatabase keys, LootItem).
- The plan references the spec for field-level detail rather than reproducing all code (inline execution).