Communitygithub.com

ClaudinNarsis/claude-video-skills

Edita vídeo y audio con FFmpeg local a partir de solicitudes en lenguaje natural: cortar, recortar, unir, redimensionar/reenmarcar (9:16, 1:1), cambio de velocidad, subtítulos (SRT/ASS, animados, karaoke), superposiciones de logotipos y texto, tercios inferiores y títulos, eliminación de silencios, sincronización multicámara y micrófono externo, normalización de sonoridad, conversión HDR/Dolby Vision a SDR, LUTs, música de fondo con ducking, exportaciones para plataformas (YouTube, Reels, TikTok, X), verificaciones de cumplimiento, detección de escenas y resúmenes destacados, hojas de contacto para inspeccionar resultados y archivos de proyecto de edición completa.

¿Qué es claude-video-skills?

Esta habilidad permite a un agente de IA editar vídeo y audio de manera programática utilizando FFmpeg local, sin depender de servicios en la nube ni claves API. Soporta una amplia gama de operaciones de edición, incluyendo cortes, uniones, ajustes de velocidad, cambio de tamaño y formato, superposición de texto, logotipos y subtítulos (incluyendo animaciones y karaoke), sincronización multicámara y de micrófono externo, normalización de sonoridad (LUFS), conversión de HDR a SDR, aplicación de LUTs, eliminación de silencios y detección de escenas. Está diseñada para plataformas como Claude Code, Cursor y Codex, y se activa con menciones a archivos de vídeo o audio, formatos específicos o acciones como 'hacerlo vertical' o 'agregar subtítulos'. Los scripts se organizan en un directorio `scripts/` y se ejecutan con Python 3.10+ (estándar, sin dependencias externas) o mediante MCP, con soporte para planificación, dry-run y verificación de resultados.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ClaudinNarsis/claude-video-skills/tree/HEAD/skills/ffmpeg-skill

Preguntar en tu IA favorita

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

Documentación

ffmpeg-skill

Los scripts residen en scripts/ junto a este archivo; ejecútalos con python3 <skill-dir>/scripts/<name>.py, y las plantillas de entrega en templates/. Este archivo es suficiente para realizar un trabajo: la tabla de abajo enruta la solicitud, y --help sobre el script que se va a ejecutar es la lista completa de opciones más económica. Un archivo de referencia cuesta lo mismo que este; ábrelo solo para una pregunta que tengas: references/scripts.md (todas las opciones de los 42 scripts), references/devices.md (iPhone HDR, GoPro, DJI, grabaciones de pantalla, Zoom), references/gotchas.md (la forma extendida de las reglas de una línea al final). MCP: tools/list muestra solo los 12 principales por defecto; los otros 30 (según esta tabla) se pueden invocar por nombre mediante tools/call, descritos por contract --json; establece FFMPEG_SKILL_MCP_FULL=1 para los 42.

Opciones compartidas (todos los scripts): --dry-run; --json (ruta de salida, su inspección y los comandos ejecutados); --json-brief (estado/salida/verificación + un summary; prefiérelo al escribir pasos); --fast (calidad de vista previa); --progress (porcentaje/ETA); --timeout SEGUNDOS (kind: timeout, por defecto 1800); --overwrite (paso 7); --plan ARCHIVO (una ejecución en seco render.py ARCHIVO se ejecutará más tarde; rechaza si una entrada cambió). Las herramientas de recodificación también aceptan --hw (GPU Apple Silicon, archivos grandes; FFMPEG_SKILL_HW=1 = por defecto, no exportación), --codec h264|hevc|av1|prores y --quality N: sin establecer, SDR es x264 (cut.py --keep-hevc: el origen HEVC permanece HEVC), HDR es x265 Main10; prores necesita -o NOMBRE.mov, h264 rechaza HDR (color.py --to-sdr primero).

Las herramientas de escritura no ejecutan nada bajo --dry-run; las herramientas de medición (probe, check, sync, multicam, scenes, cropdetect, report, silence, loudness, stabilize; overlay para un --text de varias líneas en FFmpeg 8.0-8.1.0) pueden aún ejecutar ffmpeg/ffprobe, omitiendo artefactos/archivos secundarios (--edl, --sheet, un .ass generado); verify ignora la opción. Por herramienta: contract --json dry_run.

