Skip to content

FTUE (Tutorial) Migration — Implementation Plan

Inline autonomous execution. Spec: docs/superpowers/specs/2026-06-30-ftue-migration-design.md. Verify each phase via Unity_RunCommand (compile + headless asserts); commit per task; keep the ledger at .superpowers/sdd/ftue-progress.md current. Web reference: game.js TUTORIAL/ 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; TutorialConditions pure C#; TutorialController the only new DI seam.
  • Tutorial mobs: base HP (no raid sponge / power-scale). PopulateTutorial is a parallel path — leave Populate (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: replace TutorialStub with real {int stage=1; bool done=false; bool lobbyDone; bool firstRaidShown}; migration keeps existing saves done=true.
  • Config/Tutorial/: StepCondition.cs (+ ConditionType, WhenCondition enums), TutorialLoot.cs (+ TutorialLootKind), TutorialStep.cs, TutorialStageDef.cs (SO), TutorialSet.cs (SO). Pure data + [Serializable]; mirror the web fields (spec §3.1).
  • Infrastructure/ProjectInstaller.cs: bind TutorialSet (serialized field, like BiomeSet).
  • Verify: compile; ScriptableObject.CreateInstance<TutorialStageDef>() + set fields round-trips.

Phase 1 — Conditions (pure, testable)

  • Domain/TutorialConditions.cs: Eval(StepCondition, ITutorialCtx) -> bool and Eval(WhenCondition, GameConfig) -> bool. Define a tiny ITutorialCtx read-interface (gold, latches, mobsCleared, chestsOpened, hasKey, gateOpen, bossDown, hasItem(name), hasStarterKit) so it's unit-pure.
  • Verify: headless truth-table — each ConditionType returns the expected bool from a stub ctx; anyOf ORs; Never always false; each WhenCondition reads 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 + Portals from extracts + Vault; then BuildChunks.
  • World/EnemyController.cs: scripted-AI flags IsTutorial, 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: BuildFromLayout on a stub def → expected W/H, spawn tile floor, vault gate solid-when-closed, portal count == extracts; PopulateTutorial places 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 (with when-skip) + CoachText; CanExtract from def.canExtract; apply systems to RaidController + HUD.
  • Hooks: PlayerController backstab crit → Backstabbed; heal-complete → Healed; Chest open → RaidState.ChestsOpened++; RaidState gets ChestsOpened.
  • Verify: compile; a headless driver tick advances StepIdx when a stubbed condition latches; a when-false step auto-skips.

Phase 4 — HUD message panel + systems toggles

  • UI/InGame/InGameViewModel.cs: TutorialText, TutorialVisible.
  • UI/InGame/InGameView.cs: serialized tutorialPanel/tutorialText; Render toggles + sets it.
  • UI/InGame/InGameViewController.cs: read TutorialState.CoachText (optional inject) into the VM; hide goals during tutorial.
  • World/RaidController.cs: skip timer/storm when the active tutorial stage's systems.timer/storm is false; MapController/HUD minimap suppressed when systems.minimap false.
  • Prefab wiring (headless): add panel_tutorial to InGameView.prefab, wire refs.
  • Verify: instantiate InGameView, Render with TutorialVisible=true → panel active + text set.

Phase 5 — Bootstrap + lobby flow + guided swap

  • Tester/RaidBootstrap.cs: !save.tutorial.doneBuildFromLayout(TutorialSet[stage-1]) + PopulateTutorial + spawn TutorialController; else procedural raid. Pass CanExtract to the portal.
  • Tester/MetaHud.cs: tutorial result card (Stage N Cleared / Retry; gear never lost); on win apply grants + save.tutorial.stage++ (+ done after 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 ItemDef assets (Worn Knife, Whisper Dagger, Oak Bow, Leaf Cuirass, Ironwood Vest, Fawn Boots) — web-exact stats/perks (game.js:727–732).
  • 7 TutorialStageDef assets + 1 TutorialSet — 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: TutorialSet resolves 7 stages; each stage's BuildFromLayout produces 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).