Communitygithub.com

beachyphotoandfilm-arch/video-skills

Convierte grabaciones crudas de una persona hablando a cámara en un rough cut ensamblado dentro de DaVinci Resolve. Extrae los clips de tu unidad de grabación, los transcribe localmente, elimina tomas fallidas, reinicios, comentarios secundarios y silencios, y luego crea un nuevo proyecto de Resolve con dos líneas de tiempo de edición de papel listas para tu ajuste fino.

¿Qué es video-skills?

Este skill automatiza la tediosa primera pasada de edición de videos de tipo 'talking head', tomando los archivos de cámara sin procesar y devolviendo un proyecto de DaVinci Resolve con dos líneas de tiempo de edición de papel. Primero, transcribe localmente cada clip usando whisper.cpp para obtener marcas de tiempo a nivel de palabra. Luego, tú (el usuario) debes leer la transcripción completa y escribir una lista de cortes (`cuts.json`) especificando qué eliminar: tomas fallidas, falsos comienzos, comentarios sin importancia, silencios prolongados y repeticiones accidentales. El skill procesa estos cortes con scripts de Python (segmentos y ajuste de pausas) y finalmente construye dos versiones de la línea de tiempo en Resolve: una solo con los cortes intencionales ('Paper Edit v1') y otra que además recorta las pausas excesivas ('Paper Edit v2 (tight)'). También incluye funcionalidades opcionales avanzadas como 'punch-ins' (reencuadres) sincronizados con el contenido, aplicación de LUTs y superposición de fotos o tarjetas informativas. Está diseñado para funcionar con DaVinci Resolve a través de un servidor MCP que expone `execute_resolve_code`, y requiere `ffmpeg`, `ffprobe`, `whisper-cli` y Python 3. Es una herramienta poderosa para creadores que quieren acelerar su flujo de trabajo de edición, manteniendo el control creativo sobre la versión final.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/beachyphotoandfilm-arch/video-skills/tree/HEAD/skills/paper-edit

Preguntar en tu IA favorita

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

Documentación

Edición de papel

Archivos de cámara sin procesar entran, rough cut ensamblado en Resolve sale. En su primera prueba real: raw 14:17, salida 10:16, frente a la edición manual del creador de 10:32.

La división del trabajo: Claude hace el corte amplio, el creador hace el ajuste fino. No intentes entregar una edición terminada, y no seas tan conservador que tengan que rehacer las partes obvias.

Configuración: completa estos datos

MarcadorQué esEjemplo
<FOOTAGE_DRIVE>Donde residen los archivos raw, una carpeta por video/Volumes/MyWorkDrive
<LUT_PATH>LUT opcional, relativo a la carpeta de LUTs de ResolveMyLuts/SLog3-to-709.cube
WHISPER_MODEL (env)Archivo de modelo whisper.cpppor defecto ~/.cache/whisper-models/ggml-small.en.bin
RESOLVE_APP (env, opcional)Ruta de la app de Resolve si no es estándarpor defecto /Applications/DaVinci Resolve/DaVinci Resolve.app

Requisitos: ffmpeg, ffprobe, whisper-cli (whisper.cpp), Python 3, DaVinci Resolve con un servidor MCP de Resolve que exponga execute_resolve_code.

Ejecútalo

Directorio de trabajo: usa el scratchpad de la sesión, p.ej. <scratchpad>/paperedit. El directorio del skill debajo es .claude/skills/paper-edit.

1. Encuentra el material

El material está en <FOOTAGE_DRIVE>, una carpeta por video, a menudo con nombres imprecisos.

find "<FOOTAGE_DRIVE>" -maxdepth 4 -iname "*<keyword>*" -not -path "*/.*"

Confirma la carpeta con el usuario si hay más de una coincidencia. No copies los archivos; Resolve enlaza a ellos en la unidad.

2. Transcribe cada clip

bash <skill>/scripts/transcribe.sh "<FOOTAGE_DRIVE>/<folder>" "<work>"

Escribe <clip>.json (nivel de palabra), <clip>.wav y clips.ndjson con duraciones. Aprox. 90s por 15 minutos de metraje. Omite clips ya procesados, por lo que es seguro volver a ejecutarlo.

3. Lee tú mismo la transcripción

python3 <skill>/scripts/sentences.py "<work>"

