HyperFrames
HTML es la fuente de verdad para el video. Una composición es un archivo HTML con atributos data-* para la temporización, una línea de tiempo de GSAP para la animación y CSS para la apariencia. El marco de trabajo maneja la visibilidad de los clips, la reproducción de medios y la sincronización de la línea de tiempo.
Enfoque
Descubrimiento (solo solicitudes exploratorias)
Para solicitudes abiertas ("hazme un video de lanzamiento de producto", "crea algo para nuestra marca") donde el usuario no se ha comprometido con una dirección, comprende la intención antes de elegir colores:
- Audiencia — ¿quién ve esto? ¿Desarrolladores? ¿Ejecutivos? ¿Consumidores generales?
- Plataforma — ¿dónde se reproduce? ¿Redes sociales (15s), página principal del sitio web, demostración de producto, uso interno?
- Prioridad — ¿qué es lo más importante? ¿Calidad del movimiento? ¿Precisión del contenido? ¿Fidelidad de la marca? ¿Velocidad?
- Variaciones — ¿el usuario quiere opciones o una sola mejor toma?
Para solicitudes específicas ("añade una tarjeta de título", "arregla la temporización en la escena 3"), omite el descubrimiento.
Para solicitudes exploratorias, considera ofrecer de 2 a 3 variaciones que difieran significativamente — no solo cambios de color, sino diferentes ritmos, niveles de energía o enfoques estructurales. Una segura/esperada, una ambiciosa. No lo hagas obligatorio — es una herramienta disponible cuando sea apropiado.
Paso 1: Sistema de diseño
Si design.md o DESIGN.md existe en el proyecto, léelo primero (verifica ambas mayúsculas/minúsculas — son archivos diferentes en Linux). Es la fuente de verdad para los colores de la marca, fuentes y restricciones. Usa sus valores exactos — no inventes colores ni sustituyas fuentes. Cualquier formato funciona (frontmatter YAML, prosa, tablas — solo extrae los valores).
Si nombra fuentes que no puedes encontrar localmente (sin directorio fonts/ con archivos .woff2, ni una fuente incorporada), advierte al usuario antes de escribir HTML: "design.md especifica [nombre de fuente] pero no se encontraron archivos de fuente. Agrega archivos .woff2 a fonts/ o recurriré a [la alternativa incorporada más cercana]."
Si no existe design.md, ofrece al usuario una opción:
- ¿El usuario nombró un estilo o estado de ánimo? → Lee visual-styles.md para los 8 ajustes preestablecidos con nombre. Elige la coincidencia más cercana.
- ¿Quiere explorar opciones visualmente? → Ejecuta el selector de diseño: lee references/design-picker.md para el flujo de trabajo completo. Esto sirve una página de selector visual. El usuario configura el estado de ánimo, la paleta, la tipografía y el movimiento en el navegador, luego copia el design.md generado y lo pega de nuevo en la conversación.
- ¿Quiere omitir e ir rápido? → Pregunta: estado de ánimo, claro u oscuro, ¿colores/fuentes de marca? Luego elige una paleta de house-style.md.
design.md define la marca. No define las reglas de composición de video. Esas vienen de references/video-composition.md y house-style.md. Usa los colores de la marca a una escala apropiada para video — no a la opacidad de una interfaz web.
Paso 2: Expansión de la solicitud
Ejecuta siempre en cada composición (excepto en piezas de una sola escena y ediciones triviales). Este paso fundamenta la intención del usuario con respecto a design.md y house-style.md y produce un intermediario consistente que todo agente posterior lee de la misma manera.
Lee references/prompt-expansion.md para el proceso completo y el formato de salida.
Paso 3: Plan
Antes de escribir HTML, piensa a alto nivel:
- Qué — ¿qué debería experimentar el espectador? Identifica el arco narrativo, los momentos clave y los latidos emocionales.
- Estructura — cuántas composiciones, cuáles son subcomposiciones vs. en línea, qué pistas llevan qué (video, audio, superposiciones, subtítulos).
- Ritmo — declara tu ritmo de escena antes de implementar. Qué escenas son golpes rápidos, cuáles son pausas, dónde aterrizan los sombreadores, dónde alcanza su punto máximo la energía. Nombra el patrón: rápido-rápido-LENTO-rápido-SOMBREADOR-pausa. Lee references/beat-direction.md para plantillas de ritmo.
- Temporización — qué clips impulsan la duración, dónde aterrizan las transiciones, cuál es el ritmo.
- Diseño — construye el estado final primero. Ver "Diseño Antes de la Animación" a continuación.
- Animar — luego añade movimiento usando las reglas a continuación.
Construye lo que se pidió. Una solicitud de "una tarjeta de título" no es una solicitud de "una tarjeta de título + 3 escenas de apoyo + música ambiental + subtítulos." Cada escena, cada elemento, cada interpolación debe ganarse su lugar. Si escenas o elementos adicionales mejoran genuinamente la pieza, propónlos — no los agregues.
Para ediciones pequeñas (corregir un color, ajustar la temporización, añadir un elemento), salta directamente a las reglas.
Diseño Antes de la Animación
Posiciona cada elemento donde debería estar en su momento más visible — el fotograma donde ha entrado completamente, está colocado correctamente y aún no está saliendo. Escríbelo como HTML+CSS estático primero. Aún no hay GSAP.
Por qué es importante: Si posicionas los elementos en su estado de inicio animado (fuera de pantalla, escalados a 0, opacidad 0) y los interpolas a donde crees que deberían aterrizar, estás adivinando el diseño final. Las superposiciones son invisibles hasta que el video se renderiza. Al construir el estado final primero, puedes ver y solucionar problemas de diseño antes de agregar cualquier movimiento.
El proceso
- Identifica el fotograma héroe para cada escena — el momento en que la mayoría de los elementos son visibles simultáneamente. Este es el diseño que construyes.
- Escribe CSS estático para ese fotograma. El contenedor
.scene-contentDEBE llenar la escena completa usandowidth: 100%; height: 100%; padding: Npx;condisplay: flex; flex-direction: column; gap: Npx; box-sizing: border-box. Usa padding para empujar el contenido hacia adentro — NUNCA usesposition: absolute; top: Npxen un contenedor de contenido. Los contenedores de contenido posicionados absolutamente se desbordan cuando el contenido es más alto que el espacio restante. Reservaposition: absolutesolo para elementos decorativos. - Añade entradas con
gsap.from()— anima DESDE fuera de pantalla/invisible HASTA la posición CSS. La posición CSS es la verdad fundamental; la interpolación describe el viaje para llegar allí. (En subcomposiciones cargadas víadata-composition-src, prefieregsap.fromTo()— ver reglas de GSAP de carga estructural en references/motion-principles.md.) - Añade salidas con
gsap.to()— anima HASTA fuera de pantalla/invisible DESDE la posición CSS.
Ejemplo
/* scene-content llena la escena, el padding posiciona el contenido */
.scene-content {
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
height: 100%;
padding: 120px 160px;
gap: 24px;
box-sizing: border-box;
}
.title {
font-size: 120px;
}
.subtitle {
font-size: 42px;
}
/* El contenedor se adapta a cualquier tamaño de escena (1920x1080, 1080x1920, etc.).
El padding posiciona el contenido. Flex + gap maneja el espaciado. */
INCORRECTO — dimensiones codificadas y posicionamiento absoluto:
.scene-content {
position: absolute;
top: 200px;
left: 160px;
width: 1920px;
height: 1080px;
display: flex; /* ... */
}
// Paso 3: Animar HACIA esas posiciones
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);
tl.from(".logo", { scale: 0.8, opacity: 0, duration: 0.4, ease: "power2.out" }, 0.3);
// Paso 4: Animar FUERA de esas posiciones
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
tl.to(".subtitle", { y: -30, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.1);
tl.to(".logo", { scale: 0.9, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.2);
Cuando los elementos comparten espacio a través del tiempo
Si el elemento A sale antes de que el elemento B entre en la misma área, ambos deben tener posiciones CSS correctas para sus respectivos fotogramas héroe. El orden de la línea de tiempo garantiza que nunca coexistan visualmente — pero si omites el paso de diseño, no detectarás el caso en que se superpongan accidentalmente debido a un error de temporización.
Qué cuenta como superposición intencional
Los efectos en capas (brillo detrás del texto, elementos de sombra, patrones de fondo) y los diseños apilados en z (pilas de tarjetas, capas de profundidad) son intencionales. El paso de diseño consiste en detectar superposiciones no intencionales — dos titulares que caen uno sobre otro, una estadística que cubre una etiqueta, contenido que se sale del fotograma.
Atributos de Datos
Todos los Clips
| Atributo | Requerido | Valores |
|---|---|---|
id | Sí | Identificador único |
data-start | Sí | Segundos o referencia de ID de clip ("el-1", "intro + 2") |
data-duration | Requerido para img/div/composiciones | Segundos. El video/audio predetermina la duración del medio. |
data-track-index | Sí | Entero. Los clips de la misma pista no pueden superponerse. |
data-media-start | No | Desplazamiento de recorte en la fuente (segundos) |
data-volume | No | 0-1 (por defecto 1) |
data-track-index no afecta la superposición visual — usa CSS z-index.
Clips de Composición
| Atributo | Requerido | Valores |
|---|---|---|
data-composition-id | Sí | ID de composición único |
data-start | Sí | Tiempo de inicio (composición raíz: usa "0") |
data-duration | Sí | Tiene prioridad sobre la duración de la línea de tiempo de GSAP |
data-width / data-height | Sí | Dimensiones en píxeles (1920x1080 o 1080x1920) |
data-composition-src | No | Ruta a un archivo HTML externo |
data-variable-values | No | Objeto JSON de anulaciones de variables por instancia en un host de subcomp |
En el elemento raíz <html>:
| Atributo | Requerido | Valores |
|---|---|---|
data-composition-variables | No | Array JSON de variables declaradas (id/type/label/default) — impulsa la UI de edición de Studio y proporciona valores predeterminados para getVariables() |
Estructura de Composición
Las subcomposiciones cargadas vía data-composition-src usan un envoltorio <template>. Las composiciones independientes (el index.html principal) NO usan <template> — colocan el div data-composition-id directamente en <body>. Usar <template> en un archivo independiente oculta todo el contenido del navegador y rompe la renderización.
Estructura de subcomposición:
<template id="my-comp-template">
<div data-composition-id="my-comp" data-width="1920" data-height="1080">
<!-- contenido -->
<style>
[data-composition-id="my-comp"] {
/* estilos con ámbito */
}
</style>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// interpolaciones...
window.__timelines["my-comp"] = tl;
</script>
</div>
</template>
Cargar en la raíz: <div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="10" data-track-index="1"></div>
Variables (Composiciones Parametrizadas)
Renderiza la misma composición con contenido diferente — título, color de tema, precios, subtítulos — sin editar el HTML fuente.
Patrón de tres pasos:
- Declara variables en la raíz
<html>de la composición condata-composition-variables. Cada entrada necesitaid,type(uno destring,number,color,boolean,enum),labelydefault. Las entradas Enum también necesitanoptions: [{value, label}, ...]. - Lee los valores resueltos dentro del script de la composición con
window.__hyperframes.getVariables(). Devuelve el resultado fusionado de los valores predeterminados declarados + anulaciones por instancia + anulaciones CLI. - Anula en tiempo de renderizado con
npx hyperframes render --variables '{...}'(nivel superior) o condata-variable-values='{...}'en el elemento host (por instancia para subcomps).
<!doctype html>
<html
data-composition-variables='[
{"id":"title","type":"string","label":"Title","default":"Hello"},
{"id":"theme","type":"enum","label":"Theme","default":"light","options":[
{"value":"light","label":"Light"},
{"value":"dark","label":"Dark"}
]}
]'
>
<body>
<div data-composition-id="root" data-width="1920" data-height="1080">
<h1 id="hero" class="clip" data-start="0" data-duration="3"></h1>
<script>
const { title, theme } = window.__hyperframes.getVariables();
document.getElementById("hero").textContent = title;
document.body.dataset.theme = theme;
</script>
</div>
</body>
</html>
# La vista previa de desarrollo usa los valores predeterminados declarados
npx hyperframes preview
# Renderizar con anulaciones
npx hyperframes render --variables '{"title":"Q4 Report","theme":"dark"}' --output q4.mp4
# O desde un archivo JSON
npx hyperframes render --variables-file ./vars.json
Valores por instancia de subcomposición: el mismo getVariables() funciona dentro de subcomps cargadas vía data-composition-src. Cada elemento host pasa sus propios valores:
<div
data-composition-id="card-pro"
data-composition-src="compositions/card.html"
data-variable-values='{"title":"Pro","price":"$29"}'
></div>
<div
data-composition-id="card-enterprise"
data-composition-src="compositions/card.html"
data-variable-values='{"title":"Enterprise","price":"$99"}'
></div>
Las variables proporcionan valores en tiempo de ejecución; no interpolan HTML o URL. La validación del tipo ocurre dentro de getVariables(). El renderizador CLI informa errores de combinación de tipos.
Transiciones de Escena
Las transiciones ocurren entre clips en la misma pista cuando el clip saliente y el entrante se superponen en el tiempo.
Cuando dos clips se superponen en la misma pista, el cuadro de medios del clip entrante se vuelve visible. Las transiciones se definen con atributos en el clip entrante.
Cada transición requiere un fotograma de transición. Piensa en una transición como una animación que se ejecuta en un elemento separado que se encuentra entre dos clips. Este fotograma de transición se posiciona usando un data-start y data-duration que se superpone a ambos clips.
Atributos de Transición en el Clip Saliente
| Atributo | Tipo | Requerido | Descripción |
|---|---|---|---|
data-transition | cadena | Sí | Tipo de transición (wipeLeft, wipeRight, wipeUp, wipeDown, crossfade, revealLeft, revealRight, revealUp, revealDown, shaderTransition) |
data-duration | número | Sí | Duración de la transición en segundos |
Ejemplo
<div id="scene1" data-start="0" data-duration="5" class="scene-1">
<!-- contenido de la escena 1 -->
</div>
<div id="scene2" data-start="4" data-duration="6" class="scene-2" data-transition="crossfade" data-duration="1">
<!-- contenido de la escena 2 -->
</div>
Importante: El clip que se está desvaneciendo DEBE estar completamente renderizado (sin interpolaciones de GSAP en curso) cuando comienza la transición. Asegúrate de que el data-duration de la escena saliente sea lo suficientemente largo para que su animación se complete antes de que comience la transición.
Transiciones de Sombreador
Las transiciones más complejas usan un sombreador GLSL personalizado. Esto requiere que el marco de trabajo cargue el sombreador, maneje el muelle de texturas uniforme y ejecute el sombreador de fragmentos como un efecto de pantalla completa.
<div
id="transition-el"
data-start="4"
data-duration="1.5"
data-shader-fs="uniform vec2 iResolution; uniform float iTime; uniform sampler2D iChannel0; uniform sampler2D iChannel1; void main() { vec2 uv = gl_FragCoord.xy / iResolution.xy; vec4 a = texture2D(iChannel0, uv); vec4 b = texture2D(iChannel1, uv); float progress = iTime / 1.5; gl_FragColor = mix(a, b, smoothstep(0.0, 1.0, progress)); }"
></div>
El sombreador de fragmentos recibe dos texturas de entrada (iChannel0 para la escena saliente, iChannel1 para la entrante), tiempo uniforme (iTime), resolución (iResolution) y progreso del muelle. El sombreador mezcla, distorsiona o transforma entre las dos texturas de entrada.
Audio
Reproducción de Audio
<audio
id="bg-music"
class="clip"
data-start="0"
data-duration="10"
data-volume="0.5"
src="media/background.mp3"
></audio>
Superposición de voces
<audio
id="voiceover"
class="clip"
data-start="0.5"
data-duration="8"
data-volume="1"
src="media/narration.mp3"
></audio>
El audio puede cargarse desde un archivo local o desde una URL remota. Usa siempre el formato MP3.
Shorts / Vertical
Para contenido de video de formato corto (vertical, 9:16, típicamente 1080x1920):
- El diseño de la composición vertical sigue las mismas reglas que el horizontal — construir el estado final primero, luego animar.
- Factor de escala: los elementos de texto deben ser ~25-33% más grandes que sus equivalentes horizontales porque los espectadores móviles tienen menos espacio en la pantalla y distancias de visualización variables.
- El padding vertical debe ser más generoso — el espacio seguro para contenido vertical es de aproximadamente 80-100 px en la parte superior e inferior (evitando la interfaz de la plataforma social y los recortes).
- El ritmo vertical prefiere cortes rápidos y transiciones enérgicas. Mantén las escenas por debajo de 3 segundos a menos que haya una razón narrativa convincente para una escena más larga.
Rastreo de Medios
Inicializa los clips de medios (audio y video) con setTimeout dentro de cada script de composición.
El rastreo de medios requiere que el host se registre con el planificador en data-start. El marco de trabajo busca __hyperframes.mediaRegistry en el objeto window y reproduce el clip en data-start.
setTimeout(() => {
if (window.__hyperframes?.mediaRegistry) {
window.__hyperframes.mediaRegistry.registerMedia("el-id", document.getElementById("el-id"));
}
}, 100);
Referencias
- video-composition.md — reglas de composición de video
- prompt-expansion.md — expansión de solicitudes
- beat-direction.md — plantillas de ritmo
- motion-principles.md — principios de movimiento y reglas de GSAP
- visual-styles.md — estilos visuales preestablecidos
- house-style.md — estilo de la casa
- design-picker.md — flujo de trabajo del selector de diseño
- hyperframes-cli.md — comandos CLI
- hyperframes-media.md — comandos de medios