Skip to content

Content pipeline

How content gets from designer brain to running game. Two halves: data assets (already authored), and the Blueprint authoring layer (in progress) that lets new verbs ship without C++.

Data assets

The shipping content layer. See Data assets for the conceptual intro and Authoring/RuneAuthoring for designer instructions.

Two classes today:

URuneDataAsset

One asset per rune word. Defines:

  • Display: RuneWord, EnglishDefinition, RuneVisualMesh.
  • WordType (NOUN or VERB) drives editor field visibility.
  • Noun fields: NounMesh, NounMaterials, bNounSimulatesPhysics, InherentEffectComponents, VerbComponentOverrides.
  • Verb fields: TwoWordEffectComponent, ThreeWordEffectComponent.
  • Split: bIsSplittable, RuneSplitData.
  • Audio: PickupSound, PlaceSound, SplitSound, ActivationSound.

Field visibility uses meta = (EditCondition = "WordType == EWordType::NOUN", EditConditionHides) so the inspector hides irrelevant fields based on word type. Designers see only what applies.

Convention: assets live under Content/Runes/ and are named DA_Rune_<WORD> (e.g. DA_Rune_TREE, DA_Rune_FLOAT).

UMergeRecipeDataAsset

For combine slots. Holds a TArray<FMergeRecipe>:

struct FMergeRecipe
{
    TArray<URuneDataAsset*> InputRunes;
    URuneDataAsset* OutputRune;
};

InputRunes order doesn't matter — the combine slot does set-membership matching. Multiple recipes per asset is fine; the combine slot iterates and fires the first match.

Convention: Content/Recipes/, DA_MergeRecipe_<purpose>.

Blueprint authoring layer

The "Blueprint engineer / tech designer" workflow exists to keep the rune system designer-extensible without forcing C++ for every new verb. Status today:

Authoring path Status
New rune word (data asset) shipped
New merge recipe (data asset) shipped
New noun (mesh + materials + inherent components) shipped — author the rune's data asset, optionally Blueprint-subclass the inherent component
New runeable object subclass shipped — Blueprint-subclass ARuneableObject
New slot variant shipped — Blueprint-subclass ARuneSlot (or one of the existing subclasses)
New verb effect component partial — Blueprint can subclass URuneEffectComponent for tuning, but tick logic still requires C++
New strategy not authorable in BP — strategies are stateless C++

The "partial" entry is the live project. URuneEffectComponent is Blueprintable and OnEffectApplied / OnEffectRemoved are BlueprintNativeEvent, so a designer-friendly verb whose only behavior is "spawn this Niagara, wait N seconds, undo" is buildable today in BP. Anything that ticks or interacts with physics still needs a C++ subclass first.

Roadmap: a small Blueprint base class per "verb category" (modifier, bidirectional, hazard) will be added so 80% of new verbs can ship without engine code. Tracked under Plan/DevelopmentPlan.

Asset naming and folder layout

The structure that's settled in:

Content/
  Blueprints/
    BP_RephraseCharacter
    BP_RuneCalculator           subclass per puzzle archetype
    BP_FireComponent            subclass with project's Niagara assigned
    BP_ClockDevice
    ...
  Runes/
    Nouns/
      DA_Rune_TREE
      DA_Rune_ROCK
      DA_Rune_CAMPFIRE
      ...
    Verbs/
      DA_Rune_FLOAT
      DA_Rune_ROTATE
      DA_Rune_IS
      ...
  Recipes/
    DA_MergeRecipe_*
  Input/
    IMC_Default
    IA_Move, IA_Interact, ...
  Levels/
    Rune Showcase
    L_Demo_*
  VFX/
    NS_Fire, NS_Discovery, NS_RingExpanding, ...
  Materials/
    M_*
  UI/
    WBP_HUD, WBP_RuneDefinition, ...

The exact paths float as content gets reorganized; this is the rough shape. Engineers should not be moving content folders around — coordinate with the tech designer / engineering producer.

How a designer ships a new rune

  1. Right-click in Content/Runes/Nouns/ (or Verbs/) → Miscellaneous → Data Asset → RuneDataAsset.
  2. Name it DA_Rune_<WORD>.
  3. Open the asset, fill in RuneWord, EnglishDefinition, RuneVisualMesh, WordType.
  4. Fill in word-type-specific fields (mesh + materials for noun; effect components for verb).
  5. Add to a slot's bSpawnWithInitialRune config or a memory palace assignment. The rune is now in-game.

No C++ rebuild. No engineer involvement unless a new verb effect component is needed.

Build and module dependencies

Source/Rephrased_Demo/Rephrased_Demo.Build.cs declares everything the runtime module needs:

  • Public: Core, CoreUObject, Engine, InputCore, UMG, Niagara, EnhancedInput.
  • Private: Slate, SlateCore.

UMG and Slate/SlateCore for the HUD and definition widgets. Niagara for fire, ring propagation, and discovery VFX. EnhancedInput for the input mapping context. New engine modules go in PublicDependencyModuleNames; rebuild the project after editing.

.uproject plugins

Currently enabled in Rephrased_Demo.uproject:

  • ModelingToolsEditorMode — editor-only blockout.
  • GameplayStateTree — reserved for future NPC scripting; not active.
  • Aura — disabled.

No third-party plugins in tree. Audio path will introduce the FMOD plugin when it ships (see Audio).

Source files

  • Source/Rephrased_Demo/RuneDataAsset.h
  • Source/Rephrased_Demo/MergeRecipeDataAsset.h
  • Source/Rephrased_Demo/Rephrased_Demo.Build.cs
  • Rephrased_Demo.uproject

Known constraints

  • No data validation pass. A noun with a null NounMesh or a verb with both effect-component fields null and a non-IS intent both ship as "broken" without compile-time warning. Adding asset validators is on the post-Gate-2 polish list.
  • Recipe matching is set-equality. Duplicate-input recipes (e.g. "two TREEs make one BIGTREE") need an extra int32 count field on FMergeRecipe::InputRunes — not currently supported.
  • Content/ reorganizations break references; the asset registry usually fixes them but full-content moves should still go through the tech designer.

Change history

  • 2026-05-23 — Gabriel Li — Default engineer sandbox: Rune Showcase (replaces L_Sandbox in tree example).
  • 2026-05-08 — Gabriel Li — Added baseline change history section for weekly wiki maintenance.