# Engine Constants

> **Single source of truth for all numeric values.**
> Other documents MUST reference this file, not hardcode values.
> When changing a constant, update THIS file first, then run `validate_docs.py`.

---

## Episode Constraints

| Constant | Default | Validation Range | Notes |
|----------|---------|------------------|-------|
| `WORD_COUNT` | 450-500 | 450-500 | Standard episode length (total file words) |
| `DIALOGUE_MAX_PERCENT` | 40% | Hard fail | Maximum dialogue as % of total words |
| `MAX_EXCHANGES` | 8 | Hard fail | Maximum dialogue exchanges per episode |
| `MAX_ACTION_BLOCK_LINES` | 4 | Soft limit | Typical: 1-3 lines |

**Word Count Method:** Validator counts ALL words in the episode file (no exclusions).

---

## Pattern Distribution

| Constant | Target | Validation Range | Notes |
|----------|--------|------------------|-------|
| `HOOK_SILENT_PERCENT` | 80% | 70-85% | Episode openings (20% dialogue inverse) |
| `CLIFFHANGER_MIDACTION_PERCENT` | 80% | 70-85% | Episode endings (20% aftermath inverse) |
| `MAX_CONSECUTIVE_SAME_TYPE` | 3 | - | Max 3 consecutive allowed; 4+ is violation |

**Target vs Validation:**
- **Target (80%):** What to aim for during generation
- **Validation Range (70-85%):** What passes validation gates (allows flexibility)

**Consecutive Pattern Rule:** "No 4+ consecutive same type" means you can have up to 3 episodes in a row with the same hook or cliffhanger type, but 4 or more triggers a violation. Applies to **subtypes** (e.g., M-PT, S-VP, M-CF). Different subtypes within the same main category (e.g., M-CF then M-PT then M-CT) do NOT count as consecutive. Main-category runs are informational soft flags only.

---

## Pilot Window (First 10 Episodes)

| Constant | Value | Notes |
|----------|-------|-------|
| `PILOT_EPISODE_COUNT` | 10 | Free episodes before paywall |
| `PATTERN_VARIETY_STARTS` | Episode 11 | Pattern variety rule kicks in |
| `PAYWALL_EPISODE` | 10 | Must have maximum urgency cliffhanger |

**During pilot (Ep 1-10):** All MID-ACTION cliffhangers allowed (pattern variety suspended).

---

## Kill Box Structure (90 Seconds)

| Section | Timestamp | Duration | Typical Words |
|---------|-----------|----------|---------------|
| `HOOK` | [00:00-00:05] | 5 sec | ~25 words |
| `SETUP` | [00:05-00:15] | 10 sec | ~50 words |
| `ESCALATION` | [00:15-00:40] | 25 sec | ~100 words |
| `TURN` | [00:40-00:70] | 30 sec | ~100 words |
| `CLIFFHANGER` | [00:70-00:90] | 20 sec | ~50 words |

**Note:** The "Typical Words" column totals ~325 words of prose content. The remaining words (up to 450-500 total) come from episode metadata: headers, Kill Box timestamps, scene headings, character cues, hook/cliffhanger type annotations, and formatting. The validator counts ALL words in the file.

---

## Treatment Constraints

| Constant | Value | Notes |
|----------|-------|-------|
| `TREATMENT_TOTAL_WORDS` | 3000-4000 | ~15-20 minute read |
| `TREATMENT_AVG_PER_EPISODE` | 50-65 | Regular episodes |
| `HOOK_RATIO_TARGET` | 70-85% SILENT | Validation range |
| `CLIFFHANGER_RATIO_TARGET` | 70-85% MID-ACTION | Validation range |

### Treatment Word Counts by Beat Type

| Beat Type | Word Range | Notes |
|-----------|------------|-------|
| SETUP | 40-55 | Establishing, efficient |
| COMPLICATION | 40-55 | Plot mechanics |
| CATALYST | 50-70 | Inciting incident |
| LOCK-IN | 50-70 | Commitment moment |
| COLLISION | 60-80 | Major confrontation |
| CRISIS | 60-80 | Emotional depth |
| REVELATION | 60-80 | Truth unpacking |
| CLIMAX | 70-90 | Peak drama |
| RESOLUTION | 50-70 | Landing the story |

