Files
claude-skills-reference/engineering-team/epic-design/references/depth-system.md

11 KiB
Raw Blame History

Depth System Reference

The 2.5D illusion is built entirely on a 6-level depth model. Every element on the page belongs to exactly one depth level. Depth controls four automatic properties: parallax speed, blur, scale, and shadow intensity. Together these four signals trick the human visual system into perceiving genuine spatial depth from flat assets.


The 6-Level Depth Table

Level Name Parallax Blur Scale Shadow Z-Index
0 Far Background 0.10x 8px 0.70 0.05 0
1 Glow / Atmosphere 0.25x 4px 0.85 0.10 1
2 Mid Decorations 0.50x 0px 1.00 0.20 2
3 Main Objects 0.80x 0px 1.05 0.35 3
4 UI / Text 1.00x 0px 1.00 0.00 4
5 Foreground FX 1.20x 0px 1.10 0.50 5

Parallax formula:

element_translateY = scroll_position * depth_factor * -1

A depth-0 element at scroll position 500px moves only -50px (barely moves — feels far away). A depth-5 element at 500px moves -600px (moves fast — feels close).


CSS Implementation

CSS Custom Properties Foundation

:root {
  /* Depth parallax factors */
  --depth-0-factor: 0.10;
  --depth-1-factor: 0.25;
  --depth-2-factor: 0.50;
  --depth-3-factor: 0.80;
  --depth-4-factor: 1.00;
  --depth-5-factor: 1.20;

  /* Depth blur values */
  --depth-0-blur: 8px;
  --depth-1-blur: 4px;
  --depth-2-blur: 0px;
  --depth-3-blur: 0px;
  --depth-4-blur: 0px;
  --depth-5-blur: 0px;

  /* Depth scale values */
  --depth-0-scale: 0.70;
  --depth-1-scale: 0.85;
  --depth-2-scale: 1.00;
  --depth-3-scale: 1.05;
  --depth-4-scale: 1.00;
  --depth-5-scale: 1.10;

  /* Live scroll value (updated by JS) */
  --scroll-y: 0;
}

/* Base layer class */
.layer {
  position: absolute;
  inset: 0;
  will-change: transform;
  transform-origin: center center;
}

/* Depth-specific classes */
.depth-0 {
  filter: blur(var(--depth-0-blur));
  transform: scale(var(--depth-0-scale))
             translateY(calc(var(--scroll-y) * var(--depth-0-factor) * -1px));
  z-index: 0;
}
.depth-1 {
  filter: blur(var(--depth-1-blur));
  transform: scale(var(--depth-1-scale))
             translateY(calc(var(--scroll-y) * var(--depth-1-factor) * -1px));
  z-index: 1;
  mix-blend-mode: screen; /* glow layers blend additively */
}
.depth-2 {
  transform: scale(var(--depth-2-scale))
             translateY(calc(var(--scroll-y) * var(--depth-2-factor) * -1px));
  z-index: 2;
}
.depth-3 {
  transform: scale(var(--depth-3-scale))
             translateY(calc(var(--scroll-y) * var(--depth-3-factor) * -1px));
  z-index: 3;
  filter: drop-shadow(0 20px 40px rgba(0,0,0,0.35));
}
.depth-4 {
  transform: translateY(calc(var(--scroll-y) * var(--depth-4-factor) * -1px));
  z-index: 4;
}
.depth-5 {
  transform: scale(var(--depth-5-scale))
             translateY(calc(var(--scroll-y) * var(--depth-5-factor) * -1px));
  z-index: 5;
}

JavaScript — Scroll Driver

// Throttled scroll listener using requestAnimationFrame
let ticking = false;
let lastScrollY = 0;

function updateDepthLayers() {
  const scrollY = window.scrollY;
  document.documentElement.style.setProperty('--scroll-y', scrollY);
  ticking = false;
}

window.addEventListener('scroll', () => {
  lastScrollY = window.scrollY;
  if (!ticking) {
    requestAnimationFrame(updateDepthLayers);
    ticking = true;
  }
}, { passive: true });

Asset Assignment Rules

