palette

package
v0.1.0-rc.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package palette owns colour allocation: the fixed grid of candidate colours a displaced label may be moved to, and the rule that picks one of them.

It takes colours and returns colours. It imports neither internal/config nor internal/github, which is what keeps the interesting part — determinism — testable without a config file or an HTTP mock.

Determinism

Re-running labelsync must not churn colours, and that guarantee starts here: the candidate grid is generated in a fixed order, deduplicated, and sorted ascending by hex, so the same input always produces the same allocation. A caller that breaks ties on first-wins therefore always lands on the lowest hex value.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Allocation

type Allocation struct {
	// Hex is the colour as GitHub stores it: six lower-case hex digits, no
	// leading #. This is the value to send to the label API.
	Hex string

	// Color is Hex as a colour, ready to be passed straight back into a later
	// Allocate call's used set.
	Color colorful.Color

	// Distance is the allocation's score: the perceptual distance from the
	// nearest colour in used or reserved, in go-colorful's CIEDE2000 unit
	// (ΔE2000 × 0.01). It is +Inf when both sets are empty, since there is then
	// nothing to be distant from.
	Distance float64

	// Exhausted reports that Distance fell below the exhaustion floor: every
	// candidate is perceptually close to a colour already present, and the
	// allocation below is merely the least bad one. The colour is still valid
	// and still safe to apply — this is a warning, not a failure.
	Exhausted bool
}

Allocation is one colour picked from the candidate grid, with what the caller needs to report the choice.

func Allocate

func Allocate(used, reserved []colorful.Color) Allocation

Allocate picks the candidate colour with the maximum minimum perceptual distance (CIEDE2000 in CIELAB space) from every colour in used and reserved — the colour most different from everything else present.

used and reserved are treated identically; the split is the caller's bookkeeping. used is what is on the labels today plus whatever this run has already allocated, reserved the colours configured labels are about to claim.

Contract

Allocate is stateless, so it cannot know about a colour it handed out a moment ago: **the caller must add each allocated colour to used before the next call.** Without that, two squatters allocated against the same used set are handed the same colour — the grid is fixed and the rule is deterministic, so identical input necessarily produces identical output.

Ties break first-wins, via a strict >, and the grid is sorted ascending by hex, so equally distant candidates resolve to the lowest hex value. That is what makes a second run a no-op rather than a reshuffle.

Allocate never fails. When every candidate sits within [exhaustionFloor] of an existing colour it returns the best available anyway, with Allocation.Exhausted set.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL