insomni-plot 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE.md +674 -0
  2. package/README.md +81 -0
  3. package/dist/core.d.mts +340 -0
  4. package/dist/core.mjs +1047 -0
  5. package/dist/index.d.mts +3426 -0
  6. package/dist/index.mjs +12762 -0
  7. package/dist/interactions-DEFL_F4E.mjs +5395 -0
  8. package/dist/range-presets-CzECsu3V.d.mts +1523 -0
  9. package/package.json +34 -0
  10. package/src/annotations.d.ts +121 -0
  11. package/src/annotations.ts +438 -0
  12. package/src/axis.d.ts +184 -0
  13. package/src/axis.test.ts +131 -0
  14. package/src/axis.ts +765 -0
  15. package/src/colorbar.d.ts +69 -0
  16. package/src/colorbar.ts +294 -0
  17. package/src/colors.d.ts +57 -0
  18. package/src/colors.test.ts +28 -0
  19. package/src/colors.ts +486 -0
  20. package/src/core.ts +299 -0
  21. package/src/format.d.ts +54 -0
  22. package/src/format.ts +138 -0
  23. package/src/grammar/accessibility.d.ts +147 -0
  24. package/src/grammar/accessibility.test.ts +199 -0
  25. package/src/grammar/accessibility.ts +443 -0
  26. package/src/grammar/aes.d.ts +35 -0
  27. package/src/grammar/aes.test.ts +75 -0
  28. package/src/grammar/aes.ts +120 -0
  29. package/src/grammar/annotations.d.ts +86 -0
  30. package/src/grammar/annotations.test.ts +68 -0
  31. package/src/grammar/annotations.ts +336 -0
  32. package/src/grammar/attach-brush.d.ts +44 -0
  33. package/src/grammar/attach-brush.test.ts +214 -0
  34. package/src/grammar/attach-brush.ts +111 -0
  35. package/src/grammar/attach-presets.d.ts +33 -0
  36. package/src/grammar/attach-presets.test.ts +106 -0
  37. package/src/grammar/attach-presets.ts +215 -0
  38. package/src/grammar/chart.d.ts +952 -0
  39. package/src/grammar/chart.test.ts +118 -0
  40. package/src/grammar/chart.ts +1172 -0
  41. package/src/grammar/color-utils.d.ts +29 -0
  42. package/src/grammar/color-utils.test.ts +53 -0
  43. package/src/grammar/color-utils.ts +66 -0
  44. package/src/grammar/constants.d.ts +45 -0
  45. package/src/grammar/constants.ts +61 -0
  46. package/src/grammar/coord.d.ts +183 -0
  47. package/src/grammar/coord.test.ts +355 -0
  48. package/src/grammar/coord.ts +619 -0
  49. package/src/grammar/data/pivot.d.ts +57 -0
  50. package/src/grammar/data/pivot.ts +107 -0
  51. package/src/grammar/emphasis-driver.d.ts +69 -0
  52. package/src/grammar/emphasis-driver.test.ts +199 -0
  53. package/src/grammar/emphasis-driver.ts +205 -0
  54. package/src/grammar/equality.d.ts +3 -0
  55. package/src/grammar/equality.ts +40 -0
  56. package/src/grammar/facet.d.ts +63 -0
  57. package/src/grammar/facet.test.ts +60 -0
  58. package/src/grammar/facet.ts +175 -0
  59. package/src/grammar/geoms/_categorical.d.ts +94 -0
  60. package/src/grammar/geoms/_categorical.ts +0 -0
  61. package/src/grammar/geoms/_distribution.d.ts +52 -0
  62. package/src/grammar/geoms/_distribution.ts +125 -0
  63. package/src/grammar/geoms/_mark.d.ts +69 -0
  64. package/src/grammar/geoms/_mark.ts +136 -0
  65. package/src/grammar/geoms/_shape.d.ts +41 -0
  66. package/src/grammar/geoms/_shape.ts +74 -0
  67. package/src/grammar/geoms/aggregate.d.ts +95 -0
  68. package/src/grammar/geoms/aggregate.test.ts +554 -0
  69. package/src/grammar/geoms/aggregate.ts +840 -0
  70. package/src/grammar/geoms/area.d.ts +32 -0
  71. package/src/grammar/geoms/area.test.ts +165 -0
  72. package/src/grammar/geoms/area.ts +578 -0
  73. package/src/grammar/geoms/band.d.ts +27 -0
  74. package/src/grammar/geoms/band.test.ts +57 -0
  75. package/src/grammar/geoms/band.ts +126 -0
  76. package/src/grammar/geoms/bar.d.ts +56 -0
  77. package/src/grammar/geoms/bar.test.ts +367 -0
  78. package/src/grammar/geoms/bar.ts +1054 -0
  79. package/src/grammar/geoms/boxplot.d.ts +129 -0
  80. package/src/grammar/geoms/boxplot.test.ts +299 -0
  81. package/src/grammar/geoms/boxplot.ts +834 -0
  82. package/src/grammar/geoms/connected-scatter.d.ts +27 -0
  83. package/src/grammar/geoms/connected-scatter.test.ts +157 -0
  84. package/src/grammar/geoms/connected-scatter.ts +63 -0
  85. package/src/grammar/geoms/emphasis.d.ts +76 -0
  86. package/src/grammar/geoms/emphasis.test.ts +135 -0
  87. package/src/grammar/geoms/emphasis.ts +162 -0
  88. package/src/grammar/geoms/histogram.d.ts +75 -0
  89. package/src/grammar/geoms/histogram.test.ts +262 -0
  90. package/src/grammar/geoms/histogram.ts +740 -0
  91. package/src/grammar/geoms/index.d.ts +20 -0
  92. package/src/grammar/geoms/index.ts +77 -0
  93. package/src/grammar/geoms/interval.d.ts +31 -0
  94. package/src/grammar/geoms/interval.test.ts +154 -0
  95. package/src/grammar/geoms/interval.ts +342 -0
  96. package/src/grammar/geoms/line.d.ts +38 -0
  97. package/src/grammar/geoms/line.test.ts +247 -0
  98. package/src/grammar/geoms/line.ts +659 -0
  99. package/src/grammar/geoms/point.d.ts +57 -0
  100. package/src/grammar/geoms/point.test.ts +163 -0
  101. package/src/grammar/geoms/point.ts +545 -0
  102. package/src/grammar/geoms/polar.test.ts +216 -0
  103. package/src/grammar/geoms/ribbon.d.ts +21 -0
  104. package/src/grammar/geoms/ribbon.test.ts +170 -0
  105. package/src/grammar/geoms/ribbon.ts +87 -0
  106. package/src/grammar/geoms/ridgeline.d.ts +89 -0
  107. package/src/grammar/geoms/ridgeline.test.ts +247 -0
  108. package/src/grammar/geoms/ridgeline.ts +1164 -0
  109. package/src/grammar/geoms/rolling.d.ts +43 -0
  110. package/src/grammar/geoms/rolling.test.ts +217 -0
  111. package/src/grammar/geoms/rolling.ts +387 -0
  112. package/src/grammar/geoms/rug.d.ts +28 -0
  113. package/src/grammar/geoms/rug.test.ts +126 -0
  114. package/src/grammar/geoms/rug.ts +214 -0
  115. package/src/grammar/geoms/rule.d.ts +23 -0
  116. package/src/grammar/geoms/rule.test.ts +69 -0
  117. package/src/grammar/geoms/rule.ts +212 -0
  118. package/src/grammar/geoms/smooth.d.ts +54 -0
  119. package/src/grammar/geoms/smooth.test.ts +78 -0
  120. package/src/grammar/geoms/smooth.ts +337 -0
  121. package/src/grammar/geoms/text.d.ts +29 -0
  122. package/src/grammar/geoms/text.test.ts +64 -0
  123. package/src/grammar/geoms/text.ts +234 -0
  124. package/src/grammar/geoms/tile.d.ts +61 -0
  125. package/src/grammar/geoms/tile.test.ts +157 -0
  126. package/src/grammar/geoms/tile.ts +621 -0
  127. package/src/grammar/geoms/types.d.ts +319 -0
  128. package/src/grammar/geoms/types.ts +362 -0
  129. package/src/grammar/geoms/violin.d.ts +85 -0
  130. package/src/grammar/geoms/violin.test.ts +187 -0
  131. package/src/grammar/geoms/violin.ts +672 -0
  132. package/src/grammar/index.d.ts +22 -0
  133. package/src/grammar/index.ts +269 -0
  134. package/src/grammar/interactions/_disposable.d.ts +5 -0
  135. package/src/grammar/interactions/_disposable.ts +23 -0
  136. package/src/grammar/interactions/_z.d.ts +4 -0
  137. package/src/grammar/interactions/_z.ts +16 -0
  138. package/src/grammar/interactions/brush-selection.test.ts +262 -0
  139. package/src/grammar/interactions/brush.d.ts +63 -0
  140. package/src/grammar/interactions/brush.test.ts +483 -0
  141. package/src/grammar/interactions/brush.ts +452 -0
  142. package/src/grammar/interactions/crosshair.d.ts +19 -0
  143. package/src/grammar/interactions/crosshair.test.ts +127 -0
  144. package/src/grammar/interactions/crosshair.ts +76 -0
  145. package/src/grammar/interactions/hit-layer.d.ts +64 -0
  146. package/src/grammar/interactions/hit-layer.ts +246 -0
  147. package/src/grammar/interactions/legend.d.ts +19 -0
  148. package/src/grammar/interactions/legend.ts +101 -0
  149. package/src/grammar/interactions/menu.d.ts +93 -0
  150. package/src/grammar/interactions/menu.test.ts +373 -0
  151. package/src/grammar/interactions/menu.ts +342 -0
  152. package/src/grammar/interactions/selection.d.ts +25 -0
  153. package/src/grammar/interactions/selection.test.ts +289 -0
  154. package/src/grammar/interactions/selection.ts +142 -0
  155. package/src/grammar/interactions/series-readout.d.ts +91 -0
  156. package/src/grammar/interactions/series-readout.test.ts +668 -0
  157. package/src/grammar/interactions/series-readout.ts +422 -0
  158. package/src/grammar/interactions/series-snap.d.ts +70 -0
  159. package/src/grammar/interactions/series-snap.test.ts +214 -0
  160. package/src/grammar/interactions/series-snap.ts +218 -0
  161. package/src/grammar/interactions/tooltip-axis.test.ts +176 -0
  162. package/src/grammar/interactions/tooltip-touch.browser.test.ts +49 -0
  163. package/src/grammar/interactions/tooltip-touch.test.ts +161 -0
  164. package/src/grammar/interactions/tooltip.d.ts +140 -0
  165. package/src/grammar/interactions/tooltip.test.ts +406 -0
  166. package/src/grammar/interactions/tooltip.ts +622 -0
  167. package/src/grammar/interactions/transitions.d.ts +34 -0
  168. package/src/grammar/interactions/transitions.test.ts +172 -0
  169. package/src/grammar/interactions/transitions.ts +160 -0
  170. package/src/grammar/layout.d.ts +68 -0
  171. package/src/grammar/layout.ts +186 -0
  172. package/src/grammar/legend-merge.test.ts +332 -0
  173. package/src/grammar/mount.d.ts +78 -0
  174. package/src/grammar/mount.test.ts +479 -0
  175. package/src/grammar/mount.ts +2112 -0
  176. package/src/grammar/palettes.d.ts +54 -0
  177. package/src/grammar/palettes.test.ts +80 -0
  178. package/src/grammar/palettes.ts +167 -0
  179. package/src/grammar/pan-zoom.test.ts +398 -0
  180. package/src/grammar/phylo.d.ts +65 -0
  181. package/src/grammar/phylo.test.ts +59 -0
  182. package/src/grammar/phylo.ts +112 -0
  183. package/src/grammar/pipeline.auto-ticks.test.ts +40 -0
  184. package/src/grammar/pipeline.d.ts +158 -0
  185. package/src/grammar/pipeline.test.ts +463 -0
  186. package/src/grammar/pipeline.ts +1233 -0
  187. package/src/grammar/profiling.d.ts +8 -0
  188. package/src/grammar/profiling.ts +24 -0
  189. package/src/grammar/scales.d.ts +188 -0
  190. package/src/grammar/scales.test.ts +181 -0
  191. package/src/grammar/scales.ts +800 -0
  192. package/src/grammar/svg.d.ts +3 -0
  193. package/src/grammar/svg.ts +39 -0
  194. package/src/grammar/theme.d.ts +261 -0
  195. package/src/grammar/theme.test.ts +105 -0
  196. package/src/grammar/theme.ts +490 -0
  197. package/src/heatmap/cpu.ts +109 -0
  198. package/src/heatmap/gpu.ts +565 -0
  199. package/src/heatmap/types.ts +177 -0
  200. package/src/heatmap.browser.test.ts +308 -0
  201. package/src/heatmap.test.ts +320 -0
  202. package/src/heatmap.ts +123 -0
  203. package/src/index.d.ts +1 -0
  204. package/src/index.ts +8 -0
  205. package/src/interactions.d.ts +48 -0
  206. package/src/interactions.test.ts +226 -0
  207. package/src/interactions.ts +394 -0
  208. package/src/layout/box.d.ts +48 -0
  209. package/src/layout/box.test.ts +107 -0
  210. package/src/layout/box.ts +143 -0
  211. package/src/legend.d.ts +115 -0
  212. package/src/legend.ts +422 -0
  213. package/src/marks/curve.d.ts +43 -0
  214. package/src/marks/curve.ts +244 -0
  215. package/src/marks/stack.d.ts +53 -0
  216. package/src/marks/stack.ts +184 -0
  217. package/src/marks.d.ts +273 -0
  218. package/src/marks.test.ts +541 -0
  219. package/src/marks.ts +1292 -0
  220. package/src/navigator.test.ts +174 -0
  221. package/src/navigator.ts +393 -0
  222. package/src/range-presets.d.ts +113 -0
  223. package/src/range-presets.test.ts +345 -0
  224. package/src/range-presets.ts +349 -0
  225. package/src/scales.d.ts +98 -0
  226. package/src/scales.test.ts +103 -0
  227. package/src/scales.ts +695 -0
  228. package/src/stats/index.d.ts +200 -0
  229. package/src/stats/index.test.ts +349 -0
  230. package/src/stats/index.ts +740 -0
  231. package/src/stats/regression.d.ts +38 -0
  232. package/src/stats/regression.test.ts +56 -0
  233. package/src/stats/regression.ts +396 -0
  234. package/src/stats/rolling-window.d.ts +55 -0
  235. package/src/stats/rolling-window.test.ts +237 -0
  236. package/src/stats/rolling-window.ts +256 -0
  237. package/src/test-setup.ts +19 -0
  238. package/src/viewport/axis-state.d.ts +72 -0
  239. package/src/viewport/axis-state.ts +476 -0
  240. package/src/viewport.d.ts +170 -0
  241. package/src/viewport.test.ts +363 -0
  242. package/src/viewport.ts +510 -0
