Design reference

Moving parts — all of them, in one place.

Part one renders the shipped motion behaviors live, from the real primitives in public/motion.css and public/app.js. Two shipped behaviors are deliberately not demoed here: [data-parallax] needs real scroll depth to read as anything (it ships on the home hero), and the carousel's lc-coverflow / lc-scroll-progress are demoed on carousels rather than duplicated. Part two maps the design_system/motion system catalog to what we could still adopt. Sibling of the hero sections, section gallery, backgrounds, and icons references.

01

Reveal on scroll Guide

public/motion.css · public/app.js · 420ms · --motion-duration-scroll · ease-out / emphasized

The one we lean on most. Things opt in with data-reveal and start hidden and shifted. A watcher in app.js adds .is-revealed as they scroll into view. The way they move is set by data-reveal="up|down|left|right" (default up). The vanilla equivalent of the design-system RevealOnScroll primitive.

data-revealup (default)
data-reveal="down"down
data-reveal="left"from the right
data-reveal="right"from the left
02

Stagger groups Guide

public/motion.css · public/app.js · +50ms per child · --motion-stagger-normal

A data-reveal-group makes its children come in one after another. app.js sets a delay of 50ms per item, to match --motion-stagger-normal. We use it on card grids, check lists, and top panel rows.

Capture
Campaigns
Follow-up
Reporting
Review
03

Ambient hero loops Delight / Wait

public/motion.css (keyframes) · public/styles.css (consumers) · 2.4s–16s idle loops · transform / opacity / paint only

The soft moving layer behind the top blocks. Five moves, all set inside the no-preference rule, so they do not exist at all if you ask for less motion: lc-drift, lc-aurora, lc-pulse, lc-sweep, and lc-gradient-pan.

lc-drift · 6–7s float · used by .hero-proof-mark and hero visual cards
Aurora
lc-aurora · 16s glow mass · behind .interior-hero-panel, capture/checklist/proof cards
Live
lc-pulse · 2.4s opacity pulse · the .hero-frame-chip--live status dot
Sweep
lc-sweep · 5s accent-line sweep · the .hero-compact-band top edge
qualified conversations
lc-gradient-pan · 8s paint-only pan · the .hero-highlight headline phrase
04

Pointer glow Focus

public/motion.css · public/app.js · 260ms fade · --motion-duration-slow · hover devices only

A soft light that follows your mouse across a panel. Opt in with data-pointer-glow; app.js tracks the pointer into --lc-pointer-x/y and gates the whole behavior off for reduced motion and non-hover devices. The glow layer is pointer-events: none — light, never a blocker.

Move your cursor across this panel.

On a phone, or with less motion turned on, this panel stays still on purpose. The glow is a nice extra for a mouse, never a must.

05

Header elevation Orient

public/app.js · public/styles.css (.site-header.is-scrolled) · state toggle at 8px scroll · rAF-throttled

The header starts clear, then turns solid and lifts once you scroll down — app.js toggles .is-scrolled on [data-elevate] past an 8px threshold, throttled through requestAnimationFrame. You're looking at it: scroll this page.

06

Hover & press microinteractions Focus / Confirm

public/styles.css (hover, press, and focus-ring transitions) · 120–260ms · --motion-duration-fast/normal/slow

Buttons lift and change color. Cards rise. Links get a line. Boxes get a ring when you tab to them. All plain CSS, and all under the 240ms cap our ease-of-use rules set.

Hover this card. It lifts and its edge warms, the same way every service card does.
07

Link underline wipe Focus

public/styles.css (.footer-col a) · 180ms · --motion-duration-normal · emphasized

The footer's own motion language, and the closest thing the site ships to the catalog's selection-underline recipe: the label nudges 3px along its track while a teal hairline wipes in beneath it, scaleX(0→1) from the left. Two properties, one direction, no layout work — hover and :focus-visible fire identically, so it reads the same by keyboard.

08

Accordion disclosure Orient

public/motion.css ([data-disclose]) · FAQ + /pricing · 260ms · --motion-duration-slow · standard

Every FAQ on the site is a native <details>. It used to snap open; now the panel's own auto height interpolates via ::details-content + interpolate-size, with opacity following at 180ms — no wrapper element, no JS, and the native disclosure semantics untouched. Browsers without ::details-content keep the instant open, which is a correct resting state.

Open and close me

The panel's own height is what moves. No wrapper, no measured size, no JavaScript. The arrow spin was already there at 160ms. The height and fade are the new bit.

And me — they're independent

The built-in <details> keeps its keyboard and screen-reader behavior just as it was. This only adds movement when it opens.

09

Pop-up entrances Orient

public/styles.css (popup-fade, popup-rise) · /pop-ups · 250ms fade + 300ms rise · ease-out

Every pop-up on /pop-ups comes in the same way. The back layer fades in over 250ms while the card or bar rises 0.5rem over 300ms. Both stop dead if you ask for less motion.

10

Checkout loading shimmer Wait

public/styles.css (checkout-skeleton) · /checkout · 1.3s linear-feel loop · background-position only

While the card box loads, the empty space shows a slanted shine that sweeps across. Nothing shifts or resizes, so the wait reads as "loading", not "broken". Paired with status text, never spinner-only.

11

Chat panel entrance Orient

src/components/ChatWidget.astro (lc-chat-in) · 160ms ease-out · opacity + translate + 2% scale

The env-gated chat widget's panel pops in from its launcher corner — 8px rise, 0.98→1 scale, transform-origin bottom-right. The demo below mirrors the real keyframe (the widget's own styles only load when the widget is enabled).

12

Process-rail scroll choreography Guide

public/motion.css ([data-rail]) · public/app.js · public/styles.css · 420ms per segment · --motion-duration-scroll · standard

The numbered process rails on /services, /tools, /launch-kit, and every niche page now carry a progress spine that draws as you read them: a container opts in with data-rail, app.js observes its direct children, and each step that scrolls in advances --rail-progress a fraction toward 1 while CSS scales the line. Scroll choreography from the catalog's blueprints, built on the observer we already ship rather than a scroll library — no scroll hijack, and the steps read fine with the line at zero. See it on /services →

  1. 1

    Audit

    Each step that scrolls in moves the line along.

  2. 2

    Build

    Progress is steps-seen ÷ steps-total.

  3. 3

    Launch

    One transition per segment, 420ms.

  4. 4

    Tune

    Never scrubbed to raw scroll position.

13

Cross-document route fade Orient

public/motion.css (@view-transition) · 140ms · opacity only · native view transitions

Page-to-page navigation cross-fades instead of flashing white. This is the catalog's route-fade variant in its CSS multi-page form — deliberately NOT Astro's <ClientRouter />, which would swap documents without re-running the deferred app.js and would silently break the reveal observer, theme toggle, header elevation, pointer glow, and the form engine. Browsers without view transitions navigate exactly as before. It can't be demoed in place — it only exists between documents. Navigate to /section-gallery and come back to see it.

14

Hero 3D canvas backdrop Delight

src/scripts/hero-scene (design_system/three-system) · idle loop · balanced preset · WebGL-gated

The home hero renders a vanilla Three.js scene behind the copy, authored against the design-system three-system contracts: balanced preset, mounts only when WebGL is available, idles only while visible, and holds a static pose under reduced motion. The DOM hero is the fallback, so the headline never waits on it. Not re-mounted here — see it on the home page. View it on the home page →

15

The safety nets Governance

public/motion.css · public/app.js · site-map search · always on

The layer that keeps all of the above honest: a no-JS failsafe (lc-reveal-failsafe) reveals everything at 1.2s if app.js never runs; prefers-reduced-motion stills every animation via CSS and short-circuits the observer and pointer glow in JS; hover effects are gated to hover-capable devices; and JS-driven smooth scrolling (the site-map search jump) falls back to instant under reduced motion.

What we could adopt next

The motion set, matched to this site.

design_system/motion system/ is a catalog of governed motion collections. Its React and runtime packs can't run on this vanilla Astro site — anything adopted gets vendored as a vanilla equivalent, the way the reveal layer already was. Each card names the collection, its adoption status here, where it would land, and the governance constraint that comes with it. Cards with a live demo build it from the vendored tokens.

P1

Microinteraction recipes Not adopted

CSS (vanilla equivalent of the Motion pack) · Microinteractions/Motion/microinteraction-recipes.json

The site's forms confirm success and flag errors with text alone — correct, but the catalog's confirm and focus recipes would let a saved state pop a small check and an invalid field nudge sideways, with the text staying the primary cue. All four recipes in the pack are demoed below: button-confirm-pop, field-error-nudge, selection-underline (a selected tab's rule wiping in from 72% — the selection sibling of the shipped link underline wipe, which is the only form of it the site has today), and saving-shimmer (a background save, distinct from the shipped checkout skeleton: it tints a control that already has content rather than standing in for content that isn't there yet). All token-built and under the 240ms cap.

Where it lands: The contact, class, and booking forms. Quiz and tool sends. Checkout box checks. And the step pickers on /tools and the quizzes.

Constraint: Confirms stay under 220ms and focus nudges under 240ms. Movement is never the only sign. The words and icons still say what happened.

