About this site

Motion guidelines.

Motion on this site works like film editing: it draws the visitor into each section, then gets out of the way. Every value here is the one the site ships with, and most sections come with a live demo. See also the brand guidelines.

Pure Experience Design

Draw them in, then get out of the way.

Six principles, a handful of tokens and one rule for timing. Everything else follows from them.

Motion

Principles

What every animation on the site has to answer to.

  1. 01

    Cinematic

    Each section arrives like a cut in a film. Its animation waits until the visitor is there, so they see it begin.

  2. 02

    Orient, never decorate

    Motion says where something came from, what changed or where to look next. If it does none of those, it goes.

  3. 03

    One feel

    Every reveal, panel and hover uses one family of ease-out curves and a short list of durations.

  4. 04

    Measured, not guessed

    Blur and travel were measured from reference sites; timing is checked frame by frame in storyboards.

  5. 05

    Reduced motion is a design

    Not a faster version: a still, finished one that makes sense on its own.

  6. 06

    Only when seen

    Nothing animates off-screen. Backgrounds pause when they leave the view and resume when they return.

Tokens

Duration

Three durations cover the site. Press Play to compare them on the same ease.

--m-dur-fast · 0.25sCalls to action, borders and small fades
--m-dur · 0.9sThe reveal; most entrances
--m-dur-slow · 1.4sLarge surfaces, films fading up
TokenValueUse
--m-stagger0.045sBetween words in a reveal
--m-stagger-ch0.018sBetween characters (big numbers and short titles)
--m-blur10pxStarting blur of a reveal, measured
--m-shift4remStarting offset, sideways reveals
--m-shift-y1.25remStarting offset, upward reveals

Tokens

Easing

One family: ease-out. Things arrive quickly and settle slowly, the way a camera lands on a subject. Nothing on the site eases in, bounces or overshoots.

--m-easecubic-bezier(0.16, 1, 0.3, 1)Expo-out. The default: reveals, panels, the mark. Arrives fast, settles long.
--m-ease-softcubic-bezier(0.33, 1, 0.68, 1)Softer ease-out for opacity and secondary movement.
Accordioncubic-bezier(0.22, 0.9, 0.24, 1)Opening and closing panels: the height, the rule and the icon.

Text

The reveal

Headings arrive in pieces: each word (or character) fades in from a blur and a short offset, one after another. The text is real in the page first; it is only split in the browser, with one whole copy kept for screen readers.

Seven phases, one thread.

Word · from the side (--m-shift) · titles and section headings

98.8

Character · from below (--m-shift-y) · big numbers and short titles

SettingValueWhy
Startopacity 0 · blur 10px · offset 4rem (x) or 1.25rem (y)Measured from the reference sites
Endopacity 1 · blur 0 · offset 0Blur is cleared afterward, so text stays crisp
Duration and ease0.9s · expo-out--m-dur, --m-ease
Stagger0.045s per word · 0.018s per character--m-stagger, --m-stagger-ch
WhenAt 90% of the screen; immediately if already on-screen when the page loadsA half-revealed heading under a visible eyebrow reads as broken
Long textOver 42 pieces, falls back to words, then linesBlur on too many pieces drops frames
Width changeRe-split after resize and after fonts loadLines are measured, so they must match the font on-screen
Phones and tabletsOff below 1024px: headings are simply there. On home, a case’s statement fades in with its client mark (0.9s, expo-out)Splitting and blurring words ran poorly on phones and tablets

Timing

Cinematic start

A section’s background animation starts only once the section’s top has passed 65% of the screen, never while the section above still fills the view. The visitor arrives, then the story begins.

  • Applies to every section background: canvas, WebGL, SVG and film.
  • The headline and text reveals are not delayed; only the background story waits.
  • New backgrounds use the same rule: START_AT in the component.

Page

Scroll

Smooth scrolling gives the page its weight; the header stays on-screen throughout.

BehaviorSpec
Smooth scrollLenis · duration 1.1s · expo curve 1.001 − 2^(−10t) · on GSAP’s ticker, so ScrollTrigger agrees · off on touch screens (phones and tablets scroll natively, with no soft snap)
HeaderAlways on-screen: the mark on its dark pill, the nav with a soft dark halo; on phones and tablets, a full-width dark bar with the nav centered on the mark
Anchor jumpsSmooth, with the header’s height subtracted
Soft snap (home)A wheel or trackpad scroll that comes to rest within 30% of a screen of a full-screen section’s top glides the rest of the way (160ms after the input goes quiet, a 0.075 lerp); farther, it stays put. Only sections at least a screen tall count; touch, keys, the scrollbar and links are never snapped, nor anything while the Work overlay is open
Inner scrollersOpt out of smooth scroll (data-lenis-prevent) so they scroll natively
Reduced motionSmooth scroll is off entirely, so nothing snaps

