@caustics/transition-flow · v1.0.0
svelte · react · vanilla
60fps · 20KB gzipped
$129 →
component · 0015
Transition Flow
Choreograph transitions between images — slider and before/after, in WebGL.
Checkout coming soon Open the playground → The Everything Bundle →
Quick Start

That's it. Your site now has transition flow.

npm install @caustics/transition-flow

<script>
  import { TransitionFlow } from '@caustics/transition-flow';
</script>

<TransitionFlow preset="liquid" />
Configuration API

Sensible defaults. Documented types.

Prop Type Default Description
preset string "liquid" 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-transition-flow/
├── svelte/     TransitionFlow.svelte · index.ts · types.ts
├── react/      TransitionFlow.tsx · index.ts · types.ts
├── vanilla/    transition-flow.ts · compiled .js
├── docs/       README.md · API.md · CHANGELOG.md
├── LICENSE.md  Caustics Commercial License
└── package.json

Transition Flow is the bigger sibling of Distortion Hover. Where Distortion Hover warps one image under the cursor, Transition Flow choreographs transitions between images: a complete load → cover-fit → transition → sequence pipeline rendered on a single WebGL plane, with a curated catalog of 21 hand-tuned GLSL transitions, an autoplay slider/carousel, and a draggable before/after compare mode.

The transition catalog is a “house style” — quality over quantity, every one tuned to feel premium rather than a me-too dump. There are clean fades and a film-bloom crossZoom; feathered wipes (linear, radial, diagonal); a smeared directionalWarp, a noise displace, and a molten liquid curl-flow; ripple, dissolve, and morph; the digital trio rgbGlitch, glitchBlocks, and pixelate; the classic push, slide, and reveal; iris circleOpen/circleClose; a 2D card flipX; and a swirl vortex. Six presets — liquid, glitch, softFade, editorial, compare, kinetic — each bundle a transition, easing, duration, and tuning into one finished look you apply with a single prop.

The hard part of an image transition is cover-fit, and this is where most snippets fall apart. Each texture is cover/contain/fill-fit against the container independently, so a portrait and a landscape image transition inside one box with zero positional jump at progress 0 and 1 — across any aspect-ratio mismatch. That is the difference between an engine and a shader snippet you paste from a CodePen: the snippet assumes two images of identical dimensions and breaks the moment they aren’t.

It carries the full Caustics lifecycle. The render loop idles to zero frames between transitions — a resting slider costs nothing. A windowed texture budget decodes the current image and its neighbors eagerly while an LRU cap keeps no more than eight GPU textures resident, so a fifty-image gallery never holds fifty uploads. It degrades cleanly everywhere it must: no WebGL falls back to a plain <img> opacity crossfade that keeps the slider working; a CORS-tainted texture shows the original image with an error event rather than a broken canvas; and prefers-reduced-motion turns every image change into an instant cut — never blank, never a hard-failed canvas. IntersectionObserver pauses it off-screen, ResizeObserver re-fits cover on layout change, it survives WebGL context loss and restore, caps device-pixel-ratio at 2, and destroy() releases the GPU context and restores your original <img> DOM untouched.

Both playback modes ship complete. The slider has next/prev/goTo returning promises, autoplay with pause-on-hover, loop, pointer swipe, and a full keyboard + ARIA carousel. The compare mode is a draggable before/after handle — keyboard and touch accessible — that uses the transition shader as the reveal, so the seam between before and after can be a liquid wipe rather than a hard clip. Headless by default; the optional ui layer (arrows, dots, progress) is thin and opt-in. Ships as plain ESM for Svelte 5, React 18+, and vanilla JS, with a [data-flow] auto-init for no-build pages.

Ready to ship?

Checkout coming soon The Everything Bundle

Caustics Commercial License · lifetime updates within v1