Flujo de trabajo (en este orden)

  1. Entorno, solo en caso de fallo. Nunca inicies un trabajo con doctor: una máquina rota falla con kind: missing_tool o un error de ffmpeg que nombra el filtro/codificador. Ejecuta python3 <skill-dir>/scripts/_contract.py doctor (o npx ffmpeg-skill doctor) después de tal fallo, o cuando te pregunten qué puede hacer la máquina: lee ok/usable, informa la capacidad faltante. El esquema de herramientas de contract --json es para un agente planificador, no para este flujo de trabajo.
  2. Inspecciona para planificar. Ejecuta probe.py en cada entrada desde la que planees: duración, fps, resolución, códecs, canales, variable_frame_rate_suspected; y cada vez que el usuario pregunte sobre un archivo. No hagas una inspección separada antes de cada edición: el --json de cada herramienta de escritura ya lleva su entrada y una inspección de la salida. Planifica a partir de números reales, nunca de suposiciones.
  3. Prefiere sin pérdida. Si la solicitud se puede cumplir sin recodificar (cortes simples en fotogramas clave, remux, cambios solo de audio), no recodifiques. cut.py y loudness.py copian el video por flujo por defecto; --accurate en cut.py solo para cortes exactos por fotograma.
  4. Planifica con --dry-run --json, luego ejecuta. Confía en --json, no en la línea de resumen de una ejecución en seco, para cualquier número en el plan (una dimensión allí puede ser un marcador de posición). Úsalo antes de codificaciones largas para informar hechos. Nunca apuntes -o a un archivo que no hayas creado en este trabajo a menos que el usuario haya pedido que se reemplace; pasa --overwrite solo entonces.
  5. Encadena en un orden sensato. Una solicitud de entrega sin otra edición es una ejecución de plantilla única (render.py --template NOMBRE ENTRADA), no una cadena hecha a mano. De lo contrario: color (HDR→SDR / LUT) → corte → unión → silencio → ajuste → subtítulos/superposición → sincronización → audio → sonoridad → exportación. Cambios de marco antes de subtítulos, para que el texto tenga el tamaño del marco final. Recodifica lo menos posible: intermediarios a CRF 18, export.py al final. Tres o más pasos: render.py con un project.json.
  6. Verifica el entregable. Antes de informar, ejecuta check.py SALIDA --platform X para el destino nombrado (una ejecución de plantilla ya lo hace). Las filas de formato (códec, formato de píxel, tamaño, pico verdadero, etiquetas de color, VFR) son seguras de corregir. Las filas de juicio cambian el contenido: duración (el corte pierde material), aspecto (el recorte pierde bordes), fps (pierde movimiento), sonoridad (el ambiente no debe aumentarse): corrige solo cuando la solicitud implique la respuesta, de lo contrario indica la elección y su costo. Menciona las ADVERTENCIAS; no las persigas.
  7. Verifica la salida. Confirma que la duración, resolución, fps y audio coinciden con la solicitud, a partir de la inspección de --json/--json-brief de la herramienta de escritura o de probe.py, e informa esos números ("final.mp4: 59.98 s, 1080x1920, 30 fps, AAC estéreo"). Un paso está completo solo cuando el script salió con código 0 y la salida se inspecciona como se esperaba: un código de salida distinto de cero, un archivo faltante o vacío, o una inspección que contradice la solicitud es un fallo informado con el mensaje de error del script.
  8. Conserva los originales del usuario. Nunca sobrescribas la fuente; escribe nuevos archivos junto a la entrada o donde se pida. Una ruta de salida existente es rechazada (kind: input); --overwrite es la única forma de decir "sí, reemplázalo".
  9. Mira la imagen. Siempre que la imagen haya cambiado (subtítulos, superposiciones, gráficos, recorte/pad, redimensionamiento, color, transiciones, un join.py escalando un clip al marco del primer clip, color.py --to-sdr), ejecuta look.py SALIDA --tiles 3x2 (o --at T para un solo fotograma) y visualiza el PNG (4x3 para diseño de clip completo). No termines hasta que Look: nombre ese PNG — una inspección no puede ver un subtítulo sobre una cara. Solo audio: Look: not needed. Lo que se debe buscar se divide como las filas de check.py en el paso 5:
    • Mecánico (tarea propia de esta habilidad verificar e informar): el texto/logotipo especificado está en la posición especificada, los subtítulos aparecen en las marcas de tiempo especificadas, las dimensiones son pares. El letterboxing de fit.py --fit pad es el resultado correcto de ese modo, nunca un defecto a marcar.
    • Juicio (infórmalo, no lo apruebes o falles en silencio): si un sujeto o rostro está cortado, el texto se superpone a un rostro, los colores se ven deslavados, una transición aterriza. Estos requieren decidir qué es el sujeto, es decisión del agente que llama — di lo que ves en una línea; ellos juzgan. Sin capacidad de visión, escribe Look: RUTA (píxeles no inspeccionados; el agente no tiene visor de imágenes) — nunca afirmes que se inspeccionó una imagen cuando no fue así, sin detenerte por una capacidad que no está presente.

