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

coaurora

v0.2.0

Published

A WebGL aurora background that is, internally, a Store comonad. Zero dependencies.

Readme

coaurora

A WebGL aurora background that is, internally, a Store comonad.

Zero dependencies · ~6 KB · WebGL2 two-pass renderer with a Canvas-2D fallback · band-free on any display.

Live demo →


Install

npm i coaurora
import { aurora } from 'coaurora';

const bg = aurora();              // full-page green aurora behind your content
bg.set({ speed: 0.8, tilt: 30 }); // live-tweak
bg.stop();                        // tear down

Or straight from a CDN, no build step:

<script type="module">
  import { aurora } from 'https://esm.sh/coaurora';
  aurora();
</script>

Options

aurora('#bg', {
  curtains: 16,          // number of curtain bands
  hue:      [85, 165],   // colour band [low, high] in degrees — green → teal
  thickness:0.6,
  brightness:1,          // line brightness — scales the curtains; the floor is untouched
  speed:    1,
  blur:     1.5,         // the comonadic 3×3 neighbourhood radius (0 = off)
  tilt:     22,          // degrees
  floor:    '#030503',   // lifted black floor
  dither:   true,        // TPDF blue-noise temporal dithering (kills banding)
  fps:      30,
  reducedMotion: 'auto',
});

Presets: aurora('#bg', { ...presets.ice })jagajaga (green), ice, ember, violet.


The background is a comonad

A Store s a is a pair: a function peek : s → a and a focused position pos : sa value of type a living in a space s, with one position singled out. Here s = Coord (a pixel) and a = Colour, so the aurora is a Store Coord Colour: the whole green field, plus the pixel we're looking at.

extract w    = w.peek(w.pos)                      -- the colour under the focus
extend  f w  = Store(p => f(seek(p, w)), w.pos)   -- recompute the WHOLE field,
                                                     each point free to consult
                                                     its neighbourhood
seek  p w    = Store(w.peek, p)                    -- move the focus

extend is the dual of monadic bind: instead of sequencing effects it spreads a local computation across every position. The whole picture is a pipeline of extends, read off at each pixel:

picture = extract . extend dither . extend blur . extend curtains $ positions
  1. extend curtains — light the 16 Gaussian curtain bands at every position.
  2. extend blur — average each point's 3×3 neighbourhood (peeks). This is the canonical comonadic op — genuine neighbourhood work, not just fmap.
  3. extend dither — add blue-noise (below).
  4. extract — read the colour out at each pixel.

A fragment shader is this comonad

| comonad | GLSL | |---|---| | peek | the shader body | | focus | gl_FragCoord | | extract | evaluating one fragment | | extend f | the GPU dispatching f over all fragments |

So the GPU renderer is the comonad, compiled — as a two-pass pipeline:

  • pass 1 renders extend curtains into an off-screen texture — the Store, materialised;
  • pass 2 is extract . extend dither . extend blur, where the texture sampler is peek, a neighbour tap is peeks, and the 3×3 average is extend.

The src/cpu.js fallback spells the same thing out in plain JS with Store / extract / extend / seek. Read src/store.js and src/shaders.js.


Why it never bands

Smooth dark gradients band on 8-bit displays. coaurora fixes it the way signal theory says to:

  • TPDF dither, 2 LSB. Triangular-PDF noise (two summed uniforms) makes the quantization error's mean and variance independent of the signal — the formal condition for no contouring.
  • Applied last, right before the 8-bit write (no blur after it to average it away).
  • Blue noise (interleaved-gradient), so the residual noise sits above the eye's sensitivity peak — invisible grain.
  • Temporal: the pattern shifts each frame by a golden-ratio offset; your eye integrates ~3–4 frames toward the true value → ~1–2 extra effective bits.

Bonus: the screensaver

The aurora turned out to be a pretty good screensaver — so it's also one. Native macOS (Swift + Metal, rendering at 16-bit float with an extended-sRGB colorspace: a true 10-bit+ path no browser allows) and Windows (.scr, C + OpenGL, running the web shader near-verbatim). It lives on the screensaver branch, with prebuilt binaries on the releases page.

Notes

  • The canvas sits at z-index:-1, so keep your page's backdrop on html (or leave body transparent) — an opaque body background would paint over it.
  • Honours prefers-reduced-motion (renders one static frame).
  • Render resolution tracks device pixels, capped at resolutionCap to keep the GPU honest.
  • The curtains are analytic, so the GPU path is one curtain evaluation per pixel plus a cheap blur pass.

License

MIT © Arseniy Seroka (jagajaga)