### Key Episode Treatment Words

| Episode | Word Range | Reason |
|---------|------------|--------|
| 1 | 125-150 | Pilot template, sets tone |
| 10 | 70-90 | Paywall crisis |
| 15 | 70-90 | Threshold, Act 1 end |

---

## Series Structure

| Constant | Value | Notes |
|----------|-------|-------|
| `TOTAL_EPISODES` | 61 | Full series |
| `GENERATION_BATCH_SIZE` | 5 | Episodes per generation batch |
| `TREATMENT_BATCH_SIZE` | 10 | Episodes per treatment batch |
| `TOTAL_GENERATION_BATCHES` | 13 | 12 full batches of 5 + 1 batch of 1 |
| `TOTAL_TREATMENT_BATCHES` | 7 | 6 full batches of 10 + 1 batch of 1 |

**Note:** Treatment uses larger batches (10 episodes) than generation (5 episodes) because treatment prose is smaller and benefits from seeing more context at once.

### Structural Beats (Major Plot Points)

| Episode | Beat | Notes |
|---------|------|-------|
| 15 | PLOT POINT 1 | Point of no return |
| 30 | MIDPOINT | Stakes shift to survival |
| 45 | ALL IS LOST | Defeat, mentor dies |
| 61 | RESOLUTION | Final battle, new world |

### Eight-Sequence Skeleton

| Sequence | Episodes | Name | Notes |
|----------|----------|------|-------|
| SEQ 1 | 1-8 | Status Quo & Catalyst | World establishment, inciting incident |
| SEQ 2 | 9-15 | The Predicament | Lock-in, first act climax |
| SEQ 3 | 16-23 | Fun & Games | Promise of the premise |
| SEQ 4 | 24-30 | Midpoint | Stakes escalate, commitment |
| SEQ 5 | 31-38 | Bad Guys Close In | Pressure mounts |
| SEQ 6 | 39-45 | All Is Lost | Lowest point, dark night |
| SEQ 7 | 46-53 | The Rally | New approach, allies reunite |
| SEQ 8 | 54-61 | Final Battle | Climax and resolution |

### Emotional Beat Schedule (11 Required Beats)

| Episode | Beat Name | Description | Tolerance |
|---------|-----------|-------------|-----------|
| 10 | FIRST_CRACK | First vulnerability shown, relationship shifts from transaction | ±2 eps |
| 15 | THRESHOLD | Point of no return — protagonist crosses threshold | ±2 eps |
| 20 | DEEPENING | Investment despite themselves | ±2 eps |
| 26 | VULNERABILITY | First expressed care (verbalized, even awkwardly) | ±2 eps |
| 30 | MIDPOINT | World/self fundamentally different | ±2 eps |
| 32-33 | FRACTURE | Identity crisis — core belief challenged | ±2 eps |
| 36 | BETRAYAL_DOUBT | Trust tested or masks down | ±2 eps |
| 42 | COST | Loyalty test — choose relationship over goal | ±2 eps |
| 45 | ALL_IS_LOST | Lowest point, relationship threatened | ±2 eps |
| 50 | RECONCILIATION | Connection survives crisis | ±2 eps |
| 60-61 | RESOLUTION | Primary ache resolved (catharsis) | ±2 eps |

> **Note:** Emotional beats must be present at designated episodes (±2 tolerance). Missing beats are hard failures in arc validation.

---

## Emotional Anchor Types

| Type | Function | Dramatic Engine |
|------|----------|-----------------|
| CUB | Someone to protect | "I must keep them safe" |
| GHOST | Someone lost/haunting | "I can't escape what I lost" |
| MIRROR | Reflects protagonist's fate | "I'm looking at my future" |
| SKEPTIC | Challenges protagonist's choices | "They see what I'm becoming" |
| TETHER | Grounds protagonist to humanity | "They keep me human" |
| WITNESS | Sees the protagonist clearly | "They know the real me" |
| FOIL | Represents the opposite path | "They chose differently" |
| COST | Will pay if protagonist fails | "They suffer for my choices" |

**Hybrids:** Anchors can combine types (e.g., CUB + MIRROR, GHOST + TETHER).
**Full reference:** `/appendix_c_emotion.md`

---

## Relationship Earning Schedule

