The complete guide to visual bibles
Two tables, one approval gate, and the single field that decides whether your scenes look like the same video.
A Visual Bible in VidFlow is one row per project plus two child tables — and it's the thing that decides whether your scenes look like the same video or six different short films stitched together. This post walks through what's in it, how it gets generated, and how downstream stages consume it.
The shape. The `VisualBible` row carries a `styleGuide` JSON (palette, composition rules, lighting notes), a `generationGuidance` text field (free-form notes the LLM uses when extracting), and two booleans — `isGenerated` and `isApproved`. Nothing downstream runs until `isApproved` flips true.
Characters. Each named character in the script gets a `VisualBibleCharacter` row with three image URLs: `portraitUrl` (single shot, neutral expression), `sheetUrl` (multi-angle reference), `expressionsUrl` (an expression sheet — happy, surprised, etc.). The character also has a `description` field that holds the LLM-extracted look so generation prompts can describe them in plain language when an image reference would be too brittle.
Locations. `VisualBibleLocation` carries a `referenceUrl` plus a child table of `LocationReferenceVariation` rows — viewpoint variants (wide / medium / close), time-of-day variants (day / golden hour / night), weather variants. A scene set at the same place at different times of day pulls different variations rather than re-running the location through generation.
The combined character sheet. `VisualBible.combinedCharacterSheetUrl` is a single composite image with every character at consistent scale, on a uniform background. We pass it as a reference to multi-character shots so the model doesn't drift on who's who. This is the single most important field for character consistency in long-form video.
Generation flow. Once the script is approved, the LLM (OpenRouter) reads the chapters and extracts named characters + locations. For each character, KIE generates a portrait + sheet + expressions (three image calls, parallel). For each location, KIE generates the base reference + variations. The flow is async — you can leave the workspace while it runs and come back to approve.
Approval. This is the only stage we deliberately gate with a manual step. The reason: any one bad character portrait will haunt every scene that character appears in, and regenerating after a hundred shots have already been made is expensive. So we hold the line at the bible. You can regenerate individual characters or locations, edit the description fields and rerun, or accept and move on.
How shots consume it. Each Shot record has `assignedLocationId` and a `visualRefs` JSON that lists character IDs in the shot. The generation prompt builder reads the bible records, pulls the right reference URLs, and assembles a prompt that includes them as image refs. The result: the same character in scene 4 looks like the same character in scene 47, because the reference URL is the same in both prompts.
Style guide governance. The `styleGuide` JSON is editable any time after generation. If you decide the palette should shift warmer halfway through a project, you can edit it, and new shots inherit the change without rerunning the bible. Old shots keep their original palette unless you regenerate them.
Where it falls short. The bible is per-project, not per-channel. If you ship 30 videos with the same protagonist, you generate 30 portraits today. Channel-level bibles — shared assets across a creator's projects — are on the roadmap but not built. For now: ship the first project, save the character portraits manually, and re-upload as reference in the next one. Painful, but the gap is on us, not on you.