Página de Aterrizaje Cinemática con Scrub de Ratón — La Plantilla Dorada
Construye una landing page premium y consciente de la marca donde el video héroe responda al ratón y el resto de la página guíe al espectador a través de un arco narrativo de 5 tiempos. El usuario proporciona un video, opcionalmente un logotipo + foto del producto + contexto de marca — esta habilidad se encarga de la extracción de paleta, selección tipográfica, RTL/LTR, andamiaje, la recodificación de video con todos los fotogramas clave, el efecto de scrub con el ratón, la biblioteca de secciones y la verificación.
Por qué existe esta habilidad
La implementación de referencia vive en https://github.com/hoodini/bamba — un sitio RTL israelí para el snack "במבה" (Bamba) donde un video de un bebé sigue el cursor a lo largo de toda la página mientras 4 secciones distintas debajo (receta amarilla brillante, álbum de nostalgia crema, precios oscuros contemplativos, final rojo de acción) guían al espectador a través de anhelo → alegría → nostalgia → contemplación → acción.

Cada regla en esta habilidad fue extraída de esa construcción. Los puntos en la sección de reglas estrictas son TODOS ganados con esfuerzo — anulan los valores predeterminados genéricos de "buen código".
Galería de secciones (lo que estás construyendo)
El héroe permanece en la parte superior. Debajo, elige 4 secciones de la biblioteca, ordenadas para seguir el arco narrativo. Cada una es completamente opaca (sin que el video se trasluzca) y tiene su propia identidad de marca:
| Tiempo | Tipo | Referencia |
|---|---|---|
| 1 — Anhelo | Héroe (video con scrub de ratón) | ![]() |
| 2 — Alegría | Sol — degradado brillante de acento primario, SVGs de motivos flotantes, tipografía fantasma gigante, tarjetas de estadísticas | ![]() |
| 3 — Nostalgia | Álbum — papel crema, micropatrón punteado, bento polaroid con foto real del producto | ![]() |
| 4 — Contemplación | Tostado — oscuro con brillos de acento radial, tres tarjetas de precios cada una con tratamiento visual DIFERENTE | ![]() |
| 5 — Acción | Señal — acento fuerte a sangre completa (rojo/naranja/verde), titular masivo + CTA, panel contenido en vidrio | ![]() |
Para marcas técnicas/SaaS, intercambia los tipos de sección según sea necesario (consulta la biblioteca de secciones más abajo) — pero siempre termina con una sección de Señal.
Cómo usar esta habilidad
-
Coloca los activos en un directorio de trabajo limpio:
- Video héroe (cualquier contenedor —
.mp4,.mov,.webm) - Logotipo (SVG muy preferido; PNG con transparencia aceptable)
- 1-3 imágenes del producto/tema (JPG/PNG, idealmente con transparencia)
- Video héroe (cualquier contenedor —
-
Confirma con el usuario (brevemente — propón valores predeterminados, continúa):
- Nombre del producto + meta-eslogan
- Código de idioma (determina RTL/LTR + elección de fuente)
- Contexto de marca — época, audiencia, núcleo emocional, sensación de paleta
- Opcional: códigos hex de paleta explícitos, tiempos del arco narrativo
-
Ejecuta el flujo de trabajo a continuación en orden. Todas las fases son obligatorias. No omitas la recodificación con ffmpeg — esa es la magia que hace que el scrub se sienta suave.
-
Verifica antes de reportar como completado. La Fase 9 tiene 12 comprobaciones. Ejecútalas todas.
ENTRADAS — recopila estas del usuario
PRODUCT_NAME: "<ej. במבה / Bamba / Hope the Cheetah / Acme CRM>"
TAGLINE: "<el meta-mensaje — ej. 'no es un snack, son recuerdos de por vida'>"
LANGUAGE: "<he | en | ar | es | fr | ja | ...>"
IS_RTL: "<true | false>" # he/ar/fa = true; todo lo demás = false
HERO_VIDEO_FILE: "<nombre exacto del archivo en cwd — ej. baby2.mp4>"
LOGO_FILE: "<nombre exacto del archivo — deja en blanco si no hay>"
PRODUCT_IMAGE_FILE: "<nombre exacto del archivo — deja en blanco si no hay>"
BRAND_CONTEXT: |
<2-4 oraciones: la época que evoca, quién es la audiencia, el núcleo emocional,
la identidad visual (cálida/fría/juguetona/seria). Determina la paleta y los motivos.>
PALETTE: "<opcional — códigos hex separados por comas para sobrescribir>"
NARRATIVE_ARC: "<opcional — 5 tiempos emocionales; la IA propone si está en blanco>"
La plantilla de texto completa (con el mismo bloque YAML y cuerpo del prompt) está en references/GOLDEN_PROMPT.md — pégala en Claude con el YAML completado cuando no tengas acceso directo a la habilidad.
Fase 0 — Planifica el diseño (genera un resumen de ≤200 palabras antes de codificar)
Antes de escribir cualquier código, genera:
-
Paleta de 5 colores extraída:
background(tinta más profunda),cream(texto cálido off-white — NUNCA#FFFFFF),accent(color primario de la marca),accent2(color secundario de la marca),support(tono terciario). Extrae del logotipo + imagen del producto si no se proporcionóPALETTE. La paleta debe ser internamente cohesiva — todo cálido O todo frío, nunca mezclado. Marcas cálidas (comida, naturaleza, nostalgia, animales) → sin azules, teales, mentas, cianes. Marcas frías (tecnología, finanzas, médico, ciencia ficción) → sin tonos cálidos excepto un pequeño acento. -
Tríada tipográfica (display / cuerpo / acento manuscrito) para el idioma:
he: Rubik (display) + Assistant (cuerpo) + Suez One (acento)en: Anton (display) + Inter (cuerpo) + Caveat (acento)ar: Cairo (display) + Tajawal (cuerpo) + Reem Kufi (acento)es/fr/it/de: Anton o Bebas Neue (display) + Inter (cuerpo) + Caveat (acento)ja: Noto Sans JP weight 900 (display) + Noto Sans JP (cuerpo) + Yusei Magic (acento)- Otros: elige tres Google Fonts que coincidan con el script, con los mismos roles
display-negro / cuerpo-limpio / acento-manuscrito.
-
Arco narrativo — 5 tiempos emocionales que se asignen a
BRAND_CONTEXT. Empareja cada uno con un tipo de sección de la biblioteca de secciones.
Luego ejecuta — no pidas confirmación.
Fase 1 — Preparación de activos (el paso mágico)
1a. Verifica ffmpeg
which ffmpeg # o: Get-Command ffmpeg en PowerShell
Si está ausente, detente y dile al usuario que lo instale (brew install ffmpeg / Windows: http://ffmpeg.org).
1b. Recodifica el video héroe con cada fotograma como un fotograma clave
Los navegadores solo pueden buscar instantáneamente a fotogramas clave — el video estándar tiene ~1 fotograma clave por cada 250 fotogramas, lo que hace que el scrub con el ratón sea terriblemente entrecortado. Este único comando es la diferencia entre premium y amateur:
ffmpeg -y -i <HERO_VIDEO_FILE> -g 1 -keyint_min 1 -c:v libx264 -preset slow -crf 20 -pix_fmt yuv420p -an hero.mp4
Verifica la salida: hero.mp4 debe tener entre 5-50 MB. Si > 50 MB, vuelve a ejecutar con -crf 25; si > 80 MB con -crf 28. Elimina el audio (-an) — el héroe es silencioso.
1c. Copia el logotipo + la imagen del producto
cp <LOGO_FILE> public/logo.<ext>
cp <PRODUCT_IMAGE_FILE> public/product.<ext> # si se proporcionó
Fase 2 — Andamiaje
npm create vite@latest site -- --template react-ts
cd site
npm install
npm install lucide-react
npm install -D tailwindcss@3 postcss autoprefixer
npx tailwindcss init -p
mkdir -p public
mv ../hero.mp4 public/hero.mp4
# También mueve el logotipo y la imagen del producto a public/
Fase 3 — Configuración de Tailwind
Reemplaza tailwind.config.js por completo. Usa la paleta extraída y las fuentes apropiadas para el idioma:
/** @type {import('tailwindcss').Config} */
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
colors: {
background: '<tinta/oscuro>',
cream: '<off-white cálido — NUNCA #FFFFFF>',
accent: '<color primario de la marca>',
accent2: '<secundario>',
support: '<terciario>',
},
fontFamily: {
sans: ['<fuente del cuerpo>', 'system-ui', 'sans-serif'],
display: ['<fuente de display>', 'sans-serif'],
accent: ['"<fuente manuscrita>"', 'cursive'],
},
},
},
plugins: [],
}
Fase 4 — index.html
Reemplázalo por completo. Respeta IS_RTL. Siempre incluye el enlace del favicon que apunte al logotipo:
<!DOCTYPE html>
<html lang="<LANGUAGE>" dir="<rtl|ltr>">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
<link rel="apple-touch-icon" href="/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="<URL de Google Fonts para las tres fuentes elegidas>" rel="stylesheet">
<title><PRODUCT_NAME> — <TAGLINE></title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Fase 5 — index.css (el sistema de diseño)
Reemplázalo por completo. Cada utilidad a continuación es estructural. Los nombres asumen la paleta cálida extraída anteriormente; para una marca fría, intercambia las menciones de "amarillo"/"rojo" en los tintes de sombra por los colores de acento reales.
Debe incluir:
html { scroll-behavior: smooth; }+section[id] { scroll-margin-top: 90px; }para que las secciones ancladas no aterricen bajo la navegación fija.bodybackground = colorbackground(fallback si el video falla). Cursor =crosshair. Fuente predeterminada = body sans..liquid-glass/.liquid-glass-strong— backdrop-blur + saturate + borde de luz interior + máscara de degradado de borde resaltado. La variante Strong usa un brillo interior teñido conaccent..glass-pill— píldora redondeada compacta con el mismo tratamiento de vidrio para elementos de navegación e insignias pequeñas..cta-primary— CTA de marca:linear-gradient(135deg, accent-light, accent, accent-shade)+ sombra brillante de color de acento que se intensifica al pasar el ratón + elevacióntranslateY(-1px)..brand-mark— cuadrado/círculo pequeño para marcas de logotipo pequeñas si no se proporciona un SVG..grid-bg— cuadrícula sutil de 1px con máscara de desvanecimiento radial, utilizada bajo secciones oscuras..reveal/.revealed— revelación de desplazamiento con IntersectionObserver:opacity 0 → 1+translateY 28 → 0durante 0.9s concubic-bezier(0.16, 1, 0.3, 1)..scrim-top/.scrim-bottom— superposiciones degradadas solo para el héroe.- Fondos por sección, nombrados por sensación no por color:
.sun-section— degradado brillante de acento primario + textura punteada sutil (el tiempo "alegría / abrir la bolsa")..album-section— papel off-white cálido, tintes de acento radiales + micropatrón punteado, desvanecimiento de máscara de borde..roast-section— oscuro con brillos de acento radial + acento2 en esquinas opuestas + textura de cuadrícula enmascarada..signal-section— acento fuerte a sangre completa (a menudo rojo/naranja/verde) para el final de acción.
.polaroid— tarjeta blanca, relleno14px 14px 44px 14px, sombra suave en capas, elevación al pasar el ratón atranslateY(-6px) rotate(0)..polaroid-tape= tira de cinta amarilla/acento posicionada absolutamente en el centro superior, rotada -4°, con pistas laterales discontinuas..stamp— píldora de borde discontinuo en color de acento, mayúsculas, espaciado de letras0.18em..ribbon— insignia de precios/popular conclip-pathtriángulo inferior, sombra oscura..highlight-circle— óvalo de sensación dibujado a mano a través de::after: borde de color de acento rotado 3px alrededor de un<span>en línea. Úsalo alrededor de la palabra más importante en encabezados grandes (uno por encabezado como máximo).- Filtro de motivo decorativo:
.peanut-svg/.<motif>-svgcondrop-shadow. - Respeta
prefers-reduced-motion: reduce— desactiva la animación de revelado + el desplazamiento suave dentro de la consulta de medios.
Fase 6 — Arquitectura de App.tsx
La arquitectura no es negociable. Hazlo bien la primera vez:
6a. Importaciones
import { useEffect, useRef, useState } from 'react';
import {
Menu, X, ArrowLeft, ArrowRight, ArrowDown, ArrowUp, MousePointer2,
// …además de 4-8 iconos temáticos de marca (Heart, Sparkles, Cookie, PawPrint, Cpu, Leaf, …)
} from 'lucide-react';
6b. Componentes reutilizables definidos dentro de App.tsx
useReveal<T>()— hook de IntersectionObserver que devuelve una ref; añade la claserevealeden la primera intersección (umbral 0.15).GlassCard— envoltorio con el hook de revelado, propstrongopcional, acepta className.Motif— un solo componente SVG decorativo temático paraBRAND_CONTEXT(maní para comida, pata para animales, circuito para tecnología, hoja para naturaleza, gota para bebida, rayo para energía). Flota con baja opacidad en 3-6 lugares por sección oscura/brillante.ScrollToTopButton— fijobottom-6 left-6en RTL /bottom-6 right-6en LTR. Aparece cuandowindow.scrollY > window.innerHeight * 0.6. Desplazamiento suave al inicio. Etiqueta corta apropiada para el idioma ("לראש" / "Top" / "أعلى" / "Inicio").
6c. Efecto de scrub con el ratón (el corazón)
const videoRef = useRef<HTMLVideoElement>(null);
const stateRef = useRef({ targetTime: 0, isSeeking: false });
useEffect(() => {
const video = videoRef.current;
if (!video) return;
const handleLoaded = () => {
const mid = video.duration / 2;
video.currentTime = mid;
stateRef.current.targetTime = mid;
};
const handleSeeked = () => {
const s = stateRef.current;
s.isSeeking = false;
if (Math.abs(s.targetTime - video.currentTime) > 0.01) {
s.isSeeking = true;
video.currentTime = s.targetTime;
}
};
const handleMouseMove = (e: MouseEvent) => {
const s = stateRef.current;
const d = video.duration;
if (!d || isNaN(d)) return;
const normalized = e.clientX / window.innerWidth;
// Si el sujeto se mueve "hacia atrás" en relación al cursor y se siente mal, opcionalmente
// usa `1 - (e.clientX / window.innerWidth)` en su lugar — PREGUNTA primero al usuario.
s.targetTime = Math.max(0, Math.min(d, normalized * d));
if (!s.isSeeking) { s.isSeeking = true; video.currentTime = s.targetTime; }
};
video.addEventListener('loadedmetadata', handleLoaded);
video.addEventListener('seeked', handleSeeked);
window.addEventListener('mousemove', handleMouseMove);
return () => {
video.removeEventListener('loadedmetadata', handleLoaded);
video.removeEventListener('seeked', handleSeeked);
window.removeEventListener('mousemove', handleMouseMove);
};
}, []);
El guardia isSeeking es crítico — sin él, el mousemove se dispara más rápido de lo que el navegador puede decodificar y obtienes un desbordamiento de la cola de búsqueda + parpadeo visible.
6d. Navegación clickeable con scroll-spy
const navItems: { label: string; target: string }[] = [
{ label: '<demo>', target: 'top' },
{ label: '<recipe>', target: '' },
...








