Documentation
¶
Overview ¶
Package core is the heart of wondertone.
Import it as "tone" for the most natural developer experience:
import tone "github.com/leraniode/wondertone/core"
spark := tone.New(
tone.Light(75),
tone.Vibrancy(80),
tone.Hue(30),
tone.Energy(0.9),
tone.Named("Primary Spark"),
tone.Moody("vibrant"),
)
Wondertone speaks in Light, Vibrancy, Hue, and Energy. OKLCH is the engine. You never have to know it exists.
Index ¶
- func Arousal(saturation, energy, tv float64) float64
- func CorrectedHue(h, c, l float64) float64
- func DerivedMood(valence, arousal, temperatureValue float64) string
- func EffectiveChroma(c, energy float64) float64
- func EffectiveLightness(l, energy float64) float64
- func PerceivedChroma(vibrancy, l, h float64) float64
- func TemperatureLabel(tv float64) string
- func TemperatureValue(h, c, l float64) float64
- func Valence(tv, l, saturation float64) float64
- type Option
- type Tone
- func Blend(tones []Tone, weights []float64) (Tone, error)
- func FromHex(s string) (Tone, error)
- func FromOKLCH(l, c, h float64) Tone
- func FromOKLCHString(s string) (Tone, error)
- func Gradient(start, end Tone, n int) ([]Tone, error)
- func Harmonize(base Tone, scheme string) ([]Tone, error)
- func Mix(a, b Tone, t float64) Tone
- func MustFromHex(s string) Tone
- func New(opts ...Option) Tone
- func Shift(t Tone, direction string, amount float64) (Tone, error)
- func (t Tone) AlphaValue() float64
- func (t Tone) ArousalValue() float64
- func (t Tone) Complement() Tone
- func (t Tone) ContrastWith(other Tone) float64
- func (t Tone) Darken(amount float64) Tone
- func (t Tone) DerivedMoodValue() string
- func (t Tone) Desaturate(amount float64) Tone
- func (t Tone) EffectiveC() float64
- func (t Tone) Energy() float64
- func (t Tone) EnsureContrast(bg Tone, level string) Tone
- func (t Tone) Equal(other Tone) bool
- func (t Tone) Hex() string
- func (t Tone) Hue() float64
- func (t Tone) IsDark() bool
- func (t Tone) IsLight() bool
- func (t Tone) Light() float64
- func (t Tone) Lighten(amount float64) Tone
- func (t Tone) Luminance() float64
- func (t Tone) Mood() string
- func (t Tone) Name() string
- func (t Tone) OKLCH() (l, c, h float64)
- func (t Tone) OKLCHString() string
- func (t Tone) PassesAA(bg Tone) bool
- func (t Tone) PassesAAA(bg Tone) bool
- func (t Tone) RGB() (r, g, b uint8)
- func (t Tone) RGBFloat() (r, g, b float64)
- func (t Tone) Rotate(degrees float64) Tone
- func (t Tone) Saturate(amount float64) Tone
- func (t Tone) Scale() ToneScale
- func (t Tone) Step(n int) Tone
- func (t Tone) String() string
- func (t Tone) Temperature() string
- func (t Tone) TemperatureScalar() float64
- func (t Tone) ValenceValue() float64
- func (t Tone) Vibrancy() float64
- func (t Tone) WithAlpha(a float64) Tone
- func (t Tone) WithEnergy(e float64) Tone
- func (t Tone) WithHue(h float64) Tone
- func (t Tone) WithLight(v float64) Tone
- func (t Tone) WithMood(mood string) Tone
- func (t Tone) WithName(name string) Tone
- func (t Tone) WithVibrancy(v float64) Tone
- type ToneScale
- func (s ToneScale) ActiveBackground() Tone
- func (s ToneScale) All() []Tone
- func (s ToneScale) Background() Tone
- func (s ToneScale) Border() Tone
- func (s ToneScale) ElementBackground() Tone
- func (s ToneScale) HighContrastText() Tone
- func (s ToneScale) HoveredBackground() Tone
- func (s ToneScale) HoveredSolid() Tone
- func (s ToneScale) Solid() Tone
- func (s ToneScale) Step(n int) Tone
- func (s ToneScale) StrongBorder() Tone
- func (s ToneScale) SubtleBackground() Tone
- func (s ToneScale) SubtleBorder() Tone
- func (s ToneScale) Text() Tone
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Arousal ¶ added in v0.2.0
Arousal returns the emotional arousal/energy level of a tone ∈ [-1, +1].
+1.0 = highly activated (vivid, high energy) -1.0 = calm/sleepy (muted, low energy)
Formula:
arousal = clamp(b1*S + b2*E + b3*T, -1, 1)
func CorrectedHue ¶ added in v0.2.0
CorrectedHue applies the WonderMath blue-drift correction. Returns H' — the perceptually corrected hue.
Formula:
H' = wrap360(H + A * exp(-(H-H0)² / (2w²)) * (C / C_max))
The Gaussian is chroma-weighted: grey tones get zero correction. Only vivid blues near H≈250° are nudged back from purple.
func DerivedMood ¶ added in v0.2.0
DerivedMood maps a valence/arousal vector to a named mood. This replaces the manual Moody() tag with a mathematically derived value. The manually set mood still takes precedence as a display override.
Mood regions (valence, arousal):
vivid — high arousal, mid-high valence playful — high arousal, high valence, warm urgent — high arousal, low-mid valence focused — mid arousal, mid valence warm — mid arousal, high valence, warm temperature mystical — mid arousal, low valence, cool calm — low arousal, mid valence deep — low arousal, low valence airy — low arousal, high valence
func EffectiveChroma ¶ added in v0.2.0
EffectiveChroma applies the perceptually linear Energy scaling to chroma.
Formula:
C_effective = C_base * E^γ
γ ≈ 0.7 (Stevens' power law exponent for colour saturation). This makes Energy=0.5 feel like "half as alive", not "60% as alive".
func EffectiveLightness ¶ added in v0.2.0
EffectiveLightness applies the subtle lightness glow at high energy. High-energy tones get a small brightness boost — they glow slightly.
Formula:
L_effective = L + λ * (E^γ - 1)
λ = 0.04 means full-energy tone gets +4% lightness max. At Energy=0.5: L_effective = L + 0.04 * (0.5^0.7 - 1) ≈ L - 0.015
func PerceivedChroma ¶ added in v0.2.0
PerceivedChroma converts Vibrancy [0–100] to raw OKLCH chroma C using the full WonderMath pipeline:
- Gamut-relative base: rawC = C_max * (V/100)^α
- Hue weight correction: C = rawC * k(H)
Energy is NOT applied here — it is applied separately in EffectiveC. This is the stored chroma value: what the tone IS, not how it renders.
func TemperatureLabel ¶ added in v0.2.0
TemperatureLabel maps a continuous temperature value to "warm", "cool", or "neutral". Replaces the old hue-range lookup.
func TemperatureValue ¶ added in v0.2.0
TemperatureValue returns a continuous warm↔cool scalar T ∈ [-1, +1].
+1.0 = maximally warm (vivid red-orange) 0.0 = neutral -1.0 = maximally cool (vivid blue-cyan)
Formula:
raw = cos((H - H_warm) * π/180) T = clamp(w_h*raw + w_c*(C/C_max) + w_l*(L-0.5), -1, 1)
Hue dominates (w_h=0.7). Chroma boosts the reading (more vivid = more definitely warm or cool). Lightness nudges slightly (dark oranges read slightly cooler than bright ones).
Types ¶
type Option ¶
type Option func(*Tone)
Option configures a Tone during construction.
func Energy ¶
Energy sets the aliveness multiplier [0–1]. 1.0 = full vivid (default). 0.5 = half as colorful, same hue. 0.0 = grey. Energy scales effective chroma at render time without changing the stored Tone. A palette can whisper or shout — same colors, different energy.
func Hue ¶
Hue sets the color angle [0–360). 0/360=red, 30=orange, 60=yellow, 120=green, 180=cyan, 240=blue, 300=magenta.
func Light ¶
Light sets the perceptual lightness [0–100]. 0 is black. 100 is white. 50 is a true mid-tone.
func Moody ¶
Moody gives the Tone a mood tag. Examples: "vibrant", "serene", "mystical", "focused", "playful", "warm".
func Vibrancy ¶
Vibrancy sets how colorful the tone is [0–100], relative to the maximum possible saturation at this lightness and hue. 0 is pure grey. 100 is the most vivid color the sRGB gamut allows at this exact Light+Hue combination.
This is not raw OKLCH chroma — it is a percentage of the gamut ceiling. This means Vibrancy(80) always looks 80% vivid regardless of hue.
type Tone ¶
type Tone struct {
// contains filtered or unexported fields
}
Tone is the atomic unit of wondertone — a living, named color.
Developers work with the Wondertone vocabulary:
- Light [0–100] perceptual lightness. 0=black, 100=white.
- Vibrancy [0–100] colorfulness relative to gamut max. 0=grey, 100=most vivid possible.
- Hue [0–360) color angle. 0=red, 120=green, 240=blue.
- Energy [0–1] aliveness multiplier. 0=muted/sleeping, 1=full/vivid.
Under the hood, everything is OKLCH — perceptually uniform, gamut-safe, hue-preserving. The developer never touches L, C, H directly unless they want to via FromOKLCH.
A Tone is immutable. Every method returns a new Tone.
func Blend ¶
Blend mixes multiple Tones with given weights in OKLab space. weights must be the same length as tones and sum > 0. Weights are normalized automatically — you don't need to sum to 1.
func FromOKLCH ¶
FromOKLCH creates a Tone directly from raw OKLCH values. This is the power-user escape hatch — use New() for the normal path. L [0–1], C [0–~0.37], H [0–360).
func FromOKLCHString ¶
FromOKLCHString parses an oklch string: "0.75 0.15 30" or "0.75 0.15 30 / 0.9".
func Gradient ¶
Gradient produces n evenly spaced Tones between start and end in OKLab space. n must be >= 2. The first element is start, the last is end. No grey midpoint artifacts — OKLab interpolation guarantees perceptual smoothness.
func Harmonize ¶
Harmonize returns a set of Tones related by the given harmonic scheme. All harmony is computed by hue rotation in OKLCH — lightness and vibrancy are preserved from the base Tone.
scheme: "complement", "triadic", "analogous", "split", "tetradic"
func Mix ¶
Mix blends two Tones in OKLab space at ratio t [0–1]. t=0 returns a, t=1 returns b, t=0.5 is the perceptual midpoint.
OKLab gives straight-line interpolation — no unexpected hue swings through grey that you get with HSL or even OKLCH mixing. The result name and mood are cleared (the blend is a new thing).
func MustFromHex ¶
MustFromHex parses a hex string and panics on error. Use only for known-good compile-time constants (e.g. in colour/ package).
func New ¶
New creates a Tone from options using the Wondertone vocabulary.
spark := tone.New(
tone.Light(75),
tone.Vibrancy(80),
tone.Hue(30),
tone.Energy(0.9),
tone.Named("Primary Spark"),
)
func Shift ¶
Shift nudges a Tone toward warmer or cooler territory. direction: "warmer" or "cooler". amount [0–1].
func (Tone) ArousalValue ¶ added in v0.2.0
ArousalValue returns the emotional arousal of this tone ∈ [-1, +1]. +1 = activated (vivid, energetic). -1 = calm (muted, quiet).
func (Tone) Complement ¶
Complement returns the Tone directly opposite on the hue wheel (+180°).
func (Tone) ContrastWith ¶
ContrastWith returns the WCAG 2.1 contrast ratio against another Tone [1–21].
func (Tone) DerivedMoodValue ¶ added in v0.2.0
DerivedMoodValue returns the mathematically derived mood string. Computed from valence and arousal — independent of the stored Mood() tag. Use Mood() for the display label (manual override takes precedence).
func (Tone) Desaturate ¶
Desaturate returns a new Tone with vibrancy decreased by amount [0–100].
func (Tone) EffectiveC ¶
EffectiveC returns the chroma that will actually be used for rendering. Uses the WonderMath Stevens' power law: C * E^γ (γ≈0.7). Energy=0.5 now feels half as alive, not 60% as alive. The stored C and Energy are never modified.
func (Tone) EnsureContrast ¶
EnsureContrast returns a Tone adjusted to meet the target contrast ratio against bg. Adjusts lightness only — hue, vibrancy and energy are preserved. level: "AA" (4.5:1) or "AAA" (7.0:1).
func (Tone) Equal ¶
Equal reports whether two Tones are perceptually identical within floating-point tolerance.
func (Tone) Hex ¶
Hex returns the color as a lowercase CSS hex string. Gamut-safe: out-of-range OKLCH values are mapped into sRGB before encoding.
func (Tone) OKLCHString ¶
OKLCHString returns the canonical OKLCH string: "0.750000 0.150000 30.000000". This is what .wtone files store — full precision, no loss.
func (Tone) Rotate ¶
Rotate returns a new Tone with hue rotated by degrees. Accepts negative values (counter-clockwise).
func (Tone) Scale ¶
Scale returns the 12-step perceptual tone scale for this Tone. Step 9 is the "pure" tone — closest to the original.
func (Tone) Step ¶
Step returns a single step from the 12-step scale [1–12]. 1=lightest, 12=darkest.
func (Tone) Temperature ¶
Temperature returns "warm", "cool", or "neutral". Upgraded in v0.2: uses WonderMath continuous formula instead of hue-range lookup — chroma and lightness now modulate the reading.
func (Tone) TemperatureScalar ¶ added in v0.2.0
TemperatureScalar returns the continuous warm↔cool value T ∈ [-1, +1]. +1 = maximally warm, -1 = maximally cool, 0 = neutral. More precise than Temperature() which returns a label.
func (Tone) ValenceValue ¶ added in v0.2.0
Valence returns the emotional valence of this tone ∈ [-1, +1]. +1 = positive (bright, warm, vivid). -1 = negative (dark, cool, muted).
func (Tone) WithEnergy ¶
WithEnergy returns a new Tone with the given energy [0–1].
func (Tone) WithVibrancy ¶
WithVibrancy returns a new Tone with the given vibrancy [0–100].
type ToneScale ¶
type ToneScale [12]Tone
ToneScale is a 12-step perceptual ladder from a single base Tone. Hue never drifts. Every step is in sRGB gamut.
Step roles (1=lightest, 12=darkest):
1 Page background — barely tinted white 2 Subtle background — stripes, alternating rows 3 UI element background — cards, inputs 4 Hovered element bg — hover state 5 Active/selected bg — selected state 6 Subtle border — separators 7 UI border — input borders 8 Strong border — focus rings 9 Solid bg — buttons, badges — base tone lives here 10 Hovered solid — button hover 11 Text — readable on light backgrounds 12 High-contrast text — headings, emphasis
func (ToneScale) ActiveBackground ¶
func (ToneScale) Background ¶
Semantic accessors — named by their UI role.