Endless Cascade Game World¶
Core UE5 game world with audio, characters, and environmental content.
This document will be auto-updated by Minh when code changes are detected.
Feature Repositories¶
endless-cascade→ project_id:the-smithy1/core/endless-cascade
Code Paths to Explore¶
Config/**inendless-cascadeContent/**inendless-cascade
Claude Code Templates¶
Development templates live in .claude/templates/ and define conventions for Blueprint authoring, MCP tool usage, content organization, and C++/Blueprint responsibility splits. Four templates are currently in place.
Blueprint-Artist Defaults¶
Template: .claude/templates/blueprint-artist-defaults.md
Establishes the principle that the Blueprint designer must reflect the actual runtime default state. If C++ overrides a widget's visibility at init time, the Blueprint designer value must match — not show a placeholder "full layout" view.
Core rules:
- Visual properties belong in Blueprint. Colors, padding, font sizes, opacity, and text content are set only in the Blueprint designer. C++ never overrides these at init time.
- C++ owns runtime state and structural layout. Visibility toggling on state change, slot sizing, anchor positioning, and event binding remain in C++.
- Dynamically created widgets are exempt. Widgets created via
NewObjectin C++ (e.g., CloseButton in InventoryWidget) have no Blueprint template, so their styling must remain in C++.
Inventory system reference widgets: WBP_Inventory, WBP_EquipmentSlotPanel, WBP_EquipmentSlotItem, WBP_InventorySlot, WBP_AvatarDropZone, WBP_ItemDetailPanel, WBP_DraggedInventoryItem.
Initial visibility defaults — Blueprint designer values must match C++ initial state:
| Widget | C++ Initial State | Blueprint Must Show |
|---|---|---|
EquipmentPanelContainer |
Collapsed | Collapsed |
DividerBorder |
Collapsed | Collapsed |
EmptyStateOverlay |
Set by item count | Collapsed |
ItemDetailPanel |
Collapsed | Collapsed |
EquipHintText |
Collapsed | Collapsed |
UPROPERTY categories for artist-facing tunables:
Category = "Inventory|Audio" → Sound cues, volumes
Category = "Inventory|Layout" → Visibility toggles, spacing, ratios
Category = "Inventory|Tutorial" → Hint timers, onboarding
Category = "Inventory|CloseButton" → Dynamic close button styling (C++ created)
Category = "Inventory|AvatarMode" → Avatar-centric mode settings
Category = "Equipment Slot|Icons" → Slot type icon mappings
Category = "Item Detail|Layout" → Panel width/height ratios
All should be EditDefaultsOnly with appropriate meta constraints (ClampMin, ClampMax, EditCondition).
Example — C++ controls initial state:
// C++ header — default matches what the player sees on open
UPROPERTY(EditDefaultsOnly, Category = "Inventory|Layout")
bool bShowEquipmentPanel = false; // Panel starts hidden
// C++ runtime — applies the default
EquipmentPanel->SetVisibility(bShowEquipmentPanel
? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
Blueprint designer: EquipmentPanel Visibility = Collapsed
Data-driven properties use representative placeholders (e.g., "Item Name" not empty string, placeholder icon not None).
Blueprint MCP Tooling¶
Template: .claude/templates/blueprint-mcp-tooling.md
Best practices for constructing Blueprint logic via unreal-mcp tools. These apply when an AI assistant is building or modifying Blueprints through the MCP server — not to hand-authored Blueprints.
Available MCP node tools (22 tools):
| Tool | Creates | Use For |
|---|---|---|
add_blueprint_event_node |
K2Node_Event |
BeginPlay, Tick, custom events |
add_blueprint_input_action_node |
K2Node_InputAction |
Enhanced Input action responses |
add_blueprint_function_node |
K2Node_CallFunction |
Calling any function on a target |
add_blueprint_variable |
Variable | Adding Blueprint variables |
add_blueprint_get_self_component_reference |
K2Node_VariableGet |
Getting a component ref from "self" |
add_blueprint_self_reference |
K2Node_Self |
Getting a reference to the owning actor |
add_blueprint_cast_node |
K2Node_DynamicCast |
Type casting (Cast To X) |
add_delegate_binding |
K2Node_AddDelegate |
Binding callbacks to multicast delegates |
add_component_event_override |
K2Node_ComponentBoundEvent |
Overriding C++ component events |
add_branch_node |
K2Node_IfThenElse |
Boolean conditional branching |
add_switch_node |
K2Node_Switch* |
Switch on enum, int, string, or name |
add_foreach_loop_node |
K2Node_MacroInstance |
ForEach loop over arrays |
add_make_array_node |
K2Node_MakeArray |
Construct array from individual pins |
add_make_struct_node |
K2Node_MakeStruct |
Construct struct from individual pins |
add_break_struct_node |
K2Node_BreakStruct |
Split struct into member pins |
add_variable_set_node |
K2Node_VariableSet |
Set a Blueprint variable |
add_variable_get_node |
K2Node_VariableGet |
Get a Blueprint variable |
set_pin_default_value |
Pin default | Set default value on an input pin |
disconnect_blueprint_nodes |
Pin disconnect | Break an existing connection |
delete_blueprint_node |
Node deletion | Remove a node from the graph |
connect_blueprint_nodes |
Pin connection | Wiring any two nodes together |
Not yet available: K2Node_Select (value selection by index/enum), K2Node_ExecutionSequence (ordered multi-exec).
Key rules:
- Prefer Select over Switch when mapping an enum to a value (not to different execution paths). Use Switch only when each case triggers genuinely different execution logic.
- Use high-level composite tools (
wire_component_event_to_widget_function,bind_component_delegate_to_function) over manual multi-node wiring when they fit the pattern. - Compile once at the end — call
compile_blueprintafter all node additions and connections, not after each individual node. - Read before modify — call
get_blueprint_event_graphbefore adding nodes to understand the current graph; callget_blueprint_componentsbefore adding components to avoid name collisions. - Use
find_blueprint_nodesto avoid duplicates before creating event nodes.
Graph layout conventions: Left-to-right execution flow. Events at X=0, logic/routing at X=300–600, function calls at X=600–900, terminal nodes at X=900+. Vertical spacing ~150 units between parallel chains.
LFS locking: The MCP server automatically locks .uasset files via Git LFS before any modification command runs. Read-only commands (get_*, find_*, list_*, validate_*, take_screenshot) never lock. If someone else holds the lock, the command returns an error with the lock holder's identity. Locks are released by pre-push hooks, CI pipelines on MR merge, or manual git lfs unlock.
Error recovery:
- Node creation fails: Verify target component exists (
get_blueprint_components), check function name case-sensitivity, ensure prior additions were compiled. - Connection fails: Inspect actual pin names via
get_blueprint_event_graph, verify type compatibility, disconnect existing connections on single-connection input pins first. - Compile fails: Check for unconnected required pins, verify cast targets resolve, ensure no circular variable references.
Blueprint Event Graph Standard¶
Template: .claude/templates/blueprint-event-graph-standard.md
Defines the C++/Blueprint responsibility split: C++ owns state and math, Blueprint owns visuals and audio. C++ defines BlueprintNativeEvent lifecycle hooks; Blueprint overrides them to sequence artistic responses. See the template for the canonical AShimmerEffectActor / BP_ShimmerEffect reference implementation.
Content Hierarchy¶
Template: .claude/templates/content-hierarchy.md
Defines the Content/ directory structure separating raw assets (under AudioAssets/, VisualAssets/) from gameplay Blueprints (under GameWorld/Blueprints/). Includes naming conventions (e.g., BP_, WBP_, M_, NS_ prefixes) and rules for feature subdirectory creation.
Drum Reveal System¶
The drum reveal is handled by UCascadeDrumRevealComponent (Source/EndlessCascade/Cascade/Room/Props/CascadeDrumRevealComponent.cpp/.h), a client-side component owned by CascadePlayerController. It manages the full lifecycle: finding drum actors by SmithyObjectId, animating them via Level Sequence, applying ethereal materials for non-triggering players, camera cutscenes, and pending-reveal polling for late-joining clients.
Ethereal-to-Revealed Fast Path (bDrumsAlreadyRaised)¶
When a non-triggering player joins a room where another player has already revealed drums, HandleHideDrums raises the drums to their final position and applies ethereal (ghostly) materials with collision disabled. A bDrumsAlreadyRaised flag (BlueprintReadOnly, Transient) is set before raising to gate subsequent behavior.
If this player later triggers their own drum reveal, HandleDrumReveal checks bDrumsAlreadyRaised and takes a fast path:
- Finds drum actors via
FindDrumsFromRevealData(which restores original materials from the Blueprint CDO archetype). - Re-enables collision on each drum actor.
- Returns immediately — no Level Sequence animation is played.
This avoids a redundant rise animation on drums that are already at the correct height.
HandleHideDrums (another player's reveal)
→ bDrumsAlreadyRaised = true
→ Drums raised + ethereal material + collision off
HandleDrumReveal (this player triggers later)
→ bDrumsAlreadyRaised == true → fast path
→ Restore materials, enable collision, skip animation
Level Sequence KeepState¶
The drum reveal Level Sequence (Content/Cinematics/LS_DrumReveal_v2) uses KeepState on its sequence sections so that animated transforms persist after playback ends. OnSequenceFinished no longer calls BakeDrumRevealOffset to manually re-apply the rise offset — the Sequencer retains the final positions automatically.
Runtime State Properties¶
| Property | Type | Access | Purpose |
|---|---|---|---|
DrumRevealActors |
TArray<AActor*> |
BlueprintReadWrite |
Drum actors bound to the current reveal |
DrumRevealRiseHeight |
float (default 300) |
BlueprintReadOnly |
Rise height from first drum's FDrumRevealInfo |
bDrumsAlreadyRaised |
bool (default false) |
BlueprintReadOnly |
True after HandleHideDrums raises drums; gates HandleDrumReveal to skip animation |
DrumRevealSeqActor |
ALevelSequenceActor* |
BlueprintReadWrite |
Spawned Level Sequence actor for the reveal |
RevealCameraSequence |
TSoftObjectPtr<ULevelSequence> |
EditDefaultsOnly |
Camera sequence — override in Blueprint subclass |
DrumRevealCutscene |
UCutsceneController* |
BlueprintReadWrite |
Active camera cutscene controller |
All runtime state properties use Category = "Drum Reveal" and are marked Transient (not saved/replicated).
Teach-Back System¶
The teach-back system (astrolabe#115 phase 5b) adds story-level reflection to the L2R (Learn to Read) flow. The player "teaches" Wisp by responding to prompts at L2R locations; Wisp reacts warmly, including on retry — this is never a quiz. The wire plumbing lives on ACascadePlayerController (Source/EndlessCascade/Cascade/Core/CascadePlayerController.h/.cpp); Phase 6 builds the UI that binds to these events.
Architecture¶
The teach-back flow mirrors the existing vocab dialogue pattern (ClientReceiveVocabDialogue / ServerSendWordDefine):
- Server dispatches a
dialogue_messagewith subtypeteach_back_promptorteach_back_reactionthroughFSmithyStructuredDialogueHandler::DispatchMessage. - The handler calls
ClientReceiveTeachBackDialogue(Client, Reliable RPC) which fires theOnTeachBackDialogueSubtypeBlueprintImplementableEvent. - The Phase 6 dialogue widget (
WBP_DialogueWidget,WBP_DialogueConversation) binds toOnTeachBackDialogueSubtypeand switches into reflection mode based onDialogueSubType. - On submit, the widget calls
ServerSendTeachBackResponse(Server, Reliable, BlueprintCallable RPC), which routesteach_back_responseto TheSmithy viaSmithyConnectionManager.
Server (TheSmithy)
→ dialogue_message { subtype: "teach_back_prompt" | "teach_back_reaction" }
→ FSmithyStructuredDialogueHandler::DispatchMessage
→ ClientReceiveTeachBackDialogue(Payload)
→ OnTeachBackDialogueSubtype(Payload) ← BP widget binds here
Player submits reflection
→ ServerSendTeachBackResponse(LocationId, ResponseText)
→ StampCharacterDbref(GI, Kwargs)
→ ConnMgr->SendCommandWithArgs("teach_back_response", ...)
FCascadeTeachBackDialoguePayload¶
Blueprint-accessible USTRUCT carrying the subset of dialogue_message kwargs that BP needs. Defined in CascadePlayerController.h (not SmithyParsedMessageData.h) because the BIE requires USTRUCT/UPROPERTY marshalling. All properties use Category = "L2R|TeachBack" and are BlueprintReadOnly.
| Property | Type | Default | Purpose |
|---|---|---|---|
DialogueSubType |
FString |
"teach_back_prompt" or "teach_back_reaction" — BP branches on this |
|
LocationId |
FString |
L2R location slug (e.g. "old-persey", "the-passion") |
|
Persona |
FString |
LLM persona identifier (e.g. "grit_mentee") |
|
CorrelationId |
FString |
Server-side correlation id linking prompt → response → reaction | |
Text |
FString |
Prompt text (on prompt subtype) or reaction text (on reaction subtype) | |
AudioUrl |
FString |
Narration URL; empty when no audio recorded yet | |
DurationSeconds |
float |
0.0 |
Audio narration duration in seconds |
MaxChars |
int32 |
500 |
Soft character limit for the reflection input field |
Placeholder |
FString |
Input field placeholder copy (authored per-location) | |
ResponseType |
FString |
Server RPC name for submitting the reflection ("teach_back_response") |
|
bExpectsResponse |
bool |
false |
Whether this subtype expects the player to submit a response |
ShimmerIntensity |
FString |
"low" / "medium" / "high" — Phase 7 reads this for shimmer VFX amplitude |
|
XpAwarded |
int32 |
0 |
XP awarded on success (0 on retry); Phase 7 reads for XP HUD |
FlagsSet |
TArray<FString> |
Flag names set server-side on success (informational on client) | |
bRetry |
bool |
false |
true → keep widget open + clear input; false → render reaction + close |
Character Identity Stamping (StampCharacterDbref)¶
Cascade's dedicated server uses a single shared WebSocket session to TheSmithy for all puppeted clients. This means self.get_puppet() on TheSmithy resolves to CascadeServer's own puppet, not the actual player. StampCharacterDbref (private helper on ACascadePlayerController) bridges this gap by reading the character ID from the player's USmithyPlayerSession (via USmithySessionManager) and inserting it as "character_dbref" into the OOB kwargs JSON.
The method no-ops cleanly when the session manager, session, or character ID are unavailable — TheSmithy falls back to self.get_puppet() in those cases (correct for non-Cascade callers like telnet/direct WS).
Used by ServerSendTeachBackResponse and intended for any future per-character OOB commands.
Console Test Command¶
A bench-test console command is available for testing the teach-back round trip before Phase 6 UI exists:
- First argument is the location slug (e.g.
old-persey). - Everything after is joined with spaces as the response text.
- Empty response is supported:
cascade.teach_back.respond old-persey "" - Finds the local
ACascadePlayerControllerand callsServerSendTeachBackResponse. - Logs
cascade.teach_back.respond: sending location='...' response_len=Non success. - Warns if no active world or no local controller is found.
Blueprint Events¶
| Event | Category | Fires When |
|---|---|---|
OnTeachBackDialogueSubtype |
L2R\|TeachBack |
Server delivers a teach-back prompt or reaction via ClientReceiveTeachBackDialogue |
Modified Blueprint Assets¶
The following Blueprint assets were updated to wire teach-back support:
| Asset | Path | Change |
|---|---|---|
BP_CascadePlayerController |
Content/GameModes/ |
Teach-back RPC wiring and event graph additions |
WBP_DialogueWidget |
Content/UI/Dialogue/ |
Teach-back event binding and reflection mode UI |
WBP_DialogueConversation |
Content/UI/Dialogue/ |
Conversation panel teach-back integration |
Alphabet VFX Pipeline¶
New visual assets support an alphabet particle effect system used in L2R surfaces:
| Asset | Path | Type |
|---|---|---|
T_Alphabetgrid |
Content/VisualAssets/Textures/Atlas/ |
Texture atlas — grid of alphabet glyphs |
M_Alphabet |
Content/VisualAssets/Materials/VFX/ |
VFX material sampling the alphabet grid |
NS_Alphabet |
Content/VisualAssets/Particles/ |
Niagara system driving the alphabet particle effect |
MI_Beacon |
Content/VisualAssets/Materials/Master/ |
Material instance for L2R beacon visuals |
Additionally, the following existing assets were updated:
| Asset | Path | Change |
|---|---|---|
BP_ShimmerBeacon |
Content/GameWorld/Blueprints/Rooms/Props/DynamicProps/ |
Blueprint updates (beacon visual refinements) |
M_L2R_Letter |
Content/GameWorld/Materials/L2R/ |
Material updates for L2R letter rendering |
Movement Feedback — err_traverse¶
When a player's proximity-triggered traverse attempt is blocked by an exit's traverse lock, the server sends an err_traverse message so the client can render in-world feedback. Without this handler, blocked traversals would be silent — the player overlaps the exit volume, the server refuses the move, but nothing is communicated back.
Implemented in TheSmithy!873 / endless-cascade#395, closing issues #944 and #945.
Backend Message Format¶
["err_traverse", [], {
"exit_id": "#1190",
"exit_name": "west",
"message": "The river stretches wide before you, its current steady...",
"routing_options": {
"scope": "player",
"target": "#3246",
"message_type": "err_traverse"
}
}]
| Field | Type | Required | Description |
|---|---|---|---|
exit_id |
string | At least one of exit_id/exit_name |
Smithy dbref of the blocked exit (e.g., "#1190") |
exit_name |
string | At least one of exit_id/exit_name |
Direction or key name (e.g., "west") |
message |
string | No | Lore-defined text from the exit's attribute |
routing_options |
object | No | Standard player routing (scope "player") |
The handler discards messages where both exit_id and exit_name are empty.
Message Category¶
err_traverse is registered as ClientEssential in SmithyMessageCategories, alongside err, msg, look, and other core feedback messages. It is never filtered by the message category system.
Dispatch Path¶
SmithyConnectionManager
→ FSmithyErrTraverseHandler::ParseMessage → FErrTraverseData
→ FSmithyErrTraverseHandler::DispatchMessage → DispatchWithRouting (player-scoped)
→ ACascadePlayerController::ClientErrTraverse (Client, Reliable RPC)
→ OnErrTraverseReceived (BlueprintImplementableEvent)
→ Blueprint widget renders floating text near exit actor
C++ Handler¶
FSmithyErrTraverseHandler (Source/EndlessCascade/Smithy/MessageHandlers/SmithyErrTraverseHandler.cpp/.h) extends FSmithyRoutedMessageHandler and follows the standard parse/dispatch pattern:
- ParseMessage extracts
exit_id,exit_name, andmessagefrom kwargs into anFErrTraverseDatastruct. Routing context is extracted via the base classExtractRoutingContext. - DispatchMessage uses
DispatchWithRoutingto forward the data to the correct player controller viaClientErrTraverse.
Registered in SmithyConnectionManager::RegisterCoreHandlers() for the "err_traverse" message type.
Parsed Data Struct¶
FErrTraverseData (in SmithyParsedMessageData.h):
| Field | Type | Description |
|---|---|---|
ExitId |
FString |
Smithy dbref of the blocked exit (e.g., "#1190") |
ExitName |
FString |
Direction/key (e.g., "west") |
Message |
FString |
err_traverse text from the lore-defined exit attribute |
RoutingContext |
TSharedPtr<FMessageRoutingContext> |
Player routing context |
Player Controller RPC¶
ACascadePlayerController (Source/EndlessCascade/Cascade/Core/CascadePlayerController.cpp/.h) exposes two functions for this feature:
ClientErrTraverse(ExitId, ExitName, Message)—UFUNCTION(Client, Reliable). Called server-to-client by the handler's dispatch lambda. Logs the event and forwards to the Blueprint event.OnErrTraverseReceived(ExitId, ExitName, Message)—UFUNCTION(BlueprintImplementableEvent, Category = "Movement|Feedback"). Implement in a Blueprint subclass to render feedback. The Blueprint is responsible for:- Iterating
ATeleportExitactors viaTActorIteratoror Get All Actors Of Class. - Matching on
SmithyObjectId == ExitId. - Spawning the feedback widget at the matched actor's world location.
- Applying tunable parameters (fade duration, vertical offset, text color, audio cue).
Note: Client RPCs cannot use the server-only FindSmithyObject path, so the Blueprint must locate the exit actor by iterating world actors and matching on SmithyObjectId.
Blueprint Assets¶
| Asset | Path | Purpose |
|---|---|---|
BP_ErrTraverseAnchor |
Content/GameWorld/Blueprints/Movement/BP_ErrTraverseAnchor.uasset |
World-space anchor actor for positioning the feedback widget near the blocked exit |
WBP_ErrTraverseBubble |
Content/UI/Movement/WBP_ErrTraverseBubble.uasset |
Floating-text widget that displays the lore-defined block message |
The BP_CascadePlayerController (Content/GameModes/BP_CascadePlayerController.uasset) implements the OnErrTraverseReceived event to orchestrate the anchor placement and widget spawning.
Caulking Tools Props — The Passion¶
Shipbuilding caulking tool props for The Passion room received a full art pass: dedicated PBR texture sets replaced previously baked-in diffuse textures, new material instances were created for each tool, and the prop static meshes were re-exported with significant size optimizations.
New Textures¶
Dedicated texture sets were added under Content/VisualAssets/Textures/, each in its own subdirectory following the content hierarchy convention. Each set includes a diffuse map (T_*) and, where applicable, an ORM (Occlusion/Roughness/Metallic) packed map (T_ORM_*):
| Asset | Path | Type |
|---|---|---|
T_BoatSchematics |
Content/VisualAssets/Textures/BoatSchematics/ |
Diffuse map for boat schematics prop |
T_ORM_BoatSchematics |
Content/VisualAssets/Textures/BoatSchematics/ |
ORM packed map for boat schematics |
T_Mallet |
Content/VisualAssets/Textures/Mallet/ |
Diffuse map for mallet prop |
T_ORM_Mallet |
Content/VisualAssets/Textures/Mallet/ |
ORM packed map for mallet |
T_OakumBundle |
Content/VisualAssets/Textures/OakumBundle/ |
Diffuse map for oakum bundle prop |
T_PitchPot |
Content/VisualAssets/Textures/PitchPot/ |
Diffuse map for pitch pot prop |
T_ORM_PitchPot |
Content/VisualAssets/Textures/PitchPot/ |
ORM packed map for pitch pot |
New Material Instances¶
Material instances were added under Content/VisualAssets/Materials/Instances/, sampling from the new dedicated texture sets:
| Asset | Path |
|---|---|
MI_BoatSchematic |
Content/VisualAssets/Materials/Instances/ |
MI_Mallet |
Content/VisualAssets/Materials/Instances/ |
MI_OakumBundle |
Content/VisualAssets/Materials/Instances/ |
MI_PitchPot |
Content/VisualAssets/Materials/Instances/ |
Updated Prop Meshes¶
Prop static meshes in Content/VisualAssets/Props/Tools/ were re-exported, resulting in significant size reductions (materials are now referenced externally via the new material instances rather than embedded):
| Asset | Path | Previous Size | New Size |
|---|---|---|---|
caulking-guide-scroll |
Content/VisualAssets/Props/Tools/ |
917 KB | 142 KB |
caulking-iron-and-mallet |
Content/VisualAssets/Props/Tools/ |
419 KB | 173 KB |
oakum-bundle |
Content/VisualAssets/Props/Tools/ |
1054 KB | 133 KB |
pitch-pot |
Content/VisualAssets/Props/Tools/ |
746 KB | 140 KB |
Updated Blueprint Actors¶
The dynamic prop Blueprints were updated to reference the new material instances and re-exported meshes:
| Asset | Path | Change |
|---|---|---|
BP_CaulkingIronAndMallet |
Content/GameWorld/Blueprints/Rooms/Props/DynamicProps/ |
Updated to use MI_Mallet and re-exported mesh |
BP_OakumBundle |
Content/GameWorld/Blueprints/Rooms/Props/DynamicProps/ |
Updated to use MI_OakumBundle and re-exported mesh |
BP_PitchPot |
Content/GameWorld/Blueprints/Rooms/Props/DynamicProps/ |
Updated to use MI_PitchPot and re-exported mesh |
BP_SeamMap |
Content/GameWorld/Blueprints/Rooms/Props/DynamicProps/ |
Updated to use re-exported caulking guide scroll mesh |
Updated Room Level¶
The Passion room level (Content/GameWorld/Blueprints/Rooms/RoomBase/Passion.uasset) was updated to incorporate the refreshed caulking tool props.
FAB (Floating Action Button) System¶
The FAB is a radial action menu for mobile platforms, managed by UFABController (Source/EndlessCascade/Cascade/UI/FAB/FABController.h/.cpp) and rendered by UFABWidget / UFABActionButtonWidget (Source/EndlessCascade/Cascade/UI/FAB/). It provides context-aware actions (Interact, Glean, Looper, Sense) arranged in a radial layout anchored to the virtual joystick position.
Blueprint Assets¶
| Asset | Path | Purpose |
|---|---|---|
WBP_FAB |
Content/UI/Widgets/FAB/ |
Main FAB radial menu widget |
WBP_FABactionButton |
Content/UI/Widgets/FAB/ |
Individual action button widget — implements hint dimming and restore animations |
DA_FABColorPalette |
Content/UI/Widgets/FAB/ |
Data asset overriding default color palette (FABColors:: namespace fallback) |
M_FAB_HintHalo |
Content/UI/Widgets/FAB/ |
Material for hint halo effect |
M_FAB_HintRipple |
Content/UI/Widgets/FAB/ |
Material for hint ripple effect |
WiggleCurve |
Content/UI/Widgets/FAB/ |
Animation curve for wiggle motion |
Hint System — Sibling Dimming¶
WBP_FABactionButton implements BP_OnDimAsSibling and BP_OnRestoreFromSibling (BlueprintImplementableEvents on UFABActionButtonWidget) to visually recede non-hinted buttons when a sibling button's hint is active. The Blueprint override maintains a bIsCurrentlyDimmed guard flag to prevent flicker from repeated PlayAnimation calls (UMG resets to keyframe 0 on each invocation).
The C++ wrapper (DimAsSibling() / RestoreFromSibling()) carries no state of its own — the BP is the authority on whether the button is already dimmed or restored.
Audio, Characters, and Environmental Content¶
This section needs expansion as relevant code paths in Config/** and Content/** are documented.
See Also¶
.claude/templates/blueprint-artist-defaults.md— Full Blueprint-Artist defaults checklist and anti-patterns.claude/templates/blueprint-mcp-tooling.md— Complete MCP node tool reference with common patterns.claude/templates/blueprint-event-graph-standard.md— C++/Blueprint event graph pattern and migration checklist.claude/templates/content-hierarchy.md— Content directory structure and naming conventions.claude/instructions.md— Claude Code development workflow and MCP tool development guide
Feature Repositories¶
endless-cascade→ project_id:the-smithy1/core/endless-cascade
Code Paths to Explore¶
Config/**inendless-cascadeContent/**inendless-cascade
Feature Repositories¶
endless-cascade→ project_id:the-smithy1/core/endless-cascade
Code Paths to Explore¶
Config/**inendless-cascadeContent/**inendless-cascade