@graphysdk/viz-engine 0.0.1-alpha.6 → 0.0.1-experimental.1

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.
package/dist/index.d.ts CHANGED
@@ -1,49 +1,45 @@
1
+ /**
2
+ * `@graphysdk/viz-engine` — a grammar-of-graphics engine that compiles a declarative spec into a
3
+ * render-ready `CompiledSpec`. Framework-agnostic: no DOM, no React.
4
+ *
5
+ * Rebuilding a renderer — read these first, in order:
6
+ * 1. {@link Compiler} / {@link createCompiler} — the compile lifecycle and the apply→recompile loop.
7
+ * 2. {@link CompiledSpec} — the render-ready projection you paint (and the compile/render contract).
8
+ * 3. {@link LayoutCompiler} — pixel layout (panel/axes/header rects) plus final axis-tick selection.
9
+ * 4. {@link Command} — serializable spec mutations for interactive edits.
10
+ *
11
+ * The contract in one breath: position scales emit normalized `[0,1]` (x 0=left…1=right, y 0=bottom…1=top,
12
+ * so SVG renderers invert y as `1 - y`); visual scales emit final values (color strings, px sizes); the
13
+ * engine emits format *descriptors* ({@link ValueFormat}) the renderer turns into locale strings; the
14
+ * renderer owns pixel layout, theme, and formatting. Resolve layers and scales by id, never by index.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+
1
19
  import { Area } from 'd3-shape';
2
20
  import { CurveFactory } from 'd3-shape';
3
21
  import { internal } from 'arquero';
4
22
  import { Line } from 'd3-shape';
5
23
  import { Translator } from '@graphysdk/i18n';
6
24
 
7
- /** The exact-aes object a geom def's builder accepts every admitted key optional. */
8
- declare type AesFromDef<Def extends Geom<unknown>> = {
9
- [Key in AesKeysOf<Def>]?: AestheticValue;
10
- };
11
-
12
- /**
13
- * The aes key one position role contributes: a `point` role its axis; a `min`/`max`/`scalar` role its
14
- * declared `aes` — a plain `string`, so a custom positional aesthetic (`'open'`) is recovered too (a
15
- * role with no `aes` contributes nothing). Mirrors `deriveDeclaredAesthetics` at the type level.
16
- */
17
- declare type AesFromRole<Role extends PositionRole> = Role['role'] extends 'point' ? Role['axis'] : Role['role'] extends 'min' | 'max' | 'scalar' ? Role extends {
18
- aes: infer A extends string;
19
- } ? A : never : never;
20
-
21
- /**
22
- * Distributes {@link AesFromRole} over a geom's position-role union. {@link AesFromRole} keys on
23
- * `Role['role']` rather than a naked `Role`, so it does *not* distribute on its own — applied to the
24
- * union directly it collapses to `never`. The `Roles extends Roles` hop forces per-member evaluation.
25
- */
26
- declare type AesFromRoles<Roles extends PositionRole> = Roles extends Roles ? AesFromRole<Roles> : never;
27
-
28
- /**
29
- * The aes keys a geom def admits: its position keys ∪ its declared `aesthetics` keys. A widened
30
- * `positionRoles` relaxes the position half to {@link AestheticKey}, which absorbs the union — so
31
- * authoring still compiles with the exact-aes check dropped.
32
- */
33
- declare type AesKeysOf<Def extends Geom<unknown>> = PositionAesKeys<Def> | DeclaredAesKeys<Def>;
34
-
35
- /**
36
- * Maps each aesthetic to a variable or constant value. The built-in channels (x, y, color, …) keep
37
- * exact types and autocomplete; the index signature also admits a geom's **custom positional
38
- * aesthetics** — an OHLC candlestick's `open`/`high`/`low`/`close` — which the geom declares on its
39
- * position contract and the engine then trains and scales like a built-in channel.
40
- */
41
- export declare interface AesMapping extends KnownAesthetics {
42
- [aesthetic: string]: AestheticValue | undefined;
25
+ /** Maps each visual channel (x, y, color, size, ...) to a data column or constant value. */
26
+ export declare interface AesMapping {
27
+ x?: AestheticValue;
28
+ y?: AestheticValue;
29
+ label?: AestheticValue;
30
+ color?: AestheticValue;
31
+ size?: AestheticValue;
32
+ /** Opacity channel (0–1). */
33
+ alpha?: AestheticValue;
34
+ /** Splits marks into series (separate lines/areas) without assigning a visual encoding. */
35
+ group?: AestheticValue;
36
+ strokeWidth?: AestheticValue;
37
+ /** Dash-pattern channel (solid, dashed, dotted, ...). */
38
+ lineType?: AestheticValue;
43
39
  }
44
40
 
45
- /** Name of a built-in aesthetic that can be mapped, such as `'x'` or `'color'`. */
46
- export declare type AestheticKey = keyof KnownAesthetics;
41
+ /** Name of a single visual channel that can be mapped, such as `'x'` or `'color'`. */
42
+ export declare type AestheticKey = keyof AesMapping;
47
43
 
48
44
  /**
49
45
  * Aesthetic value can be:
@@ -51,7 +47,7 @@ export declare type AestheticKey = keyof KnownAesthetics;
51
47
  * - { variable: string } (explicit variable mapping)
52
48
  * - { value: DataValue } (constant value applied to every observation)
53
49
  */
54
- export declare type AestheticValue = string | VariableMapping | ValueMapping;
50
+ declare type AestheticValue = string | VariableMapping | ValueMapping;
55
51
 
56
52
  declare function aggregate(options: AggregateOptions): AggregateTransformInput;
57
53
 
@@ -89,59 +85,6 @@ declare type AggregationInput = Record<VariableName, {
89
85
  aggregation: AggregationFunction;
90
86
  }>;
91
87
 
92
- /**
93
- * Which point of a target's box an anchor resolves to. Compass directions name the
94
- * eight edge/corner points; `center` is the box centre. Omitted means the geom-natural
95
- * point (e.g. a bar's top-edge midpoint).
96
- */
97
- export declare type AnchorAlign = 'center' | 'top' | 'right' | 'bottom' | 'left' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
98
-
99
- /**
100
- * A hit with a scale-derived panel anchor — every index kind except `'render-hit-test'`. The compiler's
101
- * position scales give it a real `(x, y)`, so an overlay marker (hover dot, guide line) can be placed at it.
102
- */
103
- export declare interface AnchoredHoverHit extends HoverHitBase {
104
- /** Discriminant: this hit has a real anchor, so `x`/`y` are safe to read. */
105
- anchored: true;
106
- /**
107
- * Paint coordinates for an overlay marker (e.g. a hover dot) at this hit. Normalized panel-local.
108
- * Cartesian: `[0, 1]²` in data-space (y=0 at the bottom, y=1 at the top — matching the compiler's
109
- * `POSITION_VARIABLES.y`); convert to panel pixels as `xPixel = x * panel.width`,
110
- * `yPixel = (1 - y) * panel.height` (invert y for top-origin renderers). Polar: `(angle in radians
111
- * clockwise from 12 o'clock, radius in [0, 1])` — place via the same angle/radius transform the
112
- * polar cells use (center = panel center, outer radius = `min(panel.w, panel.h) / 2`).
113
- */
114
- x: number;
115
- y: number;
116
- }
117
-
118
- /**
119
- * A render-owned hit (`'render-hit-test'`: sankey, treemap, voronoi): the geometry lives render-side, so
120
- * the engine has no scale-derived anchor for it — there is deliberately no `x`/`y`. A render-owned geom's
121
- * `renderHover` derives its overlay from `observation`, and the tooltip follows the live cursor.
122
- */
123
- export declare interface AnchorlessHoverHit extends HoverHitBase {
124
- /** Discriminant: no anchor. Narrow on this before reading `x`/`y`, which this variant does not carry. */
125
- anchored: false;
126
- }
127
-
128
- /**
129
- * A nudge applied after a target resolves. `unit` selects the frame: `'panel'` is a
130
- * fraction of the plot rect, `'px'` is device pixels (resolved at runtime).
131
- */
132
- export declare interface AnchorOffset {
133
- x?: number;
134
- y?: number;
135
- /** Defaults to `'panel'`. */
136
- unit?: 'panel' | 'px';
137
- }
138
-
139
- /** A per-observation anchor position in normalised panel `[0, 1]` space (annotation anchoring). */
140
- export declare interface AnchorPosition {
141
- x: number;
142
- y: number;
143
- }
144
-
145
88
  /**
146
89
  * Bounds of the segment a stack total anchors to, in normalised `[0,1]` panel space (origin
147
90
  * bottom-left, y grows up). `direction` records which side of the stack the anchor came from.
@@ -160,55 +103,6 @@ export declare interface AngleExtent {
160
103
  endAngle: NumericDataValue;
161
104
  }
162
105
 
163
- /**
164
- * Builder for the built-in annotation kinds — the pipeable counterpart to setting the `annotations`
165
- * field by hand. Each method returns an {@link AnnotationItem}; piped into `createSpec`/`pipe` it appends
166
- * to the matching {@link AnnotationsInput} field, so annotations compose left-to-right like every other
167
- * spec feature (geoms, scales, highlights). Multiple calls of the same kind accumulate.
168
- *
169
- * @example
170
- * import { pipe, createSpec, geom, scale, annotation } from '@graphysdk/viz-engine';
171
- *
172
- * pipe(
173
- * createSpec({ x: 'month', y: 'revenue', color: 'region' }),
174
- * geom.line(),
175
- * scale.x.discrete(),
176
- * scale.y(),
177
- * scale.color.palette(),
178
- * annotation.differenceArrow({
179
- * start: { anchorValue: 'Jan', groupValue: 'North' },
180
- * end: { anchorValue: 'Jun', groupValue: 'North' },
181
- * label: 'relative-difference',
182
- * }),
183
- * annotation.shape({
184
- * region: { anchorType: 'panel', x: 0, y: 0.7, width: 1, height: 0.3 },
185
- * fillColor: '#e15759',
186
- * fillOpacity: 0.12,
187
- * }),
188
- * );
189
- */
190
- export declare const annotation: {
191
- /** A labelled delta between two data observations — reads the measured gap between them. */
192
- differenceArrow(input: DifferenceArrowInput): AnnotationItem;
193
- /** A shaded box whose area is positioned by a region anchor (panel fractions or a data selection). */
194
- shape(input: ShapeInput): AnnotationItem;
195
- /** A free-standing arrow whose endpoints are point anchors (panel fractions or observations). */
196
- arrow(input: ArrowInput): AnnotationItem;
197
- /** A free-standing rich-text label positioned by a point anchor. */
198
- text(input: TextAnnotationInput): AnnotationItem;
199
- /** An image whose area is positioned by a region anchor (panel fractions or a data selection). */
200
- image(input: ImageAnnotationInput): AnnotationItem;
201
- /** Editor-only: compiles but has NO painter in `@graphysdk/react-renderer`. */
202
- sticker(input: StickerAnnotationInput): AnnotationItem;
203
- /** Editor-only: compiles but has NO painter in `@graphysdk/react-renderer`. */
204
- pinnedNumber(input: PinnedNumberAnnotationInput): AnnotationItem;
205
- /** Editor-only: compiles but has NO painter in `@graphysdk/react-renderer`. */
206
- comment(input: CommentAnnotationInput): AnnotationItem;
207
- };
208
-
209
- /** Pixel gap between an anchor and the near edge of its mini bubble. */
210
- export declare const ANNOTATION_TOOLTIP_MARKER_GAP = 9;
211
-
212
106
  /** Anchors an annotation to a data point by row position, column, and/or category value. */
213
107
  declare interface AnnotationDataPoint {
214
108
  rowIndex?: number;
@@ -217,57 +111,16 @@ declare interface AnnotationDataPoint {
217
111
  }
218
112
 
219
113
  /**
220
- * The value returned by an {@link annotation} builder. Treat it as an opaque token — pipe
221
- * it into a spec, don't construct it by hand.
222
- */
223
- export declare type AnnotationItem = {
224
- type: 'annotation';
225
- kind: 'differenceArrow';
226
- annotation: DifferenceArrowInput;
227
- } | {
228
- type: 'annotation';
229
- kind: 'shape';
230
- annotation: ShapeInput;
231
- } | {
232
- type: 'annotation';
233
- kind: 'arrow';
234
- annotation: ArrowInput;
235
- } | {
236
- type: 'annotation';
237
- kind: 'text';
238
- annotation: TextAnnotationInput;
239
- } | {
240
- type: 'annotation';
241
- kind: 'image';
242
- annotation: ImageAnnotationInput;
243
- } | {
244
- type: 'annotation';
245
- kind: 'sticker';
246
- annotation: StickerAnnotationInput;
247
- } | {
248
- type: 'annotation';
249
- kind: 'pinnedNumber';
250
- annotation: PinnedNumberAnnotationInput;
251
- } | {
252
- type: 'annotation';
253
- kind: 'comment';
254
- annotation: CommentAnnotationInput;
255
- };
256
-
257
- /**
258
- * Compiles annotations into a render-ready format. Every anchor is projected into normalized panel
259
- * space `[0, 1]²` with one convention: data-up (y=0 at the bottom). The renderer flips `y` once at
260
- * paint time.
114
+ * Compiles annotations into a render-ready format.
261
115
  *
262
- * - Difference arrows: each `(anchor, group)` endpoint is projected. Cartesian only.
263
- * - Pinned numbers / comments: observation-anchored, projected the same way (cartesian + polar).
264
- * - Shapes / images / arrows / text / stickers: their point and region anchors are projected here,
265
- * so a `panel` anchor is flipped from top-left to data-up and an `observation` anchor tracks the
266
- * observation it points at.
116
+ * - Difference arrows: each `(anchor, group)` endpoint is projected into normalized panel
117
+ * space `[0, 1]²`. Cartesian only.
118
+ * - Stickers, pinned numbers and comments: the single anchor is projected the same way.
119
+ * Supported in both cartesian and polar coord systems (pies pin annotations to slice midpoints).
120
+ * - Shapes / freeform arrows / text annotations: coordinates are already in `[0, 1]`, so the
121
+ * stage passes them through into dedicated `Compiled<Kind>` types.
267
122
  */
268
123
  declare class AnnotationsCompiler extends Stage<AnnotationsCompilerInput, CompiledAnnotations> {
269
- private readonly container;
270
- constructor(container: CommonContainer);
271
124
  protected dependencies(input: AnnotationsCompilerInput): readonly unknown[];
272
125
  protected run(input: AnnotationsCompilerInput): CompiledAnnotations;
273
126
  }
@@ -277,52 +130,30 @@ declare interface AnnotationsCompilerInput {
277
130
  annotations: AnnotationsSpec;
278
131
  layers: readonly CompiledLayer[];
279
132
  coordSystem: CoordSystem;
280
- config: AnnotationsConfig;
281
133
  }
282
134
 
283
- /**
284
- * Subset of {@link ConfigSpec} the annotations stage reads. Narrowed so unrelated config changes
285
- * don't enter the cache dependency surface.
286
- */
287
- declare type AnnotationsConfig = Pick<ConfigSpec, 'parsingLocale'>;
288
-
289
- /** All annotations attached to a graph, as user-facing input. */
135
+ /** All annotations attached to a chart, as user-facing input. Every group is optional. */
290
136
  export declare interface AnnotationsInput {
291
137
  differenceArrows?: DifferenceArrowInput[];
292
138
  shapes?: ShapeInput[];
293
- freeformArrows?: ArrowInput[];
139
+ freeformArrows?: FreeformArrowInput[];
294
140
  textAnnotations?: TextAnnotationInput[];
295
- images?: ImageAnnotationInput[];
296
141
  stickers?: StickerAnnotationInput[];
297
142
  pinnedNumbers?: PinnedNumberAnnotationInput[];
298
143
  comments?: CommentAnnotationInput[];
299
144
  }
300
145
 
301
- /** Resolved annotations for a graph, with all fields defaulted. */
146
+ /** Resolved annotations for a chart, with every group present and all fields defaulted. */
302
147
  export declare interface AnnotationsSpec {
303
148
  differenceArrows: DifferenceArrowSpec[];
304
149
  shapes: ShapeSpec[];
305
- freeformArrows: ArrowSpec[];
150
+ freeformArrows: FreeformArrowSpec[];
306
151
  textAnnotations: TextAnnotationSpec[];
307
- images: ImageAnnotationSpec[];
308
152
  stickers: StickerAnnotationSpec[];
309
153
  pinnedNumbers: PinnedNumberAnnotationSpec[];
310
154
  comments: CommentAnnotationSpec[];
311
155
  }
312
156
 
313
- /**
314
- * Whether an annotation renders beneath the geoms (background) or on top (foreground).
315
- */
316
- export declare type AnnotationZOrder = 'background' | 'foreground';
317
-
318
- /**
319
- * A transform input that may be built-in or custom. Used at the spec-construction boundary
320
- * (`pipe`/`createSpec` items, `SpecInput.transforms`) and the transform compile stage, so a custom
321
- * transform pipes in and applies through the registry — while {@link TransformInput} stays the clean
322
- * built-in union everywhere a `transformType` is narrowed.
323
- */
324
- export declare type AnyTransformInput = TransformInput | CustomTransformInput<string>;
325
-
326
157
  declare interface Appearance {
327
158
  /** Id of the color palette to apply to all series. */
328
159
  paletteId?: string;
@@ -330,7 +161,7 @@ declare interface Appearance {
330
161
  seriesStyles?: Record<string, SeriesStyle>;
331
162
  /** Colors all bars the same instead of giving each category its own palette color. */
332
163
  useSingleColorForBars?: boolean;
333
- /** Tints the graph background with the palette instead of leaving it plain. */
164
+ /** Tints the chart background with the palette instead of leaving it plain. */
334
165
  backgroundModifier?: 'none' | 'tint';
335
166
  border?: Partial<{
336
167
  style: 'none' | 'custom' | 'tinted' | 'gradient' | 'preset' | 'grey';
@@ -338,7 +169,10 @@ declare interface Appearance {
338
169
  width: number;
339
170
  }>;
340
171
  hasRoundedCorners?: boolean;
341
- textStyle?: AppearanceTextStyle;
172
+ textStyle?: Partial<{
173
+ heading: GraphTextStyle;
174
+ body: GraphTextStyle;
175
+ }>;
342
176
  /** One of the {@link CHART_TEXT_SCALES} multipliers applied to all text sizes. */
343
177
  textScale?: number;
344
178
  /** How non-highlighted series are de-emphasized when one series is highlighted. */
@@ -374,7 +208,7 @@ export declare interface AppearanceSpec {
374
208
  * Multiplier applied to every text element. The renderer sets a CSS
375
209
  * variable; em-based theme tokens scale automatically.
376
210
  *
377
- * Renderer contract: apply this at both text measurement and CSS render time.
211
+ * Renderer contract: apply this at BOTH text measurement and CSS render time.
378
212
  * The engine assumes the measured sizes it receives already include the
379
213
  * multiplier, so layout will be wrong if it is applied to only one of the two.
380
214
  * @default 1
@@ -403,11 +237,6 @@ export declare interface AppearanceSpec {
403
237
  highlightStyle: HighlightStyle;
404
238
  }
405
239
 
406
- export declare type AppearanceTextStyle = Partial<{
407
- heading: GraphTextStyle;
408
- body: GraphTextStyle;
409
- }>;
410
-
411
240
  declare function area(options?: GeomOptions<'area'>): LayerInputOf<'area'>;
412
241
 
413
242
  /**
@@ -416,7 +245,7 @@ declare function area(options?: GeomOptions<'area'>): LayerInputOf<'area'>;
416
245
  export declare interface AreaGeomParams {
417
246
  /**
418
247
  * Outline stroke width in pixels. `'auto'` reads the per-observation
419
- * `strokeWidth` value (`getStrokeWidth`), falling back to the geom default.
248
+ * `strokeWidth` channel (`getStrokeWidth`), falling back to the geom default.
420
249
  */
421
250
  lineWidth: number | 'auto';
422
251
  /**
@@ -426,12 +255,11 @@ export declare interface AreaGeomParams {
426
255
  */
427
256
  interpolate: InterpolateType;
428
257
  /**
429
- * How to handle missing (null/undefined) values. As for line:
430
- * - `'zero'`: nulls arrive already substituted with zero by the compiler.
431
- * - `'gap'`: break the path at a null.
432
- * - `'connect'`: drop nulls before pathing so the line spans the gap.
258
+ * How to handle missing (NULL/undefined) values, as for line: `'zero'`
259
+ * pre-substituted by the compiler, `'gap'` breaks the path at a null, and
260
+ * `'connect'` drops null rows before pathing.
433
261
  * @default 'gap'
434
- * */
262
+ */
435
263
  missingValues: MissingValuesType;
436
264
  }
437
265
 
@@ -440,46 +268,20 @@ export declare interface AreaPathGenerators {
440
268
  areaGenerator: Area<Observation>;
441
269
  }
442
270
 
271
+ /** One end of a freeform arrow, positioned as a fraction of the plot rect (0..1) so it re-flows on resize. */
272
+ export declare interface ArrowEndpoint {
273
+ /** 0..1 of plot width. */
274
+ x: number;
275
+ /** 0..1 of plot height. */
276
+ y: number;
277
+ }
278
+
443
279
  /** Whether an arrow end carries an arrowhead. */
444
280
  export declare type ArrowheadStyle = 'none' | 'line-arrow';
445
281
 
446
- /**
447
- * Arrow annotation. Each endpoint is a {@link PointAnchorInput}, so it can float in
448
- * panel fractions or pin to an observation. Distinct from {@link DifferenceArrowInput},
449
- * which reads the measured gap between two observations.
450
- */
451
- export declare interface ArrowInput {
452
- id?: string;
453
- /** Tail endpoint. */
454
- start: PointAnchorInput;
455
- /** Head endpoint. */
456
- end: PointAnchorInput;
457
- /** null falls back to the theme `defaultAnnotationArrowStroke`. */
458
- color?: string | null;
459
- thickness?: ArrowThickness;
460
- startArrowheadStyle?: ArrowheadStyle;
461
- endArrowheadStyle?: ArrowheadStyle;
462
- lineStyle?: ArrowLineStyle;
463
- /** Render with a raised, outlined sticker-like appearance. */
464
- hasStickerStyle?: boolean;
465
- }
466
-
467
282
  /** Whether an arrow's line is drawn solid or dashed. */
468
283
  export declare type ArrowLineStyle = 'solid' | 'dashed';
469
284
 
470
- /** Resolved arrow with all optional fields defaulted. */
471
- export declare interface ArrowSpec {
472
- id: string;
473
- start: PointAnchor;
474
- end: PointAnchor;
475
- color: string | null;
476
- thickness: ArrowThickness;
477
- startArrowheadStyle: ArrowheadStyle;
478
- endArrowheadStyle: ArrowheadStyle;
479
- lineStyle: ArrowLineStyle;
480
- hasStickerStyle: boolean;
481
- }
482
-
483
285
  /** Preset stroke weight for an arrow annotation. */
484
286
  export declare type ArrowThickness = 'thin' | 'medium' | 'thick';
485
287
 
@@ -492,8 +294,7 @@ declare interface AverageLine {
492
294
  * Visual descriptor for the swatch rendered inside an average-line label pill.
493
295
  */
494
296
  export declare interface AverageLineSymbol {
495
- /** The source layer's geom — the renderer reads its swatch shape off the geom's render contract. */
496
- geom: string;
297
+ shape: SwatchShape;
497
298
  color: string;
498
299
  }
499
300
 
@@ -526,27 +327,24 @@ declare interface AxisGridConfig {
526
327
  * Whether grid lines are visible.
527
328
  * - true/false: explicit visibility
528
329
  * - null: let the compiler decide based on geom/coord policies
529
- * (visible unless a geom policy hides it, e.g. bar charts hide the x grid)
330
+ * (defaults to false for x-axis, true for y-axis)
530
331
  */
531
332
  isVisible: boolean | null;
532
- /**
533
- * Line style of this axis's grid lines.
534
- * @default 'dashed'
535
- */
536
- lineStyle: LineStyleType;
537
- /**
538
- * Stroke width of this axis's grid lines in px. null inherits the theme's grid line width.
539
- * @default null
540
- */
541
- lineWidth: number | null;
542
333
  }
543
334
 
335
+ /**
336
+ * Label display mode for axis ticks
337
+ * - 'auto': Show all ticks (default behavior)
338
+ * - 'edges': Show only the first and last tick
339
+ */
340
+ declare type AxisLabelMode = 'auto' | 'edges';
341
+
544
342
  /**
545
343
  * Maps each positional aesthetic to its axis orientation.
546
344
  * The guide compiler uses this to determine where axes are placed
547
345
  * and what geometry they use (e.g., linear vs circular grid lines).
548
346
  */
549
- export declare interface AxisMapping {
347
+ declare interface AxisMapping {
550
348
  x: {
551
349
  position: AxisPosition;
552
350
  geometry: GuideGeometry;
@@ -584,7 +382,7 @@ export declare interface AxisTick {
584
382
  * Tick position in the same normalized space the geoms use. Normalized to [0,1]: x is 0=left…1=right,
585
383
  * y is 0=bottom…1=top (data-up). SVG / top-origin renderers invert y as `1 - y`.
586
384
  *
587
- * For discrete scales this is the band center; the band spans `position ± bandwidth/2`
385
+ * For discrete scales this is the band CENTER; the band spans `position ± bandwidth/2`
588
386
  * (see {@link CompiledAxisGuide.bandwidth}).
589
387
  */
590
388
  position: number;
@@ -599,24 +397,17 @@ export declare interface AxisTickCandidate {
599
397
  valueFormat?: ValueFormat;
600
398
  }
601
399
 
602
- /**
603
- * Display mode for axis ticks
604
- * - 'auto': Show all ticks (default behavior)
605
- * - 'edges': Show only the first and last tick
606
- */
607
- declare type AxisTickMode = 'auto' | 'edges';
608
-
609
400
  /**
610
401
  * Configuration for a single axis's ticks
611
402
  */
612
403
  declare interface AxisTicksConfig {
613
404
  isVisible: boolean;
614
- mode: AxisTickMode;
405
+ mode: AxisLabelMode;
615
406
  }
616
407
 
617
408
  /**
618
409
  * Resolved background fill (compiled from `BackgroundSpec`). The variant is decided, but
619
- * `'theme'` carries no `color`: the renderer narrows (`'color' in background`) before reading it.
410
+ * `'theme'` carries no `color` the renderer narrows (`'color' in background`) before reading it.
620
411
  *
621
412
  * Renderer materialization by variant:
622
413
  * - `'theme'`: paint the active theme's graph-background token (no `color` on this variant).
@@ -655,8 +446,8 @@ declare function bar(options?: GeomOptions<'bar'>): LayerInputOf<'bar'>;
655
446
 
656
447
  /**
657
448
  * Bar/Column-specific parameters — intentionally empty. A bar's geometry comes
658
- * entirely from the position variables (band edges plus bar length); corner radius
659
- * and grouping are renderer-owned styling, not spec params.
449
+ * entirely from the position columns (band edges plus bar length); corner radius
450
+ * and column grouping are renderer-owned styling, not spec params.
660
451
  */
661
452
  declare type BarGeomParams = Record<string, never>;
662
453
 
@@ -681,7 +472,7 @@ declare interface BaseCoordParams {
681
472
  declare interface BaseGeomOptions<T extends GeomParams> {
682
473
  /** Layer-local aesthetic mapping, merged over the spec-level mapping. */
683
474
  aes?: AesMapping;
684
- stat?: StatName | StatInput | CustomStatInput<string>;
475
+ stat?: StatName | StatInput;
685
476
  position?: PositionType;
686
477
  yScaleType?: YScaleType;
687
478
  params?: Partial<T>;
@@ -703,8 +494,8 @@ export declare const BORDER_PRESET_GRADIENTS: Record<BorderPreset, string>;
703
494
  export declare const BORDER_PRESETS: readonly ["lilac", "neon_pink", "blackberry", "sun", "iceland", "sunset", "ultraviolet", "purple", "ice_cream", "mint", "cool", "fresh"];
704
495
 
705
496
  /**
706
- * Resolved border ring (compiled from `BorderSpec`), painted inside the graph bounds. `'none'` carries no `color`/`width`.
707
- * Narrow on `type` before reading either.
497
+ * Resolved border ring (compiled from `BorderSpec`), painted inside the chart bounds. `'none'` carries
498
+ * no `color`/`width`; narrow on `type` before reading either.
708
499
  *
709
500
  * Renderer materialization by variant:
710
501
  * - `'solid'`: fill the ring with `color` as-is.
@@ -779,15 +570,14 @@ export declare type BoxSize = {
779
570
  };
780
571
 
781
572
  /**
782
- * For each average-line rule in a graph with a categorical color grouping, returns the source geom
783
- * + color the renderer paints inside the rule's label pill (mapping the geom to a swatch shape via
784
- * its `(geom, coord)` registry).
573
+ * For each average-line rule in a graph with a categorical color grouping, returns the swatch
574
+ * shape + color the renderer should paint inside the rule's label pill.
785
575
  *
786
- * Pass the source `spec.layers` (not the compiled layers) so each layer's original `stat`,
576
+ * Pass the SOURCE `spec.layers` (not the compiled layers) so each layer's original `stat`,
787
577
  * `transforms` and `mapping` are available without needing extra fields on `CompiledLayer`, and the
788
- * compiled `color` scale (`scales.color`). The returned map is keyed by rule-layer id (the id is
578
+ * compiled `color` scale (`scales.color`). The returned map is keyed by RULE-layer id (the id is
789
579
  * preserved through compilation): look up a rule by its own id; a missing entry means draw no
790
- * symbol (e.g. no categorical color grouping, or the rule's group didn't resolve to a color).
580
+ * symbol (e.g. no categorical color grouping, or the rule's series didn't resolve to a color).
791
581
  *
792
582
  * Two shapes of rule layer are handled:
793
583
  * - **Filtered**: the rule carries an `eq`-filter. The color-scale lookup value is the filter's
@@ -795,14 +585,7 @@ export declare type BoxSize = {
795
585
  * - **Unfiltered**: no filter; the rule's `mapping.y` IS the lookup value. The source layer is
796
586
  * the one whose `y` aesthetic is bound to the same variable.
797
587
  */
798
- export declare function buildAverageLineSymbols(layers: readonly LayerSpec[], colorScale: CompiledScale | undefined): ReadonlyMap<string, AverageLineSymbol>;
799
-
800
- /**
801
- * Turns placed callouts into the hit regions the pointer tracker tests. Only in-view callouts get
802
- * a region. The anchor goes through `toPanelCursor` — the same mapping the tracker applies to the
803
- * live cursor — so the hover engine resolves the same observation the marker pixel would.
804
- */
805
- export declare const buildCalloutHitRegions: (placed: readonly PlacedCallout[], panelRect: Rect) => CalloutHitRegion[];
588
+ export declare function buildAverageLineSymbols(layers: readonly LayerSpec[], colorScale: CompiledScale | undefined, coordSystem: CoordSystem): ReadonlyMap<string, AverageLineSymbol>;
806
589
 
807
590
  /**
808
591
  * Pure projection of `(layers, coordSystem, axes, formatter context, panelRect, measureDataLabel)`
@@ -831,16 +614,11 @@ export declare interface BuildDataLabelsContentInput {
831
614
  }
832
615
 
833
616
  /**
834
- * Normalise **any** thrown value into a serialisable {@link VizDiagnostic}. A {@link VizError}
835
- * maps field-for-field (`severity: 'error'`); anything else a plain `Error`, a string, an
836
- * unexpected throw becomes `kind: 'internal'`, `code: 'INTERNAL_INVARIANT'`, so even surprises
837
- * emit structured output for telemetry and codegen rather than an opaque message.
838
- */
839
- export declare function buildDiagnostic(error: unknown): VizDiagnostic;
840
-
841
- /**
842
- * Builds a CSS font shorthand string from a FontSpec.
843
- * Always quotes the family name to safely handle names with spaces.
617
+ * Builds a CSS font shorthand string from a FontSpec, in the order `"<style> <weight> <size>px
618
+ * <family>"` (e.g. `"normal 500 12px 'Inter'"`). A single family is quoted so names with spaces stay
619
+ * one token; a family already containing a comma is treated as a ready fallback list and passed
620
+ * through unquoted. A named weight (e.g. `'bold'`) is emitted as-is the browser canvas resolves it —
621
+ * rather than being mapped to a number; omitted weight/style fall back to the defaults.
844
622
  *
845
623
  * Renderer-agnostic: usable by browser (OffscreenCanvas) and backend
846
624
  * (@napi-rs/canvas) measurers to set `ctx.font` before `ctx.measureText()`.
@@ -858,16 +636,6 @@ declare interface BuildLayerYValueFormatterInput {
858
636
  locale: Locale;
859
637
  }
860
638
 
861
- /**
862
- * Formats a pinned number's value using the value format resolved onto its anchor at compile time.
863
- */
864
- export declare function buildPinnedNumberValueFormatter({ numberFormat, locale, }: BuildPinnedNumberValueFormatterInput): (anchor: ResolvedObservationPoint) => string;
865
-
866
- declare interface BuildPinnedNumberValueFormatterInput {
867
- numberFormat: NumberFormatConfig;
868
- locale: Locale;
869
- }
870
-
871
639
  /**
872
640
  * Builds the SVG arc path for a polar bar (pie / donut slice).
873
641
  *
@@ -876,7 +644,10 @@ declare interface BuildPinnedNumberValueFormatterInput {
876
644
  export declare const buildPolarBarArcPath: (input: PolarBarArcInput) => string | null;
877
645
 
878
646
  /**
879
- * Pure projection of `(compiled, hover)` into the tooltip's `{ header, rows }`. Returns `null` when there is no primary hit; use that as the tooltip show/hide signal.
647
+ * Pure projection of `(compiled, hover)` into the tooltip's `{ header, rows }`. Pure (no I/O, no
648
+ * mutation) — safe to memoize on its input.
649
+ *
650
+ * Returns `null` when there is no primary hit; use that as the tooltip show/hide signal.
880
651
  *
881
652
  * Row order is layer-declaration order across layers, color-scale domain order within a layer
882
653
  * (= the legend's display order). The primary hit is emphasized in place — never reordered to
@@ -890,9 +661,9 @@ export declare const buildTooltipContent: ({ layers, coordSystem, scales, guides
890
661
  * hits stay aligned, plus the spec's `scales`, `guides`, and config formatting fields.
891
662
  */
892
663
  export declare interface BuildTooltipContentInput {
893
- /** Compiled layers — the same array passed to the `HoverEngine`. Source of per-group swatch/label data. */
664
+ /** Compiled layers — the same array passed to the `HoverEngine`. Source of per-series swatch/label data. */
894
665
  layers: readonly CompiledLayer[];
895
- /** Compiled coord system — the same one passed to the `HoverEngine` (gates the header). */
666
+ /** Compiled coord system — the same one passed to the `HoverEngine` (drives swatch shape; gates the header). */
896
667
  coordSystem: CoordSystem;
897
668
  /** `CompiledSpec.scales`. The `color` scale's domain fixes legend (display) row order within a layer. */
898
669
  scales: CompiledScales;
@@ -925,31 +696,6 @@ export declare class CachedTextMeasurer implements TextMeasurer {
925
696
  private getCacheKey;
926
697
  }
927
698
 
928
- /**
929
- * A pinned-callout hit region the pointer tracker tests in memory.
930
- */
931
- export declare interface CalloutHitRegion {
932
- /** Hit rectangle in panel-local pixels — the same space as `(clientX, clientY) - captureRect`. */
933
- rect: Rect;
934
- /** Normalized, y-flipped cursor used to resolve this callout's observation from the hover engine. */
935
- cursor: HoverCursor;
936
- /** The data anchor (marker) in panel-local pixels; the tooltip anchors here to cover the mini. */
937
- markerPx: {
938
- x: number;
939
- y: number;
940
- };
941
- /** Direction the mini sits from the marker, so the tooltip can expand over it the same way. */
942
- placement: CalloutPlacement;
943
- }
944
-
945
- /** Which kind of annotation a callout renders. */
946
- export declare type CalloutKind = 'pinned-number' | 'comment';
947
-
948
- export declare type CalloutMeasurer = (kind: CalloutKind, text: string) => BoxSize;
949
-
950
- /** Direction the mini bubble sits relative to its anchor. */
951
- export declare type CalloutPlacement = 'top' | 'right' | 'bottom' | 'left';
952
-
953
699
  declare interface CartesianCoordInput {
954
700
  type: 'coord';
955
701
  coordType: 'cartesian';
@@ -975,9 +721,8 @@ export declare interface CartesianCoordSystem {
975
721
  * rise, X ticks on the horizontal axis); `'y'` for `coord.flip()` (bars extend, Y ticks on the
976
722
  * horizontal axis). Consumers that need to branch on flip read this; the runtime `coord/axes`
977
723
  * helpers turn it into main/cross accessors so the branch lives in one place.
978
- * When `'y'`, the x-variables carry the measure / cross-axis extent and the y-variables carry the
979
- * main-axis band but that swap is already applied to the position variables by the coord transform,
980
- * so geoms read `getX`/`getY` without branching. See {@link MainAxis}.
724
+ * When `'y'`, the x-columns carry the measure / cross-axis extent and the y-columns carry the
725
+ * main-axis band, so geoms swap which reader feeds which pixel axis. See {@link MainAxis}.
981
726
  */
982
727
  mainAxis: MainAxis;
983
728
  /** Axis orientation metadata for the guide compiler */
@@ -1012,8 +757,7 @@ declare interface CategoricalValueFormat {
1012
757
  declare interface ColorGroup {
1013
758
  value: DataValue;
1014
759
  color: string;
1015
- /** The owning layer's geom — the renderer reads its swatch shape off the geom's render contract. */
1016
- geom: string;
760
+ shape: SwatchShape;
1017
761
  layerIndex: number;
1018
762
  /** Format for the group's `value`, resolved from the owning layer's color column. */
1019
763
  valueFormat: ValueFormat;
@@ -1040,7 +784,7 @@ declare interface ColorScaleMethods {
1040
784
  }
1041
785
 
1042
786
  declare interface ComboOptions {
1043
- /** Geometry used for the bar-like series alongside line series in a combo graph. */
787
+ /** Geometry used for the bar-like series alongside line series in a combo chart. */
1044
788
  comboType?: 'grouped-bars' | 'stacked-bars' | 'lines';
1045
789
  }
1046
790
 
@@ -1065,6 +809,8 @@ export declare interface Command<TParams extends Record<string, unknown> = Recor
1065
809
  * Dispatch loop a renderer runs to reflect a command in the view: apply it to the live
1066
810
  * `CompiledSpec.spec`, and on a non-`null` result recompile the returned spec —
1067
811
  * `const result = command.apply(compiled.spec); if (!result) return; recompile({ spec: result.spec })`.
812
+ * A `null` result skips the recompile (and any notify). Always apply against `CompiledSpec.spec`,
813
+ * the canonical live spec.
1068
814
  */
1069
815
  apply: (spec: Spec) => CommandApplyResult | null;
1070
816
  }
@@ -1261,42 +1007,32 @@ export declare interface CommandStackSnapshot {
1261
1007
  */
1262
1008
  declare interface CommentAnnotationInput {
1263
1009
  id?: string;
1264
- at: ObservationAnchorInput;
1010
+ anchor: ObservationAnchorInput;
1265
1011
  content: RichTextContent;
1266
1012
  }
1267
1013
 
1268
1014
  declare interface CommentAnnotationSpec {
1269
1015
  id: string;
1270
- at: ObservationAnchor;
1016
+ anchor: ObservationAnchor;
1271
1017
  content: RichTextContent;
1272
1018
  }
1273
1019
 
1274
- /**
1275
- * Cross-cutting services shared across a single compile, created once per {@link Compiler} and
1276
- * passed as the first argument to every collaborator that needs them.
1277
- */
1278
- declare interface CommonContainer {
1279
- diagnostics: DiagnosticsCollector;
1280
- /** The geom registry, so resolvers can read declared capabilities (e.g. scale constraints). */
1281
- geomRegistry: GeomRegistry;
1282
- }
1283
-
1284
1020
  /** Comparison operators for declarative filtering. */
1285
1021
  declare type ComparisonOperator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte';
1286
1022
 
1287
1023
  /**
1288
- * All annotations of a graph after compilation, grouped by kind and ready for the renderer.
1024
+ * All annotations of a chart after compilation, grouped by kind and ready for the renderer.
1289
1025
  *
1290
- * The engine does not impose paint order across kinds; the renderer decides it. The one ordering
1291
- * signal carried here is {@link CompiledShape.zOrder}, which marks a shape as drawing behind
1292
- * (`background`) or over (`foreground`) the geoms.
1026
+ * Paint order (back to front): background shapes geoms data-labels difference-arrows
1027
+ * foreground shapes freeform-arrows text-annotations. Note that `shapes` are split by their
1028
+ * `zOrder` into two passes that bracket the geom layer (see {@link ShapeZOrder}); stickers, pinned
1029
+ * numbers and comments are marker overlays painted above text-annotations.
1293
1030
  */
1294
1031
  export declare interface CompiledAnnotations {
1295
1032
  differenceArrows: CompiledDifferenceArrow[];
1296
1033
  shapes: CompiledShape[];
1297
1034
  freeformArrows: CompiledFreeformArrow[];
1298
1035
  textAnnotations: CompiledTextAnnotation[];
1299
- images: CompiledImageAnnotation[];
1300
1036
  stickers: CompiledStickerAnnotation[];
1301
1037
  pinnedNumbers: CompiledPinnedNumberAnnotation[];
1302
1038
  comments: CompiledCommentAnnotation[];
@@ -1313,45 +1049,34 @@ export declare interface CompiledAxisGuide {
1313
1049
  /** The aesthetic this axis serves (always 'x' or 'y') */
1314
1050
  aesthetic: AestheticKey;
1315
1051
  /**
1316
- * Axis placement. Already reflects any flip, do not re-derive from the coord system's `mainAxis`.
1052
+ * Axis placement. Already reflects any flip — drive placement off this, do NOT re-derive from the coord
1053
+ * system's `mainAxis`.
1317
1054
  */
1318
1055
  position: AxisPosition;
1319
- /**
1320
- * Geometric shape the axis traces.
1321
- * - `'linear'` for a straight cartesian edge (drawn by the cartesian grid/axis renderers),
1322
- * - `'circular'` for a radar's angular spoke axis
1323
- * - `'radial'` for its ring axis.
1324
- *
1325
- * Mirrors the coord system's `axisMapping[aesthetic].geometry`.
1326
- */
1327
- geometry: GuideGeometry;
1328
1056
  /** Title text, null means no title */
1329
1057
  label: string | null;
1330
1058
  /**
1331
- * Gates the whole axis region (line + ticks + labels).
1059
+ * Gates the whole axis region (line + ticks + labels). Orthogonal to `ticksVisible` / `gridVisible` and to
1060
+ * {@link CompiledPanel.border}.
1332
1061
  */
1333
1062
  isVisible: boolean;
1334
1063
  /**
1335
- * Candidate tick sets, sorted by ascending count. These are raw candidates, not the final selection.
1336
- * Final selection happens in `LayoutCompiler`. The renderer
1337
- * paints the resulting `FormattedAxis.ticks` verbatim; it must not re-select candidates here.
1064
+ * Candidate tick sets, sorted by ascending count these are RAW candidates, not the final selection.
1065
+ * Final selection happens in `LayoutCompiler` (two phases: pick the densest candidate whose labels fit), and
1066
+ * the renderer paints the resulting `FormattedAxis.ticks` verbatim it must not re-select candidates here.
1338
1067
  */
1339
1068
  tickCandidates: AxisTickCandidate[];
1340
1069
  /**
1341
1070
  * Resolved format descriptor shared by all ticks on this axis. Already applied during tick selection: the
1342
- * renderer paints `FormattedAxis.ticks[].formattedLabel` as-is and must not re-apply this `ValueFormat`.
1071
+ * renderer paints `FormattedAxis.ticks[].formattedLabel` as-is and must NOT re-apply this `ValueFormat`.
1343
1072
  */
1344
1073
  valueFormat: ValueFormat;
1345
1074
  /** Tick mode from config. Already honored by the compiler when building candidates — don't re-filter ticks. */
1346
- tickMode: AxisTickMode;
1075
+ tickMode: AxisLabelMode;
1347
1076
  /** Whether tick marks are visible. Labels still show when this is false (independent of `isVisible`). */
1348
1077
  ticksVisible: boolean;
1349
1078
  /** Whether grid lines are visible at tick positions. Grid is drawn separately from the axis region. */
1350
1079
  gridVisible: boolean;
1351
- /** Line style of this axis's grid lines. */
1352
- gridLineStyle: LineStyleType;
1353
- /** Stroke width of this axis's grid lines in px. null inherits the theme's grid line width. */
1354
- gridLineWidth: number | null;
1355
1080
  /** Scale type — the renderer uses this to select a formatting strategy */
1356
1081
  scaleType: ScaleType;
1357
1082
  /** Band width in [0, 1] space for discrete position scales. Undefined otherwise. */
@@ -1361,9 +1086,9 @@ export declare interface CompiledAxisGuide {
1361
1086
  /**
1362
1087
  * Compile-time projection of a comment annotation.
1363
1088
  */
1364
- export declare interface CompiledCommentAnnotation {
1089
+ declare interface CompiledCommentAnnotation {
1365
1090
  id: string;
1366
- at: ResolvedObservationPoint;
1091
+ anchor: ResolvedObservationAnchor;
1367
1092
  content: RichTextContent;
1368
1093
  }
1369
1094
 
@@ -1376,8 +1101,8 @@ declare type CompiledConfig = Omit<ConfigSpec, 'appearance'> & {
1376
1101
  */
1377
1102
  export declare interface CompiledDifferenceArrow {
1378
1103
  id: string;
1379
- start: ResolvedObservationPoint;
1380
- end: ResolvedObservationPoint;
1104
+ start: ResolvedObservationAnchor;
1105
+ end: ResolvedObservationAnchor;
1381
1106
  /**
1382
1107
  * Resolved color. Precedence:
1383
1108
  * 1. user-specified `arrow.color`
@@ -1388,23 +1113,17 @@ export declare interface CompiledDifferenceArrow {
1388
1113
  size: DifferenceArrowSize;
1389
1114
  /** Which quantity the arrow's label reports (absolute, relative, or proportion of the two endpoints). */
1390
1115
  label: DifferenceArrowLabelKind;
1391
- /**
1392
- * Label position along the arrow as a fraction of its length, anchored to the geometric edge (not
1393
- * the endpoints): 0 = left, 1 = right (top/bottom when flipped). Defaults to 0.5.
1394
- */
1116
+ /** Where the label sits along the arrow, as a fraction from start (0) to end (1). */
1395
1117
  labelCrossPosition: number;
1396
1118
  }
1397
1119
 
1398
- /** The three compile-side definition shapes a plugin can contribute. */
1399
- export declare type CompileDefinition = Geom<unknown> | StatDefinition | TransformDefinition;
1400
-
1401
1120
  /**
1402
- * Compile-time projection of an arrow annotation.
1121
+ * Compile-time projection of a freeform arrow.
1403
1122
  */
1404
1123
  export declare interface CompiledFreeformArrow {
1405
1124
  id: string;
1406
- start: ResolvedPoint;
1407
- end: ResolvedPoint;
1125
+ start: ArrowEndpoint;
1126
+ end: ArrowEndpoint;
1408
1127
  /** Line color, or `null` to fall back to the theme default. */
1409
1128
  color: string | null;
1410
1129
  thickness: ArrowThickness;
@@ -1415,7 +1134,7 @@ export declare interface CompiledFreeformArrow {
1415
1134
  hasStickerStyle: boolean;
1416
1135
  }
1417
1136
 
1418
- export declare interface CompiledGeom {
1137
+ declare interface CompiledGeom {
1419
1138
  /** The reparameterized dataset (may have new computed variables) */
1420
1139
  data: Dataset;
1421
1140
  /** Any mapping overrides produced by the geom */
@@ -1447,11 +1166,6 @@ export declare interface CompiledGuides {
1447
1166
  * source legends, headline, and tooltip all read so they agree on how each series reads.
1448
1167
  */
1449
1168
  colorGroups: ColorGroup[];
1450
- /**
1451
- * Friendly display labels keyed by variable name. Runtime consumers (e.g. tooltips) resolve a
1452
- * series' label from this rather than borrowing a guide's title.
1453
- */
1454
- variableLabels: VariableLabels;
1455
1169
  }
1456
1170
 
1457
1171
  /**
@@ -1471,65 +1185,25 @@ export declare interface CompiledIdentityScale extends CompiledScaleBase {
1471
1185
  map: (value: DataValue) => DataValue;
1472
1186
  }
1473
1187
 
1474
- /**
1475
- * Compile-time projection of an image annotation.
1476
- */
1477
- export declare interface CompiledImageAnnotation {
1478
- id: string;
1479
- /** Image URL or data URI. */
1480
- src: string;
1481
- /** Whether the image draws behind the geoms (background) or over them (foreground). */
1482
- zOrder: AnnotationZOrder;
1483
- region: ResolvedRegion;
1484
- /** How the image scales inside its box. */
1485
- fit: ImageAnnotationFit;
1486
- opacity: number;
1487
- }
1488
-
1489
1188
  /**
1490
1189
  * Render-ready layer with resolved mappings and transformed data.
1491
1190
  */
1492
1191
  export declare interface CompiledLayer {
1493
1192
  /**
1494
1193
  * Stable identity carried over from `LayerSpec.id`. Preserved across recompiles (commands keep
1495
- * it too), so renderers root per-geom React keys on it — geoms morph instead of remounting — and
1194
+ * it too), so renderers root per-mark React keys on it — marks morph instead of remounting — and
1496
1195
  * join hover by matching `HoverHit.layerId === layer.id`.
1497
1196
  */
1498
1197
  id: string;
1499
1198
  /**
1500
- * This layer's transformed, render-ready dataset. Within a group, the observations
1199
+ * This layer's transformed, render-ready observations, in render order. Within a series the rows
1501
1200
  * are pre-ordered along the main axis, so a line / area path can be drawn as-is with no re-sort.
1502
1201
  * Connected geoms (line, area, polar arc) partition these by `GROUP_VARIABLES.group`
1503
- * (`data.groupBy(...)`) — one observation per group; per-observation geoms (bar, point) iterate `data` directly.
1202
+ * (`data.groupBy(...)`) — one mark per group; per-mark geoms (bar, point) iterate `data` directly.
1504
1203
  */
1505
1204
  data: Dataset;
1506
- /**
1507
- * The geom this layer paints. A plain `string` (not {@link GeomName}): the compiled spec is
1508
- * serialisable and reaches a renderer with no knowledge of the registered plugins, so a custom
1509
- * geom's identity survives as its name and downstream resolution is a registry lookup. Narrow back
1510
- * to a built-in flavour with {@link isLayerOf} / {@link CompiledLayerFor}.
1511
- */
1512
- geom: string;
1513
- /**
1514
- * The coord-agnostic hit-test shape this layer's geom declares, baked from the geom def at compile
1515
- * time. The runtime hover indexer (`build-layer-index`) reads this plus the chart's coord system to
1516
- * build the projected index, so a custom geom is indexed by what it declares rather than by name, and
1517
- * the polar projection (a pie's `cells`, a radar's angle-snap) is a runtime fact of the coord.
1518
- */
1519
- spatialKind: SpatialKind;
1520
- /**
1521
- * What counts as "the same observation" for this layer, baked from the geom def. The runtime
1522
- * resolves a `'render-hit-test'` tester's returned key against this, and morphs/hover-stability
1523
- * use it across recompiles.
1524
- */
1525
- identityKey: IdentityKey;
1526
- /**
1527
- * The geom's tooltip contract, baked from the geom def. When non-empty the tooltip shows one row
1528
- * per field (the field's `key` label, the raw value of its `aes` from the hovered observation),
1529
- * replacing the default y-value row. Empty for geoms that use the default tooltip.
1530
- */
1531
- tooltip: TooltipContract;
1532
- /** Final mapping after merging root + layer + stat + geom overrides (may carry custom positional aesthetics). */
1205
+ geom: GeomName;
1206
+ /** Final mapping after merging root + layer + stat + geom overrides */
1533
1207
  mapping: AesMapping;
1534
1208
  position: PositionType;
1535
1209
  yScaleType: YScaleType;
@@ -1567,8 +1241,8 @@ export declare type CompiledLayerFor<G extends GeomName> = Omit<CompiledLayer, '
1567
1241
  * strategy (set at layer compile time, never changes after) with the composition output
1568
1242
  * (rewritten by the highlights compile stage when applicable highlights match).
1569
1243
  *
1570
- * This is the static highlight (from the spec). A live hover transiently supersedes it: while a
1571
- * pointer is over the graph, render the hover result (see `HoverState`) in place of this.
1244
+ * This is the **static** highlight (from the spec). A live hover transiently supersedes it: while a
1245
+ * pointer is over the chart, render the hover result (see `HoverState`) in place of this.
1572
1246
  */
1573
1247
  export declare interface CompiledLayerHighlight {
1574
1248
  /** How this layer composes highlight matches above its base render. */
@@ -1580,9 +1254,9 @@ export declare interface CompiledLayerHighlight {
1580
1254
  /** A render-ready legend: its resolved placement plus the items it lists, possibly merged across aesthetics. */
1581
1255
  export declare interface CompiledLegendGuide {
1582
1256
  /**
1583
- * Visual scale keys this legend represents (may be merged): one or more of `color` / `size` / `alpha` /
1584
- * `strokeWidth` / `lineType`. When this includes `'size'` the legend is a bubble
1585
- * legend.
1257
+ * Visual SCALE keys this legend represents (may be merged): one or more of `color` / `size` / `alpha` /
1258
+ * `strokeWidth` / `lineType` — match those exact tokens. When this includes `'size'` the legend is a BUBBLE
1259
+ * legend: paint each item as a circle sized by {@link LegendItemVisual.size} (pixels) rather than a swatch.
1586
1260
  */
1587
1261
  aesthetics: AestheticKey[];
1588
1262
  /** Title text, null means no title */
@@ -1595,21 +1269,15 @@ export declare interface CompiledLegendGuide {
1595
1269
  items: LegendItem[];
1596
1270
  }
1597
1271
 
1598
- /** The plotting area's frame, telling the renderer which panel border edges to draw and how. */
1272
+ /** The plotting area's frame, telling the renderer whether to draw a border around the panel. */
1599
1273
  export declare interface CompiledPanel {
1600
1274
  /**
1601
- * Panel-rect outline, per edge. Drawn alongside the grid lines and independent of axis
1602
- * visibility. A corner is rounded only when both edges meeting at it are visible.
1275
+ * Panel-rect outline. Drawn alongside the grid lines and independent of axis visibility — an axis can be
1276
+ * hidden while this border still shows (and vice versa).
1603
1277
  */
1604
- border: Record<PanelBorderEdge, CompiledPanelBorderEdge>;
1605
- }
1606
-
1607
- /** One resolved edge of the panel border. */
1608
- export declare interface CompiledPanelBorderEdge {
1609
- isVisible: boolean;
1610
- lineStyle: LineStyleType;
1611
- /** Stroke width in px. null inherits the theme's grid line width. */
1612
- lineWidth: number | null;
1278
+ border: {
1279
+ isVisible: boolean;
1280
+ };
1613
1281
  }
1614
1282
 
1615
1283
  declare interface CompiledPerGroupHeadline {
@@ -1621,9 +1289,9 @@ declare interface CompiledPerGroupHeadline {
1621
1289
  /**
1622
1290
  * Compile-time projection of a pinned-number annotation.
1623
1291
  */
1624
- export declare interface CompiledPinnedNumberAnnotation {
1292
+ declare interface CompiledPinnedNumberAnnotation {
1625
1293
  id: string;
1626
- at: ResolvedObservationPoint;
1294
+ anchor: ResolvedObservationAnchor;
1627
1295
  }
1628
1296
 
1629
1297
  declare interface CompiledPositionAdjuster {
@@ -1661,7 +1329,7 @@ declare type CompiledPositionScaleOptions<Input = DataValue> = Omit<CompiledPosi
1661
1329
  /** Any compiled scale, discriminated by `kind` into position, visual, or identity. */
1662
1330
  export declare type CompiledScale<Input = DataValue> = CompiledPositionScale<Input> | CompiledVisualScale<Input> | CompiledIdentityScale;
1663
1331
 
1664
- /** Shared interface for all compiled scales, regardless of `kind`. */
1332
+ /** Fields shared by every compiled scale, regardless of `kind`. */
1665
1333
  declare interface CompiledScaleBase<Input = DataValue> {
1666
1334
  /** The aesthetic this scale drives (e.g. 'x', 'color'). */
1667
1335
  aesthetic: AestheticKey;
@@ -1672,22 +1340,27 @@ declare interface CompiledScaleBase<Input = DataValue> {
1672
1340
  domain: Input[];
1673
1341
  /** The spec this scale was compiled from. */
1674
1342
  spec: ScaleSpec;
1675
- /** Produces axis/legend tick values. See {@link GenerateTicksOptions} for the supported variants. */
1343
+ /** Produces axis/legend tick values; see {@link GenerateTicksOptions} for the supported variants. */
1676
1344
  generateTicks: (options?: GenerateTicksOptions) => Input[];
1677
1345
  }
1678
1346
 
1679
- /** All compiled scales for a graph, keyed by the aesthetic each one drives. Absent keys are unmapped. */
1347
+ /** All compiled scales for a plot, keyed by the aesthetic each one drives. Absent keys are unmapped. */
1680
1348
  export declare type CompiledScales = Partial<Record<ScaledAestheticKey, CompiledScale>>;
1681
1349
 
1682
1350
  /**
1683
- * Compile-time projection of a rectangle annotation.
1351
+ * Compile-time projection of a freeform rectangle. `x`/`y`/`width`/`height` are normalized
1352
+ * `[0, 1]` of the panel with a top-left origin (no y-flip) — unlike observation anchors, which
1353
+ * are data-space.
1684
1354
  */
1685
1355
  export declare interface CompiledShape {
1686
1356
  id: string;
1687
1357
  kind: ShapeKind;
1688
1358
  /** Whether the shape draws behind the geoms (background) or over them (foreground). */
1689
- zOrder: AnnotationZOrder;
1690
- region: ResolvedRegion;
1359
+ zOrder: ShapeZOrder;
1360
+ x: number;
1361
+ y: number;
1362
+ width: number;
1363
+ height: number;
1691
1364
  fillColor: string;
1692
1365
  fillOpacity: number;
1693
1366
  strokeWidth: number;
@@ -1700,11 +1373,20 @@ export declare interface CompiledShape {
1700
1373
  * renderer paints from. Coords/scales/guides/config/annotations are resolved descriptors; geom data
1701
1374
  * carries its visual values in normalized `[0,1]` position space (y up). See {@link Compiler} for the
1702
1375
  * cross-cutting conventions and {@link LayoutCompiler} for turning this into pixel rects.
1376
+ *
1377
+ * Not serializable: scales hold live `map` closures (see {@link CompiledPositionScale}). Keep a
1378
+ * `CompiledSpec` in memory only — to persist or snapshot, store {@link CompiledSpec.spec} (or the
1379
+ * original {@link CompilerInput}) and recompile.
1380
+ *
1381
+ * Reference stability: each compile returns a fresh top-level object, but a nested slice whose inputs
1382
+ * did not change keeps its prior reference (per-stage memoization). Renderers can therefore subscribe
1383
+ * by reference identity on individual slices (`layers`, `scales`, …) to skip unchanged work.
1703
1384
  */
1704
1385
  export declare interface CompiledSpec {
1705
1386
  /**
1706
1387
  * The resolved spec this output was compiled from, retained so callers can recompile or inspect the
1707
- * source.
1388
+ * source. This is the canonical live {@link Spec} to apply {@link Command}s against — feed a
1389
+ * command's resulting spec back through {@link Compiler.recompile}.
1708
1390
  */
1709
1391
  spec: Spec;
1710
1392
  coordSystem: CoordSystem;
@@ -1715,7 +1397,7 @@ export declare interface CompiledSpec {
1715
1397
  annotations: CompiledAnnotations;
1716
1398
  }
1717
1399
 
1718
- export declare interface CompiledStat {
1400
+ declare interface CompiledStat {
1719
1401
  /** The transformed dataset. */
1720
1402
  data: Dataset;
1721
1403
  /** Any mapping overrides produced by the stat (e.g., `y` → `'count'` for `CountStat`). */
@@ -1723,24 +1405,26 @@ export declare interface CompiledStat {
1723
1405
  }
1724
1406
 
1725
1407
  /**
1726
- * Compile-time projection of a sticker annotation.
1408
+ * Compile-time projection of a sticker annotation, anchored to one observation.
1727
1409
  */
1728
- export declare interface CompiledStickerAnnotation {
1410
+ declare interface CompiledStickerAnnotation {
1729
1411
  id: string;
1730
- at: ResolvedPoint;
1412
+ anchor: ResolvedObservationAnchor;
1731
1413
  sticker: StickerId;
1732
1414
  }
1733
1415
 
1734
1416
  /**
1735
- * Compile-time projection of a text annotation.
1417
+ * Compile-time projection of a text annotation. `x`/`y`/`width` are normalized `[0, 1]` of the
1418
+ * panel with a top-left origin (no y-flip), like `CompiledShape` — panel fractions, not pixels.
1736
1419
  *
1737
1420
  * There is deliberately no height: it is content-intrinsic. The renderer lays out the text within
1738
- * `width` and extends the box's height to fit the content.
1421
+ * `width` and extends the box down to the panel's bottom edge.
1739
1422
  */
1740
1423
  export declare interface CompiledTextAnnotation {
1741
1424
  id: string;
1742
1425
  content: RichTextContent;
1743
- at: ResolvedPoint;
1426
+ x: number;
1427
+ y: number;
1744
1428
  width: number;
1745
1429
  /** Fill behind the text, or `null` for no background. */
1746
1430
  backgroundColor: string | null;
@@ -1755,8 +1439,8 @@ export declare interface CompiledTextAnnotation {
1755
1439
  export declare interface CompiledVisualScale<Input = DataValue> extends CompiledScaleBase<Input> {
1756
1440
  kind: 'visual';
1757
1441
  /**
1758
- * Maps a data value to a concrete visual output (color string, pixel size, opacity etc).
1759
- * Already applied per observation by the visual mapper: read the resolved value via the matching
1442
+ * Maps a data value to a concrete visual output (color string, pixel size, opacity, ).
1443
+ * Already applied per observation by the visual mapper read the resolved value via the matching
1760
1444
  * value reader. Call `map` only for out-of-band values like legend swatches, enumerating the
1761
1445
  * inputs via {@link CompiledScaleBase.domain}.
1762
1446
  */
@@ -1768,38 +1452,42 @@ declare type CompiledVisualScaleOptions<Input = DataValue> = Omit<CompiledVisual
1768
1452
  /**
1769
1453
  * The grammar-of-graphics engine. Orchestrates the compilation of a spec into render-ready output.
1770
1454
  *
1771
- * The full pipeline is:
1455
+ * Start here. The full pipeline a renderer drives is:
1772
1456
  * `{@link CompilerInput} → {@link createCompiler}() → {@link CompiledSpec} → {@link Command}.apply →
1773
1457
  * {@link Compiler.recompile}`. {@link Compiler.compile} resolves the input and runs every stage;
1774
1458
  * {@link Compiler.recompile} re-runs the stages against an already-resolved {@link Spec} (the live
1775
- * {@link CompiledSpec.spec}), which is how a dispatched command reaches the view.
1776
- *
1777
- * Conventions that hold across every compiled output:
1778
- * - Positions are normalized to `[0,1]` with y up: x runs 0=left…1=right, y runs 0=bottom…1=top.
1779
- * A top-origin coordinate space inverts y as `1 - y`. Continuous unclamped scales may extrapolate
1780
- * outside `[0,1]` for out-of-domain inputs.
1781
- * - Output is made of descriptors, not strings: values carry a {@link ValueFormat} and are formatted
1782
- * downstream at paint time (locale stays on the rendering side). Scales are callable `map` functions
1783
- * rather than reconstructable configuration; use value readers to access the raw values.
1784
- * - Pixel layout is a separate step the engine owns: a {@link CompiledSpec} (or its slices) passes
1785
- * through {@link LayoutCompiler} to produce the panel/axis rects; geoms paint in `[0,1]` inside
1786
- * the panel rect.
1459
+ * {@link CompiledSpec.spec}) that is how a dispatched command reaches the view.
1460
+ *
1461
+ * Conventions that hold across every compiled output (so a renderer can be built against this package
1462
+ * alone):
1463
+ * - Positions are normalized to `[0,1]` with **y up**: x runs 0=left…1=right, y runs 0=bottom…1=top.
1464
+ * A top-origin renderer (SVG, canvas) must invert y as `1 - y`. Continuous unclamped scales may
1465
+ * extrapolate outside `[0,1]` for out-of-domain inputs.
1466
+ * - The engine emits **descriptors, not strings**: values carry a {@link ValueFormat} and the renderer
1467
+ * formats them at paint time (locale lives renderer-side). Likewise scales are callable `map`
1468
+ * functions, never D3 config for the renderer to rebuild.
1469
+ * - Pixel layout is a separate step the engine owns too: feed a {@link CompiledSpec} (or its slices)
1470
+ * through {@link LayoutCompiler} to get the plot/panel/axis rects; geoms paint in `[0,1]` inside the
1471
+ * panel rect. Renderers do not reimplement the grid.
1472
+ * - Resolve cross-references **by id**: a layer's scale comes from {@link CompiledSpec.scales} keyed by
1473
+ * aesthetic, its axis from {@link CompiledSpec.guides}; marks key off the layer id.
1787
1474
  *
1788
1475
  * Statefulness: a `Compiler` retains the last dataset seen by {@link Compiler.compile}/{@link Compiler.recompile}
1789
- * and reuses it to derive guides (legends, axes etc).
1790
- * Per-stage memoization and dataset retention are instance-scoped: one `Compiler` is meant to live per
1791
- * graph and be reused across recompiles.
1476
+ * and reuses it to derive guide and legend labels. Call {@link Compiler.compile} (which takes data) at
1477
+ * least once before any {@link Compiler.recompile}({ spec }), otherwise label derivation has no dataset.
1478
+ * Per-stage memoization and dataset retention are instance-scoped, so create one `Compiler` per graph
1479
+ * and reuse it across recompiles rather than building a fresh one per frame.
1792
1480
  *
1793
- * Each layer is processed through the pipeline. Coords and scales are compiled separately as they apply
1794
- * to the entire graph.
1481
+ * Each layer is processed through the pipeline. Coords and scales are compiled separately as they apply to
1482
+ * the entire plot.
1795
1483
  */
1796
1484
  export declare class Compiler {
1797
- private readonly container;
1798
1485
  private readonly dataCompiler;
1799
1486
  private readonly specCompiler;
1800
1487
  private readonly transformCompiler;
1801
1488
  private readonly constantMappingCompiler;
1802
- private readonly layerPhasedCompiler;
1489
+ private readonly layerValidationCheck;
1490
+ private readonly layerCompiler;
1803
1491
  private readonly scaleCompiler;
1804
1492
  private readonly coordCompiler;
1805
1493
  private readonly positionMapperCompiler;
@@ -1810,24 +1498,23 @@ export declare class Compiler {
1810
1498
  private readonly configCompiler;
1811
1499
  private readonly annotationsCompiler;
1812
1500
  private lastCompile;
1813
- private lastDiagnostics;
1814
1501
  private lastData;
1815
1502
  private readonly stages;
1816
- constructor(container: CommonContainer, dataCompiler: DataCompiler, specCompiler: SpecResolver, transformCompiler: TransformCompiler, constantMappingCompiler: ConstantMappingCompiler, layerPhasedCompiler: LayerPhasedCompiler, scaleCompiler: ScaleCompiler, coordCompiler: CoordCompiler, positionMapperCompiler: PositionMapperCompiler, visualMapperCompiler: VisualMapperCompiler, guideCompiler: GuideCompiler, summariseCompiler: SummariseCompiler, highlightsCompiler: HighlightsCompiler, configCompiler: ConfigCompiler, annotationsCompiler: AnnotationsCompiler);
1503
+ constructor(dataCompiler: DataCompiler, specCompiler: SpecResolver, transformCompiler: TransformCompiler, constantMappingCompiler: ConstantMappingCompiler, layerValidationCheck: LayerValidationCheck, layerCompiler: LayerCompiler, scaleCompiler: ScaleCompiler, coordCompiler: CoordCompiler, positionMapperCompiler: PositionMapperCompiler, visualMapperCompiler: VisualMapperCompiler, guideCompiler: GuideCompiler, summariseCompiler: SummariseCompiler, highlightsCompiler: HighlightsCompiler, configCompiler: ConfigCompiler, annotationsCompiler: AnnotationsCompiler);
1817
1504
  /**
1818
1505
  * Resolve `input` (a low-level spec or a high-level GraphConfig) against `data` and run the full
1819
1506
  * pipeline, producing a render-ready {@link CompiledSpec}. The primary entry point for consumers.
1820
1507
  *
1821
1508
  * Routing: reach for `compile` whenever the input or the {@link RendererContext} changes — including
1822
- * a theme or palette switch, since `ctx` is consumed only here ({@link Compiler.recompile} takes
1509
+ * a theme or palette switch, since `ctx` is consumed **only** here ({@link Compiler.recompile} takes
1823
1510
  * no `ctx`). For a data-only or command-driven update prefer {@link Compiler.recompile}, which keeps
1824
- * layer ids stable so id-keyed renderers can transition geoms instead of remounting them.
1511
+ * layer ids stable so id-keyed renderers can transition marks instead of remounting them.
1825
1512
  */
1826
- compile(args: {
1513
+ compile({ input, data, ctx }: {
1827
1514
  input: CompilerInput;
1828
1515
  data: Data;
1829
1516
  ctx?: RendererContext;
1830
- }): CompileResult;
1517
+ }): CompiledSpec;
1831
1518
  /**
1832
1519
  * Run the rendering pipeline against an already-resolved {@link Spec}.
1833
1520
  *
@@ -1838,16 +1525,16 @@ export declare class Compiler {
1838
1525
  * {@link CommandStackManager} is optional — the minimal path is just apply-then-recompile.
1839
1526
  *
1840
1527
  * Requires a prior {@link Compiler.compile} (or recompile-with-data): the retained dataset is what
1841
- * guides (legends, axes etc) are derived from.
1528
+ * guide and legend labels are derived from.
1842
1529
  *
1843
1530
  * When `data` is provided, it is parsed and spliced onto `spec` before the pipeline
1844
1531
  * runs — useful for swapping the dataset without re-resolving the spec, so layer ids
1845
1532
  * survive and id-keyed renderers can transition marks instead of unmounting them.
1846
1533
  */
1847
- recompile(args: {
1534
+ recompile({ spec, data }: {
1848
1535
  spec: Spec;
1849
1536
  data?: Data;
1850
- }): CompileResult;
1537
+ }): CompiledSpec;
1851
1538
  /**
1852
1539
  * Per-stage cache hit/miss counters. Only populated in non-production builds — production builds
1853
1540
  * always report `{ hits: 0, misses: 0 }` because the counter increments tree-shake out.
@@ -1863,18 +1550,6 @@ export declare class Compiler {
1863
1550
  * production builds.
1864
1551
  */
1865
1552
  getLastCompile(): LastCompileSnapshot | null;
1866
- /**
1867
- * Diagnostics (errors and warnings) from the most recent compile/recompile, split by severity.
1868
- */
1869
- getDiagnostics(): DrainedDiagnostics | null;
1870
- /**
1871
- * Owns the diagnostics lifecycle for one compile: reset the collector on entry, run the pipeline,
1872
- * then drain into `lastDiagnostics` on the success tail. A throw escapes before the drain, leaving
1873
- * the collector populated for {@link toErrorResult} — the single failure-drain site.
1874
- */
1875
- private runCompile;
1876
- private toOkResult;
1877
- private toErrorResult;
1878
1553
  private trackCompile;
1879
1554
  private runPipeline;
1880
1555
  }
@@ -1890,27 +1565,13 @@ export declare const COMPILER_STAGE_KEYS: readonly ["data", "transform", "consta
1890
1565
  */
1891
1566
  export declare type CompilerCacheStats = Record<CompilerStageName, MemoStats>;
1892
1567
 
1893
- /**
1894
- * Result of {@link Compiler.compile} / {@link Compiler.recompile}. A success carries the compiled
1895
- * spec; a failure carries `errors` (always a list — length 1 for a fail-fast stage, length N for
1896
- * batched validation). Both carry any `warnings` the compile produced.
1897
- */
1898
- export declare type CompileResult = {
1899
- ok: true;
1900
- compiled: CompiledSpec;
1901
- warnings: VizDiagnostic[];
1902
- } | {
1903
- ok: false;
1904
- errors: VizDiagnostic[];
1905
- warnings: VizDiagnostic[];
1906
- };
1907
-
1908
1568
  /**
1909
1569
  * Any value accepted by {@link Compiler.compile}: a low-level {@link SpecInput} or a
1910
1570
  * high-level {@link GraphConfig}. Data is passed as a separate argument.
1911
1571
  */
1912
1572
  export declare type CompilerInput = SpecInput | GraphConfig;
1913
1573
 
1574
+ /** Identifier of a single compile pipeline stage, used to key the per-stage cache counters. */
1914
1575
  declare type CompilerStageName = (typeof COMPILER_STAGE_KEYS)[number];
1915
1576
 
1916
1577
  /** A difference arrow ready to paint: SVG paths, label text and box styling, all in panel-local pixel space. */
@@ -1921,7 +1582,7 @@ export declare interface ComputedDifferenceArrow {
1921
1582
  /** SVG path for the arrowhead. */
1922
1583
  arrowheadPath: string;
1923
1584
  /**
1924
- * Pixel position of the label box center. The engine does not size the box: measure `labelText`
1585
+ * Pixel position of the label box CENTER. The engine does not size the box: measure `labelText`
1925
1586
  * yourself, then box width = measured width + `2·labelPaddingX` and box height =
1926
1587
  * `labelLineHeight + 2·labelPaddingY`.
1927
1588
  */
@@ -1950,7 +1611,10 @@ export declare interface ComputedDifferenceArrow {
1950
1611
  * A freeform arrow ready to paint: SVG paths plus stroke/dash styling, all in panel-local pixel space.
1951
1612
  *
1952
1613
  * Sticker rendering (`hasStickerStyle`): paint the union of the three path strings (`linePath`,
1953
- * `startArrowheadPath`, `endArrowheadPath`) as one shape with a light outline and a drop shadow.
1614
+ * `startArrowheadPath`, `endArrowheadPath`) as one shape with a light outline and a drop shadow. The
1615
+ * outline and shadow extend past the geometry, so the drop-shadow filter region must be inflated on
1616
+ * every side by `arrowheadExtent + strokeWidth + outlineWidth + blurRadius` to avoid clipping at the
1617
+ * arrowheads (the last two are renderer-owned).
1954
1618
  */
1955
1619
  export declare interface ComputedFreeformArrow {
1956
1620
  id: string;
@@ -1960,7 +1624,7 @@ export declare interface ComputedFreeformArrow {
1960
1624
  startArrowheadPath: string;
1961
1625
  /** SVG path for the end arrowhead or '' when there is none. */
1962
1626
  endArrowheadPath: string;
1963
- /** Resolved color or `null` to fall back to the theme `defaultAnnotationArrowStroke` token. */
1627
+ /** Resolved color, or `null` to fall back to the theme `defaultAnnotationArrowStroke` token. */
1964
1628
  color: string | null;
1965
1629
  strokeWidth: number;
1966
1630
  /** SVG `stroke-dasharray` or `null` for a solid line. */
@@ -1990,11 +1654,14 @@ export declare const computeDifferenceArrow: ({ arrow, mainAxis, panelWidth, pan
1990
1654
 
1991
1655
  declare interface ComputeDifferenceArrowParams {
1992
1656
  arrow: CompiledDifferenceArrow;
1993
- /** Graph orientation. When `y` the arrow geometry is flipped to run horizontally. */
1657
+ /**
1658
+ * Chart orientation — `CartesianCoordSystem.mainAxis`. When `'y'` the arrow geometry is flipped to
1659
+ * run horizontally. Pass `'x'` for a polar coord system.
1660
+ */
1994
1661
  mainAxis: 'x' | 'y';
1995
1662
  panelWidth: number;
1996
1663
  panelHeight: number;
1997
- /** Graph-wide text scale. */
1664
+ /** Graph-wide text scale, applied to the label so it sizes with the rest of the chart. */
1998
1665
  textScale: number;
1999
1666
  locale: Locale;
2000
1667
  }
@@ -2025,15 +1692,6 @@ declare interface ComputeFreeformArrowParams {
2025
1692
  panelHeight: number;
2026
1693
  }
2027
1694
 
2028
- /**
2029
- * Computes the strokes for a panel border with per-edge visibility, line style and width.
2030
- * A corner is rounded only when both of its edges are visible; edges sharing a style and width
2031
- * join through the full corner arc, while differing ones split the arc at its midpoint. Returns
2032
- * one path per contiguous same-styled run of visible edges — a single closed path when all four
2033
- * match, empty when every edge is hidden.
2034
- */
2035
- export declare const computePanelBorderPaths: (border: CompiledPanel["border"], rect: Rect, cornerRadius: number) => PanelBorderPath[];
2036
-
2037
1695
  /** Wraps partial config options into a tagged `ConfigItem` for inclusion in a spec. */
2038
1696
  export declare function config(options: ConfigInput): ConfigItem;
2039
1697
 
@@ -2041,8 +1699,6 @@ export declare function config(options: ConfigInput): ConfigItem;
2041
1699
  * Compiles config input into a render-ready CompliledConfig object.
2042
1700
  */
2043
1701
  declare class ConfigCompiler extends Stage<ConfigCompilerInput, CompiledConfig> {
2044
- private readonly container;
2045
- constructor(container: CommonContainer);
2046
1702
  protected dependencies(input: ConfigCompilerInput): readonly unknown[];
2047
1703
  protected run(input: ConfigCompilerInput): CompiledConfig;
2048
1704
  }
@@ -2072,9 +1728,9 @@ declare interface ConfigItem {
2072
1728
  */
2073
1729
  export declare interface ConfigSpec {
2074
1730
  /**
2075
- * Locale used to interpret source values and, by default, to format display
1731
+ * Locale used to interpret source values AND, by default, to format display
2076
1732
  * output (axis labels, tooltips, numbers). Pass `formattingLocale` to a
2077
- * `format*` helper to override display only. It resolves to
1733
+ * `format*` helper to override display only it resolves
2078
1734
  * `formattingLocale ?? parsingLocale`. The `duration` format is always
2079
1735
  * English regardless of locale.
2080
1736
  */
@@ -2247,7 +1903,7 @@ declare type ContinuousScaleSpec = Required<ContinuousScaleInput>;
2247
1903
  */
2248
1904
  export declare function convertSpecToInput(spec: Spec): SpecInput;
2249
1905
 
2250
- /** Builders for the graph's coordinate system. Pass the result as the spec's `coord` to choose cartesian, flipped, or polar. */
1906
+ /** Builders for the chart's coordinate system. Pass the result as the spec's `coord` to choose cartesian, flipped, or polar. */
2251
1907
  export declare const coord: {
2252
1908
  /**
2253
1909
  * Standard cartesian (x-y) coordinate system. This is the default if no coord is specified.
@@ -2342,15 +1998,14 @@ declare interface CoordStrategy {
2342
1998
  * Render-ready coordinate system (discriminated union).
2343
1999
  * Discriminates on geometric paradigm: cartesian plane vs polar projection.
2344
2000
  *
2345
- * The same geom renders differently per coord: a bar is a rect in cartesian and an arc in polar.
2001
+ * A mark's geometry is the `(geom, coordSystem.type)` pair, not the geom alone: the same geom
2002
+ * renders differently per coord — a bar is a rect in cartesian and an arc in polar.
2346
2003
  */
2347
2004
  export declare type CoordSystem = CartesianCoordSystem | PolarCoordSystem;
2348
2005
 
2349
- /** What a {@link CoordStrategy} receives during the transform pass — the coord spec, resolved coord system, and position-mapped layers. */
2006
+ /** What a {@link CoordStrategy} receives during the transform pass — the coord spec and position-mapped layers. */
2350
2007
  declare interface CoordTransformInput {
2351
2008
  coordSpec: CoordSpec;
2352
- /** The coord system resolved by {@link CoordStrategy.setup}, so the transform reuses its resolved angles (e.g. polar `startAngle`/`spokeRotation`) rather than re-deriving them. */
2353
- coordSystem: CoordSystem;
2354
2009
  layers: CompiledLayer[];
2355
2010
  }
2356
2011
 
@@ -2361,7 +2016,7 @@ declare interface CoordTransformInput {
2361
2016
  * - `'polar'` — Polar coordinates for pie, radar, and radial charts
2362
2017
  * - `'flip'` — Cartesian with x and y axes swapped
2363
2018
  */
2364
- export declare type CoordType = 'cartesian' | 'polar' | 'flip';
2019
+ declare type CoordType = 'cartesian' | 'polar' | 'flip';
2365
2020
 
2366
2021
  declare function count(): CountStatSpec;
2367
2022
 
@@ -2392,7 +2047,7 @@ export declare const createColorValueReader: (data: Dataset, mapping: AesMapping
2392
2047
 
2393
2048
  /**
2394
2049
  * Builds a {@link Compiler} with all built-in stages and registries wired together. The standard
2395
- * entry point for consumers. Use this rather than constructing `Compiler` by hand.
2050
+ * entry point for consumers; use this rather than constructing `Compiler` by hand.
2396
2051
  *
2397
2052
  * The returned {@link Compiler} is the head of the pipeline
2398
2053
  * (`{@link CompilerInput} → createCompiler() → {@link CompiledSpec} → {@link Command}.apply →
@@ -2400,52 +2055,13 @@ export declare const createColorValueReader: (data: Dataset, mapping: AesMapping
2400
2055
  * Because the compiler is stateful (retains the last dataset, memoizes per stage), create one
2401
2056
  * instance per graph and reuse it across recompiles instead of calling `createCompiler` each frame.
2402
2057
  */
2403
- export declare const createCompiler: ({ plugins }?: CreateCompilerOptions) => Compiler;
2404
-
2405
- /** Options for {@link createCompiler}. */
2406
- export declare interface CreateCompilerOptions {
2407
- /**
2408
- * Custom geoms, stats, and transforms to register alongside the built-ins. A render half
2409
- * (react-renderer's `GeomRendererDefinition`) is accepted too — its compile definition is read
2410
- * structurally from `.definition`, so the engine never imports a React type. A by-name render-only
2411
- * override carries no compile definition and is skipped here, leaving the built-in compile half
2412
- * intact. Built-ins seed first, then these in array order (last-in-array wins).
2413
- */
2414
- plugins?: readonly Plugin_2[];
2415
- }
2416
-
2417
- /**
2418
- * Builds the recurring layout-geom dataset shape — several observation kinds (node+flow, group+leaf,
2419
- * node+edge) in one columnar dataset, discriminated by a `kind` column — from per-kind observation groups.
2420
- * Owns the null-padding-by-construction invariant a hand-built version is easy to get wrong: every column
2421
- * any group declares exists on every observation, null where a kind doesn't carry it.
2422
- *
2423
- * Column order is the kind column first, then columns in first-seen order. Each column's `DataType`
2424
- * is inferred from its first non-null value (numeric/temporal/categorical), defaulting to categorical
2425
- * for an all-null column.
2426
- */
2427
- export declare function createDatasetFromKindPartitions(groups: readonly KindPartition[], kindColumn?: VariableName): Dataset;
2058
+ export declare const createCompiler: () => Compiler;
2428
2059
 
2429
2060
  /**
2430
- * Fresh empty highlight state for a layer of the given geom, or `null` when the geom opts out of
2431
- * highlighting. A custom geom (a name outside the built-in strategy table) opts out for now — the
2432
- * built-in highlight strategies don't yet read the declared `Geom.highlightStrategy`.
2061
+ * Fresh empty highlight state for a layer of the given geom, or `null` when the geom opts
2062
+ * out of highlighting (no entry in `HIGHLIGHT_STRATEGY_BY_GEOM`).
2433
2063
  */
2434
- export declare function createEmptyHighlight(geom: string): CompiledLayerHighlight | null;
2435
-
2436
- /**
2437
- * Build the authoring surface from a `plugins` array — the headless/advanced primitive that
2438
- * `createGraphyKit` (react-renderer) wraps. Pass the same array to `createCompiler` so the writable
2439
- * surface and the compilable surface cannot diverge. The `const` type parameter captures the tuple
2440
- * literally, so each def's `type`/`aes`/`params` flow into its generated builder method.
2441
- */
2442
- export declare function createGraphyBuilder<const P extends readonly Plugin_2[] = []>(options?: CreateGraphyBuilderOptions<P>): GraphyBuilder<P>;
2443
-
2444
- /** Options for {@link createGraphyBuilder}. */
2445
- export declare interface CreateGraphyBuilderOptions<P extends readonly Plugin_2[] = readonly Plugin_2[]> {
2446
- /** Custom geoms/stats/transforms (and render halves, read via `.definition`) the authored spec may use. */
2447
- plugins?: P;
2448
- }
2064
+ export declare function createEmptyHighlight(geom: GeomName): CompiledLayerHighlight | null;
2449
2065
 
2450
2066
  /** Reader for the raw value behind a layer's `group` mapping. */
2451
2067
  export declare const createGroupValueReader: (data: Dataset, mapping: AesMapping) => RawValueReader;
@@ -2461,8 +2077,6 @@ export declare const createHeadlineItemRows: (item: FormattedHeadlineItem) => He
2461
2077
  /** Reader for the raw value behind a layer's `label` mapping. */
2462
2078
  export declare const createLabelValueReader: (data: Dataset, mapping: AesMapping) => RawValueReader;
2463
2079
 
2464
- export declare const createLineFillAreaGenerator: (params: LineGeomParams) => Area<Observation>;
2465
-
2466
2080
  export declare const createLinePathGenerator: (params: LineGeomParams) => Line<Observation>;
2467
2081
 
2468
2082
  /**
@@ -2478,7 +2092,7 @@ export declare const createRawValueReader: (data: Dataset, aestheticValue: Aesth
2478
2092
  /**
2479
2093
  * Per-observation reader for the segment-y value of a compiled layer, in original data units.
2480
2094
  *
2481
- * When the layer is stacked, the y position variables already hold cumulative band bounds (draw
2095
+ * When the layer is stacked, the y position columns already hold cumulative band bounds (draw
2482
2096
  * segments directly) — so for a label or tooltip showing the segment's own value, use this reader,
2483
2097
  * not {@link getY} (which is normalized to `[0, 1]`). It auto-selects `yRaw` for stacked layers and
2484
2098
  * the user's y mapping otherwise.
@@ -2489,31 +2103,20 @@ export declare function createSegmentYReader(layer: CompiledLayer): (observation
2489
2103
  export declare const createSizeValueReader: (data: Dataset, mapping: AesMapping) => RawValueReader;
2490
2104
 
2491
2105
  /**
2492
- * Seed a spec the entry point for every chart. The first argument may be a bare {@link AesMapping}
2493
- * (`{ x, y, color, ... }`), which becomes the spec's global aesthetic mapping; any further arguments are
2494
- * pipeable spec items (geoms, scales, coords, transforms, config, ...) folded on in order.
2495
- *
2496
- * This is the builder pattern: `createSpec` seeds the mapping, then `pipe` (or extra args here) folds each
2497
- * item onto an immutable spec, accumulating layers/scales/etc. Always declare `scale.x()` / `scale.y()` for
2498
- * any position mapping — they are NOT auto-inferred and yield NaN positions if omitted.
2499
- *
2500
- * @example
2501
- * import { createSpec, pipe, geom, scale } from '@graphysdk/viz-engine';
2502
- *
2503
- * // Most common: mapping first, then pipe the rest.
2504
- * const spec = pipe(createSpec({ x: 'category', y: 'revenue' }), geom.bar(), scale.x(), scale.y());
2106
+ * Create a new spec, optionally piping spec items in one call. Data is passed separately
2107
+ * to {@link compile}.
2505
2108
  *
2506
2109
  * @example
2507
- * import { createSpec, transform, mapping, geom, scale } from '@graphysdk/viz-engine';
2110
+ * When the first arg is a mapping:
2111
+ * createSpec({ x: 'date', y: 'value' })
2508
2112
  *
2509
- * // All-in-one form, clearer when a transform must run before the mapping is read.
2510
- * const spec = createSpec(
2511
- * transform.reshape({ reshape: ['revenue'], keyName: 'metric', valueName: 'amount' }),
2512
- * mapping({ x: 'month', y: 'amount', color: 'metric' }),
2513
- * geom.bar(),
2514
- * scale.x(),
2515
- * scale.y(),
2516
- * );
2113
+ * When piping spec items (more readable when chaining transforms):
2114
+ * createSpec(
2115
+ * transform.reshape({ reshape: ['revenue'], keyName: 'metric', valueName: 'amount' }),
2116
+ * mapping({ x: 'month', y: 'amount', color: 'metric' }),
2117
+ * geom.bar(),
2118
+ * scale.x(),
2119
+ * )
2517
2120
  */
2518
2121
  export declare function createSpec(...items: Array<AesMapping | SpecItem>): SpecInput;
2519
2122
 
@@ -2527,6 +2130,10 @@ export declare const createStrokeWidthValueReader: (data: Dataset, mapping: AesM
2527
2130
  * locale and number-format config) into a reusable {@link ValueFormatter}. A renderer materializing a
2528
2131
  * `valueFormat` it pulled off a compiled guide/legend/headline goes through here rather than
2529
2132
  * branching on `type` itself.
2133
+ *
2134
+ * Dispatches on `valueFormat.type` and throws on an unknown kind (so a newly added format surfaces
2135
+ * loudly instead of silently formatting wrong). A `lookup` formatter needs the per-call `Observation`
2136
+ * to pick its case — see {@link ValueFormatter}; every other kind ignores the observation.
2530
2137
  */
2531
2138
  export declare const createValueFormatter: (params: ValueFormatterFactoryParams) => ValueFormatter;
2532
2139
 
@@ -2544,45 +2151,6 @@ declare interface CurrencyValueFormat {
2544
2151
  iso: CurrencyIso;
2545
2152
  }
2546
2153
 
2547
- /**
2548
- * Scales a plot-local cursor `(x, y)` in data-space `[0, 1]²` into the pie-local unit disk (centre
2549
- * `(0, 0)`, outer radius `1`), undoing the aspect ratio so the disk is inscribed in the shorter panel
2550
- * dimension and centred. In the returned frame `y` is up, so a vertex at `(angle, radius)` sits at
2551
- * {@link polarToUnit}`(angle, radius)`. Every polar query shares this one correction.
2552
- */
2553
- export declare const cursorToPiePlane: (cursor: HoverCursor, aspectRatio: number) => XYPoint;
2554
-
2555
- /** Converts a plot-local cursor into polar `(angle, radius)` in the inscribed-disk frame. */
2556
- export declare const cursorToPolar: (cursor: HoverCursor, aspectRatio: number) => {
2557
- angle: number;
2558
- radius: number;
2559
- };
2560
-
2561
- /**
2562
- * A builder method per custom geom def, keyed on its `type`. `& string` keeps the remap key legal; if
2563
- * the def's `type` widened to `string` (no `as const`), the method lands under an index signature
2564
- * instead of a named key — still usable, just unkeyed (C3).
2565
- */
2566
- declare type CustomGeomBuilders<P extends readonly Plugin_2[]> = {
2567
- [Def in GeomDefsOf<P> as Def['type'] & string]: (options?: GeomBuilderOptions<Def>) => CustomGeomLayerInput;
2568
- };
2569
-
2570
- /**
2571
- * A layer for a custom (plugin-contributed) geom. Its `geom` is a name outside {@link GeomName},
2572
- * resolved downstream through the geom registry; `params` are validated at the typed builder call
2573
- * site, so the node itself carries them as an open record.
2574
- */
2575
- export declare interface CustomGeomLayerInput extends LayerInputBase {
2576
- geom: string;
2577
- params?: Record<string, unknown>;
2578
- }
2579
-
2580
- /** A resolved layer spec for a custom geom — the {@link CustomGeomLayerInput} counterpart. */
2581
- export declare interface CustomGeomLayerSpec extends LayerSpecBase {
2582
- geom: string;
2583
- params: Record<string, unknown>;
2584
- }
2585
-
2586
2154
  /** A single named color slot within a custom palette supplied by the renderer. */
2587
2155
  export declare type CustomPaletteColor = {
2588
2156
  id: string;
@@ -2605,33 +2173,6 @@ declare type CustomPaletteInput = {
2605
2173
  /** Renderer-owned custom palettes, keyed by `paletteId`, that a GraphConfig may reference by id. */
2606
2174
  export declare type CustomPalettesInput = Record<string, CustomPaletteColor[]>;
2607
2175
 
2608
- declare type CustomStatBuilders<P extends readonly Plugin_2[]> = {
2609
- [Def in StatDefsOf<P> as Def['type'] & string]: () => CustomStatInput<Def['type'] & string>;
2610
- };
2611
-
2612
- /**
2613
- * The input node a custom (plugin-contributed) stat builder produces.
2614
- */
2615
- export declare interface CustomStatInput<Name extends string = string> {
2616
- type: Name;
2617
- }
2618
-
2619
- declare type CustomTransformBuilders<P extends readonly Plugin_2[]> = {
2620
- [Def in TransformDefsOf<P> as Def['transformType'] & string]: (options?: TransformBuilderOptions) => CustomTransformInput<Def['transformType'] & string>;
2621
- };
2622
-
2623
- /***************************************************************
2624
- * Transform Input
2625
- ***************************************************************/
2626
- /**
2627
- * The input node a custom (plugin-contributed) transform builder produces.
2628
- */
2629
- export declare interface CustomTransformInput<Name extends string = string> {
2630
- type: 'transform';
2631
- transformType: Name;
2632
- options?: Record<string, unknown>;
2633
- }
2634
-
2635
2176
  /**
2636
2177
  * Data to visualize. Structured as a table.
2637
2178
  *
@@ -2658,14 +2199,6 @@ export declare interface Data {
2658
2199
  /* Excluded from this release type: _metadata */
2659
2200
  }
2660
2201
 
2661
- /**
2662
- * Padding folded into `measureDataLabel`'s `(width, height)` so the engine sees the rendered
2663
- * box dimensions, not raw text metrics. Stack totals carry a tighter pill than per-observation labels.
2664
- */
2665
- export declare const DATA_LABEL_PADDING_X_PX = 6;
2666
-
2667
- export declare const DATA_LABEL_PADDING_Y_PX = 2;
2668
-
2669
2202
  /**
2670
2203
  * Parses raw `Data` into a typed {@link Dataset}. Swapping the `Data` reference triggers
2671
2204
  * a re-parse; repeated compiles against the same reference short-circuit. The orchestrator decides
@@ -2676,25 +2209,6 @@ declare class DataCompiler extends Stage<Data, Dataset> {
2676
2209
  protected run(input: Data): Dataset;
2677
2210
  }
2678
2211
 
2679
- /**
2680
- * Anchor along one axis of the geom's box, CSS-flexbox style. `justify` runs along the value
2681
- * axis — `'end'` is the value tip whatever the orientation or sign (e.g. the bottom of a negative
2682
- * column). `align` runs across it: bandwidth for bars, angular for pie wedges, x for
2683
- * point/line/area.
2684
- */
2685
- export declare type DataLabelAnchor = 'start' | 'center' | 'end';
2686
-
2687
- export declare interface DataLabelDimensions {
2688
- /** Font size in pixels. Box height = text height + `2·paddingY`. */
2689
- fontSize: number;
2690
- /** Font weight for the label text (CSS numeric weight). */
2691
- fontWeight: number;
2692
- /** Horizontal label padding (each of left + right). */
2693
- paddingX: number;
2694
- /** Vertical label padding (each of top + bottom). */
2695
- paddingY: number;
2696
- }
2697
-
2698
2212
  /**
2699
2213
  * Discriminator for which on-canvas typography a strategy is measuring against. The renderer
2700
2214
  * owns the actual `FontSpec` for each kind — the engine only names the kind so the renderer's
@@ -2702,23 +2216,6 @@ export declare interface DataLabelDimensions {
2702
2216
  */
2703
2217
  export declare type DataLabelKind = 'dataLabel' | 'stackTotal';
2704
2218
 
2705
- /**
2706
- * Where data labels sit relative to the geom they decorate.
2707
- * - `'auto'` — the engine chooses: fit inside, flip outside, drop or rotate as needed.
2708
- * `justify`/`align` are ignored.
2709
- * - `'inside'` — within the geom's box, hugging the `(justify, align)` anchor. Never dropped,
2710
- * flipped or rotated. On line/point geoms the label centres on the data point/marker.
2711
- * - `'outside'` — just past the value-axis edge selected by `justify`; `align` stays within the
2712
- * geom's width (line/point labels sit beside the geom). Never dropped. Stacked/filled cartesian
2713
- * bar segments coerce to `'inside'` — every segment edge borders a neighbour; use
2714
- * `showStackTotals` for stack-end totals. (Pie wedges keep `'outside'`.)
2715
- *
2716
- * Styling follows the label's effective position: over the geom → inside styling (white text,
2717
- * no plate); off it — by placement, offset, or not fitting — outside styling (dark text on a
2718
- * plate). Area labels always use the plated styling: the translucent fill can't back white text.
2719
- */
2720
- export declare type DataLabelPlacement = 'auto' | 'inside' | 'outside';
2721
-
2722
2219
  /**
2723
2220
  * Where a label sits relative to the geom or stack it decorates. Independent of `target`.
2724
2221
  * - `inside` — over the geom; renderer paints white text without a plate.
@@ -2730,7 +2227,7 @@ declare interface DataLabels {
2730
2227
  showDataLabels?: boolean;
2731
2228
  /** Whether labels show raw values or each point's share of its stack/total. */
2732
2229
  dataLabelFormat?: 'absolute' | 'percentage';
2733
- /** Shows the summed total above each stack in stacked graphs. */
2230
+ /** Shows the summed total above each stack in stacked charts. */
2734
2231
  showStackTotals?: boolean;
2735
2232
  showCategoryLabels?: boolean;
2736
2233
  }
@@ -2764,27 +2261,6 @@ export declare interface DataLabelsConfig {
2764
2261
  * @default { variable: POSITION_VARIABLES.yRaw }
2765
2262
  */
2766
2263
  labelSource: AestheticValue;
2767
- /**
2768
- * Where labels sit relative to the geom. Explicit values render exactly as asked; dropping,
2769
- * flipping and rotation happen only under `'auto'`.
2770
- * @default 'auto'
2771
- */
2772
- position: DataLabelPlacement;
2773
- /**
2774
- * Anchor along the geom's value/growth axis. Only consulted when `position` is explicit.
2775
- * @default 'end' ('center' for stacked/filled bars)
2776
- */
2777
- justify: DataLabelAnchor;
2778
- /**
2779
- * Anchor across the geom's secondary axis. Only consulted when `position` is explicit.
2780
- * @default 'center'
2781
- */
2782
- align: DataLabelAnchor;
2783
- /**
2784
- * Gap in pixels between the geom's edge and the label box. Stack totals ignore it.
2785
- * @default 4 for bars and polar wedges, 12 for point/line/area
2786
- */
2787
- offset: number;
2788
2264
  }
2789
2265
 
2790
2266
  /**
@@ -2811,7 +2287,7 @@ export declare type DataLabelTarget = 'observation' | 'aggregate';
2811
2287
  * Renderer-supplied measurer that knows which font to apply for each `DataLabelKind`. Lets
2812
2288
  * placement strategies measure text without the engine ever holding a `FontSpec`.
2813
2289
  *
2814
- * Must return the final plate size — text metrics plus the renderer's own padding. The engine
2290
+ * Must return the FINAL plate size — text metrics plus the renderer's own padding. The engine
2815
2291
  * treats the returned `width`/`height` as the plate dimensions (`PlacedDataLabel.width`/`height`)
2816
2292
  * and does not add padding of its own.
2817
2293
  */
@@ -2871,14 +2347,6 @@ export declare class Dataset {
2871
2347
  * Adds a new constant variable to the dataset. Format resolution follows {@link addVariable}.
2872
2348
  */
2873
2349
  addConstantVariable(variable: VariableName, type: DataType, value: DataValue, valueFormat?: ValueFormat): Dataset;
2874
- /**
2875
- * Returns the source literal a variable was materialised from via {@link addConstantVariable},
2876
- * or undefined if it isn't a recorded constant. The returned wrapper distinguishes a constant
2877
- * whose value is `null` (wrapper present) from a non-constant variable (undefined).
2878
- */
2879
- getConstant(variable: VariableName): {
2880
- value: DataValue;
2881
- } | undefined;
2882
2350
  /**
2883
2351
  * Derives a new variable based on existing variables, using a table expression. If `valueFormat`
2884
2352
  * is omitted, a type-based default is used.
@@ -3096,24 +2564,14 @@ declare interface DatetimeTickInterval {
3096
2564
 
3097
2565
  declare type DatetimeTickIntervalUnit = 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';
3098
2566
 
3099
- /**
3100
- * The aes keys a geom's declared `aesthetics` contributes — its visual + data channel names, only when
3101
- * declared `as const`. The widened base type (`readonly GeomAesthetic[]`) contributes nothing, so a
3102
- * position-only geom isn't silently opened to every aesthetic.
3103
- */
3104
- declare type DeclaredAesKeys<Def extends Geom<unknown>> = IsWidenedTuple<Def['aesthetics']> extends true ? never : Def['aesthetics'][number]['name'];
3105
-
3106
2567
  /**
3107
2568
  * Recursively makes every property of `T` optional.
3108
2569
  * Unlike the built-in `Partial`, this applies to nested objects as well.
3109
2570
  */
3110
2571
  declare type DeepPartial<T> = {
3111
- [K in keyof T]?: T[K] extends Array<infer U> ? Array<DeepPartial<U>> : unknown extends T[K] ? T[K] : NonNullable<T[K]> extends object ? DeepPartial<NonNullable<T[K]>> : T[K];
2572
+ [K in keyof T]?: T[K] extends Array<infer U> ? Array<DeepPartial<U>> : NonNullable<T[K]> extends object ? DeepPartial<NonNullable<T[K]>> : T[K];
3112
2573
  };
3113
2574
 
3114
- /** Series colors used when a chart specifies no palette. Cycled in order as series count grows. */
3115
- export declare const DEFAULT_COLOR_PALETTE: string[];
3116
-
3117
2575
  /**
3118
2576
  * Default font style.
3119
2577
  */
@@ -3135,93 +2593,6 @@ declare type DefaultPaletteConfig = {
3135
2593
  type: 'default';
3136
2594
  };
3137
2595
 
3138
- /**
3139
- * Recover the compile definition from a plugin. A render half (react-renderer's
3140
- * `GeomRendererDefinition`) carries its compile definition at `.definition`; a bare definition is its
3141
- * own. The engine reads this structurally so it never imports a React type.
3142
- */
3143
- export declare type DefinitionOf<T> = T extends {
3144
- definition: infer D;
3145
- } ? D : T;
3146
-
3147
- /**
3148
- * Every compile definition contributed by the `plugins` tuple. A render half carries its definition
3149
- * at `.definition` (recovered by {@link DefinitionOf}); a render-only override carries none and is
3150
- * dropped here, because `Extract<…, CompileDefinition>` excludes its `{ geom; render }` shape — so it
3151
- * contributes no builder method.
3152
- */
3153
- declare type DefsOf<P extends readonly Plugin_2[]> = Extract<DefinitionOf<P[number]>, CompileDefinition>;
3154
-
3155
- /**
3156
- * Conventional `context` keys. A diagnostic's `context` is free-form `Record<string, JsonValue>`,
3157
- * but emitters draw from this vocabulary so consumers can rely on consistent keys per code rather
3158
- * than parsing prose:
3159
- *
3160
- * - `layerIndex` — index of the offending layer
3161
- * - `aesthetic` — the aesthetic channel (`x`, `y`, `color`, …)
3162
- * - `variableName` — the offending data variable
3163
- * - `scaleType` — the scale type involved
3164
- * - `variableType` — the data type of the offending variable
3165
- * - `expected` / `actual` — the required vs. supplied value
3166
- * - `requested` / `available` — an unknown/duplicate registered type and the registered alternatives
3167
- * - `kind` — the registry or resolver label for a registration diagnostic (`UNKNOWN_REGISTERED_TYPE`,
3168
- * `DUPLICATE_REGISTERED_TYPE`, `MISSING_GEOM_RENDERER`)
3169
- */
3170
- declare const DIAGNOSTIC_CONTEXT_KEYS: readonly ["layerIndex", "aesthetic", "variableName", "scaleType", "variableType", "expected", "actual", "requested", "available", "kind"];
3171
-
3172
- /**
3173
- * Structured location + repair atoms carried by an error or diagnostic. Keys are constrained to the
3174
- * {@link DIAGNOSTIC_CONTEXT_KEYS} vocabulary, so the contract codegen binds to is compiler-checked
3175
- * at every emit site — a typo or an ad-hoc key is a type error here, not a silent drift that breaks
3176
- * a downstream consumer. Values are {@link JsonValue} so a diagnostic stays serialisable end-to-end.
3177
- */
3178
- export declare type DiagnosticContext = Partial<Record<DiagnosticContextKey, JsonValue>>;
3179
-
3180
- /** A key from the documented {@link DIAGNOSTIC_CONTEXT_KEYS} vocabulary. */
3181
- export declare type DiagnosticContextKey = (typeof DIAGNOSTIC_CONTEXT_KEYS)[number];
3182
-
3183
- /**
3184
- * The human- and machine-readable core every error and diagnostic shares: a `message`, optional
3185
- * structured `context` atoms, and an optional repair `suggestion`. The `severity`/`kind`/`code` axes
3186
- * are layered on by {@link VizDiagnostic}, and `cause` by {@link VizErrorOptions} — so the producer
3187
- * surface has one core shape rather than three overlapping ones.
3188
- */
3189
- export declare interface DiagnosticDetails {
3190
- /** Human-readable description of what went wrong. */
3191
- message: string;
3192
- /** Serialisable location + repair atoms, drawn from the documented key vocabulary. */
3193
- context?: DiagnosticContext;
3194
- /** Repair hint for a human or an LLM. Advisory prose, not part of the stable contract. */
3195
- suggestion?: string;
3196
- }
3197
-
3198
- /**
3199
- * Chart-scoped sink for diagnostics produced during one compile.
3200
- *
3201
- * Holds warnings *and* the validator's batched errors; `drain` splits them by severity.
3202
- */
3203
- declare class DiagnosticsCollector {
3204
- private diagnostics;
3205
- private persistent;
3206
- /**
3207
- * Record an advisory user-input diagnostic — a fixable problem that degraded gracefully.
3208
- *
3209
- * A `persistent` warning survives {@link reset} and resurfaces in every {@link drain} — a
3210
- * chart-level condition true for the collector's whole life (e.g. a plugin registration collision),
3211
- * so it is surfaced on every compile without being re-emitted. A normal warning is cleared each
3212
- * compile.
3213
- */
3214
- addWarning(issue: UserInputIssue, options?: {
3215
- persistent?: boolean;
3216
- }): void;
3217
- /** Record a fatal user-input diagnostic — used by validators that collect every problem before throwing. */
3218
- addError(issue: UserInputIssue): void;
3219
- /** Clear the per-compile diagnostics. Called at the start of each compile; persistent ones survive. */
3220
- reset(): void;
3221
- /** Return the accumulated diagnostics (persistent + this compile's) split by severity, deduped. */
3222
- drain(): DrainedDiagnostics;
3223
- }
3224
-
3225
2596
  declare interface DifferenceArrowDimensions {
3226
2597
  /** Gap between the arrow start point and its anchored observation. */
3227
2598
  arrowStartGap: number;
@@ -3263,7 +2634,7 @@ export declare interface DifferenceArrowInput {
3263
2634
  /** null falls back to a theme default. */
3264
2635
  color?: string | null;
3265
2636
  size?: DifferenceArrowSize;
3266
- /** AnchorOffset of the label along the arrow, as a fraction of the arrow's length. */
2637
+ /** Offset of the label across the arrow, as a fraction of the arrow's length. */
3267
2638
  labelCrossPosition?: number;
3268
2639
  }
3269
2640
 
@@ -3344,21 +2715,12 @@ declare type DiscreteScaleOptions<RangeValue extends number | string = number |
3344
2715
 
3345
2716
  declare type DiscreteScaleSpec = Required<DiscreteScaleInput>;
3346
2717
 
3347
- /** Diagnostics split by severity, as returned by {@link DiagnosticsCollector.drain}. */
3348
- declare interface DrainedDiagnostics {
3349
- errors: VizDiagnostic[];
3350
- warnings: VizDiagnostic[];
3351
- }
3352
-
3353
- /** Measured sizes (in pixels) for each edge of the layout. */
3354
- export declare type EdgeSizes = Record<LayoutEdge, number>;
3355
-
3356
2718
  /** A value format with no inner lookups. Lookup cases and fallbacks are constrained to this so a `lookup` cannot nest another `lookup` at the type level. */
3357
2719
  export declare type ExplicitValueFormat = TemporalValueFormat | NumericValueFormat | CurrencyValueFormat | CategoricalValueFormat;
3358
2720
 
3359
2721
  /**
3360
2722
  * Measured heights of content regions (header: title+subtitle, footer: caption). The caller measures
3361
- * the already-rendered header/footer DOM and feeds these back; only the heights are read (widths are
2723
+ * the already-rendered header/footer DOM and feeds these back; only the HEIGHTS are read (widths are
3362
2724
  * ignored, since those regions span the full width). Expect a zero-size first pass before the DOM has
3363
2725
  * mounted, then a second compile once real heights are known.
3364
2726
  */
@@ -3368,20 +2730,13 @@ export declare interface ExternalMeasurements {
3368
2730
  }
3369
2731
 
3370
2732
  /**
3371
- * Extracts the constant value from a `{ value }` mapping. Returns undefined for variable mappings.
2733
+ * Flattens a title, subtitle, or caption to plain text by concatenating every leaf `text` node with
2734
+ * no separators. Block boundaries (paragraphs, list items, line breaks) are intentionally dropped —
2735
+ * the result feeds text measurement and static fallbacks, not display, so it must not be shown as the
2736
+ * formatted heading.
3372
2737
  */
3373
- export declare function extractConstantValue(aestheticValue: AestheticValue | undefined): DataValue | undefined;
3374
-
3375
- /** Flattens a title, subtitle, or caption to plain text for measurement and static renderers. */
3376
2738
  export declare const extractPlainText: (content: TextContent) => string;
3377
2739
 
3378
- /**
3379
- * Extracts the variable name from an AestheticValue.
3380
- * Returns the variable name for string shorthands and { variable } mappings.
3381
- * Returns null for constant { value } mappings or undefined values.
3382
- */
3383
- export declare function extractVariableName(aestheticValue: AestheticValue | undefined): VariableName | null;
3384
-
3385
2740
  declare function filter(options: FilterOptions): FilterTransformInput;
3386
2741
 
3387
2742
  /***************************************************************
@@ -3415,12 +2770,6 @@ declare interface FilterTransformInput {
3415
2770
  */
3416
2771
  export declare function findAxisGuide(guides: CompiledGuides, scaleAestheticKey: ScaledAestheticKey): CompiledAxisGuide | null;
3417
2772
 
3418
- /** Returns the first region whose rect contains the panel-local point, or null. */
3419
- export declare const findCalloutHit: (point: {
3420
- x: number;
3421
- y: number;
3422
- }, regions: readonly CalloutHitRegion[]) => CalloutHitRegion | null;
3423
-
3424
2773
  /**
3425
2774
  * Returns the legend that covers the given visual aesthetic, or null if no legend is configured
3426
2775
  * for it. Legends may be merged across aesthetics (one legend covering color + size on a point
@@ -3475,7 +2824,8 @@ export declare interface FormatHeadlineInput {
3475
2824
  numberFormat: NumberFormatConfig;
3476
2825
  parsingLocale: Locale;
3477
2826
  /**
3478
- * Display-locale override: `locale = formattingLocale ?? parsingLocale`.
2827
+ * Display-locale override: `locale = formattingLocale ?? parsingLocale`. The supported set is small
2828
+ * ('en-GB', 'en-US', 'ar', 'pt-PT'); a `duration` figure always formats in English regardless.
3479
2829
  */
3480
2830
  formattingLocale?: Locale;
3481
2831
  t: Translator;
@@ -3493,7 +2843,8 @@ declare interface FormatLegendsInput {
3493
2843
  numberFormat: NumberFormatConfig;
3494
2844
  parsingLocale: Locale;
3495
2845
  /**
3496
- * Display-locale override: `locale = formattingLocale ?? parsingLocale`.
2846
+ * Display-locale override: `locale = formattingLocale ?? parsingLocale`. The supported set is small
2847
+ * ('en-GB', 'en-US', 'ar', 'pt-PT'); a `duration` label always formats in English regardless.
3497
2848
  */
3498
2849
  formattingLocale?: Locale;
3499
2850
  }
@@ -3501,7 +2852,8 @@ declare interface FormatLegendsInput {
3501
2852
  /**
3502
2853
  * Formats a rule layer's underlying numeric value with the same value formatter as the axis the rule
3503
2854
  * anchors to: y-rules use the y-axis; x-rules use x. Takes the rule's own `CompiledLayerFor<'rule'>`
3504
- * and returns only the formatted value — or null when the rule has no observation or a null value.
2855
+ * and returns ONLY the formatted value — or null when the rule has no observation or a null value.
2856
+ * The caller composes it with the rule's label text (this helper does not).
3505
2857
  */
3506
2858
  export declare const formatRuleValue: ({ guides, numberFormat, layer, locale }: FormatRuleValueInput) => string | null;
3507
2859
 
@@ -3533,8 +2885,8 @@ export declare interface FormattedAxis extends Omit<CompiledAxisGuide, 'tickCand
3533
2885
  }
3534
2886
 
3535
2887
  /**
3536
- * A headline showing a single grand-total number, used for polar graphs. `value` is a bare final
3537
- * display string: no prefix, label or swatch accompanies it. Render it verbatim.
2888
+ * A headline showing a single grand-total number, used for polar charts. `value` is a bare final
2889
+ * display string no prefix, label, or swatch accompanies it; render it verbatim.
3538
2890
  */
3539
2891
  export declare interface FormattedGrandTotalHeadline {
3540
2892
  kind: 'grandTotal';
@@ -3577,18 +2929,52 @@ export declare interface FormattedHeadlineItem {
3577
2929
 
3578
2930
  /** A legend guide with each item's label composed into a display string. */
3579
2931
  export declare interface FormattedLegend extends Omit<CompiledLegendGuide, 'items'> {
3580
- /** Legend items, each carrying its composed display string in `formattedLabel`. */
2932
+ /** Legend entries, each carrying its composed display string in `formattedLabel`. */
3581
2933
  items: Array<LegendItem & {
3582
2934
  formattedLabel: string;
3583
2935
  }>;
3584
2936
  }
3585
2937
 
3586
- /** A headline showing one labelled figure per group (e.g. one per group). */
2938
+ /** A headline showing one labelled figure per group (e.g. one per series). */
3587
2939
  export declare interface FormattedPerGroupHeadline {
3588
2940
  kind: 'perGroup';
3589
2941
  items: FormattedHeadlineItem[];
3590
2942
  }
3591
2943
 
2944
+ /**
2945
+ * Freeform arrow annotation. Endpoints sit in plot-fractional coordinates
2946
+ * (0..1), so they re-flow with panel size. Distinct from
2947
+ * {@link DifferenceArrowInput}, which anchors to dataset observations.
2948
+ */
2949
+ export declare interface FreeformArrowInput {
2950
+ id?: string;
2951
+ /** Tail endpoint. */
2952
+ start: ArrowEndpoint;
2953
+ /** Head endpoint. */
2954
+ end: ArrowEndpoint;
2955
+ /** null falls back to the theme `defaultAnnotationArrowStroke`. */
2956
+ color?: string | null;
2957
+ thickness?: ArrowThickness;
2958
+ startArrowheadStyle?: ArrowheadStyle;
2959
+ endArrowheadStyle?: ArrowheadStyle;
2960
+ lineStyle?: ArrowLineStyle;
2961
+ /** Render with a raised, outlined sticker-like appearance. */
2962
+ hasStickerStyle?: boolean;
2963
+ }
2964
+
2965
+ /** Resolved freeform arrow with all optional fields defaulted. */
2966
+ export declare interface FreeformArrowSpec {
2967
+ id: string;
2968
+ start: ArrowEndpoint;
2969
+ end: ArrowEndpoint;
2970
+ color: string | null;
2971
+ thickness: ArrowThickness;
2972
+ startArrowheadStyle: ArrowheadStyle;
2973
+ endArrowheadStyle: ArrowheadStyle;
2974
+ lineStyle: ArrowLineStyle;
2975
+ hasStickerStyle: boolean;
2976
+ }
2977
+
3592
2978
  /**
3593
2979
  * Options for `generateTicks`:
3594
2980
  * - `{ count }` — approximate tick count (continuous, datetime).
@@ -3607,99 +2993,14 @@ declare type GenerateTicksOptions = {
3607
2993
 
3608
2994
  /**
3609
2995
  * Base class for geoms that turn observations into visual marks (points, bars, lines etc).
3610
- *
3611
- * A geom declares its capabilities as fields and hooks with sensible base-class defaults; a subclass
3612
- * overrides only what differs. The compile and runtime pipeline reads these declarations to decide
3613
- * behaviour rather than branching on `type`, so a custom geom is a first-class participant.
3614
- *
3615
- * What earns a place on the def: a field belongs here only if it answers a question a name-agnostic
3616
- * pipeline stage must ask of *every* geom (e.g. "which coord systems do you support?", "what spatial
3617
- * index do you paint into?"). A single geom's one-off behaviour is an optional hook that geom alone
3618
- * implements — never a shared flag the base class asserts for all geoms. Fields are grouped below by
3619
- * the concern that consumes them.
3620
- */
3621
- export declare abstract class Geom<TParams = Record<string, never>> {
3622
- /** Position columns the compile half injects and the render half reads — the cross-half contract. */
3623
- readonly positionRoles: PositionRoles;
3624
- /** What makes "the same observation" across recompiles. */
3625
- readonly identityKey: IdentityKey;
3626
- /** How overlapping marks of this geom arrange when the layer omits a position (bar → dodge, area → stack). */
3627
- readonly defaultPosition: PositionType;
3628
- /** Whether layers of this geom take part in hover hit-testing by default (rule opts out). */
3629
- readonly defaultInteractive: boolean;
3630
- /**
3631
- * The aesthetics this geom honours, each tagged by {@link GeomAesthetic} `kind`: a `'visual'` scaled
3632
- * channel (`color`, `size`) or a `'data'` relational/layout input read straight from its mapped column
3633
- * without a scale (a sankey's `source`/`target`/`value`). Declaring a name registers it so the mapping
3634
- * is recognised and, when `required`, enforces its presence.
3635
- */
3636
- readonly aesthetics: GeomAesthetics;
3637
- /**
3638
- * Variable names this geom computes in its own output that an author may map an aesthetic to.
3639
- * They don't exist in the input data, so they're exempt from the unknown-variable check.
3640
- */
3641
- readonly derivedVariables: readonly string[];
3642
- /** How this geom composes highlight matches above its base render; `null` opts out of highlighting. */
3643
- readonly highlightStrategy: HighlightStrategy | null;
3644
- /** Scale-domain constraints this geom imposes (discrete band axis, zero-anchored y); unset = none. */
3645
- readonly scaleConstraints?: ScaleConstraints;
3646
- /** Coordinate systems this geom can be rendered under. */
3647
- readonly supportedCoordTypes: readonly CoordType[];
3648
- /**
3649
- * The hit-test shape this geom declares, coord-agnostic (see {@link SpatialKind}). Baked onto the
3650
- * compiled layer verbatim; the runtime hover indexer (`build-layer-index`) projects it for the chart's
3651
- * coord.
3652
- */
3653
- readonly spatialKind: SpatialKind;
3654
- /** Per-coord grid/border visibility this geom requests from the axes guide. */
3655
- readonly grid: Partial<Record<CoordType, GridPolicy>>;
3656
- /** How this geom relates to the colour legend (single-item suppression, auto-placement, direct labels). */
3657
- readonly legend: LegendPolicy;
3658
- /** Per-coord data-label defaults merged over the base config (e.g. bar+polar → percentage). */
3659
- readonly dataLabels?: Partial<Record<CoordType, Partial<DataLabelsConfig>>>;
3660
- /** Coord types the built-in placement pipeline can place this geom's data labels under. */
3661
- readonly dataLabelCoordTypes: readonly CoordType[];
3662
- /** The tooltip contract this geom declares. */
3663
- readonly tooltip: TooltipContract;
3664
- /** Per-layer aggregate summaries this geom opts into (grand total, stack totals, per-group headline). */
3665
- readonly summaries: GeomSummaries;
3666
- /** Optional bespoke mapping requirement not expressible as a position role's `aes` source. */
3667
- validateMapping?: (input: GeomMappingValidationInput) => readonly UserInputIssue[];
3668
- /**
3669
- * Optional: resolve a per-observation annotation anchor in normalised panel `[0, 1]` space. A geom
3670
- * that supports anchoring (bar, line) implements this; the annotation stage skips geoms that don't.
3671
- */
3672
- resolveAnchorPosition?: (observation: Observation, coordSystem: CoordSystem) => AnchorPosition | null;
3673
- /**
3674
- * Optional: the geom's bespoke default data-label source when none is mapped (point → the bound
3675
- * `size` variable). Returns `null` to defer to the shared segment-y default.
3676
- */
3677
- resolveDefaultLabelSource?: (mapping: AesMapping) => AestheticValue | null;
3678
- /**
3679
- * Optional: data-label defaults that depend on the layer's position adjuster (e.g. bar defaults `justify` to
3680
- * `'center'` on stacked/filled segments). Applied over the base defaults; both the per-coord defaults and
3681
- * the user's config override it.
3682
- */
3683
- resolveDataLabelDefaults?: (position: PositionType) => Partial<DataLabelsConfig>;
3684
- /**
3685
- * The geom's name. The built-in subclasses narrow this to a `GeomName` literal; the base accepts
3686
- * any `string` so a custom geom carries a name outside the built-in union (runtime identity is a
3687
- * plain string, resolved through the registry).
3688
- */
3689
- abstract readonly type: string;
3690
- /** Default values for this geom's params; also carries the params type (`TParams`). */
3691
- abstract readonly defaultParams: TParams;
3692
- /**
3693
- * Resolve this geom's params from the (optional) user-supplied params, merged over
3694
- * {@link defaultParams}. Read by the layer resolver. Override to apply a geom-specific invariant the
3695
- * merge can't express — area normalises `missingValues: 'gap'` to `'zero'`, which it can't render
3696
- * mid-stack. Params are validated at the typed builder call site, so this works on an open record.
3697
- */
3698
- resolveParams(params: Record<string, unknown> | undefined): Record<string, unknown>;
2996
+ */
2997
+ declare abstract class Geom {
2998
+ readonly requiredAesthetics: AestheticKey[];
2999
+ abstract readonly type: GeomName;
3699
3000
  abstract compile(input: GeomCompilerInput): CompiledGeom;
3700
3001
  }
3701
3002
 
3702
- /** Factories for the geom layers a graph can draw (point, line, area, bar, rule). */
3003
+ /** Factories for the geometry layers a chart can draw (point, line, area, bar, rule). */
3703
3004
  export declare const geom: {
3704
3005
  point: typeof point;
3705
3006
  line: typeof line;
@@ -3709,82 +3010,34 @@ export declare const geom: {
3709
3010
  };
3710
3011
 
3711
3012
  /**
3712
- * An aesthetic a geom reads from its layer's mapping, tagged by how the engine treats it:
3713
- *
3714
- * - `'visual'` — a scaled visual channel (`color`, `size`), trained through a scale. Constrained to the
3715
- * built-in {@link AestheticKey} vocabulary.
3716
- * - `'data'` — a relational/layout input read straight from the mapped column without any scale (a
3717
- * sankey's `source`/`target`/`value`). Free-form name, outside the built-in vocabulary.
3718
- *
3719
- * Declaring an aesthetic registers its name so the mapping is recognised (no `UNDECLARED_AESTHETIC`
3720
- * warning) and, when `required`, enforced by the missing-aesthetic check.
3721
- */
3722
- export declare type GeomAesthetic = {
3723
- readonly kind: 'visual';
3724
- readonly name: AestheticKey;
3725
- readonly required?: boolean;
3726
- } | {
3727
- readonly kind: 'data';
3728
- readonly name: string;
3729
- readonly required?: boolean;
3730
- };
3731
-
3732
- /** A geom's declared aesthetics. */
3733
- export declare type GeomAesthetics = readonly GeomAesthetic[];
3734
-
3735
- /**
3736
- * Options for a custom geom builder method. Mirrors the built-in geom option envelope, but with
3737
- * `params` typed from the def's `defaultParams` and `aes` constrained to the def's declared
3738
- * aesthetics ({@link AesFromDef}).
3739
- */
3740
- declare interface GeomBuilderOptions<Def extends Geom<unknown>> {
3741
- aes?: AesFromDef<Def>;
3742
- stat?: StatName | StatInput | CustomStatInput<string>;
3743
- position?: PositionType;
3744
- yScaleType?: YScaleType;
3745
- params?: Partial<Def['defaultParams']>;
3746
- transforms?: TransformInput[];
3747
- interactive?: boolean;
3748
- dataLabels?: DataLabelsInput;
3749
- }
3750
-
3751
- /**
3752
- * Resolves a geom by name, delegates compilation, then fills any `aes`-sourced interval roles the
3753
- * geom declares (e.g. a bar's `yMax` from its `y` aesthetic) so the geom compile half doesn't.
3013
+ * Resolves a geom by name and delegates compilation.
3754
3014
  */
3755
3015
  declare class GeomCompiler {
3756
- private readonly container;
3757
- constructor(container: CommonContainer);
3758
- compile(geomName: string, input: GeomCompilerInput): CompiledGeom;
3016
+ private readonly registry;
3017
+ constructor(registry: GeomRegistry);
3018
+ compile(geomName: GeomName, input: GeomCompilerInput): CompiledGeom;
3759
3019
  }
3760
3020
 
3761
- export declare interface GeomCompilerInput {
3021
+ declare interface GeomCompilerInput {
3762
3022
  /** The dataset after stat transformation */
3763
3023
  data: Dataset;
3764
- /** The effective mapping for the layer (may carry the geom's custom positional aesthetics). */
3024
+ /** The effective mapping for the layer */
3765
3025
  mapping: AesMapping;
3766
3026
  /** Geom-specific params */
3767
3027
  params: LayerSpec['params'];
3768
3028
  }
3769
3029
 
3770
- declare type GeomDefsOf<P extends readonly Plugin_2[]> = Extract<DefsOf<P>, Geom<unknown>>;
3771
-
3772
- /** Context a geom's `validateMapping` hook receives to assert a bespoke mapping requirement. */
3773
- export declare interface GeomMappingValidationInput {
3774
- /** The layer's effective mapping (root + layer merged). */
3775
- mapping: AesMapping;
3776
- /** Aesthetics the layer's stat computes at compile time, which count as "provided". */
3777
- computedVariables: ReadonlySet<AestheticKey>;
3778
- }
3779
-
3780
3030
  /**
3781
3031
  * The type of geometric mark used to represent data in a layer.
3782
3032
  *
3783
3033
  * - `'point'` — Scatter-style dot marks
3784
3034
  * - `'line'` — Connected line marks
3785
3035
  * - `'area'` — Filled area marks
3786
- * - `'bar'` — Rectangular bar marks (cartesian) or pie wedge (polar)
3036
+ * - `'bar'` — Rectangular bar marks
3787
3037
  * - `'rule'` — Horizontal or vertical reference line at a constant value
3038
+ *
3039
+ * A mark's geometry is the `(geom, coordSystem.type)` pair, not geom alone — a `bar` is a rect in
3040
+ * cartesian and an arc in polar — so renderers dispatch on the pair.
3788
3041
  */
3789
3042
  export declare type GeomName = 'point' | 'line' | 'area' | 'bar' | 'rule';
3790
3043
 
@@ -3804,37 +3057,22 @@ declare interface GeomParamsMap {
3804
3057
  }
3805
3058
 
3806
3059
  /**
3807
- * Geom implementations keyed by name. Built-ins are registered in the constructor; custom geoms are
3808
- * appended via `createRegistries`, so the key is a plain `string` rather than the built-in `GeomName`.
3060
+ * Built-in geom implementations keyed by {@link GeomName}.
3809
3061
  */
3810
- declare class GeomRegistry extends Registry<string, Geom<unknown>> {
3062
+ declare class GeomRegistry extends Registry<GeomName, Geom> {
3811
3063
  constructor();
3812
3064
  }
3813
3065
 
3814
- /**
3815
- * Per-layer aggregate summaries a geom opts into. Read by the summarise stage (which gates the
3816
- * grand-total / stack-total summarisers) and the headline guide (per-group eligibility), so the
3817
- * behaviour follows what a geom declares rather than its name.
3818
- */
3819
- export declare interface GeomSummaries {
3820
- /** Emit a layer-wide grand total over `y` (the figure a polar headline shows). */
3821
- grandTotal?: boolean;
3822
- /** Emit per-x stack totals for a stacked layer. */
3823
- stackTotals?: boolean;
3824
- /** Eligible to carry a per-group headline strip. */
3825
- perGroupHeadline?: boolean;
3826
- }
3827
-
3828
3066
  /**
3829
3067
  * Reads the resolved alpha (opacity) value from an observation, in `[0, 1]`.
3830
3068
  *
3831
- * `null` / `undefined` ⇒ unmapped — apply the geom default. A group (line / area) shares one
3069
+ * `null` / `undefined` ⇒ unmapped — apply the geom default. A series (line / area) shares one
3832
3070
  * resolved value across its rows; read it from the first observation.
3833
3071
  */
3834
3072
  export declare function getAlpha(observation: Observation): NumericDataValue;
3835
3073
 
3836
3074
  /**
3837
- * Reads a polar arc's angular sweep. In polar layers the x position variables are repurposed as
3075
+ * Reads a polar arc's angular sweep. In polar layers the x position columns are repurposed as
3838
3076
  * angles: absolute radians, `startAngle` already applied, clockwise from 12 o'clock — matching the
3839
3077
  * polar transform, `HoverHit`'s polar convention, and d3-shape `arc()`. Pass the values through
3840
3078
  * unmodified. Either field `null` ⇒ skip the arc.
@@ -3855,8 +3093,8 @@ export declare const getBarRectBounds: (mainAxis: MainAxis, observation: Observa
3855
3093
  /**
3856
3094
  * Reads the resolved color string from an observation.
3857
3095
  *
3858
- * `undefined` ⇒ unmapped — the renderer supplies its geom default fill. A group (line / area)
3859
- * shares one resolved value across its observations; read it from the first observation.
3096
+ * `undefined` ⇒ unmapped — the renderer supplies its geom default fill. A series (line / area)
3097
+ * shares one resolved value across its rows; read it from the first observation.
3860
3098
  */
3861
3099
  export declare function getColor(observation: Observation): string | undefined;
3862
3100
 
@@ -3867,15 +3105,6 @@ export declare const getCurve: (interpolate: InterpolateType) => CurveFactory;
3867
3105
 
3868
3106
  export declare const getDashArray: (lineType: LineStyleType) => string | undefined;
3869
3107
 
3870
- /**
3871
- * Returns pixel dimensions for a data label of the given kind. The renderer owns the
3872
- * font family; everything that must agree between renderers (size, weight, padding) lives here.
3873
- *
3874
- * `textScale` lets callers track the graph-wide text scale so labels size to the rest of the
3875
- * graph. Pass `1` to keep the base pixel sizes.
3876
- */
3877
- export declare const getDataLabelDimensions: (kind: DataLabelKind, textScale: number) => DataLabelDimensions;
3878
-
3879
3108
  /**
3880
3109
  * Returns pixel dimensions for a difference arrow at the requested size.
3881
3110
  *
@@ -3885,12 +3114,12 @@ export declare const getDataLabelDimensions: (kind: DataLabelKind, textScale: nu
3885
3114
  export declare const getDifferenceArrowDimensions: (size: DifferenceArrowSize, textScale: number) => DifferenceArrowDimensions;
3886
3115
 
3887
3116
  /**
3888
- * Reads the group value written onto an observation during compilation.
3117
+ * Reads the series-grouping key written onto an observation during compilation.
3889
3118
  *
3890
- * Connected geoms (line, area) must partition observations by this key —
3891
- * `data.groupBy(GROUP_VARIABLES.group)` — and emit one compound geom per group; other geoms
3892
- * (bar, point, polar) iterate `data` directly. Visual values are constant within a group, so
3893
- * read them from the first observation.
3119
+ * Connected geoms (line, area, polar arc) must partition observations by this key —
3120
+ * `data.groupBy(GROUP_VARIABLES.group)` — and emit one mark per group; per-mark geoms (bar, point)
3121
+ * iterate `data` directly. Visual channels are constant within a group, so read them from the
3122
+ * first observation.
3894
3123
  */
3895
3124
  export declare const getGroup: (observation: Observation) => CategoricalDataValue;
3896
3125
 
@@ -3902,7 +3131,7 @@ export declare function getHoverGuideRectProps(coordSystem: CartesianCoordSystem
3902
3131
  * Reads the resolved line type (stroke style) from an observation.
3903
3132
  * Falls back to `'solid'` when no `lineType` variable was derived.
3904
3133
  *
3905
- * A group (line / area) shares one resolved value across its observations; read it from the first
3134
+ * A series (line / area) shares one resolved value across its rows; read it from the first
3906
3135
  * observation.
3907
3136
  */
3908
3137
  export declare function getLineType(observation: Observation): LineStyleType;
@@ -3919,33 +3148,18 @@ export declare function getMainAxisCoordinate(mainAxis: MainAxis, point: XYPoint
3919
3148
  export declare const getNumericWeight: (weight: NamedWeightKey | number | undefined) => number;
3920
3149
 
3921
3150
  /**
3922
- * Arc extents for a banded polar bar's hover guide: the primary's category band on the band axis,
3923
- * swept across the full value axis — the polar analog of the cartesian band rect (band width × full
3924
- * cross extent). A `theta: 'x'` rose bands the angular spoke and sweeps the full radius; a `theta: 'y'`
3925
- * radial bar bands the radial track and sweeps the full angle.
3926
- */
3927
- export declare function getPolarHoverGuideArcProps(coordSystem: PolarCoordSystem, primary: HoverHit): HoverGuideArcProps | null;
3928
-
3929
- /**
3930
- * Reads a polar arc's radial extent. In polar layers the y position variables are repurposed as
3151
+ * Reads a polar arc's radial extent. In polar layers the y position columns are repurposed as
3931
3152
  * radii: fractions (`[0, 1]`) of the outer radius. The renderer maps these into a unit circle and
3932
3153
  * lets the browser scale it to pixels (no manual multiply by a panel radius). Either field `null`
3933
3154
  * ⇒ skip the arc.
3934
3155
  */
3935
3156
  export declare function getRadiusExtent(observation: Observation): RadiusExtent;
3936
3157
 
3937
- /**
3938
- * Reads the scaled `[0, 1]` position of a custom **scalar** aesthetic (a candlestick's `open`/`close`),
3939
- * written by the position mapper into a derived column. The aesthetic's raw value stays in the user's
3940
- * mapped column (for tooltips/labels); this returns the finished position the render half paints with.
3941
- */
3942
- export declare function getScaledAesthetic(observation: Observation, aesthetic: string): NumericDataValue;
3943
-
3944
3158
  /**
3945
3159
  * Reads the resolved size value from an observation — a nominal diameter (points halve it for the
3946
3160
  * marker radius).
3947
3161
  *
3948
- * `null` / `undefined` ⇒ unmapped — apply the geom default. A group (line / area) shares one
3162
+ * `null` / `undefined` ⇒ unmapped — apply the geom default. A series (line / area) shares one
3949
3163
  * resolved value across its rows; read it from the first observation.
3950
3164
  */
3951
3165
  export declare function getSize(observation: Observation): NumericDataValue;
@@ -3955,7 +3169,7 @@ export declare const getStablePolarBarKeyGenerator: () => ((observation: Observa
3955
3169
  /**
3956
3170
  * Reads the resolved stroke width value from an observation, in pixels.
3957
3171
  *
3958
- * `null` / `undefined` ⇒ unmapped — apply the geom default. A group (line / area) shares one
3172
+ * `null` / `undefined` ⇒ unmapped — apply the geom default. A series (line / area) shares one
3959
3173
  * resolved value across its rows; read it from the first observation.
3960
3174
  */
3961
3175
  export declare function getStrokeWidth(observation: Observation): NumericDataValue;
@@ -3971,6 +3185,9 @@ declare interface GetValuesOptions {
3971
3185
 
3972
3186
  /**
3973
3187
  * Reads the normalized x position (band center) from an observation.
3188
+ *
3189
+ * Normalized to [0,1]: x is 0=left…1=right, y is 0=bottom…1=top (data-up). SVG / top-origin
3190
+ * renderers invert y as `1 - y`.
3974
3191
  */
3975
3192
  export declare function getX(observation: Observation): NumericDataValue;
3976
3193
 
@@ -3994,6 +3211,9 @@ export declare function getXMin(observation: Observation): NumericDataValue;
3994
3211
 
3995
3212
  /**
3996
3213
  * Reads the normalized y position (band center) from an observation.
3214
+ *
3215
+ * Normalized to [0,1]: x is 0=left…1=right, y is 0=bottom…1=top (data-up). SVG / top-origin
3216
+ * renderers invert y as `1 - y`.
3997
3217
  */
3998
3218
  export declare function getY(observation: Observation): NumericDataValue;
3999
3219
 
@@ -4032,7 +3252,7 @@ declare interface GoalLine {
4032
3252
  label?: string;
4033
3253
  }
4034
3254
 
4035
- declare type GraphAnnotation = GraphStickerAnnotation | GraphTooltipAnnotation | GraphHighlightAnnotation | GraphTextAnnotation | GraphArrowAnnotation | GraphDifferenceArrowAnnotation | GraphShapeAnnotation | GraphImageAnnotation;
3255
+ declare type GraphAnnotation = GraphStickerAnnotation | GraphTooltipAnnotation | GraphHighlightAnnotation | GraphTextAnnotation | GraphArrowAnnotation | GraphDifferenceArrowAnnotation | GraphShapeAnnotation;
4036
3256
 
4037
3257
  declare interface GraphArrowAnnotation {
4038
3258
  id: string;
@@ -4058,12 +3278,12 @@ declare interface GraphArrowAnnotation {
4058
3278
  */
4059
3279
  export declare interface GraphConfig {
4060
3280
  type?: GraphType;
4061
- /** Geometry-specific settings, unioned across all graph types. */
3281
+ /** Geometry-specific settings, unioned across all chart types. */
4062
3282
  options?: Options;
4063
3283
  axes?: Axes;
4064
3284
  legend?: Legend;
4065
3285
  appearance?: Appearance;
4066
- /** Ad-hoc overrides of individual theme tokens, plus a shortcut for the graph background. */
3286
+ /** Ad-hoc overrides of individual theme tokens, plus a shortcut for the chart background. */
4067
3287
  themeOverrides?: {
4068
3288
  [key: string]: unknown;
4069
3289
  graphBackground?: string;
@@ -4095,37 +3315,15 @@ declare type GraphHighlightAnnotation = {
4095
3315
  highlight: 'data-point' | 'series' | 'x-value';
4096
3316
  } & AnnotationDataPoint;
4097
3317
 
4098
- declare interface GraphImageAnnotation {
4099
- id: string;
4100
- type: 'image';
4101
- /** Image URL or data URI. */
4102
- src: string;
4103
- /** Whether the image is drawn behind or in front of the plotted data. */
4104
- layer: 'belowPlot' | 'abovePlot';
4105
- /** Top-left position as fractions (0-1) of the plot width and height. */
4106
- x: number;
4107
- y: number;
4108
- /** Size as fractions (0-1) of the plot width and height. */
4109
- width: number;
4110
- height: number;
4111
- /** How the image scales inside its box: stretch, letterbox, or crop-to-fill. */
4112
- fit?: 'fill' | 'contain' | 'cover';
4113
- /** Opacity from 0 (transparent) to 1 (opaque). */
4114
- opacity?: number;
4115
- }
4116
-
4117
3318
  /** Output of the layout computation. */
4118
3319
  export declare interface GraphLayout {
4119
3320
  /** The full graphical area: panel + axes + axis labels, excluding header and footer. */
4120
3321
  plot: Rect;
4121
- /** The bordered container that surrounds the panel. */
4122
- panelFrame: Rect;
4123
3322
  /**
4124
3323
  * The panel area where geom layers render i.e. the data rectangle inside the axes. Strictly nested
4125
- * inside `plot`. Geoms paint here in normalized `[0,1]` data space with y inverted
3324
+ * inside {@link GraphLayout.plot}. Geoms paint here in normalized `[0,1]` data space with y inverted
4126
3325
  * (data y=0 sits at the panel bottom), so map a data point to `panel.x + x * panel.width` and
4127
- * `panel.y + (1 - y) * panel.height`. Equal to {@link panelFrame} unless the layout reserves extra space
4128
- * for content that overflows the panel.
3326
+ * `panel.y + (1 - y) * panel.height`.
4129
3327
  */
4130
3328
  panel: Rect;
4131
3329
  /** Rects for axis regions (ticks + tick labels), keyed by edge. */
@@ -4187,7 +3385,11 @@ declare interface GraphTextStyle {
4187
3385
  color?: string;
4188
3386
  }
4189
3387
 
4190
- /** Light or dark theme used when resolving theme-dependent colors during GraphConfig conversion. */
3388
+ /**
3389
+ * Active light or dark mode. Selects the full theme token set used when resolving theme-dependent
3390
+ * colors, and sets the direction tints and gradients adjust in (lighten on dark, darken on light) —
3391
+ * see the `'tinted'`/`'gradient'` variants of {@link BackgroundConfig} and {@link BorderConfig}.
3392
+ */
4191
3393
  export declare type GraphTheme = 'light' | 'dark';
4192
3394
 
4193
3395
  declare type GraphTooltipAnnotation = {
@@ -4200,46 +3402,20 @@ declare type GraphTooltipAnnotation = {
4200
3402
  /** Type of graph to use for the data. */
4201
3403
  export declare type GraphType = 'line' | 'areaStacked' | 'bar' | 'barStacked' | 'barStackedFill' | 'column' | 'columnStacked' | 'columnStackedFill' | 'combo' | 'pie' | 'donut' | 'funnel' | 'heatmap' | 'scatter' | 'bubble' | 'waterfall' | 'mekko' | 'table';
4202
3404
 
4203
- /**
4204
- * The authoring surface: the `geom`/`stat`/`transform`/`scale`/`coord` factories plus
4205
- * `createSpec`/`pipe`. The built-in factories are augmented with a typed method per custom def in
4206
- * `plugins` — `geom.<name>` / `stat.<name>` / `transform.<name>`, each with `params` typed from the
4207
- * def's `defaultParams` and `aes` from its declared aesthetics. `plugins` is re-exposed so a wrapping
4208
- * factory can seed the compiler from the same array — what can be written and what can compile derive
4209
- * from one list. A render-only override contributes no method (it has no compile-half def).
4210
- */
4211
- export declare interface GraphyBuilder<P extends readonly Plugin_2[] = readonly Plugin_2[]> {
4212
- geom: typeof geom & CustomGeomBuilders<P>;
4213
- stat: typeof stat & CustomStatBuilders<P>;
4214
- transform: typeof transform & CustomTransformBuilders<P>;
4215
- scale: typeof scale;
4216
- coord: typeof coord;
4217
- createSpec: typeof createSpec;
4218
- pipe: typeof pipe;
4219
- readonly plugins: P;
4220
- }
4221
-
4222
3405
  declare type GraphyPaletteConfig = {
4223
3406
  type: 'graphy';
4224
3407
  variant?: GraphyPaletteVariant;
4225
3408
  };
4226
3409
 
4227
- /** `waterfall` swaps in the positive/negative/total colors used by waterfall graphs. */
3410
+ /** `waterfall` swaps in the positive/negative/total colors used by waterfall charts. */
4228
3411
  declare type GraphyPaletteVariant = 'default' | 'waterfall';
4229
3412
 
4230
- /** A geom's per-coord grid/border visibility overrides, applied by the axes guide. */
4231
- export declare interface GridPolicy {
4232
- hideGridX?: boolean;
4233
- hideGridY?: boolean;
4234
- hideBorder?: boolean;
4235
- }
4236
-
4237
3413
  /**
4238
- * Internal variable holding each observation's group value.
3414
+ * Internal column name holding each observation's series-grouping key.
4239
3415
  *
4240
- * Connected geoms (line, area) must partition observations by this key —
4241
- * `data.groupBy(GROUP_VARIABLES.group)` and emit one compound geom per group; other geoms
4242
- * (bar, point, polar) iterate `data` directly. Read via `getGroup`.
3416
+ * Connected geoms (line, area, polar arc) partition observations on `group`
3417
+ * (`data.groupBy(GROUP_VARIABLES.group)`) to emit one mark per series; per-mark geoms (bar, point)
3418
+ * iterate the dataset directly. Read via `getGroup`.
4243
3419
  */
4244
3420
  export declare const GROUP_VARIABLES: {
4245
3421
  readonly group: string;
@@ -4293,8 +3469,6 @@ declare type GroupedVariableNames = {
4293
3469
  * influences axis placement.
4294
3470
  */
4295
3471
  declare class GuideCompiler extends Stage<GuideCompilerInput, CompiledGuides> {
4296
- private readonly container;
4297
- constructor(container: CommonContainer);
4298
3472
  protected dependencies(input: GuideCompilerInput): readonly unknown[];
4299
3473
  protected run(input: GuideCompilerInput): CompiledGuides;
4300
3474
  }
@@ -4319,8 +3493,8 @@ declare interface GuideCompilerInput {
4319
3493
  */
4320
3494
  declare type GuideConfig = Pick<ConfigSpec, 'axes' | 'legend' | 'headline' | 'panel'>;
4321
3495
 
4322
- /** Geometric shape an axis traces: a straight line, a full circle or a spoke from the centre. */
4323
- export declare type GuideGeometry = 'linear' | 'circular' | 'radial';
3496
+ /** Geometric shape an axis traces: a straight line, a full circle, or a spoke from the centre. */
3497
+ declare type GuideGeometry = 'linear' | 'circular' | 'radial';
4324
3498
 
4325
3499
  /** Gap between the swatch and its group label, in pixels. */
4326
3500
  export declare const HEADLINE_SWATCH_GAP = 4;
@@ -4386,8 +3560,7 @@ export declare type HeadlineFontRole = 'value' | 'label';
4386
3560
 
4387
3561
  declare interface HeadlineGroupSwatch {
4388
3562
  color: string;
4389
- /** The owning layer's geom — the renderer reads its swatch shape off the geom's render contract. */
4390
- geom: string;
3563
+ shape: SwatchShape;
4391
3564
  }
4392
3565
 
4393
3566
  declare interface HeadlineItem {
@@ -4412,8 +3585,8 @@ declare interface HeadlineItem {
4412
3585
  }
4413
3586
 
4414
3587
  /**
4415
- * What the layout needs to measure, size, and place a headline. Passing this only reserves the headline
4416
- * band during compile. To paint it, the renderer must call
3588
+ * What the layout needs to measure, size, and place a headline. Passing this only RESERVES the headline
3589
+ * band during compile — it does not place the headline. To paint it, the renderer must call
4417
3590
  * {@link resolveHeadlinePlacement} with the resolved {@link GraphLayout} for the paint rect, size, and
4418
3591
  * visible-item count.
4419
3592
  */
@@ -4531,7 +3704,7 @@ declare type HeadlineSwatch = NonNullable<FormattedHeadlineItem['swatch']>;
4531
3704
  export declare type HeadlineTextRole = 'value' | 'observation' | 'label' | 'trendPercentage' | 'trendReference';
4532
3705
 
4533
3706
  /**
4534
- * Direction of a headline's trend, and the sole source of the comparison's sign — drive both the
3707
+ * Direction of a headline's trend, and the SOLE source of the comparison's sign — drive both the
4535
3708
  * arrow and the colour off it, since `percentage` is unsigned. `flat` is neutral, so render it
4536
3709
  * without a good/bad colour or a directional arrow.
4537
3710
  */
@@ -4581,12 +3754,12 @@ declare interface HighlightBuilderOptions {
4581
3754
 
4582
3755
  /** Per-layer side-channel produced by the highlights compile stage. */
4583
3756
  export declare interface HighlightComposition {
4584
- /** True when the base render should be wrapped in a dim group (so matched observations stand out). */
3757
+ /** True when the base render should be wrapped in a dim group (so matched marks stand out). */
4585
3758
  isDimmed: boolean;
4586
3759
  /**
4587
3760
  * A real sub-`CompiledLayer` whose dataset is mask-filtered to just the matched observations
4588
3761
  * (everything else identical to the source layer). Feed it back through the same geom renderer to
4589
- * draw the highlighted geoms at full strength; `null` when no re-render pass applies.
3762
+ * draw the highlighted marks at full strength; `null` when no re-render pass applies.
4590
3763
  */
4591
3764
  matchedLayer: CompiledLayer | null;
4592
3765
  /** Observations to paint as overlay markers under `'overlay-anchor'`. Empty for other strategies. */
@@ -4610,7 +3783,8 @@ export declare interface HighlightInput {
4610
3783
  export declare interface HighlightOverlayCandidate {
4611
3784
  observation: Observation;
4612
3785
  /**
4613
- * Observation index into the source layer's dataset.
3786
+ * Row index into the **source** layer's dataset. Use only as a stable React key for the overlay;
3787
+ * it is not a coordinate or a handle into the (mask-filtered) `matchedLayer`.
4614
3788
  */
4615
3789
  observationIndex: number;
4616
3790
  }
@@ -4621,8 +3795,6 @@ export declare interface HighlightOverlayCandidate {
4621
3795
  * `CompiledLayer.highlight.composition`. The renderer reads the composition directly.
4622
3796
  */
4623
3797
  declare class HighlightsCompiler extends PerLayerStage<HighlightsCompilerInput> {
4624
- private readonly container;
4625
- constructor(container: CommonContainer);
4626
3798
  protected dependencies(input: HighlightsCompilerInput): readonly unknown[];
4627
3799
  protected compileLayer(layer: CompiledLayer, input: HighlightsCompilerInput): CompiledLayer;
4628
3800
  }
@@ -4720,20 +3892,6 @@ export declare class HoverEngine {
4720
3892
  * detection nor group/related, so they are visual decoration only as far as hover is concerned.
4721
3893
  */
4722
3894
  private nonInteractiveLayerIds;
4723
- /**
4724
- * Per-layer render-side spatial queries for `'render-hit-test'` layers, keyed by `layerId`. The
4725
- * renderer registers these (the closures live render-side and never serialise); `query` consults
4726
- * them for render-owned layers. Held on the instance, so they survive `update()`.
4727
- */
4728
- private hitTesters;
4729
- /**
4730
- * Push-path cache for {@link resolveHoverByKey}, mirroring the `cachedKey`/`cachedState` pair
4731
- * `query()` keeps: the same `(layerId, key)` resolves to the same `HoverState` reference, so a
4732
- * live geom pushing the same key on every pointermove/frame does not defeat the store's
4733
- * reference-equality dedup. Invalidated alongside the query cache on `update()`.
4734
- */
4735
- private cachedByKeyId;
4736
- private cachedByKeyState;
4737
3895
  constructor({ layers, coordSystem }: HoverEngineInput);
4738
3896
  /**
4739
3897
  * Diff-aware re-index. Layers whose `data`, `geom`, `position` or the graph's coord-system
@@ -4749,7 +3907,7 @@ export declare class HoverEngine {
4749
3907
  /**
4750
3908
  * Renderers call this on mount and on resize. Viewport is set-once, not per-query.
4751
3909
  *
4752
- * Pass the plot panel rect (the geom-drawing area), the same rect the pointer is normalized
3910
+ * Pass the plot **panel** rect (the geom-drawing area), the same rect the pointer is normalized
4753
3911
  * against before `query` — these must agree or hit-testing skews. Only the aspect ratio is used
4754
3912
  * (it corrects the scatter points-2D index); the absolute pixels are not retained.
4755
3913
  *
@@ -4760,8 +3918,8 @@ export declare class HoverEngine {
4760
3918
  */
4761
3919
  setViewport(viewport: HoverViewport): void;
4762
3920
  /**
4763
- * Synchronous query. The `cursor` is the pointer normalized to `[0, 1]` against the same rect
4764
- * passed to `setViewport` (the plot panel) — x left-to-right, y in data-space (0 bottom, 1 top),
3921
+ * Synchronous query. The `cursor` is the pointer normalized to `[0, 1]` against the **same rect
3922
+ * passed to `setViewport`** (the plot panel) — x left-to-right, y in data-space (0 bottom, 1 top),
4765
3923
  * so a top-origin renderer flips Y before calling (see {@link HoverCursor}).
4766
3924
  *
4767
3925
  * Returns the same `HoverState` reference while the primary stays on the same `(layerId,
@@ -4770,31 +3928,6 @@ export declare class HoverEngine {
4770
3928
  * every match so the next call walks a minimum number of Delaunay edges.
4771
3929
  */
4772
3930
  query(cursor: HoverCursor): HoverState;
4773
- /**
4774
- * Registers a render-side spatial query for a `'render-hit-test'` layer. The renderer owns the
4775
- * closure (it changes every render as the geom recomputes its geometry); the engine only consults
4776
- * it during {@link query}. Idempotent per `layerId` — re-registering replaces the previous tester.
4777
- */
4778
- registerHitTester(layerId: string, tester: RenderHitTester): void;
4779
- unregisterHitTester(layerId: string): void;
4780
- /**
4781
- * Resolves a render-owned layer's hit from an observation key the geom already knows — the push
4782
- * path, for a geom whose geometry keeps changing after it's drawn and which owns its own pointer
4783
- * surface. Skips the spatial test {@link query} performs and resolves the key directly against the
4784
- * layer's `byKey` lookup. Returns the resting state when the layer is missing, isn't render-owned,
4785
- * non-interactive, or the key is unknown. The hit carries no anchor coordinates — the caller
4786
- * positions the tooltip.
4787
- *
4788
- * Honors `CompiledLayer.interactive` the same way {@link query} does (which filters the layer out
4789
- * before hit-testing), so a non-interactive render-owned layer participates in no hover on either
4790
- * path.
4791
- *
4792
- * Returns the same `HoverState` reference while `(layerId, key)` is unchanged, so a live geom
4793
- * pushing the same key on every pointermove/frame short-circuits the store's reference-equality
4794
- * dedup instead of re-rendering every hover subscriber per move (the tooltip still follows the
4795
- * cursor — that anchor is the caller's, not part of this state).
4796
- */
4797
- resolveHoverByKey(layerId: string, key: string): HoverState;
4798
3931
  private invalidateCache;
4799
3932
  }
4800
3933
 
@@ -4808,14 +3941,6 @@ export declare interface HoverEngineInput {
4808
3941
  coordSystem: CoordSystem;
4809
3942
  }
4810
3943
 
4811
- /** Arc extents for the banded-polar-bar guide wedge (the polar analog of the band rect). */
4812
- export declare interface HoverGuideArcProps {
4813
- startAngle: number;
4814
- endAngle: number;
4815
- innerRadius: number;
4816
- outerRadius: number;
4817
- }
4818
-
4819
3944
  /** SVG `<line>` endpoints for the continuous-composition rule. */
4820
3945
  declare interface HoverGuideLineProps {
4821
3946
  x1: string | number;
@@ -4832,41 +3957,45 @@ declare interface HoverGuideRectProps {
4832
3957
  height: string | number;
4833
3958
  }
4834
3959
 
4835
- /**
4836
- * A single hit returned by the hover engine. Discriminated on {@link AnchoredHoverHit.anchored}: an
4837
- * anchored hit carries `(x, y)`; a render-owned hit carries none, so reading `x`/`y` without first
4838
- * narrowing on `anchored` is a compile error rather than a silent placeholder.
4839
- */
4840
- export declare type HoverHit = AnchoredHoverHit | AnchorlessHoverHit;
4841
-
4842
3960
  /**
4843
3961
  * A single hit returned by the hover engine.
3962
+ *
3963
+ * `layerId` is the stable `CompiledLayer.id` — *not* an array position. The engine preserves it
3964
+ * across `update()` calls regardless of layer reordering or insertion, so callers must resolve a
3965
+ * layer by matching `layer.id === hit.layerId`, never by `layers[layerId]`.
3966
+ *
3967
+ * `pointIndex` is an opaque per-layer stable handle for the hit geom, used by the engine as a
3968
+ * warm-start seed for subsequent queries. The encoding is per index kind:
3969
+ * - `buckets` / `rects` / `arcs`: the dataset row inside the layer's observations.
3970
+ * - `points`: the entry's position inside the layer's `points[]` (i.e. the Delaunay's array
3971
+ * index). Diverges from the dataset row when the dataset has null x/y gaps, so callers must
3972
+ * read `observation` rather than indexing `data` by `pointIndex`.
3973
+ *
3974
+ * In every case the handle is stable across `update()` calls for layers whose `data`/`geom`/
3975
+ * `position` references were not replaced (the warm-start identity promised by the ADR), and
3976
+ * callers that need the observation row should read `observation` — never index into the dataset
3977
+ * by `pointIndex`.
4844
3978
  */
4845
- declare interface HoverHitBase {
4846
- /**
4847
- * Stable `CompiledLayer.id`. The engine preserves it across `update()` calls regardless of layer
4848
- * reordering or insertion, so callers must resolve a layer by matching `layer.id === hit.layerId`,
4849
- * never by `layers[layerId]`.
4850
- */
3979
+ export declare interface HoverHit {
4851
3980
  layerId: string;
4852
- /**
4853
- * An opaque per-layer stable handle for the hit geom, used by the engine as a warm-start seed for
4854
- * subsequent queries. The encoding is per index kind:
4855
- * - `buckets` / `rects` / `cells`: the dataset row inside the layer's observations.
4856
- * - `points`: the entry's position inside the layer's `points[]` (i.e. the Delaunay's array
4857
- * index). Diverges from the dataset row when the dataset has null x/y gaps, so callers must
4858
- * read `observation` rather than indexing `data` by `pointIndex`.
4859
- */
4860
3981
  pointIndex: number;
4861
3982
  /**
4862
- * The observation being hovered over. Renderers read values from here; the engine does not format.
3983
+ * Paint coordinates for an overlay marker (e.g. a hover dot) at this hit. Normalized panel-local.
3984
+ * Cartesian: `[0, 1]²` in data-space (y=0 at the bottom, y=1 at the top — matching the compiler's
3985
+ * `POSITION_VARIABLES.y`); convert to panel pixels as `xPixel = x * panel.width`,
3986
+ * `yPixel = (1 - y) * panel.height` (invert y for top-origin renderers). Polar: `(angle in radians
3987
+ * clockwise from 12 o'clock, radius in [0, 1])` — place via the same angle/radius transform the
3988
+ * arcs use (center = panel center, outer radius = `min(panel.w, panel.h) / 2`).
4863
3989
  */
3990
+ x: number;
3991
+ y: number;
3992
+ /** The observation being hovered over. Renderers read values from here; the engine does not format. */
4864
3993
  observation: Observation;
4865
3994
  }
4866
3995
 
4867
3996
  /**
4868
3997
  * Output of `HoverEngine.query()`. Hits are partitioned into three roles. To paint, recombine
4869
- * per layer: the primary's own layer renders `primary + group + (related.get(layerId) ?? [])`;
3998
+ * **per layer**: the primary's own layer renders `primary + group + (related.get(layerId) ?? [])`;
4870
3999
  * every other layer renders only `related.get(layerId) ?? []`. Tooltips list these in legend
4871
4000
  * (color scale-domain) order, with the primary emphasized in place rather than hoisted to the top.
4872
4001
  */
@@ -4874,14 +4003,14 @@ export declare interface HoverState {
4874
4003
  /** The single hit directly under the cursor (nearest/contained geom), or `null` when over no geom. */
4875
4004
  primary: HoverHit | null;
4876
4005
  /**
4877
- * Companion hits in the primary's own layer that share its main-axis position: the stacked
4006
+ * Companion hits in the **primary's own layer** that share its main-axis position: the stacked
4878
4007
  * segments of the hovered column, or the dodged-bar siblings in the same band. Empty for point
4879
- * and cell layers (each mark stands alone). Render alongside the primary in its layer; do not
4008
+ * and arc layers (each mark stands alone). Render alongside the primary in its layer; do not
4880
4009
  * surface them in any other layer.
4881
4010
  */
4882
4011
  group: HoverHit[];
4883
4012
  /**
4884
- * Companion hits in other layers at the same main-axis position (e.g. every line/area/bar
4013
+ * Companion hits in **other** layers at the same main-axis position (e.g. every line/area/bar
4885
4014
  * crossing the hovered x), bucketed by `CompiledLayer.id` so a per-layer consumer reads its own
4886
4015
  * hits in O(1) (`related.get(layer.id) ?? []`) instead of filtering a flat array on every render.
4887
4016
  * Layers with no companions are absent from the map — callers fall back to an empty array on miss.
@@ -4890,7 +4019,7 @@ export declare interface HoverState {
4890
4019
  }
4891
4020
 
4892
4021
  /**
4893
- * Viewport facts the engine needs for aspect-corrected hit testing. Pass the plot panel rect
4022
+ * Viewport facts the engine needs for aspect-corrected hit testing. Pass the plot **panel** rect
4894
4023
  * (where geoms paint), not the whole chart — `HoverEngine.query` normalizes the pointer against
4895
4024
  * this same rect. Only the aspect ratio (`width / height`) is consumed: it corrects the points-2D
4896
4025
  * (scatter) nearest-neighbour index so Euclidean distance matches on-screen pixel distance.
@@ -4904,22 +4033,6 @@ export declare interface HoverViewport {
4904
4033
 
4905
4034
  declare function identity(): IdentityStatSpec;
4906
4035
 
4907
- /**
4908
- * What makes "the same observation" across recompiles, for morphs and hover stability.
4909
- *
4910
- * Two kinds. `'index'` and `'x-group'` are *derived*: the pipeline resolves them from the layer's
4911
- * position/mapping, so the geom names a role, not a column.
4912
- * - `'index'`: positional index into the dataset — the fallback when no field is stable.
4913
- * - `'x-group'`: the columns backing the layer's x + group aesthetics, resolved per chart from the
4914
- * mapping. The default for standard cartesian geoms, which can't name those columns themselves.
4915
- *
4916
- * `{ variable }` is *explicit*: identity is one data column the geom owns and names directly, for a
4917
- * geom keyed by its own id (sankey nodes, voronoi sites) where the x+series roles don't apply.
4918
- */
4919
- export declare type IdentityKey = 'index' | 'x-group' | {
4920
- readonly variable: string;
4921
- };
4922
-
4923
4036
  declare interface IdentityScaleInput {
4924
4037
  type: 'scale';
4925
4038
  scaledAesthetic: ScaledAestheticKey;
@@ -4937,37 +4050,6 @@ declare interface IdentityStatSpec {
4937
4050
  type: 'identity';
4938
4051
  }
4939
4052
 
4940
- /** How an image annotation scales inside its box: stretch, letterbox, or crop-to-fill. */
4941
- export declare type ImageAnnotationFit = 'fill' | 'contain' | 'cover';
4942
-
4943
- /**
4944
- * Image annotation. Its area is positioned by a {@link RegionAnchorInput} so it
4945
- * re-resolves each compile (re-flows on resize, tracks data when bound).
4946
- */
4947
- export declare interface ImageAnnotationInput {
4948
- id?: string;
4949
- /** Image URL or data URI. */
4950
- src: string;
4951
- /** Draw beneath the geoms (background) or on top (foreground). */
4952
- zOrder?: AnnotationZOrder;
4953
- /** The area the image fills. */
4954
- region: RegionAnchorInput;
4955
- /** How the image scales inside its box. */
4956
- fit?: ImageAnnotationFit;
4957
- /** Opacity, 0 (transparent) to 1 (opaque). */
4958
- opacity?: number;
4959
- }
4960
-
4961
- /** Resolved image annotation with all optional fields defaulted. */
4962
- export declare interface ImageAnnotationSpec {
4963
- id: string;
4964
- src: string;
4965
- zOrder: AnnotationZOrder;
4966
- region: RegionAnchor;
4967
- fit: ImageAnnotationFit;
4968
- opacity: number;
4969
- }
4970
-
4971
4053
  declare interface InferredScaleInput {
4972
4054
  type: 'scale';
4973
4055
  scaledAesthetic: ScaledAestheticKey;
@@ -4977,24 +4059,6 @@ declare interface InferredScaleInput {
4977
4059
 
4978
4060
  declare type InferredScaleOptions = ContinuousScaleOptions | DiscreteScaleOptions | DatetimeScaleOptions;
4979
4061
 
4980
- /**
4981
- * An engine invariant was violated — our bug.
4982
- *
4983
- * Codegen tools must report and stop, never retry-loop. `code` defaults to the
4984
- * sole `INTERNAL_INVARIANT`, so most call sites pass just a `message`.
4985
- */
4986
- export declare class InternalError extends VizError {
4987
- readonly kind = "internal";
4988
- constructor(options: Omit<VizErrorOptions<InternalErrorCode>, 'code'> & {
4989
- code?: InternalErrorCode;
4990
- });
4991
- }
4992
-
4993
- /**
4994
- * Stable code for a violated engine invariant.
4995
- */
4996
- export declare type InternalErrorCode = 'INTERNAL_INVARIANT';
4997
-
4998
4062
  /**
4999
4063
  * Curve interpolation method for lines and areas.
5000
4064
  *
@@ -5026,6 +4090,10 @@ export declare function isDefined<T>(value: T | null | undefined): value is T;
5026
4090
 
5027
4091
  /**
5028
4092
  * True when `input` is a {@link GraphConfig} rather than a {@link SpecInput}.
4093
+ *
4094
+ * Discriminates purely on the presence of `layers`: a {@link SpecInput} always carries a `layers`
4095
+ * array and a {@link GraphConfig} never has a top-level `layers`, so its absence identifies a
4096
+ * GraphConfig.
5029
4097
  */
5030
4098
  export declare const isGraphConfig: (input: SpecInput | GraphConfig) => input is GraphConfig;
5031
4099
 
@@ -5055,7 +4123,7 @@ export declare const isSafeUrl: (input: unknown) => input is string;
5055
4123
  /**
5056
4124
  * True for positions that accumulate values along an axis (`'stack'` and `'fill'`).
5057
4125
  *
5058
- * When true, the y position variables already hold cumulative band bounds — the renderer draws each
4126
+ * When true, the y position columns already hold cumulative band bounds — the renderer draws each
5059
4127
  * segment directly between them. Recover a segment's own value (for labels / tooltips) via
5060
4128
  * `getYRaw`, or in original data units via `createSegmentYReader`.
5061
4129
  */
@@ -5063,43 +4131,6 @@ export declare function isStackedPosition(position: PositionType): boolean;
5063
4131
 
5064
4132
  export declare const isTemporalValueFormat: (valueFormat: ValueFormat) => valueFormat is TemporalValueFormat;
5065
4133
 
5066
- /**
5067
- * True when a declared tuple field widened to a general array (the author omitted `as const`), detected
5068
- * via a non-literal `length`. Drives the graceful fallback to a loose aes set.
5069
- */
5070
- declare type IsWidenedTuple<Tuple> = Tuple extends readonly unknown[] ? (number extends Tuple['length'] ? true : false) : true;
5071
-
5072
- /**
5073
- * Any value that survives a `JSON.stringify` / `JSON.parse` round-trip unchanged.
5074
- */
5075
- declare type JsonValue = string | number | boolean | null | JsonValue[] | {
5076
- [key: string]: JsonValue;
5077
- };
5078
-
5079
- /** One kind's observations for {@link createDatasetFromKindPartitions} — e.g. a sankey's nodes, or its flows. */
5080
- export declare interface KindPartition {
5081
- /** Discriminator written to the kind column for every observation in this group (`'node'`, `'flow'`). */
5082
- kind: string;
5083
- /** Column-keyed observations for this kind. Columns absent here are null-padded across the union. */
5084
- observations: ReadonlyArray<Readonly<Observation>>;
5085
- }
5086
-
5087
- /** The aesthetic channels with first-class engine support — the source of {@link AestheticKey}. */
5088
- declare interface KnownAesthetics {
5089
- x?: AestheticValue;
5090
- y?: AestheticValue;
5091
- label?: AestheticValue;
5092
- color?: AestheticValue;
5093
- size?: AestheticValue;
5094
- /** Opacity (0–1). */
5095
- alpha?: AestheticValue;
5096
- /** Splits geoms into groups (separate lines/areas) without assigning a visual aesthetic. */
5097
- group?: AestheticValue;
5098
- strokeWidth?: AestheticValue;
5099
- /** Dash-pattern aesthetic (solid, dashed, dotted, ...). */
5100
- lineType?: AestheticValue;
5101
- }
5102
-
5103
4134
  /**
5104
4135
  * Snapshot of the most recent compile/recompile call returned by {@link Compiler.getLastCompile}.
5105
4136
  * `stages` holds the per-stage hit/miss delta incurred *by that call* (not cumulative);
@@ -5111,17 +4142,15 @@ export declare interface LastCompileSnapshot {
5111
4142
  }
5112
4143
 
5113
4144
  /**
5114
- * Compiles each layer through the transforms → stat → group → chronological-dategeom
5115
- * position adjusters pipeline.
4145
+ * Compiles each layer through the transforms → stat → group → geomposition adjusters pipeline.
5116
4146
  */
5117
4147
  declare class LayerCompiler extends PerLayerStage<LayerCompilerInput, LayerSpec, CompiledLayer> {
5118
- private readonly container;
5119
4148
  private readonly transformCompiler;
5120
4149
  private readonly statCompiler;
5121
4150
  private readonly groupCompiler;
5122
4151
  private readonly geomCompiler;
5123
4152
  private readonly positionAdjusterCompiler;
5124
- constructor(container: CommonContainer, transformCompiler: TransformCompiler, statCompiler: StatCompiler, groupCompiler: GroupCompiler, geomCompiler: GeomCompiler, positionAdjusterCompiler: PositionAdjusterCompiler);
4153
+ constructor(transformCompiler: TransformCompiler, statCompiler: StatCompiler, groupCompiler: GroupCompiler, geomCompiler: GeomCompiler, positionAdjusterCompiler: PositionAdjusterCompiler);
5125
4154
  protected dependencies(input: LayerCompilerInput): readonly unknown[];
5126
4155
  protected compileLayer(layer: LayerSpec, input: LayerCompilerInput): CompiledLayer;
5127
4156
  private runLayerPipeline;
@@ -5141,26 +4170,22 @@ declare interface LayerCompilerInput {
5141
4170
  }
5142
4171
 
5143
4172
  /**
5144
- * Discriminated union of all layer inputs, keyed on `geom`. The built-in arms stay exactly typed;
5145
- * the {@link CustomGeomLayerInput} arm admits a plugin geom carrying a name outside {@link GeomName}.
4173
+ * Discriminated union of all layer inputs, keyed on `geom`.
5146
4174
  * This is the user-facing type — fields are optional and will be resolved with defaults.
5147
4175
  */
5148
- export declare type LayerInput = {
4176
+ declare type LayerInput = {
5149
4177
  [G in GeomName]: LayerInputOf<G>;
5150
- }[GeomName] | CustomGeomLayerInput;
4178
+ }[GeomName];
5151
4179
 
5152
- export declare interface LayerInputBase {
4180
+ declare interface LayerInputBase {
5153
4181
  type: 'layer';
5154
4182
  /** Stable identifier; auto-assigned during resolution when omitted. */
5155
4183
  id?: string;
5156
4184
  /** Layer-local aesthetic mapping, merged over the spec-level mapping. */
5157
4185
  mapping?: AesMapping;
5158
- /**
5159
- * Statistical transform applied to this layer (e.g. count, mean, smooth), or a custom plugin stat.
5160
- * @default 'identity'
5161
- */
5162
- stat?: StatName | StatInput | CustomStatInput<string>;
5163
- /** How overlapping geoms are arranged (stack, dodge, fill, identity). */
4186
+ /** Statistical transform applied to this layer (e.g. count, mean, smooth). @default 'identity' */
4187
+ stat?: StatName | StatInput;
4188
+ /** How overlapping marks are arranged (stack, dodge, fill, identity). */
5164
4189
  position?: PositionType;
5165
4190
  /** Which y scale this layer binds to — the primary or secondary axis. */
5166
4191
  yScaleType?: YScaleType;
@@ -5183,93 +4208,13 @@ declare type LayerInputOf<G extends GeomName> = LayerInputBase & {
5183
4208
  params?: Partial<GeomParamsMap[G]>;
5184
4209
  };
5185
4210
 
5186
- /**
5187
- * The layer step of the compile pipeline: it brackets {@link LayerCompiler} with checks so the main
5188
- * {@link Compiler} sees a single call. One {@link compile} runs three phases:
5189
- *
5190
- * 1. {@link checkPreCompile} — per-layer invariant checks collected across all layers, then the first
5191
- * thrown as a representative `UserInputError`, so the compile cache never holds output for a
5192
- * rejected layer.
5193
- * 2. {@link LayerCompiler.compile} — the actual per-layer compilation (memoized).
5194
- * 3. {@link checkPostCompile} — advisory checks over the compiled output (currently: nothing-to-plot),
5195
- * emitted as non-fatal warnings.
5196
- */
5197
- declare class LayerPhasedCompiler {
5198
- private readonly container;
5199
- private readonly transformCompiler;
5200
- private readonly statRegistry;
5201
- private readonly layerCompiler;
5202
- constructor(container: CommonContainer, transformCompiler: TransformCompiler, statRegistry: StatRegistry, layerCompiler: LayerCompiler);
5203
- /** Cache telemetry for the wrapped layer compile, surfaced to the main compiler's per-stage stats. */
5204
- get stats(): MemoStats;
5205
- /** Validate inputs, compile each layer, then inspect the compiled output. */
5206
- compile(input: LayerCompilerInput): CompiledLayer[];
5207
- /** Pre-compile: validate each layer's spec, aborting the pipeline if any layer is invalid. */
5208
- checkPreCompile(input: LayerCompilerInput): void;
5209
- /**
5210
- * Post-compile: a chart whose every layer resolved to zero observations compiles cleanly but
5211
- * renders blank. Surface that as a warning so an empty dataset — or transforms that filtered every
5212
- * row away — is non-silent for both the end user and codegen, rather than a confusingly empty plot.
5213
- */
5214
- checkPostCompile(layers: CompiledLayer[]): void;
5215
- /**
5216
- * Run every per-layer check and collect their issues. Each check reads what the geom *declares*
5217
- * (its position contract, its `validateMapping` hook, its supported coords) rather than which geom
5218
- * it is, so a custom geom is validated by the same path as a built-in.
5219
- *
5220
- * 1. Required aesthetics are present (accounting for stat-computed variables).
5221
- * 2. Every mapped variable exists in the layer's dataset.
5222
- * 3. Each custom positional aesthetic maps to a numeric column.
5223
- * 4. The geom's own bespoke mapping requirement, if it declares one.
5224
- * 5. The geom supports the active coord system.
5225
- */
5226
- validateLayer(input: LayerValidationInput): UserInputIssue[];
5227
- /**
5228
- * Checks that all aesthetics required by the geom are present (accounting for stat-computed variables).
5229
- */
5230
- private validateRequiredAesthetics;
5231
- /**
5232
- * Checks that every mapped variable in the effective mapping exists in the layer's dataset (after
5233
- * transforms). Skips aesthetics that will be computed by stats (e.g. `y` when `stat='count'`).
5234
- */
5235
- private validateVariableExistence;
5236
- /**
5237
- * Checks that each **custom** positional aesthetic an interval (`min`/`max`) or `scalar` role binds
5238
- * maps to a numeric column. The position mapper reads these columns as numbers to scale them, so a
5239
- * categorical or temporal column would throw deep in the pipeline (a misclassified internal error);
5240
- * flagging it here names the offending aesthetic in a user-facing error instead.
5241
- *
5242
- * Only custom aesthetics (those whose name differs from the role's axis) are checked — a built-in `x`/`y`
5243
- * is already covered by the scale-compatibility pass and the geom's own `validateMapping` — and a role
5244
- * sourced from a constant or a stat-computed variable is left to the existing checks.
5245
- */
5246
- private validatePositionalAestheticTypes;
5247
- /**
5248
- * Runs the geom's own bespoke mapping requirement, if it declares one (e.g. a rule's "exactly one
5249
- * of x or y"). The geom returns geom-scoped issues; the validator stamps the layer context on.
5250
- */
5251
- private validateGeomMapping;
5252
- /**
5253
- * Rejects a layer under a coord system its geom doesn't declare support for (e.g. a rule under
5254
- * polar). Reads `supportedCoordTypes` so a custom geom is gated by what it declares, not by name.
5255
- */
5256
- private validateCoordSupport;
5257
- /**
5258
- * Flags a mapping that names an aesthetic the geom never declared — neither in its position
5259
- * contract (the position aesthetics) nor its declared `aesthetics`, and not one of the
5260
- * {@link UNIVERSAL_AESTHETICS} or a stat-computed channel. The extra mapping is silently ignored
5261
- * downstream, so this is a warning (a likely typo, e.g. `size` on a bar) rather than a hard error.
5262
- */
5263
- private collectUndeclaredAesthetics;
5264
- }
5265
-
5266
4211
  /**
5267
4212
  * Discriminated union of all resolved layer specs, keyed on `geom`.
5268
4213
  * All properties are fully resolved — no optionals.
5269
4214
  */
5270
- export declare type LayerSpec = {
4215
+ declare type LayerSpec = {
5271
4216
  [G in GeomName]: LayerSpecOf<G>;
5272
- }[GeomName] | CustomGeomLayerSpec;
4217
+ }[GeomName];
5273
4218
 
5274
4219
  declare interface LayerSpecBase {
5275
4220
  type: 'layer';
@@ -5288,7 +4233,7 @@ declare type LayerSpecOf<G extends GeomName> = LayerSpecBase & {
5288
4233
  params: GeomParamsMap[G];
5289
4234
  };
5290
4235
 
5291
- /** Optional per-layer aggregates the summariser emits for label rendering. Fields are present only when the layer's geom calls for them. */
4236
+ /** Optional per-layer aggregates the summariser emits for label rendering. Fields are present only when the layer's geometry calls for them. */
5292
4237
  export declare interface LayerSummary {
5293
4238
  /** Per-x stack totals — one entry per x. */
5294
4239
  stackTotals?: StackTotalEntry[];
@@ -5298,12 +4243,27 @@ export declare interface LayerSummary {
5298
4243
  absoluteGrandTotal?: number;
5299
4244
  }
5300
4245
 
5301
- /** A single layer's resolved inputs, as fed to {@link LayerPhasedCompiler.validateLayer}. */
4246
+ /**
4247
+ * Per-layer invariant checks. Runs before {@link LayerCompiler} so the compile cache never holds
4248
+ * output for rejected layers.
4249
+ */
4250
+ declare class LayerValidationCheck {
4251
+ private readonly transformCompiler;
4252
+ private readonly validator;
4253
+ constructor(transformCompiler: TransformCompiler, validator: LayerValidator);
4254
+ check(input: LayerValidationCheckInput): void;
4255
+ }
4256
+
4257
+ declare interface LayerValidationCheckInput {
4258
+ data: Dataset;
4259
+ layers: LayerSpec[];
4260
+ mapping: AesMapping;
4261
+ coords: CoordSpec;
4262
+ }
4263
+
5302
4264
  declare interface LayerValidationInput {
5303
4265
  layerId: string;
5304
- /** Position of the layer in `spec.layers`, carried into diagnostic `context`. */
5305
- layerIndex: number;
5306
- geom: string;
4266
+ geom: GeomName;
5307
4267
  stat: StatSpec;
5308
4268
  /** `spec.mapping` merged with `layer.mapping` */
5309
4269
  effectiveMapping: AesMapping;
@@ -5314,8 +4274,45 @@ declare interface LayerValidationInput {
5314
4274
  }
5315
4275
 
5316
4276
  /**
5317
- * Default outer padding around the graph, in pixels, used when {@link buildLayoutGrid} gets no explicit
5318
- * `padding` (the renderer overrides it with a resolved theme token).
4277
+ * Validates a single layer against a set of invariants.
4278
+ *
4279
+ * Checks:
4280
+ * 1. All required aesthetics are present (accounting for stat-computed variables).
4281
+ * 2. All mapped variables exist in the layer's dataset (after transforms).
4282
+ *
4283
+ * Returns issues rather than throwing. The caller (LayerCompiler) batches issues across all layers and throws
4284
+ * a single SpecValidationError at the end.
4285
+ */
4286
+ declare class LayerValidator {
4287
+ private readonly geomRegistry;
4288
+ private readonly statRegistry;
4289
+ constructor(geomRegistry: GeomRegistry, statRegistry: StatRegistry);
4290
+ validate(input: LayerValidationInput): ValidationIssue[];
4291
+ /**
4292
+ * Checks that all aesthetics required by the geom are present (accounting for stat-computed variables).
4293
+ */
4294
+ private validateRequiredAesthetics;
4295
+ /**
4296
+ * Checks that every mapped variable in the effective mapping exists in the layer's dataset (after
4297
+ * transforms). Skips aesthetics that will be computed by stats (e.g. `y` when `stat='count'`).
4298
+ */
4299
+ private validateVariableExistence;
4300
+ /**
4301
+ * Rule layers need exactly one numeric ValueMapping on `x` or `y`, unless a stat produces the
4302
+ * value at compile time (e.g. `stat.mean()` populates `y`).
4303
+ */
4304
+ private validateRuleMapping;
4305
+ /**
4306
+ * In the current version, rule layers don't have meaningful semantics under polar coords (pie / donut).
4307
+ */
4308
+ private validateRuleCoord;
4309
+ }
4310
+
4311
+ /**
4312
+ * Outer padding around the whole chart, in pixels. Already baked into every {@link GraphLayout} rect
4313
+ * (rects start at this inset), so don't re-add it when painting — it is exported only so callers can
4314
+ * reconcile against the container edge. The per-region gaps below are intentionally internal; trust the
4315
+ * returned rects rather than reproducing the spacing.
5319
4316
  */
5320
4317
  export declare const LAYOUT_PADDING = 24;
5321
4318
 
@@ -5344,28 +4341,9 @@ export declare class LayoutCompiler {
5344
4341
  constructor(measurer: LayoutMeasurer);
5345
4342
  compile(input: LayoutCompilerInput): LayoutCompileResult;
5346
4343
  /**
5347
- * Computes space that needs to be added inside and outside of the panel frame to
5348
- * accomodate content that may overflow its boundary.
5349
- */
5350
- private measurePanelOverflow;
5351
- /**
5352
- * Reserves space for overflowing content by re-measuring against the reserved panel until the reserve settles.
5353
- * Data-anchored content moves as the panel shrinks, so this handles the case where a single pass may under-reserve
5354
- * if an element is particularly close to the boundary.
5355
- */
5356
- private settlePanelOverflow;
5357
- /**
5358
- * Shapes the polar panel into a centred 1:1 square so the drawing frame has a single, aspect-free
5359
- * scale: geoms position marks as a percentage of a square viewport (fixed pixel radius, no resize
5360
- * re-render) and the inscribed circle is identical for guides, marks, hover and highlight. For a
5361
- * radar (circular axis) the panel is first inset on all four sides by the widest rim label — circular
5362
- * and radial axes claim no edge track (see measureGuides), so without this the outer ring would touch
5363
- * the shorter panel edge and rim labels would overflow — then squared. A pie/donut (no circular axis)
5364
- * is squared without a rim inset.
4344
+ * Computes the panel pad needed so annotation labels stay inside the graph and don't overlap the panel edges.
5365
4345
  */
5366
- private applyPolarPanelInset;
5367
- /** Rim-label inset for a radar's circular axis (widest label + gap per side); zero for a pie/donut. */
5368
- private measurePolarRimInset;
4346
+ private measureAnnotationOverflow;
5369
4347
  /**
5370
4348
  * Stamps each axis with a single hardcoded-label placeholder tick. This gives the grid something to measure in
5371
4349
  * the first pass. The finalize pass replaces it with the real candidate selected for the resolved panel size.
@@ -5392,9 +4370,9 @@ export declare class LayoutCompiler {
5392
4370
  export declare interface LayoutCompileResult {
5393
4371
  layout: GraphLayout;
5394
4372
  /**
5395
- * The axes with their final ticks already chosen and formatted by the compiler. Paint each
4373
+ * The axes with their final ticks already chosen and formatted by the compiler paint each
5396
4374
  * `ticks[].formattedLabel` as-is. Tick selection runs as part of layout (it depends on the resolved
5397
- * panel size), so the renderer does not re-run candidate selection or re-apply a value format.
4375
+ * panel size), so do not re-run candidate selection or re-apply a value format in the renderer.
5398
4376
  */
5399
4377
  formattedAxes: FormattedAxis[];
5400
4378
  }
@@ -5406,7 +4384,7 @@ export declare interface LayoutCompilerInput {
5406
4384
  parsingLocale: Locale;
5407
4385
  numberFormat: NumberFormatConfig;
5408
4386
  formattedLegends: FormattedLegend[];
5409
- /** Total pixel area available to the whole graph. */
4387
+ /** Total pixel area available to the whole chart. */
5410
4388
  containerSize: BoxSize;
5411
4389
  externalMeasurements: ExternalMeasurements;
5412
4390
  /** The headline to measure and place; absent = no headline. */
@@ -5415,20 +4393,14 @@ export declare interface LayoutCompilerInput {
5415
4393
  formattingLocale?: Locale;
5416
4394
  /** Annotations that may overflow the panel and need extra edge padding reserved. */
5417
4395
  annotations?: CompiledAnnotations;
5418
- /** Coord system, consulted only to decide whether panel overflow applies (cartesian only). */
4396
+ /** Coord system, consulted only to decide whether annotation overflow applies (cartesian only). */
5419
4397
  coordSystem?: CoordSystem;
5420
- /** Font size multiplier applied to all text drawn by the renderer. */
5421
- textScale?: number;
5422
- /** Compiled layers, used to reserve panel padding for data labels that would otherwise overflow the cross axis. */
5423
- layers?: readonly CompiledLayer[];
5424
- /** Strategy to apply when content overflows the panel (configured per content type) */
5425
- overflowStrategy?: OverflowStrategyInput;
5426
4398
  /**
5427
- * * Outer padding around the whole chart, in pixels, applied uniformly on all four sides. Defaults to
5428
- * {@link LAYOUT_PADDING} when omitted. Renderers thread a resolved theme token here so a consumer can
5429
- * tighten or loosen the frame (e.g. a borderless, recolored chart that wants less surrounding space).
4399
+ * Must equal the renderer's actual text zoom. It only affects layout when difference-arrow
4400
+ * annotations exist on a cartesian coord, where it scales their label measurements to reserve the
4401
+ * right panel-edge padding; otherwise it is inert.
5430
4402
  */
5431
- padding?: number;
4403
+ textScale?: number;
5432
4404
  }
5433
4405
 
5434
4406
  /** Positions where axes/labels/legends can be placed around the panel. */
@@ -5453,8 +4425,6 @@ export declare interface LayoutMeasurer extends HeadlineMeasurer {
5453
4425
  measureTickLabel: (label: string) => MeasuredText;
5454
4426
  /** Returns the size of a difference-arrow label rendered at the given size. */
5455
4427
  measureDifferenceArrowLabel: (text: string, size: DifferenceArrowSize) => MeasuredText;
5456
- /** Returns the size of a data label of the given kind. */
5457
- measureDataLabel: DataLabelTextMeasurer;
5458
4428
  }
5459
4429
 
5460
4430
  declare interface Legend {
@@ -5494,7 +4464,7 @@ declare type LegendConfigInput = Partial<LegendConfig>;
5494
4464
  */
5495
4465
  declare type LegendDisplay = 'pill' | 'direct' | 'auto';
5496
4466
 
5497
- /** One item in a legend: a domain value paired with the visual values that represent it. */
4467
+ /** One entry in a legend: a domain value paired with the visual values that represent it. */
5498
4468
  export declare interface LegendItem {
5499
4469
  /** Raw data value (e.g., "Apples") */
5500
4470
  value: DataValue;
@@ -5508,12 +4478,13 @@ export declare interface LegendItem {
5508
4478
  */
5509
4479
  normalizedY: number | null;
5510
4480
  /**
5511
- * The geom whose swatch this item describes. Per-item because a single merged legend can span
5512
- * layers of different geoms (e.g. a combo chart's bar series and line series share one legend).
5513
- * The renderer maps it to a swatch shape via its `(geom, coord)` registry the same geom that
5514
- * drives the headline and rule pills.
4481
+ * Visual signature of the geom this item describes. Per-item because a
4482
+ * single merged legend can span layers of different geoms (e.g. a combo
4483
+ * chart's bar series and line series share one legend). Resolved via the
4484
+ * same {@link SwatchShape} mapping that drives the headline and rule pills,
4485
+ * so a series paints one consistent mark everywhere.
5515
4486
  */
5516
- geom: string;
4487
+ swatchShape: SwatchShape;
5517
4488
  /**
5518
4489
  * Format descriptor for this item's `value`. Per-item because a combo legend can span layers
5519
4490
  * whose aesthetic variables have different inferred formats.
@@ -5527,41 +4498,18 @@ export declare interface LegendItem {
5527
4498
  declare interface LegendItemVisual {
5528
4499
  color?: string;
5529
4500
  /**
5530
- * Symbol diameter in pixels, present on bubble legends (see {@link CompiledLegendGuide.aesthetics}). Render a
4501
+ * Symbol diameter in PIXELS, present on bubble legends (see {@link CompiledLegendGuide.aesthetics}). Render a
5531
4502
  * sized circle rather than a swatch; skip the item when this is non-finite or ≤ 0.
5532
4503
  */
5533
4504
  size?: DataValue;
5534
4505
  alpha?: DataValue;
5535
4506
  strokeWidth?: DataValue;
5536
- /** Stroke style for `line` / `area` swatches only (solid/dashed/dotted). Other swatch shapes ignore it. */
4507
+ /** Stroke style for `line` / `area` swatches only (solid/dashed/dotted). Other `swatchShape`s ignore it. */
5537
4508
  lineType?: LineStyleType;
5538
4509
  }
5539
4510
 
5540
- /**
5541
- * How a geom relates to the colour legend. Read by the legends guide to decide whether a redundant
5542
- * single-item legend is dropped, where an `'auto'` legend lands, and whether direct (inline) labels
5543
- * can stand in for it.
5544
- */
5545
- export declare interface LegendPolicy {
5546
- /** When a single item renders, the legend is redundant (the graph shows it directly), so suppress it. */
5547
- suppressWhenSingleItem?: boolean;
5548
- /** When this geom's legend prefers the side (right) over the top; defaults to `'never'`. */
5549
- sidePlacement?: LegendSidePlacement;
5550
- /** Positions for which this geom shows direct (inline) series labels instead of a pill legend. */
5551
- directLabelSupport?: Partial<Record<PositionType, boolean>>;
5552
- }
5553
-
5554
4511
  declare type LegendPosition = 'auto' | 'right' | 'left' | 'top' | 'bottom' | 'none';
5555
4512
 
5556
- /**
5557
- * When a geom's colour legend prefers the side (right) over the top, used to resolve an `'auto'`
5558
- * legend position once the rendered item count is known:
5559
- * - `'never'`: always top-placed (the default — point, rule, and any geom that doesn't opt in).
5560
- * - `'whenCrowded'`: moves to the side once there are many items (line/area).
5561
- * - `'whenStackedVertical'`: moves to the side only for vertically-stacked layers (bar).
5562
- */
5563
- export declare type LegendSidePlacement = 'never' | 'whenCrowded' | 'whenStackedVertical';
5564
-
5565
4513
  declare function line(options?: GeomOptions<'line'>): LayerInputOf<'line'>;
5566
4514
 
5567
4515
  /**
@@ -5570,7 +4518,7 @@ declare function line(options?: GeomOptions<'line'>): LayerInputOf<'line'>;
5570
4518
  export declare interface LineGeomParams {
5571
4519
  /**
5572
4520
  * Stroke width in pixels. `'auto'` reads the per-observation `strokeWidth`
5573
- * value (`getStrokeWidth`) and falls back to the geom default when unmapped.
4521
+ * channel (`getStrokeWidth`) and falls back to the geom default when unmapped.
5574
4522
  */
5575
4523
  lineWidth: number | 'auto';
5576
4524
  /**
@@ -5588,12 +4536,6 @@ export declare interface LineGeomParams {
5588
4536
  * @default 'gap'
5589
4537
  */
5590
4538
  missingValues: MissingValuesType;
5591
- /**
5592
- * Draws a gradient fill beneath the line (series color fading from the line down to
5593
- * transparent at the panel baseline).
5594
- * @default true
5595
- */
5596
- showFill: boolean;
5597
4539
  }
5598
4540
 
5599
4541
  declare interface LineOptions {
@@ -5602,8 +4544,6 @@ declare interface LineOptions {
5602
4544
  showPoints?: boolean;
5603
4545
  /** How gaps in the data are drawn: leave a gap, connect across, or treat as zero. */
5604
4546
  missingValues?: 'gap' | 'connect' | 'zero';
5605
- /** Draws a gradient fill beneath the line (single series only) */
5606
- showFill?: boolean;
5607
4547
  }
5608
4548
 
5609
4549
  /**
@@ -5615,7 +4555,13 @@ declare interface LineOptions {
5615
4555
  */
5616
4556
  export declare type LineStyleType = 'solid' | 'dashed' | 'dotted';
5617
4557
 
5618
- /** One of the BCP-47 locale strings the engine supports for number and date formatting. */
4558
+ /**
4559
+ * One of the BCP-47 locale strings the engine supports for number and date
4560
+ * formatting. Used both to parse source values and as the display fallback (see
4561
+ * `ConfigSpec.parsingLocale`); a `format*` helper's `formattingLocale` param
4562
+ * overrides display. The supported set is deliberately small (see `LOCALES`),
4563
+ * and `duration` always formats in English regardless of the locale.
4564
+ */
5619
4565
  export declare type Locale = (typeof LOCALES)[number];
5620
4566
 
5621
4567
  /** The full set of supported BCP-47 locale strings. */
@@ -5646,12 +4592,9 @@ export declare interface LookupValueFormat {
5646
4592
 
5647
4593
  /**
5648
4594
  * The data-space axis a `CartesianCoordSystem` uses as the main (independent) axis.
5649
- * When `mainAxis === 'y'` (flip), the position variable roles swap: the x-variables (`getX`/`getXMin`/
5650
- * `getXMax`) carry the measure / cross-axis extent and the y-variables carry the main-axis band
5651
- * position. The swap is baked into the position variables at compile time (the coord transform renames
5652
- * them), so `getX`/`getY` map straight to their pixel axes regardless of flip. This flag is for
5653
- * consumers that must reason about which data axis is independent — guide placement, hover bucketing,
5654
- * label and arrow growth direction — via the `coord/axes` main/cross helpers.
4595
+ * When `mainAxis === 'y'` (flip), the position column roles swap: the x-columns (`getX`/`getXMin`/
4596
+ * `getXMax`) carry the measure / cross-axis extent and the y-columns carry the main-axis band
4597
+ * position. Geoms branch on this to decide which reader feeds which pixel axis.
5655
4598
  */
5656
4599
  export declare type MainAxis = 'x' | 'y';
5657
4600
 
@@ -5685,7 +4628,13 @@ declare interface MeanStatSpec {
5685
4628
  type: 'mean';
5686
4629
  }
5687
4630
 
5688
- /** Pixel dimensions of a measured string, including the baseline split into ascent and descent. */
4631
+ /**
4632
+ * Pixel dimensions of a measured string, in CSS pixels. `height === ascent + descent`, where ascent
4633
+ * and descent come from the font box (canvas `fontBoundingBoxAscent`/`fontBoundingBoxDescent`), not
4634
+ * the glyph box — so the height reflects the font's line metrics and is stable across strings rather
4635
+ * than tracking the actual glyphs drawn. `width` is the advance width (the pen advance), not the
4636
+ * tight ink bounding box.
4637
+ */
5689
4638
  export declare interface MeasuredText {
5690
4639
  width: number;
5691
4640
  height: number;
@@ -5708,7 +4657,8 @@ export declare interface MemoStats {
5708
4657
  * sees no nulls and paths normally.
5709
4658
  * - `'gap'` — Leave a visible gap where values are missing. The renderer breaks the path at any
5710
4659
  * null x / y (e.g. d3's `defined()`).
5711
- * - `'connect'` — Skip missing values and connect adjacent valid points. The renderer drops nulls before pathing.
4660
+ * - `'connect'` — Skip missing values and connect adjacent valid points. The renderer drops null
4661
+ * rows before pathing.
5712
4662
  */
5713
4663
  export declare type MissingValuesType = 'zero' | 'gap' | 'connect';
5714
4664
 
@@ -5768,12 +4718,9 @@ declare type NeonPaletteConfig = {
5768
4718
  variant?: NeonPaletteVariant;
5769
4719
  };
5770
4720
 
5771
- /** `waterfall` swaps in the positive/negative/total colors used by waterfall graphs. */
4721
+ /** `waterfall` swaps in the positive/negative/total colors used by waterfall charts. */
5772
4722
  declare type NeonPaletteVariant = 'default' | 'waterfall';
5773
4723
 
5774
- /** Wrap an angle into `[0, 2π)`. */
5775
- export declare const normalizeAngle: (angle: number) => number;
5776
-
5777
4724
  /**
5778
4725
  * Configuration for formatting a single number.
5779
4726
  * Defines how numeric values should be displayed in the chart.
@@ -5805,11 +4752,15 @@ export declare interface NumberFormatConfig {
5805
4752
  */
5806
4753
  decimalSeparator?: string;
5807
4754
  /**
5808
- * Prefix to prepend (e.g., '$', '€').
4755
+ * Prefix to prepend (e.g., '$', '€'). No value formatter reads this — it is
4756
+ * renderer-applied (currently inert in this package); a rebuild must prepend
4757
+ * it to the formatted string itself.
5809
4758
  */
5810
4759
  prefix?: string;
5811
4760
  /**
5812
- * Suffix to append (e.g., '%', ' units').
4761
+ * Suffix to append (e.g., '%', ' units'). No value formatter reads this — it
4762
+ * is renderer-applied (currently inert in this package); a rebuild must append
4763
+ * it to the formatted string itself.
5813
4764
  */
5814
4765
  suffix?: string;
5815
4766
  }
@@ -5835,8 +4786,8 @@ export declare interface ObservationAnchor {
5835
4786
  layerId?: string;
5836
4787
  /** Value on the main axis (x in cartesian, y in flipped). */
5837
4788
  anchorValue: DataValue;
5838
- /** The group value to match if any, otherwise match any group. */
5839
- groupValue?: DataValue;
4789
+ /** Series identity (the `group` aesthetic value). */
4790
+ groupValue: DataValue;
5840
4791
  }
5841
4792
 
5842
4793
  /** Points at a single observation by its anchor value and series. */
@@ -5845,31 +4796,12 @@ export declare interface ObservationAnchorInput {
5845
4796
  layerIndex?: number;
5846
4797
  /** Value on the main axis (x in cartesian, y in flipped). */
5847
4798
  anchorValue: DataValue;
5848
- /** The group value to match if any, otherwise match any group. */
5849
- groupValue?: DataValue;
4799
+ /** Series identity (the `group` aesthetic value). */
4800
+ groupValue: DataValue;
5850
4801
  }
5851
4802
 
5852
4803
  declare type Options = Partial<LineOptions & BarOptions & ScatterOptions & ComboOptions & PieOptions & TableOptions>;
5853
4804
 
5854
- /** How far an anchor may sit outside the panel before a callout is considered out of view. */
5855
- export declare const OUT_OF_VIEW_MARGIN_PX = 8;
5856
-
5857
- /**
5858
- * Configure a different overflow strategy per direction.
5859
- */
5860
- export declare interface OverflowStrategyConfig {
5861
- x: PanelOverflowStrategy;
5862
- y: PanelOverflowStrategy;
5863
- }
5864
-
5865
- /**
5866
- * Overflow strategy to user per content type
5867
- */
5868
- export declare interface OverflowStrategyInput {
5869
- dataLabels?: OverflowStrategyConfig;
5870
- differenceArrows?: OverflowStrategyConfig;
5871
- }
5872
-
5873
4805
  /** Resolved palette selector; a custom palette carries its looked-up `colors`. */
5874
4806
  declare type PaletteConfig = DefaultPaletteConfig | GraphyPaletteConfig | PastelPaletteConfig | NeonPaletteConfig | MonoPaletteConfig | CustomPaletteConfig;
5875
4807
 
@@ -5896,7 +4828,7 @@ export declare type PaletteOverridesInput = Record<number, {
5896
4828
  /** User-facing palette color scale; defaults to the active theme palette when `palette` is omitted. */
5897
4829
  declare interface PaletteScaleInput {
5898
4830
  type: 'scale';
5899
- /** Which aesthetic this scale drives — only color aesthetics accept palettes. */
4831
+ /** Which channel this scale drives — only color channels accept palettes. */
5900
4832
  scaledAesthetic: ScaledAestheticKey;
5901
4833
  scaleType: 'palette';
5902
4834
  /** Named or custom palette to draw group colors from. */
@@ -5921,91 +4853,21 @@ declare interface PaletteScaleSpec {
5921
4853
  overrides?: PaletteOverrides;
5922
4854
  }
5923
4855
 
5924
- /** One side of the panel border. */
5925
- export declare type PanelBorderEdge = 'top' | 'right' | 'bottom' | 'left';
5926
-
5927
- /**
5928
- * Configuration for one edge of the panel border.
5929
- */
5930
- export declare interface PanelBorderEdgeConfig {
5931
- /**
5932
- * Whether this edge is drawn.
5933
- * @default true
5934
- */
5935
- isVisible: boolean;
5936
- /**
5937
- * Line style of this edge.
5938
- * @default 'dashed'
5939
- */
5940
- lineStyle: LineStyleType;
5941
- /**
5942
- * Stroke width of this edge in px. null inherits the theme's grid line width.
5943
- * @default null
5944
- */
5945
- lineWidth: number | null;
5946
- }
5947
-
5948
- /** One stroke of the panel border: every segment in it shares a single line style and width. */
5949
- export declare interface PanelBorderPath {
5950
- lineStyle: LineStyleType;
5951
- /** Stroke width in px. null inherits the theme's grid line width. */
5952
- lineWidth: number | null;
5953
- segments: PanelBorderSegment[];
5954
- }
5955
-
5956
- /**
5957
- * A drawing primitive for the panel border, in the input rect's pixel space. Arcs follow the
5958
- * canvas 2D convention (radians, clockwise, y down) and start at the current point, so segments
5959
- * replay directly via `moveTo`/`lineTo`/`arc` or convert to an SVG path (`A` with sweep flag 1).
5960
- */
5961
- export declare type PanelBorderSegment = {
5962
- type: 'move';
5963
- x: number;
5964
- y: number;
5965
- } | {
5966
- type: 'line';
5967
- x: number;
5968
- y: number;
5969
- } | {
5970
- type: 'arc';
5971
- cx: number;
5972
- cy: number;
5973
- radius: number;
5974
- startAngle: number;
5975
- endAngle: number;
5976
- } | {
5977
- type: 'close';
5978
- };
5979
-
5980
4856
  /**
5981
- * Panel configuration. The border is configured per edge; a corner is rounded
5982
- * only when both edges meeting at it are visible.
4857
+ * Panel configuration
5983
4858
  */
5984
4859
  declare interface PanelConfig {
5985
- border: Record<PanelBorderEdge, PanelBorderEdgeConfig>;
5986
- /** Per-source, per-axis strategy to use for content that overflows the panel edge. */
5987
- overflow: {
5988
- dataLabels: OverflowStrategyConfig;
5989
- differenceArrows: OverflowStrategyConfig;
4860
+ border: {
4861
+ isVisible: boolean;
5990
4862
  };
5991
4863
  }
5992
4864
 
5993
- /**
5994
- * How the panel adapts to content that would otherwise overflow its edge.
5995
- * - `outside`: the overflowing element lands outside the panel frame and the frame shrinks to
5996
- * accomodate it.
5997
- * - `inside`: the overflowing element stays inside the panel frame and the content inside the
5998
- * frame shrinks to accomodate it.
5999
- * - `none`: no accomodation, content may overflow and overlap with other elements
6000
- */
6001
- export declare type PanelOverflowStrategy = 'outside' | 'inside' | 'none';
6002
-
6003
4865
  declare type PastelPaletteConfig = {
6004
4866
  type: 'pastel';
6005
4867
  variant?: PastelPaletteVariant;
6006
4868
  };
6007
4869
 
6008
- /** `waterfall` swaps in the positive/negative/total colors used by waterfall graphs. */
4870
+ /** `waterfall` swaps in the positive/negative/total colors used by waterfall charts. */
6009
4871
  declare type PastelPaletteVariant = 'default' | 'waterfall';
6010
4872
 
6011
4873
  /**
@@ -6032,7 +4894,7 @@ declare abstract class PerLayerStage<Input extends {
6032
4894
  }
6033
4895
 
6034
4896
  declare interface PieOptions {
6035
- /** Where the aggregate total is shown: inside the ring (donut) or outside the graph. */
4897
+ /** Where the aggregate total is shown: inside the ring (donut) or outside the chart. */
6036
4898
  pieTotalPosition?: 'center' | 'outside';
6037
4899
  }
6038
4900
 
@@ -6041,68 +4903,37 @@ declare interface PieOptions {
6041
4903
  * renderer's mini view shows the observation's measurement value; hover reveals
6042
4904
  * the full tooltip (x + y + trend).
6043
4905
  */
6044
- export declare interface PinnedNumberAnnotationInput {
4906
+ declare interface PinnedNumberAnnotationInput {
6045
4907
  id?: string;
6046
- at: ObservationAnchorInput;
4908
+ anchor: ObservationAnchorInput;
6047
4909
  }
6048
4910
 
6049
- export declare interface PinnedNumberAnnotationSpec {
4911
+ declare interface PinnedNumberAnnotationSpec {
6050
4912
  id: string;
6051
- at: ObservationAnchor;
4913
+ anchor: ObservationAnchor;
6052
4914
  }
6053
4915
 
6054
4916
  /**
6055
- * Fold a sequence of pipeable spec items onto an existing spec, left to right, returning a new spec.
6056
- * Each item is appended by kind: layers accumulate (call `geom.*` once per mark), scales accumulate,
6057
- * `config` deep-merges, `coord`/`mapping` overwrite/merge. The usual shape is
6058
- * `pipe(createSpec({...}), geom.x(), scale.x(), scale.y(), ...)`.
6059
- *
6060
- * @example
6061
- * pipe(createSpec({ x: 'month', y: 'sales', color: 'region' }), geom.line(), scale.x(), scale.y(), scale.color.palette());
4917
+ * Pipe a spec through a series of spec items (left-to-right).
6062
4918
  */
6063
4919
  export declare function pipe(spec: SpecInput, ...items: SpecItem[]): SpecInput;
6064
4920
 
6065
- /**
6066
- * Turns compiled pinned-number and comment annotations into render-ready `PlacedCallout` rects.
6067
- */
6068
- export declare function placeCallouts(input: PlaceCalloutsInput): PlacedCallout[];
6069
-
6070
- export declare interface PlaceCalloutsInput {
6071
- pinnedNumbers: readonly CompiledPinnedNumberAnnotation[];
6072
- comments: readonly CompiledCommentAnnotation[];
6073
- panelRect: Rect;
6074
- coordSystem: CoordSystem;
6075
- measurer: CalloutMeasurer;
6076
- formatPinnedNumber: (annotation: CompiledPinnedNumberAnnotation) => string;
6077
- }
6078
-
6079
- /**
6080
- * One placed callout, ready for a renderer to paint. Coordinates are in panel-pixel space
6081
- * with origin at the panel's top-left.
6082
- */
6083
- export declare interface PlacedCallout {
6084
- id: string;
6085
- kind: CalloutKind;
6086
- /** Anchor position in panel-local SVG pixels (cartesian y already flipped to top-origin). */
6087
- anchorPx: {
6088
- x: number;
6089
- y: number;
6090
- };
6091
- placement: CalloutPlacement;
6092
- miniRect: Rect;
6093
- inView: boolean;
6094
- }
6095
-
6096
4921
  /**
6097
4922
  * One placed label, ready for a renderer to paint. Coordinates are in panel-pixel space
6098
4923
  * with origin at the panel's top-left — renderers translate into their own frame.
6099
4924
  *
6100
- * Labels are placed independently, with no cross-label overlap resolution — paint each as given.
4925
+ * Labels are placed independently, with NO cross-label overlap resolution — paint each as given.
6101
4926
  * (Contrast `computeDirectLabelsLayout`, which de-collides line-end labels against each other.)
6102
4927
  */
6103
4928
  export declare interface PlacedDataLabel {
6104
4929
  /** Id of the layer this label belongs to, so the renderer can group/style by source layer. */
6105
4930
  layerId: string;
4931
+ /**
4932
+ * Stable key — derived from data identity (X value + group), not array position. Per-observation
4933
+ * labels use `${layerId}:${stableKey([xValue, groupValue])}`; stack totals use
4934
+ * `${layerId}:stack:${xKey}`. Survives appends, removals, and reorders of `layer.data`.
4935
+ */
4936
+ key: string;
6106
4937
  x: number;
6107
4938
  y: number;
6108
4939
  text: string;
@@ -6117,55 +4948,8 @@ export declare interface PlacedDataLabel {
6117
4948
  position: DataLabelPosition;
6118
4949
  }
6119
4950
 
6120
- /**
6121
- * One entry in the unified `plugins` array. Either a bare compile definition, a render half that carries
6122
- * its definition at `.definition`, or a render-only override that carries none. The first two contribute
6123
- * a compile definition (matched structurally over the field that already exists, never by naming
6124
- * react-renderer's `GeomRendererDefinition` type); the last seeds only the render registry.
6125
- */
6126
- declare type Plugin_2 = CompileDefinition | {
6127
- readonly definition: CompileDefinition;
6128
- } | RenderOnlyPlugin;
6129
- export { Plugin_2 as Plugin }
6130
-
6131
4951
  declare function point(options?: GeomOptions<'point'>): LayerInputOf<'point'>;
6132
4952
 
6133
- /** Resolved point anchor: `layerIndex` replaced with the stable `layerId`. */
6134
- export declare type PointAnchor = {
6135
- anchorType: 'panel';
6136
- x: number;
6137
- y: number;
6138
- offset?: AnchorOffset;
6139
- } | {
6140
- anchorType: 'observation';
6141
- layerId?: string;
6142
- anchorValue: DataValue;
6143
- groupValue?: DataValue;
6144
- align?: AnchorAlign;
6145
- offset?: AnchorOffset;
6146
- };
6147
-
6148
- /**
6149
- * A single position, expressed as a relationship to the graph that re-resolves each compile.
6150
- *
6151
- * - `panel`: a fraction of the plot rect (`[0,1]`), top-left origin. Does not snap to data.
6152
- * - `observation`: pinned to one observation by its `(anchorValue, groupValue)` pair.
6153
- */
6154
- export declare type PointAnchorInput = {
6155
- anchorType: 'panel';
6156
- x: number;
6157
- y: number;
6158
- offset?: AnchorOffset;
6159
- } | {
6160
- anchorType: 'observation';
6161
- /** Pick a specific layer when multiple share the same `(anchorValue, groupValue)` pair. */
6162
- layerIndex?: number;
6163
- anchorValue: DataValue;
6164
- groupValue?: DataValue;
6165
- align?: AnchorAlign;
6166
- offset?: AnchorOffset;
6167
- };
6168
-
6169
4953
  /**
6170
4954
  * Point-specific parameters
6171
4955
  */
@@ -6179,13 +4963,6 @@ declare interface PointPosition {
6179
4963
  y: number;
6180
4964
  }
6181
4965
 
6182
- /**
6183
- * Pixels between a radar's outer ring and its rim category labels. Shared across the compile/render
6184
- * seam so the layout reserves exactly the margin the guide renderer paints into (the layout compiler's
6185
- * rim inset and the polar guide renderers derive from this one value rather than hand-synced copies).
6186
- */
6187
- export declare const POLAR_RIM_LABEL_GAP_PX = 8;
6188
-
6189
4966
  export declare interface PolarBarArcInput {
6190
4967
  startAngle: number;
6191
4968
  endAngle: number;
@@ -6229,8 +5006,8 @@ declare interface PolarCoordSpec {
6229
5006
  * `innerRadius` is also exposed here so the renderer can recover the donut hole geometry
6230
5007
  * (e.g. to place a centred headline) without reaching into per-observation radii.
6231
5008
  *
6232
- * Polar layers repurpose the position variables: x-variables carry angles, y-variables carry radii.
6233
- * Angles are absolute radians (`startAngle` already applied, clockwise),
5009
+ * Polar layers repurpose the position columns: x-columns carry angles, y-columns carry radii.
5010
+ * Angles are absolute radians (`startAngle` already applied, clockwise — matches d3-shape `arc()`),
6234
5011
  * passed through unmodified. Radii are [0,1] fractions of the outer radius, mapped into a unit
6235
5012
  * circle whose center is the panel center and whose radius is `min(panel.w, panel.h) / 2`.
6236
5013
  */
@@ -6244,39 +5021,9 @@ export declare interface PolarCoordSystem {
6244
5021
  * floor, so it is recoverable from any arc.
6245
5022
  */
6246
5023
  innerRadius: number;
6247
- /**
6248
- * Angular offset of the first position, in radians (the spec's `startAngle` converted from degrees).
6249
- * The angular transform bakes it into the `x` column and the guide renderer reuses it, so painted
6250
- * marks, spokes and rim labels share one origin.
6251
- */
6252
- startAngle: number;
6253
- /**
6254
- * Extra frame rotation, in radians, that lands the first categorical spoke on `startAngle`
6255
- * (first-axis-up). The band scale places category 0 at `1/(2N)`, so this is `−(1/(2N))·2π` for a
6256
- * categorical circular axis and `0` for a continuous one (pie/donut). Added alongside `startAngle`
6257
- * in the angular transform and recovered identically by the guide renderer.
6258
- */
6259
- spokeRotation: number;
6260
- /**
6261
- * Which position axis carries the chart's categorical band, or `null` when there is none: `'x'` for a
6262
- * radar/rose (categories spoke the angular axis), `'y'` for a radial bar (categories are concentric
6263
- * radial tracks — the post-swap radius column), `null` for a pie/donut (the angle is a continuous value
6264
- * sweep, so no position axis is categorical). Resolved once in `setup` so the guide compiler (does this
6265
- * polar chart draw axes?), the hover indexer (pie enclosure vs banded-bar snap, and which axis groups
6266
- * the bands), and the polar hover guide (wedge orientation) each read one fact rather than re-deriving
6267
- * it from mapping, axis geometry, or scale type.
6268
- */
6269
- bandAxis: 'x' | 'y' | null;
6270
5024
  }
6271
5025
 
6272
- /**
6273
- * Projects a polar coordinate (angle in radians clockwise from 12 o'clock, radius as a `[0, 1]`
6274
- * fraction) to an offset in a y-**up** unit disk centred at the origin: `(r·sinθ, r·cosθ)`. Callers
6275
- * that paint in a top-origin pixel frame negate `y` and scale by the pixel radius.
6276
- */
6277
- export declare const polarToUnit: (angle: number, radius: number) => XYPoint;
6278
-
6279
- /** Internal variables holding each observation's compiled positions (normalized to `[0, 1]`). */
5026
+ /** Internal column names holding each observation's compiled positions (normalized to `[0, 1]`). */
6280
5027
  export declare const POSITION_VARIABLES: {
6281
5028
  readonly x: string;
6282
5029
  readonly y: string;
@@ -6318,13 +5065,6 @@ declare class PositionAdjusterRegistry extends Registry<PositionType, PositionAd
6318
5065
  constructor();
6319
5066
  }
6320
5067
 
6321
- /**
6322
- * The aes keys a geom's position roles contribute: the open per-role keys ({@link AesFromRoles},
6323
- * including custom positional aesthetics). When `positionRoles` widened (no `as const`) the role set is
6324
- * untyped, so this relaxes to the full {@link AestheticKey} set and the exact-aes check is dropped.
6325
- */
6326
- declare type PositionAesKeys<Def extends Geom<unknown>> = IsWidenedTuple<Def['positionRoles']> extends true ? AestheticKey : Def['positionRoles'] extends readonly PositionRole[] ? AesFromRoles<Def['positionRoles'][number]> : never;
6327
-
6328
5068
  declare interface PositionalScaleMethods {
6329
5069
  /**
6330
5070
  * Continuous (numeric) scale. Supports `transform`, `reverse`, `nice`, `zero`, `domainMin`, `domainMax`.
@@ -6353,9 +5093,6 @@ declare interface PositionalScaleMethods {
6353
5093
  sqrt: (options?: ContinuousScaleOptions) => ContinuousScaleInput;
6354
5094
  }
6355
5095
 
6356
- /** The axis a position role binds to. */
6357
- export declare type PositionAxis = 'x' | 'y';
6358
-
6359
5096
  /**
6360
5097
  * A position variable mapper that applies position scaling for a single concern
6361
5098
  * (e.g. primary x, band extents, y baseline extents).
@@ -6372,9 +5109,8 @@ declare interface PositionMapper {
6372
5109
  * ([0,1]) on each layer's dataset.
6373
5110
  */
6374
5111
  declare class PositionMapperCompiler extends PerLayerStage<PositionMapperCompilerInput> {
6375
- private readonly container;
6376
5112
  private readonly mappers;
6377
- constructor(container: CommonContainer, mappers?: PositionMapper[]);
5113
+ constructor(mappers?: PositionMapper[]);
6378
5114
  protected dependencies(input: PositionMapperCompilerInput): readonly unknown[];
6379
5115
  protected compileLayer(layer: CompiledLayer, input: PositionMapperCompilerInput): CompiledLayer;
6380
5116
  }
@@ -6388,54 +5124,17 @@ declare interface PositionMapperCompilerInput {
6388
5124
  * Context passed to each column mapper during position mapping.
6389
5125
  */
6390
5126
  declare interface PositionMapperInput {
6391
- geomRegistry: GeomRegistry;
6392
5127
  data: Dataset;
6393
5128
  layer: CompiledLayer;
6394
5129
  getPositionScale: (scaleAestheticKey: ScaledAestheticKey) => CompiledPositionScale | null;
6395
5130
  }
6396
5131
 
6397
- /**
6398
- * One position column the geom's compile half injects and its render half reads (`yMin`/`yMax`/…).
6399
- * Declaring it makes the cross-half column contract explicit, so a single-half override can be
6400
- * checked rather than silently mispainting.
6401
- *
6402
- * `aes` names the aesthetic the mapper sources the role from — a plain `string`, so a geom may bind
6403
- * a **custom positional aesthetic** (`'open'`, `'low'`) the engine then trains and scales like a
6404
- * built-in channel. A `min`/`max` role without `aes` is compile-written (e.g. a bar's
6405
- * `yMin = 0`); a `scalar` role scales its `aes` column in place into the aesthetic-named column.
6406
- */
6407
- export declare interface PositionRole {
6408
- readonly axis: PositionAxis;
6409
- readonly role: PositionRoleKind;
6410
- readonly valueKind: 'value';
6411
- readonly aes?: string;
6412
- }
6413
-
6414
- /**
6415
- * The role a position column plays on its axis (named column semantics):
6416
- * - `point`: a single per-observation position; sources its axis aesthetic implicitly.
6417
- * - `scalar`: a single value scaled in place on the axis (e.g. a reference line).
6418
- * - `min` / `max`: the two ends of a per-observation interval (e.g. a bar's `[0, value]`).
6419
- */
6420
- export declare type PositionRoleKind = 'point' | 'scalar' | 'min' | 'max';
6421
-
6422
- /** A geom's position roles. */
6423
- declare type PositionRoles = readonly PositionRole[];
6424
-
6425
5132
  /**
6426
5133
  * Subset of {@link CompiledScales} the position mapper reads. Narrowed so visual-scale changes
6427
5134
  * don't enter this stage's cache dependency surface.
6428
5135
  */
6429
5136
  declare type PositionScalesSlice = Pick<CompiledScales, 'x' | 'y' | 'ySecondary'>;
6430
5137
 
6431
- /**
6432
- * Maps a normalized `[0, 1]` axis position to its absolute angle in radians, applying the coord's
6433
- * `startAngle` origin and the first-axis-up `spokeRotation`. The single owner of the position→angle
6434
- * convention: the compiler's angular transform bakes it into the `x` column and the guide renderer
6435
- * recovers it with the identical call, so marks, spokes and rim labels stay aligned.
6436
- */
6437
- export declare const positionToAngle: (position: number, startAngle: number, spokeRotation: number) => number;
6438
-
6439
5138
  /**
6440
5139
  * Position adjustment for overlapping geometries.
6441
5140
  *
@@ -6486,26 +5185,14 @@ export declare interface RadiusExtent {
6486
5185
  /** Resolves one observation's raw, type-filtered value for an aesthetic. */
6487
5186
  declare type RawValueReader = (observation: Observation) => DataValue;
6488
5187
 
6489
- /**
6490
- * Reads a numeric value from a layout geom's own author-named column. Returns `fallback`
6491
- * (default `0`) when the column is absent or non-finite, so a missing or `NaN`/`Infinity` value
6492
- * degrades to the fallback instead of corrupting geometry coordinates.
6493
- */
6494
- export declare function readAuthoredNumber(observation: Observation, key: VariableName, fallback?: number): number;
6495
-
6496
- /**
6497
- * Reads a string value from an observation's own author-named column. The string sibling of
6498
- * {@link readAuthoredNumber}: returns `fallback` (default `''`) when the column is absent or not a string.
6499
- */
6500
- export declare function readAuthoredString(observation: Observation, key: VariableName, fallback?: string): string;
6501
-
6502
5188
  export declare function readXExtent(primary: HoverHit): number | null;
6503
5189
 
6504
5190
  export declare function readYExtent(primary: HoverHit): number | null;
6505
5191
 
6506
5192
  /**
6507
5193
  * A rectangle in pixel coordinates, origin at top-left. Every rect on a {@link GraphLayout} is measured
6508
- * from the graph container top-left (with {@link LAYOUT_PADDING} already included), never panel-local coordinates.
5194
+ * from the chart CONTAINER top-left (with {@link LAYOUT_PADDING} already included), never panel- or
5195
+ * plot-local — paint against these absolute coordinates without re-offsetting.
6509
5196
  */
6510
5197
  export declare interface Rect {
6511
5198
  x: number;
@@ -6520,28 +5207,6 @@ declare interface ReferenceLines {
6520
5207
  averageLine?: AverageLine;
6521
5208
  }
6522
5209
 
6523
- /** Resolved region anchor. */
6524
- export declare type RegionAnchor = {
6525
- anchorType: 'panel';
6526
- x: number;
6527
- y: number;
6528
- width: number;
6529
- height: number;
6530
- };
6531
-
6532
- /**
6533
- * An area, expressed as a relationship to the graph.
6534
- *
6535
- * - `panel`: a rectangle in panel-rect fractions (`[0,1]`), top-left origin.
6536
- */
6537
- export declare type RegionAnchorInput = {
6538
- anchorType: 'panel';
6539
- x: number;
6540
- y: number;
6541
- width: number;
6542
- height: number;
6543
- };
6544
-
6545
5210
  /**
6546
5211
  * A typed key-value store for looking up registered implementations by name.
6547
5212
  *
@@ -6571,7 +5236,9 @@ declare class Registry<K extends string, T> {
6571
5236
  }
6572
5237
 
6573
5238
  /**
6574
- * Render-time context used for GraphConfig conversion.
5239
+ * Render-time context used for GraphConfig conversion. Consumed only by {@link Compiler.compile}; a
5240
+ * theme or palette change therefore requires a fresh `compile` (it cannot be applied via
5241
+ * {@link Compiler.recompile}, which takes no `ctx`).
6575
5242
  */
6576
5243
  export declare interface RendererContext {
6577
5244
  /** Theme used to resolve theme-dependent colors; defaults to light when omitted. */
@@ -6580,35 +5247,6 @@ export declare interface RendererContext {
6580
5247
  customPalettes?: CustomPalettesInput;
6581
5248
  }
6582
5249
 
6583
- /**
6584
- * A render-side spatial query a layout geom registers for its layer. The cursor arrives in
6585
- * panel-local `[0, 1]` with a top-left origin — the frame the geom paints in — so it tests against
6586
- * the geometry it drew without re-projecting. Returns the identity key under the cursor, or `null`.
6587
- *
6588
- * The returned `key` must equal `getStableKey(identityValue)`, the value {@link RenderHitTestIndex.byKey}
6589
- * stored. `getStableKey` is identity for strings but normalizes other types (e.g. `Date → toISOString()`),
6590
- * so a geom keying on a numeric/temporal column must return the normalized value or the lookup
6591
- * silently misses.
6592
- */
6593
- export declare type RenderHitTester = (cursor: {
6594
- x: number;
6595
- y: number;
6596
- }) => {
6597
- key: string;
6598
- } | null;
6599
-
6600
- /**
6601
- * A render-only plugin: a geom render half keyed by an existing geom name that contributes no compile
6602
- * definition (the by-name `defineGeomRenderer('bar', …)` override). The engine recognises it
6603
- * structurally — a render half with `geom`/`render` and no `.definition` — and skips it when seeding the
6604
- * compile registries, so the built-in compile half keeps running; only the renderer consumes it.
6605
- * React-free here: `render` is opaque to the engine, never called by it.
6606
- */
6607
- export declare interface RenderOnlyPlugin {
6608
- readonly geom: string;
6609
- readonly render: object;
6610
- }
6611
-
6612
5250
  /***************************************************************
6613
5251
  * Builders
6614
5252
  ***************************************************************/
@@ -6646,14 +5284,6 @@ declare interface ReshapeTransformInput {
6646
5284
  options: ReshapeOptions;
6647
5285
  }
6648
5286
 
6649
- /**
6650
- * Recover a plugin's compile definition: a render half carries it at `.definition`; a bare definition is
6651
- * its own. A render-only override (a render half with no `.definition`) contributes no compile half, so it
6652
- * resolves to `undefined`. Read structurally so the engine never imports a React type — and exported so
6653
- * react-renderer's render-half reader reuses this one read across the package boundary.
6654
- */
6655
- export declare function resolveDefinition(entry: Plugin_2): CompileDefinition | undefined;
6656
-
6657
5287
  /** A headline size with `'auto'` resolved away — what the renderer paints at. */
6658
5288
  export declare type ResolvedHeadlineSize = Exclude<HeadlineSize, 'auto'>;
6659
5289
 
@@ -6675,45 +5305,23 @@ export declare type ResolvedLegendDisplay = Exclude<LegendDisplay, 'auto'>;
6675
5305
  export declare type ResolvedLegendPosition = Exclude<LegendPosition, 'auto' | 'none'>;
6676
5306
 
6677
5307
  /**
6678
- * A point resolved from an observation.
5308
+ * An observation's anchor projected into normalized panel space `[0, 1]²`. Data-space origin
5309
+ * (y=0 at the bottom, matching `POSITION_VARIABLES.y`), so a top-origin renderer flips `y`
5310
+ * before painting — unlike `CompiledShape`/`CompiledTextAnnotation`, which are top-left.
6679
5311
  */
6680
- export declare interface ResolvedObservationPoint extends ResolvedPoint {
6681
- geom: string;
6682
- measurementValue: number;
6683
- valueFormat: ValueFormat;
6684
- color: string | undefined;
6685
- }
6686
-
6687
- /**
6688
- * A point anchor projected into normalized panel space `[0, 1]²`. One convention across all
6689
- * annotation kinds: data-space origin (y=0 at the bottom, matching `POSITION_VARIABLES.y`), so a
6690
- * top-origin renderer flips `y` before painting.
6691
- *
6692
- * The measurement fields (`geom`/`measurementValue`/`valueFormat`/`color`) are present only for
6693
- * points resolved from an observation; a panel-anchored point leaves them undefined. Kinds that read
6694
- * them carry the narrower {@link ResolvedObservationPoint}.
6695
- */
6696
- export declare interface ResolvedPoint {
5312
+ export declare interface ResolvedObservationAnchor {
6697
5313
  x: number;
6698
5314
  y: number;
6699
- /** The geom name the anchored observation belongs to, so the renderer can offset the anchor to fit that geom's shape. */
6700
- geom?: string;
5315
+ /**
5316
+ * The geom kind the anchored observation belongs to. Advisory: lets the renderer offset a
5317
+ * marker-style annotation (sticker, pinned number, comment) to sit on that mark's shape. NOT used
5318
+ * by `computeDifferenceArrow` — its endpoint gaps come from `getDifferenceArrowDimensions`.
5319
+ */
5320
+ geom: 'bar' | 'line' | 'polar-bar';
6701
5321
  /** Raw value of the y-aesthetic (or x-aesthetic when flipped), used by label formatting. */
6702
- measurementValue?: number;
6703
- /** Value format for `measurementValue`, read from the source layer — coord-system independent. */
6704
- valueFormat?: ValueFormat;
5322
+ measurementValue: number;
6705
5323
  /** Resolved color for this observation, if any. */
6706
- color?: string;
6707
- }
6708
-
6709
- /**
6710
- * A region anchor projected into normalized panel space `[0, 1]²`.
6711
- */
6712
- export declare interface ResolvedRegion {
6713
- x: number;
6714
- y: number;
6715
- width: number;
6716
- height: number;
5324
+ color: string | undefined;
6717
5325
  }
6718
5326
 
6719
5327
  /**
@@ -6763,6 +5371,17 @@ export declare const RESTING_HOVER_STATE: HoverState;
6763
5371
 
6764
5372
  /**
6765
5373
  * TipTap-compatible rich text node (no tiptap dependency).
5374
+ *
5375
+ * Renderer contract — the vocabulary a text renderer must handle. Anything not
5376
+ * listed falls through to a `<span>` carrying the node's own marks/attrs.
5377
+ *
5378
+ * Block `type`s (snake_case and camelCase accepted): `doc`, `paragraph`,
5379
+ * `heading`, `blockquote`, `bulletList`/`bullet_list`, `orderedList`/
5380
+ * `ordered_list`, `listItem`/`list_item`, `hardBreak`/`hard_break`, `text`.
5381
+ *
5382
+ * Mark `type`s (some carry synonyms): `bold`/`strong`, `italic`/`em`,
5383
+ * `underline`, `strike`, `code`, `link`, `textStyle`. The `link` mark reads
5384
+ * `attrs.href` and the renderer URL-safety-checks it before emitting an anchor.
6766
5385
  */
6767
5386
  export declare interface RichTextContent {
6768
5387
  type?: string;
@@ -6879,9 +5498,8 @@ declare interface ScaleAPI {
6879
5498
  * Compiles scale specs into render-ready CompiledScale objects.
6880
5499
  */
6881
5500
  declare class ScaleCompiler extends Stage<ScaleCompilerInput, CompiledScales> {
6882
- private readonly container;
6883
5501
  private readonly registry;
6884
- constructor(container: CommonContainer, registry: ScaleRegistry);
5502
+ constructor(registry: ScaleRegistry);
6885
5503
  protected dependencies(input: ScaleCompilerInput): readonly unknown[];
6886
5504
  protected run(input: ScaleCompilerInput): CompiledScales;
6887
5505
  /**
@@ -6899,14 +5517,6 @@ declare class ScaleCompiler extends Stage<ScaleCompilerInput, CompiledScales> {
6899
5517
  * position-adjusted range (e.g. [0, 1] after fill).
6900
5518
  */
6901
5519
  private collectValues;
6902
- /**
6903
- * Maps each custom positional aesthetic a layer's geom declares to the scale its axis feeds. Only
6904
- * `scalar` roles need this: they bind a *new* channel the collector trains by name. An interval
6905
- * (`min`/`max`) role's values already reach the domain through its `yMin`/`yMax` column (via the
6906
- * `y` mapping below), so routing it here too would double-count. A role binding a visual channel is
6907
- * a misdeclaration and is ignored rather than rerouted into a position scale.
6908
- */
6909
- private resolveCustomPositionalAxes;
6910
5520
  /**
6911
5521
  * Determines which dataset variables to collect for a given aesthetic.
6912
5522
  *
@@ -6923,14 +5533,6 @@ declare interface ScaleCompilerInput {
6923
5533
  scales: ScaleSpec[];
6924
5534
  }
6925
5535
 
6926
- /** Scale-domain constraints a geom imposes on the inferred position scales. */
6927
- export declare interface ScaleConstraints {
6928
- /** Force this geom's band (x) scale to be discrete (e.g. a bar's categorical axis). */
6929
- discreteMainAxis?: boolean;
6930
- /** Anchor this geom's y scale at a zero baseline — its marks rise from 0. */
6931
- zeroBaseline?: boolean;
6932
- }
6933
-
6934
5536
  /**
6935
5537
  * Identifiers for scales. Superset of AestheticKey — includes `ySecondary`
6936
5538
  * which is a scale aesthetic key but NOT an aesthetic (layers still map to `y`).
@@ -6949,7 +5551,7 @@ declare type ScaledVisualAestheticKey = 'color' | 'size' | 'alpha' | 'strokeWidt
6949
5551
  declare type ScaleInput = ContinuousScaleInput | DiscreteScaleInput | PaletteScaleInput | DatetimeScaleInput | IdentityScaleInput | InferredScaleInput;
6950
5552
 
6951
5553
  declare class ScaleRegistry extends Registry<ScaleType, Scale> {
6952
- constructor(container: CommonContainer);
5554
+ constructor();
6953
5555
  }
6954
5556
 
6955
5557
  /**
@@ -7144,16 +5746,23 @@ declare type SetScaleDomainParams = {
7144
5746
  };
7145
5747
 
7146
5748
  /**
7147
- * Rectangle annotation. Its area is positioned by a {@link RegionAnchorInput} so it
7148
- * re-resolves each compile (re-flows on resize, tracks data when bound).
5749
+ * Freeform rectangle annotation. Position and size are expressed as
5750
+ * fractions of the plot rect (0..1) so the annotation re-flows when the
5751
+ * panel resizes.
7149
5752
  */
7150
5753
  export declare interface ShapeInput {
7151
5754
  id?: string;
7152
5755
  kind?: ShapeKind;
7153
5756
  /** Draw beneath the geoms (background) or on top (foreground). */
7154
- zOrder?: AnnotationZOrder;
7155
- /** The area this shape fills. */
7156
- region: RegionAnchorInput;
5757
+ zOrder?: ShapeZOrder;
5758
+ /** Left edge, as a fraction of plot width (0..1). */
5759
+ x: number;
5760
+ /** Top edge, as a fraction of plot height (0..1). */
5761
+ y: number;
5762
+ /** Width, as a fraction of plot width (0..1). */
5763
+ width: number;
5764
+ /** Height, as a fraction of plot height (0..1). */
5765
+ height: number;
7157
5766
  fillColor?: string;
7158
5767
  /** Fill alpha, 0 (transparent) to 1 (opaque). */
7159
5768
  fillOpacity?: number;
@@ -7169,16 +5778,23 @@ export declare type ShapeKind = 'rectangle';
7169
5778
  export declare interface ShapeSpec {
7170
5779
  id: string;
7171
5780
  kind: ShapeKind;
7172
- zOrder: AnnotationZOrder;
7173
- region: RegionAnchor;
5781
+ zOrder: ShapeZOrder;
5782
+ x: number;
5783
+ y: number;
5784
+ width: number;
5785
+ height: number;
7174
5786
  fillColor: string;
7175
5787
  fillOpacity: number;
7176
5788
  strokeWidth: number;
7177
5789
  strokeColor: string | null;
7178
5790
  }
7179
5791
 
7180
- /** Overlap tolerance, in pixels, before two sibling mini bubbles count as colliding. */
7181
- export declare const SIBLING_OVERLAP_THRESHOLD_PX = 2;
5792
+ /**
5793
+ * Whether the shape renders beneath the geoms (background) or on top (foreground). This is not a
5794
+ * sort key within a single pass: the renderer paints `background` shapes, then the geom layer, then
5795
+ * `foreground` shapes — two separate passes bracketing the geoms (see `CompiledAnnotations`).
5796
+ */
5797
+ export declare type ShapeZOrder = 'background' | 'foreground';
7182
5798
 
7183
5799
  /**
7184
5800
  * Builder for the smooth stat.
@@ -7247,24 +5863,6 @@ export declare interface SourceContent {
7247
5863
  url?: string;
7248
5864
  }
7249
5865
 
7250
- /**
7251
- * The coord-agnostic hit-test shape a geom declares — how its marks are shaped, never how that shape
7252
- * projects under a coord. The runtime pairs this shape with the chart's coord system to build a matching
7253
- * hover index; that projection lives in one place (`build-layer-index`), so a geom never names a
7254
- * coord-specific variant and can't mis-declare one.
7255
- *
7256
- * - `'buckets'` — marks bucket along an axis for nearest-position snapping (line/area crosshair).
7257
- * - `'rects'` — marks are rectangles (bars).
7258
- * - `'points'` — marks are discrete vertices (scatter).
7259
- * - `'noop'` — nothing hit-testable.
7260
- * - `'render-hit-test'` — geometry comes from a render-side layout algorithm rather than position
7261
- * scales, so only the renderer can hit-test it.
7262
- *
7263
- * Every shape but `'render-hit-test'` is derived from position scales at compile time, so the runtime
7264
- * builds its index from the compiled data alone.
7265
- */
7266
- export declare type SpatialKind = 'buckets' | 'rects' | 'points' | 'noop' | 'render-hit-test';
7267
-
7268
5866
  /**
7269
5867
  * Fully resolved spec — all fields populated, defaults applied, inferred types resolved.
7270
5868
  * This is what the compilation pipeline consumes.
@@ -7293,7 +5891,7 @@ export declare interface Spec {
7293
5891
  /** Resolved scale specs — one per aesthetic, all defaults filled, no 'inferred' types remaining. */
7294
5892
  scales: ScaleSpec[];
7295
5893
  /** Data transforms applied to `data` before layer compilation. */
7296
- transforms: AnyTransformInput[];
5894
+ transforms: TransformInput[];
7297
5895
  /** Predicate-driven highlights with `layerIndex` normalised to `layerId` and ids assigned. */
7298
5896
  highlights: HighlightSpec[];
7299
5897
  /** Annotation overlays (difference arrows, etc.) with optional fields defaulted. */
@@ -7312,24 +5910,22 @@ export declare interface SpecInput {
7312
5910
  mapping: AesMapping;
7313
5911
  layers: LayerInput[];
7314
5912
  scales: ScaleInput[];
7315
- transforms: AnyTransformInput[];
5913
+ transforms: TransformInput[];
7316
5914
  highlights: HighlightInput[];
7317
5915
  annotations?: AnnotationsInput;
7318
5916
  coords?: CoordInput;
7319
5917
  config: ConfigInput;
7320
5918
  }
7321
5919
 
7322
- declare type SpecItem = LayerInput | ScaleInput | CoordInput | ConfigItem | AnyTransformInput | MappingItem | HighlightInput | AnnotationItem;
5920
+ declare type SpecItem = LayerInput | ScaleInput | CoordInput | ConfigItem | TransformInput | MappingItem | HighlightInput;
7323
5921
 
7324
5922
  /**
7325
5923
  * Compiles a raw compiler input or graph config into a resolved Spec.
7326
5924
  */
7327
5925
  export declare class SpecResolver {
7328
- private readonly container;
7329
- constructor(container: CommonContainer);
7330
5926
  /**
7331
- * Resolve user input into a fully defaulted {@link Spec}.
7332
- * Accepts either a `SpecInput` or `GraphConfig`, converting the latter before resolution.
5927
+ * Resolve user input into a fully defaulted {@link Spec}. Accepts either a viz-engine
5928
+ * `SpecInput` or a legacy `GraphConfig`, converting the latter before resolution.
7333
5929
  */
7334
5930
  compile({ input, dataset, ctx }: {
7335
5931
  input: CompilerInput;
@@ -7382,12 +5978,8 @@ declare abstract class Stage<Input, Output> {
7382
5978
  /**
7383
5979
  * Base class for statistical transformations applied to layer data (e.g. binning, counting, smoothing).
7384
5980
  */
7385
- export declare abstract class Stat {
7386
- /**
7387
- * The stat's name. Built-in subclasses narrow this to a `StatName` literal; the base accepts any
7388
- * `string` so a custom stat carries a name outside the built-in union, resolved through the registry.
7389
- */
7390
- abstract readonly type: string;
5981
+ declare abstract class Stat {
5982
+ abstract readonly type: StatName;
7391
5983
  /**
7392
5984
  * Aesthetics this stat will compute (e.g. count computes 'y'). Used by validation to skip existence checks.
7393
5985
  */
@@ -7396,7 +5988,7 @@ export declare abstract class Stat {
7396
5988
  protected abstract computeStat(input: StatCompilerInput): CompiledStat;
7397
5989
  }
7398
5990
 
7399
- /** Factories for the stats a layer can apply (identity, count, smooth, mean). */
5991
+ /** Factories for the statistical transforms a layer can apply (identity, count, smooth, mean). */
7400
5992
  export declare const stat: {
7401
5993
  identity: typeof identity;
7402
5994
  count: typeof count;
@@ -7417,7 +6009,7 @@ declare class StatCompiler {
7417
6009
  }): CompiledStat;
7418
6010
  }
7419
6011
 
7420
- export declare interface StatCompilerInput {
6012
+ declare interface StatCompilerInput {
7421
6013
  /** The input dataset. */
7422
6014
  data: Dataset;
7423
6015
  /** The effective mapping for the layer. */
@@ -7431,11 +6023,6 @@ export declare interface StatCompilerInput {
7431
6023
  xScaleIsDiscrete: boolean;
7432
6024
  }
7433
6025
 
7434
- /** A custom stat is a {@link Stat} subclass instance. Named alias for its role as a plugin. */
7435
- export declare type StatDefinition = Stat;
7436
-
7437
- declare type StatDefsOf<P extends readonly Plugin_2[]> = Extract<DefsOf<P>, Stat>;
7438
-
7439
6026
  /**
7440
6027
  * User-facing stat input — either a {@link StatName} string shorthand or an object spec.
7441
6028
  */
@@ -7449,13 +6036,12 @@ declare type StatInput = IdentityStatSpec | CountStatSpec | SmoothStatInput | Me
7449
6036
  * - `'smooth'` — Fit a regression curve through `(x, y)` and emit the fitted points
7450
6037
  * - `'mean'` — Reduce the dataset to a single observation holding the mean of `y`
7451
6038
  */
7452
- export declare type StatName = 'identity' | 'count' | 'smooth' | 'mean';
6039
+ declare type StatName = 'identity' | 'count' | 'smooth' | 'mean';
7453
6040
 
7454
6041
  /**
7455
- * Stat implementations keyed by name. Built-ins are registered in the constructor; custom stats are
7456
- * appended via `createRegistries`, so the key is a plain `string` rather than the built-in `StatName`.
6042
+ * Built-in stat implementations keyed by {@link StatName}.
7457
6043
  */
7458
- declare class StatRegistry extends Registry<string, Stat> {
6044
+ declare class StatRegistry extends Registry<StatName, Stat> {
7459
6045
  constructor();
7460
6046
  }
7461
6047
 
@@ -7465,29 +6051,26 @@ declare class StatRegistry extends Registry<string, Stat> {
7465
6051
  declare type StatSpec = IdentityStatSpec | CountStatSpec | SmoothStatSpec | MeanStatSpec;
7466
6052
 
7467
6053
  /**
7468
- * Sticker annotation: a built-in emoji-like image positioned by a {@link PointAnchorInput}.
6054
+ * Sticker annotation: a built-in emoji-like image pinned to a single observation.
7469
6055
  */
7470
- export declare interface StickerAnnotationInput {
6056
+ declare interface StickerAnnotationInput {
7471
6057
  id?: string;
7472
- at: PointAnchorInput;
6058
+ anchor: ObservationAnchorInput;
7473
6059
  sticker: StickerId;
7474
6060
  }
7475
6061
 
7476
- export declare interface StickerAnnotationSpec {
6062
+ declare interface StickerAnnotationSpec {
7477
6063
  id: string;
7478
- at: PointAnchor;
6064
+ anchor: ObservationAnchor;
7479
6065
  sticker: StickerId;
7480
6066
  }
7481
6067
 
7482
- export declare type StickerId = string;
6068
+ declare type StickerId = 'rocket' | 'clapping-hands' | 'thumbs-up' | 'thumbs-down' | 'grinning-face';
7483
6069
 
7484
6070
  /**
7485
6071
  * Computes per-layer aggregates (stack totals, grand totals) consumed directly by the renderer.
7486
- * Which summaries a layer carries is gated by the geom def's declared `summaries`, not its name.
7487
6072
  */
7488
6073
  declare class SummariseCompiler extends PerLayerStage<SummariseCompilerInput> {
7489
- private readonly container;
7490
- constructor(container: CommonContainer);
7491
6074
  protected dependencies(): readonly unknown[];
7492
6075
  protected compileLayer(layer: CompiledLayer): CompiledLayer;
7493
6076
  }
@@ -7496,6 +6079,21 @@ declare interface SummariseCompilerInput {
7496
6079
  layers: CompiledLayer[];
7497
6080
  }
7498
6081
 
6082
+ /**
6083
+ * Visual signature of a geom, decoupled from `GeomName` because legends and tooltips don't care
6084
+ * about the geom's spec-level identity — only what shape best evokes its on-canvas mark.
6085
+ *
6086
+ * - `bar` + cartesian → `square`
6087
+ * - `bar` + polar → `slice` (pie / donut wedge)
6088
+ * - `line` → `line` (a horizontal stroke)
6089
+ * - `area` → `area` (filled region with a stroke accent)
6090
+ * - `point` → `circle`
6091
+ *
6092
+ * One resolver feeds the legend, the headline strip, and rule pills, so a given series shows the same mark in
6093
+ * every surface. A combo legend still carries mixed shapes — the value is resolved per series, not per chart.
6094
+ */
6095
+ export declare type SwatchShape = 'square' | 'line' | 'circle' | 'area' | 'slice';
6096
+
7499
6097
  declare type Table = internal.ColumnTable;
7500
6098
 
7501
6099
  declare interface TableOptions {
@@ -7503,14 +6101,11 @@ declare interface TableOptions {
7503
6101
  tableColumnRatios?: Record<string, number>;
7504
6102
  }
7505
6103
 
7506
- /** A full turn in radians. */
7507
- export declare const TAU: number;
7508
-
7509
6104
  declare interface TemporalValueFormat {
7510
6105
  type: 'datetime' | 'time' | 'date' | 'year' | 'quarter' | 'month_year' | 'month' | 'weekly_date_range_with_year' | 'weekly_date_range' | 'day_month';
7511
6106
  /**
7512
6107
  * Source-parsing metadata: the template the values were originally parsed from (e.g. 'dd-mm-yyyy').
7513
- * It is not a formatting instruction and is not consumed when materializing output — the renderer
6108
+ * It is NOT a formatting instruction and is not consumed when materializing output — the renderer
7514
6109
  * picks the display shape from `type` alone, not from this field.
7515
6110
  */
7516
6111
  dateFormat?: string;
@@ -7520,15 +6115,17 @@ declare interface TemporalValueFormat {
7520
6115
  export declare type TextAnnotationBackgroundColorStyle = 'fade' | 'opaque';
7521
6116
 
7522
6117
  /**
7523
- * Rich-text annotation. Its top-left corner is positioned by a {@link PointAnchorInput};
7524
- * `width` is a fraction of the plot rect. Height is intrinsic to the rendered content.
6118
+ * Freeform rich-text annotation. Position and width are fractions of the plot
6119
+ * rect (0..1). Height is intrinsic to the rendered content.
7525
6120
  */
7526
6121
  export declare interface TextAnnotationInput {
7527
6122
  id?: string;
7528
6123
  /** Rich-text body to render. */
7529
6124
  content: RichTextContent;
7530
- /** The annotation's top-left corner. */
7531
- at: PointAnchorInput;
6125
+ /** 0..1 of plot width — top-left corner. */
6126
+ x: number;
6127
+ /** 0..1 of plot height — top-left corner. */
6128
+ y: number;
7532
6129
  /** 0..1 of plot width. */
7533
6130
  width: number;
7534
6131
  /** null falls back to a transparent background. */
@@ -7541,7 +6138,8 @@ export declare interface TextAnnotationInput {
7541
6138
  export declare interface TextAnnotationSpec {
7542
6139
  id: string;
7543
6140
  content: RichTextContent;
7544
- at: PointAnchor;
6141
+ x: number;
6142
+ y: number;
7545
6143
  width: number;
7546
6144
  backgroundColor: string | null;
7547
6145
  backgroundColorStyle: TextAnnotationBackgroundColorStyle;
@@ -7570,11 +6168,6 @@ export declare interface TooltipContent {
7570
6168
  rows: TooltipRow[];
7571
6169
  }
7572
6170
 
7573
- declare type TooltipContract = ReadonlyArray<{
7574
- readonly key: string;
7575
- readonly aes: string;
7576
- }>;
7577
-
7578
6171
  /**
7579
6172
  * One row in the chart tooltip popover. Pure projection of a `HoverHit` against the layer's
7580
6173
  * compiled scales.
@@ -7585,8 +6178,8 @@ export declare interface TooltipRow {
7585
6178
  * has no color scale at all — the popover suppresses the swatch cell in that edge case.
7586
6179
  */
7587
6180
  swatchColor: string | null;
7588
- /** The row's source geom the renderer reads its swatch shape off the geom's render contract. */
7589
- geom: string;
6181
+ /** Visual signature of the row's source geom. Drives the swatch shape. */
6182
+ swatchShape: SwatchShape;
7590
6183
  /** Resolved stroke style for line/area swatches. Falls back to `'solid'` when not derived. */
7591
6184
  swatchLineType: LineStyleType;
7592
6185
  /** Row label — color value (multi-series) or layer's Y-axis title (single-series). */
@@ -7599,23 +6192,6 @@ export declare interface TooltipRow {
7599
6192
  key: string;
7600
6193
  }
7601
6194
 
7602
- /**
7603
- * Maps a panel-local pixel point to the data-space cursor the hover engine queries with: x
7604
- * normalized to the panel width, y normalized and flipped to bottom-origin (matching
7605
- * `POSITION_VARIABLES.y`). Polar queries take the same full-panel cursor — the engine applies the
7606
- * inscribed-square and aspect-ratio correction internally.
7607
- *
7608
- * Both the pointer tracker (normalizing the live cursor) and callout hit regions (normalizing a
7609
- * marker pixel) go through this, so a hit region resolves to the same observation the cursor would.
7610
- */
7611
- export declare const toPanelCursor: (point: {
7612
- x: number;
7613
- y: number;
7614
- }, panelSize: {
7615
- width: number;
7616
- height: number;
7617
- }) => HoverCursor;
7618
-
7619
6195
  /** Formats a normalized [0,1] value as a CSS percentage string for SVG positioning. */
7620
6196
  export declare const toPercent: (value: number) => string;
7621
6197
 
@@ -7641,11 +6217,6 @@ export declare const transform: {
7641
6217
  constant: typeof constant;
7642
6218
  };
7643
6219
 
7644
- /** Options for a custom transform builder method (transforms carry no declared params surface yet). */
7645
- declare interface TransformBuilderOptions {
7646
- options?: Record<string, unknown>;
7647
- }
7648
-
7649
6220
  /**
7650
6221
  * Applies transforms to a dataset via registered strategies. Cache partitioned by dataset
7651
6222
  * reference so the spec-level and per-layer call sites don't thrash each other.
@@ -7660,51 +6231,30 @@ declare class TransformCompiler extends Stage<TransformCompilerInput, Dataset> {
7660
6231
 
7661
6232
  declare interface TransformCompilerInput {
7662
6233
  data: Dataset;
7663
- transforms: AnyTransformInput[];
6234
+ transforms: TransformInput[];
7664
6235
  }
7665
6236
 
7666
- /** A custom transform is a {@link TransformStrategy}. Named alias for its role as a plugin. */
7667
- export declare type TransformDefinition = TransformStrategy;
7668
-
7669
- declare type TransformDefsOf<P extends readonly Plugin_2[]> = Extract<DefsOf<P>, {
7670
- readonly transformType: string;
7671
- }>;
7672
-
7673
- export declare type TransformInput = ReshapeTransformInput | FilterTransformInput | SortTransformInput | AggregateTransformInput | ConstantTransformInput;
6237
+ /***************************************************************
6238
+ * Transform Input
6239
+ ***************************************************************/
6240
+ declare type TransformInput = ReshapeTransformInput | FilterTransformInput | SortTransformInput | AggregateTransformInput | ConstantTransformInput;
7674
6241
 
7675
6242
  /**
7676
- * Transform implementations keyed by name. Built-ins are registered in the constructor; custom
7677
- * transforms are appended via `createRegistries`, so the key is a plain `string` rather than the
7678
- * built-in `TransformType`.
6243
+ * Built-in transform implementations keyed by transform type.
7679
6244
  */
7680
- declare class TransformRegistry extends Registry<string, TransformStrategy> {
6245
+ declare class TransformRegistry extends Registry<TransformType, TransformStrategy> {
7681
6246
  constructor();
7682
6247
  }
7683
6248
 
7684
6249
  /**
7685
6250
  * Strategy interface for compiling a specific transform type.
7686
6251
  */
7687
- export declare interface TransformStrategy {
7688
- /**
7689
- * The transform's name. Built-in transforms narrow this to a `TransformType` literal; the type
7690
- * accepts any `string` so a custom transform carries a name outside the built-in union, resolved
7691
- * through the registry.
7692
- */
7693
- readonly transformType: string;
7694
- apply: (data: Dataset, transform: AnyTransformInput) => Dataset;
7695
- /**
7696
- * Variable names this transform adds to the dataset (e.g. a reshape's key column or a constant's
7697
- * variable). Declared so consumers can discover introduced columns without branching on the type.
7698
- */
7699
- getIntroducedVariables?: (transform: AnyTransformInput) => VariableName[];
6252
+ declare interface TransformStrategy {
6253
+ readonly transformType: TransformType;
6254
+ apply: (data: Dataset, transform: TransformInput) => Dataset;
7700
6255
  }
7701
6256
 
7702
- /**
7703
- * The built-in transform names. Hand-written (not derived from {@link TransformInput}) and
7704
- * cross-checked against the registry's built-in tuple via `satisfies` in `transform.registry.ts`, so
7705
- * it stays the closed built-in union.
7706
- */
7707
- export declare type TransformType = 'reshape' | 'filter' | 'sort' | 'aggregate' | 'constant';
6257
+ declare type TransformType = TransformInput['transformType'];
7708
6258
 
7709
6259
  declare type TrendlineType = 'linear' | 'loess' | 'exponential' | 'logarithmic' | 'quadratic' | 'power' | 'polynomial';
7710
6260
 
@@ -7719,39 +6269,29 @@ declare interface UndoRedoResult {
7719
6269
  }
7720
6270
 
7721
6271
  /**
7722
- * Inverse of {@link polarToUnit}: recovers `(angle, radius)` from a point in the same y-up unit disk.
7723
- * `atan2(x, y)` yields a clockwise-from-12 angle with no sign flip because `y` is up; `hypot` recovers
7724
- * the radius.
7725
- */
7726
- export declare const unitToPolar: (x: number, y: number) => {
7727
- angle: number;
7728
- radius: number;
7729
- };
7730
-
7731
- /**
7732
- * Stable code for a failure the caller can fix by editing their {@link Spec} or {@link Data}.
6272
+ * Shared validation types used across compiler stages.
6273
+ *
6274
+ * Each validation stage (e.g. {@link LayerValidator}, the pre-pass in {@link ScaleCompiler}) collects
6275
+ * {@link ValidationIssue}s and throws a single {@link SpecValidationError} at the end of its stage.
7733
6276
  */
7734
- export declare type UserInputErrorCode = 'UNKNOWN_VARIABLE' | 'INCOMPATIBLE_TYPE' | 'INCOMPATIBLE_SCALE_DOMAIN' | 'MISSING_AESTHETIC' | 'UNDECLARED_AESTHETIC' | 'INVALID_RULE_MAPPING' | 'UNSUPPORTED_COORD' | 'MISSING_STAT_VARIABLE' | 'CONFLICTING_STAT_MAPPING' | 'UNKNOWN_REGISTERED_TYPE' | 'DUPLICATE_REGISTERED_TYPE' | 'MISSING_GEOM_RENDERER' | 'RENDER_HIT_TEST_IDENTITY' | 'MISSING_RENDER_HIT_TEST' | 'CONFLICTING_RENDER_HIT_TEST' | 'OVERLAY_REQUIRES_RENDER_HIT_TEST' | 'PALETTE_NOT_FOUND' | 'LAYER_INDEX_OUT_OF_RANGE' | 'INVALID_HIGHLIGHT_OPERATOR' | 'UNRESOLVABLE_COLOR' | 'UNSUPPORTED_GRAPH_TYPE' | 'INVALID_DATA_SHAPE' | 'EMPTY_DATASET' | 'DATA_LABEL_PLACEMENT_COERCED' | 'DATA_LABELS_UNSUPPORTED' | 'DATA_LABEL_SETTING_IGNORED';
6277
+ declare type ValidationCode = 'UNKNOWN_VARIABLE' | 'INCOMPATIBLE_TYPE' | 'MISSING_AESTHETIC' | 'INVALID_RULE_MAPPING' | 'INVALID_RULE_COORD';
7735
6278
 
7736
- /**
7737
- * One user-input problem authored once and used three ways: pushed onto the collector as a warning
7738
- * ({@link DiagnosticsCollector.addWarning}) or a batched error
7739
- * ({@link DiagnosticsCollector.addError}), or thrown as a {@link UserInputError}. `kind` is
7740
- * never restated — it is implied by the partitioned `code`, so it cannot drift from it.
7741
- */
7742
- export declare interface UserInputIssue extends DiagnosticDetails {
7743
- code: UserInputErrorCode;
6279
+ declare interface ValidationIssue {
6280
+ code: ValidationCode;
6281
+ message: string;
6282
+ layerId?: string;
6283
+ aesthetic?: string;
7744
6284
  }
7745
6285
 
7746
6286
  /**
7747
6287
  * The compiler-emitted descriptor of how a raw data value should be turned into a display string.
6288
+ * The engine never formats values itself; it tags each guide/legend/headline figure with a
6289
+ * `ValueFormat`, and the renderer materializes it via `createValueFormatter` (a descriptor is inert
6290
+ * until paired with a locale and number-format config). It surfaces on compiled guides
6291
+ * (`CompiledAxisGuide.valueFormat`, legend/headline items), so a renderer holds these values and must
6292
+ * be able to name and switch on them.
7748
6293
  *
7749
- * The engine never formats values itself: it tags each guide/legend/headline figure with a
7750
- * `ValueFormat` (e.g. `CompiledAxisGuide.valueFormat`), and the renderer materializes it via
7751
- * `createValueFormatter`. A descriptor is inert until paired with a locale and number-format config,
7752
- * so renderers hold these and switch on the `type` discriminant.
7753
- *
7754
- * `type` selects the formatter. Rendered examples (en-US, default number config):
6294
+ * The `type` discriminant selects the formatter. Rendered examples (en-US, default number config):
7755
6295
  * - `currency` — '$1,234.50' (narrow currency symbol from `iso`, 2 decimals).
7756
6296
  * - `decimal` — '1,234.5' (locale grouping; decimals/abbreviation from number-format config).
7757
6297
  * - `integer` — '1,235' (no fraction digits).
@@ -7771,7 +6311,7 @@ export declare interface UserInputIssue extends DiagnosticDetails {
7771
6311
  * - `lookup` — resolved per observation; see {@link LookupValueFormat}.
7772
6312
  *
7773
6313
  * The `isXValueFormat` guards (e.g. {@link isLookupValueFormat}, {@link isTemporalValueFormat}) narrow
7774
- * a descriptor to a family without naming every member kind.
6314
+ * a held descriptor to a family without listing every member kind by hand.
7775
6315
  */
7776
6316
  export declare type ValueFormat = ExplicitValueFormat | LookupValueFormat;
7777
6317
 
@@ -7787,7 +6327,11 @@ export declare interface ValueFormatterFactoryParams<T = ValueFormat> {
7787
6327
  valueFormat: T;
7788
6328
  locale: Locale;
7789
6329
  numberFormat: NumberFormatConfig;
7790
- /** Per-call overrides merged onto the formatter's default Intl options (e.g. compact axis dates). */
6330
+ /**
6331
+ * Advanced override merged onto the formatter's default Intl options, used by axis/tick label
6332
+ * compaction (e.g. dropping the year on dense date axes). Standard value formatting omits it and
6333
+ * lets each kind's defaults stand.
6334
+ */
7791
6335
  intlOptions?: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions;
7792
6336
  }
7793
6337
 
@@ -7806,14 +6350,6 @@ declare type Variable = {
7806
6350
  valueFormat?: ValueFormat;
7807
6351
  };
7808
6352
 
7809
- /**
7810
- * Friendly display labels for variables, keyed by variable name. Sourced from
7811
- * `Data.columns[i].label` for raw columns; consumers may extend this map to
7812
- * provide labels for transform-produced columns. Only present entries are
7813
- * stored — absent variables fall back to the raw variable name at the guide.
7814
- */
7815
- declare type VariableLabels = Record<string, string>;
7816
-
7817
6353
  /** A map of variable names to their type and values. */
7818
6354
  declare type VariableMap = Record<VariableName, Variable>;
7819
6355
 
@@ -7827,9 +6363,6 @@ declare interface VariableMapping {
7827
6363
  declare type VariableMetadata = Record<VariableName, {
7828
6364
  type: DataType;
7829
6365
  valueFormat: ValueFormat;
7830
- constant?: {
7831
- value: DataValue;
7832
- };
7833
6366
  }>;
7834
6367
 
7835
6368
  /** A type alias for variable names. */
@@ -7865,7 +6398,7 @@ export declare type VariablePredicate = {
7865
6398
  range: [DataValue, DataValue];
7866
6399
  };
7867
6400
 
7868
- /** Internal variables holding each observation's resolved visual values (color, size, etc.). */
6401
+ /** Internal column names holding each observation's resolved visual channels (color, size, etc.). */
7869
6402
  export declare const VISUAL_VARIABLES: {
7870
6403
  readonly color: string;
7871
6404
  readonly size: string;
@@ -7894,54 +6427,6 @@ declare interface VisualMapperCompilerInput {
7894
6427
  */
7895
6428
  declare type VisualScalesSlice = Pick<CompiledScales, ScaledVisualAestheticKey>;
7896
6429
 
7897
- /**
7898
- * The serialisable, normalised form of any error or warning. Every failure the engine surfaces —
7899
- * fatal errors, batched validation problems, and advisory warnings — is a `VizDiagnostic`; there is
7900
- * no second shape. Attachable to a bug report wholesale, and the unit codegen reads.
7901
- */
7902
- export declare interface VizDiagnostic extends DiagnosticDetails {
7903
- severity: VizErrorSeverity;
7904
- kind: VizErrorKind;
7905
- code: VizErrorCode;
7906
- }
7907
-
7908
- /**
7909
- * Platform-independent base for every error the engine throws.
7910
- */
7911
- declare abstract class VizError extends Error {
7912
- readonly code: VizErrorCode;
7913
- readonly context?: DiagnosticContext;
7914
- readonly suggestion?: string;
7915
- /** Whose fault the failure is. Fixed by the concrete subclass. */
7916
- abstract readonly kind: VizErrorKind;
7917
- constructor(options: VizErrorOptions);
7918
- }
7919
-
7920
- /**
7921
- * Every error code, partitioned by fault. A {@link UserInputError} only accepts a
7922
- * {@link UserInputErrorCode}; an {@link InternalError} only accepts an {@link InternalErrorCode}.
7923
- */
7924
- export declare type VizErrorCode = UserInputErrorCode | InternalErrorCode;
7925
-
7926
- /** Whose fault a failure is, and whether the caller can fix it. */
7927
- export declare type VizErrorKind = 'user-input' | 'internal';
7928
-
7929
- /**
7930
- * Construction options shared by every {@link VizError}: the {@link DiagnosticDetails} core (message,
7931
- * context, suggestion) plus a partitioned `code` and an optional `cause`. `Code` is partitioned per
7932
- * subclass, so the compiler rejects a code from the wrong fault partition (e.g. an `InternalErrorCode`
7933
- * on a {@link UserInputError}).
7934
- */
7935
- declare interface VizErrorOptions<Code extends VizErrorCode = VizErrorCode> extends DiagnosticDetails {
7936
- /** Stable, machine-readable code. The primary contract for programmatic consumers. */
7937
- code: Code;
7938
- /** The underlying error, if this wraps one. */
7939
- cause?: unknown;
7940
- }
7941
-
7942
- /** Whether a diagnostic is fatal (`error`) or advisory (`warning`). */
7943
- export declare type VizErrorSeverity = 'error' | 'warning';
7944
-
7945
6430
  /**
7946
6431
  * X-axis configuration (after defaults applied)
7947
6432
  */