glimm sweep diagram — annotated shader blueprint

glimm

glimm is a React and Next.js library for delightful shader-driven page transitions. It sweeps a single WebGL band across your screen during route changes or any state change you select. The new view appears underneath as the band moves. It is GPU-composited, under 10 KB, and has zero performance impact.

$npm install glimm

Zero runtime dependencies. React 18+ and Next 13+ are peer deps.

Installation

You can install glimm using npm, or share the following prompt with a coding agent to set it up for you.

$npm install glimm
Tell your coding agent

Add glimm to my Next.js app. 1. Install it: npm install glimm 2. In my root layout, import { GlimmProvider, InterceptLinks } from 'glimm/next', wrap the body's children in <GlimmProvider palette="prism">, and render <InterceptLinks /> just inside it: <GlimmProvider palette="prism"> <InterceptLinks /> {children} </GlimmProvider> Keep the rest of my layout markup unchanged.

Quick start

Getting started takes a single step. Wrap your app in GlimmProvider so glimm is available on every route. From there, you choose how a transition gets triggered using one of the options below. The provider stays idle until it's actually needed: it builds its one WebGL context on the very first sweep, so an app that never transitions costs nothing to set up.

app/layout.tsx
// app/layout.tsx
import { GlimmProvider } from 'glimm/next'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <GlimmProvider>{children}</GlimmProvider>
      </body>
    </html>
  )
}

Triggers

There are three ways to trigger a transition, and you can use any combination across your app. TransitionLink replaces standard links when the destination is known upfront. useTransitionRouter() handles programmatic navigation, like redirects after form submissions. Or drop in <InterceptLinks /> at the root level to automatically apply transitions to all internal links without touching existing code.

<TransitionLink>
import { TransitionLink } from 'glimm/next'

<TransitionLink href="/about" sweep={{ palette: 'berry' }}>
  About
</TransitionLink>

Presets

glimm includes 6 built-in color palettes, each tuned to a different mood using cosine gradients. Pass any palette name as a string to the palette option. If the presets don't fit your design, you can create a custom palette using the {a,b,c,d} format, covered in Custom palette below.

prism
berry
lagoon
citrus
azure
ember

Easing

Easing controls how the band speeds up and slows down as it crosses the screen. Front-loaded curves like back and easeOutQuart start fast, so the sweep feels snappy and immediate. Symmetric curves like easeInOutCubic ease in and out evenly, for a calmer, more composed feel. Pass any of the 10 built-in curves as a string, or provide your own as a (p: number) => number function.

Band width

bandTight controls how concentrated the band's gaussian falloff is. Lower values produce a wider, softer band; higher values make a narrower, more focused beam.

bandTight 14
Drag across the band to tune its width. Lower = wider, softer; higher = tighter, more concentrated.

Custom palette

Each palette is a cosine palette: color(t) = a + b·cos(2π·(c·t + d)). Each of a, b, c, d is an RGB triplet — hit Shuffle to roll one, then copy the snippet below.

custom-palette.tsx
<GlimmProvider
  palette={{
    a: [0.46, 0.88, 0.33],
    b: [0.60, 0.58, 0.74],
    c: [0.50, 0.50, 0.50],
    d: [0.54, 0.22, 0.84],
  }}
>
  {children}
</GlimmProvider>

Props

Everything you can pass to GlimmProvider (as defaults) or any trigger (as per-call overrides). Every option is optional.

PropTypeDefaultDescription
palettePaletteName | Palette'prism'6 presets or BYO {a,b,c,d}.
direction'ltr' | 'rtl' | 'ttb' | 'btt''ltr'Sweep axis + side.
easingEasingName | (p) => number'easeInOutCubic'10 built-ins or custom curve.
sweepMsnumber800Band traversal duration.
outroMsnumber350Post-traversal alpha fade.
midpointnumber0.5When routes swap mid-sweep.
peakAlphanumber1Caps band peak (0..1.5).
brightnessnumber1RGB scale; ~0.85 on dark.
bandTightnumber14Tightness; lower = wider.
waveAmountnumber1Edge wave turbulence.
rippleAmountnumber1Vertical ripple texture.
waveSpeednumber1Shader animation speed.

Best practices

glimm is recommended for highlighting moments rather than just motion. Each sweep serves as a form of punctuation, reserved for state changes that require attention while allowing the rest of the app to remain quiet.

Use glimm for:

  • Moments like publishing, submitting or completing where the action deserves a celebration.
  • Confirmed actions: a brief pause can help users notice the new state.
  • Focused modes: use it during checkout, presentations, or review screens where previous context has been replaced with new information.
  • Section-level navigation: apply it for navigation that is clearly different, not for every page change in the same area.

Avoid using glimm for:

  • Every internal navigation: although <InterceptLinks /> makes it easy to use everywhere, sweeping the screen with every click reduces its impact.
  • Passive interactions: includes hover effects, focus, tooltips, dropdowns, and menus.
  • Repeated actions in a loop: example includes adding rows, checking off items, or moving through a list.
  • Loading or skeleton states: glimm is meant for punctuation, not for spinning indicators.

To determine if a moment needs a glimm sweep, consider whether you would mention it in a changelog or launch post. If yes, then glimm is likely a good fit. If it's just “the user clicked something,” skip it. Using glimm sparingly makes the moments it does highlight more meaningful.