PTENES
MΓ“DULO 3.2

🎨 House style dark premium

Paleta, tipografΓ­a, capa de fondo y escala de video: el sistema visual que hace que cada escena sea inconfundible.

6
Temas
22
Minutos
Avanzado
Nivel
Referencia
Tipo
DARK --bg #0D1321 --bg2 #1D2D44 --bg3 #3E5C76 --fg #F0EBD8 --muted #748CAB --accent ÚNICO #FFC300 --accent2 #FCA311 --code #2EC4B6 UN acento. Siempre. FONDO TEXTO BORDES
1

🎨 La paleta

Ocho variables CSS. Una por funciΓ³n. Cero improvisaciΓ³n.

El house style no es una lista de colores bonitos: es un sistema con un rol definido para cada tono. Fondo nocturno (#0D1321), paneles un poco mΓ‘s claros, borde sutil, texto color crema cΓ‘lido, muted para la jerarquΓ­a, y Γ‘mbar como ΓΊnico acento dominante. El cian (#2EC4B6) estΓ‘ reservado exclusivamente para cΓ³digo y valores tΓ©cnicos.

--bg
#0D1321
--bg2
#1D2D44
--bg3 / borde
#3E5C76
--fg
#F0EBD8
--muted
#748CAB
--accent β˜…
#FFC300
--accent2
#FCA311
--code
#2EC4B6
:root del composition-template.mjs
:root {
  --bg:      #0D1321;   /* azul-noite – NUNCA preto puro */
  --bg2:     #1D2D44;   /* painΓ©is e cards */
  --bg3:     #3E5C76;   /* bordas e divisores */
  --fg:      #F0EBD8;   /* texto creme quente */
  --muted:   #748CAB;   /* secundΓ‘rio / hierarquia */
  --accent:  #FFC300;   /* Γ’mbar β€” destaque ÚNICO */
  --accent2: #FCA311;   /* Γ’mbar quente p/ gradientes */
  --code:    #2EC4B6;   /* verde-Γ‘gua β€” sΓ³ cΓ³digo/valores */
}
βœ“ HACER
  • βœ“Usar #0D1321 como fondo en todas las escenas
  • βœ“Γmbar solo para el accent dominante (CTAs, destacados)
  • βœ“Cian solo para cΓ³digo, URLs y valores tΓ©cnicos
  • βœ“Fondo idΓ©ntico en todas las escenas del video
βœ— NO HACER
  • βœ—Usar #000000 como fondo (parece un video de un youtuber novato)
  • βœ—Mezclar dos acentos en la misma escena (verde + Γ‘mbar)
  • βœ—Usar cian para texto decorativo
  • βœ—Cambiar la paleta de una escena a otra
🎨
8 variables
roles fijos
β˜…
1 acento
Γ‘mbar dominante
⌨
cian = cΓ³digo
solo tΓ©cnico
πŸŒ™
fondo fijo
consistencia total
2

πŸ”€ TipografΓ­a

Tres fuentes. Tres funciones. Ninguna ambigΓΌedad.

El sistema usa Sora para titulares (peso 700–800, escala de video de 72–172px en 16:9), Inter para el cuerpo y la interfaz (28–42px), y JetBrains Mono para cΓ³digo, URLs y etiquetas tΓ©cnicas. Las tres fuentes tienen .woff2 locales: el generador nunca hace solicitudes a una CDN durante la ejecuciΓ³n.

Sora 800 Β· titular 64–172px
Estilo propio
dark premium.
Inter 400 Β· cuerpo 28–42px
El cuerpo usa Inter en peso regular o medium.
Legible en pantalla grande, sin distracciones.
JetBrains Mono Β· cΓ³digo y URLs
node build-index.mjs --vertical
🌐 inema.club
Concepto principal: ΒΏpor quΓ© fuentes locales?

Durante el renderizado con Chrome headless, la pΓ‘gina no puede hacer solicitudes externas. Si la fuente viene de un CDN, Chrome renderiza con una fuente alternativa y el video desaparece en el render. El script fetch-fonts.mjs descarga las .woff2 (subset latin) y genera assets/fonts/fonts.css con @font-face local antes de cualquier renderizado.

@font-face generado por fetch-fonts.mjs
@font-face{font-family:'Sora';font-style:normal;font-weight:700;
  font-display:block;src:url('./fonts/Sora-700.woff2') format('woff2');}
@font-face{font-family:'Sora';font-style:normal;font-weight:800;
  font-display:block;src:url('./fonts/Sora-800.woff2') format('woff2');}
@font-face{font-family:'Inter';font-style:normal;font-weight:400;
  font-display:block;src:url('./fonts/Inter-400.woff2') format('woff2');}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400;
  font-display:block;src:url('./fonts/JetBrainsMono-400.woff2') format('woff2');}
