Communitygithub.com

Scroll Zoom Reveal

Efectos cinematográficos para sitios web: zoom de desplazamiento con revelado de escena dentro de un dispositivo y campo de píxeles interactivo tipo OLED.

¿Qué es Scroll Zoom Reveal?

Esta habilidad proporciona un efecto de desplazamiento tipo 'zoom-out' de alta calidad, ideal para landing pages, portafolios y sitios de productos. La primera parte ('Scroll Zoom Reveal') ancla una escena de pantalla completa (imagen, video o render) que, al desplazarse, se aleja ('dolly') para revelar que la escena está dentro de la pantalla de una laptop o monitor, con una interfaz de aplicación simulada (paneles flotantes) que se deslizan. Luego aparece un texto con fade y una galería de pestañas con transición suave. La segunda parte ('OLED Pixel Field') añade un fondo interactivo de subpíxeles RGB que reacciona al cursor, creando un rastro brillante y cambiante de color, con ondas al hacer clic. Todo está implementado en JavaScript, CSS y WebGL vanilla, sin dependencias, y funciona en cualquier framework: HTML plano, React, Next.js, Vue, Astro. El código está listo para copiar (archivos en `assets/`) y solo requiere ajustar los tokens CSS y reemplazar el contenido demo por el propio. Incluye soporte para animaciones con scroll, vídeo sincronizado, y modo de movimiento reducido.

Compatible con~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/MaybeIceloveU2/scroll-zoom-reveal/tree/HEAD

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Vista previa

Del README del skill

Scroll Zoom Reveal preview

Documentación

¿Qué hace Scroll Zoom Reveal?

Un efecto de desplazamiento listo para usar, sin dependencias:

  1. Escena anclada a pantalla completa: un titular sobre una escena oscurecida que llena el viewport.
  2. Dolly + zoom-out: la escena se asienta ligeramente, luego la "cámara" se aleja. La escena resulta estar en la pantalla de una laptop (el bisel y la base aparecen).
  3. Revelado de la aplicación: paneles del editor (barra de herramientas, organizador, propiedades, línea de tiempo) se deslizan y la escena se encoge dentro de su panel de viewport.
  4. Texto con fade-in debajo (data-zr-fade), luego una galería de pestañas con crossfade y un indicador deslizante tipo píldora.

Todos los archivos listos para usar están en assets/ junto a este archivo:

ArchivoPropósito
assets/zoom-reveal.cssTodos los estilos (tokens de tema en .zr)
assets/zoom-reveal.jsComponente + fades + galería. Expone window.ZoomReveal, auto-inicia [data-zoom-reveal] / [data-zr-gallery] / [data-zr-fade]
assets/oled-field.jsOpcional. Campo OLED de subpíxeles reactivo al cursor (window.OledField, auto-inicia [data-zr-oled]). Los estilos están en zoom-reveal.css
assets/placeholder-scenes.jsOpcional. Pinta proceduralmente arte de placeholder original en canvas (ZRScenes.drawCity, ZRScenes.drawCanyon) hasta que existan imágenes reales
assets/demo.htmlPágina completa funcional. Empieza desde este marcado.

Cómo usarlo en un sitio

  1. Copia los assets en el proyecto (ej. public/zoom-reveal/ o src/vendor/zoom-reveal/). Copia placeholder-scenes.js solo si aún no hay arte real.
  2. Lee assets/demo.html y copia el bloque <section class="zr" data-zoom-reveal>…</section> (más el bloque de galería si se desea). Mantén la estructura de clases exactamente:
