Skip to content

Add FTUE graph editor and runtime system#571

Open
Shombith03 wants to merge 16 commits into
bleeding-edgefrom
claude/ftue-editor-tool-69acq5
Open

Add FTUE graph editor and runtime system#571
Shombith03 wants to merge 16 commits into
bleeding-edgefrom
claude/ftue-editor-tool-69acq5

Conversation

@Shombith03

Copy link
Copy Markdown
Contributor

Summary

Replaces the flat TutorialSequenceSet list-based FTUE flow with a node-graph system backed by ScriptableObjects. Adds a visual editor window, runtime graph traversal with named-port branching, 15+ node types covering gameplay actions/dialogue/input/CTAs, and cloud persistence for completion state.

Key Changes

Editor Tooling

  • FTUEGraphEditorWindow — Three-panel IMGUI editor (left: graph list; center: draggable node canvas with edge drawing; right: typed inspector + connections + validation)
  • FTUEDefaultGraphBuilder — One-click generator for the canonical FTUE flow (intro → freestyle → throttle/steering prompts → dialogue → arcade game)
  • FTUERunnerSetup — Auto-wires FTUEGraphRunner references from the open scene and project assets

Core Graph System

  • FTUEGraphSO — Root asset holding ordered/branching node set and entry point
  • FTUENodeSO — Polymorphic base for all node types; each subclass carries typed fields + Execute() coroutine
  • FTUEEdge — Directed connection from named output port to target node (by stable ID, not index)
  • FTUEPorts — Canonical port names (Next, OnTimeout, OnSuccess, OnFailure, etc.) for branching

Node Types (15 total)

  • Cinematic: PlayIntroNode, PlayOutroNode
  • UI/Instructions: ShowInstructionNode, DialogueNode
  • Freestyle: EnterFreestyleNode, ExitFreestyleNode
  • Input/Timing: WaitForInputNode, WaitNode, WaitForGameLaunchNode, WaitForGamePlayedNode
  • Navigation/CTAs: NavigateNode, HighlightCTANode
  • Gameplay: LockModesNode
  • State: SetPhaseNode, EndNode

Runtime

  • FTUEGraphRunner — MonoBehaviour driver that gates on FTUECompletionStore, waits for vessel spawn, executes graph from entry node, and dispatches each node's Execute() + follows the edge for the port it advances on
  • FTUERuntimeContext — Bundle of live scene systems (DialogueManager, ScreenSwitcher, etc.) and SOAP assets passed to every node
  • FTUECompletionStore — Single gate for "has player finished FTUE?"; reads cloud (UGSDataService.FtueRepo) + local PlayerPrefs mirror

Cloud Integration

  • FTUECloudData — Serializable model for completion + resume state (CurrentPhase, LastNodeId)
  • FTUEProgressRepository — Cloud key "FTUE_PROGRESS" repository
  • UGSDataService — Added FtueRepo property

Documentation

  • FTUE_GRAPH_TOOL.md — User guide covering authoring workflow, node types, and validation

