feat(serve): a colour per node, carried across the graph, the feed and the scrubber - #176
Merged
Merged
Conversation
…d the scrubber Eight node boxes, a feed interleaving all of them, and a scrubber that says nothing about what happened where. Connecting a row in the feed to a box in the graph meant reading both. Each node now has a hue fixed by its name: the wash along the bottom of its box, its name in the graph, its prefix in the feed, and its stretch of the scrubber's track. One glance connects them. Derived rather than assigned, because the node set is not fixed — a workflow can name nodes this build has never heard of, and a lookup table would give those all one colour or none. FNV-1a over the name, quantised into 18 hues and three lightnesses. Both of those quantisations are load-bearing. Taken continuously off the hash, two of this pipeline's nodes landed seven degrees apart — different values, and nowhere near different enough to look it, which reads as one node drawn inconsistently. The lightness axis then separates the pairs that share a hue bucket. Across the twelve node names this repository uses, all twelve are distinct. The palette starts at 40 degrees rather than 0. Red is `--hazard` and means a failure, so a node washed red reads as a broken one whatever its state; the first version gave the overseer hue 0 and its idle box looked like an error. Selected and working now draw in the node's own tint too, so which node this is stays legible while its state changes. Red is left meaning one thing, and `.node--failed` is ordered last so a node that is both failed and selected reads as failed. The scrubber's track is the band, replacing a flat accent colour that only said "this is a slider" — which the slider already said. Bucketed rather than one stop per event: a long run has hundreds, and two nodes running in parallel alternate between them, which at one stop each renders as shimmer. A bucket that caught several nodes is split evenly between them, which is what "both were running here" looks like at this width. The handle stays round — the one thing you drag should not look like the panels it sits among — and is filled with a blur of what is under it, so the band reads through it rather than being covered by the control that points at it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #175 — it touches the same
Scrubbercomponent, so it is based on that branch rather than main. Merge #175 first and this retargets cleanly.Eight node boxes, a feed interleaving all of them, and a scrubber that said nothing about what happened where. Connecting a row in the feed to a box in the graph meant reading both.
Each node now has a hue fixed by its name, carried across four surfaces: the wash along the bottom of its box, its name in the graph, its prefix in the feed, and its stretch of the scrubber's track.
Derived rather than assigned, because the node set is not fixed — a workflow can name nodes this build has never heard of, and a lookup table would give those all one colour or none.
Two quantisations, both load-bearing
FNV-1a over the name, then 18 hues × 3 lightnesses.
Taken continuously off the hash, two of this pipeline's nodes landed seven degrees apart. Different values, and nowhere near different enough to look it — which reads as one node drawn inconsistently rather than as two nodes. An earlier attempt at stepping by the golden angle made it worse: that spreads sequential indices, and a hash is not sequential, so it just reintroduced correlation and put six of eight nodes inside a 40-degree band of cyan.
The lightness axis then separates the pairs that share a hue bucket. Across the twelve node names this repository uses, all twelve come out distinct.
Red is left alone
The palette starts at 40 degrees.
--hazardis red and means a failure, so a node washed red reads as broken whatever its state — the first version gave the overseer hue 0 and its idle box looked like an error.Selected and working now draw in the node's own tint as well, so which node this is stays legible while its state changes, and red keeps its weight by meaning one thing.
.node--failedis ordered last, so a node that is both failed and selected reads as failed.The state colours come from one inline
--tintcustom property rather than a colour per property: the hue is the only part CSS cannot derive, and everything downstream of it stays in the stylesheet. The.st--workingoverride is scoped to.node, because the same class carries run status in the runs list, where the live green is about the run and not about any node.The scrubber
The band is the track now, replacing a flat accent that only said "this is a slider" — which the slider already said.
Bucketed rather than one stop per event: a long run has hundreds of events, and two nodes running in parallel alternate between them, which at one stop each renders as shimmer. A bucket that caught several nodes is split evenly between them with hard stops, which is what "both were running here" looks like at this width. Hard rather than interpolated, because a blend between two nodes' colours would invent a third that means nothing.
The handle stays round — the one thing you drag should not look like the hard-edged panels around it — and is filled with a blur of what is beneath, so the band reads through it rather than being hidden by the control pointing at it.
Verified
In a browser, not asserted about the source: every node box carries a wash and a tinted name, the feed prefix matches its node's colour in the graph, and the track resolves to 224 colour stops. Screenshots checked by eye for the red-reads-as-failure problem, which is how it was found.
bun run typecheckandbun run buildpass. No Rust changed. Noteweb/has no test runner — a test file there only gates typecheck and never executes — so the browser check is the verification.