Video Scene Analysis
Analyze a local video into a structured scene sequence: cuts, visual type, zoom transitions, transcript with timecodes, and per-scene focus/emotion.
Setup (one-time)
pip3 install -r ~/.cursor/skills/video-scene-analysis/scripts/requirements.txt
bash ~/.cursor/skills/video-scene-analysis/scripts/setup_models.sh
Requires ffmpeg and ffprobe on PATH.
Quick start
SCRIPTS=~/.cursor/skills/video-scene-analysis/scripts
python3 $SCRIPTS/analyze_video.py video.mp4 -o .
python3 $SCRIPTS/analyze_video.py lolo/videos/clip.mp4 -o ./analysis --language es
Outputs in -o directory (default: cwd):
{stem}.analysis.json — machine-readable sequence
{stem}.analysis.md — human-readable report
{stem}_frames/scene_XX.jpg — one sharp representative frame per scene
Agent workflow (mandatory)
The script handles steps 1–4 (visual + audio + frames + a conservative split-screen layout.hint). You (the active session LLM) must complete steps 5–10 (camera, composition, summaries, mannerisms, avatar profile) by viewing the frames before delivering results. Do not call Gemini or any external LLM API.
- Confirm video path and output directory.
- Run setup if models or deps are missing.
- Run
analyze_video.py → JSON with "summary": null and "camera": null per scene, plus {stem}_frames/.
- Read each
representative_frame image (use the Read tool on every scene_XX.jpg). Classify camera for each scene and write scenes[].camera:{
"angle": "eye_level | low_angle | low_angle_v2 | high_angle | three_quarter | dutch_tilt | negative_space | pull_out | zoom_in | none",
"framing": "extreme_close_up | close_up | medium_close_up | medium_shot | medium_wide | wide_shot | unknown",
"description": "Nota breve en español (encuadre vertical, selfie, etc.)"
}
angle must be an English pipeline slug (snake_case), aligned with avatar prompts in lolo/angles/prompts/ when applicable. Use eye_level for baseline frontal talking head; none for B-roll that does not map to the pipeline. Cross-check zoom_from_previous (zoom_in / zoom_out → consider zoom_in / pull_out slugs on presenter shots).
- Composition (every scene — while you have the frame open). From the same
scene_XX.jpg, fill the agent-written composition fields. The script
pre-fills scenes[].layout.hint (fullscreen / possible_split_horizontal /
possible_split_vertical) as a conservative guess you must confirm or correct.
scenes[].layout — screen composition (see Layout taxonomy):{
"type": "fullscreen | split_horizontal | split_vertical | pip | overlay_graphics",
"regions": [
{ "position": "top|bottom|left|right|inset", "content": "broll|main_character|screen|graphics",
"description": "qué se ve en esa región" }
],
"notes": "breve, en español"
}
Always inspect for split scenes: a single scene that shows B-roll in
one band (top or bottom) and the main character talking in the other is
split_horizontal (side-by-side is split_vertical; a small inset is pip).
List one entry per region. For a normal single shot use "fullscreen" with
empty regions.
scenes[].broll_kind (B-roll / supplementary scenes, AND any B-roll
region of a split — see B-roll kind taxonomy). Distinguish pre-recorded
archival footage of a recognizable person (archival_known_person) from
generic complementary material (stock_generic). null for pure talking-head.
scenes[].known_people — array of recognizable real people shown in
pre-recorded footage (names if you recognize them, else short descriptions
like "older male chef, 2000s TV interview"). []/null when none or unsure.
scenes[].background (presenter / talking-head scenes — see Background
taxonomy): is the person's backdrop a real set/location or animated
(drawings, cartoons, motion graphics)?{ "type": "real_set | animated | mixed | plain | virtual | unknown",
"elements": "qué hay detrás (p.ej. 'dibujos animados de nubes', 'oficina real')",
"notes": "opcional" }
null for B-roll / non-presenter scenes.
- Read the JSON metadata. For every scene, write
scenes[].summary using:
transcript, scene_type, layout, zoom_from_previous, visual, camera, audio
- Facial mannerisms (talking-head only). For each
main_character_solo
scene (including the presenter band of a split), while you have the frame
open, write scenes[].mannerisms: a brief (one sentence) note of how the
face/head moves — eyebrow activity, head nods/tilts, eye contact,
mouth/expression, lean, gesture restraint. Leave null for B-roll /
non-presenter scenes.
- Avatar profile (talking head). Synthesize the talking-head mannerisms
into a single reusable
avatar_profile (top-level), consistent across the
video, with:{
"mannerisms_summary": "1-2 sentence description of the recurring facial behavior",
"video_prompt": "Concise p-video-avatar prompt describing how this person naturally speaks to camera (identity-consistent, present tense)",
"negative_prompt": "very brief, comma-separated failure modes to avoid (e.g. exaggerated gestures, big toothy grin, looking away, jittery head movement, subtitles, watermark)"
}
Keep video_prompt short and behavior-focused; keep negative_prompt
brevísimo. If the video has no talking-head scenes, leave avatar_profile null.
- Optionally rewrite
overview (1–2 sentences, Spanish) with the narrative arc.
- Re-render markdown:
python3 $SCRIPTS/render_report.py path/to/{stem}.analysis.json
- Present the final
.analysis.md to the user.
Never skip steps 4–10. Heuristic or API-based summaries/classification are intentionally not used.
Export the talking profile (for avatar-talking-video)
Once avatar_profile is written, export it to the avatar folder so the
avatar-talking-video skill auto-loads it for every generated talking-head clip:
python3 $SCRIPTS/export_talking_profile.py path/to/{stem}.analysis.json
# → writes <avatar>/talking_profile.json (avatar dir auto-inferred; override with --avatar-dir)
Pass several analyses to pick the first with a profile; preview with --dry-run.
Batch
Run the script for each video, then enrich each JSON before re-rendering:
SCRIPTS=~/.cursor/skills/video-scene-analysis/scripts
OUT=./analysis
mkdir -p "$OUT"
for f in lolo/videos/*.mp4; do
python3 $SCRIPTS/analyze_video.py "$f" -o "$OUT" --language es
done
# → enrich each $OUT/*.analysis.json, then render_report.py on each
Script options
| Option |
Default |
Description |
-o DIR |
cwd |
Output directory |
--scene-mode |
auto |
auto, detect (PySceneDetect), interval (fixed windows) |
--interval |
6 |
Target scene length (4/6/8) for interval/fallback |
--min-scene-duration |
2.5 |
Merge shorter scenes |
--language |
auto |
Transcription language (es, en, …) |
--whisper-model |
small |
tiny (fast), small, medium, large-v3 |
--skip-transcription |
off |
Visual-only analysis |
--skip-audio-events |
off |
Skip SFX/music detection |
--skip-frames |
off |
Skip representative frame extraction |
Camera taxonomy (agent-written)
camera.angle — English pipeline slug (primary)
| Slug |
Meaning |
eye_level |
Frontal baseline, cámara a altura de ojos |
low_angle |
Contrapicado leve (~16°) |
low_angle_v2 |
Contrapicado pronunciado (variante v2) |
high_angle |
Picado |
three_quarter |
Tres cuartos (~30° horizontal) |
dutch_tilt |
Inclinación holandesa |
negative_space |
Sujeto desplazado, espacio libre para captions |
pull_out |
Alejamiento / plano más abierto |
zoom_in |
Acercamiento / plano más cerrado |
none |
B-roll u otro inserto sin slug de pipeline |
Prompts de referencia: lolo/angles/prompts/{slug}.txt
camera.framing — shot size
| Slug |
Meaning |
extreme_close_up |
Ojos/boca, recorte muy cerrado |
close_up |
Cabeza y hombros |
medium_close_up |
Pecho arriba (talking head típico) |
medium_shot |
Cintura arriba |
medium_wide |
Rodillas arriba / americano |
wide_shot |
Cuerpo completo o entorno dominante |
Layout taxonomy (scene.layout.type — agent-written)
A single scene can combine B-roll and the presenter. Capture that here (the
script only pre-fills layout.hint).
| Slug |
Meaning |
fullscreen |
Un solo plano ocupa todo el cuadro (lo más común) |
split_horizontal |
Pantalla dividida en bandas: B-roll arriba/abajo + personaje en la otra banda |
split_vertical |
Pantalla dividida lado a lado (izquierda/derecha) |
pip |
Picture-in-picture: un recuadro pequeño sobre el plano principal |
overlay_graphics |
Gráficos/animación superpuestos sobre el plano |
For splits/pip list one regions[] entry per band: position
(top/bottom/left/right/inset) + content
(broll/main_character/screen/graphics) + a short description.
B-roll kind taxonomy (scene.broll_kind — agent-written)
For B-roll / supplementary scenes (and the B-roll region of a split), say what
kind of footage it is — pre-recorded archival of a known person vs generic.
| Slug |
Meaning |
archival_known_person |
Material pregrabado donde aparece una persona reconocible/célebre (ej. una entrevista de Anthony Bourdain) |
archival_footage |
Material pregrabado real (personas no célebres, noticias, found footage) |
stock_generic |
Stock / complementario genérico (objetos, paisajes, manos) |
screen_recording |
Captura de pantalla / demo |
graphics_animation |
Gráficos o animación (no footage real) |
other |
Otro |
Record any recognizable people in scene.known_people (array of names or short
descriptions). When a reel leans on archival_known_person/archival_footage,
sourcing it for a new reel is the job of the broll-finder skill (real
YouTube footage), not broll-generator (synthetic).
Background taxonomy (scene.background.type — agent-written, presenter scenes)
Is the main character's backdrop a real place or animated?
| Slug |
Meaning |
real_set |
Escenografía o locación real |
animated |
Fondo animado: dibujos, cartoons, motion graphics detrás de la persona |
mixed |
Real con elementos animados encima |
plain |
Fondo plano / liso (pared lisa, color sólido) |
virtual |
Fondo virtual / croma |
unknown |
No determinable |
Put a short description of what's behind the person in background.elements.
Audio profiles (per scene)
audio_profile |
Meaning |
speech_only |
Solo voz |
speech_with_sfx |
Voz + efectos puntuales |
speech_with_music |
Voz + música/ambiente continuo |
speech_mixed |
Voz + SFX + música |
sfx_only |
Solo efectos, sin voz |
music_only |
Solo música/ambiente |
ambient / silent |
Fondo bajo / sin audio relevante |
Heuristic: Whisper masks speech intervals; transients in non-speech audio → SFX; sustained energy → music bed. For mixes complejos, usar Demucs (youtube-audio-toolkit) como complemento.
What the script detects vs what you write
| Step |
Who |
What |
| Scene boundaries |
Script |
PySceneDetect + interval fallback |
| Scene type |
Script |
MediaPipe face + edge heuristics |
| Zoom vs previous |
Script |
Face area + ORB → zoom_in, zoom_out, none, hard_cut |
| Transcript |
Script |
ffmpeg + faster-whisper with word timestamps |
| SFX / music bed |
Script |
Energy + transients in non-speech windows |
| Representative frame |
Script |
Sharpest sample at 25/50/75% of scene → {stem}_frames/ |
| Split-screen hint |
Script |
Seam + half-histogram heuristic → layout.hint (you confirm) |
| Camera angle + framing |
Agent (you) |
Vision on each scene_XX.jpg |
| Layout / split-screen |
Agent (you) |
layout.type + regions (B-roll band + presenter band, pip, overlays) |
| B-roll kind + known people |
Agent (you) |
broll_kind (archival-known-person vs generic) + known_people |
| Presenter background |
Agent (you) |
background.type (real set vs animated drawings) |
| Focus + emotion |
Agent (you) |
Per-scene narrative summary in Spanish |
| Facial mannerisms |
Agent (you) |
Per talking-head scene: how the face/head moves |
| Avatar profile |
Agent (you) |
Reusable video_prompt + negative_prompt → talking_profile.json |
Scene types
| Key |
Meaning |
main_character_solo |
Talking head / personaje principal |
supplementary_material |
B-roll, inserts |
multi_person |
Multiple faces |
screen_demo |
Screen capture / UI |
unknown |
Unclassified keyframe |
Tips
- Reels with hard cuts:
--scene-mode detect (default in auto).
- Uniform 6s windows:
--scene-mode interval --interval 6.
- Quick smoke test on transcript only:
--whisper-model tiny.
- Long videos (>3 min):
--whisper-model small.
Troubleshooting
- Face model not found → run
setup_models.sh.
- scenedetect / faster-whisper missing → reinstall requirements.
- No transcript → check audio track; try
--language es.
- MD shows "Pendiente" → you skipped agent enrichment (summary or camera).
Reference
JSON schema: REFERENCE.md
1---2name: video-scene-analysis3description: Analyze local video files (mp4, mov, webm) into scene sequences: scene-change detection, scene type (talking head vs B-roll), split-screen / screen-composition detection (B-roll band + presenter, picture-in-picture, graphic overlays), B-roll kind (archival footage of a recognizable/known person vs generic material, naming the people), presenter background (real set/location vs animated/cartoons/motion graphics), zoom in/out vs previous scene, faster-whisper transcription with timecodes, SFX/music-bed detection per scene, a representative frame per scene, and per-scene focus/emotion summaries. Outputs .analysis.json, .analysis.md, and a frames folder. Use when the user asks to analyze a video, detect scenes, camera angle, split-screen layouts, archival/known-person footage, animated vs real backgrounds, transcribe a local video, detect SFX or background music, build a shot list from footage, or understand reel/avatar video structure.4---56# Video Scene Analysis78Analyze a local video into a structured scene sequence: cuts, visual type, zoom transitions, transcript with timecodes, and per-scene focus/emotion.910## Setup (one-time)1112```bash13pip3 install -r ~/.cursor/skills/video-scene-analysis/scripts/requirements.txt14bash ~/.cursor/skills/video-scene-analysis/scripts/setup_models.sh15```1617Requires `ffmpeg` and `ffprobe` on PATH.1819## Quick start2021```bash22SCRIPTS=~/.cursor/skills/video-scene-analysis/scripts2324python3 $SCRIPTS/analyze_video.py video.mp4 -o .25python3 $SCRIPTS/analyze_video.py lolo/videos/clip.mp4 -o ./analysis --language es26```2728Outputs in `-o` directory (default: cwd):2930- `{stem}.analysis.json` — machine-readable sequence31- `{stem}.analysis.md` — human-readable report32- `{stem}_frames/scene_XX.jpg` — one sharp representative frame per scene3334## Agent workflow (mandatory)3536The script handles **steps 1–4** (visual + audio + frames + a conservative split-screen `layout.hint`). **You** (the active session LLM) must complete **steps 5–10** (camera, composition, summaries, mannerisms, avatar profile) by viewing the frames before delivering results. Do **not** call Gemini or any external LLM API.37381. Confirm video path and output directory.392. Run setup if models or deps are missing.403. Run `analyze_video.py` → JSON with `"summary": null` and `"camera": null` per scene, plus `{stem}_frames/`.414. **Read each `representative_frame` image** (use the Read tool on every `scene_XX.jpg`). Classify camera for each scene and write `scenes[].camera`:42 ```json43 {44 "angle": "eye_level | low_angle | low_angle_v2 | high_angle | three_quarter | dutch_tilt | negative_space | pull_out | zoom_in | none",45 "framing": "extreme_close_up | close_up | medium_close_up | medium_shot | medium_wide | wide_shot | unknown",46 "description": "Nota breve en español (encuadre vertical, selfie, etc.)"47 }48 ```49 **`angle` must be an English pipeline slug** (snake_case), aligned with avatar prompts in `lolo/angles/prompts/` when applicable. Use `eye_level` for baseline frontal talking head; `none` for B-roll that does not map to the pipeline. Cross-check `zoom_from_previous` (`zoom_in` / `zoom_out` → consider `zoom_in` / `pull_out` slugs on presenter shots).505. **Composition (every scene — while you have the frame open).** From the same51 `scene_XX.jpg`, fill the agent-written composition fields. The script52 pre-fills `scenes[].layout.hint` (`fullscreen` / `possible_split_horizontal` /53 `possible_split_vertical`) as a conservative guess you must confirm or correct.54 - **`scenes[].layout`** — screen composition (see *Layout taxonomy*):55 ```json56 {57 "type": "fullscreen | split_horizontal | split_vertical | pip | overlay_graphics",58 "regions": [59 { "position": "top|bottom|left|right|inset", "content": "broll|main_character|screen|graphics",60 "description": "qué se ve en esa región" }61 ],62 "notes": "breve, en español"63 }64 ```65 **Always inspect for split scenes:** a single scene that shows **B-roll in66 one band (top or bottom) and the main character talking in the other** is67 `split_horizontal` (side-by-side is `split_vertical`; a small inset is `pip`).68 List one entry per region. For a normal single shot use `"fullscreen"` with69 empty `regions`.70 - **`scenes[].broll_kind`** (B-roll / supplementary scenes, AND any B-roll71 region of a split — see *B-roll kind taxonomy*). Distinguish **pre-recorded72 archival footage of a recognizable person** (`archival_known_person`) from73 generic complementary material (`stock_generic`). null for pure talking-head.74 - **`scenes[].known_people`** — array of recognizable real people shown in75 pre-recorded footage (names if you recognize them, else short descriptions76 like "older male chef, 2000s TV interview"). `[]`/null when none or unsure.77 - **`scenes[].background`** (presenter / talking-head scenes — see *Background78 taxonomy*): is the person's backdrop a **real set/location** or **animated**79 (drawings, cartoons, motion graphics)?80 ```json81 { "type": "real_set | animated | mixed | plain | virtual | unknown",82 "elements": "qué hay detrás (p.ej. 'dibujos animados de nubes', 'oficina real')",83 "notes": "opcional" }84 ```85 null for B-roll / non-presenter scenes.866. Read the JSON metadata. For **every** scene, write `scenes[].summary` using:87 - `transcript`, `scene_type`, `layout`, `zoom_from_previous`, `visual`, `camera`, `audio`887. **Facial mannerisms (talking-head only).** For each `main_character_solo`89 scene (including the presenter band of a split), while you have the frame90 open, write `scenes[].mannerisms`: a brief (one sentence) note of how the91 face/head moves — eyebrow activity, head nods/tilts, eye contact,92 mouth/expression, lean, gesture restraint. Leave `null` for B-roll /93 non-presenter scenes.948. **Avatar profile (talking head).** Synthesize the talking-head mannerisms95 into a single reusable `avatar_profile` (top-level), consistent across the96 video, with:97 ```json98 {99 "mannerisms_summary": "1-2 sentence description of the recurring facial behavior",100 "video_prompt": "Concise p-video-avatar prompt describing how this person naturally speaks to camera (identity-consistent, present tense)",101 "negative_prompt": "very brief, comma-separated failure modes to avoid (e.g. exaggerated gestures, big toothy grin, looking away, jittery head movement, subtitles, watermark)"102 }103 ```104 Keep `video_prompt` short and behavior-focused; keep `negative_prompt`105 **brevísimo**. If the video has no talking-head scenes, leave `avatar_profile` null.1069. Optionally rewrite `overview` (1–2 sentences, Spanish) with the narrative arc.10710. Re-render markdown:108 ```bash109 python3 $SCRIPTS/render_report.py path/to/{stem}.analysis.json110 ```11111. Present the final `.analysis.md` to the user.112113**Never skip steps 4–10.** Heuristic or API-based summaries/classification are intentionally not used.114115### Export the talking profile (for avatar-talking-video)116117Once `avatar_profile` is written, export it to the avatar folder so the118`avatar-talking-video` skill auto-loads it for every generated talking-head clip:119120```bash121python3 $SCRIPTS/export_talking_profile.py path/to/{stem}.analysis.json122# → writes <avatar>/talking_profile.json (avatar dir auto-inferred; override with --avatar-dir)123```124125Pass several analyses to pick the first with a profile; preview with `--dry-run`.126127### Batch128129Run the script for each video, then enrich each JSON before re-rendering:130131```bash132SCRIPTS=~/.cursor/skills/video-scene-analysis/scripts133OUT=./analysis134mkdir -p "$OUT"135for f in lolo/videos/*.mp4; do136 python3 $SCRIPTS/analyze_video.py "$f" -o "$OUT" --language es137done138# → enrich each $OUT/*.analysis.json, then render_report.py on each139```140141## Script options142143| Option | Default | Description |144|--------|---------|-------------|145| `-o DIR` | cwd | Output directory |146| `--scene-mode` | `auto` | `auto`, `detect` (PySceneDetect), `interval` (fixed windows) |147| `--interval` | `6` | Target scene length (4/6/8) for interval/fallback |148| `--min-scene-duration` | `2.5` | Merge shorter scenes |149| `--language` | auto | Transcription language (`es`, `en`, …) |150| `--whisper-model` | `small` | `tiny` (fast), `small`, `medium`, `large-v3` |151| `--skip-transcription` | off | Visual-only analysis |152| `--skip-audio-events` | off | Skip SFX/music detection |153| `--skip-frames` | off | Skip representative frame extraction |154155## Camera taxonomy (agent-written)156157### `camera.angle` — English pipeline slug (primary)158159| Slug | Meaning |160|------|---------|161| `eye_level` | Frontal baseline, cámara a altura de ojos |162| `low_angle` | Contrapicado leve (~16°) |163| `low_angle_v2` | Contrapicado pronunciado (variante v2) |164| `high_angle` | Picado |165| `three_quarter` | Tres cuartos (~30° horizontal) |166| `dutch_tilt` | Inclinación holandesa |167| `negative_space` | Sujeto desplazado, espacio libre para captions |168| `pull_out` | Alejamiento / plano más abierto |169| `zoom_in` | Acercamiento / plano más cerrado |170| `none` | B-roll u otro inserto sin slug de pipeline |171172Prompts de referencia: `lolo/angles/prompts/{slug}.txt`173174### `camera.framing` — shot size175176| Slug | Meaning |177|------|---------|178| `extreme_close_up` | Ojos/boca, recorte muy cerrado |179| `close_up` | Cabeza y hombros |180| `medium_close_up` | Pecho arriba (talking head típico) |181| `medium_shot` | Cintura arriba |182| `medium_wide` | Rodillas arriba / americano |183| `wide_shot` | Cuerpo completo o entorno dominante |184185## Layout taxonomy (`scene.layout.type` — agent-written)186187A single scene can combine B-roll and the presenter. Capture that here (the188script only pre-fills `layout.hint`).189190| Slug | Meaning |191|------|---------|192| `fullscreen` | Un solo plano ocupa todo el cuadro (lo más común) |193| `split_horizontal` | Pantalla dividida en bandas: B-roll arriba/abajo + personaje en la otra banda |194| `split_vertical` | Pantalla dividida lado a lado (izquierda/derecha) |195| `pip` | Picture-in-picture: un recuadro pequeño sobre el plano principal |196| `overlay_graphics` | Gráficos/animación superpuestos sobre el plano |197198For splits/pip list one `regions[]` entry per band: `position`199(`top`/`bottom`/`left`/`right`/`inset`) + `content`200(`broll`/`main_character`/`screen`/`graphics`) + a short `description`.201202## B-roll kind taxonomy (`scene.broll_kind` — agent-written)203204For B-roll / supplementary scenes (and the B-roll region of a split), say **what205kind** of footage it is — pre-recorded archival of a known person vs generic.206207| Slug | Meaning |208|------|---------|209| `archival_known_person` | Material pregrabado donde aparece una persona **reconocible/célebre** (ej. una entrevista de Anthony Bourdain) |210| `archival_footage` | Material pregrabado real (personas no célebres, noticias, found footage) |211| `stock_generic` | Stock / complementario genérico (objetos, paisajes, manos) |212| `screen_recording` | Captura de pantalla / demo |213| `graphics_animation` | Gráficos o animación (no footage real) |214| `other` | Otro |215216Record any recognizable people in `scene.known_people` (array of names or short217descriptions). When a reel leans on `archival_known_person`/`archival_footage`,218sourcing it for a new reel is the job of the **`broll-finder`** skill (real219YouTube footage), not `broll-generator` (synthetic).220221## Background taxonomy (`scene.background.type` — agent-written, presenter scenes)222223Is the main character's backdrop a real place or animated?224225| Slug | Meaning |226|------|---------|227| `real_set` | Escenografía o locación real |228| `animated` | Fondo animado: dibujos, cartoons, motion graphics detrás de la persona |229| `mixed` | Real con elementos animados encima |230| `plain` | Fondo plano / liso (pared lisa, color sólido) |231| `virtual` | Fondo virtual / croma |232| `unknown` | No determinable |233234Put a short description of what's behind the person in `background.elements`.235236## Audio profiles (per scene)237238| `audio_profile` | Meaning |239|-----------------|---------|240| `speech_only` | Solo voz |241| `speech_with_sfx` | Voz + efectos puntuales |242| `speech_with_music` | Voz + música/ambiente continuo |243| `speech_mixed` | Voz + SFX + música |244| `sfx_only` | Solo efectos, sin voz |245| `music_only` | Solo música/ambiente |246| `ambient` / `silent` | Fondo bajo / sin audio relevante |247248Heuristic: Whisper masks speech intervals; transients in non-speech audio → SFX; sustained energy → music bed. For mixes complejos, usar Demucs (`youtube-audio-toolkit`) como complemento.249250## What the script detects vs what you write251252| Step | Who | What |253|------|-----|------|254| Scene boundaries | Script | PySceneDetect + interval fallback |255| Scene type | Script | MediaPipe face + edge heuristics |256| Zoom vs previous | Script | Face area + ORB → `zoom_in`, `zoom_out`, `none`, `hard_cut` |257| Transcript | Script | ffmpeg + faster-whisper with word timestamps |258| SFX / music bed | Script | Energy + transients in non-speech windows |259| Representative frame | Script | Sharpest sample at 25/50/75% of scene → `{stem}_frames/` |260| Split-screen hint | Script | Seam + half-histogram heuristic → `layout.hint` (you confirm) |261| Camera angle + framing | **Agent (you)** | Vision on each `scene_XX.jpg` |262| Layout / split-screen | **Agent (you)** | `layout.type` + `regions` (B-roll band + presenter band, pip, overlays) |263| B-roll kind + known people | **Agent (you)** | `broll_kind` (archival-known-person vs generic) + `known_people` |264| Presenter background | **Agent (you)** | `background.type` (real set vs animated drawings) |265| Focus + emotion | **Agent (you)** | Per-scene narrative summary in Spanish |266| Facial mannerisms | **Agent (you)** | Per talking-head scene: how the face/head moves |267| Avatar profile | **Agent (you)** | Reusable `video_prompt` + `negative_prompt` → `talking_profile.json` |268269## Scene types270271| Key | Meaning |272|-----|---------|273| `main_character_solo` | Talking head / personaje principal |274| `supplementary_material` | B-roll, inserts |275| `multi_person` | Multiple faces |276| `screen_demo` | Screen capture / UI |277| `unknown` | Unclassified keyframe |278279## Tips280281- Reels with hard cuts: `--scene-mode detect` (default in `auto`).282- Uniform 6s windows: `--scene-mode interval --interval 6`.283- Quick smoke test on transcript only: `--whisper-model tiny`.284- Long videos (>3 min): `--whisper-model small`.285286## Troubleshooting287288- **Face model not found** → run `setup_models.sh`.289- **scenedetect / faster-whisper missing** → reinstall requirements.290- **No transcript** → check audio track; try `--language es`.291- **MD shows "_Pendiente_"** → you skipped agent enrichment (summary or camera).292293## Reference294295JSON schema: [REFERENCE.md](REFERENCE.md)