Mapa de la ruta
Contenido detallado
🖱️ Marco, cursor y zoom
La capa de animación que le da un aspecto profesional a la captura: el marco de navegador alrededor de la toma, el cursor SVG que se desliza hasta la bounding box real, el clic con pulse + ripple, el zoom en el resultado y el house style dark premium ámbar.
La ventana persistente #appwin queda en la bg-layer con data-layout-ignore: borde, radio, sombra grande, barra de título con 3 puntos y una píldora de URL monoespaciada (candado + window.urlLabel). Las capturas de pantalla quedan dentro de ella en (WIN_L, SHOT_T).
El marco mantiene el aspecto premium y disimula que el contenido es una captura de pantalla estática; sin él, parece una captura suelta.
# appwin persistente; data-layout-ignore; barra + píldora de URL; captura dentro de la ventana.
Un único elemento #cursor (flecha SVG) animada en la timeline principal — no por escena — se desliza continuamente. El hotspot queda en la punta en ~(6,3), entonces el tween usa x = alvoX - 6, y = alvoY - 3 para que la punta caiga en el centro de la bbox. Movimiento duration:.7, ease:"power3.inOut".
Apuntar al cuadro delimitador real (no al ojo) con una aceleración suave y curva es lo que hace que el cursor parezca profesional en lugar de robótico.
Cursor global; hotspot en la punta; bbox real; power3.inOut.
En el instante del clic (~start + 1.15s), el cursor hace scale:.82 en yoyo (pulse) y un #ripple (el círculo ámbar) se expande y desaparece, ubicado en el centro del objetivo.
La respuesta visual al clic comunica la acción al espectador; sin ella, parece que el cursor solo pasa por encima del botón.
pulse scale .82 yoyo; #ripple ámbar; timing ~start+1.15s.
El resaltado .hlbox es un rectángulo solo con box-shadow (anillo ámbar + glow) en el bbox mapeado con ~6px de margen, apareciendo con back.out. En el paso zoom:true, o <img> haz scale 1 → 1.12 con transformOrigin en el centro del objetivo.
Centra la mirada en el control activo sin cubrir nada y da un push-in cinematográfico en el momento del «¡tachán!» (el resultado).
.hlbox box-shadow; back.out; zoom:true; transformOrigin en el objetivo.
La paleta fija: fondo #0D1321, panel #1D2D44, borde #3E5C76, texto #F0EBD8, acento ámbar #FFC300 y código verde agua #2EC4B6. El ámbar es el ÚNICO destaque dominante — el ripple, el glow y el marco lo usan.
Mantener un solo acento y el mismo fondo en todas las escenas da la identidad premium consistente del canal.
6 colores fijos; ámbar único; fondo constante; verde agua solo en los valores.
Sora 700–800 para títulos, Inter para el cuerpo y los subtítulos, JetBrains Mono para la píldora de URL y los valores. Las tres vienen como .woff2 locales (el subset latin cubre PT-BR) en assets/fonts/ — o build-demo.mjs inyecta el fonts.css.
El render es determinista y offline; una fuente vía CDN fallaría y activaría una alternativa, lo que arruinaría el aspecto visual.
Sora/Inter/JetBrains; woff2 local; sin CDN; subset latin.
Ritmo recomendado: LEAD 0.5s (la escena aparece antes que la voz), TAIL 0.7s, FADE 0.4s entre escenas. El cursor llega al objetivo ~0.7s antes de la explicación principal; el clic ocurre cerca de start+1.15s.
Este ritmo es lo que hace que la animación parezca reaccionar a la narración; entender los parámetros te permite ajustar el video sin desincronizarlo.
LEAD 0.5s; TAIL 0.7s; FADE 0.4s; cursor antes de la voz.
🔊 Narración local y composición
La voz y el montaje: TTS local gratuito de Kokoro (voz pf_dora), generación de los WAV a partir del steps.json, medición automática de duraciones y el build-demo.mjs que sincroniza todo con el mismo array de tiempos y cierra con la CTA de INEMA.CLUB.
Kokoro es un TTS que se ejecuta 100% en la máquina (pip install kokoro-onnx soundfile), voz pf_dora en PT-BR, con --speed 0.98. La primera ejecución descarga ~340MB del modelo. No necesitas ninguna clave de API.
La narración gratuita y sin conexión mantiene la skill autocontenida; la voz es buena, sin actuación — por eso el usuario valida la locución después.
Kokoro local; pf_dora; speed 0.98; sin API.
O narration-template.sh lee steps[].narration e ctaNarration del steps.json, escribe assets/txt/sN.txt (1 por paso + CTA) y llama al TTS para generar assets/audio/sN.wav.
El steps.json es la fuente de los diálogos: generar los textos a partir de él evita que haya discrepancias entre lo escrito y lo que se dice.
steps[].narration; sN.txt → sN.wav; CTA al final.
O build-demo.mjs ejecuta ffprobe en cada sN.wav y arma el array AUDIO[] con las duraciones reales. No existe un array de tiempos escrito a mano.
El timing es la única fuente: medir el audio real elimina el riesgo de que el video y la voz no coincidan.
ffprobe; AUDIO[] derivado; timing como fuente única.
O composition-template.mjs (copiado como build-demo.mjs) lee el steps.json (pantallas + bboxes + captions + narración), mide los WAV y genera el index.html con marco, cursor, resaltado, zoom y CTA — todo listo.
Es el corazón del render: un único node build-demo.mjs produce el HTML renderizable a partir de los datos de la captura.
build-demo.mjs; lee steps.json; genera index.html; no editar a mano.
A partir de AUDIO[], el generador calcula S[] con start, dur, audioStart e end por escena (sumando LEAD/TAIL). La timeline GSAP y los <audio> las pistas leen ese mismo S[] — audio y animación sincronizados por construcción.
Compartir la fuente de tiempo entre la voz y el movimiento es lo que garantiza la sincronía sin ajustes manuales.
S[] se deriva de AUDIO[]; start/dur/audioStart; tracks alternados.
Cada paso tiene un caption no steps.json que se convierte en un subtítulo translúcido en el pie (Inter 600), que aparece y desaparece junto con la escena, en un track alternado con respecto a las escenas.
Los captions hacen que el video se entienda sin sonido (feeds silenciados) y refuerzan lo que se dice: se escriben una vez en steps.json.
subtítulo por paso; pie translúcido; sincronizado con la escena.
La última escena es la CTA: «CONTINÚA EN» + INEMA.CLUB (INEMA en crema, .CLUB ámbar con glow) + 🌐 inema.club. La narración predeterminada es "Esto es contenido de INEMA punto CLUB. Accede: inema punto club." y ya viene lista en la plantilla.
Es el punto de conversión del canal; viene incluido de forma predeterminada y garantiza que ningún video salga sin la llamada de marca.
CTA automática; INEMA.CLUB; ctaNarration; el cursor desaparece en la CTA.
🎞️ Renderizado en HyperFrames
La recta final: montar el proyecto HyperFrames, ejecutar la captura y la composición, validar con lint e inspect, renderizar en alta resolución — y qué está en el roadmap (9:16, grabación real, cursor en curva).
npx hyperframes init <nome> --example blank --non-interactive crea la carpeta del proyecto de video con la estructura base de HyperFrames.
Es el punto de partida de cada render: el proyecto queda aislado y ahí copias los scripts de la skill.
init; --example blank; --non-interactive.
Copia al proyecto: capture.mjs, composition-template.mjs (como build-demo.mjs), narration-template.sh e assets/fonts/ — o ejecuta node fetch-fonts.mjs para descargarlas.
La skill es autocontenida: incluye sus propias fuentes y su house style, sin depender de otro proyecto.
capture/build-demo/narration; assets/fonts; fetch-fonts.mjs.
node capture.mjs actions.json abre la app en un viewport fijo, ejecuta cada acción, toma 1 captura de pantalla por estado y obtiene el bounding box real del objetivo — salida: assets/shots/*.png + steps.json.
Es el vínculo entre la Trilha 2 (captura) y esta: sin el steps.json, el build-demo no tiene qué montar.
actions.json; viewport fijo; bbox real; capturas + steps.json.
node build-demo.mjs genera el index.html. Después npx hyperframes lint (0 errores) y npx hyperframes inspect --samples 14 (0 problemas) validan el diseño y las reglas antes de invertir tiempo en el render.
Lint e inspect detectan fuentes vía CDN, clips incorrectos y elementos fuera del canvas sin data-layout-ignore — barato comparado con volver a renderizar.
build-demo.mjs; lint 0 errores; inspect --samples 14.
Renderiza --quality draft para verificar (extrae 1 frame por paso y muéstraselo al usuario), después --quality high --fps 30 --output renders/<nome>-16x9.mp4.
No escuchas el audio en el renderizado; siempre revisa los fotogramas con el usuario y pídele que valide la locución antes del final.
draft → high; --fps 30; revisar frames; el usuario valida la voz.
Las reglas de oro: capturar antes y animar después (render determinista, sin sitio en vivo); viewport fijo = espacio de coordenadas; animar .scene-inner nunca .clip; elementos decorativos y marco con data-layout-ignore; fuentes locales.
Son los errores que más hacen fallar el render; conocerlos de antemano evita horas de depuración en el inspect.
capturar primero; viewport fijo; .scene-inner; data-layout-ignore.
Aún NO implementado: 9:16/Shorts (las pantallas de las apps son apaisadas y habría que reencuadrarlas); v3 grabación real de pantalla (agent-browser record) para apps con mucho movimiento; pulido del cursor en curva y de la «escritura» (typewriter) en los campos.
Conocer lo que está en el roadmap evita prometer lo que la skill aún no hace; hoy el formato natural es 16:9 con capturas de pantalla estáticas animadas.
9:16 futuro; v3 record; cursor en curva; typewriter — todo está en la hoja de ruta.