Cyberpunk "neon panel" SVG cards for GitHub profile READMEs. You get a square Catppuccin panel with mauve corner brackets, faint scanlines and a rolling scan beam. On load it flickers on like a CRT, and every few seconds a glitch tears a strip of the card apart with a red/cyan channel split. Text uses an embedded subset of Monaspace Neon (with Cyrillic), so it looks the same on every OS. The output is one self-contained SVG (CSS animations and SVG filters, no scripts), which works in a README <img>.
It is the shared look behind contrib-neon and the cards on sm-steel's profile.
npm i @sm-steel/neon-kitESM only, Node 22.18+. No runtime dependencies.
import { card, esc, FLAVORS, FONT_STACK } from "@sm-steel/neon-kit";
const p = FLAVORS.mocha;
const svg = card(
{
width: 418, // content box; the frame adds 16px padding (+22px with a title)
height: 72,
palette: p,
seed: "bio:code", // picks this card's glitch timing, so cards never tear together
label: "Code & Sound", // aria-label and <title>
title: "Code & Sound", // optional `// CODE & SOUND` header with a blinking cursor
font: { variant: "text" }, // embed the text font (default: "hud" when a title is set)
},
`<text x="0" y="16" font-family="${FONT_STACK}" font-size="16" fill="${p.text}">${esc("Hello, neon")}</text>`,
);Draw your content from 0,0. card() places it inside the frame. Escape any user text with esc(). To lay out several cards in one image, use cardGrid(), or give each card() its own ns.
| Export | Purpose |
|---|---|
card(options, content) |
Wraps SVG content in the full animated frame and returns a complete <svg>. |
cardGrid(options, cells), GridCell, GridOptions |
Several cards in one SVG: each namespaced (nk0-, nk1-, …), its own glitch timing, one shared font. |
CARD, cardTears(seed, area) |
Card constants (padding, title row, timings) and its seeded glitch tear. |
FLAVORS, isFlavor, PALETTE_KEYS, Palette, Flavor |
Catppuccin latte, frappé, macchiato and mocha palettes. |
fontFace(variant, weights), FONT_FAMILY, FONT_STACK, CHAR_WIDTH_EM |
Embedded font @font-face CSS, the font-family stack, and the fixed glyph width (0.62em). |
charsPerLine(width, size), wrapLines(text, maxChars, maxLines?) |
Monospace word wrap, ending with "…" when text exceeds maxLines. |
panel, brackets, BRACKET |
The square panel and the four L brackets. |
hudTitle, cursorAfter, cursorRect, HUD, hudCharWidth |
// TITLE header and blinking cursor. |
scanlineDefs, scanlines, beamDefs, beam, beamCss |
Scanline overlay and rolling scan beam. |
tintDefs, glitchLayer, Tear, GlitchSpec, TEAR_SECONDS |
Glitch tears for any element id. |
bootCss, CURSOR_CSS, REDUCED_MOTION_CSS |
Boot flicker, cursor blink, reduced-motion rule. |
esc, r3, seeded |
XML escaping, 3-decimal rounding, seeded PRNG. |
card() covers most uses. The lower-level pieces exist for custom layouts like contrib-neon's animated grid.
| Effect | Timing |
|---|---|
| Boot flicker (body) and bracket fade-in | 0.5s, once |
| Scan beam | sweeps every 6s |
| Glitch tear | one ~0.13s tear per 10s; position, shift and timing come from seed |
| Cursor blink | 1.1s |
Viewers with prefers-reduced-motion: reduce get a static card. The rule sits in the last <style> of the SVG, so it also stops animations in your own content's stylesheets. Inline style="animation:…" attributes can't be overridden, so animate content with classes instead. Light palettes (latte) use lighter scanlines and a softer beam.
| Variant | Characters | Size (WOFF2) |
|---|---|---|
hud |
ASCII | ~7.5 KB |
text |
ASCII, Latin-1, Cyrillic, typographic punctuation; regular and bold | ~14.5 KB per weight |
The font is subset from Monaspace Neon v1.400 (© 2023 GitHub, Inc.), pinned to static weights. The SIL Open Font License reserves the name "Monaspace" for unmodified fonts, so the subset is renamed ContribNeon Mono. Its copyright and license records are kept inside the font file. See fonts/OFL.txt. Rebuild it with npm run build:font, which downloads the pinned source and checks its SHA-256.
Tools are pinned with mise: mise install && npm ci.
npm test,npm run lint,npm run typecheck,npm run buildnode preview/preview.ts --serverenders sample cards in every flavor at http://127.0.0.1:8766/, shown on GitHub's light and dark backgrounds.
Releases are staged on npm from GitHub Actions via trusted publishing (no tokens) when a v* tag is pushed, and go live once a maintainer approves them with 2FA.
The code is MIT. The embedded font is under the SIL Open Font License 1.1 (fonts/OFL.txt).