Editorial Design — Presentation Intelligence
The agent is the editor. Each project gets a personalized reading experience. Zero config from the user.
Why This Exists
Every project is different. An investigation into IMF lending cycles feels nothing like a comic about a clockmaker. The viewer must adapt — image sizing, text treatment, transitions, narrator visibility — all tuned to the content. Users are busy. They create content, the system makes it look good.
When to Use
Step 9 (Assembly) — after investigation.json is built, before writing it to disk. The agent analyzes the content and writes a presentation block into investigation.json. The viewer reads this block and adjusts rendering automatically.
The Presentation Block
Added to investigation.json at the top level:
{
"presentation": {
"layout": "narrator",
"show_speaker_badge": false,
"image_sizing": "cover",
"text_position": "side-alternating",
"transition": "page-flip",
"typewriter_speed": 20,
"image_max_width": null,
"image_aspect": "auto"
}
}
Field Reference
| Field | Options | Default | What it controls |
|---|
layout | narrator, immersive, cinematic | auto-detect | Overall presentation mode |
show_speaker_badge | true, false | true | Whether to show speaker avatar + name label |
image_sizing | cover, contain, native | contain | How images fill their container |
text_position | side-alternating, overlay-bottom, below | varies by layout | Where text appears relative to image |
transition | page-flip, crossfade, cut | varies by layout | How panels transition |
typewriter_speed | 10-40 (ms per char) | 20 | Reading pace — lower = faster |
image_max_width | null, "60%", "80%", "100%" | null (layout default) | Constrain image width |
image_aspect | "auto", "16:9", "4:3", "1:1" | "auto" | Expected image aspect ratio |
Decision Framework
The agent makes these decisions by analyzing content signals. No user input needed.
Step 1: Layout Mode
What is this project?
├─ Investigation (systems, power, history)
│ └─ > 60% NARRATOR speaker → layout: "narrator"
│ Text-position: "side-alternating"
│ Transition: "page-flip"
│ Show-speaker-badge: false (no narrator bubble — just text)
│
├─ Story / Comic (characters, dialogue, action)
│ └─ Multiple speakers, < 60% NARRATOR → layout: "immersive"
│ Text-position: "overlay-bottom"
│ Transition: "crossfade"
│ Show-speaker-badge: true (show who's speaking)
│
└─ Cinematic / Documentary (visual-heavy, minimal text)
└─ Average text length < 80 chars AND image quality is high
→ layout: "cinematic"
Text-position: "overlay-bottom"
Transition: "crossfade"
Show-speaker-badge: false
Image-sizing: "cover" (full bleed)
Step 2: Image Treatment
Analyze the generated images:
| Signal | Decision |
|---|
| Images are 512x512 (local model) | image_sizing: "contain", image_max_width: "60%" — don't stretch low-res |
| Images are 1024+ (Gemini/cloud) | image_sizing: "cover" or "native" — let them breathe |
| Mixed aspect ratios across panels | image_aspect: "auto" — respect each image's natural shape |
| Consistent 16:9 throughout | image_aspect: "16:9" — viewer can optimize layout |
| Investigation with data/text panels | image_sizing: "contain" — readable detail matters more than atmosphere |
Step 3: Text Presentation
Analyze the script:
| Signal | Decision |
|---|
| Long narration (avg > 150 chars/panel) | text_position: "side-alternating" — give text room |
| Short punchy text (avg < 80 chars) | text_position: "overlay-bottom" — image dominates |
| Mixed speakers with dialogue | show_speaker_badge: true — reader needs to know who |
| Pure narrator, no characters | show_speaker_badge: false — the N badge is noise |
| Poetic / contemplative tone | typewriter_speed: 25 — slower, let words land |
| Dense informational content | typewriter_speed: 15 — faster, don't bottleneck |
Step 4: Transitions
| Content type | Transition | Why |
|---|
| Investigation (measured, analytical) | page-flip | Feels like turning pages in a report |
| Story (flowing, emotional) | crossfade | Smooth, cinematic continuity |
| Quick explainer | cut | Snappy, no delay |
| Documentary with dramatic reveals | crossfade with slower timing | Build anticipation |
Viewer Template Skills (7 templates)
Each layout mode has a dedicated skill file with full implementation details, CSS patterns, and design rules. Always read the relevant template skill before building a viewer.
| Template | Skill File | Best For |
|---|
| Magazine | viewer-magazine.md | System investigations, documentary-style, heavy narration. Text bleeds over image, alternating left/right. Creator's default for investigations. |
| Cinematic | viewer-cinematic.md | Visual-heavy stories, photojournalism, art-first. Image dominates, subtitles only, letterbox bars. |
| Dossier | viewer-dossier.md | Evidence-heavy analysis, data investigations, structured intel. Framed evidence, stamps, structured data. |
| Immersive | viewer-immersive.md | Multi-character stories, educational comics, dialogue-driven. Visual novel style, speaker avatars, glass-morphism. |
| Scroll | viewer-scroll.md | Accessible reading, blog-style, social media sharing. Vertical scroll, parallax, centered column. |
| Comic | viewer-comic.md | True comics, manga-style, sequential art. Panel grid, speech bubbles, gutters. |
| First-Person | viewer-first-person.md | Horror, personal narratives, confessional. Center text, vignette, breathing, no UI chrome. |
Selection rule: For system investigations, default to magazine. Only deviate if content specifically calls for dossier (evidence-heavy with structured data) or cinematic (visual-heavy, minimal text). The creator has explicitly rejected slideshow-style viewers for investigations.
Learned (2026-03-21, insurance-architecture-global-trade): The magazine template was rebuilt mid-session from a slideshow layout. Text must bleed over the image, not sit below it. This is non-negotiable for investigation-type content.
Layout Mode Details
narrator — The Magazine Spread
Best for: investigations, explainers, narrator-heavy content.
Full template: viewer-magazine.md
- Image on one side, text panel on the other
- Sides alternate per panel (left/right/left/right)
- Large faded scene number behind text (01, 02, 03...)
- Accent line under header
- Text fills remaining viewport space
- Page-flip transition
- No speaker badge for pure narrator — the text IS the narrator
Reference: All current GatorSquare investigations use this. insurance-architecture-global-trade confirmed this as the creator's preferred format.
immersive — The Visual Novel
Best for: stories, comics, multi-character dialogue.
Full template: viewer-immersive.md
- Full-viewport image with Ken Burns drift
- Text overlaid at bottom with gradient backdrop
- Speaker avatar + name shown (colored per character)
- Crossfade transition
- Speaker badge required — reader needs to track who's talking
Reference: 001-welcome (Bureau comic), clockmakers-commission.
cinematic — The Documentary
Best for: visual-heavy pieces with minimal narration, atmospheric content.
Full template: viewer-cinematic.md
- Full-bleed image, no max-width constraint
- Image sizing:
cover (fills viewport)
- Ken Burns drift with longer cycle (35s instead of 25s)
- Text appears as subtle overlay, auto-fades after reading
- Minimal UI — no scene numbers, no accent lines
- No speaker badge — pure visual experience
Reference: Not yet implemented as default. Future mode for photo-essay style content.
How the Agent Decides (Algorithm)
During Step 9 (Assembly), the agent runs this analysis:
1. Count speakers:
- narratorRatio = NARRATOR moments / total moments
- speakerCount = unique speakers (excluding NARRATOR)
2. Measure text density:
- avgTextLength = average character count across all moment texts
- maxTextLength = longest single moment text
3. Check image quality signals:
- imageSource = "local" (512px) | "cloud" (1024px) | "gemini" (high-res)
- Check first 3 image file sizes / dimensions if accessible
4. Apply decision tree:
- narratorRatio > 0.6 → narrator layout
- speakerCount >= 2 AND narratorRatio < 0.4 → immersive layout
- avgTextLength < 80 AND imageSource = "gemini" → cinematic layout
- else → narrator layout (safe default)
5. Write presentation block to investigation.json
Examples
Investigation (IMF, Opium, Banana Republic)
"presentation": {
"layout": "narrator",
"show_speaker_badge": false,
"image_sizing": "native",
"text_position": "side-alternating",
"transition": "page-flip",
"typewriter_speed": 20
}
Character Story (Clockmaker, Coffee Journey)
"presentation": {
"layout": "immersive",
"show_speaker_badge": true,
"image_sizing": "contain",
"text_position": "overlay-bottom",
"transition": "crossfade",
"typewriter_speed": 22
}
Multi-Character Comic (Bureau 001-Welcome)
"presentation": {
"layout": "immersive",
"show_speaker_badge": true,
"image_sizing": "contain",
"text_position": "overlay-bottom",
"transition": "crossfade",
"typewriter_speed": 20
}
Visual Documentary (future — photo essay style)
"presentation": {
"layout": "cinematic",
"show_speaker_badge": false,
"image_sizing": "cover",
"text_position": "overlay-bottom",
"transition": "crossfade",
"typewriter_speed": 25,
"image_max_width": "100%"
}
Adaptive Image-Text Layout
The viewer automatically handles the image-vs-text balance:
Wide Images (aspect > container)
When an image is too wide to leave 35% of viewport for text, the viewer switches to overlay mode:
- Image renders full-bleed with
object-fit: cover
- Text panel overlays the image with a gradient backdrop (transparent → 85% black → 95% black)
- The gradient bleeds from the image into the text — no hard edge
- This prevents the old problem: wide images cramming text into a 280px strip
Narrow/Square Images
When images leave enough space beside them:
- Normal side-by-side layout (image left, text right, alternating)
- Text gets at least 35% of viewport width
Text-Only Moments (No Image)
When a moment has no image (research-only, text pieces):
- Full typographic layout — text centered, larger font (1.5rem), wider line height
- Scene number displayed large and faint as background element
- Click-based pacing still works — each click advances to next text block
- Useful for: pure research presentations, text-heavy explainers, section breaks
The Agent's Job
During assembly, assess each panel's image dimensions and text length. The viewer handles the mechanics, but the agent should:
- Choose
image_sizing: "cover" for high-res atmospheric images
- Choose
image_sizing: "contain" for images with important edge detail
- Set
show_speaker_badge: false to remove narrator clutter
- Consider text-only moments for powerful quotes or section transitions
Dialogue Detection & Bubble Mode (added 2026-03-21)
When the content has multi-character dialogue, the viewer switches to dialogue bubble mode — chat-style bubbles overlaying the image, one at a time, click-to-advance.
Detection Algorithm (runs during Step 9 Assembly)
1. Count non-NARRATOR characters in characters dict
2. Scan moment text for dialogue pattern: `Name: "line"`
3. Calculate dialogue ratio: moments with 2+ dialogue lines / total moments
IF dialogueRatio > 0.5 AND nonNarratorCharacters >= 2:
→ Set presentation.dialogue_mode = "bubbles"
→ Set presentation.layout = "immersive" (image dominates)
→ Set presentation.text_position = "overlay-bubbles"
IF dialogueRatio > 0.3 AND nonNarratorCharacters >= 2:
→ Set presentation.dialogue_mode = "chat"
→ Dialogue renders as styled chat thread in side panel (colored per character)
→ Narration renders as plain text above the chat
IF dialogueRatio < 0.3 OR nonNarratorCharacters < 2:
→ No dialogue mode (standard text rendering)
What the Viewer Does with dialogue_mode: "bubbles"
The viewer parses each moment's text field for the pattern:
{Narration text}
{Speaker}: "{dialogue}" *{action}*
And renders:
- Narration as a subtle semi-transparent strip at the top of the image
- Dialogue lines as colored chat bubbles overlaying the image, appearing one per click
- Actions as italic stage direction between bubbles
- Character colors from the
characters dict drive bubble border/accent color
- Bubble position alternates — characters don't have fixed positions. Bubbles alternate left/right so the conversation flows visually. The character's color is the identity signal, not their screen position.
- After all bubbles in a moment are shown, next click advances to the next moment
Presentation Block for Dialogue Projects
"presentation": {
"layout": "immersive",
"dialogue_mode": "bubbles",
"show_speaker_badge": true,
"text_position": "overlay-bubbles",
"transition": "crossfade",
"typewriter_speed": 20,
"viewer_style": "picture-book"
}
Bubble Theming by viewer_style
The viewer renders bubbles differently based on the project's viewer_style:
| viewer_style | Bubble Background | Narration Strip | Font | Feel |
|---|
picture-book | White/cream rgba(255,255,255,0.95) | Warm cream rgba(255,250,240,0.92) | Crimson Pro serif | Soft, warm, children's book |
default / immersive | Dark glass rgba(30,30,50,0.85) | Dark blur rgba(0,0,0,0.55) | Inter sans-serif | Cinematic, moody |
editorial | White with border | White with thin border | Inter | Clean, magazine |
Character positioning rules:
- Characters do NOT have fixed left/right positions
- Bubbles alternate sides per speaker turn (same speaker stays same side)
- Character identity is conveyed via color accent (left border), not position
- This creates natural conversation flow like reading a dialogue in a book
What the Agent Must Check
When building investigation.json with merged dialogue text:
- Each dialogue line MUST follow the pattern:
Speaker: "line" (with quotes)
- Actions MUST be in
*asterisks*
- Narration MUST be separated from dialogue by
\n\n
- Speaker names MUST match keys in the
characters dict (case-insensitive lookup)
- Characters MUST have
color defined for bubble styling
Review Mode — Production Data Visibility
The review panel is the creator's window into every production decision. It must surface all data that went into creating each scene — not just the final text.
What Review Must Show (per moment)
For illustrated projects:
| Data | Source | Review Column |
|---|
| Scene prompt (the image generation prompt) | prompts.json → merged at viewer load | Current Panel → "Prompt" |
| Scene direction / variant | prompts.json → variant field | Current Panel → "Scene Direction" |
| Color accent | prompts.json → color_accent field | Current Panel (tag) |
| Script text | investigation.json → moment.text | Previous Panel → "Text" |
| Objects / characters used | investigation.json → moment.metadata.characters/environments | Current Panel → "Objects & Chain" |
| Object reference sheets | objects/ directory | Current Panel → thumbnails |
| Act / narrative position | knowledge.json → act_structure | Current Panel → "Act" |
| Emotion beat | knowledge.json → emotion_arc | Current Panel → "Emotion Beat" |
For text-only projects:
| Data | Source | Review Column |
|---|
| Scene direction | scene-plan.md → embedded in moment.metadata.scene_direction | Current Panel → "Scene Direction" |
| Act position | moment.metadata.act | Current Panel → "Act" |
| Emotion beat | moment.metadata.emotion | Current Panel → "Emotion Beat" |
| Entities referenced | moment.metadata.entities | Current Panel → "Entities Referenced" |
| Causal links active | moment.metadata.causal_links | Current Panel → "Causal Links" |
How Prompts Reach the Viewer
Prompts live in prompts.json (Director's output) — separate from investigation.json (Assembler's output). The viewer merges them at load time:
Viewer loads investigation.json
→ Also fetches prompts.json (same directory)
→ Matches prompts to moments by panel number:
prompts.json panel: 1 → investigation.json panel_id: "panel-01"
→ Merges into moment.metadata:
prompt_text ← prompt field
scene_direction ← variant field
color_accent ← color_accent field
→ Review panel reads via getMeta(moment, 'prompt_text')
If prompts.json is missing: Review panel silently hides the Prompt section. No error. This is expected for text-only projects.
Rule: Every Production File Feeds Review
If a pipeline stage produces data about a scene, that data MUST be visible in review mode. The creator should never have to open raw JSON files to understand what went into a scene. Review is the single pane of glass.
Non-Negotiables
- Every project gets a
presentation block — no project ships without editorial decisions
- The agent decides, not the user — analyze content signals, make the call
- Review your own decisions — after assembly, open the viewer and check: does this FEEL right for this content? If not, adjust.
- Image quality drives sizing — never stretch 512px images to full-bleed. Never constrain Gemini images to a tiny box.
- Speaker badges only when needed — investigations don't need a narrator badge on every panel. That's UI noise.
- Transitions match tone — page-flip for measured content, crossfade for flowing content, cut for snappy content.
- Text must always be readable — if image is wide, overlay mode kicks in. Never sacrifice readability for aesthetics.
- 10-word line rule — text should ideally show ~10 words per line. Enough to read comfortably, short enough to create rhythm. The image is the star. Text is cinema subtitles, not textbook paragraphs. The 38% overlay width with gradient backdrop naturally produces this. If text wraps wider than ~14 words/line, the column is too wide.
Common Mistakes (learned from production)
- Defaulting to slideshow layout. The creator has explicitly rejected slideshow (image above, text below, next/prev buttons) for investigations. Always use magazine, dossier, or cinematic. Never slideshow.
- Using legacy investigation.json fields. The viewer expects
project_id and moments (with panel_id, text, speaker, image). Using legacy panels array with narration causes a blank viewer. QA Patchup validates this.
- Not specifying aspect ratio in prompts. Mixed aspect ratios (some 16:9, some square, some 4:3) break the visual rhythm. Always specify 16:9 unless the creator requests otherwise.
- Text below image instead of over image. For magazine layout, text must bleed over the image with a gradient. Not sit in a separate panel below. This is the core distinction between "magazine editorial" and "slideshow."
Viewer Inheritance
The viewer reads presentation from investigation.json and applies it. If presentation is missing, it falls back to auto-detection (current behavior: >60% NARRATOR → narrator, else immersive).
This means:
- Old projects without
presentation still work (backward compatible)
- New projects get personalized treatment
- Users can override by editing the presentation block manually