¿Qué hace video-skill?
Los scripts viven en scripts/ junto a este archivo; escríbelo como $S abajo, pero escribe la ruta absoluta completa en cada comando, porque las variables de shell no se transfieren entre llamadas Bash.
No puedes ver videos, así que cada paso lo convierte en algo que sí puedes leer: fotogramas que observas y números que verificas. Hacer una película es escribir → renderizar fotogramas → leer la hoja de contacto → corregir. Entender metraje es sondear → proxy → hojas con marcas de tiempo + transcripción → juzgar. Entregar es un script que verifica códec, frecuencia de cuadros, faststart y sonoridad, para que «se reproduce en todas partes» sea un hecho.
Primera vez en un Mac
Ejecuta sh $S/setup.sh tú mismo. Verifica mise y ffmpeg (instalando ffmpeg con Homebrew cuando puede), instala la versión fijada de OpenFilm en el primer uso y ejecuta openfilm doctor. Arregla cada TODO que imprima, o explícalo claramente a la persona. Es seguro volver a ejecutarlo.
Haciendo una película: OpenFilm
OpenFilm (MIT) es el formato de autoría: una película es una carpeta con un film.html que corta páginas HTML, metraje, imágenes y sonido, y cada página dibuja cualquier momento t que se le pida. Studio es su editor local en navegador.
- Imprime el manual y léelo completo (es corto y cambia entre versiones):
$S/openfilm. Síguelo, con este archivo teniendo prioridad donde difieran. $S/openfilmes la única forma de ejecutar OpenFilm aquí: fija la versión, lo instala a través de mise en el primer uso, y evita que Studio abra una ventana del navegador. No usesnpx openfilm(salta la fijación) ninpx skills add openfilm/openfilm(un skill externo que compite con este).FILMes siempre una ruta absoluta,$HOME/Movies/OpenFilm/Projects/<film-name>. Un nombre relativo cae en la carpeta actual, como el repositorio git de alguien. Las películas nunca van en un repositorio.
| Paso | Comando |
|---|---|
| Crear o abrir | $S/openfilm open FILM |
| Verificar toda la película | $S/openfilm -C FILM look |
| Verificar un momento, un tramo, un archivo | … look 4.5, look 3-6, look assets/bed.wav |
| Verificar una entrada rápida | … look 0-2 --count 24 |
| Renderizar el MP4 | $S/openfilm -C FILM render |
| Qué servicios multimedia están conectados | $S/openfilm get |
| Diagnosticar la instalación | $S/openfilm doctor |
look y render se ejecutan sin Studio abierto e imprimen rutas relativas a FILM. La dirección de Studio contiene una clave de acceso: entrégala solo a la persona con la que estás trabajando (es 127.0.0.1, Chrome o Edge, no desde un teléfono).
Lee cada hoja de look antes de mostrar nada, y corrige lo que veas. Sus comprobaciones (el mismo t dibuja la misma imagen, fuentes cargadas, texto recortado, sonoridad) no dicen nada sobre el gusto o el diseño. Un ! sobre texto cortado durante una entrada está bien; cortado en reposo es un error. Luego mira algunos momentos a tamaño completo (look 12.5): un mosaico de 300 px oculta cosas pequeñas, incluídas personas.
Cómo se construye una película, aprendido al hacer una:
- Una página por toma; lo que las páginas comparten (un movimiento Ken Burns, fuentes, colores) va en un módulo que importan. Cada valor es una función solo de
t: sin temporizadores, sin bucle de animación, sin estado. - Las páginas se desvanecen a sí mismas (opacidad desde
t); un fundido a negro entre tomas en una pista es la transición más simple. Una encadenado necesita la toma entrante en una pista encima de la saliente. - El texto sobre fotos necesita una sombra detrás (un degradado inferior), o desaparece en escenas recargadas.
- Las fuentes van en
FILM/fonts/con@font-face, esperadas a través dewindow.film.ready(document.fonts.ready). Para fotos,ready: img.decode(). - Recorta con
#t=inicio,fin, nunca cortando archivos nuevos; un sonido más largo que la película extiende la película.
Sonido
$S/openfilm get muestra lo que está conectado; la voz generada, la música y los efectos necesitan las propias claves del proveedor de la persona (Studio: logo de OpenFilm → Configuración → Proveedores). Sin ellas, haz sonido con ffmpeg, guárdalo en FILM/assets/, anota el comando en FILM/sound-notes.txt para que pueda rehacerse, y di qué servicio lo haría mejor. No puedes oírlo, así que juzga por números:
- -16 LUFS integrado para una mezcla final (podcasts, la mayoría de video web); las plataformas de streaming normalizan cerca de -14. Mantén el pico verdadero en o bajo -1 dBTP. Una cama bajo una voz está ~-22.
- Mide:
ffmpeg -i X -af ebur128=peak=true -f null -. Normaliza una cama generada conloudnorm=I=-16:TP=-1.5:LRA=7; para una masterización final, ejecutaloudnormdos veces (mide, luego retroalimenta los valoresmeasured_*) para que la ganancia sea lineal. lookimprime la sonoridad de la mezcla, yfootage.py checkfalla en un renderizado que no alcanza el objetivo.
Metraje recibido: ingesta
El video de teléfono rara vez es lo que parece. Ejecuta esto sobre cualquier cosa antes de mirarlo o cortarlo:
uv run --no-project --with pillow python -I $S/footage.py probe CLIP.mov ...
uv run --no-project --with pillow python -I $S/footage.py proxy CLIP.mov <scratch>/clip.mp4
probe advierte sobre cada uno de estos, y proxy los corrige todos en una sola pasada (SDR BT.709, rotación incrustada, 30 fps constante, tamaño par, H.264 yuv420p, AAC 48 kHz, faststart):
- HDR (los iPhones graban HLG por defecto:
color_transfer=arib-std-b67, BT.2020). Leído como SDR, se ve desteñido y cambia los colores: el bermellón se vuelve naranja.proxymapea el tono con elavconvertintegrado de macOS, o si no conzscalede ffmpeg (ausente en muchas compilaciones de Homebrew), o si no advierte. - Rotación: los teléfonos almacenan video vertical de lado con un indicador de rotación; algunas herramientas lo ignoran.
- Frecuencia de cuadros variable: nominal 24, promedio 23.997. Los tiempos de los fotogramas se desvían y el audio se desincroniza después de cortes.
probemarca cualquier diferencia superior a 0.001 fps. - Dimensiones impares: H.264 yuv420p necesita ancho y alto pares.
Mira y corta desde el proxy; conserva el original para cualquier cosa que deba permanecer en calidad completa.
Entendiendo metraje
uv run --no-project --with pillow python -I $S/footage.py frames <scratch>/clip.mp4 <scratch>/sheets --every 4
Esto toma un fotograma en cada cambio de escena (--scene 0.3) y al menos uno cada --every segundos, con un máximo de --max 60, en hojas de 5×6 mosaicos etiquetados como 0007 · 1:23.4, con manifest.json mapeando cada id a su tiempo. Lee las hojas y responde con ids y tiempos. Práctica, no doctrina:
- Películas creadas: muestreo uniforme a la duración del plano. Metraje encontrado: cambios de escena más un mínimo de un fotograma cada 2-5 s. Acción rápida: un tramo corto con
--every 0.5. - Mantén una hoja por debajo de ~2500 px en su lado largo y lee unas pocas a la vez; para metraje largo, distribuye a subagentes sobre hojas, cada uno escribiendo un veredicto JSONL por id de mosaico, luego
python3 -I $S/check_verdicts.py manifest.json out/*.jsonl(ids faltantes, duplicados o inventados fallan; una hoja donde cada mosaico recibió la misma respuesta probablemente fue hojeada). - La mayor parte de un video con diálogo está en su audio. Transcribe en el dispositivo con tiempos de palabras:
uvx parakeet-mlx AUDIO.wav --output-format json --output-dir <scratch>(extrae audio primero:ffmpeg -i clip.mp4 -ar 16000 -ac 1 audio.wav). Une palabras a fotogramas por tiempo. Los nombres propios salen mal («torii» → «Torrey»), así que verifica los nombres contra lo que ves antes de citarlo.
Entregando
uv run --no-project --with pillow python -I $S/footage.py check FILM/<nombre>.mp4 --duration 30
uv run --no-project --with pillow python -I $S/footage.py share FILM/<nombre>.mp4 <scratch>/<nombre>-share.mp4
uv run --no-project --with pillow python -I $S/footage.py gif FILM/<nombre>.mp4 <scratch>/loop.webp --start 2.5 --duration 6 --width 480
checkdebe pasar antes de que entregues un archivo: H.264, yuv420p, tamaño par, frecuencia de cuadros constante,moovantes demdat(faststart: se reproduce mientras se descarga), duración, sonoridad ±1.5 LU, pico verdadero.- Renderiza cuando la persona pida el archivo o no pueda estar en este Mac; ejecuta
looksobre el MP4 mismo como última verificación.sharehace una copia pequeña (1280 de ancho, CRF 28: un renderizado de 30 s a 1080p pasó de 34 MB a 3.8 MB) para una página web o chat; el MP4 original de la película queda intacto. - Bucles: WebP animado sobre GIF. Un bucle de fotos de 5.6 s con un zoom lento pesaba 6.7 MB como GIF y 1.6 MB como WebP: GIF no puede reutilizar píxeles cuando cada píxel se mueve. GIF solo cuando el destino no puede mostrar WebP; entonces
footage.py gif X.gifusa una paleta generada (palettegen/paletteuse). - Elimina lo que no debe viajar: el video de iPhone lleva GPS, el modelo del teléfono y la hora en sus metadatos.
proxyyshareeliminan todo (-map_metadata -1). El archivo original, o una copia hecha por AirDrop o una exportación de Fotos, lo conserva. Verifica conexiftool -GPSCoordinates ARCHIVO.
Fotos en una película
Usa el skill photo-skill (github.com/kylefritz/photo-skill;
si no está instalado, ofrece clonarlo en ~/.claude/skills/photo-skill) para encontrarlas (busca en la biblioteca por descripción, luego juzga hojas de contacto) y descargar originales en resolución completa: las vistas previas son demasiado pequeñas para 1080p. Copia lo que la película usa en FILM/assets/, reguardado sin EXIF. Antes de que una película con las fotos de alguien vaya a algún lado, mira cada toma a tamaño completo: la detección de rostros falla en multitudes, y un mosaico de 300 px oculta personas que un fotograma de 1080p muestra.
Otras herramientas
OpenFilm se adapta mejor a un agente porque una película es HTML plano y look devuelve exactamente lo que necesitas ver. Alternativas, a finales de 2026:
| Herramienta | Autoría | Notas |
|---|---|---|
| HyperFrames (HeyGen, Apache-2.0) | HTML/CSS + GSAP, renderizado por headless Chrome | el análogo más cercano; compuerta check --json lint/diseño/contraste, instantáneas, un plugin de Claude Code |
| Remotion | Componentes React | maduro, skills oficiales para agentes; licencia de código disponible, empresas por encima de un tamaño pequeño necesitan una |
| Manim (MIT) | Escenas Python | explicaciones matemáticas y de diagramas |
| MoviePy (MIT) / ffmpeg puro | Python / gráficos de filtro | cortes y superposiciones simples; ffmpeg se mantiene mejor como la capa de E/S |
Actualizando OpenFilm
El repositorio upstream publica a menudo. Lee las notas de lanzamiento y ejecuta npm view openfilm scripts primero (una entrada preinstall o postinstall merece un vistazo), luego cambia OPENFILM_VERSION en scripts/openfilm y vuelve a ejecutar setup.sh. Después ls ~/Library/Caches/ms-playwright: la primera ejecución de OpenFilm elimina los navegadores Playwright que no tienen un marcador de enlace; setup.sh informa sobre los que eliminó, y npx playwright install chromium en el proyecto que lo necesite lo restablece.
Errores comunes
| Error | Corrección |
|---|---|
npx openfilm … | $S/openfilm …: npx salta la fijación |
look o render en la carpeta incorrecta | $S/openfilm -C FILM … |
Confiar en las comprobaciones de look sin abrir su PNG | Lee la hoja; una comprobación exitosa no dice nada sobre el diseño |
| Cortar o mirar metraje de iPhone directamente | probe, luego proxy: HDR, rotación y VFR afectan |
| Enviar el MP4 maestro a un chat | sharelo, luego check la copia |
| Un GIF para un README o una página | WebP, ~4× más pequeño |
| Studio desactualizado después de una actualización | Detén los procesos viejos de studio/server/main.mjs (pgrep -fl openfilm); un Studio son dos procesos |