Reel — Edición narrativa (fotograma completo, movimiento intenso)
El orador permanece a pantalla completa. La historia se cuenta mediante cortes a clips propios del creador, stickers/tarjetas/widgets que aparecen al pronunciar palabras, una mascota que reacciona y momentos de profundidad donde palabras gigantes o un fondo de marca se sitúan detrás del orador (máscara de persona). Ejemplo práctico: examples/story/story_stoodi_inviteraw.py.
Argumentos: $ARGUMENTS
Valores predeterminados (cambiar solo si el usuario lo indica)
Primero leer reel.config.json (si no existe, usar reel.config.example.json).
| Elemento | Predeterminado |
|---|---|
| Subtítulos | Ninguno. Los gráficos con palabras clave están bien; nunca una transcripción continua |
| Audio | Mezcla original de la toma, sin modificar — finish.py la remultiplexa. Sin efectos de sonido, sin música de fondo |
| Toma | Se asume que ya está cortada, etalonada y con música añadida → no cortar ni etalonar. Si es raw/sin editar → preguntar primero |
| B-roll | broll_dir de la configuración; descripciones en work/_catalog/<carpeta>/NOTES.md |
| Marca | brand + palette de la configuración. Sin archivos de mascota → sin escenas de mascota |
| Llamada a la acción (CTA) | Palabra clave del comentario enorme en pantalla; tarjeta de seguir = solo texto @<handle_del_creador>, nunca un recorte de rostro |
| Idioma | language de la configuración (Whisper + qué clase de texto usar) |
Entradas
El nombre de la toma y el tema provienen de los argumentos. Preguntar una vez, en un solo mensaje, solo lo que falta: ¿la toma ya está cortada/etalonada/con música?; palabra clave del comentario; nombres o jerga que Whisper pueda malinterpretar; clips que quieran incluir o excluir.
Pipeline
PY = .venv/Scripts/python.exe -X utf8 (Windows) o .venv/bin/python -X utf8 (macOS/Linux). Pasos largos en segundo plano.
| # | Paso | Comando / acción | Verificar |
|---|---|---|---|
| 1 | Inspeccionar | ffprobe la toma; hoja de contacto ffmpeg -i raw/<toma> -vf fps=1/5,scale=216:384,tile=9x2 -frames:v 1 work/<toma>/sheet.jpg y observarla | ¿espacio sobre la cabeza? ¿texto en el encuadre reflejado? ¿ya etalonada? |
| 2 | Transcribir | $PY tools/transcribe.py <toma> --prompt "<nombres, jerga>" | corregir nombres; espacios entre palabras > 3 s → volver a transcribir ese segmento |
| 3 | Rostro | $PY tools/face_track.py <toma> | imprime FACE = (x, y) y la parte superior de la cabeza |
| 4 | B-roll | $PY tools/story_assets.py <toma> catalog; leer NOTES.md; observar las tiras de clips aún no descritos y añadir sus filas a NOTES.md | banderas HDR / reflejado / VFR |
| 5 | Hoja de ritmos | escribir work/<toma>/beats.md: tiempo | palabras | modo | qué. Reglas a continuación, técnicas en references/techniques.md | cada ritmo anclado a una palabra |
| 6 | Máscara | si hay algún momento de profundidad: $PY tools/story_assets.py <toma> matte (~8 min CPU para 80 s, en segundo plano, sin ffmpeg en paralelo) | work/<toma>/matte/fg.webm |
| 7 | Módulo de toma | copiar examples/story/story_stoodi_inviteraw.py → tools/story_<slug>.py (slug: nombre de la toma, caracteres no alfanuméricos → _); establecer NAME, FACE, BROLL, TILES, MIRRORED, escenas, SCENES (DUR opcional — se sondeará). Nombres de mascota = los archivos en assets/mascot (minúsculas, espacios → -) | |
| 8 | Activos | $PY tools/story_assets.py <toma> all (mascota, logo, recortes de B-roll, mosaicos) | |
| 9 | Construir | $PY tools/story_build.py <toma>; en work/<toma>/sc: npx hyperframes lint public → 0 errores (las advertencias nested_structure son esperadas); npx hyperframes snapshot public -o ../snaps --no-end --describe false --at <cada ritmo>; leer las hojas de contacto, corregir, reconstruir | |
| 10 | Renderizado rápido | $PY tools/finish.py <toma> --seconds 12; leer work/<toma>/sc/quick_sheet.jpg | las superposiciones entran y salen; los colores no están apagados |
| 11 | Renderizado completo | $PY tools/finish.py <toma> (~12 min para 80 s, en segundo plano) → final/<toma>/, verificar, qa/sheet.jpg | leer la hoja fotograma a fotograma |
| 12 | Informe | ruta, duración, ritmos, clips utilizados, cualquier elemento volteado/remapeado de tono, verificar resultado. Si se aprende algo nuevo, agregarlo a esta habilidad |
Reglas de ritmo
- Algo cambia cada 2–4 s; nunca más de ~5 s de orador solo.
- Mezclar los modos: orador + stickers · corte a B-roll (~25–30 % de la duración) · momento de profundidad (4–6 por reel) · gráfico a pantalla completa con el orador como burbuja de cámara frontal (1–2 como máximo).
- Señal = tiempo de inicio de la palabra hablada en
transcript.json. Cada elemento desaparece antes del siguiente ritmo. - Las palabras de profundidad van sobre la cabeza (parte superior de la cabeza del paso 3): una palabra gigante a la vez, la palabra anterior sale volando. Las líneas apiladas terminan ocultas detrás de la cabeza.
- Zonas seguras: sin texto por encima de y 150 (encabezado de Instagram) ni por debajo de y 1560 (leyenda); mantener x < 960 entre y 1100–1650 (botones de me gusta/comentario).
- Los números presentados como hechos deben provenir de la toma. Las etiquetas ilustrativas están bien.
- Texto en farsi/árabe: clase
.fa(RTL limitado al elemento — nuncadir="rtl"en<html>, se renderiza en negro),letter-spacing: 0, dígitos mediantefa(), el cero grande como cero latino0(el cero persa es un punto). Texto en latín:.en; palabras gigantes de exhibición:.blk.
Contrato del motor — errores ya pagados
- Escena =
def scene(c: Comp):c.clip(layer, id, start, end, html, track),c.broll(name, a, b, mstart),c.matte(n, a, b),c.j(js...). Capas:under(detrás de la burbuja),tiles,behind(entre la toma y la máscara),fw,broll,over,fx. - Los divs de clip obtienen id
k-<id>; animar#<id>-io ids internos — nunca un.clipen sí mismo. - Cualquier elemento que se deslice desde fuera de la pantalla necesita
autoAlpha:0en su estado inicial, o se asoma antes de tiempo. - El primer tween de un elemento establece su estado inicial (
fromTose renderiza inmediatamente); tweens posteriores:.tooimmediateRender:false. - Nunca
from:"random"escalonamientos niMath.random— mezclar el orden del DOM en Python conrandom.Random(seed). - Misma propiedad, mismo elemento: un tween debe terminar antes de que comience el siguiente (lint
overlapping_gsap_tweens). #camscale/x/y/clipPath/borderRadius manejan los zoom-ins, la burbuja y el mosaico. La máscara vive dentro de#cam, por lo que los momentos de profundidad permanecen alineados a cualquier escala de cámara.- B-roll de cámara frontal con texto legible en el encuadre → agregar a
MIRRORED. Nunca voltear la toma principal. - Las fuentes HLG/HDR son remapeadas de tono por
story_assets.py. Sifinish.pyse detiene con "HDR auto-promotion", una fuente escapó de esa ruta. hyperframes snapshotno es prueba del renderizado — para eso sirve el paso 10.