Teaching Haiku to Write a Screenplay
How one Claude Haiku call turns an article into a 3–5 scene JSON script — and why that file, not the GPU, runs the whole machine.
The most important file in my reel pipeline is written by the cheapest model I pay for.
It costs about a tenth of a cent. It takes one API call. And every other stage — the voice, the captions, the motion, the GPU doing the expensive work in Part 6 — does exactly what this one file tells it to.
That file is a screenplay. This post is how Claude Haiku writes it.
Part 1 drew the whole machine: a published article in, a 9:16 MP4 out, five stages between. This is Stage 1 — Scenario — taken slowly.
By the end you’ll know the prompt, the JSON contract every downstream stage reads, and the cache trick that makes re-rendering free.
Preferred to watch? Here is 30 seconds TLDR.
Hi, I’m Daniel — a software engineer, solo builder, and the person behind Digital Craft Workshop.
I’ve spent ten years writing TypeScript, .NET, and React for a living, and the last few of them building things alongside the day job: B2B SaaS, AI tools like Article Forge, internal infrastructure, and a Unity 2D narrative game. Some shipped. Some I killed. Both are useful.
Digital Craft Workshop is for developers, AI builders, and indie founders who’d rather understand the craft than ride the hype — the kind of reader who likes Domain-Driven Design, distrusts gurus, and wants AI that’s cheap, practical, and accountable to one engineer in a workshop.
Each essay is something you can read in one sitting and use the same week: an architecture pattern, an AI workflow a single developer can actually run, a build log, or a postmortem on a project that didn’t make it. Built carefully. Explained plainly. Owned by you.
Why a screenplay, not a summary
The instinct, when you want a video out of an article, is to summarize. Shorten the text, read it out loud, done.
That produces a worse article, not a video.
An article and a reel are different media. An article is read — the eye can re-scan and slow down. A reel is heard and watched, once, at the speed I decide, while a thumb hovers over the next post. The two need different shapes.
So Stage 1 re-cuts the article instead of shortening it. It writes a screenplay. A hook that stops the thumb in the first two seconds. Three or so body beats, each landing one idea. A one-line CTA at the end. Each beat is a scene — a single narration line, a scrap of on-screen text, a color.
This is the only stage in the whole pipeline with editorial judgment. Everything downstream is mechanical. It runs what Stage 1 wrote.
Stage 1 is the one place where something decides what the reel says and in what order. Decide badly here, and the best GPU in the world animates a bad video beautifully.
That’s why the JSON file matters more than the GPU. The GPU is horsepower. The screenplay is the script, the cast, and the edit.
The prompt is a director’s brief
Haiku doesn’t get a chat. It gets a brief — a system prompt that casts it in a single role: convert a published blog article into a vertical-format short-form video script. No personality, no conversation, one job.
The brief is strict on purpose. It pins three things.
Scene roles, in fixed order. Scene 1 is always the hook. The middle scenes are body beats. The last scene is always the CTA. Haiku doesn’t get to invent the structure — only to fill it.
A brutal hook rule. The hook gets its own paragraph of constraints: one short sentence, five to nine words, maximum, landing in under 2.5 seconds. Open on a surprising number or a contradiction. And a blacklist — never start with “Hi”, “Today”, “In this video”, “Let me”, “So I”. The first three words decide whether anyone sees the fourth.
Output JSON, nothing else. No preamble, no “here’s your script!”, no markdown fences. Just the object.
The scene count and word budget aren’t hardcoded — the brief has slots that get filled at call time from the target length. Ask for a 40-second reel and the slots resolve to three-to-five scenes and a tight word budget; ask for longer and both grow. Same prompt, different dials.
One thing the brief never sees: HTML. Before the call, the article’s markup is stripped to plain text and capped at 16,000 characters. Haiku reads prose, not tags. A long article gets truncated rather than blowing the budget.
Then one call to claude-haiku-4-5-20251001, 3,000 max tokens, and a screenplay comes back.
The JSON contract
Here’s what comes back — trimmed to two of its five scenes:
{
“scenes”: [
{
“id”: 1,
“narration”: “Two dollars. That was the whole signal.”,
“headline”: “The $2 hook”,
“visualKind”: “stat”,
“visualText”: “$2”,
“accent”: “orange”
},
{
“id”: 2,
“narration”: “A memory service I’d half-forgotten was billing me every night.”,
“headline”: “The silent charge”,
“visualKind”: “title”,
“visualText”: “STILL RUNNING”,
“accent”: “teal”
}
],
“totalWordCount”: 135,
“targetDurationSeconds”: 55
}Every field earns its place.
narrationis the line my cloned voice will read.visualKindis one oftitle,stat,bullet,quote,cta— tells the visual stage what kind of card to build.visualTextis the handful of words that actually appear on screen.accentpicks a brand color: teal by default, orange for surprise, navy for the calm beats.headlineis an internal label that never appears anywhere — it’s there so I can read the JSON.
This object is the contract. Stage 1 is the only stage that writes it. Stages 2 through 5 only read it. The voice stage pulls narration. The caption stage pulls narration again once it has the timing. The visual stage pulls visualKind, visualText, and accent.
Nobody reaches past the JSON to ask Haiku a follow-up question. The model is done the moment the file is written.
Because four stages depend on it, a malformed screenplay can’t be allowed through. So the JSON goes through a validator before anything else touches it.
It must be an object. It must hold between 3 and 10 scenes. And every scene must have non-empty narration.
Miss any of that and the render fails loudly, here, at Stage 1 — instead of quietly three stages later, when the video tool downstream chokes on a scene with no audio.
One real run, end to end
Part 1 mentioned a single render end to end — my post “The $2 Bill That Made Me Self-Host My Memory”, about 1,400 words. Here’s what Stage 1 actually did with it.
Haiku read all 1,400 words — stripped to plain text, well under the 16,000-character cap — and returned five scenes totalling about 135 words of narration. One call. Roughly a tenth of a cent.
{
"scenes": [
{
"id": 1,
"narration": "Two dollars charge that changed everything..",
"headline": "The surprising spike",
"visualKind": "stat",
"visualText": "$2",
"accent": "orange"
},
// ... 3 body beats ...
{
"id": 5,
"narration": "Full story on substack. Link below.",
"headline": "Read full article",
"visualKind": "cta",
"visualText": "Read on Substack",
"accent": "navy"
}
],
"totalWordCount": 112,
"targetDurationSeconds": 61
}The hook it wrote was “Two dollars charge that changed everything.” — seven words, a number first, no throat-clearing. That is the brief working: a model left alone would have opened with “So a couple of weeks ago I noticed…” and lost the viewer before the sentence finished.
Two dollars. That was the whole signal. Five scenes, validated, written to disk. The screenplay for a 55-second video, contracted before a single byte of audio existed.
The cache that makes re-renders free
Here’s the part that turns this from a neat trick into a tool I use daily.
A reel is never right on the first render. I re-render to fix a caption color, retime a scene, swap a background. If every re-render re-ran Haiku and re-billed the voice API, iteration would cost money — and I’d stop iterating. I’ve watched that exact dynamic kill side projects.
So the screenplay JSON gets cached, and so does the audio for each scene. And here’s the key. The per-scene audio cache is keyed on the narration text itself, not on scene number or position.
That choice is the whole game. Scene numbers are positional; reorder the scenes and the numbers shift even though the spoken words didn’t. The narration string is the audio. Same words always map to the same audio.
So re-render the same article and change only the caption style. Every narration string is byte-identical.
Every scene’s audio cache hits. Haiku is never called again — the screenplay JSON is already on disk. The re-render costs $0 in AI credits.
Change a single word in one scene’s narration and only that scene’s key stops matching. That one scene gets fresh audio.
The other four still hit the cache. You pay for exactly what you changed — one scene, not five.
(There’s a ?fresh=1 escape hatch for when I want the whole thing rebuilt from scratch.)
A typical evening of tuning — six or seven re-renders chasing a color — costs the price of the first render and nothing after.
What’s still missing
At the end of Stage 1 I have a screenplay. It’s structured, validated, cached, and it knows exactly what the reel should say, beat by beat.
It is also completely silent.
The narration field is a string. To become a reel it has to be spoken. And it has to be spoken with millisecond timing, so captions can light up word by word in sync. That’s what Part 4 needs.
A voice clip alone isn’t enough. I need a voice clip and a record of the millisecond every single word starts and ends.
That’s the obstacle Part 3 takes on. Clone my voice on a $5-a-month plan, and get back the one feature most text-to-speech tools won’t give you on a budget tier: per-word timestamps.
Next Week, Part 3: how a two-minute voice sample becomes narration with millisecond timing — and why I actually came for the timestamps, not the audio.
One question before then: when you turn writing into video, what writes the script — you, a model, or a template? Tell me in the comments.
If “the cheapest model writes the most important file” is a trade-off you’d make in your own pipeline — restack this. Someone in your feed is about to over-engineer the part that should be cheap.





