PanelGauge

A moving-coil gauge with a scale that lights to the reading and a needle that is never quite still.

the reading hunts on its own

Paste into Claude Code, Cursor or any agent. Pinned to a tag, so it will not change under you.

Options

face #15171b

css colour

The dial face. Painted rather than left transparent, because a gauge is a thing with a face on it and the alternative is ticks floating on your page.

ink #8b9199

css colour

Unlit ticks and the boss at the centre. Grey rather than white: the unlit half of the scale is there to be read past, not read.

needle #ff9426

css colour

The pointer. The one thing on the dial that should be found without looking, so it wants to be the only saturated colour in the frame apart from the lit arc it belongs to.

lit #ff9426

css colour

The arc and the ticks below the reading. Usually the needle's colour, because they are telling you the same thing; set them apart only if the arc is reporting something the needle is not.

value 0.62

0 to 1

Where the needle sits on the scale. Drive this through update() to make the gauge report something real; the hunt is applied on top of whatever you set.

hunt 0.035

0 to 0.3, good: 0.02 to 0.08

How far the reading wanders either side, as a share of the scale. Small. At 0 the needle is frozen and the gauge stops reading as something connected to anything; past about 0.12 it is a fault rather than a reading.

sweep 250

90 to 320 deg, good: 200 to 270

Degrees of arc the scale covers, centred on twelve o'clock with the dead sector at the bottom. 250 is what a panel meter does, because that is where its stops are. At 320 there is nowhere for the movement to go and it reads as a ring.

majors 6

2 to 16

Major divisions, the ones a real dial numbers. Few: a scale you can count at a glance is the point of a dial, and past about ten you are reading a ruler.

minors 4

0 to 10

Minor divisions between each pair of majors. These are what let the eye read a needle between two numbers as a value. At 0 the dial can only say which division it is in.

period 18

4 to 120 s, good: 12 to 40

Seconds for one cycle of the hunt. Both sines complete whole turns in it, so the needle is in the same place at the start and the end.

seed 3

0 to 9999

Seed for the hunt's phase. Two gauges side by side want two seeds, or they wander in step and read as one instrument drawn twice.

What it needs

Category
Surfaces, an effect
Dependencies
None at all
Browser
No WebGL
Frame budget
~1.7 ms · 0 context
Pinned to
v0.13.0
  • The scale is not symmetrical about the top. A panel meter sweeps about 250 degrees from the lower left, because that is where the stops are, and the dead sector at the bottom is where the movement lives. A scale that starts at twelve o'clock and runs clockwise is a progress ring
  • Majors and minors are not the same tick. The minors between two majors are what make the eye read a position as a value rather than as an angle, and the ticks below the reading are lit while the ones above are not, which is how a scale carries the value as well as the needle does
  • The reading hunts. A real one moves by a fraction of a division because what is being measured is not still either, and a needle frozen at exactly 0.62 reads as a picture of a gauge. Two sines of different periods, so it does not tick like a metronome, and both complete whole turns in a period so the needle comes home
  • There is no overshoot, and that is a loss taken deliberately. A moving coil arrives at a reading by passing it, which is the most characterful thing a needle does, but it is a response to a change and therefore state between frames. The first version drove a closed-form damped oscillator from t: the needle swept up from zero and settled, which reads beautifully and does not loop, because frame zero was at the bottom of the scale and the last frame was at the reading
  • 2D rather than WebGL. An instrument is something you want four of on a page, and the budget is one WebGL context
  • Built for a dark ground and declared as one. The face is painted, so the item supplies its own ground and only the area outside the dial shows the page
  • One filled circle, one arc, thirty-ish ticks and a four-point needle. The tick loop is the whole cost and it is linear in majors times minors
  • Measured with `pnpm budget` at 1280 by 720: 1.7ms for a draw and a forced flush, against DustMotes at 1.6 on the same run, and 0.016 mean absolute change per frame on a 0 to 255 scale, worst 0.026. A dial that barely moves is the point: the hunt is a fraction of a division
  • No canvas and no WebGL context held between frames beyond the one it draws into, so this does not compete with a backdrop for the page's context

Concept credit: the lit scale and the live readings on the front panel in the Machine Front Panel Page, by Ray Velez. The implementation here is written from scratch.