Falling lines of syntax-highlighted code as a page background, on a plain 2D canvas.
The naive version of this effect burns the frame budget on text: colouring one line
means dozens of fillText calls, times ~50 lines, times 60 fps. Here every snippet is
tokenized and pre-rendered once into an offscreen canvas, so the animation loop is
just drawImage per line. On top of that: DPR is capped at 1.5 (the text is tiny,
full retina resolution is wasted memory), and when the section scrolls out of view the
canvas backing store is released entirely instead of animating into the void.
No dependencies.
npm i code-rain-canvasimport { createCodeRain } from 'code-rain-canvas';
const rain = createCodeRain(document.querySelector('canvas')!, {
accent: [122, 140, 255], // punctuation + cursor glow, match your theme
});
// on unmount
rain.destroy();In React it's one effect:
useEffect(() => {
const rain = createCodeRain(canvasRef.current!);
return () => rain.destroy();
}, []);Position the canvas yourself (usually position: absolute; inset: 0 with
pointer-events: none inside the hero). Mouse interaction still works — the cursor is
tracked on window, lines near it brighten and drift aside, and a soft glow follows.
snippets— your own lines to rain down; defaults to a generic web-dev mix.accent—[r, g, b]for punctuation and the glow. Default[122, 140, 255].interactive— cursor glow/ripple, defaulttrue.maxDpr— default1.5.
The tokenizer is exported too (tokenize(text) → { text, kind }[]) — it's the
string-literals / keywords / types / numbers / punctuation split the highlighter uses,
and it's deliberately dumb: good enough to colour a one-liner, not a parser.
A runnable demo lives in demo/index.html — npm run build, serve the folder, open it.
MIT