Retour au catalogue

Product Showcase Exploded

Vue eclatee d'un produit : plusieurs couches se separent au scroll (translateY/X differents). Au repos, tout est assemble.

product-showcasecomplex Both Responsive a11y
boldcorporatesaasecommerceuniversalcentered
Theme

Cómo crear una vista de producto explosionada al hacer scroll en React

Una vista explosionada guiada por scroll apila las capas del producto en posición absoluta y las separa a medida que el usuario hace scroll, usando useScroll de Framer Motion para leer el progreso y useTransform para convertir ese progreso en valores de translateY, translateX y rotateX propios de cada capa. Cada capa obtiene sus propios motion values derivados de su distancia respecto al índice central.

  • Stack: React 19 + Framer Motion 11 + custom properties CSS, ~200 líneas, cero dependencias de iconos.
  • API clave: useScroll (target + offset), useTransform, perspectiva 3D en el contenedor.
  • Accesible: la etiqueta de cada capa es texto legible; la animación es decorativa y no oculta ningún contenido.
  • Responsive: centrado con maxWidth 500px; funciona en móvil (el scroll está disponible en todas partes, a diferencia de los eventos de puntero).
  • Acepta de 3 a 5 capas; menos de 3 debilita el efecto, más de 5 genera solapamientos confusos.

Product Showcase Exploded es una sección guiada por scroll que revela la arquitectura de un producto separando sus capas visuales a medida que el usuario se desplaza. En reposo, todas las capas están apiladas al ras; conforme avanza el progreso del scroll, se despliegan vertical y lateralmente con una ligera inclinación 3D, el tipo de revelación que convierte un texto de "confía en nosotros" en un diagrama concreto y explorable.

Anatomía

Un header centrado (badge, h2, descripción) aparece en fundido al entrar por primera vez en el viewport mediante una motion.div whileInView. Debajo se sitúa un contenedor de 500px con perspective:1200px definida directamente en el prop style. Cada capa es una motion.div posicionada en absoluto (la primera en relative para establecer la altura del contenedor) que contiene una tarjeta con ratio 5:3 con fondo semitransparente, borde y etiqueta centrada. Un breve párrafo indicando el scroll aparece bajo la pila.

Cómo funciona

El elemento section se pasa como target a useScroll con el offset ["start 0.7", "end 0.3"], de modo que la animación se ejecuta mientras la sección ocupa el 60% central del viewport. Para cada capa, el código calcula un offset: el índice de la capa menos el índice central del array. Ese offset se usa luego para escalar las salidas de useTransform: las capas por encima del centro se desplazan hacia arriba y a la izquierda, las que están por debajo se desplazan hacia abajo y a la derecha. rotateX pasa de 0 a -8 grados en la primera mitad del scroll, dando a toda la pila una sutil inclinación hacia delante. La opacidad empieza en 0.6 antes de la ventana de scroll, sube a 1 durante, y vuelve a 0.8 al final.

Cómo crearlo en React

  1. Configura el observador de scroll en la sección

    Asocia un ref a tu elemento section y pásalo a useScroll. El array offset controla cuándo se abre y se cierra la ventana de animación: "start 0.7" significa que la animación empieza cuando la parte superior de la sección alcanza el 70% desde el borde superior del viewport.

    const sectionRef = useRef<HTMLElement>(null);
    const { scrollYProgress } = useScroll({
      target: sectionRef,
      offset: ["start 0.7", "end 0.3"],
    });
  2. Calcula los motion values por capa a partir del índice central

    Dentro del map, deriva un offset a partir de la distancia de la capa respecto al centro del array. Multiplica ese offset por la distancia de separación deseada para obtener los rangos de translateY y translateX. Cada llamada a useTransform produce un motion value independiente al que Framer Motion se suscribe directamente, sin re-renders al hacer scroll.

    const centerIndex = (totalLayers - 1) / 2;
    const offset = i - centerIndex;
    
    const translateY = useTransform(
      scrollYProgress,
      [0, 0.5, 1],
      [0, offset * 80, offset * 120],
    );
    const translateX = useTransform(
      scrollYProgress,
      [0, 0.5, 1],
      [0, offset * 15, offset * 25],
    );
  3. Añade una inclinación 3D con rotateX y perspective

    Define perspective:1200px en el div contenedor (no en las propias motion.div) para que todas las capas compartan el mismo espacio 3D. Proyecta scrollYProgress de 0 a 0.5 sobre valores de rotateX de 0 a -8 grados. La dirección negativa inclina la parte superior de la pila hacia el espectador.

    const rotateX = useTransform(
      scrollYProgress,
      [0, 0.5],
      [0, -8],
    );
    
    // On the container:
    <div style={{ perspective: "1200px" }}>
  4. Posiciona las capas en absoluto, la primera en relative

    Define position:'relative' en la primera capa para que el contenedor tome su altura, y position:'absolute', top:0, left:0, right:0 en todas las capas siguientes. Así todas las capas empiezan apiladas al ras y el contenedor no colapsa. Asigna zIndex como totalLayers - i para que la primera capa quede por encima.

    position: i === 0 ? "relative" : "absolute",
    top: 0,
    left: 0,
    right: 0,
    zIndex: totalLayers - i,

