▮ Plasma Gases

Gas emitting directly. No phosphor in the stack.

Plasma gases
▯ CRT Phosphors

A beam on a phosphor, which emits and then persists.

CRT phosphors

General purpose · built to be read

Specialized · built for an instrument

Switches

Simulation · never a color

Style & engine · never the hardware

The retrace band is part of the CRT simulation, and there is no sweep across a plasma panel to switch off.

JS Effects need the CRT simulation and a phosphor that holds long enough to see.

State
Technology
PLASMA
Emitter
NEON
Emission
585.2 nm
Mode
PRESET
Engine
CSS + JS
Technology

A gas in a sealed gap, struck by a sustain pulse. It emits directly — no phosphor in the stack — so the panel lights one hue and varies only how hard it is driven.

The gas the plasma panel was actually built on, and what this framework opens to. In a low-pressure glow the 2p→1s array dominates — the lowest excited states that radiate visibly, populated far more heavily than anything above them — so the discharge is one narrow orange-red rather than a mixture. Nixie tubes and the first flat panels ran on it.

A preset sets the display and its simulation. Everything stays adjustable — and Reset puts all of it back, switches, styles and engine alike.
04 AMBER CONSOLE · SYSTEM GUIDE

AFTERGLOW & PERSISTENCE

Nothing on either technology goes dark on the next refresh, and they do not go dark for the same reason. Persistence is eight separate phenomena — four of them pure CSS.

AFTERGLOW AND PERSISTENCE

A gas gap that stops being driven leaves excited and metastable atoms behind, and that population keeps emitting while it relaxes and recombines — an afterglow that is a property of the gas and of no coating at all. A phosphor is the opposite case: the persistence is the coating, it is what the compound was chosen for, and it ranges over four orders of magnitude between the parts on the board above. Most of the light is gone early either way, then a tail whose length is the whole difference between them. .ac-afterglow is that relaxation, and it is several separate things because persistence is eight separate phenomena. Four of them are pure CSS, two need JavaScript outright, and two arrive by both routes — and where JavaScript is needed it is not being withheld, the thing is genuinely not expressible in a stylesheet. Nothing in the cascade remembers the string a readout held one frame ago; scroll velocity cannot be derived from a scroll timeline, which exposes position only; and startViewTransition is the one API that hands you a picture of the screen you just replaced without navigating away from it. Those three capabilities live in amber-console.effects.js, which is optional and separate from amber-console.js — the stylesheet alone still decays, de-energizes, throbs, sweeps, and drains a whole page into the next one.

How long it lasts belongs to the emitter, not to this file. A palette that knows its own decay declares it, and every timing below is derived from that one number — so the panel does not have a persistence setting, it has whatever persistence the hardware in it had. Which is also why persistence and flicker are the same number read in two directions: a screen redraws every frame, and what is still lit when the next frame arrives is the smear while what is missing is the flicker. A screen cannot be steady and smear-free at once. P11 is fully dark between frames — no persistence, maximum flicker, which is why it was fitted to tubes meant to be photographed rather than watched. P39 is still at 91% — no flicker at any refresh rate, paid for in smear, which is why it went on radar. Both come off one decay constant and cannot disagree.

WHAT A LONG PHOSPHOR COSTS

Two consequences worth knowing before the switches surprise you. The long phosphors are capped where you wait on them and uncapped where you do not: P7's tail is three seconds, which is correct and would be an unusable dialog close, so anything that has to actually leave is clamped to 250ms and the ghosts run the full three. And a long-persistence phosphor does not decay exponentially — it follows a power law, a fast knee over a very long tail, which no single easing curve expresses. Those palettes ship a linear() sampled from the decay model itself.

P7 is the one that is worth turning on. It is two coatings rather than one: the beam writes into a blue layer that decays in microseconds, and that layer's own photons pump a yellow-green layer behind it that holds for seconds. So the ink is blue and the halo is green — text you are reading is being re-struck sixty times a second, and text that stops being written leaves only the glow behind. It is the only palette here whose halo is a different spectrum from its ink, which inverts a rule the rest of the system relies on, and it is the reason a radar sweep is still legible when the beam comes round again.

