Communitygithub.com

Framewright

Videos cortos enteramente desde código: un archivo HTML, cada fotograma una función pura de (fotograma, semilla, ancho). Compatible con Claude/Codex/Gemini/Cursor.

¿Qué es Framewright?

Framewright es una habilidad para agentes de IA que permite crear videos cortos completamente a partir de código, como un grabador produce un grabado. Todo el video se genera desde un único archivo HTML con un canvas y una función `frame` que dibuja cualquier fotograma bajo demanda usando solo el número de fotograma, la semilla y el ancho de salida. No se utilizan imágenes, fuentes, bibliotecas ni CDN. Los fotogramas se renderizan en Chrome sin interfaz gráfica y se ensamblan con ffmpeg. El sonido se sintetiza al final. La habilidad sigue un flujo de trabajo estructurado: cuestionario inicial, tres conceptos, storyboard, escenas individuales con verificación visual constante, render completo solo cuando todo está correcto, y finalmente sonido y entrega. Soporta tres modos: estándar (cortes entre escenas), mundo continuo (sin cortes) y pintura animada. Está diseñada para Claude Code, Codex, Gemini y Cursor.

Compatible con✓Claude Code✓Codex CLI✓Cursor✓Gemini CLI
npx skills add smwbev/framewright

Preguntar en tu IA favorita

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

Documentación

¿Qué hace Framewright?

Vas a hacer un video corto como un grabador hace un grabado: un archivo HTML con un canvas, una lista de escenas llamadas placas, y una función frame que dibuja cualquier fotograma bajo demanda a partir de (número de fotograma, semilla, ancho). Sin metraje, sin archivos de imagen, nada desde un CDN. Los fotogramas se renderizan en Chrome sin interfaz gráfica y se ensamblan con ffmpeg. El sonido se sintetiza al final, ajustado a las longitudes de escena bloqueadas.

Habla al usuario en su idioma. Mantén las reglas siguientes incluso cuando el usuario tenga prisa: cada atajo aquí cuesta más de lo que ahorra.

SKILL_DIR abajo significa la carpeta que contiene este archivo (en Claude Code es ${CLAUDE_SKILL_DIR}; en otros entornos es .agents/skills/framewright). Después del paso 3 los scripts también están en la carpeta scripts/ del proyecto.

No negociables

  1. Un fotograma depende solo del número de fotograma, la semilla y el ancho de salida. Nada de Math.random, ni reloj de pared, ni animación CSS, ni requestAnimationFrame como fuente de tiempo. scripts/check.mjs lo prueba antes de cada render completo.
  2. Sin archivos de imagen, video, fuente o biblioteca, sin base64, sin CDN. Los polígonos trazados desde una foto mediante un script son datos y están bien. Las fuentes del sistema son suficientes.
  3. Verificas mirando fotogramas renderizados, nunca leyendo código e imaginando. Cualquier arreglo se confirma con un fotograma.
  4. Una escena a la vez. Escribe una placa, dispara tres fotogramas, mira, arregla, luego la siguiente placa.
  5. Las longitudes de escena son múltiplos del pulso del primer boceto. El sonido llega al final.
  6. Render completo solo después de que una hoja de contactos de todo el video se vea correcta.
  7. Nunca subas frames/, shots/, *.mp4, *.wav ni las fotos del usuario.
  8. Pregunta antes de instalar paquetes del sistema. Nunca publiques la apariencia de una persona real sin que el usuario confirme que tiene derecho a usarla.

Flujo de trabajo de un vistazo

PasoQué sucedePunto de control con el usuario
0verificación del entornosolo si algo debe instalarse
1briefcuestionario, un bloque
2conceptostres opciones, elegir una
3storyboard + andamioun "adelante"
4escenas, una por unahoja de contactos cada 2-3 escenas
5activos (fotos, logotipos)vista previa del retrato trazado
6hoja completa, render, compilaciónvista previa MP4
7sonidoMP4 reconstruido
8entrega y variacionesfinal

Tiempo típico de pared: brief y conceptos 10 minutos, andamio 10, cada escena 10-20, render 2-4 minutos por minuto de video 1080p, sonido 15.

Paso 0. Entorno

bash SKILL_DIR/scripts/doctor.sh            # informe; añade --json para un resumen legible por máquina
bash SKILL_DIR/scripts/doctor.sh --install  # instala lo que falta, pregunta antes de cada paso