| Episode Range | Appropriate Level | Example |
|---------------|-------------------|---------|
| 1-10 | Actions only | No verbal declarations |
| 11-20 | Small acknowledgments | "You're not useless." |
| 21-30 | Tentative trust | "I trust you with this." |
| 31-40 | Significant statements | "I need you." |
| 41-50 | Deep connection | "I can't do this without you." |
| 51-61 | Major declarations | "I love you." |

### Accelerators (Multipliers)

| Accelerator | Multiplier |
|-------------|------------|
| Shared near-death survival | 2x |
| One saves other's life | 2x |
| Mutual vulnerability in crisis | 1.5x |
| Extended isolation together | 1.5x |

---

## Voice Contamination Checkpoints

| Batch | Episodes | Check |
|-------|----------|-------|
| 3 | 11-15 | First contamination check |
| 6 | 26-30 | Midpoint check |
| 9 | 41-45 | All Is Lost check |
| 13 | 56-61 | Final check |

---

## Character Expression Variety

**Anti-Repetition Guidance:** Character elements should feel organic, not mechanical.

| Element | Target Frequency | Anti-Pattern |
|---------|-----------------|--------------|
| Behavioral DNA | 2-3 per batch (varied) | Same behavior 2+ consecutive eps |
| Idiom/Voice | 3-4 per batch (natural) | Forcing idiom every episode |
| Signature line | 2-3 per ACT | Overusing signature phrases |
| Stress behavior | Key moments only | Every conflict triggers it |
| Orthogonal trait | When organic to story | Forced appearances |

**The Rule:** If you notice you're checking a box, you're doing it wrong. Character expression should emerge from the scene's dramatic needs, not from a frequency requirement.

---

## Episode Intensity Scale

Used in `episode_arc.md` to rate each episode's dramatic intensity.

| Score | Level | Description |
|-------|-------|-------------|
| 1-2 | Low | Setup, worldbuilding, quiet character moments |
| 3-4 | Moderate | Rising tension, new complications, relationship shifts |
| 5-6 | High | Major confrontations, revelations, significant stakes |
| 7-8 | Very High | Crisis points, betrayals, near-death, emotional peaks |
| 9-10 | Maximum | Climax moments, all-is-lost, series-defining events |

**Guidelines:**
- Pilot episodes (1-10) should average 6-8 intensity
- Midpoint (ep 30) and All Is Lost (ep 45) should be 8-10
- Resolution (ep 60-61) should be 9-10
- Quiet "valley" episodes between peaks should be 3-5

---

## Demographic

| Constant | Value |
|----------|-------|
| `TARGET_DEMO_AGE` | 18-35 |
| `TARGET_DEMO_GENDER` | Male |

---

## Thread Continuity

| Constant | Value | Notes |
|----------|-------|-------|
| `STALE_THRESHOLD` | 15 | Episodes without mention before thread is flagged stale |
| `MIN_THREAD_COUNT` | 6 | Minimum required threads per series |

---

## Goal-Backward Verification

**Purpose:** Ensure arc is on track to deliver its promises at key checkpoints.

| Checkpoint | Episode | Threads Resolved | Arc Progress | Emotional Beats |
|------------|---------|------------------|--------------|-----------------|
| Batch 3 | 15 | 0-1 | 25% | 2/11 |
| Batch 6 | 30 | 2-3 | 50% | 5/11 |
| Batch 9 | 45 | 4-5 | 75% | 8/11 |
| Batch 13 | 61 | 6+ | 100% | 11/11 |

**How to Use:**
- At each checkpoint, verify trajectory against these targets
- If off-track, generate course correction recommendations
- Thread resolution counts are cumulative
- Arc progress = (current episode / 61) × 100

**Course Correction Triggers:**
- Threads resolved < expected: Accelerate payoffs in next batch
- Emotional beats missed: Insert recovery beat in next available episode
- Arc progress stalled: Review treatment for pacing issues

---

## Visual Production

