Optional ReadonlyannotationThe annotation register — the styling for user-authored marks
(<Region> / <Baseline> / <Marker>), deliberately a distinct hue from
the data's line/area/… so a mark you place never reads as data (the
"data stays foam, marks are turquoise" rule). color is the shared register
hue (lines, region edges + fill, handles, label text); the region fill draws
at fillOpacity. Luminosity encodes depth — brighter reads as forward,
dimmer as further back. depth is the three-level ramp: [0] = level 1
(forward / brightest — a selected mark, or an edit-mode line), [1] = level 2
(mid — a hovered mark, or an edit-mode region body), [2] = level 3 (back —
the resting, backgrounded state). Cross-row guides draw fainter still (a
notional level 4, set in Layers). Falls back to a built-in turquoise.
ReadonlyareaMap from an area's semantic identifier to its outline-plus-graded-fill style
(AreaChart) — outline colour/width and the gradient (opaque at the line,
fading to transparent at the baseline). default is the fallback; the
esnet two-colour traffic look is two areas composed in the z-stack (e.g.
in above the axis + out below), each resolving area[semantic] ?? area.default.
ReadonlyaxisAxis chrome: tick-label colour, gridline stroke + dash pattern.
Readonlygrid: stringReadonlygridDash: readonly number[]Gridline dash pattern (px on/off pairs); [] for solid.
Readonlylabel: stringOptional ReadonlysessionDivider?: stringStroke for session dividers — the solid verticals a trading-time axis draws at each collapsed gap (session/day open). Optional; falls back to grid. Set it a touch stronger than the gridlines so a session boundary reads as structural.
Optional Readonlytitle?: { color?: string; opacity?: number; size?: number }Typography for the axis title — the rotated y-axis unit strip and the
x-axis label (distinct from the per-tick label colour above). Omit a
field to fall back: color → label, size → font.size + 1 (a touch
larger than the ticks so the rotated strip reads), opacity → 0.85.
Optional ReadonlybackgroundPainted behind the layers; omit for a transparent background.
ReadonlybandMap from a band's semantic identifier to its fill style — the variance
underlay (BandChart). default is the fallback; a two-tone spread
is two bands composed in the z-stack (e.g. outer p5/p95 + inner
p25/p75), each resolving band[semantic] ?? band.default.
ReadonlybarMap from a bar's semantic identifier to its style — the fill, the
selected-bar highlight, and the slot gap / minimum width (BarChart).
default is the fallback; a bar resolves bar[semantic] ?? bar.default.
ReadonlyboxMap from a box's semantic identifier to its style — a discrete
box-and-whisker per key (BoxPlot), the bar-chart analog of the
band. default is the fallback; a chart tags each box series with a role
(<BoxPlot as="latency" />) resolving box[semantic] ?? box.default.
ReadonlycandleMap from a candle's semantic identifier to its style — a first-class OHLC
mark (Candlestick), the financial sibling of the box. Unlike the
other slots a CandleStyle carries a pair (rising/falling, plus
an optional neutral doji): direction colouring is intrinsic to the mark, so
one colour can't express it. default is the fallback; a chart tags each
series with a role (<Candlestick as="AAPL" />) resolving candle[semantic] ?? candle.default. The default pair is neutral / unbranded (a
distinguishable up/down, not market green/red) — a consumer supplies its
own palette via cssVarTheme; the library owns the type + a renderable
default, never a brand.
Optional ReadonlychipReadout chip background (the flag / inline tracker modes). The value text
is the series colour; this is the panel behind it. Falls back to the plot
background if unset.
Optional ReadonlycursorCrosshair / tracker stroke colour. Falls back to axis.label if unset.
ReadonlyfontLabel / tick typography. One source for axes + chrome.
Optional ReadonlygapStyling for the inferred dashed gap connectors — the dashed and step
gap modes (GapMode). Drawn fainter than the solid line (via
connectorOpacity, 0–1, applied over the layer's colour) so an inferred
bridge across a gap reads as secondary to measured data. Per-theme, so a
dark ground can tune the faintness independently. Falls back to 0.5 if
unset. (The fade mode has its own gradient and isn't governed by this.)
ReadonlylineMap from a line's semantic identifier to its style. default is the
fallback for an identifier the theme doesn't name, so a chart always
renders; a line resolves line[semantic] ?? line.default.
ReadonlyscatterMap from a scatter's semantic identifier to its point style — the single
styling channel for the base mark (ScatterChart): fill colour,
base radius, outline, and the optional per-point label colour. default is
the fallback; a scatter resolves scatter[semantic] ?? scatter.default.
Scatter additionally supports data-driven radius + colour (a column run
through a scale — see src/encoding.ts); that is the deliberate, signed-off
exception to one-channel styling. The data-driven encoding overrides this
style's radius / color per point; this remains the fallback for
unencoded points and the source of the outline + label styling.
Visual styling for a chart, threaded through ChartContainer via context. Canvas has no CSS cascade into drawn pixels, so this typed object is the single styling channel for the drawn layers; DOM chrome (axis labels) derives from it too.
The styling pipeline is time series → columns → semantic identifier → style: a draw layer tags its column with a semantic identifier (what the data is — e.g.
heartrate,power, or a genericprimary), and the theme is the map from identifier → LineStyle. The visual discipline ("a handful of roles, not a hue per channel") lives in the theme, not the type: a good theme maps many identifiers onto few shared styles (estela maps power / speed / cadence → one foam style). Tokens grow as components land (axis tokens withYAxis, band tokens withBandChart).