Plots, variables and triggers
Plots
plots.json describes optional story structures. A plot has an ID, name, premise, status, pressure policy and beats. Beats are opportunities or developments with conditions and guidance; they are not commands to force an outcome.
Good plots answer:
- What unresolved situation can enter play?
- What signs can appear before direct confrontation?
- What changes if the player ignores it?
- Which outcomes should close or transform it?
The pacing system selects a small nudge when play lacks direction, respects cooldowns and rejection, and does not advance every active plot at once. Session progress records introduced and rejected material separately from the authored definition.
Variables
variables.json declares typed values used by conditions and tools. Initial values may be supplied by the world or relevant entity. Use variables for facts that need deterministic tests, such as whether an alarm is active or how many seals remain.
Do not turn prose state into variables merely because it can be counted. Relationships, knowledge, placement and item state already have dedicated models.
Triggers
triggers.json defines deterministic reactions to state and story conditions. A trigger has conditions, effects, repetition rules and optional timing. Triggers complement agent judgement: they are appropriate when the same condition must always cause the same world-state change.
A cue or beat is told when its audience next acts or the game master next looks, which can be a turn or two after the trigger fired. Two optional parts make it say what is true then, not what was true at the time of firing:
- A
whilecondition uses the same form aswhenand must still hold when the cue or beat is delivered. Otherwise, the cue or beat is withdrawn, and the chat settings record the reason. In a cue,"@self"means the character receiving it. For example,{"type": "place", "character": "@self", "location": "cellar"}prevents a cue from reaching someone who has left. - Within
text, names can use{character:key},{place:key},{item:key},{where:character},{holder:item},{value:variable},{value:variable:subject}and{time}. The last four forms insert a character's location, an item's holder or location, a value in words, or the current time. They are resolved when the cue or beat is delivered. If a referenced thing no longer exists, the cue or beat is withdrawn instead of guessing.
{ "type": "cue", "characters": ["clara-whitlock", "arthur-moore"],
"while": { "type": "place", "character": "@self", "location": "bar" },
"text": "You smell gas; {holder:lantern} still has the only light." }
A time condition may use an absolute from or to, a daily window, weekdays in days, and the shared calendar rules in on. The latter supports months, dates, spans, seasons, named holidays and exclusions. See Calendar and day rules. A time condition with both days and on must satisfy both.
Validate all referenced entity and variable IDs. Trigger effects run against session state, never the authored world files.
Beats that have the world author make a person
A beat can ask the world author to create a person instead of sending text to the game master. Set "dispatch": "author", then give the beat a need and text. The need explains why the author is being called: arrival for someone entering the scene, introduction for someone already nearby, or one of scene_change, object, variable and trigger. The text describes the new person.
To pick a type in code, add a draw list and place [draw] in the text. The author runs after the trigger's turn, so the new person enters the scene on the next turn. The game master is not asked to create them. Every beat in a trigger dispatched to the author must use this form. Older files that put a sentence in need still work: the sentence moves to the start of text, and need becomes arrival.
{ "key": "follower", "name": "A follower comes",
"when": { "type": "variable", "variable": "command_recruit", "op": "eq", "value": true }, "repeat": true,
"effects": [{ "type": "beat", "dispatch": "author", "need": "arrival", "text": "A newcomer: [draw]", "draw": ["a lost traveller", "a rival spy"] }] }
Slash commands
commands.json defines words the player can type after a slash, such as /recruit. Each command has a word made from letters, digits or underscores, plus a description shown to the game master when the command is used. The game reserves ooc and roll. A word outside lowercase ASCII also needs a key for its flag.
{ "commands": [
{ "word": "recruit", "description": "Bring a new follower into the cult." },
{ "word": "招募", "key": "recruit_zh", "description": "Same, written in Chinese." }
] }
Every command declares a hidden flag variable command_<key>, which is up only in the turn the command was typed and down again at the start of the next one, so a trigger waiting on it fires every time the command is used. A trigger can then ask the world author for a person, set a variable or give the game master a beat. A variable of the same name in variables.json is refused.