Léela toda. Esta es la parte que no se puede automatizar. Se intentó un detector de frases repetidas y falló gravemente: quería cortar 428 de 737 segundos, porque los profesores repiten frases a propósito («esto es lo que funciona, esto es lo que no»).

4. Escribe la lista de cortes

<work>/cuts.json, un objeto por eliminación, tiempos en segundos desde el inicio de ese clip:

[{"clip":"C0002","start":32.58,"end":39.76,"why":"tropiezo: 'lo que me di cuenta fue que incluso a veces...'"}]

Corta esto:

  • Comentarios secundarios y hablar a cámara: «eso estuvo bastante bien, no voy a mentir», «a esta cámara le queda poca batería», «esto probablemente será un video de siete minutos»
  • Falsos comienzos, conservando el último intento. Los oradores a menudo repiten una frase dos veces, mejor la segunda.
  • Tomas fallidas del CTA. A menudo hay 3-4 al final; conserva la última.
  • Silencios largos entre secciones, ruido entre paréntesis ([BLANK_AUDIO], (tecleo), (movimiento))
  • Frases abandonadas a mitad de pensamiento y reestructuradas («la razón por la que solía no hacer esto era porque tenía miedo, y...»)
  • Reinicios cortos dentro de una frase, marcados por una coma y una cláusula repetida: «todo lo que pedí a cambio es una reseña simple y esto es, y agregar la parte de la reseña...» Corta desde la cláusula abandonada hasta el reinicio. Estos duran 1-2s y son fáciles de pasar por alto al leer.
  • Las marcas de tiempo de las palabras de Whisper varían aproximadamente 0.5s. En un falso comienzo que repite las mismas palabras («me encanta ofrecer, me encanta empezar»), termina el corte al inicio del segundo «me encanta», no al final del primer intento, o sobrevive una palabra suelta.
  • Inicia un corte en el offset to de la palabra conservada, nunca en su from. En una prueba, un corte comenzó en 40.30 mientras que la palabra conservada iba de 40.19 a 40.92, por lo que la última palabra del gancho se cortó y tuvo que arrastrarse manualmente. Imprime los offsets con from|to para la palabra anterior a cada corte.
  • Después de una secuencia larga de [BLANK_AUDIO], los tiempos no son fiables. Whisper comprimió las palabras de la primera toma del gancho después de 30s de silencio, y el corte dejó un fragmento de palabra como el primer segundo del video. Cuando una toma comienza después de un silencio, verifica el nivel de audio (ffmpeg astats) para encontrar dónde comienza realmente el habla en lugar de confiar en los offsets de las palabras.

Conserva:

  • La repetición deliberada utilizada para el ritmo didáctico
  • Las digresiones que aún enseñan algo, a menos que el usuario diga lo contrario
  • Cualquier cosa de la que no estés seguro. Márcala en tu resumen en lugar de cortarla.

5. Construye los segmentos

python3 <skill>/scripts/segments.py "<work>"

Produce segments-v1.json (solo cortes intencionales), segments-v2.json (también recorta pausas de más de 0.50s a 0.22s) y cutlist.txt. Ajustables mediante variables de entorno: MIN_GAP, KEEP_PAUSE, NOISE_DB.

También elimina blips sin habla: segmentos v2 de menos de 1s sin audio a nivel de habla. Son clics de ratón y miradas a un portátil, que quedan como islas entre pausas recortadas. Ajustables: BLIP_MAX, SPEECH_DB.

Lee cada línea join: en cutlist.txt antes de mostrarla al usuario. Muestra cómo se lee la frase a través de cada corte. Si la misma frase aparece a ambos lados de |, el corte es demasiado corto.

Ambas pasadas importan. Solo con los cortes intencionales, la retroalimentación fue «hay grandes pausas en todo el video, especialmente al principio». El recorte de pausas es lo que redujo 11:32 a 10:16. No bajes KEEP_PAUSE por debajo de ~0.20s; empieza a sonar apresurado.

6. Muestra la lista de cortes antes de construir

Pega el resumen: duración raw, v1, v2, número de cortes y los cortes notables con razones. El usuario veta lo que quiera.

7. Constrúyelo en Resolve