section.zr[data-zoom-reveal]          ← aquí vive la longitud de scroll (--zr-length)
  .zr-sticky                          ← escenario anclado de 100vh
    .zr-glow                          (brillo ambiental opcional)
    .zr-device                        ← escalado por JS
      .zr-lid > .zr-display
        .zr-viewport > .zr-media > img | video | canvas   ← TU ESCENA
        .zr-chrome > .zr-panel.zr-toolbar / .zr-left / .zr-right / .zr-bottom  (interfaz de aplicación opcional)
      .zr-base                        (base de laptop; eliminar para monitor/tableta)
    .zr-scrim + header.zr-intro       ← titular sobre la escena, se desvanece primero
    .zr-caption                       ← leyenda pequeña, aparece al final
  1. Carga zoom-reveal.css en <head> y zoom-reveal.js al final de <body>.
  2. Cambia el contenido multimedia: reemplaza el canvas de demostración por la escena real:
    • Imagen: <img src="scene.avif" alt="" decoding="async">. Expórtala al menos al tamaño del viewport × DPR (2560–3200px de ancho). El efecto comienza con la imagen llenando toda la pantalla.
    • Video sincronizado con scroll: <video data-zr-scrub muted playsinline preload="auto" src="scene.mp4"></video>. JS mapea el progreso del scroll a currentTime. Codifica con cada cuadro como keyframe para que la búsqueda sea suave: ffmpeg -i in.mov -c:v libx264 -g 1 -crf 22 -an -movflags +faststart scene.mp4.
  3. Reescribe todo el texto (ceja, titular, leyenda, etiquetas de panel, nombre de archivo, etiquetas de galería) para que se ajusten al sitio. Nunca envíes el texto ficticio "Orbit / Forge" de la demo.
  4. Personaliza con los tokens en .zr: --zr-bg, --zr-fg, --zr-muted, --zr-accent, --zr-length (distancia de scroll, por defecto 360vh).

Opciones

Pasa JSON en el atributo, ej. data-zoom-reveal='{"maxWidth":1000,"viewport":{"top":0,"right":0,"bottom":0,"left":0}}', o constrúyelo en JS: new ZoomReveal(el, options).

OpciónPor defectoSignificado
maxWidth1180Ancho máximo final de la pantalla (px)
widthRatio / heightRatio0.82 / 0.64Tamaño final de la pantalla en relación al viewport
aspect0.625Alto ÷ ancho de la pantalla (16:10). Teléfono ≈ 2.16, ultraancho ≈ 0.42
overscan1.04Cuánto más allá del viewport comienza la pantalla (oculta el bisel)
dolly1.14Zoom interno inicial del contenido multimedia; se asienta a 1
lift0.035Cuánto se eleva el dispositivo al final
timelinever JSVentanas de progreso [inicio,fin] para intro, dolly, zoom, chrome, caption
viewport{top:6.5,right:21,bottom:22,left:15}Insets finales (% de la pantalla) del panel de escena dentro de la interfaz de la app. Pon todos a 0 y elimina .zr-chrome para un zoom-out puro de "escena → pantalla de dispositivo" sin interfaz de app
onProgress—fn(p) callback con progreso 0..1

Eventos: la sección despacha zr:resize con {width, height, finalWidth}, el tamaño en píxeles con el que se muestra el contenido multimedia. Úsalo para dimensionar canvases o elegir una fuente de imagen.

React / Next.js

Importa el CSS globalmente. Elimina data-zoom-reveal del marcado y constrúyelo manualmente para que esté vinculado al ciclo de vida del componente ('use client' en Next):

useEffect(() => {
  import('./zoom-reveal/zoom-reveal.js').then(() => {  // registra window.ZoomReveal
    const zr = new window.ZoomReveal(ref.current, { maxWidth: 1100 });
    const gal = galRef.current && new window.ZoomReveal.Gallery(galRef.current);
    window.ZoomReveal.initFades();
    cleanup = () => zr.destroy();
  });
  let cleanup = () => {};
  return () => cleanup();
}, []);

Convierte class → className y style="--v:78%" → style={{'--v':'78%'}}.

Campo OLED de píxeles (efecto hover del cursor)

