StoryCraft
StoryCraft
What effective storytelling looks like in TropeLang.
| Mechanical | Grammar | What is legal? |
| Protocol | Style guide | What is well-formed? |
| Application | this guide | What is good storytelling? |
A file can gate clean, follow every style rule, fire every trope it targets at conf 1.00 — and still read as a thin story. In this guide we will discuss the difference.
1 · The trope is the recognition, not the unit of composition
It may be a tempting workflow for a writer to construct with trigger-first writing: pick the target
tropes, look up each rule's when: clause, allocate one beat to deposit exactly those facts,
and move on. It works — every recognition fires — and it produces a story shaped like a checklist. The pattern is
recognizable and indicative of a thin story. The tell is structural: scenes with a single beat, each servicing
exactly one rule, characters who exist only as bundles of precondition tags.
// The scene exists to fire the rule.
char winston [+Protagonist]
char the_doorbell [+Antagonist]
scene the_button {
beat 6 {
evt the_ring [&Provokes(agent=the_doorbell, target=winston)]
winston [+Enraged]
// Berserk_Button -> done, next trope
}
} The same recognitions fire when the scene is a dramatic unit — setup, turn, consequence:
// Setup, turn, consequence — the trigger lands inside it.
char winston [+Protagonist]
char sam [+Deuteragonist]
char pat [+Caregiver]
char the_doorbell [+Antagonist]
set the_couch_corner
set the_window
scene the_button {
beat 6 { // setup: the household at rest
sam @ the_couch_corner
winston @ the_window // his post; the street is HIS street
sam [#Doubting] // carried in from the dog park
}
beat 7 { // turn: the provocation
evt the_ring [&Provokes(agent=the_doorbell, target=winston)]
winston [+Enraged]
evt the_borkening [&Crushes(target=sam)]
sam [#Frayed] // a new KIND of state, not "more upset"
}
beat 8 { // consequence: the comfort, and the bond that earns it
evt the_scoop [&Embraces(agent=pat, target=winston)]
winston [-Enraged]
pat -- sam : "She bought the book."
}
} Rule of thumb: write a scene the director could shoot, then check which tropes it fires — not the reverse. Use the trigger lookup (§9) as validation, not planning.
2 · Beats progress; scenes develop
A beat is the engine's tick — the smallest unit of narrative time. A scene with one beat is a scene where nothing develops; it states. Real scenes move through phases — setup (who is here, what they want, what they carry in), turn (the event that changes something), consequence (the new state, the reaction, the cost). That is 2–4 beats minimum. A single-beat scene is a deliberate effect — a smash cut, a stinger — and should read as the exception.
The accretive log rewards this: state asserted in the beat it becomes true, retracted ([-Tag])
in the beat it stops, intervals scoped per beat (style §7). A one-beat
scene throws that machinery away — everything becomes simultaneous, and the engine sees a tableau, not a
progression.
3 · Every beat does at least two jobs
Efficient storytelling braids threads. In any good scene the A-plot moves and a relationship shifts and a seed gets watered — in the same beats. A scene that advances exactly one thing is a skipped opportunity the audience feels as thinness. Concretely, each beat should advance at least two of:
- Plot — an
evtthat changes the situation; - A relationship — an edge asserted, relabeled, or severed (
a -- b : "…"); - A character state — a tag accrued or retracted, a transition between named conditions;
- A seed — a latent
?…?fact or named ambiguity referenced, complicated, or advanced toward payoff; - A place / thread token — presence (
@) that sets up a later scene.
When a beat does only one of these, either braid a second thread into it or merge it into a neighbor.
4 · Characters evolve between distinct states — no sliding spectra
Avoid numbers. TropeLang's numeric stats exist for the realtime-game bridge (HP, AC,
dice — the ^ arena); in a storytelling context an invented magnitude encodes nothing. There
is no unit of grief, no scale of pride. A salience=6 that becomes salience=8 is
false precision wearing the costume of development — the reader of the graph learns only that the author
typed a bigger number. (Style §8 makes the same call for qualitative
^ stats.)
Character development is a walk through named, qualitatively distinct states — asserted in the beat each becomes true, retracted in the beat it stops. Pride doesn't shrink; it shatters in stages, each a different kind of state:
char sam [+Haughty]
scene the_shedding { beat 3 { sam [+Defensive] } } // the joke armor goes on
scene the_herding { beat 5 { sam [-Defensive] sam [#Doubting] } } // the armor cracks
scene the_breaking { beat 8 { sam [#Humbled] sam [#Teachable] } } // it breaks — a different kind Each transition is an event the story can witness, a fact a rule can read, a moment a director could shoot. "Slightly more humiliated" is none of those. Where a module genuinely requires a number (a few corpus rules compare numeric slots), treat it as an enum and quarantine it: comment the named rung it indexes, write the minimal relation the rule reads once, and never vary it over time as if it measured something. A number the corpus never compares should be deleted.
5 · Tend your seeds
Planting is cheap; the style guide already says to front-load latent facts and named ambiguities. The storytelling failure is plant-and-forget: a seed asserted in the preamble and touched exactly once more, at the payoff. The graph then holds a setup and a resolution with no middle — and the payoff is unearned everywhere except in the comments.
char vale [+Grifter]
concept justice
?vale [~Pursues(goal=justice)]? // planted now; surface it by re-asserting at the turn Between planting and payoff, re-touch every seed at least once:
- reference the ambiguity from a beat (a contingent
*…*reading that keeps the question alive); - deepen the latent fact — give it a contingent sibling mid-story;
- let a character act in a way only explicable by the seed — the graph shows the cause when the resolve lands.
A seed that is never watered should get a middle touch or be cut.
6 · Encode the story; comment the annotation
The // layer is invisible to the engine, to drams, and to recognition. If a story moment
matters — the forty minutes of barking, the eleven apologized-to strangers — it must exist as an
encoded fact: an event, an edge, a state change, a presence. The comment annotates
why the fact is there; it never substitutes for it.
The test: delete every comment, then re-read the file as the engine sees it. Whatever vanished from the story was never in it.
7 · Read drams as an editorial report
tropelang drams <file> measures density × coverage: how much of what you encoded
participates in a recognized pattern. Two editorial readings:
- The gap list is your dead-threads report. Every uncovered fact is something you declared that no pattern picked up — an unused presence edge, a relationship that never figured in a recognition, a gauge asserted once. Each is a thread to develop (braid it into more beats until a rule covers it) or a declaration to cut. A long gap list with single-beat scenes means the structure is thin, not that the corpus is missing tropes.
- Score by revision, not by target. A first structural draft landing ~0.4 is normal; braiding threads and adding intra-scene progression should raise it. If a revision adds facts and the score drops, you added decoration, not story.
Free recognitions are the reward signal for real structure: a properly built crush-and-relief arc earns
TraumaCongaLine_Broken without targeting it; the character on the floor surrounded by
consequences earns HeroicBSOD. When unplanned tropes fire at high confidence, the structure
is genuinely load-bearing.
8 · Know the recognizer's grain (and write with it)
Recognition is shape-based; a few mechanics are worth writing with:
- Shared-verb binding resolves by coverage, not file order.
When two rules trigger on the same verb (e.g. both on
&Crushes), the recognizer binds each to the event whose entities best satisfy its discriminator — so two tropes whose discriminators sit on different entities but ride the same verb both fire (recognition binds them the same wayevaldoes). The corollary: this works because discriminators are contrastive (next point) — make them so and the right event binds itself. - The discriminator must ride a bound event role (style §8). Static tags on entities no event binds are invisible to coverage; when braiding threads, make sure each trope's distinguishing entity is named in a role of its trigger event.
- Sibling vignettes cross-fire. If your scene is structurally a cousin of another trope in the same family, expect it in the suggestions at ≤0.75. That's correct — only investigate when a cousin confirms at 1.00.
Debug with bisection: when an expected trope is silent, reproduce its trigger in a minimal file, confirm it fires alone, then add back the story's other facts until it goes quiet. The last addition is the collision.
9 · The workflow, revised
- Premise and cast first. Who wants what; what stands in the way; what the audience carries away. Pick the spine trope (the one the story IS) and 3–6 supporting tropes at other scales.
- Look up the triggers for every target — read the actual
ruleblocks. If two targets share a verb, give them contrastive discriminators on the entities they care about (§8), so recall binds each to its own event. - Outline scenes as dramatic units — setup/turn/consequence, 2–4 beats each, each braiding ≥2 threads. Place the trigger events where the drama puts them. Use the full
arc ▸ act ▸ scene ▸ beatspine: acts (and the arc) are first-class, taggable scopes the engine sees and recognizes over — not formatting. Group scenes into acts that carry a turn, and tag the arc itself when the story-as-a-whole is part of what a trope reads. - Draft, then verify three ways with the cli or the editor:
validate(legal) →suggest(the targets fire, at full confidence, with the right bindings) →drams(coverage; read the gap list). - Revise against the gap list — develop or cut every dead thread; deepen gauges; water seeds. Re-run drams; the score should rise.
- Prose pass last.
dialogannotations carry the voice — the graph is the structure, the prose is the performance. Annotations are transparent to recognition, so this pass cannot break the structure.
Companion documents: the grammar for the language, the style guide for authoring protocol.