What Goes in Each Depth Level

Depth 0 — Far Background

  • Full-width background images (sky, gradient, texture)
  • Very large PNGs (1920×1080+), file size 80150KB max
  • Heavily blurred by CSS — low detail is fine and preferred
  • Examples: skyscape, abstract color wash, noise texture

Depth 1 — Glow / Atmosphere

  • Radial gradient blobs, lens flare PNGs, soft light overlays
  • Size: 6001000px, file size: 3060KB max
  • Always use mix-blend-mode: screen or mix-blend-mode: lighten
  • Always filter: blur(40px100px) applied on top of CSS blur
  • Examples: orange glow blob behind product, atmospheric haze

Depth 2 — Mid Decorations

  • Abstract shapes, geometric patterns, floating decorative elements
  • Size: 200400px, file size: 2050KB max
  • Moderate shadow, no blur
  • Examples: floating geometric shapes, brand pattern elements

Depth 3 — Main Objects (The Star)

  • Hero product images, characters, featured illustrations
  • Size: 8001200px, file size: 50120KB max
  • High detail, clean cutout (transparent PNG background)
  • Strong drop shadow: filter: drop-shadow(0 30px 60px rgba(0,0,0,0.4))
  • This is the element users look at — give it the most visual weight
  • Examples: juice bottle, product shot, hero character

Depth 4 — UI / Text

  • Headlines, body copy, buttons, cards, navigation
  • Always crisp, never blurred
  • Text elements get animation data attributes (see text-animations.md)
  • Examples: <h1>, <p>, <button>, card components

Depth 5 — Foreground Particles / FX

  • Sparkles, floating dots, light particles, decorative splashes
  • Small (32128px), file size: 210KB
  • High contrast, sharp edges
  • Multiple instances scattered with different animation delays
  • Examples: star sparkles, liquid splash dots, highlight flares

Compositional Hierarchy — Size Relationships Between Assets

The most common mistake in 2.5D design is treating all assets as the same size. Real cinematic depth requires deliberate, intentional size contrast.

The Rule of One Hero

Every scene has exactly ONE dominant asset. Everything else serves it.

Role Display Size Depth
Hero / star element 5085vw depth-3
Primary companion 815vw depth-2
Secondary companion 510vw depth-2
Accent / particle 14vw depth-5
Background fill 100vw depth-0

Positioning Companions Close to the Hero

Never scatter companions in random corners. Position them relative to the hero's edge:

/*
  Hero width: clamp(600px, 70vw, 1000px)
  Hero half-width: clamp(300px, 35vw, 500px)
*/
.companion-right {
  position: absolute;
  right: calc(50% - clamp(300px, 35vw, 500px) - 20px);
  /* negative gap value = slightly overlaps the hero */
}
.companion-left {
  position: absolute;
  left: calc(50% - clamp(300px, 35vw, 500px) - 20px);
}

Vertical placement:

  • Upper shoulder: top: 35%; transform: translateY(-50%)
  • Mid waist: top: 55%; transform: translateY(-50%)
  • Lower base: top: 72%; transform: translateY(-50%)

Scatter Rule on Hero Scroll-Out

When the hero grows or exits, companions scatter outward — not just fade. This reinforces they were "held in orbit" by the hero.

heroScrollTimeline
  .to('.companion-right', { x: 80,  y: -50, scale: 1.3  }, scrollPos)
  .to('.companion-left',  { x: -70, y:  40, scale: 1.25 }, scrollPos)
  .to('.companion-lower', { x:  30, y:  80, scale: 1.1  }, scrollPos)

Pre-Build Size Checklist

Before assigning sizes, answer these for every asset:

  1. Is this the hero? → make it large enough to command the viewport
  2. Is this a companion? → it should be 1525% of the hero's display size
  3. Would this read better bigger or smaller than my first instinct?
  4. Is there enough size contrast between depth layers to read as real depth?
  5. Does the composition feel balanced, or does everything look the same size?

Floating Loop Animation

Every element at depth 25 should have a floating animation. Nothing should be perfectly static — it kills the 3D illusion.

