Page transitions

The site's real navigation motion, live and tunable — with the network and server conditions a visitor actually brings. Throttle the fetch, feel the dead time, tune the timing variables, copy them back.

How this page works

  • Every run in the frame goes through the production DirectionalTransition, the shared-element pairings, and the recipes in view-transition.css. The GUI live-overrides only the :root timing variables, opens on whatever the stylesheet ships, and clears them when you leave.
  • The network and server sliders insert the real dead time a navigation spends before anything moves: Next.js fetches the RSC payload, then the transition plays. Production ships no loading UI, so that stillness is the actual experience. The timeline below the frame plots it.
  • The work takeover measures the real viewport, so the window fills it for that run; restore it from the window chrome or press Esc. Every other navigation plays inside the frame, with its snapshots clipped to the window.
  • A view transition freezes the whole document while it runs (browser behavior), this GUI included. That is also true in production.
  • The frame scrolls through its own Lenis instance, tuned like the site's.
  • Copy writes the whole :root block for view-transition.css, every variable in its order, so a paste can never drop one.

Where each technique fires in production

nav-forward
Mask reveal from the right edge, going deeper; the old page holds still beneath. Insight cards (title links and body clicks via useClickableCard), work index rows, segment index cards, related work and post rails, and pagination toward higher pages.
nav-back
Mask reveal from the left edge, going shallower. Pagination toward lower pages and CMS links that opt into transitionDirection="back".
nav-lateral
Top-down mask reveal, no spatial depth: the scroll-reveal wipe at page scale. The CMSLink default, the header brand, the 404 link, the form block’s confirmation redirect, and the demo sidebar.
post-image morph
A post card image and its hero carry the same view-transition-name (postImageVtName) and paint into the same POST_IMAGE_FRAME, so the browser interpolates one rect into the other over the move duration, through a light blur. Type-gated to nav-forward and nav-back (postImageShare); every other pairing stays silent. Layering today: the incoming page group paints above the morph group, so the image ducks under the wipe and reappears in the hero. The simulator’s Post morph, above page toggle previews the proposed z-index fix.
work-open
The work-media takeover, from the Industry work spotlight’s "View case study" link and its media panel. The old page fades out, the media (morph-hero, workImageVtName) glides straight to vertical center, expands about its own center to full screen, then the shared hero landing closes its mask one axis at a time onto the case-study hero and dissolves the hero’s own copy in, while the new page fades in beneath. The beat split runs in WAAPI (sequenceWorkImageMorph); browsers without linear() get a single CSS glide on the same variables.
menu navigations (not view transitions)
The takeover menu owns its two navigations with GSAP and removes document.startViewTransition for the flight. A plain close holds the docked window’s media through the undock and lifts a curtain on the reveal’s own duration and ease (the lateral wipe, so a menu link lands like any lateral link); a link with hero media plays the hero handoff, whose closing half is the same hero landing the takeover plays. Tune the lift here and the landing in the Hero landing section.
pinned chrome
site-header, site-footer and the global WebGL canvas are named groups with animation: none; they hold rock-steady through every swap.
untagged: hard cut
Browser back/forward, revalidations and search-as-you-type URL sync carry no type, and default: 'none' keeps them silent by design.