Puzzle design rules¶
Ten rules of thumb for any change that adds or edits a rune puzzle: a device, a noun, a verb, or an actor that reacts to one. The review server checks P1–P10 only for puzzle changes (puzzle devices, rune content under Content/Rephrased/Gameplay/Runes/, and rune code under Source/Rephrased/RuneSystem/); other changes receive G1–G6, and mixed changes use puzzle scope. Reviews remain advisory. The Rephrased MCP shows the rules to the engineer's coding agent when a task starts. Each rule has an ID so a review finding can cite it.
The short version: mechanics are the same for every puzzle of a noun, a puzzle's state changes only through its noun, and things react to events.
Two words carry most of the rules:
- Mechanics are which state a verb leads to from a given state. They belong to the noun and are the same on every copy.
- Presentation is how a state looks and how a change plays: mesh, scale, materials, motion, timing, and camera. It belongs to the device and can differ by level.
These are guidance, and no rule stops an engineer from working or submitting for review. An engineer who departs from any of the ten says why, and the lead decides when approving.
Exceptions¶
A change that departs from a rule carries the engineer's reason in its changelist description:
Exception P6: the water names the machine it powers, because two machines share one channel.
Exception P3, P9: prototype for the vertical slice; the button is replaced by a world rune next sprint.
The Rephrased MCP writes the line. The engineer's coding agent passes the rule IDs to request_review as rule_exceptions, the tool asks the engineer why, and the answer goes into the description and to the review server. An exception already in the description is not asked for again.
The review server lists a declared exception with its reason for the lead to approve or reject. A break with no exception line is a finding. P9 is a recommendation, so an undeclared P9 break is a warning; a state that is hidden on purpose says so in an exception line like any other.
The rules¶
P1. One noun, one set of mechanics¶
A noun has one rule table. The same verb, sent to a puzzle of that noun in the same state, ends in the same state on every copy in the game, so the player learns a noun once. Whether a verb's effect is permanent or temporary is part of the table: a rule under Rules or under Temporary Rules.
A noun has one device, BP_Puzzle_<Noun> in Content/Rephrased/Gameplay/PuzzleDevices/. A different shape or scale of the same noun, such as a giant tree or a ring-shaped tile, is a child Blueprint of that device and changes presentation only.
A placed puzzle sets its situation and its presentation:
- where it stands, and its starting Status;
- State Looks and Performances: the mesh, how far and how fast a part moves, and how long a temporary effect holds before it ends;
- level references such as a Cinematic Sequence;
- Accepts Drawn Runes, which decides whether drawn runes can reach this copy. It is the one per-copy setting that affects commands. It covers every verb at once, and it changes who can command the puzzle, never what a command does.
What a result physically does in a level follows from the copy's shape and place: a grown branch that bridges a gap or pushes a column is level design, and the tree still went from Bud to Grown.
- Signs of a break: a Blueprint with the same Noun that is not a child of the device; a component or setting on one copy, or in a child Blueprint, that makes a verb end in a different state, or that refuses a verb other copies accept in the same state (Accepts Drawn Runes aside); a hold time long enough to make a temporary effect stand in for a permanent one; a copy of a shared device in a
Developers/folder that the level depends on. - Do this: put the state and rule on the noun and the part on the shared device, so every copy has it. When two levels need a verb to do different things, give the noun two states.
P2. Anything a rune changes is a puzzle actor¶
An actor whose state a rune changes is a child of ARunePuzzleActor with a Noun on its RuneableObject: a Blueprint, or a C++ subclass when the device needs native logic. An actor that only reacts to puzzles takes no commands and has no noun: it is a plain actor that listens to them, such as a machine that runs while its water flows. A listener works its state out again from the puzzles it listens to, on BeginPlay and after a checkpoint restore, so it keeps nothing a save would lose.
- Signs of a break: a plain
AActorwith its own interact event that changes a puzzle; a puzzle-like actor with no noun, no status, and no save ID; a listener with state of its own that a checkpoint does not bring back. - Do this: parent it to
ARunePuzzleActor, or keep it a listener and move the state onto the puzzle it listens to.
P3. A puzzle's state changes only through its noun¶
A puzzle's state changes in one of two ways, and both end in a state the noun lists:
- The player commands it. A rune command reaches
URuneableObjectComponent::ReceiveCommand, a noun rule applies, and the puzzle plays its Performance: Animate to Look, or a Move, Rotate, or Rise behavior. This keeps Freeze, rejection feedback, and checkpoint saves working. Commands come from the player's runes, drawn or placed in the world. - The world sets it. A listener or controller calls
SetStatuswith a state of the noun. The puzzle takes that state's look and plays the matching Performance, the same one a rune would play for that result, and the log gets a warning naming the puzzle and both states. No noun rule is checked, so the designer who wires the change owns whether it makes sense. This is for anything the world does to a puzzle: light reaches a tree and it stops being shaded, a restored channel switches a Light puzzle on, a solved room repairs a distant step.
A noun lists a state by using it in a rule, as its Default Status, or under Additional States for a state only the world sets. SetStatus drops a tag the noun never uses and applies the rest, so the caller is responsible for passing a listed combination.
When the world and a rune can both set the same state, the last one to act wins. A state that must stay under the world's control gets its own tag and no rule that leads into it.
A performance is keyed by the result, so reaching a state plays the same thing whether a rune or the world caused it. A performance that should play for one way of arriving and stay quiet for another names its From Status.
The world path carries consequences, never a new player input. A button, lever, or trigger the player uses to change a puzzle is a command by another name, and is a rune.
- Signs of a break: a Blueprint function that calls
AddLocalRotationorSetActorLocationon a puzzle; a button or trigger the player uses that changes a puzzle; code that writes theStatusproperty withoutSetStatus; a state the noun does not list; a noun with no rule for the verb the level relies on. - Do this: for a player action, add the rule to the noun and a Performance to the device, and send the verb from a world rune or a drawn one. For a consequence, add the state to the noun and call
SetStatusfrom the listener or controller.
P4. A condition is a status¶
When something decides whether a verb works, it is a state of the noun. A state with no rule for a verb rejects that verb. The thing that knows the condition sets the state with SetStatus, as in P3, and the rules do the rest. The state belongs to the noun, so every puzzle of that noun can be in it and treats it the same way. Which state a puzzle is in comes from its situation: its starting Status, or what the world does to it. Two puzzles of a noun behave differently only when they are in different states. Frozen on Water is the pattern: a second tag combined with the base state.
A detector that sets a condition is a part like any other: it goes on the shared device, so it acts on every copy of the noun. Adding one is a shared edit, and P8 applies: puzzles already placed keep behaving as they did. When only some copies should take part, taking part is itself a state the noun lists, carried by a tag that stays on the puzzle while the condition comes and goes. It is never a component added to one copy, and never something the detector remembers.
- Signs of a break: a checkbox such as "requires X" on a component; C++ that returns false for one specific status or verb; a hidden boolean that changes what a rune does; a detector added to one placed copy; a detector that remembers which puzzles take part.
- Do this: add the state to the noun, leave the blocked verb without a rule in that state, and set the status from the thing that knows the condition.
P5. React to events¶
An actor learns about a change from an event when one exists: OnStatusChangedNative, a begin and end overlap pair, or a broadcast the changing actor fires. It checks once on BeginPlay for the starting state. Tick runs only for continuous motion while that motion is active.
Some conditions have no event: whether light or shadow reaches a point, a line of sight, a distance. These are sampled when the answer matters, in this order of preference: when a related event fires, when a command arrives, or on a slow timer of a few checks a second. A command-time sample binds CanReceiveCommand, sets the status from what it finds, and returns true, so the noun's rules still decide the result. That hook takes one binding, so a puzzle has at most one command-time sampler.
- Signs of a break: a looping timer or Tick that re-checks something a delegate or an overlap already reports, such as another puzzle's status or whether two components overlap; a fast timer where a command-time check gives the same result.
- Do this: bind the event, the way
UMuralPuzzleControllerComponentbinds its tiles andAPuzzleLightBlockerVolumehandles overlaps. Sample only what has no event.
P6. Physical links are detected; authored links are listed in one place¶
Two kinds of relationship connect actors, and each has its own home.
- Physical. One actor affects another because of where they are: an overlap, a flow, a light's reach, a line of sight. The relationship is detected with the events and samples in P5. A reference list on the detector is an optional filter a designer fills in to narrow the choice, and the feature works with it empty.
- Authored. A designer decides that one thing unlocks another: three restored systems wake a central light, each solved room repairs a step of a distant staircase. Nothing in the world can detect this, so it is a list of references, set in the level, on one listener or controller.
UMuralPuzzleControllerComponentis the pattern: it lists the tiles and lights it waits for and the world rune it switches on.
A controller holds the references to its inputs and its outputs. It listens to the inputs and acts on the outputs in one of two ways: it sets a status, as in P3, or it switches a world rune on or off so a command becomes available to the player. A controller is its own component or actor and can sit on any actor in the level. A puzzle device's own Blueprint does not hold a reference to another actor in order to push state onto it.
- Signs of a break: a reference standing in for something physical, such as a machine told which tree its light reaches; puzzle devices holding references to push state onto each other; a reference assigned in BeginPlay that overrides the one set in the level; a physical link that stops working when a level designer moves or swaps a neighbor.
- Do this: detect what is physical and keep its list as a filter. Put an authored chain on one controller that lists its inputs and outputs.
P7. The core stays generic¶
URuneableObjectComponent, ARunePuzzleActor, and URuneDataAsset know nothing about one feature. A feature plugs in through the existing hooks: OnStatusChangedNative, OnRuleAppliedNative, and the capture and restore delegates, which any number of features can bind. CanReceiveCommand takes one binding per puzzle and is for the command-time sample in P5. CanApplyRule belongs to ARunePuzzleActor, which uses it for the one-performance-at-a-time lock and Accepts Drawn Runes; a feature leaves it alone. A condition that can be a state follows P4 and needs neither. A new behavior is a URunePuzzleBehavior subclass.
The puzzle actor knows three things directly: it calls TileBreakEffects, it names Status.Broken for broken pieces, and it offers IsLightOn. That list does not grow; a new feature binds a hook.
- Signs of a break: a core file that gains a feature's header; a core function that searches for one component class or names one more status tag; a feature that binds
CanApplyRule; a general-sounding component that only handles one noun. - Do this: bind a hook from the feature's own class.
P8. Shared edits are additive and declared¶
An edit to a shared noun or device leaves every puzzle already placed in the game behaving as it did. The changelist description names each shared asset and core class it touches, and the changelist holds one feature.
- Signs of a break: a changed default status or an edited existing rule; a description that names one feature while the files show two; a shared Blueprint that references an asset in someone's
Developers/folder; leftover files from an earlier attempt. - Do this: add states and rules alongside the existing ones, list the shared files in the description, and split unrelated work into its own changelist.
P9. A state the player can read (recommended)¶
A state that changes what a verb does should show in the world: a different look, a light, an effect, or a situation the player can see, such as a tree standing in a dark room. Two puzzles of a noun that respond differently should also look different. A state can stay hidden when the design calls for it, and the change says so in an exception line.
- Signs of a break: a state whose State Looks row matches another state's while a verb's result differs; a puzzle that rejects a command with nothing on screen to explain why.
- Do this: give the state its own look, or make the cause visible in the level.
P10. A change comes with its proof¶
A new state, rule, or behavior arrives with an automation test for the rule, a checkpoint save and restore check, and a wiki update: the status catalog for a new tag, the noun's page for a new rule.
- Signs of a break: a new
Status.*tag with no test that uses it; a new state with no wiki entry; puzzle state kept outside Status that a checkpoint does not capture. - Do this: add the test beside the feature's other tests, save and reload in PIE, and update the wiki in the same changelist.
Order of preference¶
When a puzzle needs something new, reach for the first of these that works:
- Data on the noun: a state or a rule.
- The shared device: a component, State Looks, Performances, or a few nodes. A child Blueprint when only the shape or scale differs.
- A new
URunePuzzleBehavior. - New C++ outside the core: a listener, a controller, or a puzzle subclass, bound to a hook.
- A change to the core, agreed with the puzzle lead first.
A placed puzzle is never where mechanics go. It sets what P1 lists: its situation and its presentation.
For reviewers¶
A finding names the rule ID, the file or asset, and the evidence it rests on. A P9 break is reported as a warning, and a declared exception is listed with its reason for the lead. P1, P3, P5, P6, and P9 often show only inside a Blueprint graph or a placed actor, so a finding about an asset rests on an Unreal observation of that asset. Without one, the asset is uninspected and the finding says so.
Related pages¶
Change history¶
- 2026-10-06 — Gabriel Li — First version: ten rules, the exception line, the order of preference, and reviewer notes.