-
-
Beat 5, CLOSE. Blocking held from a single staging sentence generated once for the scene.
-
Beat 2, MEDIUM. Marco enters, soaked. Wardrobe and faces recalled from the character sheets.
-
Beat 3, OTS. Same two people, different shot type — composition is free, identity is anchored.
-
Beat 1, WIDE. June alone, before Marco arrives. Drawn from the scene text alone.
-
Second scene, second location. Same faces, same coats, same voices — recalled from ClickHouse, not regenerated.
Inspiration
A screenwriter can read their own script a hundred times and never once hear it.
Storyboards cost thousands. A table read needs actors in a room. Both are gatekept by money and access, so scripts get judged as text, by people who cannot see or hear them. The writer least able to afford a table read is the one who most needs to know whether the scene plays.
I wanted the moment where someone presses play and hears their characters speak for the first time.
What it does
Give it one scene in Fountain — or let it write you one from a genre, a cast and a situation.
- Breakdown. A reasoning agent reads the scene the way a first AD would: four to six visual beats, a shot type for each, a physical description and a full wardrobe for every character, the fixed blocking of the room, and the tone the scene is played in. All inferred from the text. Nothing supplied by hand.
- Casting. Every character gets a reference sheet drawn once, and a distinct voice assigned deterministically.
- Storyboard. A panel per beat, each drawn against the character sheets, so the same people appear in every frame while the camera stays free to follow the shot type.
- Table read. The scene performed as multi-speaker audio, carrying the emotional direction the breakdown read out of the text.
- Animatic. Panels and audio muxed into something you can watch.
Run a second scene with the same characters and they come back with the same faces, the same clothes and the same voices — because they were recalled by query, not re-prompted.
How we built it
Google Cloud throughout. Gemini 3 Pro for reasoning and breakdown, Gemini 2.5 Flash Image for panels and character sheets, Gemini 2.5 Pro TTS for the multi-speaker table read. Orchestrated with the Agent Development Kit on Vertex AI: a root agent over breakdown, storyboard, table-read and assembly sub-agents, plus a ClickHouse toolset. FastAPI on Cloud Run, assets in Cloud Storage, ffmpeg for the mux, React and Vite for the front end.
ClickHouse is the production memory, and this is the part that makes it a system rather than a demo.
Every asset is written the moment it exists — panels, character sheets, table reads, animatics — each with its scene metadata, shot type, cast, tone and prompt. Writes go through clickhouse-connect. Reads go through the official mcp-clickhouse MCP server, wired into the agent graph as an ADK McpToolset, so the agent queries its own memory as a tool call rather than a hardcoded lookup.
Three things follow:
- Consistency is a query. Before generating anything, the breakdown agent asks ClickHouse who it already knows. A character's appearance, wardrobe, voice and reference sheet are recalled verbatim; the model does not get to re-invent them. This holds across scenes and across scripts, not just within one run.
- Nothing is generated twice. A returning character costs a
SELECT, not an image. - Runs are durable. Every stage transition is checkpointed, so a run survives a restart and replays from the gallery with its panels, audio and animatic intact.
A row store would have held the metadata. It would not have made the agent's memory a queryable surface, and the search — every night exterior, every beat played tense, every asset featuring a given character, across everything ever generated — is analytical work on analytical data.
Challenges we ran into
Image generation is throughput-limited in ways the quota console does not show. The visible limit read 0.01% used while every third call returned 429. The fix was sequential generation with exponential backoff, which turns a dead run into a slow one.
Cloud Run throttles CPU outside request handling, which starves a pipeline running as a background task. The MCP session timed out on the deployed service and never locally. It needed --no-cpu-throttling and two IAM grants that the developer's ADC had been quietly covering.
Version skew in a preview-stage SDK ecosystem. ADK 2.8.0 passes an MCP session timeout as a float; the mcp 2.x line expects a timedelta. The failure surfaced as a swallowed TaskGroup error with the real exception hidden.
A garbage collector closing a live HTTP transport. A genai.Client created as a temporary expression gets collected mid-request, closing the connection it is using. Invisible on the main thread, fatal in a worker pool. One local variable fixed it.
libx264 refuses odd dimensions. Deterministically cropping the model's drawn border off each panel produced a 1024×845 image, and the mux failed on a height not divisible by two.
Accomplishments that we're proud of
The agent recalls a character it drew in a different script and gives them the same face, the same coat and the same voice — through an MCP tool call it makes itself, against a real analytical database. That is a genuine memory, not a prompt trick.
And the fifteen seconds where a writer presses play and hears their scene performed. Everything else in the build exists to make that moment possible.
What we learned
Reference conditioning is not one mechanism. The first design chained each panel to the previous one for consistency. It worked — by producing near-identical frames. A shot specified as a close-up came back as a copy of the wide before it: identity preserved by making a duplicate. Per-character reference sheets fixed it. Appearance is anchored, composition is free, and panels can generate independently.
The model needs the scene's fixed facts, not just the beat. Characters swapped sides of the table between frames because nothing stated where they were. One staging sentence, generated once and reused verbatim in every panel, fixed continuity that no amount of describing the action could.
Negations are unreliable; descriptions are not. "No rain indoors" was ignored. "The camera is INSIDE the building; weather is visible only through the glass" was obeyed. Same with lettering on signage: prohibiting it failed, describing every surface as blank worked.
Some things should not be prompted at all. After three attempts to stop the model drawing a frame around each panel, the fix was ten lines of Pillow cropping it off. Not everything is a prompt engineering problem.
What's next for FIRST READ
- Direct the shot. Open any panel on a canvas, draw an arrow, circle a face, scrawl "closer, from behind" in your own handwriting — and the agent redraws that frame following the direction, keeping the character sheets, wardrobe and staging that made it consistent. The annotated overlay is kept beside the result as provenance.
- Temp score. A Lyria cue per scene, generated from the tone the breakdown already reads out of the text, mixed under the dialogue.
- Live progress and cancellation. Stage timings recorded to ClickHouse, so the estimate is a median over real run history rather than a guess, and a cancel that stops before the next billable stage rather than after it.
Individual entry. AGPL-3.0.
Built With
- agent-development-kit
- clickhouse
- cloud-run
- cloud-storage
- docker
- fastapi
- ffmpeg
- gemini
- gemini-tts
- google-adk
- google-cloud
- mcp
- model-context-protocol
- pydantic
- python
- react
- tailwindcss
- typescript
- vertex-ai
- vite

Log in or sign up for Devpost to join the conversation.