@@ -0,0 +1,3426 @@
1
+ import { $t as SwatchSpec, C as KdeBandwidth, D as QuantileMethod, Dn as LineDashStyle, Dr as TimeIntervalUnit, Jn as StackOrder, Nn as PointShapeKind, O as WhiskerRule, Or as TimeScale, Qn as LineCurve, S as HistogramMeasure, Sn as BarOrientation, Tr as NumericRange, U as RollingWindow, V as RollingStatistic, bn as BarBorderStyle, br as ContinuousScale, c as RangePresetsSubscriber, cn as LabelBoxStyle, cr as AxisTickFormatter, dn as ValueLabelAlign, dr as TickSpec, ft as CategoricalPalette, g as BinClosed, i as RangePresetDataDomain, jn as PointBorderStyle, kn as MarkBuilder, l as TimePresetKey, or as AxisOptions, pt as ContinuousPalette, t as RangePreset, tt as DataViewport, ur as TickIntervalSpec, v as BinResult, vr as BandScale, w as KdeKernel, y as BinRule, z as RollingAxis } from "./range-presets-CzECsu3V.mjs";
2
+ import * as _$insomni from "insomni";
3
+ import { BlendSpace, BlendSpace as BlendSpace$1, BrushAxis, BrushRect, Color, Easing, Frame, FrameTiming, GlyphAtlas, InteractionManager, Invalidator, Layer, Padding, Renderer2D } from "insomni";
4
+ import { Signal } from "insomni/reactivity";
5
+
6
+ //#region src/grammar/accessibility.d.ts
7
+ type AccessibilityMode = "auto-color" | "outline" | "shadow" | "none";
8
+ type ContrastMetric = "wcag" | "apca";
9
+ interface Accessibility {
10
+ /**
11
+ * Master switch. When `false`, `resolveTextColor` never alters colors —
12
+ * but if `warn` is also true it logs the failing site once per session so
13
+ * authors can see what would have been fixed.
14
+ */
15
+ enabled: boolean;
16
+ /**
17
+ * Which contrast metric to enforce.
18
+ *
19
+ * `"apca"` (default) uses APCA Lc — perceptually uniform and
20
+ * polarity-aware, so equalizing produces labels that read with the same
21
+ * weight whether they sit on a dark or a light cell.
22
+ *
23
+ * `"wcag"` uses the WCAG 2.1 ratio formula. Kept for backwards
24
+ * compatibility; equalizing on WCAG ratio looks visually unbalanced
25
+ * across polarities.
26
+ */
27
+ metric: ContrastMetric;
28
+ /**
29
+ * WCAG-mode target. `"AA"` = 4.5:1 normal / 3:1 large; `"AAA"` = 7:1 / 4.5:1.
30
+ * A raw number sets an absolute minimum ratio (1–21) applied to all text
31
+ * regardless of size. Ignored when `metric === "apca"`.
32
+ */
33
+ wcagLevel: "AA" | "AAA" | number;
34
+ /**
35
+ * APCA-mode target |Lc|. `"auto"` (default) looks up the recommended
36
+ * minimum from APCA's font/weight table for each site (typical body text
37
+ * lands around Lc 75–90). A raw number applies a single |Lc| floor to
38
+ * every site. Ignored when `metric === "wcag"`.
39
+ */
40
+ apcaTarget: number | "auto";
41
+ /**
42
+ * How to fix low-contrast text. `auto-color` nudges the color toward an
43
+ * accessible shade preserving hue/saturation. `outline` / `shadow` are
44
+ * reserved API hooks — both currently degrade to `auto-color` since the
45
+ * SDF text pipeline doesn't render text effects yet. `none` leaves text
46
+ * untouched (and warns when `warn` is on).
47
+ */
48
+ mode: AccessibilityMode;
49
+ /** Whether to console.warn on contrast failures the system isn't fixing. */
50
+ warn: boolean;
51
+ /**
52
+ * When true, every *mark* label (geom-rendered, sitting on a data-driven
53
+ * fill) is normalized to *exactly* the target contrast — not just `>=`.
54
+ * Equalizing prevents cells with high contrast from visually outweighing
55
+ * neighbors. Hue and saturation are preserved; only lightness shifts.
56
+ *
57
+ * Chrome text (titles, axis, legend) skips this — those sit on the
58
+ * panel background and equalizing them just dims legible chrome.
59
+ */
60
+ equalize: boolean;
61
+ /**
62
+ * How strongly the auto-fixer pulls toward colors already in the theme.
63
+ * `0` keeps the original hue/sat untouched. `1` snaps to the nearest
64
+ * passing theme accent. Intermediate values blend in `blendSpace`,
65
+ * keeping the label feeling "of the same family" as the chart's palette.
66
+ *
67
+ * The pull is only applied when at least one accent independently meets
68
+ * the contrast target — biasing toward an unreadable accent would defeat
69
+ * the fix. When `equalize` is on, the L-channel is re-fit after the blend
70
+ * so the final contrast still lands at the target.
71
+ */
72
+ themeBias: number;
73
+ /**
74
+ * Optional explicit accent palette for the bias. When unset, the
75
+ * resolver derives accents from the active theme (text/title/legend
76
+ * colors plus a sample of the categorical palette).
77
+ */
78
+ accents?: readonly Color[];
79
+ /**
80
+ * Color space used for the theme-bias blend. Defaults to `"oklch"` —
81
+ * perceptually uniform with hue preserved along the blend.
82
+ */
83
+ blendSpace: BlendSpace$1;
84
+ }
85
+ declare const DEFAULT_ACCESSIBILITY: Accessibility;
86
+ /**
87
+ * Stub for SDF text effects. Setting these on the theme today has no visual
88
+ * effect — the renderer will pick them up once outline/shadow are wired into
89
+ * the text pipeline. Kept on the public API so call sites and themes can
90
+ * declare intent now without a follow-up breaking change.
91
+ */
92
+ interface TextEffects {
93
+ outline?: {
94
+ color: Color;
95
+ width: number;
96
+ };
97
+ shadow?: {
98
+ color: Color;
99
+ blur?: number;
100
+ dx?: number;
101
+ dy?: number;
102
+ };
103
+ }
104
+ interface ResolveTextColorOptions {
105
+ /** Font size in CSS pixels. */
106
+ fontSizePx: number;
107
+ /** Treat the text as bold (affects WCAG large-text and APCA weight lookup). */
108
+ bold?: boolean;
109
+ /**
110
+ * Short label identifying the draw site (e.g. `"axis-label"`,
111
+ * `"tile-label"`). Used to namespace dedupe keys for warnings.
112
+ */
113
+ site: string;
114
+ /**
115
+ * Whether this site sits on a *data-driven* background (mark fills,
116
+ * heatmap cells) versus chrome on the panel background. `equalize`
117
+ * normalization applies only to mark sites — chrome text always sits on
118
+ * the same panel background, so equalizing it would just lower legible
119
+ * titles/axis/legend text down toward the contrast floor for no gain.
120
+ * Default `false`.
121
+ */
122
+ markLabel?: boolean;
123
+ /**
124
+ * Override the engine-computed target. When set, the resolver uses this
125
+ * value instead of the font/level lookup. Used by geoms that need to
126
+ * coordinate a layer-wide equalize floor (e.g. tile pulls every label
127
+ * down to the worst cell's max-achievable contrast so the layer reads
128
+ * uniformly, instead of saturating each label at its own per-cell max).
129
+ */
130
+ targetOverride?: number;
131
+ /** @internal — APCA polarity, computed inside the resolver. */
132
+ _apcaReverse?: boolean;
133
+ }
134
+ /**
135
+ * Resolve the actual color that should be drawn for a piece of text given
136
+ * the requested foreground, the known background, and the chart's
137
+ * accessibility policy. Pure — does not draw anything.
138
+ */
139
+ declare function resolveTextColor(fg: Color, bg: Color, theme: Theme, opts: ResolveTextColorOptions): Color;
140
+ //#endregion
141
+ //#region src/grammar/theme.d.ts
142
+ interface ThemeText {
143
+ color: Color;
144
+ fontFamily: string;
145
+ }
146
+ interface ThemeTitle {
147
+ fontSize: number;
148
+ fontWeight: string;
149
+ color: Color;
150
+ }
151
+ interface ThemeSubtitle {
152
+ fontSize: number;
153
+ color: Color;
154
+ }
155
+ interface ThemeAxis {
156
+ color: Color;
157
+ gridColor: Color;
158
+ labelFontSize: number;
159
+ labelColor: Color;
160
+ titleFontSize: number;
161
+ titleColor: Color;
162
+ }
163
+ interface ThemeLegend {
164
+ fontSize: number;
165
+ labelColor: Color;
166
+ swatchGap: number;
167
+ entryGap: number;
168
+ }
169
+ interface ThemeMarks {
170
+ pointRadius: number;
171
+ pointStroke: Color | undefined;
172
+ pointStrokeWidth: number;
173
+ /**
174
+ * Default stroke width for line-based marks (`line`, `smooth`, `statRolling`,
175
+ * `area` outline, `aggregate` line geom). Geom-level `strokeWidth` options
176
+ * override this token per layer.
177
+ */
178
+ strokeWidth: number;
179
+ barCornerRadius: number;
180
+ fillAlpha: number;
181
+ /** Font size for value/total labels rendered alongside marks (bar, text). */
182
+ labelFontSize: number;
183
+ /** Default stroke width for `rule()` lines. */
184
+ ruleStrokeWidth: number;
185
+ /** Default label inset for `rule()` annotations. */
186
+ ruleLabelInset: number;
187
+ /** Default font size for inline annotations (rule, band labels). */
188
+ annotationFontSize: number;
189
+ /** Default fill alpha for `ribbon()`. */
190
+ ribbonFillAlpha: number;
191
+ /** Default fill alpha for `band()` highlight regions. */
192
+ bandFillAlpha: number;
193
+ /** Default size-channel pixel range. */
194
+ sizeRange: readonly [number, number];
195
+ /** Default alpha-channel range. */
196
+ alphaRange: readonly [number, number];
197
+ }
198
+ type ThemeDurationKey = "fast" | "base" | "slow";
199
+ type ThemeEasingKey = "standard" | "emphasized" | "decelerate" | "linear";
200
+ interface ThemeDurations {
201
+ fast: number;
202
+ base: number;
203
+ slow: number;
204
+ }
205
+ interface ThemeEasings {
206
+ standard: Easing;
207
+ emphasized: Easing;
208
+ decelerate: Easing;
209
+ linear: Easing;
210
+ }
211
+ interface ThemeMotionChannel {
212
+ duration: ThemeDurationKey;
213
+ easing: ThemeEasingKey;
214
+ }
215
+ interface ThemeMotionTooltip {
216
+ showDelay: number;
217
+ hideDelay: number;
218
+ fadeMs: number;
219
+ /**
220
+ * Hover-intent settle (ms). Rapid enter/leave/switch events are coalesced —
221
+ * the tooltip only commits a show/hide after the cursor holds a target this
222
+ * long. Prevents an overlay re-render per cell while sweeping across a dense
223
+ * mark grid or through gaps. 0 disables (commit immediately).
224
+ */
225
+ settleDelay: number;
226
+ }
227
+ interface ThemeMotion {
228
+ /** Master switch. False → snap, no scheduled motion. */
229
+ enabled: boolean;
230
+ duration: ThemeDurations;
231
+ easing: ThemeEasings;
232
+ /** Data update / scale change transitions. */
233
+ data: ThemeMotionChannel;
234
+ /** Axis tick / domain transitions. */
235
+ axis: ThemeMotionChannel;
236
+ tooltip: ThemeMotionTooltip;
237
+ }
238
+ interface ThemeInteractionEmphasis {
239
+ /** Master enable. `false` skips both halo and dim. */
240
+ enabled: boolean;
241
+ /** Multiplier on non-active rows' fill alpha. `1` = no dim. */
242
+ dim: number;
243
+ /** Halo stroke width in CSS px. `0` skips the halo. */
244
+ haloStrokeWidth: number;
245
+ /**
246
+ * Halo ring color. When omitted, geoms fall back to a high-contrast
247
+ * foreground (`theme.text.color`) so the focus ring reads against the
248
+ * marks rather than blending in with the datum's own color. Set a `Color`
249
+ * to pin the ring (e.g. a brand accent).
250
+ */
251
+ haloColor?: Color;
252
+ /**
253
+ * Duration (ms) of the GPU dim animation driven through the core's emphasis
254
+ * uniform (P5-T3). On a hover hit-change over a dim-participating geom the
255
+ * mount ramps the emphasis `t` 0→1 (ease-out cubic) over this window; on
256
+ * hover exit it ramps t→0. Only consumed by `hover` (selection dim stays a
257
+ * compile-time treatment). `<= 0` snaps. Default ~120ms.
258
+ */
259
+ durationMs?: number;
260
+ }
261
+ /**
262
+ * Semantic row-tint tokens for tooltip rows that use the
263
+ * `accent: "positive" | "negative" | "neutral"` shorthand. `neutral` is
264
+ * intentionally omitted — it means "no override, use the default row text
265
+ * color from the underlying tooltip style." Consumers can also pass a raw
266
+ * `Color` per row to bypass these tokens entirely.
267
+ */
268
+ interface ThemeTooltipAccents {
269
+ positive: Color;
270
+ negative: Color;
271
+ }
272
+ interface ThemeInteractions {
273
+ /** Visual treatment applied while a row is hovered. */
274
+ hover: ThemeInteractionEmphasis;
275
+ /** Visual treatment applied while rows are selected. */
276
+ selection: ThemeInteractionEmphasis;
277
+ /**
278
+ * Grace window (ms) applied when hover transitions to "nothing" before
279
+ * propagating the null state to dim/halo and crosshair. If a new hit lands
280
+ * within this window, the swap goes directly from prev → next without
281
+ * passing through null — eliminates the un-dim → re-dim flash when the
282
+ * cursor crosses between adjacent or near-adjacent geoms. `0` disables.
283
+ */
284
+ hoverSwapGraceMs: number;
285
+ /** Semantic row colors for the tooltip `accent` shorthand. */
286
+ tooltipAccents: ThemeTooltipAccents;
287
+ }
288
+ interface ThemePalettes {
289
+ categorical: CategoricalPalette;
290
+ continuous: ContinuousPalette;
291
+ diverging: ContinuousPalette;
292
+ }
293
+ /**
294
+ * Semantic accent palette consumed by chart-level marks that carry meaning
295
+ * (reference regions, threshold rules, callouts, tooltip rows). Geoms that
296
+ * accept an accent key (`fill: "positive"`, `stroke: "warn"`) resolve through
297
+ * this block; literal `Color` values still bypass it.
298
+ *
299
+ * Naming exception to the "name geoms by what they are, not what they do"
300
+ * principle: these tokens exist explicitly to carry semantics. The names
301
+ * follow conventional status vocabulary so any reader can predict the role.
302
+ *
303
+ * `neutral` is intentionally omitted — it means "no override, use the
304
+ * surrounding default" (mark fill, axis label color, …) so consumers can fall
305
+ * back without spelling out a token.
306
+ *
307
+ * Distinct from {@link ThemeTooltipAccents} (under `interactions.tooltipAccents`)
308
+ * which is sized for tooltip-text contrast and may differ in luminance.
309
+ */
310
+ interface ThemeAccents {
311
+ positive: Color;
312
+ negative: Color;
313
+ warn: Color;
314
+ info: Color;
315
+ }
316
+ type ThemeAccentKey = keyof ThemeAccents;
317
+ interface Theme {
318
+ background: Color;
319
+ text: ThemeText;
320
+ title: ThemeTitle;
321
+ subtitle: ThemeSubtitle;
322
+ axis: ThemeAxis;
323
+ legend: ThemeLegend;
324
+ marks: ThemeMarks;
325
+ palettes: ThemePalettes;
326
+ /** Semantic accent palette for chart-level marks (reference regions, threshold rules, callouts). */
327
+ accents: ThemeAccents;
328
+ /**
329
+ * Text-readability policy. Applied at every draw site where the chart
330
+ * knows the local background color (titles/axis/legend versus the panel
331
+ * background; tile labels versus their cell color).
332
+ */
333
+ accessibility: Accessibility;
334
+ /**
335
+ * Default text effects (outline / drop shadow). API stub today — the SDF
336
+ * text path doesn't render these yet. See
337
+ * dev_docs/2026-04-30-text-accessibility.md.
338
+ */
339
+ textEffects?: TextEffects;
340
+ /**
341
+ * Color space used to interpolate continuous palettes (`viridis`, etc.)
342
+ * when sampled by color scales and color bars. `oklch` is the default —
343
+ * perceptually uniform with hue preserved along the gradient. Override
344
+ * per chart (`theme({ paletteBlendSpace: "srgb" })`) or per call (the
345
+ * `blendSpace` option on color-scale and `colorBar` specs).
346
+ */
347
+ paletteBlendSpace: BlendSpace$1;
348
+ /**
349
+ * Motion tokens — durations, easings, and per-channel defaults consumed by
350
+ * interactions (hover, tooltip), data transitions, and axis updates. See
351
+ * {@link defaultMotion} and {@link applyReducedMotion}.
352
+ */
353
+ motion: ThemeMotion;
354
+ /**
355
+ * Hover / selection emphasis tokens. Geoms read these to render the active
356
+ * row's halo and optionally dim the rest. See {@link defaultInteractions}.
357
+ */
358
+ interactions: ThemeInteractions;
359
+ }
360
+ declare const themeDefault: Theme;
361
+ /**
362
+ * Light/minimal theme — white plot background, soft gray gridlines, dark
363
+ * labels. Pairs well with the `category10` palette and is a good default for
364
+ * scatter / smooth charts that should read like a ggplot2 / R reference.
365
+ */
366
+ declare const themeMinimalGrid: Theme;
367
+ type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K] };
368
+ /**
369
+ * Compose a theme by deep-merging overrides into a base theme. Accepts a
370
+ * shallow override on any nested group (e.g. `{ marks: { strokeWidth: 2 } }`).
371
+ */
372
+ declare function theme(overrides: DeepPartial<Theme>, base?: Theme): Theme;
373
+ //#endregion
374
+ //#region src/grammar/attach-presets.d.ts
375
+ /** Where the chip strip sits inside its mount element. */
376
+ type AttachRangePresetsPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
377
+ interface AttachRangePresetsUi {
378
+ /** Element to append the chip strip into (typically the chart's stage). */
379
+ mount: HTMLElement;
380
+ /** Corner placement inside `mount`. Defaults to `"top-left"`. */
381
+ position?: AttachRangePresetsPosition;
382
+ /** Inset (px) from the chosen corner. Defaults to `12`. */
383
+ inset?: number;
384
+ }
385
+ interface AttachRangePresetsOptions {
386
+ axis: "x" | "y";
387
+ /**
388
+ * Presets to expose. A `TimePresetKey` string is expanded to `timePreset(key)`;
389
+ * pass a full `RangePreset` for custom presets (label override, linear/log
390
+ * presets, etc.).
391
+ */
392
+ presets: readonly (TimePresetKey | RangePreset)[];
393
+ dataDomain?: RangePresetDataDomain;
394
+ now?: () => number;
395
+ /** Omit to skip DOM construction — returns the same controller, headless. */
396
+ ui?: AttachRangePresetsUi;
397
+ }
398
+ interface AttachedRangePresets {
399
+ setActive(key: string | null): void;
400
+ getActive(): string | null;
401
+ subscribe(fn: RangePresetsSubscriber): () => void;
402
+ dispose(): void;
403
+ }
404
+ declare function attachRangePresets(viewport: DataViewport<any, any>, theme: Theme, opts: AttachRangePresetsOptions): AttachedRangePresets;
405
+ //#endregion
406
+ //#region src/grammar/coord.d.ts
407
+ interface Point {
408
+ x: number;
409
+ y: number;
410
+ }
411
+ /**
412
+ * Inputs to `Coord.renderAxes`. The pipeline owns scale construction and
413
+ * layout; the coord owns axis dispatch (Cartesian → bottom + left; polar →
414
+ * angular ring + radial spokes).
415
+ */
416
+ interface CoordAxesArgs {
417
+ axisLayer: Layer;
418
+ scales: ScaleBundle;
419
+ /** Inner plot frame — coords project relative to this. */
420
+ plotFrame: _$insomni.Frame;
421
+ /** True when the chart actually has a column on this channel. Skipped axes are not drawn. */
422
+ hasX: boolean;
423
+ hasY: boolean;
424
+ xAxisOptions: AxisOptions<unknown>;
425
+ yAxisOptions: AxisOptions<unknown>;
426
+ atlas: GlyphAtlas | undefined;
427
+ }
428
+ /**
429
+ * Inputs to `Coord.handlePan`. The mount / interactions layer passes a pointer
430
+ * delta in plot-frame pixels plus the active plot frame and a viewport handle
431
+ * the coord can use to mutate scale state. Cartesian delegates the whole
432
+ * thing to `viewport.panBy(dx, dy)`; polar decomposes into tangential
433
+ * (rotate `startAngle`) and radial (translate radius domain via the viewport).
434
+ */
435
+ interface CoordPanArgs {
436
+ dx: number;
437
+ dy: number;
438
+ /** Plot frame in absolute layer-pixel space (x, y are screen-space origin). */
439
+ plotFrame: _$insomni.Frame;
440
+ /** Viewport handle for scale-domain mutations. */
441
+ viewport: CoordViewportHandle;
442
+ }
443
+ interface CoordZoomArgs {
444
+ /**
445
+ * Multiplicative zoom factor — `> 1` zooms in, `< 1` zooms out. May be a
446
+ * scalar (both axes) or a `{ x?, y? }` per-axis form (matches
447
+ * `viewport.zoomAt` and the masking that `bindDataViewport` performs).
448
+ */
449
+ factor: number | {
450
+ x?: number;
451
+ y?: number;
452
+ };
453
+ /** Cursor position in absolute layer-pixel space (matches `viewport.zoomAt`). */
454
+ cx: number;
455
+ cy: number;
456
+ plotFrame: _$insomni.Frame;
457
+ viewport: CoordViewportHandle;
458
+ }
459
+ /**
460
+ * Minimal facade over `DataViewport` so the coord can mutate scale state
461
+ * without depending on the full viewport surface. The two methods polar
462
+ * uses (`panBy`, `zoomAt`) match `DataViewport` semantics 1:1; Cartesian's
463
+ * implementation forwards through them so behavior is byte-identical to the
464
+ * pre-`handlePan` path.
465
+ */
466
+ interface CoordViewportHandle {
467
+ panBy(dxPx: number, dyPx: number): void;
468
+ zoomAt(anchorSx: number, anchorSy: number, factor: number | {
469
+ x?: number;
470
+ y?: number;
471
+ }): void;
472
+ }
473
+ /**
474
+ * A coordinate system. Polar / cartesian today; future room for log-polar /
475
+ * geographic projections behind the same interface.
476
+ */
477
+ interface Coord {
478
+ readonly kind: "cartesian" | "polar";
479
+ /**
480
+ * Bind the coord to a specific plot frame for the upcoming render.
481
+ * Polar's `project` / `segment` / `renderAxes` need the plot-frame
482
+ * dimensions and centre to compute (cx, cy) and the default outerRadius.
483
+ * Called by the pipeline once per panel (faceted) or once per chart
484
+ * (unfaceted) before any `project` / `renderAxes` call. Cartesian no-ops.
485
+ */
486
+ bindFrame(plotFrame: _$insomni.Frame): void;
487
+ /**
488
+ * Map a single point from plot-frame pixel space (0..plotFrame.width on x,
489
+ * 0..plotFrame.height on y — i.e. the raw output of `xScale.fn` / `yScale.fn`)
490
+ * to layer-pixel space (still relative to the plot frame's origin —
491
+ * `plot.topLeft` offsets are applied later by each geom).
492
+ *
493
+ * Cartesian: identity. Polar: (θ, r) → (cx + r·cosθ, cy + r·sinθ).
494
+ */
495
+ project(p: Point): Point;
496
+ /**
497
+ * Tessellate a polyline segment between two points in plot-frame pixel
498
+ * space. Returns the projected pixel points (including both endpoints).
499
+ * Cartesian returns `[project(p1), project(p2)]`; polar returns ~N points
500
+ * along the arc.
501
+ */
502
+ segment(p1: Point, p2: Point): Point[];
503
+ /**
504
+ * Render axes into `args.axisLayer`. Cartesian draws bottom (x) + left (y);
505
+ * polar draws an angular ring (spokes) + radial concentric circles.
506
+ */
507
+ renderAxes(args: CoordAxesArgs): void;
508
+ /**
509
+ * Inverse of `project`, for hit-testing / tooltips. Cartesian is the
510
+ * identity within the plot frame. Polar inverts (θ, r) and returns `null`
511
+ * when the projected point is outside `[innerRadius, outerRadius]`.
512
+ */
513
+ unproject(p: Point): Point | null;
514
+ /**
515
+ * Translate a pointer pan delta into scale-domain mutations.
516
+ * Cartesian forwards to `viewport.panBy(dx, dy)` — byte-identical to the
517
+ * pre-coord path. Polar decomposes the delta relative to the plot centre
518
+ * into tangential (rotate `startAngle`) and radial (translate the radius
519
+ * scale via `viewport.panBy(0, radial_dy)`) components.
520
+ */
521
+ handlePan(args: CoordPanArgs): void;
522
+ /**
523
+ * Translate a zoom factor + anchor into scale-domain mutations.
524
+ * Cartesian forwards to `viewport.zoomAt(cx, cy, factor)`. Polar scales the
525
+ * radius domain around the cursor's data-space radius; angle scale
526
+ * unchanged.
527
+ */
528
+ handleZoom(args: CoordZoomArgs): void;
529
+ }
530
+ /**
531
+ * Default coord — identity projection, current axis behavior. Plot's existing
532
+ * pipeline behaves exactly as it did before the `Coord` interface was added
533
+ * when this is in use.
534
+ */
535
+ declare function coordCartesian(): Coord;
536
+ interface CoordPolarOptions {
537
+ /** Angle (radians) where the angular axis starts. Default `-π/2` (top). */
538
+ startAngle?: number;
539
+ /** Angle where the angular axis ends. Default `startAngle + 2π` (full circle). */
540
+ endAngle?: number;
541
+ /**
542
+ * Convenience for non-full-circle layouts: the gap (in radians) between
543
+ * `startAngle` and `endAngle`. `openAngle: 0` ↔ full circle;
544
+ * `openAngle: π/4` ↔ fan with a 45° gap at the start. Ignored when
545
+ * `endAngle` is provided.
546
+ */
547
+ openAngle?: number;
548
+ /** `1` (default, CCW) or `-1` (CW). */
549
+ direction?: 1 | -1;
550
+ /** Inner radius in pixels. Default `0`. */
551
+ innerRadius?: number;
552
+ /**
553
+ * Outer radius in pixels. Default `min(plotFrame.width, plotFrame.height) / 2`
554
+ * — resolved lazily on `bindFrame`.
555
+ */
556
+ outerRadius?: number;
557
+ /** Which channel maps to θ. Default `'y'` (gheatmap/circular-tree convention). */
558
+ angleChannel?: "x" | "y";
559
+ /** Angular tessellation step (radians) for `segment` and circular axes. Default ~1°. */
560
+ quality?: number;
561
+ }
562
+ /**
563
+ * Polar projection. See {@link CoordPolarOptions}.
564
+ *
565
+ * Each call returns a fresh stateful coord so the same `coordPolar({...})`
566
+ * expression can be reused safely. `bindFrame` mutates the centre and the
567
+ * default `outerRadius`.
568
+ */
569
+ declare function coordPolar(opts?: CoordPolarOptions): Coord;
570
+ /**
571
+ * Convenience polar coord: full circle, root at centre. Equivalent to
572
+ * `coordPolar({ openAngle: 0, innerRadius: 0 })`.
573
+ */
574
+ declare function coordRadial(opts?: Omit<CoordPolarOptions, "openAngle" | "innerRadius">): Coord;
575
+ //#endregion
576
+ //#region src/grammar/geoms/emphasis.d.ts
577
+ /**
578
+ * A geom's hover-dim emphasis-key resolver, captured at compile time so the
579
+ * mount can map an active {@link HoveredHit} to the namespaced key it tagged
580
+ * its focused instance(s) with — WITHOUT recompiling. `geomKind` + `data`
581
+ * identity match the resolver to the hit (the same keys that route a hit to its
582
+ * geom, mirroring {@link GeomHoverDecorator}). `resolve` returns the focused
583
+ * key, or `null` when this hit focuses nothing in the geom (the mount then
584
+ * leaves emphasis settled). The geom computes the SAME ordinal it used to tag.
585
+ */
586
+ interface EmphasisResolver {
587
+ readonly geomKind: GeomKind;
588
+ readonly data: readonly unknown[];
589
+ resolve(hit: HoveredHit): number | null;
590
+ }
591
+ //#endregion
592
+ //#region src/grammar/aes.d.ts
593
+ type ColumnKeys<T, V> = { [K in keyof T]-?: T[K] extends V ? K : never }[keyof T];
594
+ type Accessor<T, V> = (datum: T, index: number) => V;
595
+ type Aes<T, V> = ColumnKeys<T, V> | Accessor<T, V> | V;
596
+ interface ResolvedAes<T, V> {
597
+ readonly kind: "column" | "accessor" | "constant";
598
+ readonly column?: keyof T & string;
599
+ readonly fn: Accessor<T, V>;
600
+ }
601
+ /**
602
+ * Best-effort guess of a channel's data type. Used to pick a default scale
603
+ * type when no override is supplied. Null / undefined values are skipped
604
+ * (see "Null / undefined policy" above).
605
+ */
606
+ type ChannelDataType = "number" | "date" | "string" | "boolean" | "unknown";
607
+ //#endregion
608
+ //#region src/grammar/scales.d.ts
609
+ type Channel = "x" | "y" | "color" | "size" | "shape" | "alpha" | "borderStyle" | "overlayGlyph";
610
+ type PositionScaleType = "linear" | "log" | "sqrt" | "time" | "band";
611
+ type ColorScaleType = "categorical" | "continuous" | "diverging";
612
+ interface BasePositionScaleOptions {
613
+ range?: NumericRange;
614
+ nice?: boolean;
615
+ padding?: number;
616
+ }
617
+ /**
618
+ * `"nice"` is sugar for the existing `nice: true` flag — set as the domain
619
+ * shortcut so consumers don't need a second toggle when the only reason to
620
+ * touch `domain` was to pad it to round values. The data extent still
621
+ * derives the underlying numbers; `"nice"` just toggles the rounding.
622
+ */
623
+ type NumericDomainShortcut = "nice";
624
+ interface NumericPositionScaleOptions extends BasePositionScaleOptions {
625
+ type?: "linear" | "log" | "sqrt";
626
+ domain?: readonly [number, number] | NumericDomainShortcut;
627
+ }
628
+ interface TimePositionScaleOptions extends BasePositionScaleOptions {
629
+ type?: "time";
630
+ domain?: readonly [Date, Date];
631
+ }
632
+ interface BandPositionScaleOptions extends BasePositionScaleOptions {
633
+ type?: "band";
634
+ domain?: readonly string[];
635
+ }
636
+ type PositionScaleOptions = NumericPositionScaleOptions | TimePositionScaleOptions | BandPositionScaleOptions;
637
+ interface CategoricalColorScaleOptions<T> {
638
+ type?: "categorical";
639
+ domain?: readonly T[];
640
+ palette?: CategoricalPalette;
641
+ }
642
+ /**
643
+ * Color-scale domain shortcuts.
644
+ *
645
+ * - `"nice"`: alias for the existing `nice: true` flag on continuous color
646
+ * scales — pad the data extent to round values.
647
+ * - `"quantile"`: bucket the data into N quantile bins (default 5). The
648
+ * returned scale's `type` becomes `"categorical"` with bucket-label
649
+ * domain entries (`"Q1".."QN"`), and the palette is sampled at N evenly
650
+ * spaced stops along the chart's continuous palette so the color
651
+ * gradient reads as ordinal magnitude rather than nominal category.
652
+ */
653
+ type ColorDomainShortcut = "nice" | "quantile";
654
+ interface ContinuousColorScaleOptions {
655
+ type: "continuous" | "diverging";
656
+ domain?: readonly [number, number] | ColorDomainShortcut;
657
+ palette?: ContinuousPalette;
658
+ /**
659
+ * Extend the inferred domain outward to "nice" round values (e.g. data
660
+ * extent `[-2.8, 1.9]` → `[-3, 2]`). Same algorithm position scales use
661
+ * via `nice: true`. Ignored when `domain` is set explicitly to a tuple.
662
+ * Equivalent to `domain: "nice"` — keep one form per chart for clarity.
663
+ */
664
+ nice?: boolean;
665
+ /**
666
+ * Number of quantile buckets to use when `domain: "quantile"`. Default 5
667
+ * (quintiles). Ignored otherwise.
668
+ */
669
+ quantiles?: number;
670
+ /**
671
+ * Override the color space used to interpolate the palette stops.
672
+ * Falls back to `theme.paletteBlendSpace` (default `"oklch"`).
673
+ */
674
+ blendSpace?: _$insomni.BlendSpace;
675
+ }
676
+ type ColorScaleOptions<T> = CategoricalColorScaleOptions<T> | ContinuousColorScaleOptions;
677
+ interface SizeScaleOptions {
678
+ type?: "linear" | "sqrt";
679
+ domain?: readonly [number, number];
680
+ range?: readonly [number, number];
681
+ }
682
+ interface AlphaScaleOptions {
683
+ domain?: readonly [number, number];
684
+ range?: readonly [number, number];
685
+ }
686
+ interface ShapeScaleOptions {
687
+ /** Explicit category order (default: order of first appearance). */
688
+ domain?: readonly unknown[];
689
+ /** Override the shape palette. Default: `POINT_SHAPE_PALETTE` from `marks`. */
690
+ palette?: readonly PointShapeKind[];
691
+ }
692
+ interface BorderStyleScaleOptions {
693
+ /** Explicit category order (default: order of first appearance). */
694
+ domain?: readonly unknown[];
695
+ /** Override the border-style palette. Default: `DEFAULT_BORDER_STYLE_PALETTE`. */
696
+ palette?: readonly PointBorderStyle[];
697
+ }
698
+ interface OverlayGlyphScaleOptions {
699
+ /** Explicit category order (default: order of first appearance). */
700
+ domain?: readonly unknown[];
701
+ /**
702
+ * Override the overlay palette. Default: a small subset of
703
+ * `POINT_SHAPE_PALETTE` excluding `circle` so the overlay is visually
704
+ * distinct from the typical base shape. Use `null` entries to suppress an
705
+ * overlay for that domain value.
706
+ */
707
+ palette?: readonly (PointShapeKind | null)[];
708
+ }
709
+ /** A scale callable: any value → number (or color, for color channels). */
710
+ type ScaleFn<In, Out> = (value: In) => Out;
711
+ interface PositionScale {
712
+ readonly kind: "position";
713
+ readonly type: PositionScaleType;
714
+ readonly dataType: ChannelDataType;
715
+ /** Pixel-space transform within the plot frame. */
716
+ readonly fn: ScaleFn<unknown, number>;
717
+ /** Underlying scale for axis builders. */
718
+ readonly axisScale: ContinuousScale | TimeScale | BandScale<string>;
719
+ }
720
+ interface ColorScale {
721
+ readonly kind: "color";
722
+ readonly dataType: ChannelDataType;
723
+ readonly type: ColorScaleType;
724
+ readonly fn: ScaleFn<unknown, Color>;
725
+ readonly domain: readonly unknown[];
726
+ /** Original palette — present for continuous/diverging scales (used by the color-bar legend). */
727
+ readonly palette?: ContinuousPalette | CategoricalPalette;
728
+ }
729
+ interface SizeScale {
730
+ readonly kind: "size";
731
+ readonly fn: ScaleFn<unknown, number>;
732
+ readonly domain: readonly [number, number];
733
+ readonly range: readonly [number, number];
734
+ }
735
+ interface AlphaScale {
736
+ readonly kind: "alpha";
737
+ readonly fn: ScaleFn<unknown, number>;
738
+ readonly domain: readonly [number, number];
739
+ readonly range: readonly [number, number];
740
+ }
741
+ interface ShapeScale {
742
+ readonly kind: "shape";
743
+ readonly fn: ScaleFn<unknown, PointShapeKind>;
744
+ readonly domain: readonly unknown[];
745
+ readonly palette: readonly PointShapeKind[];
746
+ }
747
+ interface BorderStyleScale {
748
+ readonly kind: "borderStyle";
749
+ readonly fn: ScaleFn<unknown, PointBorderStyle>;
750
+ readonly domain: readonly unknown[];
751
+ readonly palette: readonly PointBorderStyle[];
752
+ }
753
+ interface OverlayGlyphScale {
754
+ readonly kind: "overlayGlyph";
755
+ readonly fn: ScaleFn<unknown, PointShapeKind | null>;
756
+ readonly domain: readonly unknown[];
757
+ readonly palette: readonly (PointShapeKind | null)[];
758
+ }
759
+ declare const DEFAULT_BORDER_STYLE_PALETTE: readonly PointBorderStyle[];
760
+ /**
761
+ * Default overlay palette. First slot is `null` so the most-common category
762
+ * gets no overlay — overlays are typically a minority styling for flagged /
763
+ * exceptional rows. The remaining slots are visually distinct glyphs.
764
+ */
765
+ declare const DEFAULT_OVERLAY_GLYPH_PALETTE: readonly (PointShapeKind | null)[];
766
+ //#endregion
767
+ //#region src/grammar/geoms/types.d.ts
768
+ type GeomKind = "point" | "line" | "area" | "bar" | "text" | "rule" | "band" | "boxplot" | "violin" | "histogram" | "ridgeline" | "rug" | "smooth" | "rolling" | "tile" | "interval";
769
+ /**
770
+ * Channel mappings as declared by the user. Stored at this width on `Geom<T>`
771
+ * so the chart can iterate channels generically. Geom factories accept their
772
+ * narrower per-geom channel types (PointChannels, LineChannels, ...) as the
773
+ * public surface and cast into this for storage.
774
+ */
775
+ interface ChannelSpec<_T> {
776
+ x?: unknown;
777
+ y?: unknown;
778
+ color?: unknown;
779
+ size?: unknown;
780
+ shape?: unknown;
781
+ alpha?: unknown;
782
+ borderStyle?: unknown;
783
+ overlayGlyph?: unknown;
784
+ }
785
+ /**
786
+ * Per-geom hints for position-scale construction. Geoms that have a
787
+ * conventional baseline (bar, area) request that their value axis include 0
788
+ * — or, for `position: 'fill'`, set an explicit `[0, 1]` domain. Hints are
789
+ * only applied to numeric (linear/log/sqrt) scales; band/time scales ignore
790
+ * them. An explicit `.scale(channel, { domain })` override always wins.
791
+ */
792
+ interface PositionScaleHint {
793
+ /** Force this exact domain (overrides include flags). */
794
+ domain?: readonly [number, number];
795
+ /** Extend inferred domain to include 0. */
796
+ includeZero?: boolean;
797
+ /** Extend inferred domain to include 1. */
798
+ includeOne?: boolean;
799
+ /**
800
+ * Extend the inferred domain to include this range. Unlike `domain`, this
801
+ * is unioned with the data-derived extent (and with other layers' extends)
802
+ * rather than replacing it. Use for geoms whose visual footprint extends
803
+ * past the raw data — e.g. a KDE-based violin whose smoothed tails reach
804
+ * outside `[dataMin, dataMax]`.
805
+ */
806
+ extend?: readonly [number, number];
807
+ }
808
+ interface ScaleHints {
809
+ x?: PositionScaleHint;
810
+ y?: PositionScaleHint;
811
+ }
812
+ /**
813
+ * Pixel reservations on the plot frame for a geom whose visual extent
814
+ * exceeds its data footprint. The chart shrinks the position-scale range
815
+ * by these amounts so axis ticks track the compressed layout — used by
816
+ * ridgeline rows that rise above their baseline. Reservations from
817
+ * multiple layers are merged by max (the largest demand wins).
818
+ */
819
+ interface RangeHints {
820
+ top?: number;
821
+ bottom?: number;
822
+ left?: number;
823
+ right?: number;
824
+ }
825
+ interface PrepareRangeContext<T> {
826
+ data: readonly T[];
827
+ plot: Frame;
828
+ scaleOptions: {
829
+ x?: PositionScaleOptions;
830
+ y?: PositionScaleOptions;
831
+ };
832
+ theme: Theme;
833
+ atlas: GlyphAtlas | undefined;
834
+ }
835
+ interface ScaleBundle {
836
+ x: PositionScale;
837
+ y: PositionScale;
838
+ color?: ColorScale;
839
+ size?: SizeScale;
840
+ alpha?: AlphaScale;
841
+ shape?: ShapeScale;
842
+ borderStyle?: BorderStyleScale;
843
+ overlayGlyph?: OverlayGlyphScale;
844
+ }
845
+ /**
846
+ * Per-rendered-element channel snapshot used for animated transitions.
847
+ * For simple geoms this usually matches the source datum index; for stacked /
848
+ * grouped geoms it can be one entry per visible segment. NaN marks filtered /
849
+ * hidden entries. Each geom owns the index convention used by its compile path.
850
+ */
851
+ interface GeomFrame {
852
+ count: number;
853
+ x: Float32Array;
854
+ y: Float32Array;
855
+ rgba: Float32Array;
856
+ a: Float32Array;
857
+ r?: Float32Array;
858
+ ids?: readonly string[];
859
+ }
860
+ /** Injected into CompileContext during an active data/scale transition. */
861
+ interface ActiveTransition {
862
+ /** Progress 0 → 1. */
863
+ t: number;
864
+ /** From-snapshot for this geom. Indexed by datum i. */
865
+ from: GeomFrame;
866
+ /** Resolve a stable match index in `from` for the given key. */
867
+ matchIndex(key: string, fallbackIndex?: number): number | undefined;
868
+ }
869
+ interface CompileContext<T> {
870
+ data: readonly T[];
871
+ scales: ScaleBundle;
872
+ plot: Frame;
873
+ theme: Theme;
874
+ atlas: GlyphAtlas | undefined;
875
+ /**
876
+ * Coordinate system in effect for this chart. Geoms can call
877
+ * `ctx.coord.project(p)` / `ctx.coord.segment(p1, p2)` to remap plot-frame
878
+ * pixel space into layer-pixel space — under `coordCartesian()` (the
879
+ * default) both are the identity, so existing geoms are unaffected. Phase 3
880
+ * adds `coordPolar()` / `coordRadial()` and per-geom polar projection.
881
+ *
882
+ * Optional during Phase 1: only the pipeline supplies it today, and geoms
883
+ * have not been migrated to project through it yet. Treat absence as
884
+ * `coordCartesian()` if you read it in a geom. Will become required when
885
+ * Phase 3 lands and per-geom polar projection ships.
886
+ */
887
+ coord?: Coord;
888
+ /**
889
+ * Currently hovered hit, or `null` if nothing is hovered. Geoms compare
890
+ * `hovered.data === ctx.data && hovered.geomKind === this.kind` to detect
891
+ * "their" hit and can use `hovered.dataIndex` to render a highlight (halo,
892
+ * elevated alpha/stroke, etc.). Provided by the mount; `undefined` when
893
+ * compiling outside a mount context (e.g. SSR / SVG export).
894
+ */
895
+ hovered?: HoveredHit | null;
896
+ /**
897
+ * Currently selected hits (multi-select). Empty array = nothing selected;
898
+ * `undefined` = selection is disabled (no visual treatment). Geoms render
899
+ * stroke rings on matching rows and may dim non-selected rows when the
900
+ * array is non-empty.
901
+ */
902
+ selected?: readonly HoveredHit[];
903
+ /** Set of series keys currently hidden via legend toggle. */
904
+ hidden?: ReadonlySet<string>;
905
+ /** Optional stable key used to match rows across data refreshes for transitions. */
906
+ transitionKey?: (datum: T, index: number) => string;
907
+ /**
908
+ * Active data/scale transition context. Present only during an animated
909
+ * transition; geoms use it to lerp channels from the previous frame toward
910
+ * the current compiled values.
911
+ */
912
+ activeTransition?: ActiveTransition;
913
+ /**
914
+ * Disjoint emphasis-key band base for this geom (P5-T3). The pipeline assigns
915
+ * `geomEmphasisBase(geomIndex)`; dim-participating geoms tag each mark
916
+ * instance `emphasisKey: emphasisKeyFor(base, ordinal)` so the core's GPU dim
917
+ * uniform can fade non-focused instances WITHOUT a marks recompile. `undefined`
918
+ * outside a mount (SSR / SVG export) → geoms skip tagging (no GPU emphasis).
919
+ * See {@link import("./emphasis.ts")}.
920
+ */
921
+ emphasisBase?: number;
922
+ }
923
+ /**
924
+ * The active hover state surfaced to compile contexts and exposed on
925
+ * `MountedPlot.hovered`. Coordinates are absolute element-CSS pixels
926
+ * (matching `CompiledHitTest.positions`).
927
+ */
928
+ interface HoveredHit {
929
+ geomKind: GeomKind;
930
+ dataIndex: number;
931
+ /** Optional segment key for multi-series geoms (stacked/dodged bars, stacked areas). */
932
+ seriesKey?: string;
933
+ /**
934
+ * Reference to the data array used to compile the originating geom — used
935
+ * for identity comparison (`hovered.data === ctx.data`) so multi-layer
936
+ * charts can route the hit to the right geom.
937
+ */
938
+ data: readonly unknown[];
939
+ x: number;
940
+ y: number;
941
+ }
942
+ /**
943
+ * Resolved aesthetics for each channel of a geom — used by interaction layers
944
+ * (tooltips, legends-on-hover) to read the original column name and pull the
945
+ * raw value back out for a given datum.
946
+ */
947
+ interface ResolvedChannelMap<T> {
948
+ x?: ResolvedAes<T, unknown>;
949
+ y?: ResolvedAes<T, unknown>;
950
+ color?: ResolvedAes<T, unknown>;
951
+ size?: ResolvedAes<T, unknown>;
952
+ shape?: ResolvedAes<T, unknown>;
953
+ alpha?: ResolvedAes<T, unknown>;
954
+ }
955
+ /**
956
+ * Hit-test points emitted by a geom for hover/click. Coordinates are absolute
957
+ * element-CSS pixels (the chart's plot frame offset is already baked in), so
958
+ * the consumer can hand them to a `space: "ui"` PointCloudNode without
959
+ * adjustment. `dataIndex[i]` maps hit `i` back to the original `data` array
960
+ * (after filtering NaN/null values). `seriesKey[i]` further distinguishes
961
+ * segments that share a source row.
962
+ */
963
+ interface CompiledHitTest<T> {
964
+ geomKind: GeomKind;
965
+ label?: string;
966
+ positions: Float32Array;
967
+ dataIndex: Int32Array;
968
+ seriesKey?: readonly (string | undefined)[];
969
+ pickRadius: number;
970
+ /**
971
+ * Optional per-hit bounding rect in absolute element-CSS pixels. When
972
+ * present, the hit-layer prefers rect containment over nearest-point
973
+ * picking (`positions` + `pickRadius`), giving "whole shape" hover for
974
+ * shape-based geoms (bar, histogram, ridgeline rows, tile cells, ...).
975
+ * Layout: `[x, y, w, h]` per `dataIndex` entry. `positions` is still
976
+ * required as a fallback (used to anchor tooltips, brushes, etc.).
977
+ */
978
+ rects?: Float32Array;
979
+ /**
980
+ * Distance metric for nearest-point queries. Default `"xy"` (Euclidean).
981
+ * `"x"` makes the picker resolve nearest-by-x only — used by `line()` /
982
+ * `area()` when `nearestX: true` so the user can hover anywhere along the
983
+ * curve and the active vertex follows the cursor's x.
984
+ */
985
+ pickAxis?: "x" | "y" | "xy";
986
+ channels: ResolvedChannelMap<T>;
987
+ data: readonly T[];
988
+ }
989
+ /**
990
+ * A geom's hover-focus decoration, captured at compile time so the mount can
991
+ * draw it on hover **without recompiling the pipeline**. The mount calls
992
+ * {@link decorate} into the live overlay layer (which composites above the baked
993
+ * marks), so local focus treatment — a contrast halo, bringing the hovered
994
+ * element to the front — costs only a cheap overlay repaint rather than a full
995
+ * marks recompute. The complementary *global* dim-others treatment (fading every
996
+ * other element) rides the core's GPU emphasis uniform (see {@link
997
+ * EmphasisResolver}), so a geom can provide both: the decorator draws the focus
998
+ * halo (left at emphasis key 0 = exempt, full-strength) while the uniform dims
999
+ * the rest. Geoms with no local focus shape simply omit this.
1000
+ *
1001
+ * `geomKind` + `data` identity let the mount match the decorator to the active
1002
+ * `HoveredHit` (the same keys used to route a hit to its geom).
1003
+ */
1004
+ interface GeomHoverDecorator {
1005
+ readonly geomKind: GeomKind;
1006
+ readonly data: readonly unknown[];
1007
+ /** Draw the focus decoration for `hit` into `layer` (the overlay layer). */
1008
+ decorate(hit: HoveredHit, layer: Layer): void;
1009
+ }
1010
+ interface Geom<T> {
1011
+ readonly kind: GeomKind;
1012
+ readonly channels: ChannelSpec<T>;
1013
+ /** Used by the auto-legend to label the layer. Falls back to channel name. */
1014
+ readonly label?: string;
1015
+ /** Optional position-scale hints (e.g. anchor value axis at 0 for bars). */
1016
+ readonly scaleHints?: ScaleHints;
1017
+ /**
1018
+ * When true, the geom renders into the hud layer (above marks, no clip rect)
1019
+ * instead of the marks layer. Used by geoms whose visual extent intentionally
1020
+ * exceeds the plot frame — e.g. phylo tip labels — and that should not be
1021
+ * clipped at the frame edge.
1022
+ */
1023
+ readonly overlay?: boolean;
1024
+ /**
1025
+ * Optional data-derived scale hints. Called once before scales are built,
1026
+ * so geoms whose visual extent depends on the data (e.g. KDE-smoothed
1027
+ * violins) can extend the position-scale domain accordingly. Returned
1028
+ * hints are merged with `scaleHints` and any hints contributed by other
1029
+ * layers. An explicit `.scale(channel, { domain })` override always wins.
1030
+ */
1031
+ prepareDomain?(data: readonly T[]): ScaleHints | undefined;
1032
+ /**
1033
+ * Optional layout-time hook that runs after layout but before scale
1034
+ * construction. Geoms whose visual extent exceeds their data footprint
1035
+ * — e.g. a ridgeline ridge that rises above its baseline by `overlap ×
1036
+ * cellSize` — use this to reserve pixel margins on the plot frame, so
1037
+ * the position scale (and its axis ticks) shrink to fit.
1038
+ */
1039
+ prepareRange?(ctx: PrepareRangeContext<T>): RangeHints | undefined;
1040
+ /**
1041
+ * Optional override for the auto-legend's per-series swatch. Geoms that
1042
+ * draw filled regions (bar/area/tile) or strokes (line) supply their own;
1043
+ * the pipeline falls back to a point swatch when omitted.
1044
+ */
1045
+ legendSwatch?(color: Color, theme: Theme): SwatchSpec;
1046
+ compile(ctx: CompileContext<T>): readonly MarkBuilder[];
1047
+ /**
1048
+ * Optional hit-test contribution for interactions. Implemented per geom that
1049
+ * wants to support hover/click selection (`point` in v1; bar/line/area in
1050
+ * later phases). Return `null` to opt out for a particular compile pass
1051
+ * (e.g. when the geom has no points after filtering).
1052
+ */
1053
+ compileHitTest?(ctx: CompileContext<T>): CompiledHitTest<T> | null;
1054
+ /**
1055
+ * Optional hover-focus decorator. Implemented by geoms whose focus treatment
1056
+ * is *local* (point: contrast halo + bring-to-front) so it can ride the
1057
+ * mount's cheap overlay path instead of a marks recompute. Called once per
1058
+ * full compile with the same `ctx`; returns `null` to opt out (e.g. empty
1059
+ * data). See {@link GeomHoverDecorator}.
1060
+ */
1061
+ hoverDecoration?(ctx: CompileContext<T>): GeomHoverDecorator | null;
1062
+ /**
1063
+ * Emphasis-key resolver for geoms whose hover treatment is *global* (dim the
1064
+ * others via the core's GPU emphasis uniform: bar/line/violin/...). Captured
1065
+ * once per full compile with the same `ctx` (so it sees the same `emphasisBase`
1066
+ * + scales the tagging used); the mount maps an active {@link HoveredHit} to the
1067
+ * namespaced key the geom tagged its focused instance(s) with — without
1068
+ * recompiling. Returns `null` to opt out (e.g. empty data, or `emphasisBase`
1069
+ * absent). Mutually complementary with {@link hoverDecoration} (local focus).
1070
+ * See {@link import("./emphasis.ts").EmphasisResolver}.
1071
+ */
1072
+ emphasisResolution?(ctx: CompileContext<T>): EmphasisResolver | null;
1073
+ /**
1074
+ * Capture a per-datum channel snapshot for use as a transition "from" frame.
1075
+ * Called after `compile` on each stable (non-animating) frame. Returns `null`
1076
+ * if the geom has no meaningful frame to capture (e.g. empty data).
1077
+ */
1078
+ captureFrame?(ctx: CompileContext<T>): GeomFrame | null;
1079
+ }
1080
+ //#endregion
1081
+ //#region src/grammar/interactions/series-readout.d.ts
1082
+ interface SeriesReadoutRow {
1083
+ /** Series name (color-channel value) or layer label. */
1084
+ label: string;
1085
+ /** Formatted display value (raw y at the snapped x). */
1086
+ value: string;
1087
+ /** Series swatch color, when the layer has a color channel. */
1088
+ color?: Color;
1089
+ /** True for the row whose snapped position is closest to the cursor. */
1090
+ active: boolean;
1091
+ }
1092
+ interface SeriesReadoutSnapshot {
1093
+ /** Formatted snapped x (from the closest layer). */
1094
+ x: string;
1095
+ /** Raw snapped x value (column-typed). Useful for custom formatting. */
1096
+ xValue: unknown;
1097
+ /** One row per series across all layers, in original layer + series order. */
1098
+ rows: readonly SeriesReadoutRow[];
1099
+ }
1100
+ type SeriesReadoutFormat = {
1101
+ /** Format the snapped x for the panel title. Default: `defaultFormat`. */x?: (value: unknown) => string; /** Format each per-series y value. Default: `defaultFormat`. */
1102
+ y?: (value: unknown) => string;
1103
+ };
1104
+ type SeriesReadoutPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
1105
+ interface SeriesReadoutUi {
1106
+ /** Element to append the panel into (typically the chart's stage). */
1107
+ mount: HTMLElement;
1108
+ /** Corner inside `mount`. Default `"top-right"`. */
1109
+ position?: SeriesReadoutPosition;
1110
+ /** Inset (px) from the chosen corner. Default `12`. */
1111
+ inset?: number;
1112
+ }
1113
+ interface AttachSeriesReadoutOptions {
1114
+ /** DOM mount info. Omit to run headless and observe via `subscribe`. */
1115
+ ui?: SeriesReadoutUi;
1116
+ /**
1117
+ * How to pick a hit per series.
1118
+ * - `"nearest-x"` (default): the hit with smallest |x − cursorX|. Best for
1119
+ * time-series readouts; one row per series at the cursor's x.
1120
+ * - `"hover"`: only show rows while the cursor is over a real hit (the
1121
+ * tooltip-style behavior, but extended to every series in the chart).
1122
+ */
1123
+ snap?: "nearest-x" | "hover";
1124
+ /** Per-channel formatters. */
1125
+ format?: SeriesReadoutFormat;
1126
+ /** Hide when the cursor leaves the plot frame. Default `true`. */
1127
+ hideOnLeave?: boolean;
1128
+ /** Notified whenever the snapshot changes (incl. with `ui` attached). */
1129
+ onChange?(snapshot: SeriesReadoutSnapshot | null): void;
1130
+ }
1131
+ interface AttachedSeriesReadout {
1132
+ peek(): SeriesReadoutSnapshot | null;
1133
+ subscribe(fn: (snapshot: SeriesReadoutSnapshot | null) => void): () => void;
1134
+ dispose(): void;
1135
+ }
1136
+ //#endregion
1137
+ //#region src/grammar/interactions/brush.d.ts
1138
+ interface GrammarBrushConfig {
1139
+ /** Which axes the brush spans. Default `"xy"`. */
1140
+ axis?: BrushAxis;
1141
+ /** Translucent fill color. Default theme.axis.color × 0.12 alpha. */
1142
+ fillColor?: Color;
1143
+ /** Outline color. Default theme.axis.color × 0.6 alpha. */
1144
+ strokeColor?: Color;
1145
+ /** Outline width in CSS px. Default 1. */
1146
+ strokeWidth?: number;
1147
+ /**
1148
+ * Enable edge/corner resize handles on the committed rect. Default `true`.
1149
+ * Disable to lock a brush rect to its initial drag.
1150
+ */
1151
+ handles?: boolean;
1152
+ /** Hit-test extent of each handle in CSS px. Default 8. */
1153
+ handleSize?: number;
1154
+ /**
1155
+ * Enable drag-to-move on the committed rect interior. Default `true`. The
1156
+ * rect's size is held constant during the move; off-axis movement is locked
1157
+ * for `axis: "x"` / `"y"` brushes. Disable to lock a brush rect in place.
1158
+ */
1159
+ translate?: boolean;
1160
+ /**
1161
+ * Snap brush rect edges to the nearest hit-test position along the chosen
1162
+ * axis. `true` snaps on the brush's active `axis`; pass `"x"` / `"y"` /
1163
+ * `"xy"` to override. Default `false`. Useful for axis-locked range brushes
1164
+ * over discrete x-ticks. The snap is computed against the live hit-test
1165
+ * positions (refreshed on every `sync()`), so it follows the data.
1166
+ */
1167
+ snap?: boolean | BrushAxis;
1168
+ }
1169
+ interface GrammarBrush {
1170
+ /** Replace the active hit-test set after each pipeline run. */
1171
+ sync<T>(hits: readonly CompiledHitTest<T>[]): void;
1172
+ /** Read-only snapshot of the current brushed hits. */
1173
+ current(): HoveredHit[];
1174
+ /** Current brush rect, or null when idle. */
1175
+ rect(): BrushRect | null;
1176
+ /** Imperatively clear the brush. */
1177
+ clear(): void;
1178
+ /** Draw the brush overlay into the hud layer. */
1179
+ draw(): void;
1180
+ dispose(): void;
1181
+ }
1182
+ //#endregion
1183
+ //#region src/grammar/attach-brush.d.ts
1184
+ interface AttachBrushOptions extends GrammarBrushConfig {
1185
+ /**
1186
+ * Fires whenever the brushed set changes — including the empty `[]` after
1187
+ * `clear()` / background tap. Receives one `HoveredHit` per data row whose
1188
+ * hit-test position falls within the brush rect.
1189
+ */
1190
+ onSelect?(hits: readonly HoveredHit[]): void;
1191
+ }
1192
+ interface AttachedBrush {
1193
+ /** Read-only snapshot of the current brushed hits. */
1194
+ peek(): readonly HoveredHit[];
1195
+ /** Current brush rect in element-local CSS px, or `null` while idle. */
1196
+ rect(): BrushRect | null;
1197
+ /** Subscribe to changes. Fires immediately with the current set. */
1198
+ subscribe(fn: (hits: readonly HoveredHit[]) => void): () => void;
1199
+ /** Imperatively clear the brush. */
1200
+ clear(): void;
1201
+ /** Tear down the brush + interaction nodes. */
1202
+ dispose(): void;
1203
+ }
1204
+ interface AttachBrushDeps {
1205
+ manager: InteractionManager;
1206
+ /** Plot-frame bounds in element-local CSS px. */
1207
+ bounds: () => Frame;
1208
+ hudLayer: () => Layer;
1209
+ theme: () => Theme;
1210
+ invalidator: Invalidator;
1211
+ }
1212
+ /**
1213
+ * Internal handle exposed to the mount so it can drive `sync` + `draw` from
1214
+ * its rAF loop and dispose alongside teardown. Public consumers receive the
1215
+ * narrower `AttachedBrush` view returned by `MountedPlot.attachBrush`.
1216
+ */
1217
+ interface AttachedBrushInternal extends AttachedBrush {
1218
+ syncHits<T>(hits: readonly CompiledHitTest<T>[]): void;
1219
+ draw(): void;
1220
+ /** Underlying grammar brush — exposed for tests; not part of the public API. */
1221
+ readonly brush: GrammarBrush;
1222
+ }
1223
+ declare function createAttachedBrush(deps: AttachBrushDeps, opts: AttachBrushOptions): AttachedBrushInternal;
1224
+ //#endregion
1225
+ //#region src/grammar/annotations.d.ts
1226
+ type FrameAnchorX = "left" | "center" | "right";
1227
+ type FrameAnchorY = "top" | "middle" | "bottom";
1228
+ /** Coordinate value accepted by annotation factories — data value or frame anchor. */
1229
+ type AnnotationX = FrameAnchorX | number | Date | string;
1230
+ type AnnotationY = FrameAnchorY | number | Date | string;
1231
+ interface TextAnnotationSpec {
1232
+ kind?: "text";
1233
+ text: string;
1234
+ /**
1235
+ * Horizontal position. A `FrameAnchorX` resolves to the plot frame edges;
1236
+ * a number/Date is run through the active x scale.
1237
+ */
1238
+ x: AnnotationX;
1239
+ /** Vertical position. See `x` — but resolves against the y scale. */
1240
+ y: AnnotationY;
1241
+ /** Pixel offset added after position resolution. */
1242
+ offsetX?: number;
1243
+ offsetY?: number;
1244
+ align?: ValueLabelAlign;
1245
+ color?: Color;
1246
+ fontSize?: number;
1247
+ fontStyle?: string;
1248
+ box?: LabelBoxStyle;
1249
+ }
1250
+ interface ArrowAnnotationSpec {
1251
+ kind: "arrow";
1252
+ /** Tail of the arrow — `[x, y]` in data or frame-anchor coordinates. */
1253
+ from: readonly [AnnotationX, AnnotationY];
1254
+ /** Head of the arrow. Direction is `from → to`. */
1255
+ to: readonly [AnnotationX, AnnotationY];
1256
+ /** Optional label rendered near the arrowhead. */
1257
+ label?: string;
1258
+ /**
1259
+ * Pixel offset for the label relative to the arrowhead. Default
1260
+ * `[6, -6]` — to-the-right-and-above the head.
1261
+ */
1262
+ labelOffset?: readonly [number, number];
1263
+ labelAlign?: ValueLabelAlign;
1264
+ labelBox?: LabelBoxStyle;
1265
+ /** Stroke color for the shaft and head fill. Defaults to `theme.text.color`. */
1266
+ color?: Color;
1267
+ /** Shaft thickness in CSS pixels. Default `1.5`. */
1268
+ strokeWidth?: number;
1269
+ /**
1270
+ * Arrowhead size in CSS pixels — total length from base to tip. Default
1271
+ * `9`; the head is `headSize × 0.5` wide at the base.
1272
+ */
1273
+ headSize?: number;
1274
+ fontSize?: number;
1275
+ fontStyle?: string;
1276
+ }
1277
+ interface CalloutAnnotationSpec {
1278
+ kind: "callout";
1279
+ /** Data point the callout is anchored to. */
1280
+ at: readonly [AnnotationX, AnnotationY];
1281
+ /** Label text rendered at the offset position. */
1282
+ label: string;
1283
+ /**
1284
+ * Pixel offset from the anchor to the label position. The leader line
1285
+ * runs between them. Default `[40, -20]`.
1286
+ */
1287
+ offset?: readonly [number, number];
1288
+ /** Leader stroke color. Defaults to `theme.text.color` (faded by `leaderAlpha`). */
1289
+ color?: Color;
1290
+ /** Multiplier on the leader's stroke alpha. Default `0.6`. */
1291
+ leaderAlpha?: number;
1292
+ /** Leader thickness in CSS pixels. Default `1`. */
1293
+ strokeWidth?: number;
1294
+ /** Label text color. Defaults to `theme.text.color`. */
1295
+ labelColor?: Color;
1296
+ align?: ValueLabelAlign;
1297
+ box?: LabelBoxStyle;
1298
+ fontSize?: number;
1299
+ fontStyle?: string;
1300
+ }
1301
+ type AnnotationSpec = TextAnnotationSpec | ArrowAnnotationSpec | CalloutAnnotationSpec;
1302
+ declare const annotate: {
1303
+ readonly arrow: (spec: Omit<ArrowAnnotationSpec, "kind">) => ArrowAnnotationSpec;
1304
+ readonly callout: (spec: Omit<CalloutAnnotationSpec, "kind">) => CalloutAnnotationSpec;
1305
+ readonly text: (spec: Omit<TextAnnotationSpec, "kind">) => TextAnnotationSpec;
1306
+ };
1307
+ //#endregion
1308
+ //#region src/grammar/facet.d.ts
1309
+ type FacetScales = "fixed" | "free";
1310
+ interface FacetStripStyle {
1311
+ height?: number;
1312
+ fontSize?: number;
1313
+ color?: Color;
1314
+ background?: Color;
1315
+ }
1316
+ interface FacetSpec<T> {
1317
+ /** Accessor / column name producing the facet key per datum. */
1318
+ by: Aes<T, unknown>;
1319
+ /** Number of columns. Default: ceil(sqrt(n)). */
1320
+ ncol?: number;
1321
+ /** Number of rows. Default: ceil(n / ncol). */
1322
+ nrow?: number;
1323
+ /**
1324
+ * Scale handling across panels.
1325
+ * - `"fixed"` (default) — every panel shares the same x/y/color/… scales.
1326
+ * - `"free"` — each panel computes its own scales from its data.
1327
+ */
1328
+ scales?: FacetScales;
1329
+ /** Spacing between panels in pixels. Default `12`. */
1330
+ gap?: number;
1331
+ /** Strip header style. */
1332
+ strip?: FacetStripStyle;
1333
+ /** Optional formatter for the strip label. */
1334
+ format?: (key: unknown) => string;
1335
+ }
1336
+ //#endregion
1337
+ //#region src/grammar/geoms/point.d.ts
1338
+ interface PointChannels<T> {
1339
+ x: Aes<T, number | Date>;
1340
+ y: Aes<T, number | Date>;
1341
+ color?: Aes<T, unknown>;
1342
+ size?: Aes<T, number>;
1343
+ /**
1344
+ * Categorical shape mapping. Values are looked up in the active shape scale
1345
+ * — by default a built-in palette (`POINT_SHAPE_PALETTE`). Pass a literal
1346
+ * `PointShapeKind` accessor and `.scale("shape", { palette: [...] })` to
1347
+ * customize. When the value is already a `PointShapeKind`, it's used as-is.
1348
+ */
1349
+ shape?: Aes<T, unknown>;
1350
+ alpha?: Aes<T, number>;
1351
+ /**
1352
+ * Per-datum border treatment. The accessor may return either a resolved
1353
+ * {@link PointBorderStyle} (used as-is) or any other categorical value that
1354
+ * gets routed through the active `borderStyle` scale (default palette:
1355
+ * `solid`, `open`, `dashed`, `dotted`). Configure a custom mapping with
1356
+ * `.scale("borderStyle", { palette: [...] })`.
1357
+ */
1358
+ borderStyle?: Aes<T, unknown>;
1359
+ /**
1360
+ * Optional secondary glyph overlaid on the base shape at the same anchor.
1361
+ * Accepts either a resolved {@link PointShapeKind}/`null`, or a categorical
1362
+ * value routed through the `overlayGlyph` scale (default palette starts
1363
+ * with `null` so the most-common category gets no overlay). Configure with
1364
+ * `.scale("overlayGlyph", { palette: [...] })`.
1365
+ */
1366
+ overlayGlyph?: Aes<T, unknown>;
1367
+ /** Overlay radius as a fraction of base radius. Default `0.6`. */
1368
+ overlayScale?: Aes<T, number>;
1369
+ }
1370
+ interface PointOptions {
1371
+ /** Constant fill if color channel is absent. */
1372
+ fill?: Color;
1373
+ /** Constant point radius if size channel is absent. */
1374
+ radius?: number;
1375
+ /** Override theme stroke. */
1376
+ stroke?: Color | null;
1377
+ /** Override theme stroke width. */
1378
+ strokeWidth?: number;
1379
+ /** Constant shape if shape channel is absent. */
1380
+ shape?: PointShapeKind;
1381
+ /** Constant border style if border-style channel is absent. */
1382
+ borderStyle?: PointBorderStyle;
1383
+ /** Constant overlay glyph if overlay-glyph channel is absent. */
1384
+ overlayGlyph?: PointShapeKind | null;
1385
+ /** Constant overlay scale if overlay-scale channel is absent. */
1386
+ overlayScale?: number;
1387
+ /** Display label for legend (defaults to color column name). */
1388
+ label?: string;
1389
+ }
1390
+ declare function point<T>(channels: PointChannels<T>, options?: PointOptions): Geom<T>;
1391
+ //#endregion
1392
+ //#region src/grammar/geoms/line.d.ts
1393
+ interface LineChannels<T> {
1394
+ x: Aes<T, number | Date>;
1395
+ y: Aes<T, number | Date>;
1396
+ /** Categorical color channel splits the line into one stroke per category. */
1397
+ color?: Aes<T, unknown>;
1398
+ /**
1399
+ * Optional ordering aesthetic. When present, rows are connected in ascending
1400
+ * order (globally, or within each color-grouped series).
1401
+ */
1402
+ order?: Aes<T, number | Date>;
1403
+ }
1404
+ interface LineOptions {
1405
+ stroke?: Color;
1406
+ strokeWidth?: number;
1407
+ curve?: LineCurve;
1408
+ curveSamples?: number;
1409
+ dashPattern?: readonly number[];
1410
+ /**
1411
+ * Categorical dash treatment. `dashPattern` takes precedence when both
1412
+ * are supplied. See {@link LineDashStyle}.
1413
+ */
1414
+ dashStyle?: LineDashStyle;
1415
+ label?: string;
1416
+ /**
1417
+ * When true, hover hit-tests resolve to the nearest vertex *by x* — the
1418
+ * cursor's vertical position doesn't influence which datum is picked, so
1419
+ * the user can hover anywhere along the line. Default `false` (per-vertex
1420
+ * Euclidean pick within `pickRadius`). For multi-line charts this means
1421
+ * the cursor's x picks one vertex per series; the topmost series wins
1422
+ * via PointCloud zIndex order.
1423
+ */
1424
+ nearestX?: boolean;
1425
+ }
1426
+ declare function line<T>(channels: LineChannels<T>, options?: LineOptions): Geom<T>;
1427
+ //#endregion
1428
+ //#region src/grammar/geoms/connected-scatter.d.ts
1429
+ interface ConnectedScatterChannels<T> {
1430
+ x: Aes<T, number | Date>;
1431
+ y: Aes<T, number | Date>;
1432
+ color?: Aes<T, unknown>;
1433
+ order: Aes<T, number | Date>;
1434
+ size?: Aes<T, number>;
1435
+ shape?: Aes<T, unknown>;
1436
+ alpha?: Aes<T, number>;
1437
+ }
1438
+ interface ConnectedScatterOptions {
1439
+ /** Line-layer options. */
1440
+ line?: LineOptions;
1441
+ /** Point-layer options. Pass `false` to render only the connecting path. */
1442
+ point?: PointOptions | false;
1443
+ }
1444
+ /**
1445
+ * Grammar helper for the common "connected scatterplot" recipe:
1446
+ * a path ordered by a third variable, optionally topped with points.
1447
+ *
1448
+ * Returns plain geoms so callers still compose with `.layer(text(...))`,
1449
+ * `.annotate(...)`, facets, transitions, and the normal interaction stack.
1450
+ */
1451
+ declare function connectedScatter<T>(channels: ConnectedScatterChannels<T>, options?: ConnectedScatterOptions): readonly Geom<T>[];
1452
+ //#endregion
1453
+ //#region src/grammar/geoms/area.d.ts
1454
+ type AreaPosition = "identity" | "stack" | "fill";
1455
+ interface AreaChannels<T> {
1456
+ x: Aes<T, number | Date>;
1457
+ /**
1458
+ * Single column → simple area from y=0 to y. Array of column keys → stacked
1459
+ * area, with the implicit `__series` color channel keyed by column name.
1460
+ */
1461
+ y: Aes<T, number | Date> | readonly (keyof T & string)[];
1462
+ color?: Aes<T, unknown>;
1463
+ }
1464
+ interface AreaOptions {
1465
+ fill?: Color;
1466
+ stroke?: Color;
1467
+ strokeWidth?: number;
1468
+ /** "identity" (default), "stack" (offset zero), or "fill" (offset expand). */
1469
+ position?: AreaPosition;
1470
+ /** Stack ordering — only meaningful with stacked positions. */
1471
+ order?: StackOrder;
1472
+ label?: string;
1473
+ /**
1474
+ * When true, hover hit-tests resolve to the nearest vertex *by x* — the
1475
+ * cursor's vertical position doesn't influence which datum (or stacked
1476
+ * segment) is picked, so the user can hover anywhere along the area.
1477
+ * Default `false` (per-vertex Euclidean pick within `pickRadius`).
1478
+ */
1479
+ nearestX?: boolean;
1480
+ }
1481
+ declare function area<T>(channels: AreaChannels<T>, options?: AreaOptions): Geom<T>;
1482
+ //#endregion
1483
+ //#region src/grammar/geoms/bar.d.ts
1484
+ type BarPosition = "identity" | "stack" | "dodge" | "fill";
1485
+ interface BarChannels<T> {
1486
+ x: Aes<T, string | number | Date>;
1487
+ /**
1488
+ * Single column → simple bars (one per category). Array of column keys →
1489
+ * multi-series bars (stacked / dodged / 100% stacked).
1490
+ *
1491
+ * For horizontal layouts (`orientation: "x"`) the single-column form carries
1492
+ * the band category, so a string is accepted; the value axis then lives on
1493
+ * `x`.
1494
+ */
1495
+ y: Aes<T, string | number | Date> | readonly (keyof T & string)[];
1496
+ color?: Aes<T, unknown>;
1497
+ }
1498
+ interface BarOptions<T = unknown> {
1499
+ orientation?: BarOrientation;
1500
+ fill?: Color;
1501
+ stroke?: Color;
1502
+ strokeWidth?: number;
1503
+ cornerRadius?: number;
1504
+ /**
1505
+ * Border treatment shared across every bar (or segment, for stacked/dodged
1506
+ * layouts). See {@link BarBorderStyle}.
1507
+ */
1508
+ borderStyle?: BarBorderStyle;
1509
+ /**
1510
+ * Multi-series layout. Only meaningful when `y` (or `x`) is an array of keys.
1511
+ * - `"stack"` (default for arrays) — segments stacked from 0
1512
+ * - `"dodge"` — bars side-by-side within each category
1513
+ * - `"fill"` — stacked, normalized to [0, 1]
1514
+ * - `"identity"` — each datum drawn at its raw value
1515
+ */
1516
+ position?: BarPosition;
1517
+ order?: StackOrder;
1518
+ label?: string;
1519
+ /** Inner-band padding for `position: 'dodge'`. Default 0.05. */
1520
+ groupPadding?: number;
1521
+ /** If set, render a label above each bar with the per-category total. */
1522
+ showTotals?: (total: number, datum: T, datumIndex: number) => string;
1523
+ /**
1524
+ * If set, render a label per-bar (or per-segment for stacked / fill) with
1525
+ * the segment's value. For `fill`, the supplied `value` is normalized
1526
+ * `[0, 1]`; for other positions it's the raw segment value. `key` is the
1527
+ * column name for multi-series bars, `undefined` for simple bars.
1528
+ */
1529
+ showValues?: (value: number, datum: T, datumIndex: number, key?: string) => string;
1530
+ /** Override label color. */
1531
+ labelColor?: Color;
1532
+ /** Override label font size. */
1533
+ labelFontSize?: number;
1534
+ }
1535
+ declare function bar<T>(channels: BarChannels<T>, options?: BarOptions<T>): Geom<T>;
1536
+ //#endregion
1537
+ //#region src/grammar/geoms/histogram.d.ts
1538
+ type HistogramPosition = "identity" | "stack" | "dodge" | "fill";
1539
+ interface HistogramChannels<T> {
1540
+ /** Numeric variable to bin. Provide one of `x` (vertical bars) or `y`. */
1541
+ x?: Aes<T, number>;
1542
+ /** Numeric variable to bin. Provide one of `x` (vertical bars) or `y`. */
1543
+ y?: Aes<T, number>;
1544
+ /** Optional categorical group key — splits the sample into per-group bins. */
1545
+ color?: Aes<T, unknown>;
1546
+ }
1547
+ interface HistogramOptions {
1548
+ /** Explicit bin count. Loses to `binwidth` and `breaks`. */
1549
+ bins?: number;
1550
+ /** Explicit bin width in data units. Beats `bins` and `rule`. */
1551
+ binwidth?: number;
1552
+ /** Fully explicit edge array. Beats every other bin selector. */
1553
+ breaks?: readonly number[];
1554
+ /**
1555
+ * Auto-bin rule when none of `bins`, `binwidth`, `breaks` is set.
1556
+ *
1557
+ * - `"sturges"` (default) — R / ggplot default; works for ~normal data.
1558
+ * - `"rice"` — slightly more bins.
1559
+ * - `"scott"` — uses σ; good for normal-ish data.
1560
+ * - `"fd"` — Freedman–Diaconis; robust to outliers.
1561
+ */
1562
+ rule?: BinRule;
1563
+ /** Clip / extend the value-axis range used when computing edges. */
1564
+ domain?: readonly [number, number];
1565
+ /** Round outer edges + step to nice numbers. Default `true`. */
1566
+ nice?: boolean;
1567
+ /** Edge convention. Default `"left"` (`[x0, x1)` plus closed last bin). */
1568
+ closed?: BinClosed;
1569
+ /**
1570
+ * Y measure. Default `"count"`.
1571
+ *
1572
+ * - `"count"` / `"frequency"` — raw bin count.
1573
+ * - `"density"` — `count / (n · width)`. Integrates to 1 across bins.
1574
+ * - `"proportion"` — `count / n`. Sums to 1 across bins (per group).
1575
+ */
1576
+ y?: HistogramMeasure;
1577
+ /**
1578
+ * Multi-group layout. Default `"stack"` when `color` channel is present,
1579
+ * else `"identity"`.
1580
+ *
1581
+ * - `"identity"` — bars share a baseline of 0; useful with reduced
1582
+ * `fillAlpha` for an overlay effect.
1583
+ * - `"stack"` — per-bin counts stacked.
1584
+ * - `"dodge"` — sub-divide bin width across groups, side by side.
1585
+ * - `"fill"` — stack normalized to `[0, 1]` per bin.
1586
+ */
1587
+ position?: HistogramPosition;
1588
+ /** Render bars below the baseline (negate the count axis). Default `false`. */
1589
+ mirror?: boolean;
1590
+ /** Override theme `fillAlpha`. Lower this for `position: "identity"` overlays. */
1591
+ fillAlpha?: number;
1592
+ fill?: Color;
1593
+ stroke?: Color;
1594
+ strokeWidth?: number;
1595
+ cornerRadius?: number;
1596
+ /** Pixel gap between adjacent bars. Default `0` (continuous wall). */
1597
+ gap?: number;
1598
+ /** Inner-band padding for `position: "dodge"` (fraction of bin width). Default `0.05`. */
1599
+ groupPadding?: number;
1600
+ /** Optional per-bar label (uses bin midpoint + value). */
1601
+ showCounts?: (value: number, bin: BinResult, key?: string) => string;
1602
+ labelColor?: Color;
1603
+ labelFontSize?: number;
1604
+ /** Used by the auto-legend. */
1605
+ label?: string;
1606
+ }
1607
+ declare function histogram<T>(channels: HistogramChannels<T>, options?: HistogramOptions): Geom<T>;
1608
+ //#endregion
1609
+ //#region src/grammar/geoms/rug.d.ts
1610
+ interface RugChannels<T> {
1611
+ x?: Aes<T, number | Date>;
1612
+ y?: Aes<T, number | Date>;
1613
+ /** Categorical color split for the ticks. */
1614
+ color?: Aes<T, unknown>;
1615
+ }
1616
+ type RugSide = "x" | "y" | "both";
1617
+ interface RugOptions {
1618
+ /**
1619
+ * Which edges receive ticks. Defaults to whichever channels are wired —
1620
+ * with both `x` and `y`, both edges; otherwise just the matching edge.
1621
+ * Use `"both"` to force both edges (mirrors x onto bottom, y onto left).
1622
+ */
1623
+ side?: RugSide;
1624
+ /** Tick length in pixels. Default `6`. */
1625
+ length?: number;
1626
+ /** Tick stroke width. Default `1`. */
1627
+ strokeWidth?: number;
1628
+ /** Override stroke color (defaults to theme.axis.color). */
1629
+ stroke?: Color;
1630
+ /** Multiplier on the resolved stroke alpha. Default `0.6`. */
1631
+ opacity?: number;
1632
+ label?: string;
1633
+ }
1634
+ declare function rug<T>(channels: RugChannels<T>, options?: RugOptions): Geom<T>;
1635
+ //#endregion
1636
+ //#region src/grammar/color-utils.d.ts
1637
+ /**
1638
+ * Accent-key shorthand used by chart-level marks (`band`, `rule`, `interval`,
1639
+ * `ribbon`). Literal {@link Color} values bypass theme resolution; accent
1640
+ * keys resolve through `theme.accents`.
1641
+ */
1642
+ type ColorOrAccent = Color | ThemeAccentKey;
1643
+ //#endregion
1644
+ //#region src/grammar/geoms/rule.d.ts
1645
+ interface RuleChannels<T> {
1646
+ x?: Aes<T, number | Date>;
1647
+ y?: Aes<T, number | Date>;
1648
+ }
1649
+ interface RuleOptions {
1650
+ /**
1651
+ * Stroke color. Accepts a literal {@link Color} or a theme accent key
1652
+ * (`"positive" | "negative" | "warn" | "info"`); accent keys resolve through
1653
+ * `theme.accents`.
1654
+ */
1655
+ stroke?: ColorOrAccent;
1656
+ strokeWidth?: number;
1657
+ dashPattern?: readonly number[];
1658
+ /** Optional inline rule label (only meaningful for non-data rules). */
1659
+ label?: string;
1660
+ labelColor?: Color;
1661
+ labelInset?: number;
1662
+ }
1663
+ declare function rule<T>(channels: RuleChannels<T>, options?: RuleOptions): Geom<T>;
1664
+ //#endregion
1665
+ //#region src/grammar/geoms/smooth.d.ts
1666
+ type SmoothMethod = "lm" | "poly" | "loess";
1667
+ interface SmoothChannels<T> {
1668
+ x: Aes<T, number | Date>;
1669
+ y: Aes<T, number>;
1670
+ /** Categorical color channel — fits one curve per group. */
1671
+ color?: Aes<T, unknown>;
1672
+ }
1673
+ interface SmoothLabelOptions {
1674
+ /** Pixel offset from the right end of the fit. */
1675
+ offsetX?: number;
1676
+ offsetY?: number;
1677
+ /** Custom label color. Defaults to the curve color. */
1678
+ color?: Color;
1679
+ fontSize?: number;
1680
+ /** Optional rounded-rect background. */
1681
+ box?: LabelBoxStyle;
1682
+ }
1683
+ interface SmoothOptions {
1684
+ /** Fit method. Default `"lm"`. */
1685
+ method?: SmoothMethod;
1686
+ /** Degree for `"poly"` (default `2`) or `"loess"` local polynomial (default `1`). */
1687
+ degree?: number;
1688
+ /** Span for `"loess"` (fraction of data per neighborhood). Default `0.5`. */
1689
+ span?: number;
1690
+ /**
1691
+ * Confidence ribbon. `true` (default) → 95%, `false` → no ribbon, `number`
1692
+ * → that confidence level (e.g. `0.99`).
1693
+ */
1694
+ ci?: boolean | number;
1695
+ /** Number of x samples for the curve & ribbon. Default `64`. */
1696
+ samples?: number;
1697
+ stroke?: Color;
1698
+ strokeWidth?: number;
1699
+ /** Override the ribbon fill. Defaults to the stroke color at low alpha. */
1700
+ ribbonFill?: Color;
1701
+ ribbonOpacity?: number;
1702
+ /**
1703
+ * Per-group inline label at the right end of each fitted curve. Only emitted
1704
+ * when the `color` channel is present. `true` uses the group key as the
1705
+ * label string.
1706
+ */
1707
+ label?: boolean | SmoothLabelOptions;
1708
+ /**
1709
+ * When true, hit-tests resolve to the nearest sample by x. Hover anywhere
1710
+ * along the curve and the closest source row in the matching group is
1711
+ * picked. Default `false` (Euclidean within `pickRadius`).
1712
+ */
1713
+ nearestX?: boolean;
1714
+ }
1715
+ declare function smooth<T>(channels: SmoothChannels<T>, options?: SmoothOptions): Geom<T>;
1716
+ //#endregion
1717
+ //#region src/grammar/geoms/rolling.d.ts
1718
+ interface StatRollingChannels<T> {
1719
+ x: Aes<T, number | Date>;
1720
+ y: Aes<T, number>;
1721
+ /** Categorical color channel — runs one rolling fit per group. */
1722
+ color?: Aes<T, unknown>;
1723
+ }
1724
+ interface StatRollingOptions<T> {
1725
+ /** Sliding window. See `RollingWindow` — bare number = count, object for explicit unit. */
1726
+ window: RollingWindow;
1727
+ /** Default `"mean"`. */
1728
+ statistic?: RollingStatistic<T>;
1729
+ /** Default `"x"`. */
1730
+ axis?: RollingAxis;
1731
+ /** Rows failing the filter are dropped from every window and the output series. */
1732
+ filter?: (datum: T, index: number) => boolean;
1733
+ /** Line curve. Default `"linear"` — pre-smoothed data rarely needs another smoother. */
1734
+ curve?: LineCurve;
1735
+ /** Override the per-group stroke color. When `color` is set, defaults to the color scale. */
1736
+ stroke?: Color;
1737
+ strokeWidth?: number;
1738
+ dashStyle?: LineDashStyle;
1739
+ /**
1740
+ * When true (default), hovering anywhere along the curve resolves to the
1741
+ * nearest rolling point by x — the cursor reads off "the smoothed value
1742
+ * here." Set false for Euclidean nearest within a small pickRadius.
1743
+ *
1744
+ * Hits always carry the synthetic {@link RollingPoint} (`{ x, y, count,
1745
+ * sourceIndex }`) as `info.datum`, not the underlying source row — so a
1746
+ * tooltip resolver can describe the *line's* value at the cursor (e.g.
1747
+ * "14-day mean: 88.4 kg") rather than misattributing a source row's tooltip
1748
+ * to a position on the smoothed curve. Branch on `info.mark === label` to
1749
+ * format the rolling tooltip distinctly from sibling point/line layers.
1750
+ */
1751
+ nearestX?: boolean;
1752
+ /** Used by the auto-legend and tooltip discrimination. Default `"rolling"`. */
1753
+ label?: string;
1754
+ }
1755
+ declare function statRolling<T>(channels: StatRollingChannels<T>, options: StatRollingOptions<T>): Geom<T>;
1756
+ //#endregion
1757
+ //#region src/grammar/geoms/ribbon.d.ts
1758
+ interface RibbonChannels<T> {
1759
+ x: Aes<T, number | Date>;
1760
+ y0: Aes<T, number | Date>;
1761
+ y1: Aes<T, number | Date>;
1762
+ }
1763
+ interface RibbonOptions {
1764
+ /**
1765
+ * Fill color. Accepts a literal {@link Color} or a theme accent key
1766
+ * (`"positive" | "negative" | "warn" | "info"`); accent keys resolve through
1767
+ * `theme.accents`.
1768
+ */
1769
+ fill?: ColorOrAccent;
1770
+ stroke?: ColorOrAccent;
1771
+ strokeWidth?: number;
1772
+ fillAlpha?: number;
1773
+ label?: string;
1774
+ }
1775
+ declare function ribbon<T>(channels: RibbonChannels<T>, options?: RibbonOptions): Geom<T>;
1776
+ //#endregion
1777
+ //#region src/grammar/geoms/interval.d.ts
1778
+ interface IntervalChannels<T> {
1779
+ /** Anchor for vertical intervals (required when `yMin`/`yMax` are bound). */
1780
+ x?: Aes<T, number | Date>;
1781
+ /** Anchor for horizontal intervals (required when `xMin`/`xMax` are bound). */
1782
+ y?: Aes<T, number | Date>;
1783
+ yMin?: Aes<T, number | Date>;
1784
+ yMax?: Aes<T, number | Date>;
1785
+ xMin?: Aes<T, number | Date>;
1786
+ xMax?: Aes<T, number | Date>;
1787
+ /** Optional categorical color channel — routed through the chart's color scale. */
1788
+ color?: Aes<T, unknown>;
1789
+ }
1790
+ interface IntervalOptions {
1791
+ /**
1792
+ * Stroke color. Accepts a literal {@link Color} or a theme accent key
1793
+ * (`"positive" | "negative" | "warn" | "info"`); accent keys resolve through
1794
+ * `theme.accents`.
1795
+ */
1796
+ stroke?: ColorOrAccent;
1797
+ strokeWidth?: number;
1798
+ /** Render perpendicular caps at each end. Default `true`. */
1799
+ caps?: boolean;
1800
+ /** Cap length in pixels (total, across both sides of the spine). Default `6`. */
1801
+ capWidth?: number;
1802
+ /** Display label for legend. */
1803
+ label?: string;
1804
+ }
1805
+ declare function interval<T>(channels: IntervalChannels<T>, options?: IntervalOptions): Geom<T>;
1806
+ //#endregion
1807
+ //#region src/grammar/geoms/band.d.ts
1808
+ interface BandChannels {
1809
+ x?: readonly [number | Date, number | Date];
1810
+ y?: readonly [number | Date, number | Date];
1811
+ }
1812
+ interface BandOptions {
1813
+ /**
1814
+ * Fill color. Accepts a literal {@link Color} or a theme accent key
1815
+ * (`"positive" | "negative" | "warn" | "info"`); accent keys resolve through
1816
+ * `theme.accents` and have `theme.marks.bandFillAlpha` applied unless
1817
+ * {@link BandOptions.alpha} is set.
1818
+ */
1819
+ fill?: ColorOrAccent;
1820
+ stroke?: ColorOrAccent;
1821
+ strokeWidth?: number;
1822
+ /**
1823
+ * Override the fill alpha. Defaults to `theme.marks.bandFillAlpha` when
1824
+ * `fill` is omitted or is an accent key; defaults to no override (use the
1825
+ * color's own alpha) when `fill` is a literal {@link Color}.
1826
+ */
1827
+ alpha?: number;
1828
+ label?: string;
1829
+ labelColor?: Color;
1830
+ }
1831
+ declare function band<T>(channels: BandChannels, options?: BandOptions): Geom<T>;
1832
+ //#endregion
1833
+ //#region src/grammar/geoms/text.d.ts
1834
+ type TextCollisionMode = "none" | "hide" | "stagger";
1835
+ interface TextChannels<T> {
1836
+ x: Aes<T, number | Date | string>;
1837
+ y: Aes<T, number | Date | string>;
1838
+ text: Aes<T, string>;
1839
+ }
1840
+ interface TextOptions {
1841
+ fontSize?: number;
1842
+ color?: Color;
1843
+ align?: ValueLabelAlign;
1844
+ offsetX?: number;
1845
+ offsetY?: number;
1846
+ /** Optional rounded-rect background. Requires the chart's glyph atlas. */
1847
+ box?: LabelBoxStyle;
1848
+ label?: string;
1849
+ /**
1850
+ * Post-layout collision handling. Default `"none"`. `"hide"` drops
1851
+ * overlapping labels via a greedy first-fit pass; `"stagger"` adds an
1852
+ * alternating y offset so adjacent labels sit on two rows.
1853
+ */
1854
+ collisionMode?: TextCollisionMode;
1855
+ /** Pixel padding around each label's measured rect when checking overlap. Default `2`. */
1856
+ collisionPadding?: number;
1857
+ }
1858
+ declare function text<T>(channels: TextChannels<T>, options?: TextOptions): Geom<T>;
1859
+ //#endregion
1860
+ //#region src/grammar/geoms/boxplot.d.ts
1861
+ type PointsMode = "auto" | "always" | "none";
1862
+ interface BoxplotChannels<T> {
1863
+ /** Categorical band axis. */
1864
+ x: Aes<T, string | number | Date>;
1865
+ /**
1866
+ * Numeric value axis (the distribution to summarize) when vertical. For
1867
+ * horizontal layouts (`orientation: "x"`) this carries the band category, so
1868
+ * a string is accepted; the value axis then lives on `x`.
1869
+ */
1870
+ y: Aes<T, string | number | Date>;
1871
+ /**
1872
+ * Optional grouping key. When supplied (and distinct from `x`) the layer
1873
+ * dodges side-by-side by this channel within each band.
1874
+ */
1875
+ color?: Aes<T, unknown>;
1876
+ }
1877
+ /**
1878
+ * Mean-overlay configuration. `true` → default red dot; `false` (default) →
1879
+ * no overlay; object → fully customised.
1880
+ */
1881
+ interface MeanMarkerOptions {
1882
+ shape?: PointShapeKind;
1883
+ /** Radius in pixels. Default `3.5`. */
1884
+ radius?: number;
1885
+ fill?: Color;
1886
+ stroke?: Color;
1887
+ strokeWidth?: number;
1888
+ }
1889
+ interface BoxplotOptions {
1890
+ /** Auto-detected from scale types when omitted (band axis = category axis). */
1891
+ orientation?: "x" | "y";
1892
+ /**
1893
+ * Box width as a fraction of the bandwidth (or grouped inner bandwidth, when
1894
+ * dodging). Default `0.6`.
1895
+ */
1896
+ width?: number;
1897
+ /**
1898
+ * Scale box widths by `√(n / nMax)` so groups with more samples render
1899
+ * wider — matches ggplot's `varwidth = TRUE`. Default `false`.
1900
+ */
1901
+ varwidth?: boolean;
1902
+ /** Whisker rule. Default `1.5` (Tukey). Pass `"minmax"` for no outliers. */
1903
+ whisker?: WhiskerRule;
1904
+ /** Quantile interpolation method. Default `"type-7"` (R default). */
1905
+ quantile?: QuantileMethod;
1906
+ /**
1907
+ * Render notches around the median at `± 1.58 · IQR / √n` (McGill 1978's
1908
+ * 95% CI). Useful as an informal significance test: non-overlapping
1909
+ * notches between groups suggest medians differ. Default `false`.
1910
+ */
1911
+ notched?: boolean;
1912
+ /**
1913
+ * Notch indent as a fraction of the box width (how far the sides pull in
1914
+ * at the median). Default `0.5`.
1915
+ */
1916
+ notchWidth?: number;
1917
+ /**
1918
+ * When to overlay raw jittered points.
1919
+ *
1920
+ * - `"auto"` (default) — only when `n < pointsThreshold` for the group.
1921
+ * Rationale: small samples are easy to mislead with a box; show the dots.
1922
+ * - `"always"` — always overlay.
1923
+ * - `"none"` — never overlay (still draws outliers unless `outliers: false`).
1924
+ */
1925
+ points?: PointsMode;
1926
+ /** Threshold for `points: "auto"`. Default `10`. */
1927
+ pointsThreshold?: number;
1928
+ /** Jitter spread, fraction of the per-box width. Default `0.5`. */
1929
+ pointJitter?: number;
1930
+ /** Radius of overlay & outlier points. Default `2.5`. */
1931
+ pointRadius?: number;
1932
+ /** Override fill for jittered overlay points. Default `alphaize(stroke, 0.5)`. */
1933
+ pointFill?: Color;
1934
+ /** Override fill for outlier points. Default = stroke. */
1935
+ outlierFill?: Color;
1936
+ /** Outlier point radius. Default = `pointRadius`. */
1937
+ outlierRadius?: number;
1938
+ /** Seed for deterministic jitter. Default `1`. */
1939
+ jitterSeed?: number;
1940
+ /** Render outlier dots beyond the whiskers. Default `true`. */
1941
+ outliers?: boolean;
1942
+ /** Constant fill when no `color` channel. Default theme palette[0]. */
1943
+ fill?: Color;
1944
+ /**
1945
+ * Override the theme's fill alpha (use `0` for outline-only boxes, e.g.
1946
+ * to match ggplot's bottom-middle "no-fill" look). When unset the layer
1947
+ * uses `theme.marks.fillAlpha`.
1948
+ */
1949
+ fillAlpha?: number;
1950
+ /** Box stroke color. Default theme text color (light line on dark fill). */
1951
+ stroke?: Color;
1952
+ /** Box stroke width. Default `1`. */
1953
+ strokeWidth?: number;
1954
+ /** Median line color. Defaults to `stroke`. */
1955
+ medianStroke?: Color;
1956
+ /** Median line stroke width. Default `2`. */
1957
+ medianStrokeWidth?: number;
1958
+ /** Whisker line stroke width. Default = `strokeWidth`. */
1959
+ whiskerStrokeWidth?: number;
1960
+ /** Whisker cap width as a fraction of box width. Default `0.5`. */
1961
+ capWidth?: number;
1962
+ /**
1963
+ * Mean overlay. `true` for the default red dot; `false` (default) to omit;
1964
+ * pass an object to customize shape, radius, fill, stroke. The mean is
1965
+ * **not** part of the box geometry — it's an annotation on top.
1966
+ */
1967
+ mean?: boolean | MeanMarkerOptions;
1968
+ /** Inner-band padding for grouped (color-split) layout. Default `0.05`. */
1969
+ groupPadding?: number;
1970
+ /**
1971
+ * Render an `n=<count>` label per band-axis category, just outside the
1972
+ * plot frame. Counts are summed across dodge groups. Default `false`.
1973
+ */
1974
+ showCounts?: boolean;
1975
+ /** Pixel offset of count labels from plot frame. Default `28` (vertical) / `32` (horizontal). */
1976
+ countsOffset?: number;
1977
+ countsFontSize?: number;
1978
+ countsColor?: Color;
1979
+ /** Display label for legend. */
1980
+ label?: string;
1981
+ }
1982
+ declare function boxplot<T>(channels: BoxplotChannels<T>, options?: BoxplotOptions): Geom<T>;
1983
+ //#endregion
1984
+ //#region src/grammar/geoms/_distribution.d.ts
1985
+ /** How per-row width relates to density across groups. */
1986
+ type DensityScale = "width" | "area" | "count";
1987
+ //#endregion
1988
+ //#region src/grammar/geoms/violin.d.ts
1989
+ interface ViolinChannels<T> {
1990
+ x: Aes<T, string | number | Date>;
1991
+ /**
1992
+ * Numeric value axis when vertical. For horizontal layouts
1993
+ * (`orientation: "x"`) this carries the band category, so a string is
1994
+ * accepted; the value axis then lives on `x`.
1995
+ */
1996
+ y: Aes<T, string | number | Date>;
1997
+ color?: Aes<T, unknown>;
1998
+ }
1999
+ type ViolinScale = DensityScale;
2000
+ type ViolinInner = "box" | "quartile" | "stick" | "none";
2001
+ interface ViolinOptions {
2002
+ orientation?: "x" | "y";
2003
+ /** Violin width as a fraction of the bandwidth (or grouped inner bandwidth). Default `0.9`. */
2004
+ width?: number;
2005
+ /** KDE bandwidth — number, `"silverman"` (default), or `"scott"`. */
2006
+ bandwidth?: KdeBandwidth;
2007
+ /** KDE evaluation grid size. Default `64`. */
2008
+ gridSize?: number;
2009
+ /** KDE kernel. Default `"gaussian"`. */
2010
+ kernel?: KdeKernel;
2011
+ /** Clip KDE to data range (true, default) or pad outward by ~3 bandwidths. */
2012
+ trim?: boolean;
2013
+ /**
2014
+ * Width-normalization mode.
2015
+ *
2016
+ * - `"width"` (default) — each violin uses its full allotted width; shapes
2017
+ * are easy to compare but **areas are misleading**.
2018
+ * - `"area"` — density scaled relative to the global max so areas are
2019
+ * comparable across groups (groups with low n look skinny).
2020
+ * - `"count"` — area scales with sample size (bigger n → wider violin).
2021
+ */
2022
+ scale?: ViolinScale;
2023
+ /**
2024
+ * Inner annotation drawn on top of the violin.
2025
+ *
2026
+ * - `"none"` (default) — bare KDE polygon, like ggplot's `geom_violin`.
2027
+ * - `"box"` — slim box plot with median, IQR, whiskers.
2028
+ * - `"quartile"` — three horizontal/vertical lines at Q1, median, Q3.
2029
+ * - `"stick"` — single line at the median only.
2030
+ */
2031
+ inner?: ViolinInner;
2032
+ /** When to overlay raw jittered points. See `BoxplotOptions["points"]`. */
2033
+ points?: PointsMode;
2034
+ pointsThreshold?: number;
2035
+ pointJitter?: number;
2036
+ pointRadius?: number;
2037
+ jitterSeed?: number;
2038
+ /** Box stats: whisker rule when `inner: "box"`. Default `1.5`. */
2039
+ whisker?: WhiskerRule;
2040
+ /** Box stats: quantile method. Default `"type-7"`. */
2041
+ quantile?: QuantileMethod;
2042
+ fill?: Color;
2043
+ stroke?: Color;
2044
+ strokeWidth?: number;
2045
+ /** Color of inner annotation marks. Defaults to `stroke` (or theme text). */
2046
+ innerStroke?: Color;
2047
+ /** Stroke width for the embedded mini-box body. Default `1`. */
2048
+ innerStrokeWidth?: number;
2049
+ /** Inner-band padding for grouped (color-split) layout. Default `0.05`. */
2050
+ groupPadding?: number;
2051
+ /**
2052
+ * Render an `n=<count>` label per group, aligned with the band axis just
2053
+ * outside the plot frame. Useful when the categorical labels alone hide
2054
+ * sample-size differences.
2055
+ */
2056
+ showCounts?: boolean;
2057
+ /**
2058
+ * Pixel offset of the count labels from the plot frame edge along the
2059
+ * band-axis perpendicular. Increase to clear longer tick labels. Default
2060
+ * `28` (vertical) / `32` (horizontal).
2061
+ */
2062
+ countsOffset?: number;
2063
+ countsFontSize?: number;
2064
+ countsColor?: Color;
2065
+ label?: string;
2066
+ }
2067
+ declare function violin<T>(channels: ViolinChannels<T>, options?: ViolinOptions): Geom<T>;
2068
+ //#endregion
2069
+ //#region src/grammar/geoms/ridgeline.d.ts
2070
+ type RidgelineGeom = "kde" | "histogram";
2071
+ type RidgelineScale = DensityScale;
2072
+ type RidgelineInner = "none" | "median" | "quartile" | "mean";
2073
+ type RidgelineFillMode = "solid" | "gradient";
2074
+ interface RidgelineChannels<T> {
2075
+ /** Numeric value being distributed. Provide one of x or y; the other is the row category. */
2076
+ x: Aes<T, string | number>;
2077
+ y: Aes<T, string | number>;
2078
+ /** Optional categorical group key. Drives palette fill (chart color scale). */
2079
+ color?: Aes<T, unknown>;
2080
+ }
2081
+ interface RidgelineOptions {
2082
+ /** Auto-detected from scale types when omitted. The default reproduces the common "rows on y, values on x" layout. */
2083
+ orientation?: "x" | "y";
2084
+ /** Density estimator. Default `"kde"`. */
2085
+ geom?: RidgelineGeom;
2086
+ /**
2087
+ * How tall a ridge can be relative to its band-cell spacing. `1` = no
2088
+ * overlap (each ridge stays inside its row); `>1` allows overlap into
2089
+ * neighbours. Default `2.5`.
2090
+ */
2091
+ overlap?: number;
2092
+ /**
2093
+ * Across-group height normalization (same semantics as `violin`'s `scale`).
2094
+ *
2095
+ * - `"width"` (default) — each row uses its full allotted height.
2096
+ * - `"area"` — heights normalized by the global max density.
2097
+ * - `"count"` — heights scaled by sample size on top of `"area"`.
2098
+ */
2099
+ scale?: RidgelineScale;
2100
+ bandwidth?: KdeBandwidth;
2101
+ gridSize?: number;
2102
+ kernel?: KdeKernel;
2103
+ trim?: boolean;
2104
+ bins?: number;
2105
+ binwidth?: number;
2106
+ breaks?: readonly number[];
2107
+ rule?: BinRule;
2108
+ measure?: HistogramMeasure;
2109
+ closed?: BinClosed;
2110
+ /**
2111
+ * Solid fill (default) uses the chart color scale per category, or the
2112
+ * theme's categorical palette if no `color` channel is mapped. Gradient
2113
+ * fill ignores the category and applies a value-axis-mapped color ramp,
2114
+ * reproducing the "Lincoln NE temperatures" look.
2115
+ */
2116
+ fillMode?: RidgelineFillMode;
2117
+ /**
2118
+ * Color ramp for `fillMode: "gradient"`. Receives `t ∈ [0, 1]` mapped from
2119
+ * the value-axis range. Default = `theme.palettes.continuous`.
2120
+ */
2121
+ gradient?: (t01: number) => Color;
2122
+ /** Per-row inner annotation. Default `"none"`. */
2123
+ inner?: RidgelineInner;
2124
+ innerStroke?: Color;
2125
+ innerStrokeWidth?: number;
2126
+ /** Radius of the median/mean dot when `inner` includes a point. Default `3`. */
2127
+ innerDotRadius?: number;
2128
+ /** Draw a thin rule along each row's baseline. Default `true`. */
2129
+ baseline?: boolean;
2130
+ baselineStroke?: Color;
2131
+ baselineWidth?: number;
2132
+ /** `n=<count>` per row, anchored inline at the row baseline by default. */
2133
+ showCounts?: boolean;
2134
+ countsAnchor?: "outside" | "inline";
2135
+ /** Pixel offset for the counts label. Default 4 (inline) / 28 (outside, vertical) / 32 (outside, horizontal). */
2136
+ countsOffset?: number;
2137
+ countsFontSize?: number;
2138
+ countsColor?: Color;
2139
+ /** Solid fill for the silhouette. Default theme palette[0] (overridden by chart color scale when `color` is set). */
2140
+ fill?: Color;
2141
+ fillAlpha?: number;
2142
+ /** Silhouette outline. Default theme text color. */
2143
+ stroke?: Color;
2144
+ strokeWidth?: number;
2145
+ /** Inner-band padding when dodging via `color`. Default `0.05`. */
2146
+ groupPadding?: number;
2147
+ whisker?: WhiskerRule;
2148
+ quantile?: QuantileMethod;
2149
+ label?: string;
2150
+ }
2151
+ declare function ridgeline<T>(channels: RidgelineChannels<T>, options?: RidgelineOptions): Geom<T>;
2152
+ //#endregion
2153
+ //#region src/grammar/geoms/tile.d.ts
2154
+ interface TileChannels<T> {
2155
+ x: Aes<T, string | number | Date>;
2156
+ y: Aes<T, string | number | Date>;
2157
+ /**
2158
+ * Continuous fill — typically a numeric column. Drives the chart's color
2159
+ * scale (legend renders as a continuous color bar). For a per-cell constant
2160
+ * color, pass `options.fill` instead and omit this channel.
2161
+ */
2162
+ fill?: Aes<T, unknown>;
2163
+ }
2164
+ interface TileNAOptions {
2165
+ /** Fill for missing/non-finite values. When unset, NA cells are skipped. */
2166
+ fill?: Color;
2167
+ }
2168
+ interface TileOptions<T = unknown> {
2169
+ /**
2170
+ * Constant cell color when no `fill` channel is mapped. Ignored when
2171
+ * `channels.fill` is present (in which case the color scale supplies the
2172
+ * fill).
2173
+ */
2174
+ fill?: Color;
2175
+ /** Horizontal/vertical inset between cells. Default `0`. */
2176
+ padding?: number;
2177
+ /** Per-axis padding override (multi-key form). Wins over `padding`. */
2178
+ paddingX?: number;
2179
+ paddingY?: number;
2180
+ /** Optional border outline per cell. */
2181
+ stroke?: Color;
2182
+ strokeWidth?: number;
2183
+ cornerRadius?: number;
2184
+ /**
2185
+ * Per-cell text label. Receives the (numeric) fill value when the `fill`
2186
+ * channel is mapped; receives `NaN` otherwise (in which case you'll
2187
+ * typically derive the label from the datum directly).
2188
+ */
2189
+ showValues?: (value: number, datum: T, index: number) => string;
2190
+ labelColor?: Color;
2191
+ labelFontSize?: number;
2192
+ /**
2193
+ * Skip per-cell labels when the projected cell is below this pixel size on
2194
+ * either axis. Labels at small cell sizes are unreadable smudges and the
2195
+ * shaping cost dominates frame time at high cell counts. Default: unset
2196
+ * (every cell labeled). A value around `1.5 * labelFontSize` is a sensible
2197
+ * floor for legibility.
2198
+ */
2199
+ minLabelCellPx?: number;
2200
+ /**
2201
+ * For numeric/time x or y axes only — the implicit cell width/height in
2202
+ * domain units. When omitted, the cell extent is inferred from the
2203
+ * smallest gap between sorted unique values in the data.
2204
+ */
2205
+ cellWidth?: number;
2206
+ cellHeight?: number;
2207
+ /** Missing-value handling. */
2208
+ na?: TileNAOptions;
2209
+ label?: string;
2210
+ }
2211
+ declare function tile<T>(channels: TileChannels<T>, options?: TileOptions<T>): Geom<T>;
2212
+ //#endregion
2213
+ //#region src/grammar/geoms/aggregate.d.ts
2214
+ type AggregateBinBy = "x" | "y";
2215
+ type AggregateBinSize = number | "auto" | ((info: AutoBinSizeInfo) => number);
2216
+ interface AutoBinSizeInfo {
2217
+ /** Pixel span of the binned axis (positive). */
2218
+ pixelSpan: number;
2219
+ /** Domain span of the binned axis in axis units (positive). For time scales, ms. */
2220
+ domainSpan: number;
2221
+ /** `pixelSpan / domainSpan` — pixels per domain unit on the binned axis. */
2222
+ pixelsPerUnit: number;
2223
+ }
2224
+ type AggregateSummaryKind = "mean" | "median" | "count" | "sum" | "first" | "last";
2225
+ interface AggregateBinView<T> {
2226
+ /** Values from the *non-binned* axis, in input order within this bin. */
2227
+ values: readonly number[];
2228
+ /** Source items inside this bin, in input order. */
2229
+ items: readonly T[];
2230
+ /** Count after filter. */
2231
+ count: number;
2232
+ /** Bin's lower edge on the binned axis (inclusive). */
2233
+ lo: number;
2234
+ /** Bin's upper edge on the binned axis (exclusive, except the final bin). */
2235
+ hi: number;
2236
+ }
2237
+ type AggregateSummary<T> = AggregateSummaryKind | ((bin: AggregateBinView<T>) => number);
2238
+ /** Result of a bundle summary — one center + a [lo, hi] range per bin. */
2239
+ interface AggregateBundleResult {
2240
+ center: number;
2241
+ lo: number;
2242
+ hi: number;
2243
+ }
2244
+ type AggregateBundleSummaryKind = "mean+ci" | "median+iqr";
2245
+ /**
2246
+ * Bundle summaries emit `{ center, lo, hi }` per bin and pair with the
2247
+ * `interval` or `ribbon` inner geom. Built-in kinds plus a quantile triple
2248
+ * `{ quantiles: [loQ, centerQ, hiQ] }` (e.g. `[0.1, 0.5, 0.9]` for an 80%
2249
+ * range) or a custom function returning the bundle directly.
2250
+ */
2251
+ type AggregateBundleSummary<T> = AggregateBundleSummaryKind | {
2252
+ quantiles: readonly [number, number, number];
2253
+ } | ((bin: AggregateBinView<T>) => AggregateBundleResult);
2254
+ interface AggregateChannels<T> {
2255
+ x: Aes<T, number | Date>;
2256
+ y: Aes<T, number | Date>;
2257
+ }
2258
+ type AggregateInnerGeom = "point" | "line" | "bar" | "interval" | "ribbon";
2259
+ interface AggregateOptions<T> {
2260
+ /** Axis to slide along. Default `"x"`. */
2261
+ binBy?: AggregateBinBy;
2262
+ /** Bin width in domain units; `"auto"` targets `~autoTargetPx` px. Default `"auto"`. */
2263
+ binSize?: AggregateBinSize;
2264
+ /**
2265
+ * Reduction applied per bin. Scalar kinds (`"mean"`, `"median"`, …) pair
2266
+ * with `geom: "point" | "line" | "bar"`. Bundle kinds (`"mean+ci"`,
2267
+ * `"median+iqr"`, `{ quantiles }`, function-returning-`{center, lo, hi}`)
2268
+ * pair with `geom: "interval" | "ribbon"`. Default `"mean"`.
2269
+ */
2270
+ summary?: AggregateSummary<T> | AggregateBundleSummary<T>;
2271
+ /** Row predicate. Rejected rows are excluded from both binning and the
2272
+ * raw-fallback path. */
2273
+ filter?: (datum: T, index: number) => boolean;
2274
+ /** When `avg-points-per-bin < dissolveAt`, render raw geom instead.
2275
+ * Default `1.2`. */
2276
+ dissolveAt?: number;
2277
+ /** Inner mark kind. Default `"point"`. */
2278
+ geom?: AggregateInnerGeom;
2279
+ /** Fill / stroke applied to every emitted mark. */
2280
+ fill?: Color;
2281
+ stroke?: Color;
2282
+ strokeWidth?: number;
2283
+ /** Point-specific. */
2284
+ radius?: number;
2285
+ shape?: PointShapeKind;
2286
+ /** Line-specific. */
2287
+ curve?: LineCurve;
2288
+ /** Target pixels per bin for `"auto"` sizing. Default `7`. */
2289
+ autoTargetPx?: number;
2290
+ /** Display label for legend / hit-test (forwarded to inner mark). */
2291
+ label?: string;
2292
+ /**
2293
+ * Confidence level for the `"mean+ci"` bundle summary. Default `0.95`.
2294
+ * Ignored for other summaries.
2295
+ */
2296
+ ciLevel?: number;
2297
+ /** Interval-specific: render perpendicular caps. Default `true`. */
2298
+ caps?: boolean;
2299
+ /** Interval-specific: cap length in pixels. Default `6`. */
2300
+ capWidth?: number;
2301
+ /** Ribbon-specific: fill alpha override (otherwise theme.marks.ribbonFillAlpha). */
2302
+ fillAlpha?: number;
2303
+ }
2304
+ declare function aggregate<T>(channels: AggregateChannels<T>, options?: AggregateOptions<T>): Geom<T>;
2305
+ //#endregion
2306
+ //#region src/grammar/chart.d.ts
2307
+ type Row = Record<string, unknown>;
2308
+ interface PlotSpec<T> {
2309
+ data: readonly T[] | Signal<readonly T[]>;
2310
+ width?: number;
2311
+ height?: number;
2312
+ background?: Color;
2313
+ padding?: Padding;
2314
+ /**
2315
+ * Inner padding inside the plot frame, in pixels. Adds slack between the
2316
+ * axis lines and the data — as if the view were zoomed out a bit. Accepts a
2317
+ * single number applied to all sides, or per-side overrides. Different from
2318
+ * `padding`, which is the *outer* canvas inset before axes/legend/title.
2319
+ */
2320
+ framePadding?: number | {
2321
+ top?: number;
2322
+ right?: number;
2323
+ bottom?: number;
2324
+ left?: number;
2325
+ };
2326
+ device?: GPUDevice;
2327
+ /** Initial theme; can be replaced via `.theme(...)`. */
2328
+ theme?: Theme;
2329
+ }
2330
+ interface AxisSpec {
2331
+ title?: string | {
2332
+ text: string;
2333
+ maxWidth?: number;
2334
+ };
2335
+ format?: AxisTickFormatter;
2336
+ /**
2337
+ * How many ticks to render:
2338
+ * - `number` — target count (default 5).
2339
+ * - `"auto"` — pick the count from the axis's pixel span (~80px/tick
2340
+ * horizontal, ~50px/tick vertical). Useful for time-series so dense
2341
+ * per-day ticks decay to weeks / months / quarters as the view widens.
2342
+ * - `{ interval, step? }` — explicit time interval (time scales only).
2343
+ * `interval: "quarter"` is sugar for `month, step: 3`.
2344
+ */
2345
+ ticks?: TickSpec;
2346
+ gridLines?: boolean;
2347
+ /** Draw the axis line itself (the spine along the plot frame). Default `true`. */
2348
+ axisLine?: boolean;
2349
+ label?: {
2350
+ maxWidth?: number;
2351
+ };
2352
+ /**
2353
+ * Auto-decimate tick labels until they no longer visually overlap.
2354
+ * `"auto"` measures the formatted labels and inflates the effective
2355
+ * `labelStep` accordingly. Useful for dense band axes (≥15 categories)
2356
+ * and time axes whose density shifts under zoom. Default off — opt in
2357
+ * per axis.
2358
+ */
2359
+ labelCollision?: "auto";
2360
+ }
2361
+ interface AxesSpec {
2362
+ x?: AxisSpec;
2363
+ y?: AxisSpec;
2364
+ }
2365
+ /**
2366
+ * Chart title / subtitle. Each accepts a string or `{ text, maxWidth }` —
2367
+ * the object form clips with an ellipsis when the rendered text exceeds the
2368
+ * given pixel width.
2369
+ */
2370
+ interface TitleSpec {
2371
+ title?: string | {
2372
+ text: string;
2373
+ maxWidth?: number;
2374
+ };
2375
+ subtitle?: string | {
2376
+ text: string;
2377
+ maxWidth?: number;
2378
+ };
2379
+ }
2380
+ /**
2381
+ * Float-over-plot position. `x` and `y` are normalized to the plot frame
2382
+ * (`0..1`); `justify` controls which corner of the legend's bbox lands on
2383
+ * that point. Inspired by ggplot2's `legend.position = c(x, y)`.
2384
+ */
2385
+ interface LegendInsidePosition {
2386
+ inside: {
2387
+ x: number;
2388
+ y: number;
2389
+ };
2390
+ /** Default `"start"` — top-left of legend lands on the point. */
2391
+ justify?: {
2392
+ x?: "start" | "center" | "end";
2393
+ y?: "start" | "center" | "end";
2394
+ };
2395
+ }
2396
+ type LegendPosition = "top" | "right" | "bottom" | "left" | LegendInsidePosition;
2397
+ /**
2398
+ * Channels eligible for being merged into a single legend entry. When merged,
2399
+ * each domain value's swatch shows the resolved value from every listed scale
2400
+ * — e.g. `merge: ["color", "shape"]` produces one row per category whose
2401
+ * swatch is colored by the color scale AND shaped by the shape scale.
2402
+ *
2403
+ * `size` participation is supported only when another categorical channel is
2404
+ * also in the merge list (the entries are still iterated over the categorical
2405
+ * domain; size is sampled from its numeric range at evenly-spaced positions).
2406
+ */
2407
+ type LegendMergeChannel = "color" | "shape" | "size" | "borderStyle" | "overlayGlyph";
2408
+ interface LegendSpec {
2409
+ /** Disable the auto-legend. */
2410
+ show?: boolean;
2411
+ /**
2412
+ * Where the legend sits. Outer slots: `"top" | "right" | "bottom" | "left"`.
2413
+ * For an over-plot legend, pass `{ inside: { x, y } }` with `x`/`y` in `0..1`
2414
+ * (plot-frame coords). Default depends on legend type — `"right"` for
2415
+ * continuous color bars, `"top"` for categorical swatches.
2416
+ */
2417
+ position?: LegendPosition;
2418
+ /** Optional title rendered above the legend entries / color bar. */
2419
+ title?: string;
2420
+ /** Override color-bar long-axis pixel length. Default 160. */
2421
+ length?: number;
2422
+ /** Override color-bar thickness. Default 12. */
2423
+ thickness?: number;
2424
+ /** Continuous legend — major tick count target. Default `5`. */
2425
+ ticks?: number;
2426
+ /** Continuous legend — explicit major tick values (override `ticks`). */
2427
+ tickValues?: readonly number[];
2428
+ /**
2429
+ * Continuous legend — minor (unlabeled) tick marks. Number subdivides each
2430
+ * major interval (`2` = one minor halfway); array places ticks explicitly.
2431
+ */
2432
+ minorTicks?: number | readonly number[];
2433
+ /**
2434
+ * Continuous legend — render a tick label every `N`th major tick.
2435
+ * Default `1`. Combine with `minorTicks` for "lines every 0.5, labels
2436
+ * every 1.0" style guides.
2437
+ */
2438
+ labelStep?: number;
2439
+ /** Continuous legend — tick label formatter. */
2440
+ format?: (value: number) => string;
2441
+ /**
2442
+ * Continuous legend — override the color space used to interpolate the
2443
+ * palette stops for the bar's gradient. Falls back to the chart's color
2444
+ * scale (which itself defaults to `theme.paletteBlendSpace = "oklch"`).
2445
+ */
2446
+ blendSpace?: _$insomni.BlendSpace;
2447
+ /**
2448
+ * Merge the listed aesthetic channels into a single combined legend. When
2449
+ * provided, every listed channel must encode the same field (the consumer
2450
+ * is asserting this) and the merged legend iterates the primary scale's
2451
+ * domain (priority: color → shape → borderStyle → overlayGlyph). Each
2452
+ * entry's swatch combines the resolved values across every listed scale.
2453
+ *
2454
+ * Channels that are listed but have no active scale on the chart are
2455
+ * silently skipped — they contribute nothing to the swatch. Omitting this
2456
+ * option leaves the default behavior unchanged (color-only legend).
2457
+ */
2458
+ merge?: readonly LegendMergeChannel[];
2459
+ }
2460
+ type ScaleOptionsByChannel<C extends Channel> = C extends "x" | "y" ? PositionScaleOptions : C extends "color" ? ColorScaleOptions<unknown> : C extends "size" ? SizeScaleOptions : C extends "alpha" ? AlphaScaleOptions : C extends "shape" ? ShapeScaleOptions : never;
2461
+ interface TransitionsConfig {
2462
+ /** Duration in milliseconds. Default: theme.motion.data duration (240ms). */
2463
+ duration?: number;
2464
+ /** Stable key for matching rows across data refreshes. Required for enter animations. */
2465
+ key?: (datum: unknown, index: number) => string | number;
2466
+ }
2467
+ /** Handle exposed on MountedPlot to request manual transitions. */
2468
+ interface TransitionsHandle {
2469
+ /** Trigger a transition on the next draw (e.g. after a scale domain change). */
2470
+ requestTransition(): void;
2471
+ }
2472
+ interface MountPlotOptions<T> {
2473
+ /**
2474
+ * GPU device. Required when the mount has to create a `Renderer2D` or
2475
+ * `GlyphAtlas` (i.e. when you don't pass them yourself). Either source
2476
+ * works — `plot({ device })` or `mount(canvas, { device })`.
2477
+ */
2478
+ device?: GPUDevice;
2479
+ /**
2480
+ * Builder closure called on every `invalidate()`. Use this when chart
2481
+ * settings live in module-scope state (controls, signals, etc.) and you
2482
+ * want the chart to be re-derived on each draw. The closure should return
2483
+ * a fresh `Chart<T>` (typically by calling the same `plot().layer()...`
2484
+ * chain that produced this chart).
2485
+ *
2486
+ * If omitted, the mount renders the chart you mounted on, statically.
2487
+ * Either way, `handle.update(newChart | newBuilder)` swaps it.
2488
+ */
2489
+ build?: () => Chart<T>;
2490
+ /**
2491
+ * Use an externally owned renderer. The mount won't call `setBackground`,
2492
+ * `resize`, `setDpr`, or `destroy()` on it — those become the caller's
2493
+ * responsibility. Useful for sharing a single renderer across multiple
2494
+ * charts or compositing a chart over a world-space scene.
2495
+ */
2496
+ renderer?: Renderer2D;
2497
+ /**
2498
+ * External layers (axis under, marks middle, hud over). Mount won't clear
2499
+ * them outside the pipeline. The optional `overlay` layer sits on top of the
2500
+ * hud and carries the cursor-driven overlays (tooltip / crosshair / brush /
2501
+ * menu); omit it and the mount creates its own.
2502
+ */
2503
+ layers?: {
2504
+ axis: Layer;
2505
+ marks: Layer;
2506
+ hud: Layer;
2507
+ overlay?: Layer;
2508
+ };
2509
+ /**
2510
+ * Extra layers rendered alongside the chart's own layers. Called each draw
2511
+ * to read the current list, so callers can lazy-create or swap layers
2512
+ * without re-mounting. Layers returned here are NOT cleared by the chart
2513
+ * pipeline — they persist across draws until the caller clears them
2514
+ * themselves. Use this for retained, world-anchored content (large label
2515
+ * sets that ride the camera, scatter overlays driven by a separate camera
2516
+ * viewport, etc.) where per-frame re-emission would dominate CPU cost.
2517
+ *
2518
+ * Two slots:
2519
+ * - `belowMarks`: rendered after axes, before chart marks. Behind data.
2520
+ * - `aboveMarks`: rendered after chart marks, before the HUD. Above
2521
+ * data but below tooltips / brushes / interactive overlays.
2522
+ */
2523
+ extraLayers?: () => {
2524
+ belowMarks?: readonly Layer[];
2525
+ aboveMarks?: readonly Layer[];
2526
+ };
2527
+ /** Fixed width (CSS px). When set with `height`, disables auto-resize by default. */
2528
+ width?: number;
2529
+ /** Fixed height (CSS px). When set with `width`, disables auto-resize by default. */
2530
+ height?: number;
2531
+ /** Override DPR. Default: `window.devicePixelRatio`. */
2532
+ dpr?: number;
2533
+ /** Track canvas size via `ResizeObserver`. Default: `true` unless `width` and `height` are both set. */
2534
+ autoResize?: boolean;
2535
+ /** Run an internal `requestAnimationFrame` loop. Default `true`. Set false to call `update()` from your own loop. */
2536
+ autoFrame?: boolean;
2537
+ /** Pause draws while `document.hidden`. Default `true`. */
2538
+ pauseOnHidden?: boolean;
2539
+ /** Background override. Falls back to `chart.background` then `theme.background`. */
2540
+ background?: Color;
2541
+ /** Per-frame CPU/GPU timing callback. Forwarded to the underlying `Renderer2D`. */
2542
+ onFrameTiming?: (t: FrameTiming) => void;
2543
+ /** Enable detailed GPU pipeline-level profiling. Forwarded to the underlying `Renderer2D`. */
2544
+ enablePipelineProfiling?: boolean;
2545
+ /**
2546
+ * Default interactions wired into the chart. Pass `false` to disable all of
2547
+ * them. Pass `true` (or omit) to enable the defaults: a hover tooltip on
2548
+ * geoms that support hit-testing (`point` / `bar` / `line` / `area`) plus a
2549
+ * snapping crosshair on continuous x-scale charts. Pass an object to enable
2550
+ * a subset and tune options.
2551
+ */
2552
+ interactions?: boolean | InteractionsConfig;
2553
+ /**
2554
+ * Animated transitions when data or chart config changes. On by default
2555
+ * (inherits `theme.motion.data` duration and easing). Pass `false` to disable.
2556
+ */
2557
+ transitions?: boolean | TransitionsConfig;
2558
+ /**
2559
+ * Wire up pan/zoom on the chart's x/y scales. Off by default. Pass `true`
2560
+ * to enable with default zoom limits, or an object to override.
2561
+ *
2562
+ * Behavior when enabled:
2563
+ * - The mount creates a `DataViewport` seeded from the chart's x/y scale
2564
+ * domain options (the values you passed to `.scale("x", { domain })`).
2565
+ * - Pointer events on the canvas pan/zoom the viewport.
2566
+ * - The viewport's visible domains are written back into the chart's x/y
2567
+ * scale options on every draw, so axes/ticks update automatically.
2568
+ * - The viewport is exposed on `MountedPlot.viewport` for read-only
2569
+ * introspection (e.g. a `build:` closure that re-bins data into the
2570
+ * visible domain).
2571
+ *
2572
+ * Requires both x and y scales to be continuous (linear / log / sqrt /
2573
+ * time). Throws if either scale is missing a numeric/date domain.
2574
+ */
2575
+ panZoom?: boolean | PanZoomConfig;
2576
+ /**
2577
+ * Clip marks to the inner plot panel rect. Default `true`. When on, the
2578
+ * mount sets `marksLayer.setClipRect(plotFrame)` after each pipeline run
2579
+ * so geom rects/lines/etc. don't bleed into axis / legend / title slots.
2580
+ */
2581
+ clipMarks?: boolean;
2582
+ /**
2583
+ * Damage-tracked partial redraw. On by default — set `false` to opt out,
2584
+ * which renders byte-identically to the classic full-frame path.
2585
+ *
2586
+ * When on (and the mount owns its renderer), the renderer is given a
2587
+ * persistent backbuffer and the static marks are baked to a texture, so
2588
+ * cursor-driven overlays (tooltip / crosshair / brush / menu) repaint only
2589
+ * their own damage rect instead of clearing + re-compiling the whole chart
2590
+ * on every pointer move. View-changing events (data, pan/zoom, resize,
2591
+ * selection, legend toggle, transitions) still run a full frame and re-bake.
2592
+ *
2593
+ * Silently ignored when an external `renderer` or `layers` is supplied (the
2594
+ * mount can't reconfigure pieces it doesn't own); only an *explicit*
2595
+ * `partialRedraw: true` in that situation logs a one-time warning.
2596
+ */
2597
+ partialRedraw?: boolean;
2598
+ }
2599
+ /**
2600
+ * Per-axis pan / zoom enable. Either axis can be silenced independently.
2601
+ * Sugar: `true` ≡ `"xy"`, `false` ≡ `"none"`.
2602
+ */
2603
+ type PanZoomAxes = "x" | "y" | "xy" | "none";
2604
+ /**
2605
+ * Pan-bound margins, expressed as fractions of the visible span. A bare
2606
+ * number applies to both axes. See `DataPanBoundsOptions` for the full
2607
+ * `{ overshoot, drift }` shape inherited from the viewport.
2608
+ */
2609
+ type ChartPanBounds = ChartPanBoundsOptions | false;
2610
+ interface ChartPanBoundsOptions {
2611
+ /** Pan-past-content allowance when zoomed in (content > viewport). */
2612
+ overshoot?: number | {
2613
+ x?: number;
2614
+ y?: number;
2615
+ };
2616
+ /** Drift allowance when zoomed out (content ≤ viewport). */
2617
+ drift?: number | {
2618
+ x?: number;
2619
+ y?: number;
2620
+ };
2621
+ }
2622
+ interface PanZoomConfig {
2623
+ /**
2624
+ * Minimum zoom factor relative to the chart's base domain. `1` means the
2625
+ * user cannot zoom *out* past the data extent — a sensible chart default.
2626
+ * Smaller values (e.g. `0.1`) allow zooming out into empty space.
2627
+ *
2628
+ * Default `1` (zoom-out clamped to the data extent).
2629
+ */
2630
+ minZoom?: number;
2631
+ /**
2632
+ * Maximum zoom factor relative to the chart's base domain. `100` lets the
2633
+ * user zoom in to 1% of the data range — usually a sane floor before axis
2634
+ * ticks and labels collapse.
2635
+ *
2636
+ * Default `100`.
2637
+ */
2638
+ maxZoom?: number;
2639
+ /**
2640
+ * Pan-bound the visible domain to the chart's base (data) domain. When
2641
+ * zoomed in, panning stops at content edges plus an `overshoot` margin;
2642
+ * when zoomed out far enough that content fits in view, the viewport can
2643
+ * still drift by `drift × visibleSpan`.
2644
+ *
2645
+ * Default `{ overshoot: 0.1 }` (the user can rubber-band 10% past the
2646
+ * data edges but can't drag the chart fully off-screen). Pass `false`
2647
+ * to opt out entirely.
2648
+ */
2649
+ panBounds?: ChartPanBounds;
2650
+ /**
2651
+ * Lock pan to a subset of axes. Default `"xy"` (both axes pan).
2652
+ */
2653
+ pan?: PanZoomAxes;
2654
+ /**
2655
+ * Lock zoom to a subset of axes. Default `"xy"` (both axes zoom).
2656
+ */
2657
+ zoom?: PanZoomAxes;
2658
+ /**
2659
+ * When set, the Y scale's domain is recomputed every frame from whatever
2660
+ * data is currently visible along X (financial-chart "auto-Y" behavior).
2661
+ * Implies `pan: "x"` and `zoom: "x"` — Y becomes read-only.
2662
+ *
2663
+ * `true` uses the default 5% padding around the visible Y extent; pass
2664
+ * `{ padding }` to override (0..0.5).
2665
+ *
2666
+ * The Y scale must still declare an explicit `domain` (used as a fallback
2667
+ * when no data is visible in the current X window).
2668
+ */
2669
+ yFit?: boolean | {
2670
+ padding?: number;
2671
+ };
2672
+ }
2673
+ interface InteractionsConfig {
2674
+ tooltip?: boolean | TooltipConfig;
2675
+ /**
2676
+ * Hover crosshair (guide line). Default: enabled on charts whose x-scale
2677
+ * is continuous (`linear` / `log` / `sqrt` / `time`); auto-disabled on
2678
+ * band x-scales. Pass `false` to disable, `true` for defaults, or an
2679
+ * object to tune. Snaps to the same hit positions the tooltip uses.
2680
+ */
2681
+ crosshair?: boolean | CrosshairConfig;
2682
+ /**
2683
+ * Click-to-select. Off by default — selection has app-level semantics so
2684
+ * the chart shouldn't claim it silently. Pass `true` to enable defaults
2685
+ * (plain click replaces, shift toggles, meta/ctrl removes, click-empty
2686
+ * clears) or an object to tune. The active selection is exposed on
2687
+ * `MountedPlot.selected` and surfaces to geoms via `CompileContext.selected`
2688
+ * — selected rows get a stroke ring and unselected rows dim while a
2689
+ * selection is active.
2690
+ */
2691
+ selection?: boolean | SelectionConfig;
2692
+ /**
2693
+ * Drag-to-rect brush. Off by default — like click-selection, brush semantics
2694
+ * are app-specific. Pass `true` to enable defaults (xy rect, dismiss on
2695
+ * background tap) or an object to tune. The active brushed rows are exposed
2696
+ * on `MountedPlot.brushed`. Brush populates a separate signal from
2697
+ * click-selection so the two coexist with different semantics (range query
2698
+ * vs. discrete pick).
2699
+ */
2700
+ brush?: boolean | BrushConfig;
2701
+ /**
2702
+ * Legend interactivity. Default: enabled when `interactions` is on.
2703
+ * Enables click-to-toggle visibility of categorical series.
2704
+ */
2705
+ legend?: boolean | LegendInteractionConfig;
2706
+ /**
2707
+ * Context-menu trigger. Off by default — requires an `onTrigger` handler so
2708
+ * the host app can render its own menu UI. Fires for right-click, touch
2709
+ * long-press (≥500ms), and the keyboard ContextMenu / Shift+F10 keys. The
2710
+ * library only emits the event; menu rendering / positioning stays the
2711
+ * consumer's responsibility.
2712
+ */
2713
+ contextMenu?: ContextMenuConfig;
2714
+ }
2715
+ interface ContextMenuConfig {
2716
+ /**
2717
+ * Resolution policy for the trigger point. Default `"nearest-point"`.
2718
+ *
2719
+ * - `"nearest-point"`: snap to the nearest mark within its `pickRadius`
2720
+ * (skips region-based geoms like bars). When no mark is within range, the
2721
+ * trigger is **suppressed entirely** — matches the behavior of the hover
2722
+ * tooltip / crosshair (no popup unless something would be highlighted).
2723
+ * - `"any-mark"`: include region-based geoms (bars, histograms, tiles).
2724
+ * Same suppression behavior as `"nearest-point"` when no mark is hit.
2725
+ * - `"background"`: never resolve — `hit`/`datum`/`mark` are always null,
2726
+ * and the trigger always fires. Useful for "add a point here" menus.
2727
+ */
2728
+ hitMode?: "nearest-point" | "any-mark" | "background";
2729
+ /** Touch long-press hold duration (ms). Default `500`. */
2730
+ holdMs?: number;
2731
+ /** Max pointer movement during long-press hold (CSS px). Default `5`. */
2732
+ slopPx?: number;
2733
+ /**
2734
+ * Menu items. Static array or a per-trigger resolver. When provided, the
2735
+ * library renders a GPU-drawn menu inside the canvas (no DOM, no host
2736
+ * popover required) and routes clicks through `onAction`. When omitted the
2737
+ * library only emits `onTrigger` and rendering is the consumer's problem.
2738
+ */
2739
+ items?: readonly ContextMenuItem[] | ((info: ContextMenuTriggerPayload) => readonly ContextMenuItem[]);
2740
+ /** Called when an item in the rendered menu is clicked. */
2741
+ onAction?(itemId: string, info: ContextMenuTriggerPayload): void;
2742
+ /** Placement of the rendered menu relative to the trigger point. */
2743
+ placement?: _$insomni.MenuPlacement;
2744
+ /** Style overrides for the rendered menu. */
2745
+ style?: _$insomni.MenuStyle;
2746
+ /**
2747
+ * Low-level trigger callback. Fires even when `items` is set, so consumers
2748
+ * can hook telemetry / aria-live announcements alongside the rendered menu.
2749
+ * Required only when `items` is omitted (otherwise the library has no idea
2750
+ * what menu to show).
2751
+ */
2752
+ onTrigger?(info: ContextMenuTriggerPayload): void;
2753
+ }
2754
+ interface ContextMenuItem {
2755
+ /** Stable id passed to `onAction`. Ignored for separators. */
2756
+ id: string;
2757
+ /** Display label. Ignored for separators. */
2758
+ label: string;
2759
+ /** Renders as a thin separator line; non-interactive. */
2760
+ separator?: boolean;
2761
+ /** Greyed out; ignored by hover/click. */
2762
+ disabled?: boolean;
2763
+ /** Tinted with the menu's `dangerColor` (destructive actions). */
2764
+ danger?: boolean;
2765
+ /** Optional swatch dot at the start of the row. */
2766
+ swatch?: Color;
2767
+ /** Optional right-aligned shortcut hint (e.g. "⌘D"). */
2768
+ kbd?: string;
2769
+ }
2770
+ interface ContextMenuTriggerPayload {
2771
+ /**
2772
+ * Resolved hit at the trigger point, or `null` for a background trigger /
2773
+ * `hitMode: "background"`.
2774
+ */
2775
+ hit: HoveredHit | null;
2776
+ /** Convenience: the data row at `hit.dataIndex`, or `null` for background. */
2777
+ datum: unknown | null;
2778
+ /** Convenience: the geom kind that produced the hit. */
2779
+ mark: HoveredHit["geomKind"] | null;
2780
+ /** Element-local CSS px where the menu should anchor. */
2781
+ screenX: number;
2782
+ screenY: number;
2783
+ source: "mouse" | "touch" | "pen" | "keyboard";
2784
+ mods: _$insomni.Mods;
2785
+ originalEvent: Event | null;
2786
+ }
2787
+ interface LegendInteractionConfig {
2788
+ /** Default `0.2` — alpha for hidden series labels/swatches. */
2789
+ dimAlpha?: number;
2790
+ }
2791
+ /**
2792
+ * Semantic accents for `TooltipShorthandRow.accent`. `positive` / `negative`
2793
+ * resolve through `theme.interactions.tooltipAccents`. `neutral` is a
2794
+ * no-op marker — the row uses the default text color. Passing a raw `Color`
2795
+ * bypasses theme tokens entirely.
2796
+ */
2797
+ type TooltipAccent = "positive" | "negative" | "neutral" | Color;
2798
+ interface TooltipShorthandRow {
2799
+ label?: string;
2800
+ /**
2801
+ * Row value. Numbers / Dates / null / undefined are formatted through the
2802
+ * library's default formatter; strings are emitted verbatim.
2803
+ */
2804
+ value: string | number | Date | boolean | null | undefined;
2805
+ /** Optional swatch dot to the left of the row. */
2806
+ swatch?: Color;
2807
+ /**
2808
+ * Semantic accent applied to the row's text color (positive/negative tint
2809
+ * for diffs, deltas, status changes). `neutral` is a no-op.
2810
+ */
2811
+ accent?: TooltipAccent;
2812
+ }
2813
+ /**
2814
+ * Shorthand object form of `TooltipContent`. The grammar normalizes this into
2815
+ * the canvas-tooltip's full `TooltipContent` shape, applying default
2816
+ * formatting to non-string values and resolving accents through the theme.
2817
+ */
2818
+ interface TooltipContentShorthand {
2819
+ title?: string;
2820
+ rows: readonly TooltipShorthandRow[];
2821
+ }
2822
+ interface TooltipContentInfo<T = unknown> {
2823
+ /** The hovered datum (the row from the geom's data array). */
2824
+ datum: T;
2825
+ /** Index into the data array. */
2826
+ dataIndex: number;
2827
+ /** Geom kind (e.g. `"point"`, `"bar"`, `"line"`). */
2828
+ mark: string;
2829
+ /** Series key when the geom emits multiple segments per row (stacks, dodges). */
2830
+ seriesKey?: string;
2831
+ /**
2832
+ * Resolved aesthetic accessors for the geom. Useful for advanced resolvers
2833
+ * that need to read a channel's raw value or column name — most consumers
2834
+ * can ignore this and just read fields off `datum`.
2835
+ */
2836
+ channels: Readonly<Record<string, unknown>>;
2837
+ }
2838
+ /**
2839
+ * Override the auto-built tooltip content. Receives the hovered datum and
2840
+ * returns either the canvas-tooltip's full `TooltipContent` (with
2841
+ * `swatch`/`color`/`fontSize` per row), the shorthand `{ title, rows }` form
2842
+ * with optional `accent` tokens, or a plain string (single-row body), or
2843
+ * `null` to fall back to the default channel-driven content.
2844
+ */
2845
+ type TooltipContentResolver<T = unknown> = (info: TooltipContentInfo<T>) => TooltipContentResult | null | undefined;
2846
+ type TooltipContentResult = TooltipContentShorthand | string;
2847
+ /** One auto-built series row in axis-mode tooltips (mirrors SeriesReadoutRow). */
2848
+ interface AxisTooltipRow {
2849
+ /** Series label (color-channel value, seriesKey, or layer label). */
2850
+ label: string;
2851
+ /** Formatted value at the snapped column. */
2852
+ value: string;
2853
+ /** Raw value at the snapped column (pre-format) for custom transforms. */
2854
+ rawValue: unknown;
2855
+ /** Series swatch color, when resolvable. */
2856
+ color?: Color;
2857
+ /** True for the row whose snapped position is closest to the cursor. */
2858
+ active: boolean;
2859
+ /** seriesKey when the row came from a stacked / dodged segment. */
2860
+ seriesKey?: string;
2861
+ }
2862
+ /** Info handed to the axis-mode tooltip content hook. */
2863
+ interface AxisTooltipInfo {
2864
+ /** Raw snapped column value (the X for `axis:"x"`, the Y for `axis:"y"`). */
2865
+ columnValue: unknown;
2866
+ /** Formatted column value (`axisTitleFormat` / `defaultFormat`). */
2867
+ columnLabel: string;
2868
+ /** Which screen axis we snapped on. */
2869
+ axis: "x" | "y";
2870
+ /** Auto-built series rows (one per series at the snapped column). */
2871
+ rows: readonly AxisTooltipRow[];
2872
+ /**
2873
+ * The snapped datum(s) — one entry per hit-testable layer that produced a
2874
+ * group at this column, in layer order. Each carries the source datum, its
2875
+ * data index, and the layer's mark label, so a consumer can read any field
2876
+ * off a wide row (incl. fields belonging to ribbon/band/text layers that
2877
+ * have no hit tests of their own). For wide rows, `data[0].datum` already
2878
+ * holds every column.
2879
+ */
2880
+ data: readonly {
2881
+ datum: unknown;
2882
+ dataIndex: number;
2883
+ mark: string;
2884
+ }[];
2885
+ }
2886
+ /**
2887
+ * Axis-mode tooltip content hook. Return a `{ title?, rows }` shorthand (the
2888
+ * same shape the item resolver returns) to REPLACE the auto rows, or
2889
+ * `null` / `undefined` to keep them verbatim. `accent` / `swatch` per row
2890
+ * resolve through the theme exactly like the item path.
2891
+ */
2892
+ type AxisTooltipContentResolver = (info: AxisTooltipInfo) => TooltipContentShorthand | null | undefined;
2893
+ interface TooltipConfig {
2894
+ showDelay?: number;
2895
+ hideDelay?: number;
2896
+ fadeMs?: number;
2897
+ placement?: "top" | "bottom" | "left" | "right" | "auto";
2898
+ /**
2899
+ * Override the default channel-driven tooltip body. Receives the hovered
2900
+ * datum and returns either:
2901
+ * - a plain string (single-row body, no label)
2902
+ * - a `{ title?, rows: [{label?, value, accent?, swatch?}] }` shorthand —
2903
+ * `accent: "positive" | "negative" | "neutral" | Color` tints the row
2904
+ * text via `theme.interactions.tooltipAccents`
2905
+ * - `null` / `undefined` to fall back to the auto-built content
2906
+ *
2907
+ * The library renders the canvas tooltip primitive — there's no HTML/CSS
2908
+ * surface to style; row colors come from the theme.
2909
+ *
2910
+ * Ignored in `trigger:"axis"` mode (use `axisContent`).
2911
+ */
2912
+ content?: TooltipContentResolver;
2913
+ /**
2914
+ * Tooltip trigger model. Default `"item"` (today's behavior — one box per
2915
+ * hovered mark, fully backward compatible). `"axis"` turns the tooltip into
2916
+ * a floating, cursor-following unified readout: it snaps to the nearest data
2917
+ * column across ALL hit-testable layers and lists one row per series in a
2918
+ * single box.
2919
+ */
2920
+ trigger?: "item" | "axis";
2921
+ /**
2922
+ * Which screen axis to snap on in `trigger:"axis"` mode. `"x"` (default) =
2923
+ * nearest-X (vertical time-series — pick the column under the cursor's x).
2924
+ * `"y"` = nearest-Y (horizontal charts — pick the row under the cursor's y).
2925
+ * Ignored when `trigger:"item"`.
2926
+ */
2927
+ axis?: "x" | "y";
2928
+ /**
2929
+ * Axis-mode content hook. Receives the snapped column plus the auto-built
2930
+ * series rows AND the snapped datum(s), so a consumer can append rows that
2931
+ * are NOT y-series (a wind-direction arrow, a day/night flag, a UV risk
2932
+ * band) or transform the auto rows. Return value REPLACES the auto rows when
2933
+ * non-null; return null/undefined to keep the auto-built rows verbatim.
2934
+ * Ignored unless `trigger:"axis"`.
2935
+ */
2936
+ axisContent?: AxisTooltipContentResolver;
2937
+ /** Format the snapped column value used as the tooltip title in axis mode. */
2938
+ axisTitleFormat?: (value: unknown) => string;
2939
+ /** Format each auto-built series row's value in axis mode. */
2940
+ axisValueFormat?: (value: unknown) => string;
2941
+ }
2942
+ interface CrosshairConfig {
2943
+ /** Which guide line(s) to draw. Default `"x"` (vertical line tracking cursor). */
2944
+ axis?: "x" | "y" | "xy";
2945
+ /** Stroke color. Default theme.colors.muted at 0.6 alpha. */
2946
+ color?: Color;
2947
+ /** Stroke width in CSS px. Default 1. */
2948
+ width?: number;
2949
+ /**
2950
+ * Track the raw pointer position even between data points (no snap). Useful
2951
+ * for sparse line/area charts where the snapped-to-hit default leaves big
2952
+ * gaps. Snapping still wins when the cursor is over a hit; outside hits the
2953
+ * crosshair follows the cursor within the plot frame. Default `false`.
2954
+ */
2955
+ followPointer?: boolean;
2956
+ }
2957
+ interface BrushConfig {
2958
+ /** Which axes the brush spans. Default `"xy"`. */
2959
+ axis?: "x" | "y" | "xy";
2960
+ /** Translucent fill. Default theme axis color × 0.12 alpha. */
2961
+ fillColor?: Color;
2962
+ /** Outline color. Default theme axis color × 0.6 alpha. */
2963
+ strokeColor?: Color;
2964
+ /** Outline width in CSS px. Default 1. */
2965
+ strokeWidth?: number;
2966
+ /** Enable edge/corner resize handles. Default `true`. */
2967
+ handles?: boolean;
2968
+ /** Enable drag-the-rect-interior translate. Default `true`. */
2969
+ translate?: boolean;
2970
+ /**
2971
+ * Snap brush rect edges to nearest hit-test position. `true` snaps on the
2972
+ * brush's `axis`; pass `"x"` / `"y"` / `"xy"` to override. Default `false`.
2973
+ */
2974
+ snap?: boolean | "x" | "y" | "xy";
2975
+ }
2976
+ /**
2977
+ * Read-only view of a `Signal<HoveredHit[]>` exposed on `MountedPlot.brushed`.
2978
+ * Empty array when nothing is brushed; remains an empty array (never `null`)
2979
+ * when brush is disabled. Independent of `selected` — click + brush coexist
2980
+ * with different semantics.
2981
+ */
2982
+ interface BrushedSignal {
2983
+ get(): readonly HoveredHit[];
2984
+ peek(): readonly HoveredHit[];
2985
+ subscribe(fn: (v: readonly HoveredHit[]) => void): () => void;
2986
+ /** Imperatively clear the active brush. */
2987
+ clear(): void;
2988
+ }
2989
+ interface SelectionConfig {
2990
+ /**
2991
+ * Alpha applied to non-selected marks while a selection is active. Default
2992
+ * `0.3`. Set `1` to disable dimming (selected rows still get a stroke ring).
2993
+ */
2994
+ dimAlpha?: number;
2995
+ /** Stroke ring color override; defaults to theme.axis.color. */
2996
+ ringColor?: Color;
2997
+ /** Stroke ring width in CSS px. Default 2. */
2998
+ ringWidth?: number;
2999
+ }
3000
+ /**
3001
+ * Read-only view of a `Signal<HoveredHit[]>` exposed on `MountedPlot`. The
3002
+ * array is empty when nothing is selected; `null` is never produced (use
3003
+ * `length === 0` to detect the empty case).
3004
+ */
3005
+ interface SelectedSignal {
3006
+ get(): readonly HoveredHit[];
3007
+ peek(): readonly HoveredHit[];
3008
+ subscribe(fn: (v: readonly HoveredHit[]) => void): () => void;
3009
+ /** Imperatively clear the active selection. */
3010
+ clear(): void;
3011
+ }
3012
+ /**
3013
+ * Read-only view of a `Signal<ReadonlySet<string>>` exposed on `MountedPlot.hidden`.
3014
+ * Empty set when all series are visible.
3015
+ */
3016
+ interface HiddenSignal {
3017
+ get(): ReadonlySet<string>;
3018
+ peek(): ReadonlySet<string>;
3019
+ subscribe(fn: (v: ReadonlySet<string>) => void): () => void;
3020
+ /** Clear the hidden set (show all). */
3021
+ clear(): void;
3022
+ }
3023
+ /**
3024
+ * Read-only view of a `Signal<HoveredHit | null>` exposed on `MountedPlot`.
3025
+ * Drops `set`/`update` so callers can subscribe + peek without writing.
3026
+ */
3027
+ interface HoveredSignal {
3028
+ get(): HoveredHit | null;
3029
+ peek(): HoveredHit | null;
3030
+ subscribe(fn: (v: HoveredHit | null) => void): () => void;
3031
+ }
3032
+ interface MountedPlot<T> {
3033
+ /** Schedule a redraw on the next animation frame. */
3034
+ invalidate(): void;
3035
+ /**
3036
+ * Replace the active chart spec or builder.
3037
+ * - Pass a `Chart<T>` to swap to a static spec.
3038
+ * - Pass `() => Chart<T>` to swap the rebuild closure.
3039
+ * - Pass nothing to force a rebuild via the existing builder.
3040
+ *
3041
+ * When `autoFrame: false`, also draws synchronously.
3042
+ */
3043
+ update(source?: Chart<T> | (() => Chart<T>)): void;
3044
+ /** Replace the data array (drops any reactive data signal subscription). */
3045
+ setData(data: readonly T[]): void;
3046
+ /**
3047
+ * Manual resize. If `autoResize` is on you usually don't need this.
3048
+ * Pass no args to re-read the canvas's current bounding rect.
3049
+ */
3050
+ resize(w?: number, h?: number): void;
3051
+ /** Override the background color. Pass `null` to revert to the chart/theme default. */
3052
+ setBackground(color: Color | null): void;
3053
+ /** Static SVG export from the current spec + data. */
3054
+ toSVG(opts?: {
3055
+ width?: number;
3056
+ height?: number;
3057
+ atlas?: GlyphAtlas;
3058
+ }): SVGSVGElement;
3059
+ /** Tear down: cancels the rAF loop, ResizeObserver, signal subs; destroys what we created. */
3060
+ destroy(): void;
3061
+ readonly renderer: Renderer2D;
3062
+ readonly axisLayer: Layer;
3063
+ readonly marksLayer: Layer;
3064
+ readonly hudLayer: Layer;
3065
+ /** Cursor-overlay layer (tooltip / crosshair / brush / menu), above the hud. */
3066
+ readonly overlayLayer: Layer;
3067
+ readonly invalidator: Invalidator;
3068
+ /**
3069
+ * Read-only signal carrying the currently hovered hit (geom kind, dataIndex,
3070
+ * data array reference, snapped position) or `null` when nothing is
3071
+ * hovered. Updated synchronously from pointer events. Geoms also receive
3072
+ * the same value via `CompileContext.hovered` during compile.
3073
+ */
3074
+ readonly hovered: HoveredSignal;
3075
+ /**
3076
+ * Read-only signal carrying the currently selected rows (one `HoveredHit`
3077
+ * per selected datum). Empty array when nothing is selected; remains an
3078
+ * empty array (never `null`) when selection is disabled. Geoms receive
3079
+ * the same payload via `CompileContext.selected` during compile.
3080
+ */
3081
+ readonly selected: SelectedSignal;
3082
+ /**
3083
+ * Read-only signal carrying the rows currently inside the brush rect.
3084
+ * Empty array when nothing is brushed (or when brush is disabled).
3085
+ * Independent of `selected`.
3086
+ */
3087
+ readonly brushed: BrushedSignal;
3088
+ /**
3089
+ * Read-only signal carrying the set of series keys currently hidden via
3090
+ * legend toggle. Empty set when all series are visible; remains an empty
3091
+ * set (never `null`) when legend interaction is disabled.
3092
+ */
3093
+ readonly hidden: HiddenSignal;
3094
+ /**
3095
+ * Handle for programmatic transition control. Always present even when
3096
+ * transitions are disabled (calls become no-ops in that case).
3097
+ */
3098
+ readonly transitions: TransitionsHandle;
3099
+ /** CSS-pixel width currently rendered. */
3100
+ readonly width: number;
3101
+ /** CSS-pixel height currently rendered. */
3102
+ readonly height: number;
3103
+ /** Active device-pixel ratio. */
3104
+ readonly dpr: number;
3105
+ /** Combined shape count across the three internal layers. */
3106
+ readonly shapeCount: number;
3107
+ /** Combined triangle count across the three internal layers. */
3108
+ readonly triangleCount: number;
3109
+ /** True when `invalidate()` has been called and a draw hasn't happened yet. */
3110
+ readonly needsFrame: boolean;
3111
+ /**
3112
+ * Inner plot panel rect (absolute element-CSS px) — the area enclosed by
3113
+ * the axes, where geom marks draw. Updated each frame from the pipeline.
3114
+ * For faceted charts this is the union of all panel frames. Returns a
3115
+ * zero-rect before the first draw.
3116
+ */
3117
+ readonly plotFrame: Frame;
3118
+ /**
3119
+ * The chart's pan/zoom viewport, present only when `panZoom` was enabled
3120
+ * on mount. Lets the caller subscribe to view changes, read the visible
3121
+ * domain (e.g. for re-binning data), or call `.reset()`. The mount keeps
3122
+ * its frame in sync with `plotFrame` automatically.
3123
+ */
3124
+ readonly viewport: DataViewport<number, number> | null;
3125
+ /**
3126
+ * Wire a `createRangePresets` controller against this chart's viewport and
3127
+ * optionally render a chip strip into a host element. Throws if `panZoom`
3128
+ * was not enabled at mount time (no `viewport` to drive).
3129
+ *
3130
+ * The headless flow is preserved — omit `opts.ui` and you get the same
3131
+ * controller (`setActive` / `getActive` / `subscribe`) without any DOM
3132
+ * construction. Strings in `presets` are expanded to `timePreset(key)`.
3133
+ */
3134
+ attachRangePresets(opts: AttachRangePresetsOptions): AttachedRangePresets;
3135
+ /**
3136
+ * Attach a dygraph-style pinned legend — a side panel that updates with each
3137
+ * series' value at the cursor's snapped x. Reuses the chart's compiled
3138
+ * hit-tests (no separate spatial index) so the snap stays aligned with what
3139
+ * the tooltip would have shown.
3140
+ *
3141
+ * Headless: omit `opts.ui` and observe via `subscribe()` to render your own
3142
+ * UI. With `opts.ui` set, a minimal absolute-positioned panel is appended
3143
+ * into the mount element and disposed alongside this readout.
3144
+ */
3145
+ attachSeriesReadout(opts: AttachSeriesReadoutOptions): AttachedSeriesReadout;
3146
+ /**
3147
+ * Wire a drag-to-rect brush onto the chart imperatively. Mirrors the
3148
+ * declarative `interactions: { brush: ... }` config path — the same
3149
+ * `MountedPlot.brushed` signal observes the brushed set — but lets a
3150
+ * consumer attach (and later dispose) a brush after mount without
3151
+ * rebuilding the chart spec.
3152
+ *
3153
+ * Throws if a brush is already configured on this mount, either via
3154
+ * `interactions.brush` or a prior `attachBrush` call that hasn't been
3155
+ * disposed. The two surfaces are mutually exclusive: the brush rect is a
3156
+ * singleton.
3157
+ */
3158
+ attachBrush(opts: AttachBrushOptions): AttachedBrush;
3159
+ /**
3160
+ * Convert an event-relative canvas coordinate (e.g. `event.offsetX/Y`, or
3161
+ * `clientX - rect.left`) into the chart's data space, routing through the
3162
+ * active coord's `unproject` (identity for Cartesian, polar inverse for
3163
+ * `coordPolar` / `coordRadial`).
3164
+ *
3165
+ * Returns `null` when:
3166
+ * - the point falls outside the active plot frame, or
3167
+ * - `coord.unproject` returns null (e.g. polar point outside the radius
3168
+ * band), or
3169
+ * - the pipeline has not produced scales yet (no draw has happened), or
3170
+ * - either position scale lacks an `invert` (band scales).
3171
+ *
3172
+ * `dataX` / `dataY` are the result of `xScale.axisScale.invert(plotFrameX)`
3173
+ * and `yScale.axisScale.invert(plotFrameY)` respectively. `plotFrameX/Y` are
3174
+ * relative to the plot frame's top-left.
3175
+ *
3176
+ * This is the screen → data primitive consumers use to drive picking on top
3177
+ * of their own spatial index. The mount doesn't know what's in the chart —
3178
+ * downstream layers (phylo's `hitTestPhylo`, custom geoms, etc.) take it
3179
+ * from here.
3180
+ */
3181
+ pickAt(canvasX: number, canvasY: number): {
3182
+ plotFrameX: number;
3183
+ plotFrameY: number;
3184
+ dataX: number;
3185
+ dataY: number;
3186
+ frame: Frame;
3187
+ } | null;
3188
+ }
3189
+ /** @deprecated kept for back-compat; use `MountedPlot<T>`. */
3190
+ type MountedChart<T = Row> = MountedPlot<T>;
3191
+ interface RenderTarget {
3192
+ axisLayer: Layer;
3193
+ marksLayer: Layer;
3194
+ hudLayer: Layer;
3195
+ width?: number;
3196
+ height?: number;
3197
+ }
3198
+ interface Chart<T> {
3199
+ layer(geom: Geom<T>): Chart<T>;
3200
+ layers(geoms: readonly Geom<T>[]): Chart<T>;
3201
+ /**
3202
+ * Configure a scale. `domain` is always optional — when omitted it is
3203
+ * inferred from the data, and when `panZoom` is enabled on `.mount()` the
3204
+ * pipeline overrides the x/y position-scale domain each frame from the
3205
+ * viewport's visible window. Consumers should NOT re-thread the viewport's
3206
+ * visible domain back through `.scale()` from a `build:` closure; it's
3207
+ * redundant and forces a rebuild on every dirty draw.
3208
+ */
3209
+ scale<C extends Channel>(channel: C, options: ScaleOptionsByChannel<C>): Chart<T>;
3210
+ axes(spec: AxesSpec): Chart<T>;
3211
+ title(spec: TitleSpec | string): Chart<T>;
3212
+ legend(spec: LegendSpec | false): Chart<T>;
3213
+ /** Add a free-form text/box annotation. Multiple calls accumulate. */
3214
+ annotate(spec: AnnotationSpec): Chart<T>;
3215
+ /** Split data into a grid of panels by `spec.by`. Replaces any prior facet. */
3216
+ facet(spec: FacetSpec<T>): Chart<T>;
3217
+ /**
3218
+ * Set the coordinate system. Defaults to `coordCartesian()`. Polar / radial
3219
+ * coords land in Phase 3 of the phylo-on-plot rewrite.
3220
+ */
3221
+ coord(coord: Coord): Chart<T>;
3222
+ theme(theme: Theme): Chart<T>;
3223
+ /**
3224
+ * Bind this chart to a canvas. The mount owns the renderer, atlas, three
3225
+ * layers, rAF loop, ResizeObserver and visibility-pause unless you pass
3226
+ * your own pieces in `opts`. See `MountPlotOptions` for every escape hatch.
3227
+ */
3228
+ mount(canvas: HTMLCanvasElement, opts?: MountPlotOptions<T>): MountedPlot<T>;
3229
+ /**
3230
+ * Compile + emit into externally owned layers. Use when the host already
3231
+ * owns a `Renderer2D` (and wants its own per-frame timing). For simpler
3232
+ * cases, prefer `mount(canvas)`.
3233
+ */
3234
+ render(target: RenderTarget): void;
3235
+ /** Static SVG export. Caller mounts the returned element where they want. */
3236
+ toSVG(options?: {
3237
+ width?: number;
3238
+ height?: number;
3239
+ atlas?: GlyphAtlas;
3240
+ }): SVGSVGElement;
3241
+ }
3242
+ declare function plot<T>(spec: PlotSpec<T>): Chart<T>;
3243
+ //#endregion
3244
+ //#region src/grammar/data/pivot.d.ts
3245
+ interface FromMatrixOptions {
3246
+ /** Y labels (rows). Top to bottom. Length must equal `values.length`. */
3247
+ rows: readonly string[];
3248
+ /** X labels (cols). Left to right. Length must equal `values[0].length`. */
3249
+ cols: readonly string[];
3250
+ /** Output key for the row label. Default `"row"`. */
3251
+ rowKey?: string;
3252
+ /** Output key for the col label. Default `"col"`. */
3253
+ colKey?: string;
3254
+ /** Output key for the cell value. Default `"value"`. */
3255
+ valueKey?: string;
3256
+ }
3257
+ /**
3258
+ * Convert a 2D `values[row][col]` matrix into long-format rows that the
3259
+ * `tile()` geom consumes directly. Cells with `NaN` / `null` / `undefined`
3260
+ * are kept (so consumers can opt into NA cell rendering); cells whose
3261
+ * coordinates are out of range are skipped.
3262
+ *
3263
+ * Example:
3264
+ * ```ts
3265
+ * const long = fromMatrix(temperatures, {
3266
+ * rows: ["00:00", "06:00", "12:00", "18:00"],
3267
+ * cols: ["Mon", "Tue", "Wed", "Thu", "Fri"],
3268
+ * });
3269
+ * tile({ x: "col", y: "row", fill: "value" })
3270
+ * ```
3271
+ */
3272
+ declare function fromMatrix(values: readonly (readonly number[])[], opts: FromMatrixOptions): {
3273
+ row: string;
3274
+ col: string;
3275
+ value: number;
3276
+ }[];
3277
+ interface PivotLongerOptions<T> {
3278
+ /** Output column name for the original key. Default `"name"`. */
3279
+ nameKey?: string;
3280
+ /** Output column name for the value. Default `"value"`. */
3281
+ valueKey?: string;
3282
+ /** Optional id columns kept verbatim alongside the long pair. */
3283
+ idColumns?: readonly (keyof T & string)[];
3284
+ }
3285
+ /**
3286
+ * Pivot a wide row to a sequence of long rows — one per `keys` entry.
3287
+ * `idColumns` are copied through to every output row so a per-row identifier
3288
+ * (e.g. car name in the mtcars example) is preserved.
3289
+ *
3290
+ * Example:
3291
+ * ```ts
3292
+ * const long = pivotLonger(mtcars, ["mpg", "cyl", "disp", "hp"], {
3293
+ * idColumns: ["model"],
3294
+ * });
3295
+ * // → [{ model, name: "mpg", value }, { model, name: "cyl", value }, ...]
3296
+ * ```
3297
+ */
3298
+ declare function pivotLonger<T extends Record<string, unknown>>(rows: readonly T[], keys: readonly (keyof T & string)[], options?: PivotLongerOptions<T>): Record<string, unknown>[];
3299
+ //#endregion
3300
+ //#region src/grammar/palettes.d.ts
3301
+ /** Built-in categorical palette identifiers supported by `distinguishable`. */
3302
+ type DistinguishableScheme = "category10" | "tableau10" | "set1" | "set2" | "set3" | "dark2" | "paired" | "pastel";
3303
+ interface DistinguishableOptions {
3304
+ /** Per-channel cardinality. Each count must be ≥ 1. */
3305
+ for: {
3306
+ color: number;
3307
+ shape: number;
3308
+ };
3309
+ /**
3310
+ * Categorical palette to source the color palette from. Default
3311
+ * `"category10"`. Pass a `CategoricalPalette` directly for a custom set.
3312
+ */
3313
+ scheme?: DistinguishableScheme | CategoricalPalette;
3314
+ /**
3315
+ * Override the shape pool. Default: `POINT_SHAPE_PALETTE` from `marks`,
3316
+ * which is already ordered for silhouette distinctness.
3317
+ */
3318
+ shapes?: readonly PointShapeKind[];
3319
+ }
3320
+ interface DistinguishablePalettes {
3321
+ /**
3322
+ * A categorical palette sliced to exactly `for.color` colors from the
3323
+ * requested scheme. Plug into `scale("color", { palette })`.
3324
+ */
3325
+ color: CategoricalPalette;
3326
+ /**
3327
+ * Shape palette sliced to exactly `for.shape` entries. Plug into
3328
+ * `scale("shape", { palette })`.
3329
+ */
3330
+ shape: readonly PointShapeKind[];
3331
+ }
3332
+ /**
3333
+ * Build a matched `{ color, shape }` pair sized for the two channels'
3334
+ * cardinalities. Sugar over manual `palette.colors.slice(0, N)` +
3335
+ * `POINT_SHAPE_PALETTE.slice(0, M)` — the goal is one declaration site for
3336
+ * the visual contract of a multi-encoding chart.
3337
+ *
3338
+ * Counts that exceed the source pool wrap modulo length, matching the
3339
+ * default `CategoricalPalette` / scale wrap semantics so the helper never
3340
+ * silently drops categories. (The visual distinction degrades past the pool
3341
+ * size — that's an authoring problem, not a library one — but the runtime
3342
+ * stays consistent with the rest of the scale system.)
3343
+ */
3344
+ declare function distinguishable(options: DistinguishableOptions): DistinguishablePalettes;
3345
+ /**
3346
+ * `palettes` namespace — currently the home of `distinguishable`. Future
3347
+ * combinators (legend-paired schemes, perceptual-uniform slicing, …) live
3348
+ * here so the surface stays small and predictable.
3349
+ */
3350
+ declare const palettes: {
3351
+ readonly distinguishable: typeof distinguishable;
3352
+ };
3353
+ //#endregion
3354
+ //#region src/grammar/profiling.d.ts
3355
+ interface RecorderHook {
3356
+ recordCpu(name: string, durationMs: number): void;
3357
+ recordGpu(name: string, startNs: number, endNs: number): void;
3358
+ }
3359
+ /** Inject a recorder (e.g. devtools' `recordCpu`/`recordGpu`). Pass `null` to reset to no-op. */
3360
+ declare function setRecorderHook(rec: RecorderHook | null): void;
3361
+ //#endregion
3362
+ //#region src/grammar/phylo.d.ts
3363
+ /**
3364
+ * Subset of `@phylon/renderer`'s `TipAxis` consumed by the bridge. Any object
3365
+ * with this shape (typically the `tipAxis` field on a `RectLayout`) works.
3366
+ */
3367
+ interface TipAxisLike {
3368
+ /** Number of tips. */
3369
+ count: number;
3370
+ /** Tip node ids in display order (top→bottom for rectilinear). */
3371
+ order: ArrayLike<number>;
3372
+ /** Tip node id → label, or `null` if the tip is unnamed. */
3373
+ name(tipId: number): string | null;
3374
+ }
3375
+ interface TipScaleOptions {
3376
+ /**
3377
+ * Band padding in [0, 1). Default `0` — heatmaps and tile-style geoms want
3378
+ * tight rows. Bump to e.g. `0.1` for visible gaps between bars.
3379
+ */
3380
+ padding?: number;
3381
+ /**
3382
+ * Replacement label for unnamed tips. Receives the tip's node id and its
3383
+ * row index. Default: `(id) => "tip_" + id`.
3384
+ */
3385
+ unnamed?: (tipId: number, row: number) => string;
3386
+ }
3387
+ /**
3388
+ * Build a y-channel `PositionScaleOptions` from a phylo `TipAxis`. The
3389
+ * resulting scale is a band scale whose domain is the tip names in tree
3390
+ * display order (top→bottom). Geoms whose `y` aesthetic resolves to a tip
3391
+ * name will land on the matching tree row.
3392
+ *
3393
+ * Tip labels in the data must match `axis.name(tipId)`. Use `joinByTip`
3394
+ * (phylo) to align metadata rows to tip names ahead of time.
3395
+ */
3396
+ declare function tipScale(axis: TipAxisLike, opts?: TipScaleOptions): BandPositionScaleOptions;
3397
+ /**
3398
+ * Structural shape of a phylo `CladeStrip` — neutral data describing a clade
3399
+ * range plus a label. Mirrors `@phylon/renderer`'s exported `CladeStrip` so the
3400
+ * plot package doesn't have to depend on phylo to consume them.
3401
+ */
3402
+ interface CladeStripLike {
3403
+ label: string;
3404
+ tipCenter: string;
3405
+ color?: Color;
3406
+ offsetX?: number;
3407
+ }
3408
+ interface CladeStripAnnotationOptions {
3409
+ /**
3410
+ * Pixel offset added to every strip's annotation. Default `8` — pushes the
3411
+ * label clear of the chart's right edge / tip labels. Per-strip
3412
+ * `offsetX` is added on top of this.
3413
+ */
3414
+ offsetX?: number;
3415
+ fontSize?: number;
3416
+ fontStyle?: string;
3417
+ }
3418
+ /**
3419
+ * Convert phylo `CladeStrip[]` into plot `AnnotationSpec[]`. Labels anchor at
3420
+ * the chart's right frame edge, vertically aligned to the clade's y-center
3421
+ * (resolved by the y-channel's `tipScale`). v1 emits text-only annotations;
3422
+ * brackets are a follow-up that needs a non-text annotation kind.
3423
+ */
3424
+ declare function cladeStripsToAnnotations(strips: readonly CladeStripLike[], opts?: CladeStripAnnotationOptions): TextAnnotationSpec[];
3425
+ //#endregion
3426
+ export { type Accessibility, type AccessibilityMode, type Accessor, type Aes, type AggregateBinBy, type AggregateBinSize, type AggregateBinView, type AggregateBundleResult, type AggregateBundleSummary, type AggregateBundleSummaryKind, type AggregateChannels, type AggregateInnerGeom, type AggregateOptions, type AggregateSummary, type AggregateSummaryKind, type AlphaScaleOptions, type AnnotationSpec, type AnnotationX, type AnnotationY, type AreaChannels, type AreaOptions, type AreaPosition, type ArrowAnnotationSpec, type AttachBrushOptions, type AttachRangePresetsOptions, type AttachRangePresetsPosition, type AttachRangePresetsUi, type AttachSeriesReadoutOptions, type AttachedBrush, type AttachedBrushInternal, type AttachedRangePresets, type AttachedSeriesReadout, type AutoBinSizeInfo, type AxesSpec, type AxisSpec, type AxisTickFormatter, type AxisTooltipContentResolver, type AxisTooltipInfo, type AxisTooltipRow, type BandChannels, type BandOptions, type BarChannels, type BarOptions, type BarPosition, type BlendSpace, type BorderStyleScaleOptions, type BoxplotChannels, type BoxplotOptions, type CalloutAnnotationSpec, type Channel, type ChannelSpec, type Chart, type ChartPanBounds, type ChartPanBoundsOptions, type CladeStripAnnotationOptions, type CladeStripLike, type ColorOrAccent, type ColorScaleOptions, type ColorScaleType, type CompileContext, type CompiledHitTest, type ConnectedScatterChannels, type ConnectedScatterOptions, type ContrastMetric, type Coord, type CoordAxesArgs, type CoordPanArgs, type CoordPolarOptions, type CoordViewportHandle, type CoordZoomArgs, DEFAULT_ACCESSIBILITY, DEFAULT_BORDER_STYLE_PALETTE, DEFAULT_OVERLAY_GLYPH_PALETTE, type DistinguishableOptions, type DistinguishablePalettes, type DistinguishableScheme, type FacetScales, type FacetSpec, type FacetStripStyle, type FrameAnchorX, type FrameAnchorY, type FromMatrixOptions, type Geom, type GeomKind, type HistogramChannels, type HistogramMeasure, type HistogramOptions, type HistogramPosition, type HoveredHit, type IntervalChannels, type IntervalOptions, type LegendMergeChannel, type LegendSpec, type LineChannels, type LineOptions, type MountPlotOptions, type MountedChart, type MountedPlot, type OverlayGlyphScaleOptions, type PanZoomAxes, type PanZoomConfig, type PivotLongerOptions, type PlotSpec, type Point, type PointChannels, type PointOptions, type PointsMode, type PositionScaleOptions, type PositionScaleType, type RecorderHook, type RenderTarget, type ResolveTextColorOptions, type ResolvedChannelMap, type RibbonChannels, type RibbonOptions, type RidgelineChannels, type RidgelineFillMode, type RidgelineGeom, type RidgelineInner, type RidgelineOptions, type RidgelineScale, type Row, type RugChannels, type RugOptions, type RugSide, type RuleChannels, type RuleOptions, type ScaleBundle, type ScaleOptionsByChannel, type SeriesReadoutFormat, type SeriesReadoutPosition, type SeriesReadoutRow, type SeriesReadoutSnapshot, type SeriesReadoutUi, type ShapeScaleOptions, type SizeScaleOptions, type SmoothChannels, type SmoothLabelOptions, type SmoothMethod, type SmoothOptions, type StatRollingChannels, type StatRollingOptions, type TextAnnotationSpec, type TextChannels, type TextEffects, type TextOptions, type Theme, type ThemeAccentKey, type ThemeAccents, type ThemeAxis, type ThemeInteractions, type ThemeLegend, type ThemeMarks, type ThemePalettes, type ThemeSubtitle, type ThemeText, type ThemeTitle, type ThemeTooltipAccents, type TickIntervalSpec, type TickSpec, type TileChannels, type TileNAOptions, type TileOptions, type TimeIntervalUnit, type TipAxisLike, type TipScaleOptions, type TitleSpec, type ViolinChannels, type ViolinInner, type ViolinOptions, type ViolinScale, aggregate, annotate, area, attachRangePresets, band, bar, boxplot, cladeStripsToAnnotations, connectedScatter, coordCartesian, coordPolar, coordRadial, createAttachedBrush, distinguishable, fromMatrix, histogram, interval, line, palettes, pivotLonger, plot, point, resolveTextColor, ribbon, ridgeline, rug, rule, setRecorderHook, smooth, statRolling, text, theme, themeDefault, themeMinimalGrid, tile, tipScale, violin };