# Screen Test Tab — Design Document

> **Date:** 2026-03-01
> **Status:** Approved
> **Location:** Pre-Production Console, Tab 7 ("Screen Test")

## Overview

A dedicated tab in the Pre-Production Console where the director reviews characters in their full wardrobe phases from the script. Each character gets a grid with one cell per wardrobe phase — showing the cast actor in the complete look (wardrobe + hair/makeup + distinguishing marks). The director can lock, hold, reject, or re-roll each phase with optional natural-language direction.

## Prerequisites

- Character must have `status: turnaround_complete` or `fully_cast` in casting_state
- Global bible must exist with character phases
- Hero + three-quarter reference images available in `output/refs/characters/{char}/`

## Layout

- **Top bar:** Character selector (one character at a time)
- **Grid:** 3 columns, rows as needed per character's phase count
  - Jinx: 7 phases (3 rows)
  - Kian: 5 phases (2 rows)
  - Varek: 4 phases (2 rows)

### Cell Contents

Each cell displays:
- **Phase name** (e.g., "Lower Deck Salvager")
- **Episode range** (e.g., "EP 1-8")
- **Full look description** from bible: `wardrobe_description` + `hair_makeup` + `distinguishing_marks`
- **Generated 9:16 image** (or empty placeholder)
- **State badge:** `EMPTY` / `GENERATING` / `HOLD` / `LOCKED` / `REJECTED`
- **Action buttons:** Lock / Hold / Reject / Re-roll / Deep Re-roll (3-4)
- **Anchor star** on locked phases designated as style anchors

## Director's Notes (Re-roll Enhancement)

When re-rolling a phase:

1. Optional **"Director's note"** text field appears
2. Director types natural language: *"more battle-worn, darker lighting, hair matted down"*
3. System enrichment pipeline:
   - Takes base phase description from bible (wardrobe + hair/makeup + distinguishing marks)
   - Passes director's note + base description to Gemini Flash
   - Flash translates the note into optimized prompt modifications for the image model
4. If no note provided, re-generates with temperature variation only
5. **Notes persist** — locked phases retain their director's note for production use
6. **Generation history** per cell — can scroll back to previous rejected attempts

## Image Generation

- **Model:** NBP (Gemini 3 Pro Image) — $0.134/frame
- **Input references:** Hero image + three-quarter image from casting pipeline
- **Prompt construction:** `[character visual description] + [phase wardrobe_description] + [phase hair_makeup] + [phase distinguishing_marks] + [director's note if any]`
- **Re-roll:** 1 image, same prompt with temperature variation
- **Deep re-roll:** 3-4 images, shown as mini-carousel within the cell (arrows to browse, lock/hold/reject each independently)

### "Build Around" Anchoring

- A locked phase can be marked as **style anchor**
- Anchor image included as additional reference for unlocked phase generations
- Maintains visual coherence across character arc (skin tone, lighting quality, art style)
- One anchor per character at a time

## State Management

### File: `projects/{project}/state/starsend/screen_test_state.json`

```json
{
  "JINX": {
    "anchor_phase": "jinx_lower_deck_salvager",
    "phases": {
      "jinx_lower_deck_salvager": {
        "status": "locked",
        "locked_image": "output/refs/characters/jinx/screen_test/phase_1_locked.png",
        "director_note": null,
        "enriched_prompt": "...",
        "held_images": ["path1.png"],
        "generation_history": [
          {
            "image": "output/refs/characters/jinx/screen_test/phase_1_v1.png",
            "prompt": "...",
            "note": null,
            "timestamp": "2026-03-01T10:00:00Z",
            "verdict": "rejected"
          },
          {
            "image": "output/refs/characters/jinx/screen_test/phase_1_v2.png",
            "prompt": "...",
            "note": null,
            "timestamp": "2026-03-01T10:05:00Z",
            "verdict": "locked"
          }
        ]
      },
      "jinx_dead_zone_survivor": {
        "status": "held",
        "held_images": ["path1.png", "path2.png"],
        "director_note": "more battle-worn, darker lighting",
        "enriched_prompt": "...",
        "generation_history": []
      }
    }
  }
}
```

### Status Lifecycle

```
empty → generating → generated → held | locked | rejected
                                    ↓
                              (re-roll) → generating → ...
```

## API Endpoints

| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/project/{name}/screen-test/{character}` | Phase grid state + bible data |
| POST | `/api/project/{name}/screen-test/{character}/generate` | Generate all empty phases |
| POST | `/api/project/{name}/screen-test/{character}/{phase}/reroll` | Re-roll one phase. Body: `{ "director_note": "...", "deep": false }` |
| POST | `/api/project/{name}/screen-test/{character}/{phase}/verdict` | Body: `{ "action": "lock" | "hold" | "reject" }` |
| POST | `/api/project/{name}/screen-test/{character}/set-anchor` | Body: `{ "phase": "phase_id" }` |

## Output Directory Structure

```
output/refs/characters/{char}/screen_test/
├── phase_1_v1.png          # generation history
├── phase_1_v2.png
├── phase_1_locked.png      # locked image (symlink or copy)
├── phase_2_v1.png
├── phase_2_v2.png
├── phase_2_held_01.png
└── ...
```

## Integration with Production Pipeline

Once screen tests are locked:

1. **Prompt engine** pulls locked screen test image as character reference per episode
2. **Phase resolution** automatic — each episode knows its phase from bible episode ranges
3. **Replaces generic hero reference** with the exact approved look for that narrative phase
4. **Director's notes** feed into production prompt construction for consistency

## Data Sources

- **Character phases:** `data/render_manifests/global_bible.json` → `characters.{char}.phases[]`
- **Phase fields used:** `phase_id`, `start_ep`, `end_ep`, `wardrobe_description`, `hair_makeup`, `distinguishing_marks`
- **Character references:** `output/refs/characters/{char}/hero.png`, `{char}_three_quarter.png`
- **Casting state:** `projects/{project}/state/starsend/casting_state.json`

## Cost Estimate (Per Character)

- Initial generation (all phases): ~$0.134 × N phases
  - Jinx (7 phases): ~$0.94
  - Kian (5 phases): ~$0.67
  - Varek (4 phases): ~$0.54
- Re-roll: $0.134 per image
- Deep re-roll: ~$0.54 (4 images)
- Director's note enrichment: ~$0.01 (Flash)
- Full screen test for all 3 characters: ~$2.15 base + re-rolls
