Perceptually distinct run colors#64
Merged
Demonstrandum merged 3 commits intoMar 3, 2026
Merged
Conversation
Overhaul the run color deconfliction system to produce truly perceptually
distinct colors by searching across all three OKLCH axes (lightness,
chroma, and hue) instead of just hue.
Key changes:
1. **Raised MIN_DELTA_E from 0.04 to 0.075** — more conservative threshold
that ensures colors are clearly distinguishable on charts.
2. **3-axis findDistantColor** — replacement colors are now chosen by
maximizing the minimum OKLAB delta-E across a grid of 6 lightness ×
4 chroma × 72 hue candidates (1728 points), with sRGB gamut filtering.
Previously only 72 hue values at fixed L/C were searched.
3. **Separate deconfliction state** — deconflicted colors are stored in a
new `deconflictedRunColors` map on the runs state, separate from
user-set `runColorOverrideForGroupBy`. This means:
- Deconfliction colors are NEVER saved in profiles
- They are cached in a separate localStorage key
(`_tb_run_color_deconfliction.v1`)
- If the cache is lost, they are deterministically recomputed
4. **Incremental computation** — when new runs are added, only the new
runs are checked against the full set of existing effective colors
(including cached deconflictions). Existing cached runs keep their
colors. Cache is invalidated when dark mode changes, runs are removed,
or base colors change.
5. **Color priority** in getRunColorMap:
user override > deconfliction override > hash-based > legacy > inactive
Files changed:
- oklch_colors.ts: new computeDeconfliction(), improved findDistantColor()
- runs_types.ts: added deconflictedRunColors field
- runs_actions.ts: runColorDeconflictionComputed, runColorDeconflictionLoaded
- runs_reducers.ts: reducers for new actions
- runs_selectors.ts: getDeconflictedRunColors selector
- ui_selectors.ts: updated getRunColorMap with deconfliction layer
- runs_effects.ts: new cache pipeline, incremental deconfliction
- testing.ts: updated test builder
- AGENTS_DEV.md: documented new localStorage key and feature
Co-authored-by: Samuel <samuel@knutsen.co>
|
Cursor Agent can help with this pull request. Just |
Preview Deployment
Details
|
Co-authored-by: Samuel <samuel@knutsen.co>
…tests Fix a bug where a hash-based run sorting before a user-overridden run would not be deconflicted against the user's explicit color choice. The algorithm now has three phases: - Phase 0: Place ALL user-overridden colors as immovable landmarks first, regardless of sort position. This ensures every hash-based run is always checked against every user-chosen color. - Phase 1: Place cached non-user runs (preserving their deconflictions). - Phase 2: Process remaining new non-user runs against the full set. Add comprehensive test suite (oklch_colors_test.ts) covering: - Basic: no runs, single run, distant colors (no deconfliction) - Clash detection: identical colors, very similar colors, multiple clashes - User overrides: never deconflicted, respected as landmarks, hash runs checked against user colors regardless of sort order - Mixed scenarios: user override in middle, user override sorting later - Replacement quality: 3-axis search verified, sRGB-valid output - Incremental/cache: cached runs preserved, new runs checked against all - Determinism: same inputs → same outputs, Map insertion order independent - Dark mode: different lightness ranges - Stress: 30 identical runs, realistic 12-run scenario Co-authored-by: Samuel <samuel@knutsen.co>
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.
Motivation for features / changes
The existing hash-based run color assignment sometimes resulted in perceptually indistinct colors, making it difficult to differentiate runs. The previous clash resolution mechanism was limited, only adjusting hue and mixing deconflicted colors with user-set overrides, leading to these computed colors being inadvertently saved in user profiles.
This change aims to:
Technical description of changes
oklch_colors.tsmodule now uses a higherMIN_DELTA_E(0.075) andfindDistantColorsearches across all three OKLCH axes (lightness, chroma, hue) for a wider range of perceptually distinct color candidates (1,728 options). ThecomputeDeconflictionfunction supports incremental updates and deterministic color assignment.deconflictedRunColors: Map<RunId, string>, has been added toRunsDataNamespacedStateto store deconflicted colors, ensuring they are distinct from user-defined overrides.runColorDeconflictionComputedandrunColorDeconflictionLoadedactions, along with their respective reducers, manage the new deconfliction state.ui_selectors.ts'sgetRunColorMapnow applies colors in the order: user override > deconfliction override > hash-based > legacy palette > inactive.runs_effects.tsimplements a new pipeline to load and persist deconflicted colors to_tb_run_color_deconfliction.v1in localStorage. Deconfliction is computed incrementally for new runs afterfetchRunsSucceeded, and the cache is validated for consistency. Deconflicted colors are explicitly excluded from profile saving.AGENTS_DEV.mdhas been updated to reflect the new deconfliction mechanism and localStorage key.Screenshots of UI changes (or N/A)
N/A (Changes affect color generation logic, not UI components directly, though the visual outcome will be more distinct run colors).
Detailed steps to verify changes work correctly (as executed by you)
_tb_run_color_deconfliction.v1entry from localStorage (e.g., using browser dev tools).Alternate designs / implementations considered (or N/A)
N/A