Tipografía Cinética
Crea videos donde las palabras mismas son la imagen. Una frase aterriza, llena el encuadre, es golpeada y reemplazada por la siguiente, al ritmo. Debe sentirse audaz, rápido y musical, como un póster que se mueve.
Opciones
| Opción | Por Defecto | Notas |
|---|---|---|
| formato | vertical 1080×1920 | o apaisado 1920×1080, cuadrado 1080×1080 |
| duración | 10–20 s | que coincida con la voz en off o la sección de la canción |
| tono | contundente | tranquilo (deslizamientos y fundidos de 0.4 s, menos giros), contundente (por defecto), caótico (todo mayúsculas, golpes, sacudidas, un giro en cada dos frases) |
| ritmo | tempo fijo | o tiempos de palabras de voz en off, o ritmos musicales |
Resumen (responder antes de planificar)
- ¿Cuál es la única frase que el espectador debe recordar?
- Divide el guión en frases de 1–4 palabras; marca una palabra héroe por frase.
- ¿Dónde está el pico de energía (la frase que obtiene el cambio de color)?
- ¿Cuál es el bloqueo final (título, llamada a la acción, nombre de usuario)?
Hoja de lectura (escríbela con la lista de tiempos)
Para cada tiempo, escribe la única cosa que el espectador debe entender ("el robot no puede volar", "la caché falló") y cuánto tiempo permanece legible. Una lectura a la vez. Pisos de texto: una etiqueta permanece al menos 0.8 s, una oración aproximadamente 0.3 s por palabra una vez que está completamente en pantalla. Si el texto no cabe en el tiempo, recorta palabras en lugar de acelerar.
Disciplina de movimiento
- El movimiento es causal: cada movimiento tiene una razón en pantalla (un clic, una caída, un paquete que llega), y el siguiente movimiento se deriva de él.
- Elige una dirección principal de viaje para todo el video y mantenla. Usa las otras direcciones para dar significado: hacia arriba para éxito o conclusión, un zoom out para "aquí está la imagen completa".
- La salida de una escena prepara la siguiente entrada: mismo eje, misma dirección, velocidad similar. Transporta un objeto a través del cambio en lugar de hacer un crossfade.
- Sin movimiento de relleno inactivo (flotante, respiratorio, tambaleante) en diagramas, gráficos o texto. Si nada debe moverse, quédate quieto; un desplazamiento de cámara deliberado es suficiente.
- Suavizado: ease-out suave para entradas (
power2.outapower4.out), ease-in más rápido para salidas (aproximadamente el 75% del tiempo de entrada). Entradas de máximo 0.8 s. Escalonamiento total para un grupo de máximo 0.5 s. Overshoot (back.out) solo para pequeños estallidos; sin elástico ni rebote. - Una cosa se mueve a la vez cuando es importante; el ojo solo puede seguir una.
- Añade un momento de quietud de 0.3–0.75 s justo antes del momento culminante.
Reglas de estilo (siempre)
Estas hacen que sea este estilo; mantenlas independientemente de los colores o las palabras.
- El tipo ocupa el 50–80% del ancho del encuadre, porque el texto pequeño se lee como subtítulos, no como el elemento visual.
- Una idea en pantalla a la vez: 1–4 palabras, como máximo 3 líneas. Todo lo demás se ha ido.
- Cada palabra llega con un movimiento (golpe, deslizamiento, estiramiento, revelación de máscara, giro). Nada simplemente aparece.
- Los cambios aterrizan en un ritmo: una nueva palabra o movimiento cada 0.25–0.7 s, y las palabras clave en el tiempo o la sílaba acentuada.
- El contraste es extremo: casi negro sobre blanco roto o viceversa, más un color de acento solo para la palabra clave.
- Cada frase obtiene una palabra héroe: la más grande, de color de acento, o que se mueve de manera diferente al resto.
Valores por defecto (cambiar libremente)
Fuentes, colores, palabras, sincronización y fondo. Si el usuario proporciona fuentes o colores de marca, los suyos ganan. Precedencia: marca o especificación del usuario, luego la solicitud explícita, luego estos valores por defecto.
- Fondo
#111111, texto#f4f1ea, acento#ff4d2e. Cambia a claro sobre oscuro u oscuro sobre claro por frase para dar energía. - Fuente de visualización: una cara condensada y pesada (Anton, Bebas Neue o Archivo Black), todo mayúsculas para las palabras héroe. Fuente de apoyo: una sans-serif pesada (Inter 800) para palabras de conexión pequeñas.
- Tamaño: palabras héroe 180–320 px en 9:16; palabras pequeñas 60–90 px.
Configuración (una vez)
node -v # necesita 22+
ffmpeg -version
npx hyperframes init mi-video --non-interactive --resolution portrait && cd mi-video # apaisado para 16:9
Dentro de una carpeta vacía existente usa npx hyperframes init . --non-interactive --resolution portrait, luego reemplaza el index.html generado con la plantilla de abajo.
Decidir antes de construir
Indica esto al usuario en una línea antes de escribir código.
- Relación de aspecto: 9:16 (1080×1920) o 16:9 (1920×1080). Por defecto es 9:16.
- Palabras y sincronización: divide el guión en frases de 1–4 palabras. Con una voz en off, toma los tiempos de sus marcas de tiempo de palabras (
npx hyperframes transcribe voz.wav). Sin una, asigna a cada frase 0.6–1.4 s, y da a las palabras héroe más tiempo. - Fuente de ritmo: voz (aterrizar en sílabas acentuadas), música (aterrizar en tiempos;
npx hyperframes beats musica.mp3), o un tempo fijo (p. ej., 120 BPM = un tiempo cada 0.5 s). - Palabra héroe por frase y qué movimiento recibe.
| Necesidad | HyperFrames + GSAP (por defecto) | Remotion |
|---|---|---|
| Movimientos de palabras y letras, máscaras, estiramientos | sí | sí |
| Sincronización a partir de datos de voz o ritmo | sí (etiquetas) | sí (fotogramas) |
| Funciona solo con Node y FFmpeg | sí | sí |
| Licencia | gratuita | gratuita hasta 3 personas, de pago para más |
Vocabulario de movimientos
| Movimiento | Cómo (GSAP) | Úsalo para |
|---|---|---|
| Golpe | from {scale: 2.6, opacity: 0}, expo.out, 0.22 s, más una sacudida de pantalla de 6 px durante 0.1 s | palabras héroe |
| Apilar deslizando | líneas from {yPercent: 110} dentro de máscaras overflow:hidden, escalonamiento 0.06 s, power4.out 0.35 s | listas, frases de dos líneas |
| Estiramiento | scaleY: 1.6 → 1, transformOrigin: bottom, back.out(3) 0.3 s | énfasis, verbos |
| Cascada de letras | letras from {y: -120, rotation: -20, opacity: 0}, escalonamiento 0.025 s, back.out(2) | nombres, títulos |
| Intercambio giratorio | palabra antigua rotationX: 90 saliendo (0.12 s), palabra nueva rotationX: -90 → 0 entrando (0.18 s) | X se convierte en Y |
| División | mitades de palabras se deslizan separadas x: ±140 para revelar una palabra más pequeña entre ellas | contrastes |
| Salida | yPercent: -110 o scale: 0.7, opacity: 0, 0.15 s, power2.in | cada frase que se va |
Las salidas son rápidas (0.12–0.18 s) y las entradas son más rápidas de lo que piensas (0.18–0.35 s). Mantén cada frase al menos 0.35 s después de que aterrice, para que pueda leerse.
Hazlo llamativo
- Llena el encuadre. Ajusta el tamaño de las palabras al ancho del encuadre, no a un tamaño de fuente. Las fuentes condensadas a 250+ px son el estilo.
- Cambios de color: el fondo alterna entre oscuro y claro (o al acento) en 2–3 frases clave, como un corte brusco en el tiempo.
- Textura y profundidad: una superposición sutil de grano, una sombra suave o un duplicado desplazado detrás de las palabras héroe (color de acento, desplazamiento 10–14 px), y una palabra gigante ocasional desvanecida en el fondo.
- Energía de cámara: un desplazamiento de escala lento del 2–4% en todo el escenario, un zoom (escala 1.06 durante 0.1 s) en los golpes de héroe, y una sacudida de 6–10 px en los golpes.
- Formas con palabras: barras de subrayado que se dibujan, círculos que aparecen detrás de una palabra, flechas. Color de acento, planos.
- Termina con un bloqueo: el título o la llamada a la acción, completamente compuestos, mantenidos 1–1.5 s, que coincidan con el encuadre de apertura para que se repita.
- Control de calidad: si alguna captura muestra texto pequeño centrado sobre un fondo liso, no está terminado.
Construir: plantilla
<!doctype html><html><head><meta charset="UTF-8">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Anton&family=Inter:wght@800&display=swap">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<style>
html,body{margin:0;width:1080px;height:1920px;overflow:hidden;background:#111}
#root{width:100%;height:100%;position:relative;overflow:hidden}
#stage{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}
.phrase{position:absolute;left:60px;right:120px;top:270px;bottom:670px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:0}
.line{overflow:hidden;line-height:.92;padding:0 8px}
.w{display:inline-block;font-family:Anton,sans-serif;text-transform:uppercase;color:#f4f1ea;white-space:nowrap}
.hero{color:#ff4d2e}
.flip .w{color:#fff}.flip .hero{color:#111}
.small{font-family:Inter,system-ui,sans-serif;font-weight:800;text-transform:none}
#bg{position:absolute;inset:0;background:#111}
</style></head>
<body><div id="root" data-composition-id="main" data-start="0" data-duration="8" data-width="1080" data-height="1920">
<div id="bg"></div><div id="stage"></div></div>
<script>
// [time, lines, moveName, heroWordIndex, flipBackground?] -- edit this list; times in seconds
const FRASES = [
[0.2, ["PALABRAS"], "golpe", 0],
[1.0, ["pueden", "MOVVERSE"], "apilar", 1],
[2.0, ["COMO", "MÚSICA"], "estirar", 1, true],
[3.2, ["una", "idea"], "apilar", 1],
[4.2, ["A LA", "VEZ"], "golpe", 1],
[5.4, ["TIPOGRAFÍA", "CINÉTICA"], "cascada", 1],
];
const FIN = 8, ANCHO = 1080 - 180;
// measure text only after the web fonts load, then build and register the timeline
document.fonts.ready.then(() => {
const tl = gsap.timeline({ paused: true });
const escenario = document.getElementById("stage");
FRASES.forEach(([t, lines, move, hero, flip], i) => {
const p = document.createElement("div"); p.className = "phrase" + (flip ? " flip" : ""); escenario.appendChild(p);
const words = lines.map((txt, k) => {
const linea = document.createElement("div"); linea.className = "line";
const w = document.createElement("span"); w.className = "w" + (k === hero ? " hero" : "") + (txt === txt.toLowerCase() && k !== hero ? " small" : "");
w.textContent = txt; linea.appendChild(w); p.appendChild(linea);
w.style.fontSize = "100px"; const fit = Math.min(420, (100 * ANCHO) / w.getBoundingClientRect().width); // fill the width
w.style.fontSize = (w.classList.contains("small") ? Math.min(fit, 110) : fit) + "px";
return w;
});
gsap.set(p, { autoAlpha: 0 });
tl.set(p, { autoAlpha: 1 }, t);
if (move === "golpe") tl.from(words, { scale: 2.6, opacity: 0, duration: 0.22, ease: "expo.out", stagger: 0.08 }, t)
.fromTo("#stage", { x: -10 }, { x: 10, duration: 0.04, yoyo: true, repeat: 3, ease: "none" }, t + 0.18).set("#stage", { x: 0 }, t + 0.34);
if (move === "apilar") tl.from(words, { yPercent: 110, duration: 0.35, ease: "power4.out", stagger: 0.07 }, t);
if (move === "estirar") tl.from(words, { scaleY: 1.7, opacity: 0, transformOrigin: "50% 100%", duration: 0.3, ease: "back.out(3)", stagger: 0.08 }, t);
if (move === "cascada") words.forEach((w, k) => {
const letters = Array.from(w.textContent); w.textContent = "";
letters.forEach((c) => { const l = document.createElement("span"); l.style.display = "inline-block"; l.textContent = c; w.appendChild(l); });
tl.from(w.children, { y: -140, rotation: -20, opacity: 0, duration: 0.4, ease: "back.out(2)", stagger: 0.03 }, t + k * 0.15); });
const siguiente = FRASES[i + 1] ? FRASES[i + 1][0] : null;
if (flip) tl.set("#bg", { background: "#ff4d2e" }, t).set("#bg", { background: "#111" }, siguiente || FIN); // colour flip on a key phrase
if (siguiente) tl.to(words, { yPercent: -110, opacity: 0, duration: 0.15, ease: "power2.in", stagger: 0.03 }, siguiente - 0.17)
.set(p, { autoAlpha: 0 }, siguiente);
});
tl.fromTo("#root", { scale: 1 }, { scale: 1.04, duration: FIN, ease: "none" }, 0); // slow drift
tl.set({}, {}, FIN);
window.__timelines["main"] = tl;
});
</script></body></html>
Edita FRASES para cambiar las palabras y los tiempos. Añade movimientos agregando una rama if (move === ...) del vocabulario de movimientos. Con una voz en off, coloca el elemento <audio> en la raíz y toma los tiempos de las frases de su transcripción.
Parámetros a exponer al usuario
aspecto · frases (tiempo, líneas, movimiento, héroe) · fuenteVisualizacion · fuenteApoyo · colores (fondo, texto, acento) · tempo o audio · frasesCambio (donde el fondo cambia) · bloqueoFinal.
Evitar
- Fundidos de entrada y desplazamientos lentos como movimiento principal. Parece una presentación de diapositivas.
- Más de 4 palabras o 3 líneas en pantalla a la vez.
- Varios colores de acento. Un acento, usado solo en palabras héroe.
- Pesos de fuente finos o ligeros, o fuentes script para palabras héroe.
- Texto en los 670 px inferiores o 270 px superiores de un encuadre 9:16 (la interfaz de la plataforma los cubre).
- Variación aleatoria o por renderizado. Cada valor debe provenir de la línea de tiempo.
Modos de fallo
| Parece | Causa | Solución |
|---|---|---|
| Una presentación de diapositivas | fundidos, mantenciones largas, el mismo movimiento cada vez | varía los movimientos del vocabulario; entradas por debajo de 0.35 s; salidas 0.15 s |
| Subtítulos, no diseño | palabras demasiado pequeñas, centradas en espacio vacío | ajusta el tamaño de las palabras al ancho del encuadre; fuente condensada; 250+ px |
| Desordenado, ilegible | demasiadas palabras o movimientos a la vez | una frase en pantalla; una palabra héroe; mantén 0.35 s después de aterrizar |
| Fuera de ritmo | tiempos de frases adivinados | usa tiempos de transcripción o ritmo; aterriza los golpes 2–3 fotogramas antes |
| Palabras recortadas por máscaras | interlineado demasiado ajustado para la fuente | line-height 0.92–1.0 con relleno en .line; verifica las capturas |
| Fuente incorrecta en el renderizado | fuente no cargada | <link> de Google Fonts en el encabezado; verifica que una captura muestre la cara condensada |
Validar antes del renderizado final
npx hyperframes check
npx hyperframes snapshot --at <un tiempo por frase 0.3 s después de que aterrice, más uno a mitad de salida>
npx hyperframes render -o renders/<nombre>.mp4
ffprobe -v error -show_entries stream=width,height,r_frame_rate:format=duration -of csv=p=0 renders/<nombre>.mp4
Mira cada captura y snapshots/contact-sheet.jpg, y confirma:
- cada frase ocupa el 50–80% del ancho y es legible en tamaño de teléfono
- una palabra héroe por frase, en el color de acento o con un movimiento diferente
- no hay dos frases que se superpongan en ningún fotograma
- todo el texto dentro del área segura para la relación de aspecto
- el bloqueo final se mantiene al menos 1 s y coincide con la apertura
- el tamaño y la duración coinciden con la solicitud
Autocrítica antes del renderizado final
Puntúa la hoja de capturas del 1 al 10 en: gancho (primer segundo), legibilidad en ancho de teléfono, calidad de movimiento, composición, precisión, y la "prueba muda" (¿puede un espectador resumirlo en una frase sin sonido?). Arregla solo lo que puntúe 7 o menos, vuelve a tomar capturas, y repite hasta que todo sea 8 o más. Si puedes, haz que una pasada de solo lectura haga la puntuación, para que no estés calificando tu propio trabajo.
| No hacer | En su lugar |
|---|---|
| Hacer crossfade entre dos diseños ocupados | salir del contenido antiguo, luego traer el nuevo, o transportar un objeto a través |
| Hacer que varias cosas se muevan a la vez | escalonar, un foco |