shisaku ~/devlog
$ auth github

Author sign in

Sign in with GitHub to comment on devlog entries.

Continue with GitHub
← all posts

# Devlog #13 — Leitmotif, or the Tool Learns to Direct

Building the whole authoring app on top of the contract — timeline, inspector, live stage, pickers, export — and the quiet satisfaction of a loop that finally closes on itself.

Devlog #13 — Leitmotif, or the Tool Learns to Direct

Date: July 1, 2026

Focus: Building the whole authoring app on top of the contract — timeline,

inspector, live stage, pickers, export — and the quiet satisfaction of a loop that

finally closes on itself.


Last time I made the scene file into something a second program could hold. This

time I built that second program until it could hold a whole scene — and then hand

it back to the game, unbroken, on purpose. There is a specific kind of joy in

watching a system close a loop it was designed to close. It is not loud. It is the

feeling of a door latching into a frame that was cut to fit it.

The app is called Leitmotif, which is the right word for a tool that arranges

recurring, deliberate themes into a whole. It lives in its own repository, nested

as a submodule, so none of its weight ever leans on the game. It talks to the game

through exactly three things and refuses to learn a fourth.


1. A Timeline You Can Shove Around

The first real milestone that felt like directing was the node-graph timeline.

A sequence becomes a row of steps, left to right, and each step holds its beats as

cards you can pick up and drop somewhere else — into a later step, into a parallel

lane, wherever the moment wants them.

The temptation with drag-and-drop is to make it clever. I made it obvious instead:

drop-zones that light up, a card that dims while it’s in the air, and one function

in the document model that owns every reorder so nothing else is allowed to have an

opinion about where a beat lives. When there is exactly one place that moves a

thing, moving things stops being frightening.


moveBeat(seqId, si, bi, toStep, toIndex) { */* the only path a beat may travel */* }

That is a boring line. Boring lines are how you earn the right to have interesting

features later.


2. Forms That Build Themselves

The inspector was the part I most wanted to cheat on, and most glad I didn’t. A

beat has a verb and a handful of fields, and the fields differ per verb. The lazy

version hand-writes a form for each verb and then rots the moment the engine grows

a new one.

Instead the form reads the generated schema for each field’s type and description,

consults a small map for which fields a verb even uses, and assembles itself.

Add a field to a beat in the engine, regenerate the schema, and it simply appears

in the app with its help text attached. The map that remains — the part the schema

couldn’t supply, because the engine parses those strings at runtime — is small and

honest about being small. I would rather have one visible seam than a hundred

invisible ones.


3. The Stage That Does Not Lie

Then the piece the whole architecture had been quietly building toward: a stage

where the writer scrubs time and watches the actors move.

The important word is truthful. The stage does not approximate what the game

does; it draws frames computed by the game’s own headless evaluator. A companion

enters from off the right edge, walks to her mark, turns, and stops — and it is the

same arithmetic the real game will run, minus the sprites. Because of that, the

preview is allowed to be trusted, which is the only thing that makes a preview

worth having.


$ choreo preview scene.toml eve_walk_in_demo

  eve  (2810,1080) -> (2070,1080)   # off-screen east, then home to her mark

I drew it small — markers, name labels, facing arrows, a dashed camera frame that

pans and zooms. No art, just truth. The art comes later; the truth had to come

first.


4. Never Make Them Type an Id

A tool for non-programmers earns its keep in the moments it refuses to punish them.

So actors, targets, and sounds became pickers, fed by the game’s actual data —

thirteen characters, twelve-hundred-odd sound cues — offered as suggestions the

writer chooses from, while still allowing a typed id for the modder who’s inventing

something new. Forgiving without being rigid. The app should meet the writer where

they are, not where a parser would prefer them to be.


5. The Loop Closes

And finally the gold button: Export to game. It does one careful thing before it

does the obvious one — it validates, and if the scene has a problem it writes

nothing and says why, in a sentence a person can read:


  error  sequence 'bad' triggers on_sequence_finished of unknown sequence 'does_not_exist'

That refusal is the whole point. The writer can be as bold and wrong as they like

inside the editor, and the game will only ever receive scenes that are whole. The

freedom and the safety live in the same button, which is exactly where they should

live.

Author a scene, press the gold button, and the game plays what you made. The loop

that started as “make the file serializable” ends as "hand the game a finished

scene it can trust." Everything in between was just earning the right to that

sentence.


6. The Part I Am Allowed to Be Proud Of

I held this whole thing to one bar, stated plainly: be so intuitive and so

specialised for directing this game that we out-class the generic tools. Not by

having more buttons — by having fewer, better ones, a preview that doesn’t lie, and

an interface that teaches as it’s used. I don’t think we’re finished against that

bar. I think we’ve built something honest enough that finishing is now a matter of

polish and taste rather than architecture, which is the good kind of unfinished.

If I reduce it to one sentence: the game learned to be directed the day the tool

learned to hand it a scene without breaking it.

The scenes were always possible. Now they’re authorable — by someone who has

never seen a bracket, and never has to.

$ comments

Reader notes

0 notes

No notes yet.

If you're reading this as a developer: this devlog is built in the open.

If you're reading this as a modder: the direction is source-visible, inspectable systems.