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
| Marcador | Qué es | Ejemplo |
|---|---|---|
<FOOTAGE_DRIVE> | Donde residen los archivos raw, una carpeta por video | /Volumes/MyWorkDrive |
<LUT_PATH> | LUT opcional, relativo a la carpeta de LUTs de Resolve | MyLuts/SLog3-to-709.cube |
WHISPER_MODEL (env) | Archivo de modelo whisper.cpp | por defecto ~/.cache/whisper-models/ggml-small.en.bin |
RESOLVE_APP (env, opcional) | Ruta de la app de Resolve si no es estándar | por 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
tode la palabra conservada, nunca en sufrom. 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 confrom|topara 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 (ffmpegastats) 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 conffmpeg -loop 1 -framerate 24000/1001 -i x.png -frames:v N -c:v prores_ks -profile:v 3. - Para un .mov,
AppendToTimelinenecesitaendFrame= 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": 1para 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/heightenparams.jsonpara tu material. - El timecode a 23.976 cuenta 24 fotogramas por segundo de timecode:
frames = round(seconds / 1.001 * 24). AppendToTimelinetrataendFramecomo 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.bines 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