/* Float variants — apply different ones to different elements */
@keyframes float-y {
  0%, 100% { transform: translateY(0px); }
  50%       { transform: translateY(-18px); }
}
@keyframes float-rotate {
  0%, 100% { transform: translateY(0px) rotate(0deg); }
  33%       { transform: translateY(-12px) rotate(2deg); }
  66%       { transform: translateY(-6px) rotate(-1deg); }
}
@keyframes float-breathe {
  0%, 100% { transform: scale(1); }
  50%       { transform: scale(1.04); }
}
@keyframes float-orbit {
  0%   { transform: translate(0, 0) rotate(0deg); }
  25%  { transform: translate(8px, -12px) rotate(2deg); }
  50%  { transform: translate(0, -20px) rotate(0deg); }
  75%  { transform: translate(-8px, -12px) rotate(-2deg); }
  100% { transform: translate(0, 0) rotate(0deg); }
}

/* Depth-appropriate durations */
.depth-2 .float-loop { animation: float-y 10s ease-in-out infinite; }
.depth-3 .float-loop { animation: float-orbit 8s ease-in-out infinite; }
.depth-5 .float-loop { animation: float-rotate 6s ease-in-out infinite; }

/* Stagger delays for multiple elements at same depth */
.float-loop:nth-child(2) { animation-delay: -2s; }
.float-loop:nth-child(3) { animation-delay: -4s; }
.float-loop:nth-child(4) { animation-delay: -1.5s; }

Shadow Depth Enhancement

Stronger shadows on closer elements amplify depth perception:

/* Depth shadow system */
.depth-2 img { filter: drop-shadow(0 10px 20px rgba(0,0,0,0.20)); }
.depth-3 img { filter: drop-shadow(0 25px 50px rgba(0,0,0,0.35)); }
.depth-5 img { filter: drop-shadow(0 5px 15px rgba(0,0,0,0.50)); }

Glow Layer Pattern (Depth 1)

The glow layer is critical for the "product floating in light" premium feel:

/* Glow blob behind the main product */
.glow-blob {
  position: absolute;
  width: 600px;
  height: 600px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--brand-color) 0%, transparent 70%);
  filter: blur(80px);
  opacity: 0.45;
  mix-blend-mode: screen;
  /* Position behind depth-3 product */
  z-index: 1;
  /* Slow drift */
  animation: float-breathe 12s ease-in-out infinite;
}

HTML Scaffold Template

<section class="scene" data-scene="[name]">
  <div class="scene-inner">

    <!-- DEPTH 0: Far background -->
    <div class="layer depth-0" aria-hidden="true">
      <div class="bg-gradient"></div>
      <!-- OR: <img src="bg-texture.png" alt=""> -->
    </div>

    <!-- DEPTH 1: Glow atmosphere -->
    <div class="layer depth-1" aria-hidden="true">
      <div class="glow-blob glow-primary"></div>
      <div class="glow-blob glow-secondary"></div>
    </div>

    <!-- DEPTH 2: Mid decorations -->
    <div class="layer depth-2" aria-hidden="true">
      <img class="deco float-loop" src="shape-1.png" alt="">
      <img class="deco float-loop" src="shape-2.png" alt="">
    </div>

    <!-- DEPTH 3: Main product/hero -->
    <div class="layer depth-3">
      <img class="product-hero float-loop" src="product.png"
           alt="[Meaningful description of product]" />
    </div>

    <!-- DEPTH 4: Text & UI -->
    <div class="layer depth-4">
      <h1 class="hero-title split-text" data-animate="converge">
        Your Headline
      </h1>
      <p class="hero-sub" data-animate="fade-up">Supporting copy here</p>
      <a class="cta-btn" href="#" data-animate="scale-in">Get Started</a>
    </div>

    <!-- DEPTH 5: Foreground particles -->
    <div class="layer depth-5" aria-hidden="true">
      <img class="particle float-loop" src="sparkle.png" alt="">
      <img class="particle float-loop" src="sparkle.png" alt="">
      <img class="particle float-loop" src="sparkle.png" alt="">
    </div>

  </div>
</section>