CoreReveals and Continuous Motionmotion/react

ParallaxDepthScene

Multilevel spatial composition where background, midground, and foreground planes translate at proportional depth intensities in response to pointer or scroll offsets.

Preview

Z-PLANE // FOREGROUND (1.0x)

Tri-Plane Depth Composition

Customize

4 props
22
22

Installation

Copies the component source and its CSS Module into your project.

npx motionfoundry add parallax-depth-scene

Writes components/ui/parallax-depth-scene.tsx and components/styles/parallax-depth-scene.module.css.

Usage

Updates live as you change the controls — only props that differ from the defaults are included.

example.tsx
1import { ParallaxDepthScene } from "@motionfoundry/ui";2 3export function Example() {4  return (5    <ParallaxDepthScene />6  );7}

Props

PropTypeDefault
title

Foreground layer label.

string'Tri-Plane Depth Composition'
depthMultiplier

Maximum pixel translation of the foreground plane.

number22
damping

Spring damping constant across depth planes.

number22
showGridLayer

Toggle the deep background wireframe grid plane.

booleantrue

Accessibility

Automatically dampens motion on touch/small viewports and disables layer displacement when prefers-reduced-motion is active.

Toggle prefers-reduced-motion in your OS or browser devtools (Rendering → Emulate CSS media feature) to verify the reduced-motion state.

Source

components/ui/parallax-depth-scene.tsx
1"use client";2 3import * as React from "react";4import { motion, useMotionValue, useSpring, useTransform, useReducedMotion } from "motion/react";5import styles from "../styles/parallax-depth-scene.module.css";6 7export interface ParallaxDepthSceneProps {8  /** Foreground card title */9  title?: string;10  /** Maximum translation in pixels */11  depthMultiplier?: number;12  /** Spring damping */13  damping?: number;14  /** Render deep background grid layer */15  showGridLayer?: boolean;16  /** Optional className */17  className?: string;18}19 20export function ParallaxDepthScene({21  title = "Tri-Plane Depth Composition",22  depthMultiplier = 22,23  damping = 22,24  showGridLayer = true,25  className = "",26}: ParallaxDepthSceneProps) {27  const prefersReducedMotion = useReducedMotion();28  const normX = useMotionValue(0);29  const normY = useMotionValue(0);30 31  const smoothX = useSpring(normX, { stiffness: 200, damping });32  const smoothY = useSpring(normY, { stiffness: 200, damping });33 34  const bgX = useTransform(smoothX, (v) => v * -depthMultiplier * 0.4);35  const bgY = useTransform(smoothY, (v) => v * -depthMultiplier * 0.4);36  const midX = useTransform(smoothX, (v) => v * depthMultiplier * 0.65);37  const midY = useTransform(smoothY, (v) => v * depthMultiplier * 0.65);38  const fgX = useTransform(smoothX, (v) => v * depthMultiplier);39  const fgY = useTransform(smoothY, (v) => v * depthMultiplier);40 41  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {42    if (prefersReducedMotion || e.pointerType === "touch") return;43    const rect = e.currentTarget.getBoundingClientRect();44    const nx = (e.clientX - rect.left) / rect.width - 0.5;45    const ny = (e.clientY - rect.top) / rect.height - 0.5;46    normX.set(nx * 2);47    normY.set(ny * 2);48  };49 50  const handlePointerLeave = () => {51    normX.set(0);52    normY.set(0);53  };54 55  return (56    <div57      onPointerMove={handlePointerMove}58      onPointerLeave={handlePointerLeave}59      className={`${styles.scene} ${className}`.trim()}60    >61      {showGridLayer && (62        <motion.div63          aria-hidden="true"64          style={{ x: prefersReducedMotion ? 0 : bgX, y: prefersReducedMotion ? 0 : bgY }}65          className={styles.bgLayer}66        />67      )}68      <motion.div69        aria-hidden="true"70        style={{ x: prefersReducedMotion ? 0 : midX, y: prefersReducedMotion ? 0 : midY }}71        className={styles.midLayer}72      >73        <span className={styles.planeLabel}>Z-PLANE // MIDGROUND (0.65x)</span>74      </motion.div>75      <motion.div76        style={{ x: prefersReducedMotion ? 0 : fgX, y: prefersReducedMotion ? 0 : fgY }}77        className={styles.fgLayer}78      >79        <span className={styles.planeLabel}>Z-PLANE // FOREGROUND (1.0x)</span>80        <h4 className={styles.title}>{title}</h4>81      </motion.div>82    </div>83  );84}