058

Scroll Depth Corridor

£10 or the whole Vault, £99

A corridor of panels receding into depth that the camera flies through as you scroll, wrapping from far to near so it never ends, with a hard flick opening the field of view and streaking the whole corridor past a headline that holds dead still at the vanishing point.

ScrollTrigger Lenis advanced
6 more details
3d-transformsinfinite-loopvelocity-reactivepinningwrapparallax

This demo reads better at your own screen size than in the frame below:

Updated

About this effect

A corridor of panels standing in ranks either side of the viewer, with light strips overhead and plates underfoot, that the camera flies through as you scroll. Panels wrap from the far plane back to the near one, so the corridor has no start and no end however far you scroll.

Read the full effect overview

Scroll velocity is the second layer, and the reason the effect has a signature moment. A hard wheel flick opens the field of view, pulls the depth fog back off the far panels, stretches every panel along the direction of travel and drives a field of light streaks toward the vanishing point, then springs the whole thing back to cruise with an elastic overshoot.

The headline is the still point of the shot. It is a flat overlay stacked above the corridor rather than a plate inside it, which is what makes the promise unconditional: no panel can cross in front of it at any velocity or any viewport, it never picks up the perspective, and it stays exactly the same size and pin-sharp while the field streaks past behind it. A soft aperture opens around it in step with the warp, so the vanishing point stays the quietest part of the frame at the exact moment the fog pulls back and the far panels become readable.

The camera is the product here. No panel reacts to a pointer, which is why every panel is a plain non-interactive article and the whole 3D chain opts out of hit testing.

Scroll Depth Corridor - GSAP animation effect preview

What's included

11 items
  • An endless corridor: panels wrap from the far plane to the near one with gsap.utils.wrap, so the fly-through has no seam and no reset
  • Ranks self-fill: author a handful of panels and the effect measures the depth it has to cover and clones them to whatever length fills it, rounding to a whole number of panels so none ever lands beside its own clone
  • The warp, four channels off one velocity reading: the field of view widens, the depth fog pulls back, the panels stretch along the direction of travel and light streaks converge on the vanishing point
  • A headline that cannot be occluded: it is a flat overlay above the corridor rather than a plate inside the 3D field, so it holds its size, its sharpness and its position through the whole warp with nothing to recompute per frame
  • An aperture that opens with the warp, keeping the vanishing point clear at the moment the fog pulls back and every far panel becomes readable at once
  • Elastic settle back to cruise on a back.out ease, with a small recoil past level, and a ticker watchdog that guarantees the release even though scroll events stop firing
  • Panels yaw to face the camera as they reach the near plane, on a squared curve so the turn belongs to the last stretch of the approach rather than creeping in from the far end
  • Aerial perspective on a curve, not a straight line: far panels are hazed toward the room's own colour with a scrim rather than transparency, so a distant panel never shows the panel behind it
  • Four ranks driven by one data hook, left, right, ceiling and floor, each with its own spacing, so the corridor can be two walls or a full tube
  • Reduced motion and no-JS both fall back to a still corridor composed entirely in CSS custom properties, with no panel hidden and nothing to restore
  • Viewport-gated ticker, one transform write per panel per frame, and a full teardown that removes the clones and hands the corridor back to that CSS composition

Perfect for

5 use cases
  • Landing and launch heroes that need a sense of arrival before the page proper begins
  • Agency, studio and festival sites where the work should feel like a space you move through rather than a grid you scan
  • Product and hardware pages where a single claim needs to hold still while everything around it accelerates
  • Editorial and long-form openers that want a designed transition into the first section instead of a fade
  • Event, film and music sites where the corridor is the venue and the panels are the bill

How it works

6 sections

The corridor is one perspective and one preserve-3d chain. A zero-size camera element is pinned to the centre of the frame and every panel is placed from it with a single translate3d, so the whole corridor costs one style write per panel per frame rather than a tween per property. Depth, the yaw toward the camera, the haze and the stretch all derive from the same z, which is why they are written together as one transform string.

Each rank is a fixed-length runway. The script takes the panel's extent along the corridor, works out how many it needs to cover the configured depth, clones up to a whole number of authored panels and wraps each one's position into a window whose near edge is fixed and whose far edge absorbs the rounding. Because the window is exactly the cycle length, every slot is filled exactly once and the loop has no seam.