Antes de ejecutar algo: qué preguntar, qué asumir

Haz una pregunta corta solo cuando la respuesta cambie materialmente la salida y la solicitud no la implique. Cuando varias cosas estén abiertas a la vez (un vago "hazlo para redes sociales" deja destino, aspecto, duración y subtítulos abiertos), no preguntes una por turno: propón un paquete con tus valores por defecto y deja que el usuario cambie cualquier parte ("Reels: 9:16 con padding, 60 s, -14 LUFS, sin subtítulos — ¿OK?"). Una pregunta, una respuesta, luego la ejecución. Nunca preguntes lo que probe.py pueda decirte.

  • Destino decide aspecto, límite de duración, sonoridad y códec; "para Reels" responde las cuatro cosas y nombra una plantilla. Sin destino y un simple corte/subtítulo: mantén el formato de origen y dilo. Si el usuario dice "exportar", "publicar" o "entregar", pregunta dónde.
  • Duración ("hazlo de 60 s") sin un método: acelera para cambios ≤1.5×, recorta en caso contrario, dilo. Pregunta cuando el contenido sea una charla (recortar pierde palabras) y el cambio sea grande.
  • Subtítulos sin una fuente de texto: --transcribe si existe un motor local, de lo contrario pide el texto o un archivo con tiempos; nunca inventes diálogos.
  • Fuentes y marca: si el usuario menciona una marca, colores o "nuestra fuente", pide o crea brand.json una vez, reutilízalo.
  • Texto CJK / no latino: deja que la herramienta elija la fuente por escritura (--font lo desactiva); --lang ja|ko para texto solo Han. doctor --json .fonts.scripts dice qué se renderiza aquí. Tofu es un trabajo fallido.
  • Posición de recorte para --fit crop: centrado por defecto, pero cuando la solicitud o la fuente nombren un sujeto descentrado ("mantén el producto a la derecha", alguien visiblemente descentrado en la hoja) usa --crop-x/--crop-y (0=izquierda/arriba, 1=derecha/abajo) en lugar de adivinar el centro, o pregunta qué borde mantener.
  • Cualquier otra cosa (tipo de transición, estilo de subtítulo): elige el valor por defecto convencional, di lo que elegiste, ofrece la alternativa en una línea.

Qué esta habilidad hace y no decide

Esta habilidad corta, une, mide, sincroniza, exporta y verifica archivos — ejecuta una edición, no la decide. Lo que pertenece al humano, al agente que llama o a otra habilidad:

  • Qué corte es correcto, o si un entregable es aprobable — esta habilidad mide e informa (PASS/WARN/FAIL de check.py, error de duración de cut.py); el usuario o el agente de producción decide si eso se envía.
  • Qué hace que un momento destacado sea interesante — scenes.py --highlights clasifica por un proxy medido (energía de audio, duración): candidatos, no un veredicto.
  • Composición de miniatura o portada — una decisión de diseño, no una medición.
  • Entender de qué trata un video — no hay visión aquí más allá de las hojas de contacto de look.py, para los ojos del agente que llama, no para que esta habilidad interprete.
  • Juzgar qué se ve bien — "aplica este LUT", "corrige la exposición en +0.3 pasos" (color.py) es mecánico; "grado esta escena para que se vea cinematográfica" pertenece a una habilidad de gradación de color (color-grading-skill) que decide los parámetros, luego llama a color.py.
  • Las palabras en un subtítulo — el texto de la señal se quema tal como está escrito. Demasiado largo para el marco significa un tamaño más pequeño, --max-lines, o la propia edición del usuario; nunca reescribas, acortes o parafrasees, incluso cuando se te pida "hazlo encajar" — dilo, ofrece --max-lines 1 a un tamaño más pequeño.
  • Elegir un sujeto o región que no se te dio — "recortar a x=200, y=0" es mecánico una vez que se conoce el cuadro; "recortar para mantener al orador en el encuadre" necesita decidir qué es el orador, un juicio para el agente que llama (a partir de una hoja de look.py).