Interface

Interaction

Small, quick and always paired with a change of color or state, never movement alone.

Hover · color 0.5s · translate 6px over 0.6s · accordion ease

The height opens with the grid-rows trick over 0.8s; the accent rule draws across the top over 0.9s; the plus turns into a minus.

Disclosure · grid-template-rows 0fr → 1fr · 0.8s · one open at a time

PatternSpec
The markPill widens 0.7s expo; words fade in 0.6s, staggered 0.1 / 0.16 / 0.22s; the tagline follows at 0.35s
Links in running textWhite, at the text’s weight, with an accent underline; the text turns to the accent over 0.2s. Navigation, breadcrumbs and cards have no underline
Calls to actionOpacity to 70% over 0.25s
Frames and cardsImage scale 1.03 over 0.8s on hover; no lift, no shadow
Accordion scrollThe row you open stays steady while one above closes, then glides up under the header (cubic ease-out, 0.8s), so what you opened is what you see
Lightbox and overlaysFade in; focus moves in and returns to where it came from
FocusNever animated away: the ring appears instantly

Media

Backgrounds and film

The live backgrounds and films behind the words, from the home hero to the case studies. They are storyboarded frame by frame on the About this site page.

  • Start at 65%, run only while on-screen, pause when off-screen.
  • Films are muted and play inline; they wait in the dark, fade up as their section arrives and pause when it leaves. 10-bit AV1 and HEVC first, so dark gradients don’t band, then H.264 and VP9; each file’s URL carries a content stamp, so a re-cut film is never served stale. A poster frame for each.
  • Endings hand off rather than cut: a film into its still, footage into a live halftone, dots into a mark.
  • Vignettes are soft and shaped by the footage, never an oval.
  • Legibility comes first: anything behind text is checked against the brightest frame.
  • Testable: heavy canvases expose a seek hook (qaSeek(t)) that renders one exact moment, paused, for tests and storyboards.

Accessibility

Reduced motion

When a visitor’s system asks for reduced motion, every effect has a still alternative. One switch in the tokens zeroes blur, travel and stagger site-wide.

EffectUnder reduced motion
Text revealBlur, travel and stagger go to zero; text fades in over 0.15s, whole.
Smooth scrollOff: the browser scrolls natively.
Intro curtain and headline rotatorThe curtain never plays; the rotator shows its last word.
BackgroundsA finished still: the last frame of a story, not the first; a loop holds one of its frames.
FilmsThe poster frame; no autoplay.
Accordions and the markOpen and close instantly; state still changes and is announced.
Scroll-driven sequencesShown in their end state.

Engineering

Performance

Motion is only cinematic if it’s smooth.

  • Animate transform, opacity and filter only; never layout properties per frame (the accordion’s grid-rows height is the one exception).
  • will-change is set for a tween and released the moment it ends.
  • Blur is capped at 42 pieces per reveal; past that, coarser pieces.
  • Canvases and films stop drawing off-screen (IntersectionObserver), when the tab is hidden and while the Work overlay is open: the page under it is held, so nothing draws behind the overlay.
  • Every animation that can start two ways guards itself with a flag, so it never plays twice.
  • A script that rebuilds animations kills only the tweens it made, never every ScrollTrigger on the page.

Code

Tokens

The motion block of packages/tokens/tokens.css, printed from the file itself, with the reduced-motion switch.

:root {
  /* ---- Motion ---------------------------------------------------------
     Motion is tokenized exactly like color. Change the feel of every
     reveal on every site from these values. */
  --m-dur-fast:   0.25s;
  --m-dur:        0.9s;   /* the reveal itself                       */
  --m-dur-slow:   1.4s;
  --m-stagger:    0.045s; /* per word                                */
  --m-stagger-ch: 0.018s; /* per character (hero only)               */
  --m-blur:       10px;   /* measured off fantasy.co                 */
  --m-shift:      4rem;   /* measured off fantasy.co                 */
  --m-shift-y:    1.25rem;
  --m-ease:       cubic-bezier(0.16, 1, 0.3, 1);   /* expo-out       */
  --m-ease-soft:  cubic-bezier(0.33, 1, 0.68, 1);
}
/* One switch kills the whole motion layer. Blur + translate + smooth
   scroll is a vestibular trigger stack; this is not optional. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --m-dur: 0.15s;
    --m-dur-slow: 0.15s;
    --m-stagger: 0s;
    --m-stagger-ch: 0s;
    --m-blur: 0px;
    --m-shift: 0px;
    --m-shift-y: 0px;
  }
}

More about this site

Start a conversation