Motion
Scroll
One smooth scroll for the whole app. Lenis glides the page; GSAP's clock drives it; ScrollTrigger reads it. Everything that reacts to scroll goes through that one chain.
The scroll engine
These numbers update live as you scroll this page.
Scrolled0px
Speed0
Page read0%
Direction—
new Lenis({"autoRaf": false, "anchors": false, "lerp": 0.09, "wheelMultiplier": 0.9})
gsap.ticker.add((t) => lenis.raf(t * 1000)) · gsap.ticker.lagSmoothing(0) · lenis.on('scroll', ScrollTrigger.update)Scroll rules
- One loop. Lenis never runs its own animation frame (
autoRaf: false); GSAP's ticker feeds it. - scrub: true, never a number. Lenis already smooths the scroll; a numeric scrub smooths it twice and the page feels late.
- No ScrollTrigger snap. It fights the glide. Jump with
scrollToTarget()instead. - Entrances play once. Content reveals the first time it reaches the screen, then stays put. Scrolling back never hides it.
- Inner scroll areas opt out. Menus, lists and sheets that scroll carry
data-lenis-prevent; sideways strips carrydata-lenis-prevent-horizontal. - Overlays stop the page. Dialogs, drawers and the palette call
lockScroll()and give it back on close. - Phones scroll natively. Touch keeps the browser's own momentum; only wheel and trackpad are smoothed.
Scroll to
Jumps glide through Lenis (1.4s); they never use window.scrollTo.
Scrubbed progress
Tied to scroll with scrub: true — it moves exactly with the page, forward and back.
This section's progress through the screen
Scroll reveal
Each word sharpens as the paragraph rises; the block untilts at the same time (website About section).
| Prop | Values | Default | What it does |
|---|---|---|---|
text | string | — | The paragraph |
baseOpacity / blurStrength | number · px | 0.1 · 4 | How faint and blurred words start |
baseRotation | degrees | 3 | The tilt the block straightens from |
stagger | number | 0.05 | How far apart the words sharpen |
Reveal on enter
use:reveal — content slides up and fades in once, the first time it arrives (React Bits AnimatedContent).
Jobs on site0
Crew-days booked0
Invoices paid0
| Prop | Values | Default | What it does |
|---|---|---|---|
distance / direction / reverse | px · 'vertical' | 'horizontal' · bool | 100 · vertical · false | Where it comes from |
duration / ease / delay | s · ease · s | 0.8 · power3.out · 0 | The move |
stagger | s | 0 | Reveal each child in turn |
scale / blur / initialOpacity | number · px · 0–1 | 1 · 0 · 0 | Extra ways in |
threshold | 0–1 | 0.1 | How much must be visible first |