npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

glimm

v0.3.1

Published

WebGL sweep transitions for the web — framework-agnostic core with React and Next.js adapters.

Readme

glimm

WebGL sweep transitions for the web. A colour band sweeps across the viewport, revealing the incoming view behind it while retaining the outgoing view ahead — the iOS "name drop" feel, as a masked page transition.

  • Framework-agnostic core — drive the shader directly from vanilla JS.
  • React adapter<GlimmProvider> + useGlimm().
  • Next.js adapter<TransitionLink>, useTransitionRouter(), auto link interception.
  • Zero runtime dependencies. WebGL decoration with browser snapshots and an opaque fallback; no image assets required.
  • Respects prefers-reduced-motion and degrades gracefully when WebGL is unavailable.

Install

npm install glimm

react and next are optional peer dependencies — install whichever adapter you use. The core entry point needs neither.

Quick start (Next.js, App Router)

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

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <GlimmProvider palette="prism">
          <InterceptLinks />
          {children}
        </GlimmProvider>
      </body>
    </html>
  )
}

<InterceptLinks /> runs every same-origin link click through a sweep. Opt a link out with data-glimm-skip.

Per-navigation control

'use client'
import { TransitionLink, useTransitionRouter } from 'glimm/next'

// Declarative — a drop-in <Link> replacement:
<TransitionLink href="/about" sweep={{ palette: 'berry', direction: 'rtl' }}>
  About
</TransitionLink>

// Programmatic — a drop-in useRouter():
const router = useTransitionRouter()
await save(form)
router.push('/dashboard', { palette: 'ember' })

React (without Next.js)

import { GlimmProvider, useGlimm } from 'glimm/react'

function MyButton() {
  const { sweep } = useGlimm()
  return <button onClick={() => sweep(() => doNavigation())}>Go</button>
}

sweep(navigate, options?) plays the band, awaits your navigate callback at the midpoint, and returns a { midpoint, done, cancel } handle.

Vanilla / framework-agnostic core

import { createShader, playSweep } from 'glimm'

const canvas = document.querySelector('canvas')!
const ctrl = createShader({ canvas, /* palette, bandTight, direction */ })

playSweep(ctrl, {
  palette: 'citrus',
  onMidpoint: () => swapPageContent(),
  onComplete: () => ctrl.destroy(),
})

Alternate looks: createMeshShader (vertex-displaced mesh) and createNamedropShader (radial bulge reveal).

Sweep options

| Option | Default | Notes | | ------------- | -------- | ----- | | sweepMs | 1100 | ms for the band to cross the viewport | | outroMs | 220 | ms for the post-traversal fade-out | | midpoint | 0.56 | 0–1 progress point where onMidpoint fires | | palette | prism | preset name or a custom Palette | | direction | ltr | ltr | rtl | ttb | btt | | easing | ease | preset name or an (p) => number fn | | bandTight | — | band sharpness | | peakAlpha | 1 | caps the band's peak opacity | | brightness | 1 | 0–1.5, multiplies band RGB (dim it on dark backgrounds) | | waveAmount | 0 | 0–2, opt-in edge displacement; 0 is straight | | rippleAmount| 1 | 0–2, vertical ripple texture | | waveSpeed | 1 | 0–3, multiplies time-based motion | | swellAmount | 0.55 | 0–1, depth swell | | onMidpoint | — | fires when the band reaches midpoint — swap pages here | | onComplete | — | fires when the outro fade finishes |

Built-in palettes: prism, berry, lagoon, citrus, azure, ember. Build your own with accentPair, accentChain, or shuffleAccentPalette.

Built-in easings: linear, easeOutQuart, easeOutCubic, easeInCubic, easeInOutCubic, easeOutExpo, easeInOutQuint, snap, ease, back.

Entry points

| Import | Use for | | --------------- | ------- | | glimm | Framework-agnostic core: shader factories, playSweep, palettes, easings, colour math. | | glimm/react | <GlimmProvider> and useGlimm() for any React app. | | glimm/next | Everything in glimm/react plus <TransitionLink>, useTransitionRouter(), and interceptLinks / <InterceptLinks>. |

