Skip to content

Latest commit

 

History

14 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Z-Scroll

A Next.js project that simulates 3D scrolling through depth (the Z-axis) using pure mathematics - no 3D engines, no Three.js, no WebGL. Just mathematical transformations applied to 2D elements to create the illusion of moving through space.

Next.js React TypeScript

Test it Yourself => https://z-scroll.vercel.app/

Recording.2025-12-08.170932.mp4

Overview

This project demonstrates how to create a convincing 3D depth-scrolling effect by manipulating 2D elements with mathematical formulas. Instead of scrolling vertically or horizontally, users scroll "through the screen" - moving forward and backward through layers of content positioned at different depths.

How It Works

The entire effect relies on mathematical transformations applied to CSS properties. Here's the breakdown:

1. Depth Positioning

Each element is assigned a z-depth value (0-15) representing its position in 3D space:

[Component, x, y, width, height, z]
[TitleComponent, 0, 0, 360, 180, 0],      // z = 0 (closest)
[InfoComponent, 10, 30, 384, 192, 1],     // z = 1
[ImageComponent, -10, 27, 400, 300, 2],   // z = 2
// ... up to z = 13

2. Perspective Scaling

As you scroll, elements scale based on their distance from the "camera" (current scroll position):

scale: `calc(${Math.exp(scroll - z)})`;

Mathematical principle: Exponential scaling creates realistic perspective. Objects further away (when scroll < z) shrink exponentially, while objects behind the camera (when scroll > z) grow exponentially.

  • When scroll = z: Element is at the focal plane (scale = 1)
  • When scroll < z: Element is "in front" (scale > 1, appears larger)
  • When scroll > z: Element is "behind" (scale < 1, appears smaller)

3. Parallax Offset

Elements shift position based on depth using exponential parallax:

left: `calc(50dvw + ${(Math.pow(6, scroll - z) * x) / 2}% - ${w / 2}px)`;
top: `calc(50dvh + ${(Math.pow(6, scroll - z) * y) / 2}% - ${h / 2}px)`;

Mathematical principle: The formula 6^(scroll - z) creates dramatic parallax motion. Elements with offset values (x, y) appear to "fly by" the camera at different speeds based on their depth:

  • Base 6 was chosen for pronounced effect
  • The offset (x, y) determines lateral movement direction
  • Division by 2 moderates the extreme values

4. Depth of Field Blur

Elements blur based on their distance from focus:

filter: Math.abs(scroll - z) < 0
  ? `blur(${Math.pow(Math.abs(z - scroll), 2) * 0.4}px)`
  : `blur(${Math.pow(Math.abs(z - scroll) + 0.4, 6)}px)`;

Mathematical principle:

  • Behind camera (scroll - z < 0): Quadratic blur () for gentle defocus
  • In front of camera (scroll - z > 0): Sixth-power blur (x⁶) for rapid defocus
  • Creates a realistic depth-of-field effect like a camera lens

5. Opacity Falloff

Elements fade in/out using a skewed Gaussian distribution:

function skewedGaussian(x, A, b, c1, c2) {
  const c = x < b ? c1 : c2;
  return A * Math.exp(-Math.pow(x - b, 2) / (2 * Math.pow(c, 2)));
}

opacity: skewedGaussian(scroll - z, 1, 0, 1, 0.5);

Mathematical principle:

  • Standard Gaussian (bell curve) centered at focal point (b = 0)
  • Asymmetric falloff (c1 = 1 behind, c2 = 0.5 in front)
  • Elements fade faster when passing the camera than when approaching

6. Culling

Elements too far from view are hidden for performance:

display: Math.abs(scroll - z) > 2 ? "none" : "block";

Only renders elements within ±2 depth units of current scroll position.

7. Smooth Animation

GSAP provides smooth interpolation between scroll states:

gsap.to(smoothScroll, {
  current: newScroll,
  duration: 0.5,
  ease: "power2.out",
});

Prevents jarring jumps and creates fluid motion through 3D space.

The Math Behind It

The illusion works because:

  1. Exponential functions (e^x, 6^x) mimic real-world perspective projection
  2. Gaussian distribution creates natural visibility falloff like atmospheric depth
  3. Power functions (quadratic, sixth-power) simulate camera lens blur characteristics
  4. Synchronized transformations across scale, position, blur, and opacity create coherent depth perception

No actual 3D rendering occurs - just clever application of calculus and exponential functions to 2D CSS properties.

Tech Stack

  • Next.js 15.3 - React framework
  • React 19 - UI library
  • TypeScript - Type safety
  • GSAP - Animation engine
  • Tailwind CSS - Styling

Getting Started

# Install dependencies
npm install

# Run development server
npm run dev

Open http://localhost:3000 and scroll to experience the depth effect.

Controls

  • Mouse Wheel: Scroll through depth (desktop)
  • Touch Drag: Swipe to navigate depth (mobile)
  • Depth Indicator: Top-right corner shows current Z-position (0-15)

Customization

Modify the arr array in page.tsx to add/remove elements:

[Component, xOffset, yOffset, width, height, zDepth];
  • xOffset, yOffset: Lateral displacement from center (%)
  • width, height: Element dimensions (px)
  • zDepth: Position in 3D space (0 = front, 15 = back)

Performance Notes

  • Elements beyond ±2 depth units are culled (not rendered)
  • Mobile disables blur effects for better performance
  • GSAP's power2.out easing provides smooth 60fps animation
  • Only visible elements receive backdrop blur effects

License

MIT


No 3D engines. No libraries. Just mathematics.

About

Scrolling through depth using pure mathematics - no 3D engines, no Three.js, no WebGL.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages