Build note · Type 99 bench scope
How the bench was wired
LISSAJOUS is an XY oscilloscope with no signal generator inside it — you are the signal. Your cursor's horizontal and vertical position are the two channels; the beam plots one against the other on a phosphor screen that holds the light, and the panel measures the frequency ratio and phase of your motion and names the figure you draw.
The concept
An instrument pointed at your hand
Wave 4 is Second Person: the page is inert until you drive it. Here the bench sits dark and still with a resting dot until you move — then it becomes a measuring instrument reading you back. Move slowly in a circle and you trace a clean ellipse; oscillate twice sideways for every rise and you draw a figure-eight; scribble and the panel calls it what it is: noise. It is built for anyone who has ever watched a scope in XY mode and wanted to be the waveform.
Palette · argued from the tube
Phosphor green on scope black
Every colour comes from a real cathode-ray tube, not a mood board. Bright green is reserved for the beam, marks, and rules; small body text uses a softer phosphor-grey ink so nothing bright sits on the busy screen.
Type
A display face and a lab face
ArchivoDisplay · UI
A grotesque with real presence at heavy weights — the wordmark, headline, and figure name. Set tight and dark for the second-person address.
JetBrains MonoInstrument
Every measured quantity, label, and readout. A monospace makes the tabular numbers line up like a real front panel and never jitters as values change.
Techniques
What draws the glow
- Canvas 2DTwo stacked canvases: a static graticule underneath, and a transparent beam layer on top.
- PersistenceEach frame the beam layer is decayed with a translucent destination-out fill and the new segment redrawn with lighter (additive) compositing — real phosphor afterglow and self-brightening crossings, with the grid showing through.
- MappingCursor position is normalised against the central square of the viewport, so a circular hand motion reads as a circle rather than the viewport's ellipse.
- FrequencyEach channel's mean-crossings over a 1.5 s window give its frequency; the ratio reduces to small whole numbers.
- PhaseThe Pearson correlation of the two channels is the cosine of their phase difference — out of step is a circle, in step is a line.
- NamingRatio, phase, and a steadiness score choose the figure's name and light LOCK; low steadiness collapses it to noise.
The signature is honest phosphor. There is no video and no pre-baked path: sixty times a second the beam eases toward your pointer, its position is pushed into two ring buffers, the whole screen dims a fraction, and only the newest bright segment is painted back additively. Turn up persistence and the fade shrinks, so your loop stays lit longer; leave the mouse and the light decays to the resting dot and the readout drops to No signal.
Iteration log
Three passes, each driving the beam
01 Craft
- Set a deliberate type scale and reserved bright phosphor for marks only — body copy moved to a #CFE6D6 ink and mute labels lifted to #7C9C88 to clear 4.5:1 on scope black.
- Rebuilt the graticule to a true 10×8 division grid with brighter centre axes and 0.2-division tick marks, plus corner instrument tags (XY, P31, 1 V/DIV) on the static layer.
- Tightened the readout panel to tabular-nums so the amber values stop jittering as they update, and gave the CRT a curved-glass vignette and reflection.
02 Depth
- Enriched the signature: additive layered strokes (soft halo + bright core) and a velocity-scaled head glow, so slow moves lay a clean bright loop and fast moves streak — the built-in "scribble = noise" feel.
- Added the persistence knob as the one working control — a genuine micro-interaction that changes the phosphor decay rate live.
- Second-read details: a procedural Lissajous atlas (six figures drawn from the real equations in SVG, with a subtle hover-lift) and a LOCK lamp that lights only when your motion is clean and low-ratio. Credited Bowditch, 1815, in the atlas note.
- One tasteful micro-interaction: the figure cell throws a single amber glow-pulse the instant your motion locks onto a figure — fired only on the unlocked→locked transition, never repeating.
03 Hardening
- 375 px: hero stacks, readout reflows to a 2-column grid with the figure cell spanning full width, atlas drops to two columns. Caught the model sub-line shoving the nav off the right edge of the fixed masthead (a false pass for a scroll-width probe) and hid it below 480 px — verified no element crosses the viewport box.
- Driving the beam in headless Chrome ten times over exposed an intermittent misread — a clean circle occasionally naming itself 5:4 because the frequency came from raw integer crossing-counts that wobble ±1 at the window edges. Rebuilt it to read frequency from the median interval between sub-frame-interpolated crossings, smoothed over time, and biased the ratio fit toward the simplest whole numbers. Ten further runs: a stable 1 : 1 every time.
- Reduced-motion path: no bloom, no idle breathing; the loop settles the readout to Standing dot then freezes when still, and resumes only on movement. DPR capped at 2, canvases resize, loop pauses on document.hidden. Removed one excess ornament (the redundant in-screen DC tag).
Colophon
Self-contained: one HTML file, inline CSS and JS, canvas 2D, no build step, no raster images, no third-party libraries. Fonts from Google Fonts. Every glow is computed live from your cursor.