| Constant | Value | Notes |
|----------|-------|-------|
| `SHOTS_PER_EPISODE` | 28-41 | Determined by script paragraph structure (Camera Test rule); genre-configurable via project_config.json → shots_per_episode |
| `SECONDS_PER_SHOT` | ~5-6 | Anything over 6s feels static in AI video |
| `SCENE_PROSE_WORDS` | 30-80 | Novelistic scene description for hybrid JSON+prose prompts |
| `DIMENSION_MULTIPLE` | 16 | All generation dimensions must be multiples of 16 |
| `DEFAULT_DIMENSIONS` | 576x1024 | 9:16 vertical (width x height) |
| `PREVIZ_DIMENSIONS` | 512x896 | 9:16 previz (width x height) |
| `PREVIZ_STEPS` | 8 | Z-Image Turbo inference steps for previz |
| `PREVIZ_MODEL` | z_image_turbo | fal-ai/z-image/turbo/lora |
| `PREVIZ_COST_PER_MP` | $0.0085 | fal.ai rate: $0.005/MP base + $0.0035/MP LoRA |
| `PREVIZ_COST_PER_FRAME` | ~$0.0039 | At 512x896 (0.459 MP) |
| `VIDEO_FRAMES` | 81 | WAN 2.1 default frame count |
| `VIDEO_FPS` | 16 | WAN 2.1 default frames per second |
| `STORYBOARD_SCHEMA_VERSION` | 2 | Current storyboard_schema.json version |
| `BREAKDOWN_SCHEMA_VERSION` | 1 | Current breakdown_schema.json version |

### Film Stock

| Constant | Value | Notes |
|----------|-------|-------|
| `FILM_STOCK` | Kodak Vision3 500T | Appended to all generation prompts for consistent look |

### Default Lens Package

| Shot Type | Lens | Aperture | Notes |
|-----------|------|----------|-------|
| ECU, CU | 85mm | f/1.4 | Telephoto compression, strong bokeh |
| MCU, MS | 50mm | f/2.0 | Natural perspective, minimal distortion |
| LS, WIDE | 24mm | f/8 | Deep focus, dramatic perspective |
| POV | 50mm | f/2.0 | Matches human perspective |

### Shot Grammar (Empirical — Visual Grammar Bible)

> Source: `/_research/visual_grammar_bible/FINDINGS.md` + Leviathan creative direction
> Rules: `/appendix_g_vertical_grammar.md`

| Constant | Value | Notes |
|----------|-------|-------|
| `ECU_MIN_PER_EPISODE` | 2 | Minimum ECUs per episode (validator warning if below) |
| `SCALE_CHANGE_MIN_STEPS` | 2 | Same-subject cuts need 2+ SCALE_ORDER steps or angle change |
| `SAME_TYPE_CONSECUTIVE_MAX` | 2 | 3+ consecutive same shot_type = hard error |
| `STATIC_CAMERA_TARGET` | 77% | Movement is the exception, not the default (corpus: 77.0%) |
| `ASL_TARGET_SECONDS` | 1.5-2.0 | Average shot length for pacing reference (corpus: 1.65s) |
| `SHOT_SCALE_DIST_TOLERANCE` | 15% | Warning if any shot type is >15% outside appendix_g target range |

### Flux 2 Reference Slots

| Slots | Purpose |
|-------|---------|
| 1-5 | Character identity (front, profile, three-quarter, full body, back) |
| 6 | Wardrobe/props (signature items) |
| 7-8 | Environment (location refs, architecture) |
| 9 | Lighting reference (mood) |
| 10 | Pose/layout (depth maps, blocking guides) |

---

## Validation Exit Codes

| Code | Meaning | Action |
|------|---------|--------|
| 0 | PASS | Proceed |
| 1 | FAIL / DRIFT | Fix before continuing (hard) or review (soft) |
| 2 | WARNINGS | Can proceed but review recommended |

---

## Document References

When referencing constants in other documents, use this format:

```markdown
Word count: 450-500 (see `/CONSTANTS.md`)
```

Or for inline:

```markdown
Maximum dialogue is 40% (ref: CONSTANTS.md → DIALOGUE_MAX_PERCENT)
```

---

*Last updated: 2026-02-10*
*Changes: Added Shot Grammar constants (ECU_MIN, SCALE_CHANGE_MIN_STEPS, SAME_TYPE_CONSECUTIVE_MAX, STATIC_CAMERA_TARGET, ASL_TARGET, SHOT_SCALE_DIST_TOLERANCE) from Visual Grammar Bible research*
*Run `python3 /tools/validate_docs.py` after any changes.*
