@glowbox/nixie
v1.12.0
Published
Nixie-tube display component — a glowing vector-numeral rendering core in the glowbox family.
Downloads
428
Maintainers
Readme
@glowbox/nixie
A nixie-tube display component — a sibling rendering core to @glowbox/led-grid's LED grid. It renders a single glowing numeral the way a real nixie works: a stack of bent-wire cathodes inside a glass tube, only one lit. Each digit is a thin geometric filament (a single-stroke vector wire) that glows warm-orange with a hot core, in front of the full stack of unlit dull-metal cathode wires nested behind the honeycomb anode mesh. Zero runtime deps.
yarn add @glowbox/nixieimport { createNixieTube } from '@glowbox/nixie';
const tube = createNixieTube(canvas, { value: 7, style: 'classic', glow: 0.8 });
tube?.setValue(8);Give it a canvas + a value; it owns the 2D render, glow, and resize. A clock or counter is just a row of tubes — and the row is built in too:
import { createNixieRow } from '@glowbox/nixie';
const row = createNixieRow(container, { value: '12:34:56' });
setInterval(() => row?.setValue(new Date().toTimeString().slice(0, 8)), 250);Value
A single symbol per tube: a char 0–9, :, ., -, or null / '' for
all-cathodes-dark. setValue(v) relights it live. A longer string is truncated to its
first character (with a one-time console warning) — use createNixieRow for multi-digit
values.
Row
createNixieRow(container, opts) lights one tube per character of value
('12:34', '3.14', '-42') inside any block element, with the narrow separators
(: . -) in slimmer slots. The row owns slot sizing — tubes fill the container
height at a digit aspect and shrink to fit its width — and reads to assistive tech as
one image (aria-label = the whole string), not one per tube. All appearance options
below apply and fan out live via setOptions; row extras: gap (px between tubes,
default 6), digitAspect (digit width:height, default 0.56), separatorScale
(separator slot width as a fraction of a digit's, default 0.47), and label (row
aria-label, defaults to the value). setValue with the same string length relights
tubes in place (a ticking clock never recreates canvases); tubes exposes the live
NixieTubes; dispose() removes everything it added.
Options
| option | default | notes |
| ------------ | ----------- | ------------------------------------------------------------------ |
| value | — | the lit symbol (see above) |
| style | 'classic' | physical tube numeral shape: 'classic' · 'slim' · 'tall' |
| color | warm orange | glow colour — a Color ([r,g,b] 0..1 or any CSS string) |
| glow | 0.7 | glow strength 0..1 |
| background | near-black | tube glass colour behind the numerals |
| mesh | true | draw the honeycomb anode mesh over the tube |
| ghost | true | draw the other, unlit cathodes faintly behind — the stacked depth |
| wire | dull nickel | unlit cathode-wire colour (the filament stack behind the glass) |
| theme | 'dark' | 'light' / 'auto' bundle the colour defaults (see Themes below) |
| pixelRatio | 2 | cap on devicePixelRatio |
| bare | false | contents only, transparent canvas (no glass) — for 3D/compositing |
| label | lit symbol | accessible name (aria-label); a blank unlabelled tube is hidden |
All update live via setOptions(patch).
Sizing & backgrounds
The render is size-adaptive: at large sizes you get the full illusion (a thin
filament under a heavy bloom, behind the honeycomb mesh and the nested cathode stack); as
the tube shrinks it switches methods rather than forcing a sub-pixel wire to survive its
own blur — dropping the stack, then the bloom passes, and fattening the wire, so a tiny
tube stays a legible bold glyph. The tube draws as a rounded glass module that casts a
soft drop shadow into a transparent margin, so it floats correctly on any backdrop —
including light/white pages. (A bloom can't read against white, so the glass itself stays
dark; the shadow + glass rim, not a light glass, are what let it sit right on a light
surface.) color and background retint the glow and glass together (e.g. a blue tube:
{ color: '#57b6ff', background: '#04121f' }), and the vignette rim follows the glass
tint instead of going pure black.
3D / compositing
nixie stays 2D and depends on no 3D engine, but exposes everything a 3D scene needs so you only supply the glass + effects. Build a real bent-wire tube (reads from every angle, spins a full 360° — unlike a flat plane that thins out edge-on):
nixieCathodes()→ the full digit stack0–9in physical front→back order, each{ symbol, path, depth, offset }. Extrude every cathode'spathat itsdepth(as a z offset) and light the one matching the current value — so the whole stack is present and one numeral glows among the rest.nixieStyle(style)→{ squash: [x, y], strokeWidth }— the tube's proportions and filament gauge (usestrokeWidthas the wire diameter so 3D matches 2D).nixieMesh(w, h)→ the honeycomb anode-grille cells ({ radius, cells }) over aw×hface, to build the grille in front of the stack.glyphPath(symbol)/GLYPH_VIEWBOX→ the raw SVG centreline (d) for one symbol (e.g. the:/-separators) and its coordinate space ({ width: 60, height: 100 }, y-down).NIXIE_WIRE_COLORis the dull-nickel colour for the unlit cathodes.{ bare: true }(an option, not a helper) renders a tube's glowing contents on a transparent canvas — no glass module — for texturing onto a plane; straight (un-premultiplied) alpha,mesh/ghostindependent.
import { nixieCathodes, nixieStyle, GLYPH_VIEWBOX } from '@glowbox/nixie';
for (const { symbol, path, depth } of nixieCathodes()) {
// extrude `path` (in GLYPH_VIEWBOX coords) → your tube geometry, place at z = f(depth)
}The Svelte gallery's /nixie route has a 2D/3D toggle whose 3D scene is built entirely
from these (three.js owns only the glass cylinder + bloom).
Methods
setValue(v), setOptions(patch), resize() (after the canvas box changes),
snapshot(): string (PNG data URL), dispose().
Themes
theme bundles the housing: 'dark' (the default), 'light', or 'auto' to follow the
page's prefers-color-scheme.
A lit numeral needs dark glass to bloom against, so a nixie tube is a dark object in
both themes — what the light theme changes is the hardware around the glass: a heavier
drop shadow and a brighter rim, so the tube sits on a pale page instead of floating on
it. background and wire stay yours to set.
Part of the glowbox family of glowing retro displays — see @glowbox/led-grid (3D LED grid). Live demos: https://eetu.github.io/glowbox/.