Scroll drives a single position value rather than a scrubbed timeline: a pinned ScrollTrigger writes the target, a frame-rate independent ticker chases it, and an idle drift is added to the same value so the corridor glides on after the wheel stops.

Scroll speed is clamped to 0-1 and eased with a spring, which is what makes the return to cruise settle rather than snap. That one number reduces the CSS perspective (widening the field of view), opens the fog gradient's inner radius, scales every panel along its own travel axis and fades in a conic streak layer that is only in the document while it is doing something.

The headline is deliberately not part of any of that. It sits outside the 3D chain as a flat overlay stacked above the corridor, so the widening field of view cannot move it, resize it or bury it, and no depth sort can put a panel in front of it. Holding a plate inside the corridor at a constant projected size is arithmetic anyone can get right, and it still loses the moment a near panel crosses the line of sight. The only thing the headline takes from the warp is its aperture, a well of the room's own colour that deepens with the same custom property the fog and the streaks read.

Every element in the 3D chain is pointer-events: none, panels included. In a preserve-3d context an ancestor's own flat box sits at z = 0 while the panels are rotated away from it, so across most of the frame that flat box is in front of what the visitor is pointing at and swallows the event, including events the surrounding page wants.

Plugins ScrollTrigger
Difficulty Advanced
Smooth scroll Lenis integration
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Scroll Depth Corridor opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£10 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £99, one payment.

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add before the closing </body> tag:

Code snippet omitted: it ships with the download.

3. Add the effect HTML anywhere in your <body>:

Code snippet omitted: it ships with the download.

Author as few panels per rank as you like. The script measures the corridor and clones them until the rank covers the configured depth, so four panels per rank is a normal starting point even on a 4K screen.

Using It With Your Own Design

What the effect needs from your markup. Five hooks, and nothing else:

  • [data-corridor] on the section. This is the element the script reads the configuration from, the one the pinned ScrollTrigger uses, and the one the --corridor-p and --warp custom properties are written to.
  • [data-corridor-viewport] on the element that gets pinned, carries the perspective and clips the corridor. It must be the thing you want to fill the screen: the script reads its size to work out how far apart the ranks stand and how long the pin runs.
  • [data-corridor-camera] on a zero-size element pinned to the centre of the viewport. Every panel is placed from this origin, so if it has a size or is not centred the whole corridor moves off axis.
  • [data-corridor-field] on the element the ranks live in. It exists so the ranks can be measured and rebuilt as a group without disturbing the camera.
  • [data-corridor-rank="left|right|top|bottom"] on each rank. The value is the wall it belongs to and it decides everything about the placement: which side of the centre line the panels sit on, which way they face, whether the panel's width or its height runs along the corridor, and which axis the warp stretches them on. A rank may also carry its own data-gap.
  • [data-corridor-panel] on each panel. Panels must be direct children of a rank, and every panel in a rank must be the same size along the corridor (width for left/right, height for top/bottom), because that size is the cycle the wrap is built on.

The headline is not a hook. Put whatever you want at the vanishing point in a plain element that is a sibling of the camera, stacked above it, and give it no translateZ. That single decision is the whole guarantee: a panel cannot pass in front of something that is not in the preserve-3d chain, at any velocity, at any viewport, whatever the depth sort does, and a flat element never picks up the perspective, so it holds its size and its sharpness through a warp with nothing recomputed per frame. Putting the headline inside the corridor at a fixed depth and counter-scaling it looks like the clever answer and is the wrong one: the size holds, and then a near panel slices straight through the word. Leave the element out entirely and the corridor simply runs with nothing at the far end.

Panels are <article> elements on purpose. Nothing in the corridor is clickable, hoverable or focusable, so there is no hover and no focus parity to build; making them buttons would put a row of empty tab stops in the page.

What is only the demo's styling. Everything inside a panel is yours: the .corridor__cap, .corridor__type, .corridor__num, .corridor__mark, .corridor__bars and .corridor__rule classes are demo furniture and the script never looks at them. The palette, the --bone/--graphite/--signal panel variants, the fonts, the vignette and the cue chip can all go. The script reads data attributes and panel geometry, never a decoration class.