Requiere Preferencias > Sistema > General > Scripting externo usando: Local (se configura una vez, permanece). No pidas al usuario que abra Resolve. Ejecuta esto primero; lanza Resolve si está cerrado y espera hasta que la API responda:

bash <skill>/scripts/ensure_resolve.sh

Si se agota el tiempo de espera con Resolve ejecutándose, la creación de scripts está desactivada; esa es la única parte que debes pedir al usuario que corrija.

Escribe <work>/params.json:

{"project":"<Nombre del Video> - YYYY-MM-DD","work":"<work>",
 "files":["<FOOTAGE_DRIVE>/<folder>/C0001.MP4","..."],
 "fps":23.976,"width":1920,"height":1080}

Luego una llamada a execute_resolve_code:

PARAMS = "<work>/params.json"
exec(open("<skill>/scripts/resolve_build.py").read())

Varios videos: constrúyelos uno a la vez, nunca como llamadas de herramienta paralelas. Resolve tiene un proyecto actual, por lo que dos construcciones chocan. Una vez que dos construcciones se ejecutaron juntas y una v2 salió vacía, aunque el script informó que cada elemento se agregó. Después de cada construcción, verifica tú mismo el recuento de elementos de cada línea de tiempo.

Nombra el proyecto <Video> - YYYY-MM-DD para que proyectos con el mismo nombre nunca se confundan. Crea un nuevo proyecto, importa los clips y construye Paper Edit v1 y Paper Edit v2 (tight). No se modifica nada existente. Este es un uso autorizado de execute_resolve_code; append_to_timeline no puede tomar puntos de entrada/salida, por lo que no hay una herramienta alternativa. Muestra el código al usuario la primera vez en una sesión.

Plan de respaldo si no se puede acceder a Resolve (ejecución en la nube o programada, o ensure_resolve.sh falló): escribe un FCPXML de elementos asset-clip, uno por segmento, con start y duration en frames*1001/24000s, y deja que el usuario lo importe. Mismo resultado, un clic adicional.

8. Entrega

Informa al usuario de que ambas líneas de tiempo existen, cuál debe revisar primero (v2) y que v1 es la red de seguridad si v2 se siente demasiado recortada. Luego pregunta si el corte está bloqueado, porque las superposiciones vienen después (consulta video-overlays, si lo tienes).

9. Reencuadres (línea de tiempo opcional)

La variación de encuadre estático hace que una persona hablando sea más atractiva. La API de Resolve no tiene acceso a keyframes, por lo que los zooms lentos son imposibles de automatizar; el encuadre estático por clip («de vez en cuando uno de los clips está un poco más ampliado») es lo que se puede hacer.

Vincula cada cambio a la transcripción, nunca a un temporizador. Una versión basada en temporizador se sintió aleatoria. Haz zoom en las líneas más impactantes o donde comienza un nuevo tema, para que tenga sentido.

Escribe <work>/framing.json:

[{"clip":"C0002","at":361.40,"framing":"med","why":"CONSEJO 3"},
 {"clip":"C0002","at":371.80,"framing":"close","why":"'esta es la parte que importa'"}]

at es el inicio de la oración de sentences.py. Luego python3 <skill>/scripts/punchins.py "<work>" y establece "punchins": true en params.json. Divide un segmento donde sea que caiga una marca dentro de él, en el punto más silencioso cerca del inicio de la oración, porque las personas que hablan a menudo se extienden sin pausa y de lo contrario el cambio se desliza tarde.

Si el usuario recortó manualmente v2 en Resolve, su línea de tiempo es el corte. Lee sus elementos (GetLeftOffset/GetDuration, fotogramas x 1.001/24 = segundos) en segments-locked.json, ejecuta con SEGMENTS=segments-locked.json, y agrega solo v3 al proyecto existente con "timelines": ["v3"]. Apunta a un cambio cada ~20-40s: plano general en cada nuevo tema, medio para enseñanza, primer plano en la línea importante. El constructor coloca un marcador azul en cada cambio nombrando la razón, para que la lógica sea visible.

Encuadres: wide 1.00, med 1.11 (inclinación -12), close 1.21 (inclinación -24).

Si el usuario etalonó v2 mientras lo recortaba, v3 se construye desde cero solo con el LUT, así que copia el etalonaje de v2 a v3 justo después de construirlo:

src = v2.GetItemListInTrack("video", 1)[5]          # cualquier elemento etalonado de v2
src.CopyGrades(v3.GetItemListInTrack("video", 1))    # funciona entre líneas de tiempo; zoom/inclinación sobreviven

Verifica con GetNodeGraph().GetToolsInNode(1) en cada elemento de v3. No uses la ruta de la galería (GrabStill + ExportStills a .drx): la exportación devuelve False a través de la API. Si se usó GrabStill, elimina el still para que la galería se mantenga limpia.

Al leer un v2 bloqueado: GetLeftOffset() y GetDuration() dan los fotogramas de origen. El primer segmento te dice si el gancho fue recortado. Compara los segmentos bloqueados con segments-v2.json y anota lo que cambió, para calibrar la siguiente edición.

10. Color

Establece "lut": "<LUT_PATH>" en params.json para aplicarlo a cada clip en el nodo 1. Si la cámara graba en perfil log (p. ej., S-Log3), el metraje sin etalonar se ve plano y gris, por lo que vale la pena establecer un LUT. La API no puede agregar un segundo nodo; para un etalonaje multinodo, etalona un clip a mano y extiéndelo con CopyGrades.

11. Fotos sobre la charla (opcional)

Cuando el orador habla de algo de lo que tienes imágenes fijas, colócalas en la V2 de v3, sobre un fondo blanco.

  • Tarjetas, no una presentación de diapositivas. Renderiza PNG de 1920x1080 sobre blanco puro: tres retratos lado a lado (escala a h840, espacios de 50px), dos retratos (h880, espacio de 60px) o un paisaje (h900). Agrupa las fotos por lo que se está diciendo.
  • Temporiza cada tarjeta para que coincida con el inicio de una oración de la transcripción bloqueada, y cambia de tarjeta en la siguiente oración. Aproximadamente 2-5s por tarjeta. Mantén las fotos solo mientras se están describiendo.
  • Impórtalas como .mov ProRes con duración exacta, no como imágenes fijas. Las imágenes fijas entran en Resolve con una duración fija de 2s y se superponen entre sí. Los nombres numerados (card1.png, card2.png) se importan como una secuencia de imágenes única, así que usa nombres con palabras. Renderiza con ffmpeg -loop 1 -framerate 24000/1001 -i x.png -frames:v N -c:v prores_ks -profile:v 3.
  • Para un .mov, AppendToTimeline necesita endFrame = el número de fotogramas (no count-1), o cada tarjeta aterriza un fotograma corto y el orador aparece en pantalla entre tarjetas. Pasa "mediaType": 1 para que no venga audio.
  • Nombra la pista « fotos», coloca las tarjetas en su propia carpeta de la mediateca y nunca les pongas el LUT (ya están etalonadas).
  • Muestra al usuario una hoja de contactos de las tarjetas en el chat antes de colocarlas.

Datos que vale la pena recordar

  • Calibración a partir de ediciones reales: después de un v2, el creador normalmente elimina de 10 a 20s a mano de un corte de ~10 minutos. La mayor parte es ajuste a nivel de fotograma en los bordes de los segmentos, más líneas reformuladas, donde un punto se dice y luego se dice mejor en unos segundos. Cuando una oración reformula la anterior, corta la primera versión. Esto es diferente de la repetición didáctica deliberada, que repite una frase a lo largo de las secciones, no consecutivamente. Cuando un punto se hace dos veces con distancia, marca la versión más débil como un posible corte.
  • La preocupación habitual es cortar en exceso para que haya que agregar cosas, así que aprieta solo con evidencia, nunca por corazonada.
  • Formato de origen de ejemplo: 4K 23.976 MP4 con audio de 48kHz; línea de tiempo de entrega 1920x1080 23.976, comenzando en 01:00:00:00. Ajusta fps/width/height en params.json para tu material.
  • El timecode a 23.976 cuenta 24 fotogramas por segundo de timecode: frames = round(seconds / 1.001 * 24).
  • AppendToTimeline trata endFrame como exclusivo: pasa el fotograma después del último que quieras. Una regla «inclusivo, resta 1» elimina un fotograma de cada segmento (aproximadamente 4s en una línea de tiempo de 10 minutos, y cualquier segmento de 1 fotograma desaparece).
  • Algunos oradores casi no usan muletillas; verifica antes de construir la edición basada en la eliminación de muletillas.
  • Aproximadamente el 20% del metraje crudo de una persona hablando es eliminable, y aproximadamente tres cuartas partes de eso son juicio (tomas y reinicios), una cuarta parte es silencio.
  • Modelo Whisper: ggml-small.en.bin es lo suficientemente preciso; malinterpreta algunas palabras, lo que no importa para los puntos de corte pero sí importa si citas al orador.

