KOMPOSE.
All resources
WebsiteClaude

How the Lando Norris, Charles Leclerc and Oscar Piastri sites are built

The problem it solves

F1 driver sites (landonorris.com, charlesleclerc.com, oscarpiastri.com) look like an unreachable budget, yet none of the three uses 3D: it is all Lenis, GSAP ScrollTrigger, masked line-by-line text reveals and well encoded full-bleed video. The real blocker is that a single prompt cannot produce this kind of site, because the systems depend on each other (scroll engine before any animation, preloader before the hero, consecutive pins in one sequence). This breaks down what actually runs on all three, then splits the build into 10 steps with a ready-to-paste prompt for each.

The prompt to copy

Optimized withClaude
You are my build partner for a cinematic athlete / driver one-page site in the style of landonorris.com, oscarpiastri.com and charlesleclerc.com: full-bleed video hero, smooth inertia scroll, pinned chapters, masked text reveals, draggable card decks, and a UI theme that inverts as you scroll.

This is too large to build in one shot. We will build it in 10 numbered steps. Do ONE step per message, and nothing else.

Pick one stack and keep it for the whole build:
A. Next.js App Router + Tailwind + GSAP 3.13 (ScrollTrigger, SplitText, Flip, Observer, Draggable + InertiaPlugin, ScrambleText, CustomEase) + Lenis. Best for a fully custom, deployable site.
B. Webflow + the same GSAP / Lenis bundle loaded from jsDelivr and driven by data-attributes. Best when a client has to edit the content afterwards.

The 10 steps:
1. Foundations: project setup, design tokens, type scale, grid, motion tokens.
2. Scroll engine: Lenis inertia scroll wired to a single GSAP ticker and ScrollTrigger, with reduced-motion and mobile branches.
3. Preloader and entry transition: real loading counter, then a masked reveal into the hero.
4. Cinematic hero: full-bleed muted looping video, line-by-line masked title, rotating scramble word, scroll cue.
5. Navigation: fullscreen overlay menu, staggered link reveal, and a nav theme that inverts per section.
6. Identity block: driver stats as a pinned key-value strip with count-up numbers.
7. Chaptered story: pinned chapters, progress indicator, full-screen detail overlays.
8. Interactive modules: draggable flick-card deck, stacking cards on scroll, custom GSAP slider with dots.
9. Gallery with hover swaps, partners, social wall, newsletter, footer.
10. Performance, accessibility, i18n and SEO pass, then a QA checklist.

Rules for every step:
- Output complete, runnable files, not fragments. Say which file each block belongs to.
- Never re-scaffold what an earlier step produced. Extend it.
- Register every animation in one place and kill it on unmount or page transition.
- Ship the prefers-reduced-motion fallback in the same step that creates the effect, never at the end.
- Write the mobile choreography as its own branch, not as a shrunken desktop one.
- End each step with: what to check in the browser to know it worked, and what comes next.

Project brief to build against: [name, sport and role, team, 3 to 5 career milestones, brand colours, partner list, social links, whether a store is linked].

Start with step 1. Wait for me to say next before moving on.

Three Formula 1 driver sites, three different agencies, three different stacks, and yet the same feeling: a page you watch like a film. We opened and inspected each one to see what actually runs, then split the build into 10 steps, each with its own prompt.

https://landonorris.com, https://www.oscarpiastri.com, https://charlesleclerc.com/en/

What actually runs under the hood

landonorris.com: Webflow with a bespoke layer on top

  • Base: Webflow (assets served from website-files.com), so the client keeps editing the content, plus a custom JS bundle served by the agency OFF+BRAND from its own CDN.
  • Scroll: Lenis for the inertia.
  • Vector animation: Rive, not Lottie. Files are driven by state machines (data-rive-state-machine, data-rive-artboard) and some are scroll-triggered (data-rive-scrolltrigger-start and -end). That is what powers the living button arrows and the page transitions.
  • Per-section theme: every block carries a data-theme (lime, dark) and a data-nav-theme-target, so the navigation recolours as you scroll.
  • Micro-interactions: 31 elements with data-anim="text-hover" and around thirty coloured sweeps via data-anim-high="right, lime".
  • Video: seven streamed Vimeo players, muted, looping, hover triggered (data-stream-hover).
  • The rest: Klaviyo for the newsletter, iubenda for consent, 71 WebP images and not a single JPEG.