Requerido: Node 20+, npm, ffmpeg con libx264, Puppeteer con Chrome en el proyecto. Opcional: Python 3 con numpy, scipy, Pillow, solo cuando se trazará una foto. Si el doctor informa herramientas faltantes, dile al usuario qué se instalará y dónde, recibe un sí, luego ejecuta --install (añade --yes cuando el usuario ya aceptó). No comiences el paso 3 con un doctor fallando.

Paso 1. El brief

Ejecuta el cuestionario de references/questionnaire.md. Usa la herramienta de preguntas estructuradas del armazón cuando exista (Claude Code: AskUserQuestion, hasta cuatro preguntas por llamada, dos a cuatro opciones cada una, pon la opción recomendada primero y márcala). Sin tal herramienta, imprime las preguntas como una lista numerada con opciones con letras y un valor predeterminado por pregunta, y acepta respuestas concisas como 1b 2a 3c. Siempre pregunta, en este orden:

  1. Mensaje: qué debe entender o sentir el espectador, en una oración. Nombres, fechas, enlaces, frases exactas que deben aparecer en pantalla.
  2. Dónde se reproduce y el formato: 16:9, 9:16, 1:1, 4:5.
  3. Duración: 10-15, 20-25, 30-40, 45-60 segundos.
  4. Tono: juguetón, inexpresivo, cálido, épico, técnico, oscuro.
  5. Estilo: dejar que propongas (predeterminado) o una familia de references/styles.md.
  6. Activos: fotos, logotipos, capturas de pantalla. Los archivos deben colocarse en la carpeta del proyecto; una imagen pegada en el chat no puede ser guardada por ti. Pregunta sobre los derechos de las personas reales.
  7. Sonido: sintetizado, ninguno, o espacio para la pista del usuario (luego pregunta su BPM).
  8. Entregables y calidad: borrador o final, cortes adicionales (vertical, GIF, fotograma de póster, variaciones de semilla), una portada como primer fotograma del MP4 (los feeds la muestran como vista previa).

Si el usuario dice "tú decides", toma los valores predeterminados, di cuáles tomaste y continúa.

Paso 2. Conceptos

Propón exactamente tres conceptos antes de cualquier código. Constrúyelos desde tres ángulos: literal (muestra el sujeto), metáfora (un sistema visual que representa la situación: una carta de ajuste de TV para la espera, un plano para un proyecto, una terminal para un proceso), y parodia de género (boletín de noticias, modo de atracción de arcade, tarjeta de seguridad, pronóstico del tiempo, teletexto). Para cada concepto da: un nombre, una frase de una línea, el sistema visual y la paleta, tres a cinco escenas clave en orden, el final, un esbozo de sonido, por qué encaja, y su principal riesgo. Presenta una tabla compacta, recomienda uno, y pide al usuario que elija. El método y los ejemplos trabajados están en references/questionnaire.md. Un concepto cuya frase es un viaje sin cortes (una línea que nunca se levanta, un vuelo desde un detalle hacia un paisaje) se construye como un mundo continuo (references/world.md); dilo en su fila, porque cambia cómo se construyen y modifican las escenas. Un concepto que es una vista dibujada, pintada y cobrada vida (un dibujo a lápiz que se convierte en una pintura al óleo viva, estilos 13-16) se construye como una película de pintura (references/painting.md); dilo en su fila también: sus placas son capítulos de tiempo sobre una pintura, y la escena es la obra.

Paso 3. Storyboard y andamio

Llena storyboard.md (plantilla en assets/storyboard.md): una fila por placa, longitudes en compases, la cuadrícula de pulso (30 fps, 120 BPM: pulso 15 fotogramas, compás 60), el segundo del evento principal, el total. El total debe igualar la duración acordada; cuando se añade una escena más tarde, otra escena cede un compás. Muestra la tabla y pide un solo "adelante".

Luego el andamio:

bash SKILL_DIR/scripts/init.sh              # index.html, scripts/, audio.mjs, storyboard.md, package.json
bash SKILL_DIR/scripts/init.sh . --world    # lo mismo, pero index.html es el esqueleto de un solo mundo (sin cortes)
bash SKILL_DIR/scripts/init.sh . --painting # el esqueleto de pintura; audio.mjs y nature.mjs crean sonido de naturaleza
npm install                                 # puppeteer (Chrome viene de la caché o se descarga una vez)
node scripts/look.mjs shot 0,30,60 1200 7