Implementation Details

  • Polymorphic SO design mirrors the project's Effect/Scoring-rule patterns; nodes hold no mutable state (all runtime state in coroutine locals + context)
  • Named ports enable branching (e.g., OnTimeout vs OnSuccess) without hardcoded indices
  • Event-driven completion (e.g., DialogueManager.OnDialogueFinished, GameData.OnMiniGameEnd) avoids polling and race conditions
  • Subscription cleanup via FTUERuntimeContext.RunCleanups() prevents event-delegate leaks onto persistent SOAP assets
  • Cloud + local mirror gating allows offline first-run while syncing across devices
  • Editor-only (#if !LINUX_BUILD) for the three editor tools; runtime code is platform-agnostic

https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz

claude and others added 16 commits June 30, 2026 18:36
…e breadcrumb

Recreate the XP/Quest progression system per the Quest Track + Breadcrumb design.
Quest completion is now the only progression currency and the progression spine is
the single driver of the Call-to-Action breadcrumb.

C1 — Remove XP entirely:
- Delete ParticipationXpAwarder, XPTrackView, SO_XPTrackData, SO_XPTrackReward
  (+ assets) and the ParticipationXpAwarder component in Bootstrap.unity.
- Strip GetXP/AddXP/OnXPChanged from PlayerDataService; drop participationXpPerGame
  from SO_ProgressionConfig. The cloud PlayerProfileData.xp field is left dormant.

Retire the old quest stack:
- Delete Quest, QuestSystem, UserJourneySystem, SO_QuestChain (+ assets) and remove
  the SO_QuestChain field from SO_TrainingGame.

Generalize the unlock model:
- Rename SO_GameModeQuestData -> SO_UnlockData and SO_GameModeQuestList -> SO_UnlockList
  (script GUIDs + field names preserved so authored assets keep their data). Add a
  FeatureKind enum (GameMode/Vessel/IntensityTier/Screen/Captain/Episode/UIElement),
  FeatureRef, UnlockKey, and the breadcrumb fields CallToActionTargetID /
  CompletionUserAction / DependencyTargetIDs + BuildCallToAction().

KEY WIRE — progression drives the breadcrumb (C2):
- GameModeProgressionService funnels every change through RaiseProgressionChanged,
  which recomputes the active frontier and lights its authored CallToAction,
  retracting the previous one (single guidance channel).
- CallToActionSystem gains RemoveCallToAction, guards double-activation, and keeps
  dismissed callbacks so a target can re-light.

C3 — continuity law:
- CallToActionTarget blooms (scale + fade in) on activate and withers on dismiss via
  DOTween instead of instant SetActive.

Author breadcrumb data on the 6 unlock assets (the 4 game modes point at their
PlayGame* card via ArcadeMenu; the Vessel Hangar Screen node points at HangarMenu).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
…breadcrumb design

Review follow-up.

- Fix IsVesselHangarUnlocked: test the persistent done signal (IsUnlockObjectiveDone —
  a completed quest stays at max intensity) instead of the transient CompletedQuests set,
  which ClaimQuestAndUnlockNext empties on claim. The old conjunction was unsatisfiable, so
  the hangar (and its new breadcrumb, and the hangar feature gate) never unlocked.
- Document the intentional CompletionUserAction=None on game-mode frontier breadcrumbs:
  multi-play quests stay lit until the objective is met (progression-owned), not dismissed
  after a single play via fragile event ordering.
- Add Docs/QUEST_TRACK_AND_BREADCRUMB.md (architecture, content chain, in-editor wiring
  checklist, v1 boundaries); update MENU_PROGRESSION_AND_IAP.md and Analytics/DATA_INVENTORY.md
  to drop the removed XP track and rename SO_GameModeQuestData/List -> SO_UnlockData/List.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Drop GameModeQuest_WildlifeBlitz from SO_UnlockList and delete the asset; the chain
is now CrystalCapture -> HexRace -> Joust -> PartyGame(placeholder) -> VesselHangar.
Update the doc chain tables to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Set defaultMaxIntensity 2 -> 3 (config asset + SO default). Intensities 1, 2 and 3
are now playable the moment a mode unlocks; completing the intensity-3 goal unlocks
intensity 4 and finishes the quest. The intensity-2->3 branch in RecordIntensityPlay
is now inert (never fires while the floor is 3). Docs updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Add Assets/_Graphics/UI/CTA_Glow_Outline_Cyan.png (the breadcrumb ActiveIndicator —
9-slice neon border, spriteBorder 88) and Card_Frame_Cyan.png (sci-fi frame for the
game-mode card, spriteBorder 74). Both import as Sprite (Single) with 9-slice borders
preset via their .meta, so they stretch to any element size.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
- Replace the cyan CTA highlight with CTA_Glow_Outline_Green.png (neon green, 9-slice
  rectangular outline glow, spriteBorder 66).
- CallToActionTarget now runs a continuous glow pulse while active (alpha yoyo, or a
  subtle scale yoyo when the ActiveIndicator has no CanvasGroup), tunable + toggleable,
  on top of the existing bloom-in / wither-out. Resumes on menu re-entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Card_Frame_Cyan.png now fills its interior with an opaque dark-navy vertical gradient
(was a transparent-center outline) and uses a much subtler glow. Same file/GUID/9-slice
meta, so existing wiring is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Adds a ScriptableObject node-graph system for authoring the First-Time-User-
Experience as a branching flowchart, an IMGUI editor to build it, a runtime
runner that executes it against existing systems, cloud-synced completion
persistence, and a generator for the canonical onboarding flow.

Extends the existing Assets/FTUE scaffold (reuses TutorialUIView / FTUEIntroAnimator /
FTUEEventManager) and replaces the flat, non-branching TutorialSequenceSet with a graph.

- Graph model: FTUEGraphSO + polymorphic FTUENodeSO (+ FTUEEdge/FTUEPorts/FTUERuntimeContext)
  with 15 node types: PlayIntro/Outro, ShowInstruction, Dialogue, EnterFreestyle,
  ExitFreestyle, WaitForInput, HighlightCTA, LockModes, Navigate, WaitForGameLaunch,
  WaitForGamePlayed, Wait, SetPhase, End — each mapped to a real runtime system.
- FTUEGraphRunner: first-run gated on GameData.OnClientReady + cloud completion, edge-based
  advancement, per-node SOAP subscription cleanup (no leaked delegates).
- Editor: FTUE Graph window (node canvas, port wiring, per-node inspector, live validation),
  Create Default FTUE Graph generator (authors the described flow end-to-end), and a
  Setup Runner In Scene helper that auto-resolves references.
- Cloud persistence: FTUECloudData + FTUEProgressRepository wired into UGSDataService
  (key FTUE_PROGRESS) with a PlayerPrefs mirror via FTUECompletionStore.
- DialogueManager.OnDialogueFinished event so dialogue nodes advance without polling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…h tool

Renames the FTUE graph system to Quest Graph (GUID-preserving) and rebuilds it
around the design plan: a QuestSO holds ordered phase graphs; the graph is the
source of truth driving CTA breadcrumbs, GameModeProgressionService, dialogue,
and per-node UGS persistence.

- Phase model: QuestSO (ordered QuestPhaseGraphSO phases with designer notes);
  QuestPhaseEndNode advances phases, QuestEndNode completes the quest.
- New nodes: WaitForIntensity (tier gate), WaitForModeUnlocked (claim gate),
  UnlockMode (direct progression write), WaitForUserAction (generic gate);
  WaitForGamePlayed gains mode + min-intensity filters. Node categories,
  tooltips, and live field summaries on every node.
- Runner v2: runs a quest across phases with exact mid-phase resume from UGS,
  records every completed node (QuestProgressCloudData, key QUEST_GRAPH_PROGRESS),
  and owns guidance while running via GameModeProgressionService.BreadcrumbSuppressed.
- Progression service: public UnlockMode(mode) + breadcrumb suppression window.
- Enums/hooks: CallToActionTargetType ProfileMenu/EpisodeMenu/PlayGameMaelstrom;
  UserActionType ViewProfileMenu/ViewEpisodeMenu/UnlockVessel; ScreenSwitcher
  fires ViewProfileMenu on Profile navigation.
- Quest Graph Editor (FrogletTools ▸ Quest Graph Editor): cached asset lists +
  validation (no per-frame AssetDatabase hits), cursor-anchored wheel zoom,
  middle/alt-drag pan, content-sized node cards, category colors + legend,
  hover tooltips, drag-to-connect with spawn-and-connect, quest/phase panel
  with reorder, default asset locations (no file dialogs), F-frame/Delete keys.
- Generator: FrogletTools ▸ Quest Graph ▸ Create Main Quest builds the full
  6-phase FTUE plan (onboarding/CC → HexRace → Joust → Maelstrom → vessel tour
  → episodes finale) with notes baked in.
- Docs: QUEST_GRAPH_TOOL.md; shareable/editable progression map at
  Docs/QuestMap/QUEST_MAP.html (data embedded via Save-as-HTML).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
- Enable/disable switches at every level (test harness): QuestSO.questEnabled
  (runner never starts a disabled quest), QuestPhaseGraphSO.phaseEnabled
  (runner skips disabled phases), QuestNodeSO.nodeEnabled (runner passes
  straight through disabled nodes via their next edge). Toggles in the left
  panel rows, node card headers, right-panel inspectors, and node context
  menu, with dimmed/OFF visuals and an entry-node-disabled validation warning.
- Quest inspector gains Rename Asset and Reset Local Progress (PlayerPrefs
  mirror) controls.
- Removed the Standalone Graphs section and the standalone graph creation
  button — phase graphs now exist only as quest phases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
Code contracts for the five designer-built UIs, wired into the graph:

- QuestInstructionView — lightweight control-teaching overlay (plain text +
  NiceVibrations haptic pulse, CanvasGroup fade). ShowInstruction nodes now
  drive it (new fields: haptic preset, minDisplaySeconds, hideOnAdvance;
  next-press removed) with the legacy TutorialUIView as fallback; runner
  hides it at phase/quest boundaries.
- QuestDialoguePanelView — IDialogueView with captain portrait, typewriter
  body, Next (complete-then-advance) and Skip (fast-forward set); slots into
  DialogueViewResolver's MainMenu channel for Dialogue nodes.
- QuestRewardRevealView — IDialogueView for the Reward channel: profile-screen
  panel populated from the set's RewardData, Continue steps lines and closes.
- QuestToastNotifier — achievement toasts through ToastNotificationAPI: mode
  unlocked, intensity tier, quest-track objective met, quest-graph phase and
  quest completion (templates + toggles serialized).
- FTUEEventManager gains OnQuestPhaseCompleted / OnQuestCompleted, raised by
  the runner at phase/quest boundaries.
- UserActionTrigger gains optional triggerOnEnable so panels (e.g. the episode
  panel inside profile) fire their UserActionType on open.
- Runner/setup expose + auto-resolve the instruction view; default-content
  generator updated for the new ShowInstruction fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…nels, control icons

Redesigns the Phase 0 in-flight tutorial to the new control curriculum:
sticks-outward speed up, sticks-inward slow down, movement-stick look-around,
LT+RT drift, skim 10 prisms (live counter), and press-B exit — the player is
never forced out of freestyle except by their own B press.

- QuestInstructionView: keyed CanvasGroup panels (designer-built instruction
  sets with icons, cross-toggled by ShowInstruction's new panelKey) + a
  progress counter ("3 / 10") for counting gates.
- New gates: QuestWaitForDriftNode (IVesselStatus.IsDrifting sustained) and
  QuestWaitForSkimNode (rides the shared skim-boost SOAP channel, filtered to
  the local vessel and to boost INCREASES so per-frame decay raises don't
  count; drives the live counter).
- Success haptics: WaitForInput/WaitForDrift/WaitForSkim pulse a configurable
  HapticType when the player performs the correct action (per-skim pulse
  separate, default off — the skimmer's own haptics effect covers it).
- QuestExitFreestyleNode gains forceExit (+retry/timeout): pairs with a
  WaitForInput(Button3/B) gate so the exit fires exactly on B.
- Runner/context/setup expose the skim-boost event asset.
- Control icon sprite set (white, tintable, animatable parts) at
  Assets/_Graphics/UI/ControlIcons: thumbstick base/cap, chevron arrow,
  composed outward/inward pulls, look-around stick, LT/RT triggers, B button.
- Generator Phase 0 rewritten to the new sequence (panel keys authored);
  design map (Docs/QuestMap/QUEST_MAP.html) updated with the flight school
  and embedded as the file's data revision.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
- QuestPhase0UIWirer (FrogletTools ▸ Quest Graph ▸ Wire Phase 0 UI): wires the
  hand-built Menu_Main UI in place — InGameInstructionSet/Container children
  become keyed instruction panels (flight-school order, mapping logged), a
  starter skim ProgressText is created if missing, DialogueSetUI gets
  QuestDialoguePanelView with captain/body/next resolved by heuristics and is
  plugged into the dialogue resolver, QuestToastNotifier lands on the runner,
  then the standard runner setup re-resolves references.
- DialogueViewResolver: optional per-channel override slots (any IDialogueView
  MonoBehaviour) so the new panels take over MainMenu/Reward channels without
  replacing the existing concrete views; validated in OnValidate.
- QuestExitFreestyleNode hides the instruction overlay when the flight ends
  (all completion paths) so the exit prompt can't linger over the menu.
- QuestInstructionView only auto-grabs a fallback TMP in plain-text mode —
  with keyed panels the first child TMP belongs to a panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
… dialogue system retired from the quest path

Per design: the Main Quest no longer uses DialogueManager/DialogueSet assets.
QuestDialogueNode now carries its own lines (speaker + optional portrait
override + [TextArea] lines) and drives the DialogueSetUI panel directly.

- QuestDialoguePanelView: new PlayLines(speaker, portrait, lines, onComplete)
  self-driving sequence (typewriter, Next steps, Skip fast-forwards, hides and
  calls back after the last line), CancelIfPlaying for clean teardown, default
  captain portrait preserved across per-beat overrides. IDialogueView impl kept
  for optional legacy use.
- QuestRuntimeContext: DialoguePanel scene ref + prefab/parent fallback with
  lazy instantiation (GetOrCreateDialoguePanel); DialogueManager removed.
- Runner/setup wire the panel (auto-resolved); Phase 0 UI wirer no longer
  touches the dialogue resolver.
- Generator: every dialogue beat now ships with authored placeholder lines
  (maps tour, profile explainer, per-mode reward reveals, hangar tour, finale)
  — the MainQuest runs end-to-end with zero DialogueSet assets.
- Docs + design map updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants