Communitygithub.com

johnnyfekete/video-framing

Encuadra cortes de entrevista en DaVinci Resolve Studio como un editor profesional. Recorta cada configuración de cámara a un encuadre limpio y centrado, eliminando el desorden y añadiendo zooms dinámicos para mejorar la narrativa visual.

¿Qué es video-framing?

Esta habilidad automatiza la tediosa y altamente artesanal tarea de encuadrar cortes de 'talking head' (persona hablando a cámara) en DaVinci Resolve Studio. Está diseñada para ser utilizada después de `video-tighten` (que oculta los cortes bruscos que esta genera) y antes de `video-color`. Su objetivo es transformar un corte 'amateur' y desordenado en una pieza visualmente profesional. La habilidad funciona mediante un pipeline de scripts de Python que: (1) analiza meticulosamente el metraje para identificar rostros, ojos, manos y configuraciones de cámara; (2) te presenta imágenes fijas y te pide que tomes decisiones críticas (qué es desorden, qué es decorado, qué líneas merecen un zoom); (3) resuelve matemáticamente el mejor encuadre posible, respetando reglas cinematográficas como mantener los ojos en la línea del tercio superior y evitar cortar las manos en movimiento; y (4) aplica estos cambios en Resolve, creando una nueva versión de la línea de tiempo y generando un informe detallado. Los usuarios deben tener instalados `resolve-bridge`, `ffmpeg`, `ffprobe` y `swift`. La habilidad es principalmente autónoma, pero requiere que el usuario tome decisiones estéticas cruciales y luego revise los resultados. Aunque `apply` configura los encuadres y zooms, los fotogramas clave para las transiciones de zoom deben añadirse manualmente en el Inspector de Resolve, un paso que la habilidad facilita mediante comandos paso a paso.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/johnnyfekete/resolve-video-skills/tree/HEAD/skills/video-framing

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace video-framing?

Ejecútala después de video-tighten (oculta los cortes bruscos que esta crea) y antes de video-color. Requiere la habilidad resolve-bridge instalada junto a esta (la encuentra en ../resolve-bridge, o configurando RVS_BRIDGE), además de ffmpeg, ffprobe y swift (macOS lo incluye; Apple Vision mide rostros y manos). La transcripción necesita uv (Whisper local) o un comando de transcripción en RVS_TRANSCRIBE_CMD; si la transcripción falla, prepare continúa con una advertencia y la transcripción queda incompleta.

Ejecuta los scripts como python3 <carpeta de esta habilidad>/scripts/framing.py <comando> --workdir <carpeta>. Comandos: prepare, solve, apply, pushes.

Los scripts miden y hacen los cálculos. Tú tomas las decisiones (qué es desorden, qué configuraciones son simples, qué líneas merecen un zoom). Nunca te detengas a pedir aprobación. El usuario revisa después. Una decisión de la que no estés seguro se aplica igual y el proceso continúa; añádela a la lista issues en decisions.json (ver Cómo decidir), y apply la convierte en un elemento de la lista de verificación. Los campos reason solo aparecen en el informe.

