Dialogue was already plain text, so the gap was never the .yarn files. It was
that the character material a writing session needs was either missing or stored
somewhere a writer could not comfortably work.
Three things were wrong. The writing handbook was not in the repo and was cited
by SC101.yarn as though it were. The best voice material — register, verbal tics,
success/failure/passive samples — was a \n-escaped string inside a JSON field.
The named NPCs had no sheets at all, existing only as their Yarn lines.
writing/ now holds the dialogue-facing layer, at the repo root so it gets no
.meta files and is not a Unity asset:
STYLE.md register, the five tone moves, the ban list, branching
shapes, the Wrong Truth rule, flag families, candidate rules
YARN-PRIMER.md the one page of syntax needed to write a scene
GLOSSARY.md in-world and project vocabulary
voices/ the eleven skill voices, one readable sheet each
characters/ Bartender, Chevalier Cassian Thal, Bradford Kane
scenes/ SC-101's brief: intent, beats, checks, constraints
lore/ the three identity readings and the rules that bind them
STYLE.md is a digest of the Mystery Writing Handbook in the Obsidian vault, with
pointers rather than copies. The vault stays the authoring home for design work,
and Ground Truth — the solution document — deliberately stays out of this repo.
The voice sheets are generated from skill_bible.json but are the source of truth
for the prose. tools/writing/sync_voices.py folds edits back; voicelib.py
guarantees notes -> dict -> notes is identity for all eleven, so --to-json on
unchanged sheets is byte-identical. VoiceSheetSyncTests fails the build on drift
in either direction, and was verified to fail on real drift rather than merely
to pass.
SC101.yarn's header is trimmed from prose rationale to the six rules that bind
while editing that file, with the reasoning moved to the scene brief.
EditMode 42/42. YarnCheck compiles 9 files / 35 nodes.
Co-Authored-By: Claude Opus 5 <[email protected]>
63 lines
2.9 KiB
Markdown
63 lines
2.9 KiB
Markdown
# The eleven voices
|
||
|
||
One sheet per skill. A skill in this game is a **character**, not a stat: it wants something for
|
||
you, and it is wrong about something. Both halves matter — the wrongness is what makes it a
|
||
voice instead of a hint system.
|
||
|
||
## These files are generated — and they are still the source of truth for the prose
|
||
|
||
Each sheet has two halves, with truth flowing in opposite directions:
|
||
|
||
| Half | Direction | Who edits it |
|
||
|---|---|---|
|
||
| The **prose** — domain, what it wants, what it's wrong about, register, tics, voice samples | `.md` → `skill_bible.json` | **you** |
|
||
| The **machine fields** table | `skill_bible.json` → `.md` | an engineer, in the JSON |
|
||
|
||
So: edit the prose here, freely. Then run, from the repo root:
|
||
|
||
```bash
|
||
python3 tools/writing/sync_voices.py --to-json
|
||
```
|
||
|
||
That folds your words into `Assets/Skills/skill_bible.json`, which Unity turns into the
|
||
`SkillDefinition` assets the game reads. Never edit the JSON prose directly — the markdown wins,
|
||
and your JSON edit would be overwritten the next time anyone syncs.
|
||
|
||
To check without changing anything:
|
||
|
||
```bash
|
||
python3 tools/writing/sync_voices.py --check
|
||
```
|
||
|
||
The EditMode suite runs the same check (`VoiceSheetSyncTests`), so drift fails the build rather
|
||
than quietly shipping a voice that no longer matches its sheet.
|
||
|
||
Hard-wrapping a paragraph is fine — lines within a section are rejoined on sync.
|
||
|
||
## The cast
|
||
|
||
Four opposed pairs plus three specialists. Opposed pairs are a writing engine: fire both halves
|
||
with contradictory readings and the scene generates its own friction.
|
||
|
||
| Pair / group | Voice | Voice | The argument |
|
||
|---|---|---|---|
|
||
| Reason | [PROVENANCE](provenance.md) | [CONFLUENCE](confluence.md) | Is the world legible? |
|
||
| Body | [HOUSE POUR](house_pour.md) | [THE LONG SHIFT](long_shift.md) | What do we owe the flesh? |
|
||
| Social | [FACEWORK](facework.md) | [PLACEMENT](placement.md) | Is understanding others care, or leverage? |
|
||
| Self | [AMNESTY](amnesty.md) | [STANDING ORDER](standing_order.md) | Should we keep doing this? |
|
||
| Specialist | [UNDISCLOSED](undisclosed.md) | [THE FLOAT](the_float.md) | — |
|
||
| Specialist | [ROOM TONE](room_tone.md) | | — |
|
||
|
||
**Budget scene outputs against eight, not eleven.** CONFLUENCE, AMNESTY and STANDING ORDER
|
||
generate almost no clues by design — they are the interior register and the deduction engine.
|
||
The clue-producing cast is the other eight.
|
||
|
||
## Writing a voice well
|
||
|
||
- It **advocates**, it does not report. Even when it is right, the line is its own biased reading.
|
||
- Respect its forbidden domains. Each sheet ends with the domains that voice must not comment on.
|
||
PROVENANCE does not discuss appetite. That is characterisation, not bookkeeping.
|
||
- A failing voice sounds exactly like a succeeding one. See `../STYLE.md` §4.
|
||
- Passive lines are 1–3 sentences and carry most of the personality — aim for 60–70% of all
|
||
skill text to be passive.
|