parallax-depth-systems

Installation
SKILL.md

Parallax Depth Systems

When to use this

  • You want a hero or section where multiple visual layers (background sky, midground mountains, foreground trees) move at visibly different rates to sell depth, on scroll or on mouse/pointer movement.
  • You need to decide actual numeric speed ratios per layer instead of guessing values that "look kind of right."
  • You want to know whether to use real CSS 3D (perspective + translateZ) or faked 2D layered translateY multipliers, since they produce different visual results and have different cost/complexity tradeoffs.
  • Do NOT use this for a single background image with a slight scroll offset; that's a much simpler one-layer effect and doesn't need a "system." This skill is for coordinating 3+ layers with a consistent depth model. Do NOT use scroll-based parallax as the primary interaction for content-critical sections; pair with sticky-pinning-sequences if the layers need to also pin/hold at points.

Mental model

Parallax fakes depth perception using the same cue your eyes actually use in the real world: closer objects appear to move faster across your field of view than distant ones for the same amount of viewer movement. The core relationship is apparent_speed = viewer_movement / distance. This gives you a principled way to assign per-layer speed multipliers instead of eyeballing them: pick a "distance" value per layer (e.g. background = 800 depth units, midground = 400, foreground = 100, subject/UI layer = 0, meaning it doesn't move relative to the viewport at all), and each layer's multiplier is baseDistance / layerDistance, normalized so your nearest moving layer gets a sensible max multiplier (commonly 1.0-1.5x scroll speed) and the farthest gets the smallest (0.1-0.3x).

There are two structurally different implementations, and conflating them causes most parallax bugs. Faked 2D parallax applies a different translateY multiplier to each flat layer, all rendered at the same simulated distance from the camera (there is no real camera, no real distance, just numbers you picked). This is cheap, works everywhere, and is right for 95% of use cases. True 3D parallax uses an actual CSS 3D scene: a perspective value on a parent establishes a virtual camera distance, and children get real translateZ() values placing them at different distances from that camera; when the parent's perspective-origin or a wrapping rotation/translation shifts (via mouse move or scroll), the browser's actual 3D projection math produces correct parallax as an emergent property of true perspective projection, not a hand-picked multiplier per layer. True 3D is more physically consistent (multiple simultaneous motion axes stay correct together, e.g. combined mouse-x and mouse-y parallax) but is harder to reason about, since your translateZ values interact with your perspective value in a specific formula (apparent_scale = perspective / (perspective - translateZ)), and elements placed at translateZ values close to or exceeding your perspective value flip or vanish.

Mobile needs categorically different handling, not just smaller numbers. Scroll-linked parallax on mobile via transform triggered by a scroll listener is more prone to visible jank because mobile scroll events historically fire on a throttled/passive basis and main-thread contention is more common on weaker devices; mouse-move-driven parallax has no equivalent on touch devices at all (no persistent pointer position) and should be replaced with device-orientation-driven parallax (gyroscope tilt) or disabled outright, never left as dead unreachable code paths.

Installs
2
First Seen
Aug 30, 2026
parallax-depth-systems — avnehsbhatia/ultraui