Flujo de trabajo

  1. Dónde estamos. python3 <resolve-bridge>/scripts/rvs.py --workdir <carpeta> status. Adopta la línea de tiempo primero si aún no se ha rastreado nada (ver resolve-bridge).

  2. Preparar. No cambia nada en Resolve:

    python3 scripts/framing.py prepare --workdir <carpeta>
    

    Si Resolve está abierto y la línea de tiempo rastreada tiene ediciones manuales que aún no están registradas, prepare primero las registra como una nueva versión (manual, "ediciones manuales antes del encuadre") a través de resolve-bridge, y lo notifica. Informa al usuario. Si Resolve está abierto y su modo de escalado haría que apply se negara (ver Qué hace en la línea de tiempo), prepare imprime una advertencia al inicio, para que el usuario pueda cambiarlo antes de la ejecución larga.

    Encuentra los elementos en cámara, los agrupa en configuraciones de cámara, mide rostro, ojos, cuerpo y manos (aproximadamente 4 muestras por segundo), y escribe:

    • generated/framing/setups/<id>.jpg: una imagen fija por configuración con una cuadrícula etiquetada al 10% (0.0 a 1.0 en ambos ejes);
    • .edit/framing/transcript.md: MM:SS.ss-MM:SS.ss <configuración> <texto>, una línea por frase escuchada en cámara, en tiempo de línea de tiempo. Cada fragmento en cámara contiene solo las palabras dentro de su propio rango de origen (tiempos de palabra de Whisper), para que nada se repita entre fragmentos, y los tiempos son los de la primera y última palabra. Selecciona los rangos de zoom directamente de estas líneas;
    • .edit/framing/decisions.json: una plantilla con cada configuración vacía (una re-ejecución mantiene las decisiones para configuraciones cuyos elementos no cambiaron), context.json con presupuestos e imágenes fijas.

    La primera ejecución de prepare es lenta: la medición toma aproximadamente 1.5 s por segundo de metraje, y Whisper se ejecuta una vez por archivo de origen. Ejecútala en segundo plano y espera decenas de minutos para un video de 5 minutos. Imprime una línea de progreso por elemento y por origen (vaciada, por lo que un registro redirigido la muestra). Las ejecuciones posteriores se almacenan en caché y son rápidas; una actualización de la habilidad que cambie la forma de medir realiza una medición adicional.

    Imprime una línea por configuración (elementos, presupuesto de zoom, imagen fija) y el número de elementos que ya tienen encuadre manual: esos se dejan exactamente como están, y la lista está en context.json y REPORT.md.

  3. Decidir. Observa cada imagen fija de configuración y completa decisions.json (ver Cómo decidir). Luego selecciona las líneas para zoom.

  4. Resolver. Una ejecución de prueba que no cambia nada en Resolve y nunca se conecta a él. Siempre funciona a partir del plan registrado de la versión actual en el estado rastreado (una línea de tiempo adoptada a través de resolve-bridge), por lo que las ediciones manuales hechas en Resolve desde la última versión registrada no están incluidas: prepare y apply las registran primero.

    python3 scripts/framing.py solve --workdir <carpeta>
    

    Escribe generated/framing/REPORT.md, setups/<id>_before_after.jpg por configuración y flags/<n>.jpg por elemento marcado, y .edit/framing/solution.json. Un decisions.json inválido (etiqueta faltante, cuadro fuera de 0..1) se detiene con el motivo y código de salida 2.

  5. Revisa las previsualizaciones tú mismo. Abre cada imagen de antes/después y las imágenes de marcadores. Cada previsualización muestra un fotograma: el primer elemento de la configuración, o el elemento marcado, en su punto medio. Un gesto en otro elemento o en otro momento no está incluido, por lo que revisa la previsualización de cada elemento marcado, no solo las de la configuración, y lee el texto del marcador. Para una mano que está baja en el encuadre (alcanzando hacia el objetivo, gesticulando cerca del borde inferior), considera "bottom_hands": "gesture" incluso si el único fotograma mostrado se ve bien. Disposición: la mitad izquierda es el metraje completo con el encuadre que se envía en verde, los cuadros de exclusión en rojo y los cuadros de inclusión en azul (el fotograma final de un zoom en cian; en un marcador sobre un zoom omitido o un zoom abandonado, el intento rechazado en naranja); la mitad derecha es el resultado tal como lo ve el espectador, con tercios. Busca las cosas que las reglas prohíben: una tangente a lo largo del borde del encuadre, una mano recortada (si una mano se corta en el borde inferior mientras alcanza hacia el objetivo o gesticula, no descansando sobre las rodillas o una mesa, establece "bottom_hands": "gesture" en esa configuración y resuelve de nuevo), una cabeza demasiado cerca de la parte superior, desorden aún en un borde, una planta elegida recortada. Si un encuadre se ve mal, corrige tus propias decisiones (mueve un cuadro, cambia una etiqueta, elimina un zoom) y resuelve de nuevo. Repite hasta que las previsualizaciones estén bien o los problemas restantes sean solo aquellos que una persona puede juzgar. Lee también los marcadores del informe y los zooms descartados: el informe proporciona los detalles brutos de cada marcador (coordenadas del cuadro, claves del elemento) debajo de él; los elementos de la lista de verificación reciben el texto breve en lenguaje sencillo.

  6. Aplicar. Necesita Resolve abierto con el proyecto cargado.

    python3 scripts/framing.py apply --workdir <carpeta>
    

    Resuelve de nuevo, luego bifurca <base>_vNN_framing a través de resolve-bridge (los grados, efectos y ediciones manuales se mantienen), establece Zoom, Panorámica y Inclinación (un clip con zoom obtiene su fotograma inicial), archiva la versión anterior y guarda el proyecto. Después de que el paso esté registrado, cada marcador y cada entrada de tu lista issues se convierte en un elemento en EDIT_CHECKLIST.md, ubicado por nombre de clip y código de tiempo. Los marcadores se fusionan primero: todos los zooms omitidos de una configuración se convierten en un elemento con sus razones contadas, y los marcadores idénticos en una configuración se convierten en uno solo. Informa al usuario el nuevo nombre de la línea de tiempo, los IDs de los elementos y dónde está el informe. El código de salida 2 significa un error esperado con un mensaje (sin línea de tiempo rastreada, un modo de escalado para el que el encuadre no está calibrado, etc.).

  7. Añadir fotogramas clave a los zooms en el Inspector. La API de scripting de Resolve no puede crear fotogramas clave, por lo que apply deja cada clip con zoom en su fotograma inicial, escribe .edit/framing/keyframes_todo.json y añade un elemento de la lista de verificación por zoom con los valores exactos. Si tienes control de computadora, hazlo ahora; de lo contrario, informa al usuario que los elementos son suyos (aproximadamente un minuto por clip), y se marcan como completados por pushes check después de la siguiente sincronización de ediciones manuales del usuario.

    python3 scripts/framing.py pushes begin --workdir <carpeta>     # bifurca <base>_vNN_pushins, lista los zooms
    python3 scripts/framing.py pushes goto 1 start --workdir <carpeta>
    python3 scripts/framing.py pushes finish --workdir <carpeta>    # verifica los fotogramas clave, guarda, cierra los elementos
    

    Para cada zoom, en el Inspector de la página de Edición de Resolve (Video > Transformar). El control de aplicaciones en segundo plano no puede escribir en Resolve, por lo que esto necesita control de pantalla completa:

    1. pushes goto N start. El script mueve el cabezal de reproducción, y el Inspector lo sigue. Hacer clic en un clip puede mover el cabezal un fotograma, por lo que no hagas clic en la línea de tiempo después. Verifica que el Inspector nombre el clip.
    2. Haz clic en los diamantes de fotograma clave de Zoom y Posición, a la derecha de cada fila. Se vuelven rojos. Los valores ya son los del fotograma inicial.
    3. pushes goto N end. Haz doble clic en Zoom X, luego selecciona todo, escribe el zoom final y presiona Retorno (Zoom Y lo sigue cuando está vinculado). Haz lo mismo para Posición X e Y. Aparecen nuevos fotogramas clave por sí solos.
    4. Suavizado: haz clic derecho en cada diamante rojo. Al final, elige Entrada suave. Al inicio, una vez que existe el final, elige Entrada y salida suaves. El menú de un fotograma clave solo ofrece los suavizados que permiten sus vecinos, y la marca de verificación no siempre se actualiza, por lo que verifica el resultado: a la mitad, el Zoom debería estar cerca del promedio de los dos valores, y a un cuarto debería estar por debajo del valor de línea recta.
    5. Nunca establezcas una propiedad mediante script en un clip con fotogramas clave: Resolve elimina todos sus fotogramas clave.

    pushes finish lee los fotogramas clave de vuelta (a través de una exportación FCPXML) y compara fotogramas y valores. Si falta uno o es incorrecto, indica cuál y deja el paso abierto. --partial guarda de todos modos y deja esos elementos abiertos. pushes check hace la misma verificación sin guardar. apply --pushes fusion hace zoques de Transformación Fusion en su lugar (la forma antigua, completamente automatizada).