Saved you@example — invalid email
Saving your answers…
P2

UI Motion variants & unused primitives Partially adopted

CSS Motion pack · UI Motion/Motion/motion-variants.json · ui-motion-primitives.css

Two of the pack's four variants are now live. route-fade shipped as a cross-document view transition (see the shipped specimen above), and the orphaned data-reveal="scale" primitive — vendored into motion.css but with zero usages on any page — now drives the /pricing tier cards, so the plans scale up into place instead of sliding. What's still open is panel-enter and dialog-scale, demoed below: the overlay layer uses its own popup-rise pair rather than these, and no panel or tab surface consumes them yet. The spring tokens (--motion-spring-*) are also vendored but unconsumable in pure CSS; they'd matter only if a JS motion engine is ever adopted. Two more primitives sit in the same orphaned state data-reveal="scale" was in, and are named here rather than left for the next sweep to rediscover: .page-progress (motion.css, geometry in styles.css) and [data-ticker-row]/.ticker-row (same pair) are both fully built and consumed by nothing anywhere in src/ — they arrived under the HOME SCROLL STORY banner and no page ever opted in.

Where it lands: Panel and tab changes on /tools and the quizzes, plus loading screens outside checkout.

Constraint: Screen changes stay under 360ms, and only fade or shift.

data-reveal="scale"no longer unused. It now drives the /pricing plan cards
panel-enter 220ms · opacity + 12px rise. Where it would land: the /tools panel switcher and the quiz step body.
dialog-scale 180ms · opacity + 0.98→1 scale. Tighter and more centred than the popup-rise pair the overlays use today.
P3

Complex scroll choreography Partially adopted

GSAP contracts → hand-rolled vanilla · Complex Scroll Effects/GSAP/scroll-choreography-blueprint.json · scroll-trigger-safety.json

The step-by-step explainer half of this is now live — see the process-rail specimen above. The GSAP runtime still can't ship here (flat nginx root), so the choreography rides the IntersectionObserver we already have, exposed as a generic [data-rail] primitive any container can opt into. The demo below is that same line-draw. What's still unadopted is the comparison-reveal blueprint (two columns resolving against each other as you scroll) and anything scrubbed continuously to scroll position rather than stepped.

Where it lands: Already live on the step rails (/services, /tools, /launch-kit, trade pages). Still to do: price plan reveals and long explainer runs.

Constraint: Scroll bits stay under 700ms. We never take over your scrolling. And nothing is hidden from the page's real order.

1 · Audit
2 · Build
3 · Launch
4 · Tune
P4

Illustration animations Not adopted

Lottie (or a static-step-stack fallback) · Illustration Animations/Lottie/workflow-progress-lottie

The set has a step-by-step Lottie for showing how a flow works. A Lottie player is a real weight on a small site. So the plain step stack is also the cheap first take. Steps that show up one by one read like a moving explainer and cost nothing. See it below.

Where it lands: Getting started, empty /docs screens, and the what-happens-next on the class page.

Constraint: Any Lottie needs a still picture for less-motion mode. Load the player late, and keep it below the top of the page.

Form submitted
Lead routed to follow-up
Call booked on the calendar
P5

3D product stage Partially adopted

Three.js (vanilla, via three-system contracts) · 3D Experiences/orbital-product-stage · orbital-product-stage-animation

The home top block already uses the 3D set. The next step is the slow-spin product stage: a gentle turning showcase for the product page, with a plain fallback for slower devices.

Where it lands: /products gallery hero; the Launch Kit offer page.

Constraint: A still picture if you ask for less motion. A plain fallback when 3D is not supported. And never above the main headline.

P6

Marketing video loops Not adopted

MP4/WebM · Marketing Videos/launch-overview-video-kit · marketing-video-render-profiles

The video and class paths are built but still show stand-in videos. The set spells out the sizes and formats for launch loops and explainers. A quiet, poster-backed loop is the one move these paths still lack.

Where it lands: /vsl (the sales video itself), /webinar room, a muted launch loop on the home proof band.

Constraint: poster-fallback is mandatory; autoplay only muted; loops pause when off-screen; route large renders through the media pipeline, not the repo.

P7

Heavy physics / particle fields Available, likely overkill

Three.js / WebGPU · Heavy Physics/particle-field-webgpu

The set has a heavy 3D dust-cloud scene for fancy moments. For a lead site, it costs more than it gives. We list it so you know it exists, not because we should use it.

Where it lands: Nowhere yet. A push or a launch moment at most.

Constraint: static-particle-poster fallback mandatory; WebGPU support is still uneven; never beside task UI.