Colophon · how it was made
Queue A single-server line, simulated event by event, and the arithmetic that makes it explode.
Queue is a live M/M/1 queue: customers arrive at random and one server works them off at random. The page's single job is to make one counter-intuitive fact physical — that a line does not degrade gently as it fills. Push utilisation ρ toward one and the mean wait rockets along a 1/(1−ρ) wall. The audience is anyone who has watched a checkout, a call centre, or a server melt down at what looked like reasonable load.
Mean time in the system for M/M/1. At ρ = 0.85 that is 6.7 service-times; at ρ = 0.97 it is 33; at ρ = 0.99 it is 100. The last few percent of utilisation cost more than all the rest combined.
01 Palette
A dark operations terminal, not a spreadsheet. Teal is reserved strictly for the healthy marks — the ticks in the line, the curve, the floor — while a single red-orange carries every signal of strain, so the eye reads overload as heat spreading through the board.
Per the collection's ink/line rule, the bright teal is a marks-only token. Copy is set in board ink #D8E0E2 and secondary labels in #8B989E, both comfortably past 4.5:1 on the slate.
02 Type
A grotesque with a variable width axis. The wordmark runs expanded (~122% stretch, 800 weight) for a machined, signage feel — the one moment of typographic bravery.
Every number — ρ, queue length, wait, the axis ticks — is monospaced and tabular so readouts don't jitter as digits change under the running simulation.
03 Technique
Everything is procedural: no images, no libraries. The board is a single <canvas> driven by one requestAnimationFrame loop; the copy and readouts are plain DOM for crisp text and accessibility.
The discrete-event core
Under the animation runs a genuine M/M/1 event simulation, not a scripted loop. Service rate is fixed at μ = 1; arrival rate is λ = ρ·μ. The engine holds two scheduled events — the next Poisson arrival and the current exponential departure — and advances simulated time, processing whichever comes first: an arrival joins the tail (or seizes an idle server); a departure frees the server and pulls the next waiter forward. Inter-event gaps are drawn as −ln(1−U)/rate. Time-averaged queue length is integrated exactly across event boundaries, and each departure banks its sojourn, so the live L and W readouts converge to the theoretical values rather than being faked.
The signature
The rendering interpolates each customer toward its slot so the line visibly lengthens and shuffles. Beside it sits the law itself: the W = 1/(1−ρ) curve with a glowing operating point that climbs it. Drag ρ up and two things happen at once — the physical line strains and overflows leftward while the point rockets up the curve toward the dashed ρ→1 asymptote, both bleeding from teal to ember. Cause and consequence in one frame. At rest ρ sits at 0.85 with a long line already stacked, so the static thumbnail reads instantly.
Robustness
DPR is capped at 2; a ResizeObserver-free resize handler re-fits the canvas to its container; the loop pauses on document.hidden and clamps its delta on resume so a backgrounded tab doesn't fast-forward the sim. prefers-reduced-motion halts the rAF loop entirely and paints one settled static frame (still fully interactive via the slider). A missing 2D context falls back to a typeset explanation of the formula.
04 Iteration log
- Drove the slider across its range. At ρ ≥ 0.9 the measured W lagged badly because accumulators kept averaging in the old regime — reset the L/W integrators on every ρ change so readouts re-converge to the new law within a couple of seconds.
- Tightened the readout grid to four tabular cells with a theoretical "→ target" sub-line, so measured-vs-analytic reads at a glance.
- Rebalanced the type scale: expanded the wordmark to 122% width / 800 and pulled the promise line up to a real sub-head rather than caption size.
- Added the occupancy history sparkline. The board had dead vertical space, and near ρ=1 the M/M/1 line only fills over long timescales, so a single physical row read thin. A scrolling in-system, last 22s area-chart now sits under the line — it visibly breathes at 0.85 and slams to a high plateau at 0.97, carrying the "straining" story even when the instantaneous line is short.
- Enriched the signature. Added the operating-point dot with dashed guide-lines onto the W-curve, and a gradient that turns the curve ember near ρ=1 — the second-read detail is that the line, the sparkline and the curve all strain from teal to ember together.
- Gave the server box a live service-progress fill driven by the scheduled departure time; added an overflow "+N" marker, a status pill (stable → busy → straining → overloaded), and made dragging ρ snap the visible occupancy to the new regime's mean so the line responds instantly.
- 375px: the canvas layout switches from side-by-side to stacked (queue over curve); readouts drop to a 2×2 grid; the slider wraps to full width. Verified nav and wordmark stay inside the viewport with a clean scrollWidth.
- Reduced-motion: confirmed the rAF loop never starts, a settled frame is painted, and the slider still re-renders single static frames.
- Removed one ornament (Chanel rule): dropped the row of decorative floor tick-marks under the queue — they added texture but competed with the customer ticks. Also re-keyed the strain colour to ρ (the regime) rather than raw count, so the line stays teal at 0.85 and reserves ember for the true blow-up near one.
- Re-checked: SPEED tuned so the seeded line stays visibly long through a 7s thumbnail settle; focus states, DPR cap and visibility-pause verified; console clean at every ρ.