Abre los PNG con tu herramienta de visualización de imágenes y míralos. La placa de demostración del esqueleto debe renderizarse antes de que la toques. Luego reemplaza la placa de demostración con tu primera escena. En una película de pintura el fotograma 0 es papel en blanco: dispara 30,82,200 (el dibujo, el color llegando, la pintura viva) en su lugar, y reemplaza el bloque de escena de la demostración mientras el kit de pintura permanece como está.

Paso 4. Escenas

Lee references/guide.md una vez antes de la primera escena. Lo esencial:

  • plate('name', {len: 2*BAR}, (S, R) => { ... }). S.t es progreso 0..1, S.i el fotograma local, S.f el fotograma global, S.g el contexto 2D en coordenadas lógicas (lado corto 1080). R es un generador estable para toda la placa; S.b re-sembrado cada tres fotogramas y da una línea viva; S.nz cambia cada fotograma para ruido. Las semillas derivan del nombre de la placa.
  • Toda la geometría en unidades lógicas, centrada a través de CX, CY. Mantén el contenido importante dentro del 92 % central del fotograma; en 9:16 también fuera del 15 % superior y el 20 % inferior, donde están los botones y subtítulos de la plataforma.
  • Tiempo dentro de una placa en pulsos: Math.floor(S.i/BEAT), span(S.i, a, b), ease.out(...). Nunca codifiques números de fotograma global dentro de una escena. Algo que continúa a través de cortes toma el tiempo de otra placa por nombre, at('plate', beats); un momento que el sonido debe alcanzar va en CUES y se lee con cue('name').
  • Los ayudantes viven encima del bloque de placas, nunca entre placas.
  • Las transiciones son dibujadas por el motor en los bordes de las placas (indicadores cutIn/cutOut); las escenas no saben de ellas.
  • Una película de mundo (--world) no tiene cortes. Las placas son constructores, build(W, {pen, b, R}), que añaden a una línea de tiempo: b(x) es el pulso x de la placa, el lápiz continúa la línea desde donde la placa anterior lo dejó, camKey mueve una cámara, title añade texto. Lee references/world.md antes del primer constructor.
  • Una película de pintura (--painting) dibuja una pintura fija en tres medios. Sus placas todas llaman a drawPainting(S); la vista vive en el objeto SCENE y sus capas entre /* ===== scene ===== */ y /* ===== end scene ===== */, y el kit de pintura sobre ella permanece como está. Lee references/painting.md antes de la primera capa. Revisa el dibujo solo primero, luego la revelación, luego la vida (references/painting.md, sección 13).

Por escena: escríbela, dispara el primer fotograma, uno en el medio, uno cinco fotogramas antes del final, mira, arregla, mira de nuevo. Después de cada dos o tres escenas:

node scripts/look.mjs sheet 24 480 7 shots/sheet.png
FROM=240 TO=480 node scripts/look.mjs sheet 12 480 7 shots/sheet-b.png   # una sección, más densa

Lista de verificación para la hoja, cada elemento con tus ojos: cada celda se lee como un fotograma fijo en 1.5 segundos; ningún texto está recortado; líneas y paneles vecinos no se tocan; dos celdas adyacentes

de una placa nunca se ven idénticas; los cortes caen donde se planeó y no se comen el primer fotograma

de una escena; nada importante está en el 8 % exterior; el color no es turbio; las líneas finas no se deshacen; el evento principal está en su segundo planeado; el último fotograma se ve como un final; ningún título comparte la pantalla en el mismo lugar. Una escena que falla "1.5 segundos" se rediseña, no se decora. Una escena vacía recibe un objeto más grande o una cámara más cercana, nunca más detalle; un primer plano ocupado tiene su decoración atenuada alrededor del sujeto. En una película de mundo también dispara el último fotograma de cada placa junto al primer fotograma del siguiente: nada puede saltar.

Envía la hoja al usuario en estos puntos con dos oraciones de estado. No narres código.

Paso 5. Activos

Las fotos se convierten en polígonos posterizados, nunca píxeles:

bash scripts/portrait.sh foto.jpg --levels 0.14,0.28,0.42,0.56,0.70,0.84 --height 900
node scripts/look.mjs shot <fotograma en la escena de retrato> 1200 7