/* subset: latin β€” cobre PT-BR: Γ‘ Γ  Γ’ Γ£ Γ© Γͺ Γ­ Γ³ Γ΄ Γ΅ ΓΊ Γ§ */
Flujo: fuentes locales en el pipeline
1
node fetch-fonts.mjs β€” descarga un .woff2, genera fonts.css
2
build-index.mjs β€” inyecta readFileSync("fonts.css") en HTML
3
Chrome headless carga HTML β€” fuentes ya inline, cero CDN
βœ“
Frame renderizado con Sora perfecta β€” sin fallback
Sora
700–800 Β· tΓ­tulos
Inter
400–700 Β· cuerpo
Mono
JetBrains Β· cΓ³digo
πŸ“¦
.woff2 local
nunca CDN
3

🌌 Capa de fondo persistente

El fondo que respira: siempre presente, nunca compite.

Cada escena tiene una capa de fondo persistente marcada con data-layout-ignore. El motor de layout nunca la reubica. Contiene cuatro elementos: un glow radial Γ‘mbar que respira, un ghost text gigante que flota, una cuadrΓ­cula hairline y grano (ruido SVG). Juntos crean profundidad sin distraer.

⚠ Atención: data-layout-ignore

El atributo data-layout-ignore indica al generador que ese elemento queda en position:absolute; z-index:-1 y no forma parte del flujo del layout. Sin Γ©l, el texto fantasma o el glow desplazan el contenido real de la escena.

HTML β€” capa persistente (composition-template.mjs)
<!-- FUNDO PERSISTENTE β€” data-layout-ignore -->
<div data-layout-ignore class="bg-layer">
  <!-- glow radial Γ’mbar respirando -->
  <div class="glow-amber"></div>
  <!-- ghost text gigante driftando -->
  <div class="ghost-text">DARK</div>
  <!-- grid hairline -->
  <svg class="grid-lines" ...></svg>
  <!-- grΓ£o (SVG feTurbulence) -->
  <canvas class="grain"></canvas>