Relacionados

  • video-overlays: gráficos animados, ejecutar después de que el corte esté bloqueado (si está instalado)
  • video-reels: cortes verticales del mismo material (si está instalado)
  • video-thumbnails: miniaturas y títulos (si está instalado)
  • lapel-sync: ejecutar primero cuando el audio se grabó en un micrófono de solapa/grabadora separada

Individual skills in this repo

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

beachyphotoandfilm-arch/video-skills

Sync camera footage to a separate lapel or field-recorder track (e.g. Tascam DR-10L and similar) and lay it up in DaVinci Resolve. Stitches the recorder's split files, finds each clip's exact place in the audio by matching words then waveforms, cuts one lapel slice per clip so every later skill works unchanged, checks for clipping, and builds a synced timeline in a new Resolve project. Trigger on "sync the lapel", "sync my audio", "line up the recorder", "I used a lav", or any shoot with a separate audio folder (live talks, events, workshops). Run it before paper-edit or video-reels.

beachyphotoandfilm-arch/video-skills

Design a unique Instagram cover for each reel in your house style. Reads what the reel is about, writes a short hook headline, picks one of your own photos from a tagged photo library, lays it out like your existing covers, and proofs it in grid view at phone size. Renders locally, never with AI image generation. Can be called by a scheduling skill before reels are scheduled. Trigger on "make covers", "reel covers", "cover photo for this reel", "design the IG covers".

beachyphotoandfilm-arch/video-skills

Render finished reels out of DaVinci Resolve, write captions in the creator's voice, attach a custom Instagram cover from reel-covers, and schedule them to Instagram, TikTok and YouTube Shorts through Metricool. Handles the Drive upload hop, collision checks against the existing calendar, and cleanup. Trigger on "schedule the reels", "post these", "put these on the calendar", or after reels are approved.

beachyphotoandfilm-arch/video-skills

Build animated brand overlays (motion graphics) for a talking-head video, timed to the speaker's exact words, plus a DaVinci Resolve import file. House style is in-scene type (text beside and behind the speaker's head) plus diagrams. Transcribes the rough cut locally, picks the moments, renders transparent .mov clips, and writes an FCPXML that drops every clip onto the timeline already in position. Trigger on "make animations for this video", "add overlays/motion graphics", "animate this", "b-roll graphics for my YouTube video", or when the user shares a rough cut and asks for graphics.

beachyphotoandfilm-arch/video-skills

Cut vertical Instagram reels out of a long-form talking-head video, hook first. Picks the strongest standalone moments from the transcript, opens each reel on its punchiest line, builds vertical timelines in DaVinci Resolve framed on the speaker's face with the LUT applied, and finishes them: a hook (a held text card, or a word-by-word "build" hook with punch-in) and burned-look captions on V3; this-or-that reels get product graphics and a comment-keyword CTA card. You trim and render, nothing to import. Trigger on "make reels", "clip this for Instagram", "cut some verticals", or after a YouTube video is cut.

beachyphotoandfilm-arch/video-skills

Design YouTube thumbnails and titles for a talking-head video. Pulls graded full-res frames out of the raw footage, renders brand-styled variants in two proven layouts, and proofs them at phone size where the click actually gets decided. Trigger on "make thumbnails", "thumbnail for this video", "title and thumbnail", or after a video is cut.

beachyphotoandfilm-arch/video-skills

Run the whole YouTube video pipeline end to end, one stage at a time, stopping for the creator's approval at every gate. Paper edit, punch-ins, reels, reel covers, scheduling the reels, overlays, thumbnail and title, then scheduling the long-form video, all through Metricool. Keeps state per video so you can stop anywhere and pick up later. Trigger on "/youtube", "let's do the whole video", "run the video pipeline", "continue the <name> video", or when handed raw footage for a YouTube video.

Skills relacionados