Mira shots/portrait_preview.png y el fotograma renderizado. Ajusta niveles, desenfoque, recorte y umbral de fondo según references/photo.md. Mientras el archivo aún no está en la carpeta, construye la escena sobre el marcador de posición sintético que viene en el esqueleto y dilo.

Paso 6. Hoja completa, render, compilación

node scripts/look.mjs sheet 24 480 7 shots/sheet.png      # míralo, arregla, repite
node scripts/check.mjs                                    # determinismo y autocontención, debe decir OK
node scripts/render.mjs frames 7 1920 5                   # dir, semilla, ancho (omitido: 1920 horizontal, 1080 vertical), pestañas
bash scripts/build.sh out.mp4                             # frames (+ track.wav) -> mp4

La verificación renderiza cinco fotogramas de cada placa en siete órdenes (primer fotograma de una nueva pestaña, adelante, atrás, mezclado, justo después del fotograma anterior, después de otro ancho, después de un barrido sobre la película como lo recorre una pestaña de render) y exige píxeles idénticos. También escanea la fuente en busca de Math.random, Date y performance.now, falla cuando la página solicita cualquier archivo, e imprime la cuadrícula de pulso y el tiempo de render esperado. Arregla cada FALLO antes de renderizar; make.sh ejecuta la verificación y se detiene en un fallo. Un fotograma que cambia con el orden de render apunta a un estado que sobrevive a un fotograma: un canvas agrupado dibujado sin limpiar, un global que una placa cambia, una clave de caché sin todas sus entradas.

Verifica desde el archivo, no desde los fotogramas: el conteo de fotogramas de ffprobe iguala el total de look.mjs info, la duración iguala fotogramas dividido por 30, y un mosaico hecho desde el MP4 coincide con la hoja:

ffmpeg -i out.mp4 -vf "select='not(mod(n\,50))',scale=480:-1,tile=6x4" -frames:v 1 shots/out_sheet.png

Envía el primer MP4 al usuario tan pronto como exista, incluso con marcadores de posición, y di qué es un marcador de posición.

Paso 7. Sonido

scripts/export-curves.mjs escribe curves.json desde la página: inicios de placa, las señales, y para cada fotograma en una película de mundo la velocidad y posición en pantalla de la cabeza de la línea, en una película de pintura las cuotas reveladas, vida, gust y zoom. audio.mjs toma su línea de tiempo de ahí, por lo que nunca se desvía de la imagen (una página sin RISO.curves() necesita los inicios de look.mjs info copiados en T a mano). Escribe un bloque de eventos por placa usando el mapa de señales en references/audio.md; los golpes en algo que la imagen marca toman su tiempo de las señales de la página, cue('name') (CUES, o W.cues en una película de mundo), no de números de pulso copiados de una placa; en una película de mundo dale a la línea o al personaje una voz que siga las curvas (follow(), references/audio.md, sección 7). Una pintura o un paisaje recibe ambiente de naturaleza en lugar de pulsos: viento, agua, susurro y pájaros desde nature.mjs, sincronizados con las señales y con el gust de la página por el audio.mjs que --painting copia desde assets/audio-nature.mjs (references/audio.md, sección 8, Ambiente de naturaleza). Luego:

node scripts/export-curves.mjs curves.json
node audio.mjs track.wav
ffmpeg -i track.wav -filter_complex "showwavespic=s=1800x300:split_channels=1" -frames:v 1 shots/wave.png
bash scripts/build.sh out.mp4

No puedes escuchar, así que lee la forma de onda: sin silencio accidental dentro de escenas activas, sin escena anclada al techo. Cada vez que cambie la duración de una escena, regenera la pista.

Paso 8. Entrega

Entrega out.mp4 (1920×1080, H.264, AAC, ~0.7 MB por segundo en estilos ruidosos) y di cómo reconstruir: bash scripts/make.sh [foto.jpg] [semilla] [ancho]. Ofrece, no impongas: otra semilla (una impresión diferente de las mismas placas), un corte vertical (AR=9:16 node scripts/render.mjs frames-v 7 1080 5, luego verifica una hoja con AR=9:16; los títulos inferiores están al 70 % de la altura allí, TITLE_Y, libres de los botones de la plataforma; un

Skills relacionados