oscarpiastri.com: Webflow plus the full GSAP arsenal

  • Base: Webflow as well, but all of the motion comes from GSAP 3.13 loaded from jsDelivr, with nearly every plugin: ScrollTrigger, SplitText, Flip, Draggable, InertiaPlugin, Observer, ScrambleTextPlugin, CustomEase.
  • Scroll: Lenis 1.2.3, with split-type as a SplitText backup.
  • Rotating headline: data-rotating-words="driven, calm, ready, sharp" combined with ScrambleText, so the headline word recomposes letter by letter.
  • Flick deck: seven data-flick-cards-item cards, one per weekday, thrown with Draggable and InertiaPlugin.
  • Stacking cards: three data-stacking-cards-item blocks for career milestones, each settling over the previous one on scroll.
  • In-house slider: data-gsap-slider-init with its own prev / next controls and dot container, not a carousel plugin.
  • Entry: a transition-mask and a mask-title reveal the hero. Background videos are webm with an mp4 fallback and a poster image.

charlesleclerc.com: bespoke WordPress, cut into chapters

  • Base: WordPress with a custom theme (theme-custom) and WPML for English, Italian and French. No page builder.
  • Motion: a single 263KB output.js bundle holding GSAP with ScrollTrigger, ScrollSmoother, SplitText, Flip and Observer, plus Lenis and Lottie.
  • Structure: 13 numbered sections (section-1 through section-13) and dedicated mobile variants (section-1-mobile, -4-mobile, -8-mobile, -12-mobile). Two distinct scroll choreographies, not plain responsive.
  • Narrative: five chapters (data-chapter) and five full-screen overlays (training, preparation, racing, off-season, driver) that open without leaving the page.
  • Opening: lottie-intro and lottie-container for the entry animation, then masks (mask, mask2, grid-overlay) for the reveals.
  • Navigation: burger, fake-burger, menu-container, mini-menu-left, sub-menu, with duplicated labels held in data-text for the hover effect.

The common denominator

None of the three uses 3D or WebGL. The premium feel comes from four things only: inertia scrolling (Lenis on all three), GSAP ScrollTrigger for pinning and scrubbing, masked line-by-line text reveals (SplitText), and well encoded full-bleed video. The rest is discipline: condensed typography, an inverting theme, and a mobile choreography written separately.

Why one prompt is not enough

Asking for a site like Lando Norris’s always produces the same thing: a decent, flat page with no scroll direction. The reason is mechanical. This kind of site is not a page, it is a stack of systems that depend on each other. The scroll engine has to exist before any animation. The preloader has to know the real loading state of the hero video. Consecutive pins have to be built in one sequence or they push each other around. A model writing it all in one go improvises those dependencies, and the result breaks on the first resize.

Hence the split below: one orchestration prompt that sets the frame and the 10 steps (that is the Prompt block at the top of this page), then one prompt per step. Stay in the same conversation, and validate each step in the browser before moving on.

Step 1: foundations

Goal: lock the stack, the design tokens and a scrollable skeleton. No animation yet.

Step 1 of 10: foundations.

Set up the project shell for a cinematic driver / athlete one-pager. No sections content yet, no animation yet.

