Vibeset

FrontLaxWeb

Turns a landing into a web experience: parallax, scroll-driven motion and premium gestures, always at 60fps.

Cuándo se usa

When building a hero, product storytelling, or any site that should feel like a video the visitor drives with scroll, cursor or finger.

SKILL.md

# FrontLaxWeb — premium parallax and scroll-driven motion

Turns an ordinary landing into a web experience: scroll and pointer become the controller of a
continuous animation. Brand-agnostic: it takes each project's own colors and tokens. It is the pro
version of the "Animate on scroll" skill; if you only need simple, safe reveals, that one is enough.

## First, always: the intake questionnaire (MANDATORY)

Do not start building cold. Before touching a line, ask the user this questionnaire and hand back a
brief they approve. Building without context is exactly how generic design happens. If they say "just
do it", ask at least the first three. Once per project.

1. **The product in one sentence.** What is it and what does it do? What is the ONE action you want
   from the visitor (buy, sign up, read, contact)?
2. **Who for and which niche.** Who will see it? Which sector? (fintech, fashion, SaaS, portfolio, event).
3. **Tone, on two axes.** More functional (trust, restraint) or more expressive (impact, brand)? Does it
   sell fast, capture a lead, or tell a story?
4. **The brand.** Three adjectives it should convey. Colors and type if you already have them.
5. **Your taste.** Open vibeset.dev/components and vibeset.dev/concepts and name 2 or 3 effects or
   concepts you like, and why. Paste 1 or 2 sites that blow your mind. Without reference taste you get
   generic tokens, and the references come from the user, not the designer.
6. **The practical bits.** React or plain HTML/CSS/JS? Any constraints (strict performance, motion-
   sensitive audience, deadline)?

From the answers, deliver a **brief** and approve it before building: archetype and intensity, token
direction (marked "to validate" if there are no references, never invented), 1 or 2 catalog effects,
suggested components, and the three dial stops.

## The 7 effects (the catalog)

1. Smooth scroll (foundation) — Lenis. The base that makes everything feel premium.
2. Layer parallax — slow backgrounds, fast foreground: depth.
3. Scroll-linked animation — properties tied to scroll percentage.
4. Scroll reveal — enter or animate as elements reach the viewport.
5. Sticky / pin — something pins while its surroundings change (stacking cards).
6. Pointer micro-interactions — 3D tilt, lerped cursor, magnetic hover.
7. Spring gestures — drag, drop, tap: interruptible spring physics instead of fixed-duration CSS
   transitions. Distilled from Apple's WWDC motion principles collected by Emil Kowalski
   (github.com/emilkowalski/skills).

## Non-negotiable foundations (performance)

- Animate transform and opacity ONLY: GPU. Never top, left, width, height, margin.
- Reveals use IntersectionObserver, never a bare scroll listener.
- If you need the exact scroll position, read it inside requestAnimationFrame, not in the event.
- Listeners with { passive: true }.
- Safety belt: never leave content invisible at the mercy of an observer or rAF. In a background tab
  they do not fire. After load, a rescue setTimeout reveals whatever is already visible.

## The --motion-gain dial (the motion policy)

The standard move is to switch motion off when the system asks for prefers-reduced-motion. FrontLaxWeb
offers another path: instead of switching off, it scales AMPLITUDE down. One dial governs the whole site.

- Default: gain 1 — the full experience.
- System set to reduce: gain 0.25 — the same design with a quarter of the travel.
- URL with ?motion=off: gain 0 — whatever moved on its own goes still.
- URL with ?motion=full: forces 1, ignoring the system preference.

The three rules:

1. gain multiplies TRAVEL: pixels, scale, rotation, skew. In continuous effects it multiplies speed.
2. gain NEVER multiplies opacity. A crossfade makes no one dizzy, so it always shows; at gain 0 an
   effect degrades to a fade instead of an empty gap.
3. gain does NOT scale user-driven motion (drag, hover, tilt, cursor). It scales only unsolicited
   motion: parallax, scroll zoom, scrubbing, horizontal, velocity skew.

Central switch, in the head, before any animation CSS:

    <script>
    (function () {
      var h = document.documentElement;
      var q = new URLSearchParams(location.search).get('motion');
      var reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
      var gain = q === 'off' ? 0 : q === 'full' ? 1 : reduce ? 0.25 : 1;
      h.style.setProperty('--motion-gain', String(gain));
      h.classList.toggle('motion', gain > 0);
    })();
    </script>

**Accessibility, done right (WCAG, MDN, web.dev).** This policy is opinionated and only holds if:
- The **off valve** exists. WCAG 2.3.3 (AAA) requires being able to DISABLE motion, not just reduce it;
  ?motion=off is that mechanism and must always be present and discoverable. Without it you do not comply.
