spatial-scroll · loading…
@caustics/spatial-scroll · v1.0.0
svelte · react · vanilla
60fps · 22KB gzipped
$149 →
component · 002
Spatial Scroll
The scroll-driven 3D product reveal — as a declarative keyframe timeline.
Checkout coming soon Open the playground → The Everything Bundle →
Quick Start

That's it. Your site now has spatial scroll.

npm install @caustics/spatial-scroll

<script>
  import { SpatialScroll } from '@caustics/spatial-scroll';
</script>

<SpatialScroll preset="orbit" />
Configuration API

Sensible defaults. Documented types.

Prop Type Default Description
preset string "orbit" Named preset. Overrides individual props when set.
colors string[] undefined Override palette. Accepts hex, hsl, or CSS custom properties.
reducedMotion 'pause' | 'static' 'pause' Behavior when prefers-reduced-motion is active.
class string undefined Additional CSS classes applied to the root element.
What's Included

A zip. Everything else lives at caustics.dev.

caustics-spatial-scroll/
├── svelte/     SpatialScroll.svelte · index.ts · types.ts
├── react/      SpatialScroll.tsx · index.ts · types.ts
├── vanilla/    spatial-scroll.ts · compiled .js
├── docs/       README.md · API.md · CHANGELOG.md
├── LICENSE.md  Caustics Commercial License
└── package.json

Spatial Scroll is the 3D line’s flagship — the scroll-bound 3D reveal you’ve seen on flagship product pages, expressed as a declarative keyframe timeline instead of a hand-wired animation rig. You give it a GLB and a sequence of camera keyframes (or a named preset); it binds them to scroll progress and renders a quaternion-correct camera path, frame-rate-independent, with HTML captions that track 3D anchors.

It is the catalog’s first component to ship a 3D renderer, and it does so without bloating the bundle. Rather than pull in three.js (~160 KB), it owns a trimmed OGL renderer and its own GLB loader, lazy-loaded as a code-split chunk — so a page that scrolls past the section pays a few KB, and the renderer only loads when the model does. Honest, gzipped: a ~0.4 KB headline entry plus a ~2.7 KB engine and the ~19 KB lazy OGL renderer, around 22 KB per page for a plain GLB. The owned loader decodes glTF accessors, flattens the node hierarchy to world matrices, and reads embedded textures; a malformed or compressed (DRACO / KTX2) GLB throws a clear error and the engine shows your poster instead of a blank canvas.

The hard parts are handled. Camera interpolation is a shortest-arc quaternion slerp with an nlerp fallback near parallel — no gimbal flips at the keyframe seams. The scrub is frame-rate-independent (60 Hz and 144 Hz land identically). The mobile pin is computed from the ratio of measured rects, never window.innerHeight, so the iOS address-bar resize doesn’t make the pinned section jump. Captions project from 3D to screen with a behind-camera clip test. It honors the full Caustics lifecycle — IntersectionObserver and Page-Visibility gating, WebGL context-loss/restore from the cached model, reduced-motion (a held final frame), DPR capped at 2, a poster fallback when WebGL is unavailable, and an idempotent destroy(). Ships for Svelte 5, React 18+, and vanilla JS through one factory.

Ready to ship?

Checkout coming soon The Everything Bundle

Caustics Commercial License · lifetime updates within v1