La línea: la misma entrada + los mismos parámetros explícitos que siempre producen la misma salida verificable pertenecen aquí; cualquier cosa que dependa del gusto, la comprensión o lo que se vea o suene bien pertenece a quien haga ese juicio.

Si una solicitud necesita una característica de FFmpeg que ninguno de los 42 scripts expone, dilo y nombra la opción incorporada más cercana — nunca adivines una invocación directa de ffmpeg/ffprobe fuera de scripts/*.py. Eso elude todas las garantías que esta habilidad hace, por lo que nunca es un plan de respaldo.

Solicitud → script

Esta tabla y la lista tools de doctor --json son la fuente de verdad de lo que existe: nombra solo un script que hayas visto en una de ellas (no hay doctor.py, ni trim.py, ni subtitle.py).

Las opciones de marca de tiempo (--start, --end, --at, --from, --duration, --offset, y los tiempos en archivos de señal y capítulos) aceptan segundos, mm:ss(.fff), hh:mm:ss(.fff) o SMPTE hh:mm:ss:ff con @fps (00:01:02:[email protected]) — pega una hoja de señal de NLE tal cual; las opciones de duración (--min-silence, --margin, --fade) son segundos simples.

El usuario diceHaz
"corta de 1:20 a 2:05", "recorta los primeros 10 s"cut.py entrada.mp4 --start 1:20 --end 2:05
"conserva solo estas partes", "elimina el medio"cut.py entrada.mp4 --segments 0-1:00,1:30-2:00
"hazlo exactamente de 60 segundos"fit.py entrada.mp4 --duration 60 (velocidad) o --method trim
"corta esto y hazlo HEVC / AV1 / ProRes" (códec de salida nombrado)cut.py entrada.mp4 --start 0:10 --end 0:40 --codec hevc (ProRes necesita -o NOMBRE.mov)
"elimina las pausas", "cortes bruscos"silence.py entrada.mp4 [--threshold -40 --min-silence 0.8]
"elimina los eeeh y ahh", "elimina las palabras de relleno"silence.py entrada.mp4 --filler --words palabras.json (tiempos de palabras medidos; --transcribe los genera)
"no cortes dentro de una oración, solo las pausas reales"silence.py entrada.mp4 --speech-aware — un respiro bajo --min-silence dentro de una oración se conserva, solo se cortan las pausas en límites de oraciones; se combina con --filler en una lista
"un resumen de 60 s de esta hora"scenes.py larga.mp4 --highlights 6 --target 60 --edl picks.txt → cut.py --segments
"corta al ritmo", "edítalo con la música"scenes.py pista.mp4 --beats --json > beats.json, luego cut.py entrada.mp4 --segments ... --snap beats --snap-source beats.json (--snap-source lleva la cuadrícula medida)
"acelera aquí, cámara lenta allí" (segmentos conocidos)speedramp.py accion.mp4 --segment 0-3:1.0 --segment 3-4:0.25 --segment 4-8:2.0
"mantén este fotograma", "congela el último fotograma"freeze.py clip.mp4 --hold 2
"cámara lenta suave", "media velocidad pero fluida"fit.py entrada.mp4 --duration 2x --smooth interpolate (lenta) o --smooth blend
"invierte este clip"reverse.py entrada.mp4
"repite este clip para llenar 30 segundos"loop.py bg_loop.mp4 --duration 30
"hazlo vertical / 9:16 / cuadrado"fit.py entrada.mp4 --aspect 9:16 --fit pad (o --fit crop; --pad-fill blur para barras borrosas)
"redimensiona a una altura/ancho"fit.py entrada.mp4 --height 1080 (o --width, o ambos para un marco exacto)
"recorta a este cuadro exacto" (x/y/w/h conocidos)crop.py entrada.mp4 --x 100 --y 0 --width 1080 --height 1920
"fondo borroso en lugar de barras negras"fit.py entrada.mp4 --aspect 9:16 --fit blur (imagen completa conservada, bordes una copia borrosa y oscurecida)
"gira 90 grados", "voltea"fit.py entrada.mp4 --rotate 90 / fit.py entrada.mp4 --flip h
"el horizonte está inclinado" (grados conocidos)straighten.py inclinado.mp4 --degrees -2.5
"vista plana de este video 360" (yaw/pitch/fov conocidos)sphere.py insta360.mp4 --yaw 90 --pitch 0 --h-fov 100 --v-fov 70
"este metraje antiguo está entrelazado"deinterlace.py entrada.mp4
"es granuloso/ruidoso, límpialo"denoise.py entrada.mp4 --strength medium
"desenfoca/pixelea esta cara/placa" (cuadro conocido)redact.py entrada.mp4 --x 820 --y 140 --width 240 --height 240 --mode pixelate
"elimina este logotipo fijo" (cuadro conocido)redact.py entrada.mp4 --x 40 --y 20 --width 180 --height 60 --mode delogo
"estabiliza este metraje tembloroso"stabilize.py entrada.mp4
"¿hay barras negras en esto?"cropdetect.py entrada.mp4
"el clip Dolby Vision de iPhone se ve mal"color.py entrada.mp4 --to-sdr
"aplica un LUT. Receta lista: C:\Users(...)\"color.py entrada.mp4 --lut RUTA – el usuario da la ruta exacta o la arrastra, --lookup-table es sinónimo
"ponle subtítulos", "agrega encabezados a esto"subtitles.py entrada.mp4 --text "Hola mundo" y overlay.py entrada.mp4 --text "Título" --position top? Espera, la tabla original menciona overlay.pypara texto, pero el nombre correcto aquí parecesubtitles.py. La tabla original dice subtitles.py entrada.mp4 --text "Hola mundo"pero luegooverlay.pypara texto. Revisa la tabla original: no tieneoverlay.pypara texto, tienesubtitles.pyyoverlay.pypara logotipos. La tabla original truncada mencionasubtitles.pyyoverlay.py. Mantendré la coherencia con la tabla truncada original: para texto en pantalla usar subtitles.py, para logotipos usar overlay.py. Pero la fila dice "ponle subtítulos" → subtitles.py. Para texto superpuesto como títulos, la tabla original tiene subtitles.py --text. Mejor seguir la tabla: subtitles.py entrada.mp4 --text "Hola mundo"`.
"pon un logotipo en la esquina superior derecha"overlay.py entrada.mp4 --logo logo.png --position top-right
"haz un tercio inferior para el orador"lowerthird.py entrada.mp4 --name "Juan Pérez" --title "CEO"
"sincroniza el audio de la grabación de Zoom con el micrófono externo"sync.py entrada.mp4 --audio audio.wav
"alinea estas tres tomas de cámara"multicam.py cam1.mp4 cam2.mp4 cam3.mp4
"haz que el audio esté a -14 LUFS"loudness.py entrada.mp4 --lufs -14
"pon música de fondo que baje cuando alguien habla"music.py entrada.mp4 --music pista.mp3 --duck
"exporta para YouTube"render.py entrada.mp4 --template youtube
"haz un Reel de Instagram"render.py entrada.mp4 --template instagram_reel
"prepáralo para TikTok"render.py entrada.mp4 --template tiktok
"hazlo para X"render.py entrada.mp4 --template x
"verifica si cumple con las especificaciones de YouTube"check.py entrada.mp4 --platform youtube
"encuentra escenas en este metraje"scenes.py entrada.mp4
"haz un resumen destacado"scenes.py entrada.mp4 --highlights 5
"haz una hoja de contacto"look.py entrada.mp4 --tiles 3x2
"crea un archivo de proyecto de edición"project.py entrada.mp4 --steps ...

Notas finales

  • Todos los scripts aceptan --help para ver todas las opciones.
  • Usa --dry-run --json para planificar sin ejecutar.
  • Si un script no existe en la lista, no lo invoques; di que no está disponible y ofrece la alternativa más cercana.
  • Los archivos intermedios se guardan en el mismo directorio que la entrada, a menos que se especifique -o.
  • Los códecs de hardware (Apple Silicon) se usan por defecto para archivos grandes; desactívalos con --hw.
  • Para ediciones complejas de varios pasos, usa render.py con un archivo project.json.

Individual skills in this repo

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

Skills relacionados