- Under reduce, 0.25 is a STARTING POINT. What makes people dizzy is large-amplitude motion (parallax,
  zoom, large-surface translation), not opacity. That large motion must go to ~zero or be replaced by a
  fade, not left "smaller but present". For a 16px reveal, 0.25 is plenty; for a 300px parallax it still
  dizzies: go lower or switch to opacity.
- **WCAG 2.2.2 "Pause, Stop, Hide" (level A, mandatory):** any auto-looping motion over 5s (marquee,
  background video, moving gradient) MUST have a pause or stop control. The dial does not replace it.

If the audience is sensitive or the site is functional (banking, health, forms, checkout), use the
standard off switch from "Animate on scroll".

## When to and when not to

- YES: product hero, feature storytelling, "how it works", long scrolling sections.
- NO: forms, dense dashboards, tables, checkout, legal pages, or if it drops LCP, INP or CLS.
  (Good p75 thresholds, verified 2026: LCP < 2.5s, INP < 200ms, CLS < 0.1.)
- Golden rule: the effect serves the message, not the other way round.

## What this can break: indexing (cross with SiteIndex)

Indexable first, beautiful second. If the site cannot be found, the most polished
effect is only seen by people who already knew the address.

- The content has to be in the served HTML. This is where scroll storytelling fails:
  the copy ends up inside components that only exist once JavaScript mounts. Search
  engines do render eventually, but the assistants that answer questions do not run
  JavaScript and leave empty-handed. A reveal hides with CSS something that is ALREADY
  in the HTML; it never decides whether the text exists.
- INP: smooth scroll and scrubbing intercept user input.
- LCP: a 120-frame sequence is 120 requests. Preload them separately, never ahead of
  the largest element.
- CLS: a reveal that pushes layout instead of moving with transform counts as an
  unexpected shift.

## Context rules (step 0) and the archetype matrix

Place the site on two axes before picking a single effect: functional vs expressive, conversion vs
narrative. The archetype falls out, and it decides the rest.

- SaaS / B2B — low-medium. YES reveal with stagger, sticky demo, counters, micro hover. NO scrolljacking
  or heavy WebGL. References: Linear, Vercel.
- Fintech / health — low. YES subtle fade and slide, typographic hierarchy. NO deep parallax or scrolljacking.
- E-commerce / physical product — medium. YES sticky with product scrubbing, scroll zoom. NO checkout hijack.
- Creative brand / fashion / agency — high. YES WebGL, horizontal, kinetic type, lerped cursor. NO the
  generic and timid. References: Obys, Lusion.
- Portfolio — medium-high. YES masks, magnetic hover, WebGL if you are a dev.
- Editorial / media — medium. YES scrollytelling, narrative parallax. NO hijacking.
- Launch landing — medium-high. YES hero parallax, marquee, countdown. NO long preloaders.

## Page transitions: the View Transitions API (native)

Moving from one page to another is native now, ahead of Barba.js or AnimatePresence.
- Same-document (SPA): document.startViewTransition(() => updateDOM()). Already Baseline (~90%).
- Multi-page (MPA): two lines of CSS, zero JS:

    @view-transition { navigation: auto; }
    .hero { view-transition-name: hero; }

  Covers ~85% (Chrome/Edge 126, Safari 18.2). Firefox does not do it yet but degrades to a normal
  navigation. So: never use it as the only signal of a state change, and it requires same origin.

## The kitchen sink: from a niche to a whole site

1. Context: the intake questionnaire above. The archetype and brief come from it.
2. Static design tokens: type, color scale, spacing. The easiest layer to neglect and the most
   noticeable; do it deliberately, anchored to the user's references.
3. Components: pick the pieces that set the archetype, not the flashiest.
4. Motion: one or two catalog effects, with the dial built in.
5. Close: test the three dial stops and measure Core Web Vitals.

Each layer is ruled by the one above it.

## Engines by stack (verified 2026)

- React: Motion (formerly Framer Motion; package motion, import motion/react, v13; with LazyMotion and
  the m component startup drops to ~4.6kb) plus Lenis (package lenis, ReactLenis component). Add GSAP
  with ScrollTrigger only for scrubbing, pin or SplitText. When syncing Lenis with GSAP's ticker, start
  Lenis with autoRaf: false, or you run two rAF loops at once (the classic bug).
- Vanilla: for reveals and parallax, CSS scroll-driven (animation-timeline: view()/scroll()) is 0 KB but
  it is progressive enhancement, NOT a base: Firefox stable does not ship it yet (~85%). The base state
  must be the visible one and the effect goes on top with @supports (animation-timeline: view()); if the
  base is opacity: 0, Firefox users see nothing. For scrubbing, pin or horizontal: GSAP with
  ScrollTrigger, plus Lenis.
- GSAP is 100% free since 2025 (Webflow acquisition): SplitText, MorphSVG and ScrollSmoother included.
- WebGL (Three.js or React Three Fiber): only if the brand IS the experience; opt-in with a capability check.

When you finish, say what animates, what it was built with, and what happens at the three dial stops.