Import the provider and hooks from a single entry point per app so they share one React context.

License

MIT © Noman Ijaz. Free to use, modify, and distribute.

Lifecycle and cancellation

midpoint settles after the midpoint callback finishes. done waits for that work and the outro. Callback failures are logged, and handles settle without rejecting. Instant reduced-motion and no-WebGL navigation also run the per-call lifecycle callbacks.

Cancelling settles the handle and prevents any midpoint callback that has not started. It cannot undo navigation or asynchronous work that has already begun. The core cancel() preserves the current band position and alpha for a replacement sweep; when stopping without a replacement, call ctrl.setAlpha(0) or destroy the controller. The default renderer stops drawing while alpha is zero.

Next.js router calls do not return a readiness promise. The provider coordinates them through React transitions; this does not guarantee that every image, effect, or independently streamed boundary has finished loading.

Local checks

From packages/glimm, run npm test, npm run typecheck, and npm run build. The regression tests cover cancellation, callback failures, slow midpoint work, invalid timing values, instant fallback behavior, link handling, unmount cleanup, and idle rendering.

Masked React and Next.js transitions

The provider now retains the outgoing rendered view with the browser View Transitions API. The sweep is a real boundary: the incoming view is revealed behind the band, while outgoing pixels remain ahead of it. The browser's default crossfade is disabled. The iridescent canvas is a separate live transition layer.

Navigation/state updates run during snapshot preparation. The provider waits for React transition commits (including suspending updates) and a returned navigation promise before revealing the new tree. Supply work through the navigation callback; updates scheduled later by unrelated timers/effects are outside this handoff. An explicitly committed loading boundary can still be the incoming view.

When browser snapshots are unavailable or fail, an opaque, theme-aware curtain covers the view before updating it, then reveals the committed content. Its opacity is independent of shader brightness and alpha. Reduced motion and unavailable WebGL continue to use immediate navigation. An 8-second preparation timeout avoids trapping the page; it cannot cancel application requests already in progress.

The low-level playSweep API remains a decorative canvas sweep; automatic content coordination belongs to GlimmProvider. Core cancellation preserves shader state; provider cancellation now also removes its masks and clears the overlay.

Run npm run test:browser for browser pixel checks. It uses an installed Chrome (default macOS path); set CHROME_PATH for another installation. The test verifies both sides of the boundary with shader alpha set to zero, all four directions, slow Suspense commits, and opaque fallback behavior.

To inspect the local form demo at exactly 0.1× animation speed, run npm run test:slow while the site is running at http://127.0.0.1:3041. Set GLIMM_URL to use another form-demo URL. This slows the animation clock, including shader motion, and checks the expected ~13.2-second duration, monotonic mask movement, cleanup, and browser errors. Captured frames and a JSON report are written to a temporary directory printed by the command.

Use BROWSER=webkit npm run test:browser or BROWSER=firefox npm run test:browser for additional engines. Install their test binaries with npx playwright-core install webkit firefox first. Firefox's screenshot implementation omits active View Transitions (Mozilla bug 2008417), so its suite checks live mask styles and lifecycle behavior; native-window visual inspection is required for its composited boundary. Chrome and WebKit assert outgoing/incoming pixel colors in all four directions.

For native Safari or an iOS simulator, run npm run test:native and open http://127.0.0.1:3043/?client=safari (use client=ios on the simulator). The page runs manually released Suspense content, replacement transitions, cancellation, and a slow visual sweep, then saves its reports in the printed temporary directory. The visual case reports completion/cleanup; inspect the actual browser window for rendering. Native Safari automation need not be enabled.

For a production integration check against the npm tarball in an isolated Next.js app, follow the repository’s packaged fixture instructions. This checks the installed public entry points and actual server-route navigation, including slow responses, rapid navigation, history, anchors, and cancellation.