</div>
CSS β€” capa y animaciones ambientales
.bg-layer {
  position: absolute; inset: 0; z-index: -1; overflow: hidden;
}
.glow-amber {
  position: absolute; top: 40%; left: 50%;
  transform: translate(-50%, -50%);
  width: 60%; height: 40%;
  background: radial-gradient(ellipse, #FFC300 0%, transparent 70%);
  opacity: 0.06;
  animation: breathe 4s ease-in-out infinite;
}
.ghost-text {
  position: absolute; font-family: 'Sora', sans-serif;
  font-size: 172px; font-weight: 800;
  color: #F0EBD8; opacity: 0.035;
  animation: drift 8s ease-in-out infinite;
}
@keyframes breathe {
  0%,100% { opacity:.04; transform: translate(-50%,-50%) scale(1); }
  50%     { opacity:.08; transform: translate(-50%,-50%) scale(1.08); }
}
@keyframes drift {
  0%   { transform: translateX(0px) translateY(0px); }
  33%  { transform: translateX(12px) translateY(-6px); }
  66%  { transform: translateX(-8px) translateY(4px); }
  100% { transform: translateX(0px) translateY(0px); }
}
πŸ’‘ Tip β€” Opacidad de los elementos decorativos

Los elementos decorativos deben quedar entre 12–25% de opacidad. Por debajo del 12% desaparece con la compresiΓ³n H.264. Por encima del 25% compite con el contenido y parece poco profesional. El texto fantasma queda en ~3.5% (casi invisible, solo da sensaciΓ³n de profundidad).

πŸŒ…
glow Γ‘mbar
radial pulsante
DARK
ghost text
3.5% Β· a la deriva
⊞
grid hairline
profundidad
β–‘
grano
textura premium
4

πŸ’Ύ Fuentes locales .woff2

Subconjunto latin. @font-face local. Cero CDN al renderizar.

El script fetch-fonts.mjs usa el User-Agent de Chrome 131 para simular el navegador, hace una solicitud a la API de Google Fonts, filtra solo el subset latin (unicode-range U+0000-00FF cubre todo PT-BR: Γ‘ Γ  Γ’ Γ£ Γ© Γͺ Γ­ Γ³ Γ΄ Γ΅ ΓΊ Γ§), descarga los .woff2 y genera assets/fonts/fonts.css.

πŸ“Š Archivos generados por fetch-fonts.mjs
Sora
Sora-700.woff2
Sora-800.woff2
~18KB cada uno
Inter
Inter-400.woff2
Inter-500.woff2
Inter-600.woff2
Inter-700.woff2
~14KB cada uno
JetBrains Mono
JetBrainsMono-400.woff2
JetBrainsMono-600.woff2
JetBrainsMono-700.woff2
~22KB cada uno
βœ“ HACER
  • βœ“Ejecutar node fetch-fonts.mjs una vez por proyecto
  • βœ“Usar font-display:block (sin flash)
  • βœ“Hacer commit assets/fonts/ en el repositorio
  • βœ“Verificar el subset latin con unicode-range
βœ— NO HACER
  • βœ—Enlace al CDN de Google Fonts en el HTML de la escena
  • βœ—Usar font-display:swap (causa un flash en el render)
  • βœ—Descargar todos los subsets (aumenta el tamaΓ±o sin beneficiar al PT-BR)
  • βœ—Ignorar el .gitignore β€” las fuentes deben incluirse en el commit
.woff2
formato ideal
πŸ‡§πŸ‡·
subset latin
cubre PT-BR
⚑
font-display:block
sin flash
πŸ“
assets/fonts/
siempre local
5

🎬 Escala de video, no de web

8–10 elementos por escena. Titulares de 64–172px. Movimiento ambiental en todo.

El mayor error al crear videos con HTML es usar la escala web. En 1920Γ—1080 con zoom 1:1, el texto de 16px desaparece. El house style define headline mΓ­nima de 64px, cuerpo de 28–42px, y elementos decorativos con 12–25% de opacidad para crear capas sin recargar. 8–10 elementos por escena es el lΓ­mite: mΓ‘s que eso crea caos visual en la compresiΓ³n.

Escala tipogrΓ‘fica segΓΊn el contexto
16:9 Β· 1920Γ—1080
headline: 72–172px
cuerpo: 28–40px
caption: 32–36px
kicker: 20–28px
9:16 Β· 1080Γ—1920
headline: 104–118px
cuerpo: 36–42px
caption: 38–44px
kicker: 24–32px
Decorativos
opacidad: 12–25%
bordes: 2–4px
ghost text: ~3.5%
glow: 4–8%
πŸ’‘ Tip β€” Movimiento ambiental

Toda decoraciΓ³n tiene movimiento ambiental: entradas de 0.4–0.6s, eases variados, combinando transform + opacity, stagger de 0.08–0.14s entre elementos. La regla es: si es decorativo, respira. Si es contenido, aparece una vez y se detiene.

AnatomΓ­a de una escena (8–10 elementos)
z:-1 Capa de fondo: glow + ghost + grid + grain (data-layout-ignore)
z:1 Kicker/etiqueta: fuente de 20–28px, Γ‘mbar o muted, entrada de 0.8s
z:1 Titular: Sora 800, 72–172px, blanco crema, entrada 0.4s ease-out
z:1 Regla Γ‘mbar: 2–3px de alto, 0% β†’ 100% de ancho, 0.6s ease
z:1 SubtΓ­tulo: Inter 400, 28–36px, atenuado, escalonado 0.12s despuΓ©s del titular
z:2 Caption en el pie: Inter 600, fondo translΓΊcido #0D1321CC
z:2 Barra de progreso Γ‘mbar: 2px de altura en el pie, scaleX(progress)
8–10
elementos/escena
mΓ‘ximo
172px
headline max
16:9
0.4s
entrada rΓ‘pida
ease-out
25%
decorativo max
opacidad
6

🏁 La CTA de INEMA.CLUB

La ΓΊltima escena. La firma predeterminada. No la elimines jamΓ‘s.

La scene9 (última escena de todos los videos de HyperFrames) es la CTA INEMA.CLUB: texto "CONTINÚA EN" en muted, INEMA en crema (--fg), .CLUB en Ñmbar con drop-shadow glow, y 🌐 inema.club en JetBrains Mono. Es la firma del canal: todos los videos terminan igual.

CONTINÚA EN
INEMA.CLUB
🌐 inema.club
scene9() β€” composition-template.mjs (no eliminar)
function scene9() {
  return `
    <div class="cta-wrap">
      <div class="cta-pre">CONTINUA EM</div>
      <div class="cta-brand">
        <span class="cta-inema">INEMA</span>
        <span class="cta-club">.CLUB</span>
      </div>
      <div class="cta-url">🌐 inema.club</div>
    </div>`;
}

/* CSS correspondente */
.cta-pre  { font-family:'Inter'; color:var(--muted); letter-spacing:.2em; }
.cta-brand{ font-family:'Sora'; font-weight:800; font-size:clamp(72px,8vw,120px); }
.cta-inema{ color:var(--fg); }                /* INEMA β€” creme */
.cta-club { color:var(--accent);              /* .CLUB β€” Γ’mbar */
             filter:drop-shadow(0 0 16px #FFC300aa); }
.cta-url  { font-family:'JetBrains Mono'; color:var(--code); } /* 🌐 inema.club */
πŸ’‘ Tip β€” NarraciΓ³n de la CTA

La narraciΓ³n predeterminada de scene9 es: "Esto es contenido de INEMA punto CLUB. Accede: inema punto club." β€” generada con pf_dora --speed 0.98. DuraciΓ³n tΓ­pica: ~3.84s. LEAD: 0.5s, TAIL: 0.9s.

βœ“ HACER
  • βœ“Mantener scene9 como ΓΊltima escena de cada video
  • βœ“INEMA en --fg (crema), .CLUB en --accent (Γ‘mbar)
  • βœ“Resplandor de sombra paralela en .CLUB
  • βœ“URL en JetBrains Mono + cian
βœ— NO HACER
  • βœ—Eliminar u omitir scene9
  • βœ—Cambiar el color de .CLUB por otro color de la ruta
  • βœ—Usar una fuente diferente en la CTA
  • βœ—Omitir el 🌐 en la URL
INEMA
--fg crema
.CLUB
--accent + glow
🌐 inema.club
JetBrains Mono
🏁
scene9
siempre la ΓΊltima

πŸ“‹ Resumen del MΓ³dulo 3.2

QuΓ© aprendiste
  • βœ“La paleta de 8 variables CSS con funciones fijas
  • βœ“Γ‘mbar como ΓΊnico acento dominante (#FFC300)
  • βœ“Tres fuentes: Sora / Inter / JetBrains Mono con funciones distintas
  • βœ“Por quΓ© .woff2 local y nunca desde una CDN al renderizar
  • βœ“Capa de fondo persistente con data-layout-ignore
  • βœ“Escala de video: titulares de 64–172px, 8–10 elementos por escena
  • βœ“CTA INEMA.CLUB: INEMA crema + .CLUB Γ‘mbar + glow + 🌐
Referencias del mΓ³dulo
  • πŸ“„ references/house-style.md
  • πŸ“„ scripts/composition-template.mjs
  • πŸ“„ scripts/fetch-fonts.mjs
  • πŸ”‘ Regla Γ‘mbar: 1 accent. Fondo idΓ©ntico. NUNCA CDN.
PrΓ³ximo mΓ³dulo:
βš™οΈ
3.3 β€” El generador build-index.mjs
CΓ³mo el generador transforma HTML en frames y los frames en MP4.