Scenes to Sequence
Given analyzed scenes and a style pack, the planner determines shot order, hold durations, transition types, and camera overrides — producing a deterministic sequence manifest with no LLM calls.
Overview
Given scenes with metadata from analyze_scene and a style pack name, plan_sequence determines how to assemble the shots into a cohesive video. The planner is rule-based and deterministic — no LLM calls, fully testable.
The planner loads style pack definitions from catalog/style-packs.json and personality constraints from catalog/personalities.json at module level. Camera overrides are validated against each personality's allowed_movements — moves not permitted by the personality are downgraded to null.
Style packs
Ten style packs are available, each mapping to an animation personality with specific hold durations, transition rules, and camera behavior.
| Style | Personality | Tempo | Transitions | Camera | Use case |
|---|---|---|---|---|---|
prestige | editorial | Longer (2.5–3.5s) | Hard cuts + crossfade on weight change or emotional/hero | Selective push_in/drift by content type | Product showcases |
energy | montage | Short (1.5–2.0s), 4s cap | Hard cuts (70%) + whip-wipes every 3rd (30%) | Always static | Sizzle reels |
dramatic | cinematic-dark | Variable (2.5–3.5s) | Crossfade default, hard cut for same-weight | push_in for emotional/hero, drift for detail | Marketing, drama |
minimal | neutral-light | Uniform (3.0–4.0s) | Hard cuts only | Always static | Tutorials, docs |
intimate | cinematic-dark | Longer (3.0–4.0s) | Crossfade 800ms emotional, 500ms default | push_in 0.15 portrait/product, drift detail | Brand narratives |
corporate | editorial | Uniform (2.5–3.0s) | Crossfade 300ms on weight change, hard cut default | push_in product, drift UI | Enterprise demos |
kinetic | montage | Very short (1.0–1.5s), 3s cap | Whip every 2nd (200ms), hard cut default | Always static | Keynotes, launches |
fade | editorial | Medium (2.0–3.0s) | All crossfade 500ms | push_in 0.1 portrait/product only | Photo essays |
analog | editorial | Longer (2.5–4.0s) | Crossfade on weight change (600ms), crossfade default (400ms) | push_in portrait, drift product | Retro brand stories |
documentary | editorial | Very long (3.5–5.0s) | Crossfade on weight change (600ms), crossfade default (500ms) | Drift only for portrait/product | Observational storytelling |
Duration table by motion energy
| motion_energy | prestige | energy | dramatic | minimal | intimate | corporate | kinetic | fade | analog | documentary |
|---|---|---|---|---|---|---|---|---|---|---|
| static | 3.5s | 2.0s | 3.0s | 4.0s | 4.0s | 3.0s | 1.5s | 3.0s | 4.0s | 5.0s |
| subtle | 3.0s | 2.0s | 2.5s | 3.5s | 3.5s | 2.75s | 1.5s | 2.5s | 3.5s | 4.5s |
| moderate | 3.0s | 1.5s | 3.0s | 3.0s | 3.0s | 2.5s | 1.0s | 2.0s | 3.0s | 4.0s |
| high | 2.5s | 1.5s | 3.5s | 3.0s | 3.0s | 2.5s | 1.0s | 2.0s | 2.5s | 3.5s |
Planning stages
The planner runs four stages in sequence.
1. Shot order
Intent-bucket approach with variety post-processing.
Bucketing: Each scene goes into a bucket by its highest-priority intent tag. Priority: closing > opening > hero > emotional > detail > informational > transition > untagged.
Assembly:
- Opening scenes first
- Hero scenes second
- Middle: interleave detail/informational/transition/untagged, distributing emotional scenes at even intervals
- Closing scenes last
Post-processing:
- Variety rule — no consecutive same
content_type. Swap with next different type (look-ahead up to 3). - Weight alternation — no 3+ consecutive same
visual_weight. Swap to break runs. - Energy arc — don't start at peak energy unless tagged
hero/opening.
2. Duration assignment
Each scene's duration_s comes from the style pack's hold_durations table, keyed by the scene's motion_energy. If max_hold_duration is set on the pack (energy: 4.0s, kinetic: 3.0s), it acts as a hard cap.
3. Transition selection
The first scene always gets null (no transition in). Subsequent scenes are evaluated through the style pack's transition rules.
4. Camera overrides
Camera overrides are evaluated through the style pack's camera_overrides rules, then validated against the personality's allowed_movements. Moves not allowed by the personality are downgraded to null. drift and static bypass validation.
Transition rules
Transition rules are evaluated in strict priority order. The first matching rule wins.
| Priority | Rule type | Description |
|---|---|---|
| 1 | pattern | Positional — e.g., energy's every-3rd whip-wipe cycle |
| 2 | on_same_weight | Fires when consecutive scenes share visual_weight |
| 3 | on_weight_change | Fires when visual_weight differs between scenes |
| 4 | on_intent | Matches incoming scene's intent_tags |
| 5 | default | Fallback |
Priority matters. on_same_weight fires before on_intent. This means dramatic's same-weight hard cut beats its emotional crossfade when both conditions are true. Prestige has no on_same_weight rule, so its emotional crossfade fires correctly even for same-weight scenes.
Per-style transition behavior
- Prestige — hard cut default. Crossfade (400ms) on weight change or emotional/hero intent.
- Energy — every 3rd transition is a whip-wipe (cycling left/right/up/down), rest are hard cuts.
- Dramatic — crossfade (400ms) default. Hard cut between same-weight scenes. 600ms crossfade for emotional intent.
- Minimal — hard cuts only.
- Intimate — crossfade 500ms default. 800ms crossfade for emotional intent.
- Corporate — hard cut default. Crossfade 300ms on weight change.
- Kinetic — every 2nd transition is a whip-wipe (cycling left/right, 200ms), rest are hard cuts.
- Fade — all crossfade 500ms.
Camera overrides
Three camera rule types, evaluated in order:
| Rule type | Behavior | Used by |
|---|---|---|
force_static | All scenes get { move: 'static' } | energy, minimal, kinetic |
by_content_type | Maps content type to camera move | prestige, intimate, corporate, fade, analog, documentary |
by_intent | Maps intent tag to camera move | dramatic, intimate |
Per-style camera behavior
| Style | portrait | product_shot | ui_screenshot | emotional/hero intent | detail intent |
|---|---|---|---|---|---|
| prestige | push_in 0.2 | push_in 0.2 | drift 0.2 | — | — |
| dramatic | — | — | — | push_in 0.3 | drift 0.3 |
| intimate | push_in 0.15 | push_in 0.15 | — | — | drift 0.15 |
| corporate | — | push_in 0.15 | drift 0.15 | — | — |
| fade | push_in 0.1 | push_in 0.1 | — | — | — |
| energy/minimal/kinetic | static | static | static | static | static |
Per-scene style blending
A single sequence can mix styles by setting metadata.style_override on individual scenes. The override affects that scene's durations, transitions, and camera while the rest uses the default style.
{
"scenes": [
{ "scene_id": "sc_intro", "metadata": { "content_type": "typography", "style_override": "minimal" } },
{ "scene_id": "sc_hero", "metadata": { "content_type": "product_shot" } },
{ "scene_id": "sc_closing", "metadata": { "content_type": "brand_mark", "style_override": "fade" } }
],
"style": "prestige"
}
In this example, sc_intro uses minimal (hard cut, static camera, longer hold), sc_hero uses prestige (sequence default), and sc_closing uses fade (crossfade 500ms, minimal camera).
The style_override travels with the scene through reordering. Unknown overrides throw in the planner. When overrides are used, notes.style_overrides_used lists the unique override names.
Output format
plan_sequence returns a manifest and editorial notes:
{
"manifest": {
"sequence_id": "seq_planned_1710000000",
"resolution": { "w": 1920, "h": 1080 },
"fps": 60,
"style": "prestige",
"scenes": [
{
"scene": "sc_brand_mark",
"duration_s": 3.0,
"transition_in": null,
"camera_override": { "move": "drift", "intensity": 0.2 }
},
{
"scene": "sc_product_ui",
"duration_s": 3.0,
"transition_in": { "type": "crossfade", "duration_ms": 400 },
"camera_override": { "move": "push_in", "intensity": 0.2 }
}
]
},
"notes": {
"total_duration_s": 6.0,
"scene_count": 2,
"style_personality": "editorial",
"ordering_rationale": "...",
"transition_summary": { "crossfade": 1, "null": 1 }
}
}
Style differentiation
The same 4 scenes produce measurably different manifests across styles:
| Metric | prestige | energy | dramatic |
|---|---|---|---|
| Average duration | ~3.0s | ~1.7s | ~3.0s |
| Dominant transition | hard_cut + crossfade | hard_cut + whips | crossfade |
| Camera overrides | selective | all static | selective |
| Total duration | ~11s | ~6s | ~10s |
Try it
Try asking your AI:
Show me the prestige style pack — what are its transition rules and camera overrides?
Plan a sequence from these 6 scenes using the energy style. Show me the shot list and transition summary.
Plan this sequence with prestige as the default, but override the opening scene to use minimal and the closing to use fade.