CSS the effect depends on. These are the rules a reskin usually breaks:

  • pointer-events: none on the camera, the field, the ranks, the panels and the hero. In a preserve-3d context an ancestor's own flat box sits at z = 0 while the panels are rotated and translated away from it, so across most of the frame that flat box is in front of what the visitor is pointing at. Leave it off and the corridor silently swallows selection, clicks and anything you layer over the frame.
  • transform-style: preserve-3d on the camera, the field and every rank, and perspective on the viewport only. One perspective, one 3D chain. A second perspective anywhere inside flattens everything below it.
  • No filter on anything in that chain. filter forces the used value of transform-style to flat, which collapses the corridor. That is why the depth haze is an opaque ::after scrim of the room colour rather than a brightness filter.
  • The camera is centred with position: absolute; top: 50%; left: 50% and a zero size, not with place-items: center. The field is deliberately larger than the frame, and a grid or flex item larger than its container is aligned to the start rather than centred, which parks the whole corridor in one corner.
  • The headline stays out of the 3D chain, and out of the perspective. The viewport carries the perspective, so a translateZ on the overlay would project it straight back into the field and hand the occlusion problem back. Stack it with z-index above the camera and the two overlay layers instead.
  • overflow: hidden on the viewport. Near panels are magnified well past the frame edge; without the clip they extend the page's scrollable area sideways.
  • The --pz, --py, --px, --turn and --haze custom properties on the panels. They are the still corridor the page shows with JavaScript off and under reduced motion. The script overwrites the whole transform inline while it runs, and clearing those inline styles on teardown hands the corridor straight back to them. Nothing is pre-hidden, so there is nothing to restore.

Options

Every attribute goes on the [data-corridor] section, except data-gap, which may also go on an individual rank to override the section default.

Attribute Values Default Description
data-depth Any number (px) 1800 (1600 on touch) Minimum distance to the far plane. The real far plane is this rounded up to a whole number of authored panels, so a larger value just means more panels in the frame. Very large values are a per-frame cost for panels the haze has already taken to black.
data-near Any number (px) 340 How far past the camera a panel travels before it wraps back to the far end. Must stay well under the smallest perspective the warp reaches (about data-fov × 0.58); above that a panel crosses the camera plane, inverts, and flares across the whole frame.
data-fov Any number (px) 1000 (1400 on touch) The perspective, which is the field of view: smaller is wider. Below about 600 the corridor fisheyes and the panel type shears at the frame edge; above about 1800 the depth flattens out of existence.
data-scroll Any number 2.5 (2.8 on touch) Pinned scroll length, in viewport heights. Below about 1 the corridor is gone before it has been read.
data-speed Any number 1 Multiplier on how far the corridor travels per unit of scroll. Past about 3 panels cross a whole pitch between frames and the motion strobes.
data-drift Any number (px/sec) 24 Idle drift, so the corridor is alive before anyone scrolls. 0 parks it completely. Much above 80 it reads as an autoplay video rather than as something you are steering.
data-gap Any number (px) 150 Spacing between panels along the corridor. Small values pack the corridor and cost a panel-write per frame each; large values leave visible holes between panels.
data-spread Any number 1 Multiplier on how far the ranks stand from the centre line. Below about 0.7 the ranks crowd the vanishing point and the headline area gets busy; above about 1.6 the walls leave the frame and the corridor stops being a corridor.
data-turn Any number (deg) 34 How far a panel yaws to face the camera as it reaches the near plane. 0 keeps the walls perfectly flat. Past about 60 panels turn before they are close enough for the turn to read, and the ranks stop looking like walls.
data-warp true, false true The velocity reaction. Always off on coarse pointers, whatever this is set to: touch inertia makes the velocity reading noisy, and a field of view that opens at random reads as a bug rather than as speed.

Accessibility

  • Reduced motion: the script never builds the corridor. The page keeps the still corridor composed in CSS, with every panel visible and legible. Nothing is pre-hidden, so nothing needs restoring.
  • Without JavaScript: the same still corridor. The effect adds no start states of its own, so there is no blank page and no flash.
  • No keyboard surface to mirror: nothing in the corridor is interactive, so panels are <article> elements rather than buttons and the tab order runs straight past them.
  • Cloned panels are marked aria-hidden="true", so a corridor of forty panels reads to assistive technology as the handful you actually authored.
  • Ceiling and floor slats are decorative and marked aria-hidden="true".
  • The interaction cue never promises what the pointer cannot do: the warp copy is hidden on coarse pointers, where the warp is switched off.

Dependencies

Required:

  • GSAP 3.12+
  • ScrollTrigger plugin

Optional:

  • Lenis (smooth scroll integration; the script wires it up if it is present, and honours data-smooth="off" on <html> and ?smooth=off in the URL)

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.