Deliver:
- The scaffold: Next.js App Router + TypeScript + Tailwind, or a Webflow-ready index.html plus a single main.js if we chose Webflow.
- A design token file: two background themes (near-black #0B0B0B and off-white #F4F2EE), one accent colour taken from the team livery, a six step neutral ramp, each exposed as a CSS custom property so a section can flip theme by setting one attribute.
- A type scale: one condensed uppercase display face for headlines (Fjalla One, Anton or a Druk-like) and one neutral grotesk for body copy. Sizes with clamp(), from 0.85rem body to a 12vw hero.
- A 12 column grid, max width 1440px, consistent section padding, exposed as utility classes.
- Motion tokens: three durations (0.4 / 0.8 / 1.2s), one custom ease for entrances, one for exits, one stagger value.
- An empty page made of 10 placeholder sections, each carrying a data-theme attribute and a visible label, so scrolling top to bottom already shows the skeleton.

Add no library beyond the framework yet. Show me the file tree, then the full content of every file you create.

Done when: the page scrolls end to end, the 10 sections alternate backgrounds, and changing one token changes the whole site.

Step 2: the scroll engine

Goal: the most important step. Everything else depends on it, and this is where 90% of attempts fall apart.

Step 2 of 10: the scroll engine.

Add smooth inertia scrolling and wire it correctly to GSAP. Every later animation depends on this step.

Deliver:
- Lenis installed and initialised once, at app level, lerp around 0.1, native scrolling left alone on touch.
- Lenis driven by the GSAP ticker (gsap.ticker.add) with gsap.ticker.lagSmoothing(0), and ScrollTrigger.update called on every Lenis scroll event. Do not run two independent requestAnimationFrame loops.
- ScrollTrigger.scrollerProxy configured if the scroll container is not the window.
- One reusable helper that registers a ScrollTrigger and returns its cleanup, so no trigger ever leaks across route changes or hot reloads.
- ScrollTrigger.refresh() called after fonts load and after any image or video finishes loading.
- A gsap.matchMedia setup with three branches: desktop (full motion), touch and small screens (simplified, no pinning), and prefers-reduced-motion (no smooth scroll at all, instant states, native scrolling).
- One throwaway demo trigger, a box that fades and translates on scroll, to prove the pipeline works.

Then explain in three lines how I can verify in devtools that the ticker is unified rather than double-driven.

Done when: scrolling has inertia without jitter, and the demo tracks the scroll to the pixel, including after a resize.

Step 3: preloader and entry transition

Goal: the opening. On all three references this is what flips perception in the first second.

Step 3 of 10: preloader and entry transition.

Deliver:
- A full-viewport preloader above the page: a percentage counter from 0 to 100 tied to real asset progress (images decoded and the hero video reaching canplaythrough), not a fake timer, with a hard 3 second cap so a slow network never blocks entry.
- Scroll locked while the preloader is up (Lenis stopped), released the instant the reveal ends.
- The exit: two to four panels wipe away with a clip-path or transform, revealing the hero underneath. Use CustomEase, not a stock ease.
- The hero entrance chained to that exit on a single GSAP timeline: hero video scaling from 1.12 to 1, title lines rising out of their masks, nav fading in last.
- Session memory: the full counter runs once per session, subsequent visits get a 400ms fade only.
- Reduced motion: no counter, no wipe, content visible immediately.
- Optional Lottie variant: same choreography with a Lottie JSON instead of the panels, library lazy loaded so it never blocks first paint.

One timeline, one entry point, killed cleanly on unmount.

Done when: the counter reflects real loading, scroll control is handed back exactly as the reveal ends, and a reload within the session does not replay the counter.

Step 4: the cinematic hero

Goal: full-bleed video, line-by-line masked title, rotating word. The signature moment.

Step 4 of 10: the cinematic hero.

Deliver a full-viewport hero:
- Background: a muted, looping, playsinline, autoplaying video (webm with an mp4 fallback and a poster image), object-fit cover, with a dark gradient scrim behind the text for contrast. It must never cause a layout shift.
- The name in the condensed display face, split into lines with SplitText or SplitType, each line inside an overflow-hidden mask, revealed with a staggered y translate.
- A one-line role and team subtitle, plus a rotating word that swaps every 2.5 seconds using ScrambleText (for example: driven, calm, ready, sharp). Pause the rotation when the tab is hidden.
- A scroll cue at the bottom that fades out over the first 100px of scroll.
- On scroll out: the video scales up slightly and darkens while the title translates up faster than the background, a parallax scrub tied to ScrollTrigger.
- Mobile: fall back to the poster image when the connection is constrained (navigator.connection.saveData, or effectiveType 2g or 3g), and let the title wrap onto more lines rather than shrinking below 9vw.
- Reduced motion: static poster, no scramble, no parallax, title visible from the start.

Give me the component, the CSS, and the video encoding settings you recommend: resolution, bitrate, target file size.

Done when: there is no layout shift on load, the title rises out of its masks, and the hero stays legible over a bright frame.

Step 5: navigation and theme inversion

Goal: the fullscreen menu and the nav that recolours per section. The detail everyone notices without being able to name it.

Step 5 of 10: navigation and per-section theme inversion.

Deliver:
- A fixed minimal header: wordmark left, three to five links right, burger on mobile.
- A fullscreen overlay menu: opens with a clip-path or panel wipe, links revealed with a 60ms stagger, each link hovering with the label sliding up while a duplicate slides in from below (hold the duplicate in a data-text attribute). Close on Escape, on link click, and on browser back. Trap focus while open, restore it on close, and stop Lenis while open.
- Theme inversion: every section carries data-theme dark or light. One ScrollTrigger per section updates a single CSS custom property on the header, so wordmark, links and burger recolour as the section crosses the header line. Tween the colour, do not swap it instantly.
- An active-section indicator in the header, plus a thin scroll progress bar.
- Full keyboard support, correct aria-expanded, aria-controls and roles.

Do not rebuild the sections from step 1, only read their data-theme.

Done when: the nav stays legible on every section, the menu closes from the keyboard, and focus returns to the burger.

Step 6: the identity block

Goal: turn a fact list into a design moment, exactly what the driver card on oscarpiastri.com does.

Step 6 of 10: the identity block.

Deliver a stats strip that turns a dull fact list into a moment:
- Six to eight key-value pairs: nationality, race number, debut, height, favourite circuit, born, wins, podiums.
- Desktop: the section pins for the length of its own height while the pairs move horizontally, each pair fading and rising into place as it reaches centre. Numbers count up from 0 to their value with a GSAP tween on a proxy object, formatted with toLocaleString.
- Type contrast carries the design: label in small uppercase letter-spaced type, value in the display face at a much larger size.
- Mobile: no pin, a simple two column list with a per-row reveal.
- Reduced motion: final values rendered directly, no count up, no pin.

The pin must not create a jump: set pinSpacing correctly and call ScrollTrigger.refresh after fonts load.

Done when: the pin causes no jump, the numbers count once, and mobile stays a plain list.

Step 7: the chaptered story

Goal: the spine. This is what separates a documentary from a landing page, and it is the whole principle behind charlesleclerc.com.

Step 7 of 10: the chaptered story.

This is the spine of the page, the part that makes it feel like a documentary rather than a landing page.

Deliver:
- Five chapters, each with a chapter number, a title, one paragraph and one full-bleed image or short video.
- Each chapter pins while its copy crossfades and its media scales slowly from 1 to 1.08, then unpins into the next. Consecutive pins must not fight each other: build them as one ScrollTrigger sequence, not five independent ones.
- A fixed chapter indicator in 01 / 05 style that updates as chapters change, plus a thin vertical progress line.
- A pull quote between two chapters, revealed word by word on scroll with SplitText, at a large size on a plain background.
- Detail overlays: four chapters expose a read more that opens a full-screen overlay panel (training, preparation, racing, off-season). The overlay animates in from the click origin, locks the scroll behind it, closes on Escape and on backdrop click, and returns focus to its trigger.
- Mobile: chapters stack normally with a fade and rise, overlays become full-screen pages.

Content can stay placeholder, the structure is what matters here.

Done when: you can move through all five chapters without a stutter, the indicator keeps up, and overlays open and close without losing scroll position.

Step 8: the interactive modules

Goal: the three signature modules from oscarpiastri.com. They are what make the site feel handled rather than watched.

Step 8 of 10: the three interactive modules.

Build all three, each self-contained, each with a mobile path and a reduced-motion path.

1. Flick-card deck, a seven day routine with one card per day. A horizontal deck the user can drag and flick, using Draggable with InertiaPlugin, snapping to card boundaries. Arrow keys move one card at a time. The active card scales up while the others dim. A dot row reflects the position and is clickable.

2. Stacking cards, three to five career milestones. Cards share the same sticky position, and as you scroll each new card slides over the previous one, which scales down slightly and loses contrast. Use position sticky with one ScrollTrigger scrub for the scale, not one pin per card.

3. Custom slider for news or partners. A GSAP-driven track with prev and next controls, dots, wheel and touch support through Observer, and a hover state where the cursor becomes a drag label. Looping, with clones handled so there is no visible jump at the seam.

For each one: keyboard accessible, aria-roledescription set, and no layout shift when the module hydrates.

Done when: the deck flicks and snaps, the cards stack without flicker, and the slider loops with no visible seam.

Step 9: gallery, partners, socials, newsletter, footer

Goal: the lower half of the page, where landonorris.com puts its helmet gallery and social wall.

Step 9 of 10: gallery, partners, social wall, newsletter and footer.

Deliver:
- A gallery grid (helmets, kit, moments): each item has a base image and a hover image that wipes in from one side behind a mask, with the item title revealed at the same time. Grid items animate in with a staggered scale and fade tied to their row. Click opens a lightbox with keyboard navigation.
- A partners section: responsive logo grid, monochrome by default, full colour on hover, each logo a link with a proper accessible name. Optionally one marquee row whose speed follows scroll velocity and whose direction flips with scroll direction.
- A social wall: six images in an offset grid, each linking out, plus a follow block with platform icons.
- A newsletter block: one email field, one button, inline validation, loading and success states, a honeypot plus a simple rate limit, and a clear consent line. Put the provider (Klaviyo, Resend, Mailchimp) behind a single function so it can be swapped.
- The footer: repeated nav, socials, legal links, and one oversized tagline in the display face that reveals on scroll.

Every hover effect needs a touch equivalent, because hover does not exist on mobile.

Done when: every hover effect has a touch equivalent, and the newsletter surfaces a readable error state without a reload.

Step 10: performance, accessibility, i18n, SEO and QA

Goal: the pass that separates a demo from a deliverable. On this kind of project it is almost as much work as the nine steps before it.

Step 10 of 10: performance, accessibility, i18n, SEO and QA.

Go through the whole build and fix things, do not just report them.

Performance:
- Hero video under 3MB, webm plus mp4, poster preloaded, preload none for anything below the fold, lazy loading for every image outside the first viewport.
- Every image in AVIF or WebP with explicit width and height, a correct sizes attribute, and priority only on the hero.
- GSAP plugins imported individually rather than as one bundle. Lottie and any heavy module dynamically imported.
- Animate transform and opacity only. Audit every animated property and list any that forces layout.
- Fonts self-hosted, woff2, font-display swap, preload only the display face used above the fold.
- Targets: LCP under 2.5s, CLS under 0.05, INP under 200ms on a mid-range phone.

Accessibility:
- Every animation honours prefers-reduced-motion, verified section by section.
- A full keyboard path through menu, overlays, slider, deck and lightbox, with a visible focus ring throughout.
- Contrast measured against the video scrim, not against a flat colour.
- Headings in order, a single h1, alt text on every meaningful image, decorative ones aria-hidden.
- Video muted and playsinline, no autoplay with sound anywhere.

i18n and SEO:
- Every string in a message file, no hardcoded copy, locale-prefixed routes, hreflang including x-default.
- Title, meta description, canonical and Open Graph per locale, plus Person and BreadcrumbList JSON-LD.
- Sitemap and robots.

Then give me a QA checklist as a table: what to test, on which device, and the pass condition.

Done when: mobile Lighthouse clears the thresholds, and the site stays usable with a keyboard alone and animations disabled.

The traps that show up on every build

  • Two animation loops. Lenis and GSAP each running their own requestAnimationFrame gives a subtly jittery scroll. One ticker, always.
  • Consecutive pins. Five independent pinned ScrollTriggers push each other around. Use one sequence, or position sticky.
  • The missing refresh. Without ScrollTrigger.refresh() after fonts and video load, every start point is wrong on a cold load.
  • The hero video. It is almost always what kills LCP. Preloaded poster, video at preload none, webm first.
  • Mobile treated as responsive. All three references write a separate mobile choreography, charlesleclerc.com goes as far as duplicating whole sections. Shrinking the desktop version does not work.
  • prefers-reduced-motion forgotten. Handle it inside the step that creates the effect, never at the end of the project.

How long it takes

With this split and a coding assistant, budget 3 to 5 days for a convincing desktop version, then as much again for mobile, performance and accessibility. The real cost centre stays the content: all three references lean on graded video and professional photography, and that is half the effect.

Related resources

All resources
WebsiteClaude

Build an Apple-style product page from A to Z (the code teardown)

Apple product pages look out of reach, yet they rest on five stackable layers that are all reproducible. This resource opens the production JavaScript bundles of iPhone 17 Pro, AirPods Pro and MacBook Pro, shows what each one actually does (hand written GLSL shaders, HLS video scrubbing, a CSS driven keyframe engine), then gives the build order and the full prompt.

›_You are building an Apple-style product page: a long scroll where the visuals are driven b
Open the sheet
WebsiteClaude

Building genuinely high-end scroll animations

Smooth scroll dropped in with three lines gives you a sluggish site that judders on pinned sections and turns annoying on mobile. Studio-grade scrolling is four distinct layers, each tuned separately: inertia, reveal, pinning, scrubbing. This guide covers all four, with the code, the values that actually work, and a teardown of three sites that get them right.

›_# Scroll motion layer: build spec # Portable: save it as CLAUDE.md (Claude Code) or AGENTS
Open the sheet
WebsiteClaude

Building a 10k website with AI: the full pipeline

A client shows you igloo.inc and asks for a quote. These sites look impossible to ship solo, yet two of the three run on a very reproducible stack. This guide gives the real teardown of all three, what a 10k budget actually buys, and the full production pipeline with Claude and the external tools around it.

›_# Protocol: build a studio-grade marketing site, step by step You are my build partner on
Open the sheet
Take action

Want us to build the site?

These resources set the tone. We can deliver the full site, fast and built to convert.

Book a callAbout us