1 · DECAY-OUT — CSS Anything that disappears drains instead of switching off — a tab panel, a closing dialog, an acknowledged alarm. Pure CSS, and the one part that carries the effect on its own. The transition is declared on the hidden state only, so hiding decays and showing snaps back instantly. Nothing here ever fades in.
2 · GHOSTING — effects.js Text rewritten in place leaves the previous value behind for a beat. Watch the clock and the frame counter on the console page. This is the one part CSS cannot do — nothing in the cascade remembers the old string — so a MutationObserver in amber-console.effects.js parks a copy at the rect it occupied. The copy is .ac-ghost, and it is worth knowing the name: it is a real element in your DOM for the length of the tail, it is aria-hidden and pointer-events: none, and it is the hook to style or suppress if a ghost lands somewhere you do not want one. .ac-ghost--fast is the same node on the short tail, used where a value rewrites often enough that the full decay would stack copies on top of each other. Both are removed when they finish; nothing accumulates. <span class="ac-ghost"> <!-- mounted and removed by effects.js --> .ac-ghost { display: none } /* suppress it in one region, without the module */
3 · RESIDUAL PATCHES — CSS The glass never sits perfectly uniform; charge relaxes unevenly. Four overlapping pools at 3% over the amber, drifting on a 47s cycle. You do not notice it directly — you notice when it stops.
4 · THE BLINK OFF-EDGE — CSS A blinking alarm is the thing on the panel that stops being driven most often — once a second, forever — so it is the last place the decay should be missing. .ac-blink stays steps(1) by default; with persistence on, only the ON edge stays hard. Instant up, curve down.
5 · DE-ENERGIZING — CSS The commonest light-off event on a control panel is not a node disappearing, it is a lamp going out: a pressed button releasing, a tab deselecting, an interlock unchecking. Split by what each property describes: the structure — background, border, color — releases fast so the control reads as off immediately, while the halo decays on the full uncapped tail, because the halo is the scattered light that persists. Under P39 a released button glows for a second and a half. Hover is excluded on purpose — a wake behind the cursor reads as lag.
6 · SCROLL SMEAR — effects.js Scrolling hands every cell on the panel a new value at once, which is the largest light-off event there is, and the image trails. Scaled by real scroll velocity, which is why it cannot be CSS: a scroll timeline exposes position, and velocity is not derivable from it. Scroll this page briskly.
7 · FRAMEBUFFER DECAY — CSS and effects.js The one place a real framebuffer snapshot is available. Everything above decays an element — something the cascade can name. A phosphor decays whatever was drawn, including the parts of the screen no element owns. It arrives twice, by two different routes, which is why the board's engine panel lists framebuffer decay as a JavaScript effect while this half needs no script at all. Between pages — CSS. Navigate to the console and back under P39 and the old page drains behind the new one, per pixel. Needs one line in your own stylesheet — @view-transition with navigation: auto — because it is a document-level switch, and linking a stylesheet must not rewrite how your site navigates. Within a page — effects.js. A tab switch or a dialog replaces most of the screen without navigating anywhere, and CSS has no hook for that. The effects module exports transition(fn), which wraps the change in a view transition so the same decay runs over it; amber-console.js already calls it for tabs and dialogs. This is the half that goes dark when JS Effects is switched off — and the signature is in REFERENCE with the other two exported functions.
8 · A LIT AREA SHRINKING — CSS + effects.js A bargraph does none of the seven things above: the element stays, its text is elsewhere, its color never moves. What changes is its width, so the strip it vacates was lit a moment ago and is now simply not drawn. On a two-second phosphor that was the most visible wrong thing on the panel — everything around the bar trailed and the bar itself snapped. A second bar now lags behind the live one on --ac-persist-tail, and the asymmetry needs no rule of its own: on a fall the ghost is wider and its trailing strip drains, and on a rise it is narrower, so it hides underneath and nothing fades in. Watch a load bar on the server dashboard under P39.