Cómo decidir

decisions.json:

{
  "setups": {
    "A": {
      "items": ["..."],
      "label": "plain",
      "reason": "sentado en la mesa, de frente, estático. Microondas con imanes en el borde derecho, silla extra en el extremo izquierdo; la planta se queda.",
      "keep_out": [[0.00, 0.45, 0.12, 1.00], [0.86, 0.30, 1.00, 0.80]],
      "keep_in":  [[0.60, 0.20, 0.74, 0.62]]
    },
    "B": {"items": ["..."], "label": "dynamic", "reason": "sentado en la encimera, ángulo alto", "keep_out": [], "keep_in": []}
  },
  "reclassify": {"V1@1234": "broll"},
  "push_ins": [
    {"start_s": 41.2, "end_s": 47.0, "text": "Escribir es pensar.",
     "reason": "la tesis, primera vez que se dice claramente"}
  ],
  "issues": [
    {"text": "Planta en el borde derecho recortada con las mesas de centro; no estoy seguro de que fuera desorden",
     "where": "S04_IMG_1234.MOV en 00:14.00"}
  ]
}

Los cuadros son [izquierda, superior, derecha, inferior], normalizados 0..1 en la imagen fija de la configuración (léelos de su cuadrícula). start_s y end_s son segundos de línea de tiempo de transcript.md. items es completado por prepare; déjalo.

  • Cuadros de exclusión: todo lo que nadie eligió mostrar, cerca de los bordes. Electrodomésticos, imanes, sillas extra, lámparas, cables, termostatos, marcos de puerta, un fragmento de sofá. El solucionador los recorta donde puede sin recortar un gesto.
  • Cuadros de inclusión: decoración elegida por el hablante. Plantas, flores, un jarrón. El solucionador los mantiene completos, o los recorta claramente, nunca un fragmento. Encuadra la parte que importa (el ramo, las hojas de la planta), no hasta el borde del metraje: un cuadro que toca el borde del metraje nunca puede mantenerse completo dentro de un recorte.
  • Etiqueta cada configuración como plain o dynamic. plain es de frente, a la altura de los ojos y estático (sentado en una mesa). dynamic es un ángulo alto o bajo, una posición inusual (sentado en una encimera) o una diagonal fuerte. Las configuraciones dinámicas no reciben zooms.
  • Razón: una línea por configuración, siempre. Aparece en el informe.
  • Manos bajas (opcional): "bottom_hands": "gesture" en una configuración. Por defecto, las manos que tocan la parte inferior del metraje (desde el 93% de su altura hacia abajo) cuentan como en reposo: el encuadre puede detenerse por encima de ellas. Las manos que alcanzan hacia el objetivo también tocan el borde inferior, y esa regla las recortaría. Si una previsualización de antes/después o de marcador muestra una mano cortada en el borde inferior mientras alcanza o gesticula, establece esto en esa configuración y resuelve de nuevo: esas manos entonces cuentan por completo, y el encuadre es más amplio.
  • Issues: cada decisión de la que no estés seguro (desorden o elegido, cuál de dos cosas mantener, una línea que casi elegiste), con tu mejor respuesta aplicada. text dice lo que decidiste y qué debe verificar una persona; where es el nombre del clip y el código de tiempo (de context.json), por ejemplo S04_IMG_1234.MOV en 00:14.00. Ambos deben estar no vacíos. Se convierten en elementos de la lista de verificación cuando apply termina.
  • Reclasificar solo para corregir la agrupación: un elemento que el script trató como en cámara pero que en realidad es b-roll (broll), o viceversa (on_camera). La clave es V<pista>@<fotograma de inicio> (por ejemplo V1@1234): las claves de items en .edit/framing/context.json, que también da el nombre del clip y el código de tiempo de cada elemento. Una clave que no coincide con ningún elemento se ignora, así que compruébala contra context.json. Una configuración cuyos elementos están todos reclasificados como broll no necesita etiqueta.
  • Líneas de zoom provienen del script y transcript.md: la tesis, un giro en el argumento, un remate, un llamado a la acción. No relleno, no oraciones de preparación. Mantenlas de 3 a 8 s de duración y al menos separadas 30 s, colócalas en configuraciones simples donde ningún b-roll cubra al hablante, y escribe una razón para cada una. Menos es mejor que débiles. El solucionador descarta cualquier que rompa las reglas y dice qué regla en el informe (y muestra el zoom rechazado en naranja en su previsualización de marcador). Los zooms se mantienen en segundos de línea de tiempo, por lo que solve verifica el texto de cada uno contra la transcripción de la línea de tiempo actual: cuando la línea ya no se dice en su rango (la línea de tiempo cambió desde que la elegiste), el zoom se descarta con un elemento para volver a elegirlo. Copia el texto de transcript.md para que la verificación pueda encontrarlo. Sin una transcripción en caché para el rango, el zoom se mantiene y el informe dice que no fue verificado.

Las reglas de encuadre

Estas son las que los scripts aplican. Las razones están aquí para que puedas juzgar tomas que las reglas no cubren.

Encuadre base, uno por configuración

  • Ojos en o justo por encima de la línea del tercio superior, un espacio de cabeza pequeño e igual para cada clip. Los ojos cerca del tercio superior se leen como naturales y comprometidos; demasiada pared arriba se ve amateur. Un encuadre que corta la frente o toca el pelo parece un error. Cuando las manos bajas en el encuadre tiran del encuadre hacia abajo y empujan los ojos por encima del tercio, el encuadre se inclina hacia atrás para mantener aproximadamente el 10% de la altura del encuadre sobre la cabeza (estimado a partir del tamaño del rostro), con el mismo zoom; donde los gestos, el desorden o una articulación no dejan espacio, solo la línea de los ojos decide.
  • Centrado en el rostro para discurso directo, desplazándose del centro como máximo un 5% del ancho para mantener el desorden fuera. Mirar directamente al objetivo implica simetría; los rostros descentrados se leen como un error a menos que la toma esté claramente compuesta así.
  • El borde inferior nunca se sitúa sobre una articulación (barbilla, cuello, codos, muñecas, cintura...).

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills relacionados