Generación de código y renderizado
Estás convirtiendo un brief en plan.json y renderizándolo. El proyecto de referencia ya implementa la gramática del video de lanzamiento; tú le proporcionas datos, no estás escribiendo un video desde cero.
El nivel de pulido del proyecto de referencia es el nivel de pulido de cada video que esta herramienta producirá. Por lo tanto, la opción predeterminada sólida es: escribe plan.json, no cambies nada más. Cada línea de animación personalizada que añadas a una ejecución es pulido que nunca llega al siguiente video, y una nueva forma de que el renderizado se rompa.
El mapa de archivos
pitchframe/
├── plan.json ← el plan de escenas. Este es el video.
├── palette.json ← colores extraídos. Datos, nunca prosa.
├── public/assets/*.png ← capturas de pantalla.
├── scripts/
│ ├── extract-palette.mjs ← tailwind → vars CSS → URL en vivo
│ ├── apply-palette.mjs ← escribe src/theme.ts desde palette.json
│ └── capture.mjs ← servidor de desarrollo + captura con Playwright
├── src/
│ ├── Root.tsx ← registra la composición LaunchVideo
│ ├── LaunchVideo.tsx ← mapea ritmos a Sequences. Controla el cross-dissolve.
│ ├── theme.ts ← GENERADO. Cada color se resuelve aquí.
│ ├── lib/
│ │ ├── types.ts ← el contrato del plan
│ │ └── motion.ts ← easing, fundidos, pulso de clic, deriva sostenida
│ ├── components/ ← Background, Cursor, FocusOverlay, Zoom, Panel, …
│ └── scenes/
│ ├── TypographyBeat.tsx
│ ├── InteractionBeat.tsx ← el momento heroico
│ ├── UIBeat.tsx
│ └── CTABeat.tsx
└── output.mp4
Escribiendo el plan
Carga pitchframe-launch-video para la estructura y el esquema. La versión corta:
- Cuatro partes — setup, hero, payoff, CTA. En ese orden. Siempre.
- Exactamente un ritmo de
interaction, y recibe al menos el 30% de los fotogramas. - La duración proviene de
thesis_weighten el brief, no de un valor predeterminado. - Copia
video_thesisyhero_momenten el plan para que la pasada de crítica pueda verificar el video contra la afirmación.
Haz la aritmética correcta antes de renderizar
Un renderizado fallido cuesta dos minutos; un plan cuyos ritmos se desvían cuesta un rerenderizado más el tiempo para darse cuenta. Verifica a mano, cada vez:
- Ritmos contiguos — cada
frames[0]es igual alframes[1]anterior. - El primer ritmo comienza en 0; el último ritmo termina exactamente en
total_frames. total_frames === duration_seconds * fps.- Ningún ritmo de tipografía por debajo de 45 fotogramas.
- Ritmo de interacción ≥ 30% de
total_frames.
Razona sobre las coordenadas, no las adivines
target_element.coordinates y zoom_target son porcentajes de la captura de pantalla. Son afirmaciones sobre dónde están los píxeles interesantes, y un punto focal desplazado un 10% del centro centra la toma heroica en un cromo vacío.
Abre la captura de pantalla, encuentra el elemento, convierte a porcentajes y verifica el resultado contra lo que se supone que debe mostrar el ritmo. Cuando la consecuencia de una acción ocurre en otro lugar que no sea el objetivo —el destino de un arrastre, un campo que se actualiza en otro lugar—, apunta zoom_target a la consecuencia, no a lo que tocó el cursor.
Colores: nunca en el plan, nunca en un componente
theme.ts es generado por apply-palette.mjs desde palette.json. Es el único lugar donde se escribe un color.
node pitchframe/scripts/extract-palette.mjs # → palette.json
node pitchframe/scripts/apply-palette.mjs # → src/theme.ts
Reglas que se derivan de eso:
- Nunca pongas un color en
plan.json. El plan dice qué palabra está acentuada; el tema dice cuál es el acento. - Nunca pongas un color literal en un componente. Si necesitas un tono que el tema no expone, añade un token derivado al generador para que cada video futuro también lo obtenga.
- Nunca edites
theme.tsmanualmente. Se sobrescribe en la siguiente generación.
Si los videos de dos productos se ven coloreados de manera idéntica, theme.ts no fue regenerado. Eso es lo primero que hay que verificar, antes de tocar cualquier otra cosa.
El renderizado
cd pitchframe && npx remotion render LaunchVideo output.mp4
Tres verificaciones primero, que cuestan un segundo y ahorran un renderizado fallido de dos minutos:
plan.jsonse analiza; la aritmética anterior se cumple.- Cada captura de pantalla nombrada en el plan existe en
public/assets/. Un ritmo de interacción necesita tantobefore_screenshotcomoafter_screenshot. node_modulesexiste enpitchframe/. Si no, ejecutanpm installallí primero.
Espera de 20 a 60 segundos para un video de 20 segundos.
Cuando el renderizado falla
Lee el error real antes de cambiar nada.
| Síntoma | Causa | Solución |
|---|---|---|
Cannot find module '../plan.json' | Andamio incompleto | Vuelve a ejecutar npx pitchframe install |
Cannot find name 'ACCENT' etc. | theme.ts no generado | Ejecuta apply-palette.mjs |
| Tiempo de espera de renderizado de fuentes agotado | Sin conexión, o una fuente no está en Google Fonts | Establece fonts.sans a Inter en palette.json y regenera |
| Error de decodificación de imagen | Captura de pantalla corrupta o parcial | Vuelve a capturar esa toma |
| Discrepancia en la duración de la composición | total_frames no coincide con los ritmos | Corrige la aritmética |
| OOM / fallo de Chrome | Capturas de pantalla enormes | Reduce la escala de cualquier cosa de más de ~4000px de ancho; --concurrency=2 |
Nunca respondas a un fallo de renderizado reescribiendo la composición. Corrige los datos.
Si el renderizado falla dos veces, detente y conserva la evidencia. Deja plan.json, palette.json y los assets en su lugar y di qué archivo revisar. Un renderizado fallido con un plan inspeccionable es recuperable; uno que ha sido "arreglado" por una reescritura no lo es.
Cuando tienes que tocar los componentes
Solo cuando un plan necesita algo que los componentes de ritmo genuinamente no pueden expresar. Tres reglas si llegas ahí:
- Añade, nunca reescribas. Un nuevo movimiento de cámara es una entrada en
SHOTSenlib/camera.ts, no un componente reestructurado — y tiene que estar listado enpitchframe-motion-languageo nada lo elegirá nunca. - Usa
lib/motion.tsylib/camera.ts.EASE,EASE_OUT,clickPulse,heldDrift,entranceBlurson el género. El easing hecho a mano es cómo un ritmo termina pareciendo que vino de un video diferente. Los resortes, rebotes y curvas elásticas están prohibidos. Hay exactamente un sistema de cámara. No añadasperspectiveo una transformación 3D fuera deStage.tsx; este repo tuvo dos una vez, se desviaron y las tomas dejaron de parecer filmadas por la misma persona. - Mantenlo basado en datos. Cualquier cosa que añadas debe poder alcanzarse desde un campo en
plan.json. Si la única forma de activarlo es editando el componente, es algo único y no pertenece a la referencia.
Siempre está mal aquí: un color literal; el nombre del producto o texto copiado directamente en un componente; una nueva composición de nivel superior; cambiar el contrato de 1920×1080 / 30fps; importar una biblioteca de animación.
Añadir un tipo de ritmo es casi siempre la respuesta incorrecta. El esquema tiene cuatro porque un video de lanzamiento necesita cuatro. Un nuevo tipo de ritmo suele ser un ritmo de característica disfrazado, y en el momento en que el esquema puede expresar una lista de características, los planes comienzan a contener una.
Después de un renderizado exitoso
Informa la ruta y la opción de edición:
Listo. Video disponible en ./pitchframe/output.mp4
Para editar, solo pregunta:
"mantén el momento heroico más tiempo"
"amplía el campo que cambió en su lugar"
La edición es manejada por pitchframe-editing, no por volver a ejecutar el pipeline.