The eighth is the one place the two tiers do different things rather than one filling a gap the other leaves, and the difference is real. A bar falling gradually stops driving each cell at a slightly different moment, so the honest result is a taper behind a receding edge — which is what the CSS draws, and what a drifting value actually does. A bar that drops suddenly stops every vacated cell at once and should fade uniformly instead. CSS cannot hold the old width, so it cannot tell those apart; effects.js recovers the old geometry and parks a proper uniform ghost for that case — which is also how the radar's A-scope and echoes get theirs, since it watches for any lit area that shrank rather than for anything named.

BLINK — ALARM ✳ LAMP FAULT ✳ Toggle CRT on the board above and watch this one. Off, it snaps between full and 10%. On, it holds, then drains over an ~88ms window of the 1.1s cycle — deliberately near the floor of what registers as a decay at all.
EVERY BLINK SITE FOLLOWS One rule swaps the animation-name rather than the shorthand, so .ac-blink, .ac-cursor, an invalid .ac-input and an over-range .ac-meter--alarm bar all keep their own cycle length and pick up the same curve. The de-energizing rules use the same trick as decay-out: the transition is declared on the UNLIT half, so going out drains and coming on is instant.
<div class="ac-screen ac-afterglow"><span class="ac-persist"></span> … </div>

THE PPI SWEEP

The one widget where persistence is the whole thing, and the one place a decaying trail is achievable in pure CSS. The obvious way to draw a radar wake is to stamp a mark every frame and fade each one, which is a per-pixel framebuffer problem and needs a canvas. But a PPI trail is not a history of marks — it is one continuous falloff behind a rotating line, and a conic-gradient already is that falloff. Rotate it and the decay comes for free, on the GPU, in one element, with no script at all.

The angular stops are the phosphor's decay curve read in degrees rather than milliseconds, which is a substitution rather than a pun: the beam turns at a constant rate, so angle behind the beam is time since that bearing was painted. Same curve, same fast-knee-long-tail shape, different axis. The rotation period comes off --ac-persist-tail, so the sweep returns about as the trail finishes draining — which is precisely the trade P7 and P39 were bought to make.

PPI — NO SCRIPT Switch the display to P7 and the leading edge turns blue against a yellow-green wake — that is --ac-halo-flash against --ac-halo-1, the two coatings doing exactly what they did on the real tube. Every other emitter has one coating, so its leading edge is simply the brighter end of its own trail. The line itself is a constant-width arm rather than the first few degrees of the gradient, which would be a wedge and would thin to nothing near the middle; the center is bright because all 360 bearings cross it and it takes the whole revolution's dose.
WHY IT SLOWS DOWN Under P39 the sweep takes 3s and under P7 4.5s, because both are scaled from the tail. Neon would scale to 0.16s, which is not a radar but a strobe, so the period has a floor. A face whose trail has not drained by the time the beam returns never reads as dark, and stops looking like a radar at all — it looks like a spinning pie chart.
<div class="ac-sweep" role="img" aria-label="Search radar"><span class="ac-sweep__beam"></span></div>

Assuming a removed node ghosts itself. The observer only sees text change; a node that stops existing has no rect left to pin a ghost to, so ghost it before you remove it — AmberConsoleEffects.afterglow(row), then row.remove(). Retune the decay with the three tokens it is built from, none of which is a duration you set directly — each is the palette's own --ac-persist under a different cap. --ac-decay is capped at 250ms and belongs to things that must actually leave; --ac-decay-fast is capped at 60ms and belongs to de-energizing controls and hover release, because it fires on every control the pointer crosses; --ac-persist-tail is uncapped and belongs to the ghosts and the residual patches, which is where a long phosphor is allowed to be long. Rewritten text is its own case at 400ms, enough to keep one generation legible and not two. --ac-decay-ease is the curve.