Cuándo usarlo

Recurre a este patrón cuando un producto tiene capas técnicas claramente diferenciadas que merece la pena nombrar: plataformas SaaS (UI, API, infra), productos hardware (carcasa, PCB, matriz de sensores) u herramientas de diseño (motor de render, capa de plugins, canvas). Funciona mejor en una sección de "cómo funciona" o "tecnología" situada de la parte inicial a la media de la página. Evítalo en páginas de marketing sencillas donde la complejidad es un lastre, y no lo coloques nunca justo antes o después de un footer o un formulario de auth: el efecto necesita espacio y un lector ya involucrado con el producto.

Usado por

  • Stripe, Usa ilustraciones de tarjetas apiladas por capas que se separan para revelar la arquitectura del flujo de pago en sus páginas de producto.
  • Linear, Emplea revelaciones de capas guiadas por scroll para mostrar la estructura de su motor de gestión de proyectos.
  • Apple, Las páginas de producto de Mac Pro y iPhone usan animaciones de capas de hardware explosionadas para comunicar la profundidad de su ingeniería.
  • Vercel, Los diagramas de infraestructura de la página de plataforma se separan en capas distintas (Edge Network, Functions, Build) a medida que el usuario hace scroll.

FAQ

¿Por qué llamar a useTransform dentro del bucle map en lugar de calcular los valores fuera?

Cada capa necesita su propio motion value independiente: useTransform crea un valor derivado al que Framer Motion se suscribe directamente sin provocar re-renders de React. Llamarlo por capa dentro del map es intencionado; las violaciones de las rules of hooks no aplican aquí porque la longitud del array de capas es fija en el momento del render.

¿Cómo controlo la distancia de separación entre las capas?

La separación se controla con el multiplicador de los arrays de salida de useTransform: offset * 80 para la Y a mitad del scroll y offset * 120 para la Y al final del scroll. Aumenta esos números para separar más las capas, redúcelos para una separación más sutil. Los multiplicadores de X (15 y 25) añaden una ligera diagonal que evita que las capas parezcan una pila plana.

¿Funciona esto sin Framer Motion?

Puedes replicar la lectura del scroll con un simple listener del evento scroll y custom properties CSS, pero pierdes el scheduling rAF optimizado y la mutación directa del DOM de Framer Motion. La diferencia se nota a 60fps en dispositivos de gama baja: quédate con Framer Motion o considera la Web Animations API como alternativa más ligera.

¿Cuál es el número mínimo de capas para que el efecto sea legible?

Tres capas es el mínimo práctico. Con dos, la separación parece un simple deslizamiento en lugar de una revelación estructural. Cuatro es el punto ideal para la mayoría de productos; cinco funciona para análisis técnicos en profundidad pero exige una diferenciación de color cuidada entre capas adyacentes para que no se fundan visualmente al apilarse.

"use client";

import { useRef } from "react";
import { motion, useScroll, useTransform } from "framer-motion";

interface Layer {
  label: string;
  color: string;
}

interface ProductShowcaseExplodedProps {
  badge?: string;
  title?: string;
  description?: string;
  layers?: Layer[];
}

const EASE = [0.16, 1, 0.3, 1] as const;

export default function ProductShowcaseExploded({
  badge = "Technologie",
  title = "Anatomie du produit",

Code complet réservé à Pro

Code source intégral, export multi-framework et playground.

Passer en Pro, 9,99€/mois

Autres variantes product-showcase

Reseñas

Vista explosionada scroll React, Capas Framer Motion