Un fondo a pantalla completa de pequeñas barras de subpíxeles RGB, tenuemente iluminadas. Mover el cursor agita una pequeña simulación de fluido. Los píxeles en la trayectoria se iluminan, crecen y cambian de color de violeta a cian a lima a blanco cálido, luego el resplandor se desplaza en la dirección del cursor, se extiende y se desvanece. Un clic o toque envía una onda expansiva. Cuando el cursor está inactivo (y en pantallas táctiles), un "cursor fantasma" lento lo mantiene vivo. El renderizado es un fragment shader WebGL1, la simulación es una pequeña rejilla en CPU, y solo se ejecuta mientras la sección está en pantalla. Sin WebGL, cae en un spotlight CSS.

Úsalo detrás de un bloque de especificaciones/estadísticas, un héroe o una banda CTA. Cualquier elemento funciona: añade class="zr-oled" data-zr-oled, pon contenido dentro, carga zoom-reveal.css + oled-field.js. El componente inserta el canvas por sí mismo. Consulta el bloque "OLED PIXEL FIELD" en assets/demo.html.

<section class="zr-oled" data-zr-oled='{"cell":7}'>
  <div class="your-content">…estadísticas / titular…</div>
</section>
<script src="oled-field.js"></script>
OpciónPor defectoSignificado
cell6Píxeles CSS por píxel (3 barras de subpíxeles). 5–9 se ve bien; usa más grande en móvil para rendimiento
radius2.4Radio del pincel en celdas
strength0.55Cuánta luz añade el cursor. Los valores por defecto son deliberadamente sutiles; 1 es audaz
decay0.94Desvanecimiento por fotograma; más alto = estelas más largas (0.92 corto … 0.97 largo)
flow0.55Cuánto se desplaza el resplandor a lo largo de la dirección del cursor
diffusion0.35Qué tan rápido se extiende el resplandor
base0.09Brillo de la cuadrícula sin iluminar
palette['#5a3cff','#1fd6ff','#b6ff4a','#fff4d8']4 colores, baja → alta energía. Combina con la marca, ej. cálido ['#ff3c5a','#ff9a1f','#ffe14a','#fff8e8']
ambient / ripplestrueCursor fantasma mientras inactivo / onda al hacer clic

Para un aspecto más audaz (más cercano a un efecto de exhibición) usa {"radius":3.2,"strength":1,"decay":0.962,"flow":0.9}. Mantén los valores por defecto sutiles detrás de secciones con mucho texto.

API: const f = new OledField(el, opts), f.pulse(clientX, clientY) (disparar una onda desde código), f.destroy() (llamar en la limpieza de React). Dale al texto sobre el campo una suave text-shadow oscura para que siga siendo legible sobre las estelas brillantes.

Errores comunes (verifica antes de terminar)

  • El sticky se rompe si algún ancestro de .zr tiene overflow: hidden/auto/clip o un transform. Usa overflow-x: clip en body si el desbordamiento horizontal debe ocultarse.
  • No envuelvas .zr en librerías de scroll suave que transformen la página (Locomotive v4 etc.). Lenis está bien.
  • El dispositivo se coloca grande y se escala hacia abajo, por lo que el contenido multimedia permanece nítido. No pongas tamaños fijos en px dentro de .zr-device: usa em (1em = 1% del ancho de la pantalla).
  • Movimiento reducido está manejado: la sección se desancla y muestra el estado final; la galería deja de reproducirse automáticamente; el campo OLED sigue reaccionando al cursor pero elimina el cursor fantasma y las ondas.
  • Las animaciones se pausan en pestañas en segundo plano (requestAnimationFrame se detiene). Al probar el campo OLED en un panel del navegador, mantén la página visible o parecerá congelada.
  • Por debajo de ~500px de ancho la laptop es pequeña. Considera {"widthRatio":0.92} o aspect ajustado a un marco de teléfono en móvil.
  • Prueba desplazándote lentamente de arriba a abajo en el navegador en anchos de escritorio y móvil. Confirma que el titular se desvanezca antes de que comience el zoom-out, que no aparezca bisel al inicio y que la leyenda no se superponga a la base.
  • Usa arte y texto originales o con licencia. Esto recrea la técnica de movimiento; no copies imágenes, renders de productos o texto de otra marca.

Skills relacionados