@svgsketch/core 0.7.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -269,6 +269,75 @@ interface SerializedAnimationTimeline {
269
269
  x: number;
270
270
  y: number;
271
271
  };
272
+ /**
273
+ * CSS selector for a DOM element to animate directly, used when the
274
+ * animation target is not an editor Shape — e.g. an `<animateTransform
275
+ * xlink:href="#rect1"/>` whose target lives inside a `<clipPath>`
276
+ * definition. The track's `shapeId` is a synthetic `__dom__<id>` in
277
+ * this case (no editor Shape exists to bind to). Without this field,
278
+ * the SMIL exporter has no way to re-locate the target after a
279
+ * save/reload round-trip and silently drops every clip/mask-internal
280
+ * animation.
281
+ */
282
+ domTargetSelector?: string;
283
+ /**
284
+ * For `property === 'domTransformStack'` tracks: the original
285
+ * `<animateTransform>` `type` function (`translate` / `scale` /
286
+ * `rotate` / `skewX` / `skewY` / `matrix`). The SMIL exporter
287
+ * (`addDomTransformStackEntry`) early-returns when this is missing,
288
+ * silently dropping every stacked DOM-transform animation across
289
+ * save/reload. Per SVG Animation §19.4.2 the export must re-emit
290
+ * the same `type` — and per SMIL §4.2 the document-order index
291
+ * (`transformStackIndex`) controls additive composition of the
292
+ * stack. Both are essential for clip/mask internal animations.
293
+ */
294
+ transformFunction?: 'translate' | 'scale' | 'rotate' | 'skewX' | 'skewY' | 'matrix';
295
+ /**
296
+ * For `property === 'domTransformStack'` tracks: document-order
297
+ * index within the target element's `<animateTransform>` stack.
298
+ * The renderer sorts tracks by this index before applying the
299
+ * SMIL animation sandwich (SVG 2 §19.2.7).
300
+ */
301
+ transformStackIndex?: number;
302
+ /**
303
+ * For `property === 'domTransformStack'` tracks: the target
304
+ * element's pre-animation `transform` attribute value (the
305
+ * underlying value in the SMIL animation sandwich). Captured at
306
+ * import time.
307
+ */
308
+ transformBaseValue?: string;
309
+ /**
310
+ * For `property === 'domAttribute'` tracks: the SVG attribute name
311
+ * to write on the target element each frame (`cx`, `cy`, `r`, `x`,
312
+ * `y`, `width`, `height`, `opacity`, `fill-opacity`, `fill`,
313
+ * `stroke`, `d`, etc.). Generic carrier for `<animate>` / `<set>`
314
+ * inside `<clipPath>` / `<mask>` defs that the editor doesn't
315
+ * decompose into per-attribute first-class tracks. Set jointly with
316
+ * `domAttributeValueType` so the manager knows how to interpolate
317
+ * the raw keyframe values.
318
+ * @see SVG Animations §3.5
319
+ */
320
+ domAttribute?: string;
321
+ /**
322
+ * For `property === 'domAttribute'` tracks: how to interpolate the
323
+ * keyframe values. `'number'` → numeric tween; `'color'` → RGB
324
+ * channel tween via the existing color interp; `'string'` →
325
+ * discrete (no interpolation, holds each keyframe until the next).
326
+ * Determined at import time from the source `<animate>`'s
327
+ * `attributeName` (geometry → number, paint → color, others →
328
+ * string). `<set>` always produces `'string'` regardless of attr.
329
+ */
330
+ domAttributeValueType?: 'number' | 'color' | 'string';
331
+ /**
332
+ * SMIL `calcMode` (SVG Animations §2.10) — controls interpolation
333
+ * between keyframes. Persisted because it changes how the SMIL
334
+ * exporter materializes the track: `'discrete'` round-trips a
335
+ * single-keyframe track as `<set>` and a multi-keyframe track as one
336
+ * `<set>` per keyframe, while the absent/`'linear'` form emits a
337
+ * single `<animate values="…">`. Without this field, set-semantics
338
+ * tracks degrade to interpolated `<animate>` after save/reload.
339
+ */
340
+ calcMode?: 'linear' | 'discrete' | 'paced' | 'spline';
272
341
  keyframes: {
273
342
  time: number;
274
343
  value: number | string;
@@ -312,7 +381,7 @@ interface AnimatablePropertyDescriptor {
312
381
  * Only enums referenced by SerializedShape or HistorySnapshot live here.
313
382
  * Editor-only enums (Mode, ControlPointPosition, etc.) stay in the editor.
314
383
  */
315
- declare enum SplineCurveType {
384
+ declare enum PathCurveType {
316
385
  LINEAR = "linear",
317
386
  QUADRATIC = "quadratic",
318
387
  CUBIC = "cubic",
@@ -321,7 +390,7 @@ declare enum SplineCurveType {
321
390
  BASIS = "basis",
322
391
  MIXED = "mixed"
323
392
  }
324
- declare enum SplinePointType {
393
+ declare enum PathPointType {
325
394
  SMOOTH = "smooth",
326
395
  CORNER = "corner",
327
396
  SYMMETRIC = "symmetric"
@@ -400,6 +469,15 @@ interface LinearGradient {
400
469
  * element's bbox-normalised [0, 1] space. See `GradientUnits`.
401
470
  */
402
471
  gradientUnits?: GradientUnits;
472
+ /**
473
+ * SVG 2 §13.9 `color-interpolation` — color space for stop
474
+ * interpolation. Spec applies the property to gradient elements;
475
+ * `linearRGB` produces physically-linear blends, `sRGB` (the spec
476
+ * initial value) produces the perceptual blends most authors expect.
477
+ * Round-trip the attribute when authored so re-export does not
478
+ * silently shift mid-tone colors.
479
+ */
480
+ colorInterpolation?: 'auto' | 'sRGB' | 'linearRGB';
403
481
  /**
404
482
  * Original `id` from the imported source SVG. Runtime `id` is always
405
483
  * a fresh GUID (to keep editor uniqueness invariants), but `sourceId`
@@ -419,6 +497,14 @@ interface RadialGradient {
419
497
  r: number;
420
498
  ry: number;
421
499
  rotation: number;
500
+ /**
501
+ * Focal-circle radius (SVG 2 §14.2.3.1 `fr`). When present and > 0, the
502
+ * gradient's first stop is rendered along this circle (not at a single
503
+ * focal point) — produces a "donut" radial gradient. Same coordinate
504
+ * space as `r` (i.e. governed by `gradientUnits`). Defaults to 0
505
+ * when omitted, matching the spec's initial value and pre-SVG-2 behaviour.
506
+ */
507
+ fr?: number;
422
508
  stops: GradientStop[];
423
509
  spreadMethod: GradientSpreadMethod;
424
510
  opacity: number;
@@ -427,6 +513,8 @@ interface RadialGradient {
427
513
  * `r`/`ry` are in document user space. See `GradientUnits`.
428
514
  */
429
515
  gradientUnits?: GradientUnits;
516
+ /** See `LinearGradient.colorInterpolation`. */
517
+ colorInterpolation?: 'auto' | 'sRGB' | 'linearRGB';
430
518
  /** See `LinearGradient.sourceId`. */
431
519
  sourceId?: string;
432
520
  }
@@ -563,7 +651,7 @@ interface CustomPatternDef {
563
651
  /** Tile height in userSpaceOnUse coordinates. */
564
652
  height: number;
565
653
  }
566
- type FilterType = 'drop-shadow' | 'inner-shadow' | 'gaussian-blur' | 'motion-blur' | 'point-light' | 'spot-light' | 'diffuse-lighting' | 'specular-lighting' | 'outline' | 'sharpen' | 'pixelate' | 'warp' | 'morphology' | 'contouring-discrete' | 'contouring-table' | 'round-edges' | 'grayscale' | 'channel-painter' | 'brightness' | 'contrast' | 'opacity' | 'invert' | 'hue-rotate' | 'saturate' | 'black-and-white' | 'sepia' | 'duotone' | 'xray' | 'noise' | 'emboss' | 'film-grain' | 'watercolor' | 'gouache' | 'ink-blot' | 'crumpled-plastic' | 'riddled' | 'glow' | 'inner-glow' | 'raw-svg';
654
+ type FilterType = 'drop-shadow' | 'inner-shadow' | 'gaussian-blur' | 'motion-blur' | 'point-light' | 'spot-light' | 'diffuse-lighting' | 'specular-lighting' | 'outline' | 'sharpen' | 'pixelate' | 'warp' | 'morphology' | 'contouring-discrete' | 'contouring-table' | 'round-edges' | 'grayscale' | 'channel-painter' | 'brightness' | 'contrast' | 'opacity' | 'invert' | 'hue-rotate' | 'saturate' | 'black-and-white' | 'sepia' | 'duotone' | 'xray' | 'noise' | 'emboss' | 'film-grain' | 'watercolor' | 'gouache' | 'ink-blot' | 'crumpled-plastic' | 'riddled' | 'glow' | 'inner-glow' | 'raw-svg' | 'svg-primitive-chain';
567
655
  type BlurQuality = 'normal' | 'high';
568
656
  interface BaseFilter {
569
657
  id: string;
@@ -831,14 +919,265 @@ interface RawSvgFilter extends BaseFilter {
831
919
  floodOpacity?: string;
832
920
  lightingColor?: string;
833
921
  }
834
- type ShapeFilter = DropShadowFilter | InnerShadowFilter | GaussianBlurFilter | MotionBlurFilter | PointLightFilter | SpotLightFilter | DiffuseLightingFilter | SpecularLightingFilter | OutlineFilter | SharpenFilter | PixelateFilter | WarpFilter | MorphologyFilter | ContouringDiscreteFilter | ContouringTableFilter | RoundEdgesFilter | GrayscaleFilter | ChannelPainterFilter | BrightnessFilter | ContrastFilter | OpacityFilter | InvertFilter | HueRotateFilter | SaturateFilter | BlackAndWhiteFilter | SepiaFilter | DuotoneFilter | XrayFilter | NoiseFilter | EmbossFilter | FilmGrainFilter | WatercolorFilter | GouacheFilter | InkBlotFilter | CrumpledPlasticFilter | RiddledFilter | GlowFilter | InnerGlowFilter | RawSvgFilter;
835
- type SegmentCurveType = 'LINEAR' | 'CUBIC' | 'QUADRATIC' | 'ARC';
836
- interface SplinePoint {
922
+ type ShapeFilter = DropShadowFilter | InnerShadowFilter | GaussianBlurFilter | MotionBlurFilter | PointLightFilter | SpotLightFilter | DiffuseLightingFilter | SpecularLightingFilter | OutlineFilter | SharpenFilter | PixelateFilter | WarpFilter | MorphologyFilter | ContouringDiscreteFilter | ContouringTableFilter | RoundEdgesFilter | GrayscaleFilter | ChannelPainterFilter | BrightnessFilter | ContrastFilter | OpacityFilter | InvertFilter | HueRotateFilter | SaturateFilter | BlackAndWhiteFilter | SepiaFilter | DuotoneFilter | XrayFilter | NoiseFilter | EmbossFilter | FilmGrainFilter | WatercolorFilter | GouacheFilter | InkBlotFilter | CrumpledPlasticFilter | RiddledFilter | GlowFilter | InnerGlowFilter | RawSvgFilter | SvgPrimitiveChainFilter;
923
+ /** Common attributes on every filter primitive (FE1 §7.2). */
924
+ interface BaseFilterPrimitive {
925
+ /** Editor-only stable id; not serialized to SVG. */
926
+ id: string;
927
+ /** SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha |
928
+ * FillPaint | StrokePaint | <filter-primitive-reference>. Omitted ⇒
929
+ * defaults to previous primitive's result (or SourceGraphic if first). */
930
+ in?: string;
931
+ /** Custom result name for forward references. Omitted ⇒ implicit. */
932
+ result?: string;
933
+ /** Filter primitive subregion (FE1 §7.3). */
934
+ x?: string;
935
+ y?: string;
936
+ width?: string;
937
+ height?: string;
938
+ /** Per-primitive override of color-interpolation-filters. */
939
+ colorInterpolationFilters?: 'auto' | 'sRGB' | 'linearRGB';
940
+ /** Carry of attributes the editor doesn't model (style, class, data-*,
941
+ * unknown spec attrs). Re-emitted verbatim. Keys exclude attrs already
942
+ * modeled on this primitive. */
943
+ unknownAttrs?: Record<string, string>;
944
+ /** SMIL animation children attached to this primitive — preserved
945
+ * verbatim. Each entry is the outerHTML of an <animate>, <set>,
946
+ * <animateTransform>, or <animateMotion> element. */
947
+ animations?: string[];
948
+ }
949
+ /** Blend modes per Compositing 1 §3 + the FE1-specific extensions. */
950
+ type FilterBlendMode = 'normal' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color-dodge' | 'color-burn' | 'hard-light' | 'soft-light' | 'difference' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity' | 'plus-darker' | 'plus-lighter';
951
+ interface FeBlendPrimitive extends BaseFilterPrimitive {
952
+ type: 'feBlend';
953
+ in2?: string;
954
+ mode?: FilterBlendMode;
955
+ /** FE1 extension — boolean attribute, presence-based. */
956
+ noComposite?: boolean;
957
+ }
958
+ interface FeColorMatrixPrimitive extends BaseFilterPrimitive {
959
+ type: 'feColorMatrix';
960
+ matrixType?: 'matrix' | 'saturate' | 'hueRotate' | 'luminanceToAlpha';
961
+ /** Verbatim attribute string so we preserve the exact author spelling
962
+ * (matrix arg counts, whitespace inside). Omitted ⇒ spec defaults
963
+ * apply (matrix=identity, saturate=1, hueRotate=0). */
964
+ values?: string;
965
+ }
966
+ type TransferFunc = {
967
+ type: 'identity';
968
+ } | {
969
+ type: 'table' | 'discrete';
970
+ tableValues: number[];
971
+ } | {
972
+ type: 'linear';
973
+ slope?: number;
974
+ intercept?: number;
975
+ } | {
976
+ type: 'gamma';
977
+ amplitude?: number;
978
+ exponent?: number;
979
+ offset?: number;
980
+ };
981
+ interface FeComponentTransferPrimitive extends BaseFilterPrimitive {
982
+ type: 'feComponentTransfer';
983
+ funcR?: TransferFunc;
984
+ funcG?: TransferFunc;
985
+ funcB?: TransferFunc;
986
+ funcA?: TransferFunc;
987
+ }
988
+ interface FeCompositePrimitive extends BaseFilterPrimitive {
989
+ type: 'feComposite';
990
+ in2?: string;
991
+ operator?: 'over' | 'in' | 'out' | 'atop' | 'xor' | 'lighter' | 'arithmetic';
992
+ k1?: number;
993
+ k2?: number;
994
+ k3?: number;
995
+ k4?: number;
996
+ }
997
+ interface FeConvolveMatrixPrimitive extends BaseFilterPrimitive {
998
+ type: 'feConvolveMatrix';
999
+ /** <number-optional-number>; preserved as authored (e.g. "3" or "3 3"). */
1000
+ order?: string;
1001
+ /** Space-separated kernel values, preserved as authored. */
1002
+ kernelMatrix?: string;
1003
+ divisor?: number;
1004
+ bias?: number;
1005
+ targetX?: number;
1006
+ targetY?: number;
1007
+ edgeMode?: 'duplicate' | 'wrap' | 'none';
1008
+ /** <number-optional-number>; preserved as authored. */
1009
+ kernelUnitLength?: string;
1010
+ preserveAlpha?: boolean;
1011
+ }
1012
+ /** Light source elements (FE1 §16) — never appear at <filter> top level,
1013
+ * only as children of feDiffuseLighting/feSpecularLighting. */
1014
+ type FilterLightSource = {
1015
+ kind: 'feDistantLight';
1016
+ azimuth?: number;
1017
+ elevation?: number;
1018
+ } | {
1019
+ kind: 'fePointLight';
1020
+ x?: number;
1021
+ y?: number;
1022
+ z?: number;
1023
+ } | {
1024
+ kind: 'feSpotLight';
1025
+ x?: number;
1026
+ y?: number;
1027
+ z?: number;
1028
+ pointsAtX?: number;
1029
+ pointsAtY?: number;
1030
+ pointsAtZ?: number;
1031
+ specularExponent?: number;
1032
+ limitingConeAngle?: number;
1033
+ };
1034
+ interface FeDiffuseLightingPrimitive extends BaseFilterPrimitive {
1035
+ type: 'feDiffuseLighting';
1036
+ surfaceScale?: number;
1037
+ diffuseConstant?: number;
1038
+ /** <number-optional-number>; preserved as authored. */
1039
+ kernelUnitLength?: string;
1040
+ lightingColor?: string;
1041
+ lightSource?: FilterLightSource;
1042
+ }
1043
+ interface FeSpecularLightingPrimitive extends BaseFilterPrimitive {
1044
+ type: 'feSpecularLighting';
1045
+ surfaceScale?: number;
1046
+ specularConstant?: number;
1047
+ specularExponent?: number;
1048
+ kernelUnitLength?: string;
1049
+ lightingColor?: string;
1050
+ lightSource?: FilterLightSource;
1051
+ }
1052
+ interface FeDisplacementMapPrimitive extends BaseFilterPrimitive {
1053
+ type: 'feDisplacementMap';
1054
+ in2?: string;
1055
+ scale?: number;
1056
+ xChannelSelector?: 'R' | 'G' | 'B' | 'A';
1057
+ yChannelSelector?: 'R' | 'G' | 'B' | 'A';
1058
+ }
1059
+ interface FeDropShadowPrimitive extends BaseFilterPrimitive {
1060
+ type: 'feDropShadow';
1061
+ dx?: number;
1062
+ dy?: number;
1063
+ /** <number-optional-number>; preserved as authored. */
1064
+ stdDeviation?: string;
1065
+ floodColor?: string;
1066
+ /** Numeric value or the literal 'inherit'. */
1067
+ floodOpacity?: string;
1068
+ }
1069
+ interface FeFloodPrimitive extends BaseFilterPrimitive {
1070
+ type: 'feFlood';
1071
+ floodColor?: string;
1072
+ floodOpacity?: string;
1073
+ }
1074
+ interface FeGaussianBlurPrimitive extends BaseFilterPrimitive {
1075
+ type: 'feGaussianBlur';
1076
+ /** <number-optional-number>; preserved as authored (e.g. "3" or "3 1"). */
1077
+ stdDeviation?: string;
1078
+ edgeMode?: 'duplicate' | 'wrap' | 'none';
1079
+ }
1080
+ interface FeImagePrimitive extends BaseFilterPrimitive {
1081
+ type: 'feImage';
1082
+ /** Canonical (SVG 2). */
1083
+ href?: string;
1084
+ /** Back-compat alias re-emitted only when the original used xlink:href
1085
+ * and no href was authored. */
1086
+ xlinkHref?: string;
1087
+ preserveAspectRatio?: string;
1088
+ crossorigin?: 'anonymous' | 'use-credentials';
1089
+ }
1090
+ interface FeMergePrimitive extends BaseFilterPrimitive {
1091
+ type: 'feMerge';
1092
+ /** <feMergeNode> children inlined. */
1093
+ nodes: {
1094
+ in?: string;
1095
+ }[];
1096
+ }
1097
+ interface FeMorphologyPrimitive extends BaseFilterPrimitive {
1098
+ type: 'feMorphology';
1099
+ operator?: 'erode' | 'dilate';
1100
+ /** <number-optional-number>; preserved as authored. */
1101
+ radius?: string;
1102
+ }
1103
+ interface FeOffsetPrimitive extends BaseFilterPrimitive {
1104
+ type: 'feOffset';
1105
+ dx?: number;
1106
+ dy?: number;
1107
+ }
1108
+ interface FeTilePrimitive extends BaseFilterPrimitive {
1109
+ type: 'feTile';
1110
+ }
1111
+ interface FeTurbulencePrimitive extends BaseFilterPrimitive {
1112
+ type: 'feTurbulence';
1113
+ /** <number-optional-number>; preserved as authored. */
1114
+ baseFrequency?: string;
1115
+ numOctaves?: number;
1116
+ seed?: number;
1117
+ stitchTiles?: 'stitch' | 'noStitch';
1118
+ turbulenceType?: 'fractalNoise' | 'turbulence';
1119
+ }
1120
+ type FilterPrimitive = FeBlendPrimitive | FeColorMatrixPrimitive | FeComponentTransferPrimitive | FeCompositePrimitive | FeConvolveMatrixPrimitive | FeDiffuseLightingPrimitive | FeSpecularLightingPrimitive | FeDisplacementMapPrimitive | FeDropShadowPrimitive | FeFloodPrimitive | FeGaussianBlurPrimitive | FeImagePrimitive | FeMergePrimitive | FeMorphologyPrimitive | FeOffsetPrimitive | FeTilePrimitive | FeTurbulencePrimitive;
1121
+ type FilterPrimitiveType = FilterPrimitive['type'];
1122
+ /**
1123
+ * A `<filter>` element modeled as an ordered list of editable primitives.
1124
+ *
1125
+ * This variant is the parser's default when no curated stylized preset
1126
+ * matches — it preserves every spec primitive 1:1 so imported third-party
1127
+ * SVG round-trips with semantic equivalence and remains editable in the
1128
+ * filters panel. Distinct from `RawSvgFilter` (which is opaque XML
1129
+ * passthrough); this one walks the primitives.
1130
+ */
1131
+ interface SvgPrimitiveChainFilter extends BaseFilter {
1132
+ type: 'svg-primitive-chain';
1133
+ /** <filter> wrapper attributes — all optional; omitted ⇒ UA spec default. */
1134
+ filterUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1135
+ primitiveUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1136
+ x?: string;
1137
+ y?: string;
1138
+ width?: string;
1139
+ height?: string;
1140
+ filterColorInterpolation?: 'auto' | 'sRGB' | 'linearRGB';
1141
+ /** Inheritable presentation attrs author placed on <filter> so child
1142
+ * primitives can resolve them via the CSS `inherit` keyword. */
1143
+ floodColor?: string;
1144
+ floodOpacity?: string;
1145
+ lightingColor?: string;
1146
+ /** <title> child text, captured for a11y/round-trip. */
1147
+ filterTitle?: string;
1148
+ filterDescription?: string;
1149
+ /** SMIL animation children directly on <filter> (rare). */
1150
+ filterAnimations?: string[];
1151
+ /** The primitive chain. Order is significant — implicit input chains
1152
+ * match document order. */
1153
+ primitives: FilterPrimitive[];
1154
+ }
1155
+ /**
1156
+ * Per-segment command hint, recording the SVG path command the segment
1157
+ * was authored with. Lets the serializer emit the original command form
1158
+ * (H, V, S, T, A) when the current geometry still satisfies its
1159
+ * constraints — and auto-demote to L/C/Q when a user edit invalidates
1160
+ * the shorthand condition. Replaces the old `originalD` round-trip
1161
+ * cache with a property of the geometry itself.
1162
+ *
1163
+ * - LINEAR → `L` (default for handle-less segments)
1164
+ * - HORIZONTAL → `H`; valid when `from.y === to.y`
1165
+ * - VERTICAL → `V`; valid when `from.x === to.x`
1166
+ * - CUBIC → `C`
1167
+ * - SMOOTH_CUBIC → `S`; valid when `to.handleIn` reflects the previous
1168
+ * segment's exit-tangent about the previous endpoint
1169
+ * - QUADRATIC → `Q`
1170
+ * - SMOOTH_QUADRATIC → `T`; valid when the implicit control reflects the
1171
+ * previous quadratic's control about the current point
1172
+ * - ARC → `A`
1173
+ */
1174
+ type SegmentCurveType = 'LINEAR' | 'HORIZONTAL' | 'VERTICAL' | 'CUBIC' | 'SMOOTH_CUBIC' | 'QUADRATIC' | 'SMOOTH_QUADRATIC' | 'ARC';
1175
+ interface PathPoint {
837
1176
  x: number;
838
1177
  y: number;
839
1178
  handleIn?: Point;
840
1179
  handleOut?: Point;
841
- pointType: SplinePointType;
1180
+ pointType: PathPointType;
842
1181
  isSubpathStart?: boolean;
843
1182
  segmentType?: SegmentCurveType;
844
1183
  arcParams?: ArcParams$1;
@@ -850,6 +1189,12 @@ interface ArcParams$1 {
850
1189
  largeArc: boolean;
851
1190
  sweep: boolean;
852
1191
  }
1192
+ /**
1193
+ * Hyperlink target per SVG 2 §16.2. Kept for UI convenience — the four
1194
+ * well-known keywords plus any authored `<XML-Name>` (custom named
1195
+ * browsing context). Hyperlink shapes themselves store target as a plain
1196
+ * string so arbitrary names round-trip.
1197
+ */
853
1198
  type LinkTarget = '_self' | '_blank' | '_parent' | '_top';
854
1199
  type AriaRole = '' | 'img' | 'button' | 'link' | 'presentation' | 'none' | 'graphics-document' | 'graphics-object' | 'graphics-symbol';
855
1200
  interface ShapeMetadata {
@@ -859,9 +1204,58 @@ interface ShapeMetadata {
859
1204
  description: string;
860
1205
  role: AriaRole;
861
1206
  ariaLabel: string;
862
- linkUrl: string;
863
- linkTarget: LinkTarget;
864
1207
  customData: Record<string, string>;
1208
+ /**
1209
+ * Generic ARIA attribute bag — every `aria-*` attribute *except*
1210
+ * `aria-label` (which has its own dedicated field for the metadata
1211
+ * panel's back-compat path). Keys are the full attribute name, e.g.
1212
+ * `'aria-labelledby'`, `'aria-describedby'`, `'aria-hidden'`.
1213
+ *
1214
+ * Spec: SVG 2 §5.12.3 — "All aria- attributes" are valid on every SVG
1215
+ * element. Stored verbatim so the full WAI-ARIA surface round-trips.
1216
+ */
1217
+ aria?: Record<string, string>;
1218
+ /**
1219
+ * Per-element `lang` / `xml:lang` value (SVG 2 §5.11.3). Authored
1220
+ * `xml:lang` is preferred but `lang` is accepted as a fallback. Emit
1221
+ * as `xml:lang` per spec recommendation.
1222
+ */
1223
+ lang?: string;
1224
+ /**
1225
+ * Per-element `tabindex` (SVG 2 §5.11.5). Stored as integer. Negative
1226
+ * values are valid (focusable but not in the default tab order).
1227
+ */
1228
+ tabindex?: number;
1229
+ /** Per-element `autofocus` (SVG 2 §5.11.6). Boolean attribute. */
1230
+ autofocus?: boolean;
1231
+ /**
1232
+ * Per-element `xml:space` value (SVG 2 §5.11.4) for non-text shapes.
1233
+ * Text-bearing shapes (`Text`) own their own `xml:space` lifecycle
1234
+ * via the rich-text serializer.
1235
+ */
1236
+ xmlSpace?: 'default' | 'preserve';
1237
+ /**
1238
+ * Foreign-namespaced or prefixed attributes preserved verbatim for
1239
+ * round-trip (SVG 2 §5.10 — "elements and attributes from foreign
1240
+ * namespaces ... must be ignored for rendering ... [but] preserved
1241
+ * when the SVG document is loaded and saved"). Covers `inkscape:`,
1242
+ * `sodipodi:`, `serif:`, `figma:`, and any other authoring-tool
1243
+ * markers, plus arbitrary user-defined namespaces. Stored as a list
1244
+ * (rather than a record) to preserve ordering and to permit multiple
1245
+ * attributes with the same local name across different namespaces.
1246
+ */
1247
+ foreignAttrs?: Array<{
1248
+ name: string;
1249
+ namespaceURI: string | null;
1250
+ value: string;
1251
+ }>;
1252
+ /**
1253
+ * Hyperlink target — when set, the shape is rendered inside an SVG `<a>`
1254
+ * element with `href="${linkUrl}"`. Round-trips through SVG import/export.
1255
+ */
1256
+ linkUrl?: string;
1257
+ /** Hyperlink target window — maps to `<a target="...">`. */
1258
+ linkTarget?: LinkTarget;
865
1259
  /**
866
1260
  * Lossless carrier for any `<metadata>` elements that appeared as children
867
1261
  * of this shape's SVG element. Stored as a serialized string containing
@@ -947,6 +1341,19 @@ interface DocumentMetadata {
947
1341
  * `ShapeMetadata.rawDescription`; see there for the emit rule.
948
1342
  */
949
1343
  rawDescription?: string;
1344
+ /**
1345
+ * Lossless carrier for HTML metadata elements (`<link>`, `<meta>`)
1346
+ * that appeared as direct children of the root `<svg>`. Stored as a
1347
+ * serialized string of one or more elements in document order.
1348
+ *
1349
+ * Spec: SVG 2 §5.9 — "The HTML elements `meta`, `link` and `style`
1350
+ * may appear inside the `svg` element". `<style>` is consumed by
1351
+ * the CSS parser; `<link>` (often used for external stylesheets)
1352
+ * and `<meta>` (charset, viewport hints, OpenGraph) round-trip
1353
+ * verbatim through this field so downstream tooling that produced
1354
+ * them sees its data preserved.
1355
+ */
1356
+ rawHtmlMetadata?: string;
950
1357
  /**
951
1358
  * Decimal precision for coordinate values when the document is
952
1359
  * serialized — file save, cloud sync, undo capture, and SVG export.
@@ -1028,6 +1435,24 @@ interface DocumentStyle {
1028
1435
  }
1029
1436
  /** Type of a template variable's value. */
1030
1437
  type TemplateVariableType = 'string' | 'color' | 'number';
1438
+ /**
1439
+ * How the variable participates in export. Two genuinely different
1440
+ * substitution mechanisms — declaring intent up-front lets the export
1441
+ * pipeline pick the right one.
1442
+ *
1443
+ * - `live` → emitted as `var(--name, fallback)` references; the
1444
+ * variable definition rides along in a `<style>` block,
1445
+ * so consumers can re-theme the SVG at runtime via the
1446
+ * CSS cascade.
1447
+ * - `stamped` → resolved to its literal value at export time. Used
1448
+ * for `{{name}}` template-style stamping, and for
1449
+ * attributes (`width`, `x`, geometry) where `var()`
1450
+ * in attribute values has uneven interop.
1451
+ *
1452
+ * Defaults to `live` for `color` (well-supported in browsers), `stamped`
1453
+ * for `number`/`string` (where attribute-level var() is unreliable).
1454
+ */
1455
+ type TemplateVariableMode = 'live' | 'stamped';
1031
1456
  /**
1032
1457
  * Where a TemplateVariable came from. `user` is hand-authored in the
1033
1458
  * Variables panel; `palette` is auto-generated by the palette-token
@@ -1074,7 +1499,19 @@ interface TemplateVariable {
1074
1499
  * settings palette.
1075
1500
  */
1076
1501
  source?: TemplateVariableSource;
1502
+ /**
1503
+ * Substitution mode at export time. When omitted, callers should
1504
+ * apply the type-based default in `defaultVariableMode()`:
1505
+ * `color` → `live`, `number`/`string` → `stamped`.
1506
+ */
1507
+ mode?: TemplateVariableMode;
1077
1508
  }
1509
+ /**
1510
+ * Type-based default substitution mode. Color variables work reliably as
1511
+ * runtime `var()` references in browsers; numbers and strings are far
1512
+ * better baked into literal attribute values at export time.
1513
+ */
1514
+ declare function defaultVariableMode(type: TemplateVariableType): TemplateVariableMode;
1078
1515
  interface Guide {
1079
1516
  id: string;
1080
1517
  orientation: 'horizontal' | 'vertical';
@@ -1148,11 +1585,31 @@ interface SerializedShape {
1148
1585
  textDirection?: 'ltr' | 'rtl';
1149
1586
  unicodeBidi?: 'normal' | 'embed' | 'bidi-override' | 'isolate' | 'isolate-override' | 'plaintext';
1150
1587
  fontVariationSettings?: Record<string, number>;
1151
- charOffsets?: {
1588
+ /**
1589
+ * Per-glyph positioning data, mirroring SVG 2 §11.2's five attribute
1590
+ * lists (`x`, `y`, `dx`, `dy`, `rotate`).
1591
+ *
1592
+ * - `x`/`y` are absolute user coordinates; `null` means "no
1593
+ * override at this glyph — the cursor advances naturally".
1594
+ * - `dx`/`dy` are additive shifts on top of natural advance.
1595
+ * - `rotate` is per-glyph rotation in degrees.
1596
+ *
1597
+ * For backward compatibility, the legacy three-field shape
1598
+ * `{x, y, rotate}` (produced before the spec-aligned model shipped)
1599
+ * is still accepted on read; its `x`/`y` are interpreted as the
1600
+ * additive shifts (`dx`/`dy`).
1601
+ */
1602
+ charOffsets?: ({
1603
+ x: number | null;
1604
+ y: number | null;
1605
+ dx: number;
1606
+ dy: number;
1607
+ rotate: number;
1608
+ } | {
1152
1609
  x: number;
1153
1610
  y: number;
1154
1611
  rotate: number;
1155
- }[];
1612
+ })[];
1156
1613
  linePositions?: {
1157
1614
  x: number;
1158
1615
  dy: number;
@@ -1181,9 +1638,29 @@ interface SerializedShape {
1181
1638
  borderColor?: string;
1182
1639
  borderWidth?: number | string;
1183
1640
  strokeOpacity?: number;
1641
+ /**
1642
+ * Inherit `fill` from the ancestor cascade rather than emit an explicit
1643
+ * attribute. Set at import for shapes inside `<defs>`/`<symbol>` that
1644
+ * have no own `fill` — they're reachable only via `<use>`, whose shadow
1645
+ * tree inherits paint from the `<use>` element itself (SVG 2 §5.5.4).
1646
+ * Baking the SVG-default black onto the inner shape would block the
1647
+ * `<use fill="…">` cascade and render the instance override dead.
1648
+ */
1649
+ inheritFill?: boolean;
1650
+ /** See {@link inheritFill}. */
1651
+ inheritStroke?: boolean;
1184
1652
  /** CSS `paint-order` (SVG 2). Canonical SVG token string, e.g.
1185
1653
  * 'stroke fill markers'. Omitted when equivalent to default 'normal'. */
1186
1654
  paintOrder?: string;
1655
+ /**
1656
+ * CSS Transforms 2 §6.2 — `transform-box` reference box. SVG
1657
+ * default is `view-box`; persisted on the shape so authored values
1658
+ * (`fill-box`, `stroke-box`) survive round-trip. The editor bakes
1659
+ * `transform-origin` into a numeric pivot at import using the
1660
+ * resolved box, so this field exists for export fidelity rather
1661
+ * than rendering.
1662
+ */
1663
+ transformBox?: 'view-box' | 'fill-box' | 'stroke-box' | 'content-box' | 'border-box';
1187
1664
  /** Marker id applied as `marker-start` (rendered `url(#id)` in SVG). */
1188
1665
  markerStart?: string;
1189
1666
  /** Marker id applied as `marker-mid`. */
@@ -1304,17 +1781,49 @@ interface SerializedShape {
1304
1781
  /** @deprecated v2 — see `filterX`. */
1305
1782
  filterHeight?: string;
1306
1783
  rawTransform?: string;
1307
- splinePoints?: SplinePoint[];
1308
- splineCurveType?: SplineCurveType;
1309
- splineClosed?: boolean;
1310
- splineTension?: number;
1311
- splineArcParams?: ArcParams$1[];
1784
+ ancestorTransform?: number[];
1785
+ pathPoints?: PathPoint[];
1786
+ pathCurveType?: PathCurveType;
1787
+ pathClosed?: boolean;
1788
+ pathTension?: number;
1789
+ pathArcParams?: ArcParams$1[];
1790
+ /**
1791
+ * SVG 2 §6 `pathLength` — author's stated total length of the path.
1792
+ * Used to scale distance-along-a-path computations (text-on-path,
1793
+ * `<animateMotion>`, `stroke-dasharray`) by `pathLength / actualLength`.
1794
+ * A non-negative number; negative values are an error per spec.
1795
+ */
1796
+ pathLength?: number;
1797
+ /**
1798
+ * CSS Vector Effects — `vector-effect` property. `non-scaling-stroke`
1799
+ * keeps stroke width constant under zoom/transforms (heavily used in
1800
+ * CAD/diagram SVGs). Applies to any graphic element, not just paths;
1801
+ * persists at the SerializedShape state level so all shape types can
1802
+ * round-trip it.
1803
+ */
1804
+ vectorEffect?: 'none' | 'non-scaling-stroke' | 'non-scaling-size' | 'non-rotation' | 'fixed-position';
1312
1805
  polylinePoints?: Point[];
1313
1806
  polylineClosed?: boolean;
1314
1807
  href?: string;
1315
1808
  originalWidth?: number;
1316
1809
  originalHeight?: number;
1810
+ /**
1811
+ * Editor-internal flag controlling whether interactive resize keeps
1812
+ * the image's natural aspect ratio. NOT the SVG `preserveAspectRatio`
1813
+ * attribute — this is purely a UX behavior switch on the resize
1814
+ * handles. Persisted so the user's setting survives reload.
1815
+ */
1317
1816
  preserveAspectRatio?: boolean;
1817
+ /**
1818
+ * SVG 2 §8.7 — verbatim `preserveAspectRatio` attribute value
1819
+ * (e.g. `'xMidYMid slice'`, `'defer xMidYMid meet'`, `'none'`). When
1820
+ * unset, the spec default applies. The editor canvas always renders
1821
+ * `<image>` with `preserveAspectRatio="none"` so the visible box
1822
+ * matches the resize handles; this field carries the author's
1823
+ * intent through round-trip and is restored on export by
1824
+ * `SvgExportFinalizer`.
1825
+ */
1826
+ specPreserveAspectRatio?: string;
1318
1827
  imageOpacity?: number;
1319
1828
  mediaKind?: 'audio' | 'video';
1320
1829
  mediaMimeType?: string;
@@ -1350,12 +1859,36 @@ interface SerializedShape {
1350
1859
  * soundtracks / captioned video versions.
1351
1860
  */
1352
1861
  systemLanguage?: string;
1862
+ /**
1863
+ * Space-separated list of required IRI references that the user agent
1864
+ * must support for this shape to be rendered. SVG 2 §15.4 conditional
1865
+ * processing — typically `http://www.w3.org/TR/SVG11/feature#…` strings.
1866
+ * Persisted alongside `systemLanguage` so `<switch>` content round-trips.
1867
+ */
1868
+ requiredExtensions?: string;
1353
1869
  shapeInsideRef?: string;
1354
1870
  shapePadding?: number;
1355
1871
  isTextPath?: boolean;
1356
- textPathPoints?: SplinePoint[];
1872
+ textPathPoints?: PathPoint[];
1873
+ /**
1874
+ * Curve type used to interpolate `textPathPoints` into a renderable
1875
+ * path. Mirrors `pathCurveType` for plain path shapes; persisted
1876
+ * separately so author-set text-path curves don't have to share the
1877
+ * shape's geometry curve type.
1878
+ */
1879
+ textPathCurveType?: PathCurveType;
1357
1880
  textPathStartOffset?: number;
1881
+ textPathStartOffsetUnit?: '%' | 'user';
1358
1882
  textPathSide?: 'left' | 'right';
1883
+ textPathMethod?: 'align' | 'stretch';
1884
+ textPathSpacing?: 'auto' | 'exact';
1885
+ textPathLengthAdjust?: 'spacing' | 'spacingAndGlyphs';
1886
+ textPathLength?: number;
1887
+ textPathLengthUnit?: '%' | 'user';
1888
+ textPathInlineFormat?: 'defs-path' | 'path-attr';
1889
+ textPathRefShapeId?: string;
1890
+ /** Transient: import-time href target id, resolved away by ImportExportManager. */
1891
+ textPathImportRefId?: string;
1359
1892
  fillRule?: 'nonzero' | 'evenodd';
1360
1893
  strokeLinejoin?: 'miter' | 'round' | 'bevel';
1361
1894
  strokeLinecap?: 'butt' | 'round' | 'square';
@@ -1363,7 +1896,40 @@ interface SerializedShape {
1363
1896
  opacity?: number;
1364
1897
  blendMode?: string;
1365
1898
  shapeRendering?: 'auto' | 'optimizeSpeed' | 'crispEdges' | 'geometricPrecision';
1899
+ textRendering?: 'auto' | 'optimizeSpeed' | 'optimizeLegibility' | 'geometricPrecision';
1900
+ imageRendering?: 'auto' | 'optimizeSpeed' | 'optimizeQuality' | 'crisp-edges' | 'pixelated' | 'smooth' | 'high-quality';
1901
+ colorRendering?: 'auto' | 'optimizeSpeed' | 'optimizeQuality';
1902
+ /**
1903
+ * SVG `color-interpolation` (SVG 2 §13.9). Selects the color space —
1904
+ * sRGB or linearized RGB — used for *non-filter* color operations:
1905
+ * gradient-stop interpolation, SMIL color animation interpolation,
1906
+ * and the compositing/blending of graphics elements. The
1907
+ * filter-pipeline analogue is `color-interpolation-filters`
1908
+ * (carried separately on filter chains as `filterColorInterpolation`).
1909
+ * Spec initial value: `sRGB`. Authors who pick `linearRGB` get
1910
+ * physically-linear stop interpolation; missing this attribute on
1911
+ * round-trip silently shifts mid-tone gradient colors.
1912
+ */
1913
+ colorInterpolation?: 'auto' | 'sRGB' | 'linearRGB';
1914
+ /**
1915
+ * SVG `display` presentation attribute as authored on the source
1916
+ * element. Distinct from `visible` (editor's layer-hide boolean,
1917
+ * which writes inline `style="display:none"`): `display: 'none'`
1918
+ * here carries the author's intent through round-trip as an XML
1919
+ * attribute (`<rect display="none"/>`), preserving SVG 2 §3.2.2
1920
+ * semantics that `display:none` removes the element from the
1921
+ * rendering tree.
1922
+ */
1923
+ display?: 'none';
1366
1924
  metadata?: Partial<ShapeMetadata>;
1925
+ /**
1926
+ * Shape-scoped `<script>` elements (SVG 2 §15.9 allows scripts as
1927
+ * descendants of any container). Emitted as children of the shape's
1928
+ * exported element on save; preserved verbatim through .svgs round-trip,
1929
+ * undo/redo, copy/paste. Distinct from `HistorySnapshot.documentScripts`
1930
+ * which sits at the SVG root and runs in document order.
1931
+ */
1932
+ scripts?: DocumentScript[];
1367
1933
  groupId?: string;
1368
1934
  cssClipPath?: string;
1369
1935
  cssMaskProperties?: Record<string, string>;
@@ -1382,6 +1948,53 @@ interface SerializedShape {
1382
1948
  * variant (`def.shapes`). Only meaningful on `symbol-instance` shapes.
1383
1949
  */
1384
1950
  variantKey?: string;
1951
+ /**
1952
+ * Per-instance presentation cascade (SVG 2 §5.5.4): attributes set on
1953
+ * the source `<use>` element that are inherited into the symbol shadow
1954
+ * tree on render and re-emitted on export. Keyed by the SVG attribute
1955
+ * name in its canonical kebab-case form (`fill`, `stroke-width`,
1956
+ * `color-interpolation-filters`, `paint-order`, etc.). Values are the
1957
+ * verbatim attribute string — numeric parsing happens at the edit /
1958
+ * render boundary, not at storage time.
1959
+ *
1960
+ * The map is the single source of truth: importing a `<use>` stores
1961
+ * every presentation-class attribute the author wrote, applying it
1962
+ * mirrors every entry onto the wrapper `<g>`, and exporting emits
1963
+ * every entry back onto the `<use>`. No whitelist — any attribute the
1964
+ * SVG cascade honors round-trips.
1965
+ *
1966
+ * Special case: `transform` is composed with the editor's geometry
1967
+ * (position / rotation / skew / scale) rather than applied raw to the
1968
+ * wrapper. See `SymbolInstance.buildTransformString`.
1969
+ *
1970
+ * Legacy (pre-refactor) documents may carry camelCase keys
1971
+ * (`fillOpacity`, `strokeWidth`, …). `SymbolInstance.createFromSerialized`
1972
+ * normalises them to kebab-case on load; no runtime readers of this
1973
+ * field should assume either form.
1974
+ *
1975
+ * Only meaningful on `symbol-instance` shapes.
1976
+ */
1977
+ instancePresentation?: Record<string, string>;
1978
+ /**
1979
+ * Inline children for container shape types (`hyperlink`, `switch`,
1980
+ * `container`, embedded `svg`). Each child is a self-contained
1981
+ * `SerializedShape` rendered nested inside the parent's element.
1982
+ *
1983
+ * Groups (`type === 'group'`) do NOT use this field — they store
1984
+ * children flat in `HistorySnapshot.shapes[]` and back-reference the
1985
+ * parent group via `state.groupId`. The two pickup paths exist
1986
+ * because groups predate the inline-children container model.
1987
+ */
1988
+ children?: SerializedShape[];
1989
+ /** Legacy `xlink:href`, preserved alongside `href` for round-trip. */
1990
+ hrefXlink?: string;
1991
+ linkTarget?: '_self' | '_blank' | '_parent' | '_top' | string;
1992
+ linkRel?: string;
1993
+ linkDownload?: string;
1994
+ linkPing?: string;
1995
+ linkHreflang?: string;
1996
+ linkType?: string;
1997
+ linkReferrerPolicy?: string;
1385
1998
  /**
1386
1999
  * Id of the canvas shape this `shape-reference` (Linked Copy) targets.
1387
2000
  * A Linked Copy renders as a live clone of another top-level shape and
@@ -1446,6 +2059,44 @@ interface SerializedShape {
1446
2059
  topWidthPercent?: number;
1447
2060
  /** Document shape: wave amplitude as a % of height. */
1448
2061
  waveAmplitudePercent?: number;
2062
+ /** View shape: viewBox X component (animatable axis of the 4-tuple). */
2063
+ viewBoxX?: number;
2064
+ /** View shape: viewBox Y component (animatable axis of the 4-tuple). */
2065
+ viewBoxY?: number;
2066
+ /** View shape: viewBox width component (animatable axis of the 4-tuple). */
2067
+ viewBoxWidth?: number;
2068
+ /** View shape: viewBox height component (animatable axis of the 4-tuple). */
2069
+ viewBoxHeight?: number;
2070
+ /** View shape: name used as `<view id="...">` and fragment URL target. */
2071
+ viewName?: string;
2072
+ /** View shape: optional preserveAspectRatio (SVG 2 §7.8 — animatable). */
2073
+ viewPreserveAspectRatio?: string;
2074
+ /** View shape: SVG 1.1 §16.5 zoomAndPan. */
2075
+ viewZoomAndPan?: 'disable' | 'magnify';
2076
+ /** View shape: deprecated SVG 1.1 viewTarget — preserved verbatim. */
2077
+ viewTarget?: string;
2078
+ /** View shape: when true, this View's viewBox becomes the root SVG viewBox. */
2079
+ isHomeView?: boolean;
2080
+ /** SvgShape: viewBox X component (animatable). */
2081
+ svgViewBoxX?: number;
2082
+ /** SvgShape: viewBox Y component (animatable). */
2083
+ svgViewBoxY?: number;
2084
+ /** SvgShape: viewBox width component (animatable). */
2085
+ svgViewBoxWidth?: number;
2086
+ /** SvgShape: viewBox height component (animatable). */
2087
+ svgViewBoxHeight?: number;
2088
+ /** SvgShape: preserveAspectRatio (SVG 2 §7.8 — animatable, discrete). */
2089
+ svgPreserveAspectRatio?: string;
2090
+ /** SvgShape: outermost = intrinsic doc size, embedded = viewport rect width. */
2091
+ svgWidth?: number;
2092
+ /** SvgShape: outermost = intrinsic doc size, embedded = viewport rect height. */
2093
+ svgHeight?: number;
2094
+ /** SvgShape: x position (no effect on outermost per §5.1.4 ¶3, embedded only). */
2095
+ svgX?: number;
2096
+ /** SvgShape: y position (no effect on outermost per §5.1.4 ¶3, embedded only). */
2097
+ svgY?: number;
2098
+ /** SvgShape: marks the singleton root <svg> shape (one per document). */
2099
+ isRootSvg?: boolean;
1449
2100
  };
1450
2101
  }
1451
2102
  type SerializedViewbox = Viewbox;
@@ -1507,6 +2158,18 @@ interface HistorySnapshot {
1507
2158
  * MarkerManager and are NOT persisted here — only user-authored defs are.
1508
2159
  */
1509
2160
  library?: LibraryDef[];
2161
+ /**
2162
+ * Raw XML fragments for `<mask>` / `<clipPath>` defs that live in editor
2163
+ * defs but have no typed entry in `library`. Populated by paste pipelines
2164
+ * that clone source paint-server defs verbatim (preserving original ids so
2165
+ * `url(#id)` refs resolve). Without this field, the save/reload cycle
2166
+ * drops the masks entirely because `library` has no kind for them; shapes
2167
+ * that reference those ids render without their mask.
2168
+ *
2169
+ * Each entry is a serialised fragment (`<mask id="…">…</mask>`) ready to
2170
+ * `innerHTML`-append into editor defs on restore.
2171
+ */
2172
+ rawPaintServerDefs?: string[];
1510
2173
  /** @deprecated v2 — use `library`. Read-only: v1 docs migrate into `library`. */
1511
2174
  customPatterns?: CustomPatternDef[];
1512
2175
  /** @deprecated v2 — use `library`. Read-only: v1 docs migrate into `library`. */
@@ -1556,6 +2219,14 @@ interface SerializedGroup {
1556
2219
  parentId: string | null;
1557
2220
  /** CSS transform-origin value (e.g. "50px 50px") for group animations */
1558
2221
  transformOrigin?: string;
2222
+ /**
2223
+ * SVG `<g>` transform attribute (e.g. "matrix(...)" or "scale(2,1)").
2224
+ * Preserved verbatim from import so the group carries its ancestor/own
2225
+ * transform through serialization (clipboard, undo/redo, collab).
2226
+ * Shapes inside stay in the group's local frame — the browser composes
2227
+ * `groupTransform × child` natively at render.
2228
+ */
2229
+ transform?: string;
1559
2230
  /**
1560
2231
  * Zero-based position of this group among its parent container's
1561
2232
  * children (including both sibling groups and sibling shape nodes).
@@ -1576,6 +2247,13 @@ interface SerializedGroup {
1576
2247
  filter?: string;
1577
2248
  cssFilter?: string;
1578
2249
  mixBlendMode?: string;
2250
+ /**
2251
+ * CSS `isolation` (Compositing & Blending §6.1). CSS-only property —
2252
+ * no SVG presentation-attribute form, so it lives in inline style on
2253
+ * the group element. Round-tripped here so authored
2254
+ * `<g style="isolation:isolate">` survives serialize/restore.
2255
+ */
2256
+ isolation?: string;
1579
2257
  clipPath?: string;
1580
2258
  mask?: string;
1581
2259
  /**
@@ -1700,7 +2378,28 @@ interface LibraryDefBase {
1700
2378
  */
1701
2379
  interface SymbolLibraryDef extends LibraryDefBase {
1702
2380
  kind: 'symbol';
2381
+ /**
2382
+ * Source SVG element form for round-trip fidelity. Most symbols are
2383
+ * authored as `<symbol>` (SVG 2 §5.5.1); `<defs><g id="X"/>` referenced
2384
+ * by `<use href="#X"/>` is a legally distinct pattern that the editor
2385
+ * also models as a SymbolLibraryDef but must export as `<g>` to remain
2386
+ * spec-faithful — `<symbol>` would silently introduce viewport-
2387
+ * establishment (SVG 2 §5.5.2) and `overflow: hidden` defaulting that
2388
+ * the source `<g>` does not have. Default `'symbol'` for backward
2389
+ * compatibility with documents authored before this field existed.
2390
+ */
2391
+ defKind?: 'symbol' | 'group';
1703
2392
  viewBox: string;
2393
+ /**
2394
+ * Wrapper attributes from the source `<g id="X">` def root that apply to
2395
+ * the def's contents (transform, opacity, fill cascade, mask, filter,
2396
+ * clip-path). Re-emitted on the exported `<g id="X">` when `defKind === 'group'`
2397
+ * — `<symbol>` doesn't legally accept these attributes per SVG 2 §5.5.1.
2398
+ * Without this, `<use href="#X"/>` would silently render the children at
2399
+ * their unwrapped local coords / paint, losing every non-id attribute on
2400
+ * the source `<g>` def root.
2401
+ */
2402
+ wrapperAttrs?: Record<string, string>;
1704
2403
  /**
1705
2404
  * Default variant shapes. When `variantAxes` is present this represents the
1706
2405
  * variant where every axis is at its first value.
@@ -1849,6 +2548,7 @@ interface CommonNodeProps {
1849
2548
  gapLength: number;
1850
2549
  dashOffset: number;
1851
2550
  strokeDasharray: string | null;
2551
+ colorInterpolation: 'auto' | 'sRGB' | 'linearRGB' | null;
1852
2552
  filters: unknown[];
1853
2553
  filterColorInterpolation: 'auto' | 'sRGB' | 'linearRGB' | null;
1854
2554
  filterUnits: 'userSpaceOnUse' | 'objectBoundingBox' | null;
@@ -1858,6 +2558,7 @@ interface CommonNodeProps {
1858
2558
  filterWidth: string | null;
1859
2559
  filterHeight: string | null;
1860
2560
  rawTransform: string | null;
2561
+ ancestorTransform: number[] | null;
1861
2562
  metadata: unknown | null;
1862
2563
  cssClipPath: string | null;
1863
2564
  cssMaskProperties: Record<string, string> | null;
@@ -1933,11 +2634,22 @@ interface TextNodeProps extends CommonNodeProps {
1933
2634
  scaleAnchor: Point | null;
1934
2635
  useRichText: boolean;
1935
2636
  richTextData: unknown | null;
1936
- charOffsets: {
2637
+ /**
2638
+ * Per-glyph positioning data — see `SerializedShape['state'].charOffsets`
2639
+ * in `serialized.ts` for full semantics. Legacy `{x, y, rotate}` form
2640
+ * accepted on read for back-compat with pre-spec-aligned saves.
2641
+ */
2642
+ charOffsets: ({
2643
+ x: number | null;
2644
+ y: number | null;
2645
+ dx: number;
2646
+ dy: number;
2647
+ rotate: number;
2648
+ } | {
1937
2649
  x: number;
1938
2650
  y: number;
1939
2651
  rotate: number;
1940
- }[] | null;
2652
+ })[] | null;
1941
2653
  fontVariationSettings: Record<string, number>;
1942
2654
  isTextPath: boolean;
1943
2655
  textPathPoints: unknown[] | null;
@@ -1957,14 +2669,14 @@ interface ImageNodeProps extends CommonNodeProps {
1957
2669
  preserveAspectRatio: boolean;
1958
2670
  imageOpacity: number;
1959
2671
  }
1960
- interface SplineNodeProps extends CommonNodeProps {
2672
+ interface PathNodeProps extends CommonNodeProps {
1961
2673
  x: number;
1962
2674
  y: number;
1963
2675
  width: number;
1964
2676
  height: number;
1965
- splinePoints: unknown[];
1966
- splineArcParams: unknown[];
1967
- splineControlBounds: {
2677
+ pathPoints: unknown[];
2678
+ pathArcParams: unknown[];
2679
+ pathControlBounds: {
1968
2680
  x: number;
1969
2681
  y: number;
1970
2682
  width: number;
@@ -2042,7 +2754,7 @@ interface NodeTypePropsMap {
2042
2754
  line: LineNodeProps;
2043
2755
  text: TextNodeProps;
2044
2756
  image: ImageNodeProps;
2045
- spline: SplineNodeProps;
2757
+ path: PathNodeProps;
2046
2758
  polyline: PolylineNodeProps;
2047
2759
  triangle: TriangleNodeProps;
2048
2760
  ngon: NGonNodeProps;
@@ -2057,7 +2769,7 @@ interface NodeTypePropsMap {
2057
2769
  document: DocumentNodeProps;
2058
2770
  }
2059
2771
  /** Union of all node prop types. */
2060
- type AnyNodeProps = RectangleNodeProps | SquareNodeProps | CircleNodeProps | EllipseNodeProps | LineNodeProps | TextNodeProps | ImageNodeProps | SplineNodeProps | PolylineNodeProps | TriangleNodeProps | NGonNodeProps | StarNodeProps | CrossNodeProps | RingNodeProps | SpiralNodeProps | GearNodeProps | ArrowNodeProps | SymbolInstanceNodeProps | GroupNodeProps | DocumentNodeProps;
2772
+ type AnyNodeProps = RectangleNodeProps | SquareNodeProps | CircleNodeProps | EllipseNodeProps | LineNodeProps | TextNodeProps | ImageNodeProps | PathNodeProps | PolylineNodeProps | TriangleNodeProps | NGonNodeProps | StarNodeProps | CrossNodeProps | RingNodeProps | SpiralNodeProps | GearNodeProps | ArrowNodeProps | SymbolInstanceNodeProps | GroupNodeProps | DocumentNodeProps;
2061
2773
 
2062
2774
  /**
2063
2775
  * @svgsketch/core — Schema migrations.
@@ -2452,6 +3164,28 @@ declare function renderToSvg(snapshot: HistorySnapshot, options?: RenderOptions)
2452
3164
  * @packageDocumentation
2453
3165
  */
2454
3166
 
3167
+ /**
3168
+ * Render a single `FilterPrimitive` to its SVG element string.
3169
+ *
3170
+ * Walks every modeled spec attribute and re-emits it. Author-preserved
3171
+ * attributes (e.g. <number-optional-number> spellings, kernelMatrix
3172
+ * whitespace) are stored as strings on the primitive and emitted verbatim,
3173
+ * so import → render produces semantically equivalent output.
3174
+ *
3175
+ * `unknownAttrs` are emitted last (alphabetised) so re-export is stable.
3176
+ * `animations` children are appended inside the element.
3177
+ */
3178
+ declare function renderFilterPrimitive(p: FilterPrimitive): string;
3179
+ /**
3180
+ * Render an `SvgPrimitiveChainFilter` as a complete `<filter>` element.
3181
+ *
3182
+ * Wrapper attributes are author-faithful: omitted ⇒ unset on the element ⇒
3183
+ * UA spec defaults apply (filterUnits=objectBoundingBox, primitiveUnits=
3184
+ * userSpaceOnUse, region -10%/-10%/120%/120%, color-interpolation-filters=
3185
+ * linearRGB). The chain is emitted in document order with no synthetic
3186
+ * `in`/`result` rewriting.
3187
+ */
3188
+ declare function renderSvgPrimitiveChainFilter(filterId: string, f: SvgPrimitiveChainFilter): string;
2455
3189
  /**
2456
3190
  * Render SVG filter primitive string(s) for a single filter.
2457
3191
  *
@@ -3415,6 +4149,68 @@ declare abstract class ShapeBuilder<T extends ShapeBuilder<T>> {
3415
4149
  cssClipPath(value: string): T;
3416
4150
  /** Set CSS mask sub-properties (`mask-image`, `mask-mode`, etc.). */
3417
4151
  cssMaskProperties(props: Record<string, string>): T;
4152
+ /**
4153
+ * SVG 2 §13.4 `vector-effect`. `non-scaling-stroke` keeps stroke width
4154
+ * constant under zoom and transforms (heavily used in CAD/diagram SVGs).
4155
+ */
4156
+ vectorEffect(value: 'none' | 'non-scaling-stroke' | 'non-scaling-size' | 'non-rotation' | 'fixed-position'): T;
4157
+ /** CSS Transforms 2 `transform-box`. */
4158
+ transformBox(value: 'view-box' | 'fill-box' | 'stroke-box' | 'content-box' | 'border-box'): T;
4159
+ /** SVG 2 §13.10 `paint-order` (e.g. `'stroke fill'`, `'fill stroke markers'`). */
4160
+ paintOrder(value: string): T;
4161
+ /** Compositing & Blending 2 `mix-blend-mode` (e.g. `'multiply'`, `'screen'`). */
4162
+ blendMode(value: string): T;
4163
+ /**
4164
+ * SVG `visibility` attribute — paint-only hiding that preserves layout.
4165
+ * Distinct from `.visible(false)` which sets `display:none`.
4166
+ */
4167
+ visibility(value: 'visible' | 'hidden' | 'collapse'): T;
4168
+ /** SVG 2 §13.6 `shape-rendering`. */
4169
+ shapeRendering(value: 'auto' | 'optimizeSpeed' | 'crispEdges' | 'geometricPrecision'): T;
4170
+ /** Color-interpolation hint for filter chains attached to this shape. */
4171
+ filterColorInterpolation(value: 'auto' | 'sRGB' | 'linearRGB'): T;
4172
+ /**
4173
+ * Suppress the shape-level `fill` so the `<use>` cascade can drive it
4174
+ * (used by symbol instances with `instancePresentation`).
4175
+ */
4176
+ inheritFill(value?: boolean): T;
4177
+ /** Suppress the shape-level `stroke` so the `<use>` cascade can drive it. */
4178
+ inheritStroke(value?: boolean): T;
4179
+ /** SVG 2 §5.8.5 `systemLanguage` conditional-processing attribute (BCP 47 tag). */
4180
+ systemLanguage(tag: string): T;
4181
+ /** SVG 2 §5.8 `requiredExtensions` conditional-processing attribute. */
4182
+ requiredExtensions(value: string): T;
4183
+ /**
4184
+ * Reference a library-registered fill (gradient or pattern) by id.
4185
+ * The `kind` parameter tells the renderer which `<defs>` shape to expect;
4186
+ * it's the discriminator on the matching `LibraryDef` entry.
4187
+ * Mutually exclusive with `.fill()`/`.fillGradient()`/`.fillPattern()`.
4188
+ */
4189
+ fillLibrary(id: string, kind?: 'linear-gradient' | 'radial-gradient' | 'pattern'): T;
4190
+ /** Reference a library-registered stroke (gradient or pattern) by id. */
4191
+ strokeLibrary(id: string, kind?: 'linear-gradient' | 'radial-gradient' | 'pattern'): T;
4192
+ /**
4193
+ * Reference one or more library-registered filters by id. The chain is
4194
+ * composed in order, then merged with any inline `.filter()`/`.dropShadow()`/etc.
4195
+ */
4196
+ filterLibrary(...ids: string[]): T;
4197
+ /**
4198
+ * Reference a library-registered marker for the start vertex.
4199
+ * Distinct from the `Line`/`Path` `.markerStart()` preset accessors —
4200
+ * those set the `startEndpoint` preset, this points at a library def id.
4201
+ */
4202
+ markerStartRef(id: string): T;
4203
+ /** Reference a library-registered marker for intermediate vertices. */
4204
+ markerMidRef(id: string): T;
4205
+ /** Reference a library-registered marker for the end vertex. */
4206
+ markerEndRef(id: string): T;
4207
+ /**
4208
+ * Bind a shape property to a template variable name. The variable must be
4209
+ * registered on the document via `Document.defineVariable(...)`. At export
4210
+ * time the property's serialized value is replaced by `{{varName}}`, which
4211
+ * `Document.toSVG({ variables })` then substitutes.
4212
+ */
4213
+ bind(propertyName: string, variableName: string): T;
3418
4214
  /** Set shape metadata (name, title, description, etc). */
3419
4215
  metadata(meta: Partial<ShapeMetadata>): T;
3420
4216
  /** Assign this shape to a group. */
@@ -3538,6 +4334,26 @@ declare class Text extends ShapeBuilder<Text> {
3538
4334
  shapePadding(value: number): Text;
3539
4335
  /** Set rich text data for per-segment styling. */
3540
4336
  richTextData(data: RichTextData): Text;
4337
+ /**
4338
+ * Toggle rich-text rendering. When `true`, `richTextData` drives output and
4339
+ * the plain `text` field is treated as a fallback. When `false` (default),
4340
+ * the plain `text` field is rendered.
4341
+ */
4342
+ useRichText(flag?: boolean): Text;
4343
+ /**
4344
+ * Set per-line position overrides. Used when imported `<tspan>` runs
4345
+ * carried explicit `x`/`y`/`dx`/`dy` lists that the editor must round-trip.
4346
+ */
4347
+ linePositions(positions: {
4348
+ x?: number | null;
4349
+ y?: number | null;
4350
+ dx?: number;
4351
+ dy?: number;
4352
+ }[]): Text;
4353
+ /** SVG `textLength` attribute (target advance width). */
4354
+ textLength(value: number): Text;
4355
+ /** SVG `lengthAdjust` attribute (`spacing` or `spacingAndGlyphs`). */
4356
+ lengthAdjust(value: 'spacing' | 'spacingAndGlyphs'): Text;
3541
4357
  }
3542
4358
  declare abstract class PolygonShapeBuilder<T extends PolygonShapeBuilder<T>> extends ShapeBuilder<T> {
3543
4359
  constructor(type: SerializedShape['type'], cx: number, cy: number, radius: number);
@@ -3600,26 +4416,195 @@ declare class Arrow extends PolygonShapeBuilder<Arrow> {
3600
4416
  /** Set the arrow shaft width as a percent (0–100). */
3601
4417
  shaftWidth(percent: number): Arrow;
3602
4418
  }
3603
- declare class Spline extends ShapeBuilder<Spline> {
3604
- constructor(points?: (Point | SplinePoint)[]);
4419
+ declare class Heart extends PolygonShapeBuilder<Heart> {
4420
+ constructor(cx: number, cy: number, radius: number);
4421
+ /** Set the lobe radius as a percent of the bounding circle (30–70). */
4422
+ lobeRadius(percent: number): Heart;
4423
+ /** Set the cleft (top notch) depth as a percent (10–50). */
4424
+ cleftDepth(percent: number): Heart;
4425
+ }
4426
+ declare class Lightning extends PolygonShapeBuilder<Lightning> {
4427
+ constructor(cx: number, cy: number, radius: number);
4428
+ /** Set the number of zigzag bend segments. */
4429
+ segments(n: number): Lightning;
4430
+ /** Set the horizontal sway as a percent (10–80). */
4431
+ jaggedness(percent: number): Lightning;
4432
+ /** Set the bolt ribbon thickness as a percent (10–60). */
4433
+ thickness(percent: number): Lightning;
4434
+ }
4435
+ declare class Cloud extends PolygonShapeBuilder<Cloud> {
4436
+ constructor(cx: number, cy: number, radius: number);
4437
+ /** Set the number of bumps around the cloud silhouette. */
4438
+ bumps(n: number): Cloud;
4439
+ /** Set the puffiness (bump radius) as a percent. */
4440
+ puffiness(percent: number): Cloud;
4441
+ }
4442
+ declare class SpeechBubble extends PolygonShapeBuilder<SpeechBubble> {
4443
+ constructor(cx: number, cy: number, radius: number);
4444
+ /** Set the tail angle in degrees (0 = right, 90 = down, etc.). */
4445
+ tailAngle(degrees: number): SpeechBubble;
4446
+ /** Set the tail length as a percent of the bounding radius. */
4447
+ tailLength(percent: number): SpeechBubble;
4448
+ /** Set the tail base width as a percent of the bounding radius. */
4449
+ tailWidth(percent: number): SpeechBubble;
4450
+ }
4451
+ /**
4452
+ * Mixin base for shape builders whose `state.children` is an inline array
4453
+ * of `SerializedShape`. Hyperlink, Switch, Container, NestedSvg all extend
4454
+ * this. The `.add()` method accepts another `ShapeBuilder` (its `.build()`
4455
+ * is called immediately) or a raw `SerializedShape`.
4456
+ */
4457
+ declare abstract class ContainerShapeBuilder<T extends ContainerShapeBuilder<T>> extends ShapeBuilder<T> {
4458
+ /** Append a shape (builder or pre-built SerializedShape) as a child. */
4459
+ add(shape: ShapeBuilder<any> | SerializedShape): T;
4460
+ /** Append multiple children in a single call. */
4461
+ addAll(...shapes: (ShapeBuilder<any> | SerializedShape)[]): T;
4462
+ /** Replace the children array wholesale. */
4463
+ children(shapes: (ShapeBuilder<any> | SerializedShape)[]): T;
4464
+ }
4465
+ declare class Hyperlink extends ContainerShapeBuilder<Hyperlink> {
4466
+ constructor(href?: string);
4467
+ /** Set the link target URL (`href` attribute). */
4468
+ href(value: string): Hyperlink;
4469
+ /** Set the legacy `xlink:href` (kept for round-trip with SVG 1.1 sources). */
4470
+ hrefXlink(value: string): Hyperlink;
4471
+ /** Set the link target window — `'_self'`, `'_blank'`, etc. */
4472
+ target(value: '_self' | '_blank' | '_parent' | '_top' | string): Hyperlink;
4473
+ /** Set the `download` attribute (file name hint for download links). */
4474
+ download(value: string): Hyperlink;
4475
+ /** Set the `rel` attribute (e.g. `'noopener noreferrer'`). */
4476
+ rel(value: string): Hyperlink;
4477
+ /** Set the `ping` attribute (space-separated URLs notified on click). */
4478
+ ping(value: string): Hyperlink;
4479
+ /** Set the `hreflang` attribute. */
4480
+ hreflang(value: string): Hyperlink;
4481
+ /** Set the `type` attribute (MIME type hint for the destination). */
4482
+ type(value: string): Hyperlink;
4483
+ /** Set the `referrerpolicy` attribute. */
4484
+ referrerPolicy(value: string): Hyperlink;
4485
+ }
4486
+ declare class Switch extends ContainerShapeBuilder<Switch> {
4487
+ constructor();
4488
+ }
4489
+ /**
4490
+ * Generic container shape: emits `<g>` wrapping inline children. Distinct
4491
+ * from the editor's `Group` system, which uses flat-with-`groupId` storage —
4492
+ * use this when programmatically composing a document where you want the
4493
+ * children persisted under their parent rather than in the flat shapes array.
4494
+ */
4495
+ declare class Container extends ContainerShapeBuilder<Container> {
4496
+ constructor();
4497
+ }
4498
+ declare class View extends ShapeBuilder<View> {
4499
+ constructor(viewBox?: {
4500
+ x: number;
4501
+ y: number;
4502
+ width: number;
4503
+ height: number;
4504
+ });
4505
+ /** Set the viewBox (x, y, width, height) the view exposes. */
4506
+ viewBox(x: number, y: number, width: number, height: number): View;
4507
+ /** Human-readable name (round-tripped as `data-view-name`). */
4508
+ name(value: string): View;
4509
+ /** SVG 2 `preserveAspectRatio` (e.g. `'xMidYMid meet'`). */
4510
+ preserveAspectRatio(value: string): View;
4511
+ /** Legacy `zoomAndPan` attribute (`'disable' | 'magnify'`). */
4512
+ zoomAndPan(value: 'disable' | 'magnify'): View;
4513
+ /** SVG `viewTarget` attribute. */
4514
+ viewTarget(value: string): View;
4515
+ /** Mark this view as the canonical "home" view of the document. */
4516
+ asHome(value?: boolean): View;
4517
+ }
4518
+ declare class NestedSvg extends ContainerShapeBuilder<NestedSvg> {
4519
+ constructor(x?: number, y?: number, width?: number, height?: number);
4520
+ /** Set the position on the parent canvas. */
4521
+ position(x: number, y: number): NestedSvg;
4522
+ /** Set width and height on the parent canvas. */
4523
+ size(width: number, height: number): NestedSvg;
4524
+ /** Set the `viewBox` (the inner coordinate system). */
4525
+ viewBox(x: number, y: number, width: number, height: number): NestedSvg;
4526
+ /** SVG 2 `preserveAspectRatio` for the nested viewport. */
4527
+ preserveAspectRatio(value: string): NestedSvg;
4528
+ /** Mark this as the root SVG element (rare; typically only one per document). */
4529
+ asRoot(value?: boolean): NestedSvg;
4530
+ }
4531
+ declare class ShapeReference extends ShapeBuilder<ShapeReference> {
4532
+ constructor(targetShapeId?: string);
4533
+ /** ID of the shape this reference clones. */
4534
+ target(shapeId: string): ShapeReference;
4535
+ /** Offset from the source's reference point (mapped to `<use x>`/`<use y>`). */
4536
+ offset(x: number, y: number): ShapeReference;
4537
+ /** Override the rendered width/height (mapped to `<use width>`/`<use height>`). */
4538
+ size(width: number, height: number): ShapeReference;
4539
+ }
4540
+ declare abstract class MediaShapeBuilder<T extends MediaShapeBuilder<T>> extends ShapeBuilder<T> {
4541
+ /** Position on the canvas. */
4542
+ position(x: number, y: number): T;
4543
+ /** Bounding-box width/height of the foreignObject wrapper. */
4544
+ size(width: number, height: number): T;
4545
+ /** Source URL or data URI. */
4546
+ src(href: string): T;
4547
+ /** MIME type hint (e.g. `'video/mp4'`, `'audio/mpeg'`). */
4548
+ mimeType(value: string): T;
4549
+ /** Source duration in seconds (set by the editor on `loadedmetadata`). */
4550
+ naturalDuration(seconds: number): T;
4551
+ /** Timeline offset where playback starts. */
4552
+ begin(seconds: number): T;
4553
+ /** Source-relative in/out trim (seconds). */
4554
+ trim(start: number, end: number): T;
4555
+ volume(value: number): T;
4556
+ muted(value?: boolean): T;
4557
+ loop(value?: boolean): T;
4558
+ playbackRate(value: number): T;
4559
+ /** Convenience volume ramps applied live by the sync controller. */
4560
+ fade(inDuration: number, outDuration: number): T;
4561
+ /** SVG conditional-processing `systemLanguage` (BCP 47 tag). */
4562
+ language(tag: string): T;
4563
+ }
4564
+ declare class Video extends MediaShapeBuilder<Video> {
4565
+ constructor(href?: string);
4566
+ /** First-frame thumbnail URL or data URI. */
4567
+ poster(href: string): Video;
4568
+ /** Crop window in source-pixel space. */
4569
+ sourceRect(rect: {
4570
+ x: number;
4571
+ y: number;
4572
+ width: number;
4573
+ height: number;
4574
+ }): Video;
4575
+ }
4576
+ declare class Audio extends MediaShapeBuilder<Audio> {
4577
+ constructor(href?: string);
4578
+ }
4579
+ declare class Path extends ShapeBuilder<Path> {
4580
+ constructor(points?: (Point | PathPoint)[]);
3605
4581
  /** Set the spline points. */
3606
- points(pts: (Point | SplinePoint)[]): Spline;
4582
+ points(pts: (Point | PathPoint)[]): Path;
3607
4583
  /** Add a point to the spline. */
3608
- addPoint(x: number, y: number): Spline;
4584
+ addPoint(x: number, y: number): Path;
3609
4585
  /** Set the curve type. */
3610
- curveType(type: SplineCurveType): Spline;
4586
+ curveType(type: PathCurveType): Path;
3611
4587
  /** Set whether the spline is closed. */
3612
- closed(value?: boolean): Spline;
4588
+ closed(value?: boolean): Path;
3613
4589
  /** Set the tension for Catmull-Rom curves (0–1). */
3614
- tension(value: number): Spline;
4590
+ tension(value: number): Path;
3615
4591
  /** Set arc params for ARC curve type. */
3616
- arcParams(params: ArcParams$1[]): Spline;
4592
+ arcParams(params: ArcParams$1[]): Path;
3617
4593
  /** Set the start endpoint marker. */
3618
- markerStart(style: EndpointStyle): Spline;
4594
+ markerStart(style: EndpointStyle): Path;
3619
4595
  /** Set the end endpoint marker. */
3620
- markerEnd(style: EndpointStyle): Spline;
4596
+ markerEnd(style: EndpointStyle): Path;
3621
4597
  /** Convenience: set both markers. */
3622
- markers(start: EndpointStyle, end: EndpointStyle): Spline;
4598
+ markers(start: EndpointStyle, end: EndpointStyle): Path;
4599
+ /**
4600
+ * Resolve this path to its SVG `d` attribute string. Useful for path-morph
4601
+ * animations: the `d` track property accepts a `d` string per keyframe, and
4602
+ * SMIL interpolates between matching command sequences character-by-character.
4603
+ *
4604
+ * The output uses the same geometry pipeline as `Document.toSVG()`, so the
4605
+ * animated values match the static render of the same path exactly.
4606
+ */
4607
+ toD(): string;
3623
4608
  }
3624
4609
  declare class Polyline extends ShapeBuilder<Polyline> {
3625
4610
  constructor(points?: Point[]);
@@ -3746,7 +4731,7 @@ declare class Track {
3746
4731
  *
3747
4732
  * @example
3748
4733
  * ```ts
3749
- * const curve = new Spline(...).id('curve');
4734
+ * const curve = new Path(...).id('curve');
3750
4735
  * doc.add(curve);
3751
4736
  *
3752
4737
  * const track = new Track('rect-1', 'pathMotion')
@@ -3945,6 +4930,16 @@ declare class Document {
3945
4930
  viewBox?: string;
3946
4931
  thumbnail?: string;
3947
4932
  groups?: SerializedGroup[];
4933
+ /** SVG-element form: `'symbol'` (the default) or `'group'` (`<defs><g>`). */
4934
+ defKind?: 'symbol' | 'group';
4935
+ /** Wrapper attributes from a source `<g id>` def root, when `defKind === 'group'`. */
4936
+ wrapperAttrs?: Record<string, string>;
4937
+ /** Named variant axes, e.g. `[{ name: 'color', values: ['red', 'blue'] }]`. */
4938
+ variantAxes?: SerializedVariantAxis[];
4939
+ /** Variant shape arrays keyed by canonical `axis=val,…` string. */
4940
+ variants?: Record<string, SerializedShape[]>;
4941
+ /** Per-variant thumbnails keyed by canonical variant string. */
4942
+ variantThumbnails?: Record<string, string>;
3948
4943
  }): string;
3949
4944
  /**
3950
4945
  * Place a symbol instance on the canvas.
@@ -3952,14 +4947,88 @@ declare class Document {
3952
4947
  * @param symbolId - The ID of the symbol definition.
3953
4948
  * @param x - X position.
3954
4949
  * @param y - Y position.
3955
- * @param width - Instance width (optional).
3956
- * @param height - Instance height (optional).
4950
+ * @param widthOrOptions - Instance width, or an options bag.
4951
+ * @param height - Instance height (only when `widthOrOptions` is a number).
3957
4952
  */
3958
- placeSymbolInstance(symbolId: string, x: number, y: number, width?: number, height?: number): Document;
4953
+ placeSymbolInstance(symbolId: string, x: number, y: number, widthOrOptions?: number | {
4954
+ width?: number;
4955
+ height?: number;
4956
+ /** Selected variant key, e.g. `'color=red,size=large'`. */
4957
+ variantKey?: string;
4958
+ /** Per-inner-shape state patches applied to this instance only. */
4959
+ symbolOverrides?: Record<string, Partial<SerializedShape['state']>>;
4960
+ /** Per-instance attribute cascade applied to the `<use>` element (SVG 2 §5.5.4). */
4961
+ instancePresentation?: Record<string, string>;
4962
+ }, height?: number): Document;
3959
4963
  /** Remove a symbol definition by ID. */
3960
4964
  removeSymbol(id: string): boolean;
3961
4965
  /** Get all symbol definitions. */
3962
4966
  get symbols(): readonly SerializedSymbolDef[];
4967
+ /**
4968
+ * Register a marker definition. Shapes can then reference the marker by
4969
+ * id via `.markerStartRef(id)` / `.markerMidRef(id)` / `.markerEndRef(id)`.
4970
+ *
4971
+ * @returns The marker library def id.
4972
+ */
4973
+ defineMarker(name: string, shapes: (ShapeBuilder<any> | SerializedShape)[], options?: {
4974
+ viewBox?: string;
4975
+ refX?: number;
4976
+ refY?: number;
4977
+ markerWidth?: number;
4978
+ markerHeight?: number;
4979
+ markerUnits?: 'strokeWidth' | 'userSpaceOnUse';
4980
+ orient?: 'auto' | 'auto-start-reverse' | number;
4981
+ thumbnail?: string;
4982
+ groups?: SerializedGroup[];
4983
+ }): string;
4984
+ /**
4985
+ * Register a reusable filter chain. Shapes reference it via `.filterLibrary(id)`.
4986
+ *
4987
+ * @returns The filter library def id.
4988
+ */
4989
+ defineFilter(name: string, filters: ShapeFilter[], options?: {
4990
+ colorInterpolation?: 'auto' | 'sRGB' | 'linearRGB';
4991
+ filterUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
4992
+ primitiveUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
4993
+ x?: string;
4994
+ y?: string;
4995
+ width?: string;
4996
+ height?: string;
4997
+ thumbnail?: string;
4998
+ }): string;
4999
+ /**
5000
+ * Register a reusable linear gradient. Shapes reference it via `.fillLibrary(id)`.
5001
+ *
5002
+ * @returns The library def id.
5003
+ */
5004
+ defineLinearGradientLibrary(name: string, gradient: LinearGradientBuilder | LinearGradient, options?: {
5005
+ thumbnail?: string;
5006
+ }): string;
5007
+ /**
5008
+ * Register a reusable radial gradient. Shapes reference it via `.fillLibrary(id, 'radial-gradient')`.
5009
+ *
5010
+ * @returns The library def id.
5011
+ */
5012
+ defineRadialGradientLibrary(name: string, gradient: RadialGradientBuilder | RadialGradient, options?: {
5013
+ thumbnail?: string;
5014
+ }): string;
5015
+ /**
5016
+ * Register a reusable pattern. Shapes reference it via `.fillLibrary(id, 'pattern')`.
5017
+ *
5018
+ * @returns The library def id.
5019
+ */
5020
+ definePatternLibrary(name: string, pattern: PatternBuilder | PatternFill, options?: {
5021
+ thumbnail?: string;
5022
+ }): string;
5023
+ /** Remove a library def (marker / filter / gradient / pattern) by id. */
5024
+ removeLibraryDef(id: string): boolean;
5025
+ /** Read-only view of every registered library def. */
5026
+ get library(): readonly LibraryDef[];
5027
+ /**
5028
+ * Push a library def, lazily initializing `_snapshot.library` and
5029
+ * deduplicating by id (last write wins).
5030
+ */
5031
+ private _pushLibraryDef;
3963
5032
  /**
3964
5033
  * Add a clip group.
3965
5034
  *
@@ -4178,4 +5247,4 @@ declare class Document {
4178
5247
  private _ensureMetadata;
4179
5248
  }
4180
5249
 
4181
- export { type AnimatablePropertyDescriptor, type AnimationKeyframe, type AnimationTimeline, type AnimationTrack, type AnimationTrigger, type AnimationTriggerType, type AnyNodeProps, type ArcParams$1 as ArcParams, type AriaRole, Arrow, type ArrowNodeProps, BUILTIN_MARKER_ID_MAP, type BaseFilter, type BlackAndWhiteFilter, type BlurQuality, type BrightnessFilter, CURRENT_SCHEMA_VERSION, type ChannelPainterFilter, Circle, type CircleNodeProps, type CodeFormat, type CodegenOptions, type CommonNodeProps, type ConnectionDirection, type ConnectionPoint, type ContouringDiscreteFilter, type ContouringTableFilter, type ContrastFilter, type CornerShapeValue, type CreateDocumentOptions, type CreateShapeOptions, Cross, type CrossNodeProps, type CrumpledPlasticFilter, type CustomPatternDef, type CycleBehavior, DEFAULT_COORDINATE_PRECISION, type DiffuseLightingFilter, Document, type DocumentMetadata, type DocumentNodeProps, type DocumentOptions, type DocumentScript, type DocumentStyle, type DropShadowFilter, type DuotoneFilter, EASING_CURVES, EVENT_TRIGGER_OPTIONS, EasingType, Ellipse, type EllipseNodeProps, type EmbossFilter, type ExtractedVariables, type FillType, type FilmGrainFilter, type FilterLibraryDef, type FilterType, type GaussianBlurFilter, Gear, type GearNodeProps, type GlowFilter, type GouacheFilter, type GradientDefinition, type GradientSpreadMethod, type GradientStop, type GradientUnits, type GrayscaleFilter, type GroupNodeProps, type Guide, type HistorySnapshot, type HueRotateFilter, type ImageAttribution, type ImageNodeProps, ImageShape, type InkBlotFilter, type InnerGlowFilter, type InnerShadowFilter, type InvertFilter, LIBRARY_EMIT_ORDER, type LibraryDef, type LibraryDefBase, type LibraryDefOfKind, type LibraryKind, type LicenseType, type LightSource, Line, type LineEndpointValue, type LineNodeProps, type LinearEasingPoint, type LinearGradient, LinearGradientBuilder, type LinearGradientLibraryDef, type LinkTarget, MARKER_HEIGHT, MARKER_VIEWBOX, MARKER_WIDTH, MAX_COORDINATE_PRECISION, MIGRATIONS, type MarkerDescriptor, type MarkerLibraryDef, type Measurement, type Migration, type MorphologyFilter, type MorphologyOperator, type MotionBlurFilter, NGon, type NGonNodeProps, type NodeTypePropsMap, type NoiseFilter, type OpacityFilter, type OutlineFilter, type OutlinePosition, type ParseOptions, PatternBuilder, type PatternElement, type PatternFill, type PatternLibraryDef, type PatternParams, type PatternSvgContentResult, type PatternType, type PixelateFilter, type Point, type PointLightFilter, type PolygonBaseNodeProps, Polyline, type PolylineNodeProps, type RadialGradient, RadialGradientBuilder, type RadialGradientLibraryDef, type RawSvgFilter, Rectangle, type RectangleNodeProps, type RenderOptions, type RichTextData, type RichTextLine, type RichTextSegment, type RichTextSegmentStyle, type RiddledFilter, Ring, type RingNodeProps, type RoundEdgesFilter, type SaturateFilter, type SegmentCurveType, type SepiaFilter, type SerializedAnimationTimeline, type SerializedClipMaskGroup, type SerializedGroup, type SerializedMarkerDef, type SerializedShape, type SerializedSymbolDef, type SerializedVariantAxis, type SerializedViewbox, ShapeBuilder, type ShapeFilter, type ShapeMetadata, type SharpenFilter, type SpecularLightingFilter, Spiral, type SpiralNodeProps, Spline, SplineCurveType, type SplineNodeProps, type SplinePoint, SplinePointType, type SpotLightFilter, Square, type SquareNodeProps, Star, type StarNodeProps, type StepPosition, type StepsParams, type StringifyOptions, type StrokeType, type SymbolInstanceNodeProps, type SymbolLibraryDef, type TemplateVariable, type TemplateVariableSource, type TemplateVariableType, Text, type TextNodeProps, Timeline, Track, Triangle, type TriangleNodeProps, type ValidationError, type ValidationResult, type VariableMap, type Viewbox, type WarpFilter, type WarpType, type WatercolorFilter, type XrayFilter, collectReferencedLibraryIds, computeArrowVertices, computeCloudPath, computeCrossVertices, computeDashArray, computeGearPath, computeGearVertices, computeHeartPath, computeLightningVertices, computePolygonVertices, computeRectanglePath, computeRingPath, computeSpeechBubbleVertices, computeSpiralPath, computeSplinePath, computeStarVertices, createDocument, createShape, createViewbox, escXml, extractVariables, filterAttr, generateCode, generateCssCode, generateD3Code, generateId, generatePatternSvgContent, generateReactCode, generateSvgCode, generateVueCode, getBuiltInMarkerDefs, getEasingCubicBezier, getEffectivePrecision, getMarkerDescriptors, getPatternElements, linearGradient, migrateSnapshot, parseDocument, parseVariableArgs, pattern, radialGradient, renderAnimationElements, renderBuiltinMarkerDefs, renderCircle, renderEllipse, renderFilterDefs, renderFilterLibraryDef, renderFilterPrimitivesForType, renderImage, renderLibraryDef, renderLibraryDefs, renderLine, renderLinearGradientLibraryDef, renderMarkerLibraryDef, renderPatternLibraryDef, renderPolygonShape, renderPolyline, renderRadialGradientLibraryDef, renderRectangle, renderReferencedLibraryDefs, renderShape, renderSpline, renderSymbolLibraryDef, renderText, renderToSvg, roundCoord, roundNumberString, roundSerializedShape, roundSnapshot, stringifyDocument, substituteString, substituteVariables, validateSnapshot, verticesToPath };
5250
+ export { type AnimatablePropertyDescriptor, type AnimationKeyframe, type AnimationTimeline, type AnimationTrack, type AnimationTrigger, type AnimationTriggerType, type AnyNodeProps, type ArcParams$1 as ArcParams, type AriaRole, Arrow, type ArrowNodeProps, Audio, BUILTIN_MARKER_ID_MAP, type BaseFilter, type BaseFilterPrimitive, type BlackAndWhiteFilter, type BlurQuality, type BrightnessFilter, CURRENT_SCHEMA_VERSION, type ChannelPainterFilter, Circle, type CircleNodeProps, Cloud, type CodeFormat, type CodegenOptions, type CommonNodeProps, type ConnectionDirection, type ConnectionPoint, Container, ContainerShapeBuilder, type ContouringDiscreteFilter, type ContouringTableFilter, type ContrastFilter, type CornerShapeValue, type CreateDocumentOptions, type CreateShapeOptions, Cross, type CrossNodeProps, type CrumpledPlasticFilter, type CustomPatternDef, type CycleBehavior, DEFAULT_COORDINATE_PRECISION, type DiffuseLightingFilter, Document, type DocumentMetadata, type DocumentNodeProps, type DocumentOptions, type DocumentScript, type DocumentStyle, type DropShadowFilter, type DuotoneFilter, EASING_CURVES, EVENT_TRIGGER_OPTIONS, EasingType, Ellipse, type EllipseNodeProps, type EmbossFilter, type ExtractedVariables, type FeBlendPrimitive, type FeColorMatrixPrimitive, type FeComponentTransferPrimitive, type FeCompositePrimitive, type FeConvolveMatrixPrimitive, type FeDiffuseLightingPrimitive, type FeDisplacementMapPrimitive, type FeDropShadowPrimitive, type FeFloodPrimitive, type FeGaussianBlurPrimitive, type FeImagePrimitive, type FeMergePrimitive, type FeMorphologyPrimitive, type FeOffsetPrimitive, type FeSpecularLightingPrimitive, type FeTilePrimitive, type FeTurbulencePrimitive, type FillType, type FilmGrainFilter, type FilterBlendMode, type FilterLibraryDef, type FilterLightSource, type FilterPrimitive, type FilterPrimitiveType, type FilterType, type GaussianBlurFilter, Gear, type GearNodeProps, type GlowFilter, type GouacheFilter, type GradientDefinition, type GradientSpreadMethod, type GradientStop, type GradientUnits, type GrayscaleFilter, type GroupNodeProps, type Guide, Heart, type HistorySnapshot, type HueRotateFilter, Hyperlink, type ImageAttribution, type ImageNodeProps, ImageShape, type InkBlotFilter, type InnerGlowFilter, type InnerShadowFilter, type InvertFilter, LIBRARY_EMIT_ORDER, type LibraryDef, type LibraryDefBase, type LibraryDefOfKind, type LibraryKind, type LicenseType, type LightSource, Lightning, Line, type LineEndpointValue, type LineNodeProps, type LinearEasingPoint, type LinearGradient, LinearGradientBuilder, type LinearGradientLibraryDef, type LinkTarget, MARKER_HEIGHT, MARKER_VIEWBOX, MARKER_WIDTH, MAX_COORDINATE_PRECISION, MIGRATIONS, type MarkerDescriptor, type MarkerLibraryDef, type Measurement, type Migration, type MorphologyFilter, type MorphologyOperator, type MotionBlurFilter, NGon, type NGonNodeProps, NestedSvg, type NodeTypePropsMap, type NoiseFilter, type OpacityFilter, type OutlineFilter, type OutlinePosition, type ParseOptions, Path, PathCurveType, type PathNodeProps, type PathPoint, PathPointType, PatternBuilder, type PatternElement, type PatternFill, type PatternLibraryDef, type PatternParams, type PatternSvgContentResult, type PatternType, type PixelateFilter, type Point, type PointLightFilter, type PolygonBaseNodeProps, Polyline, type PolylineNodeProps, type RadialGradient, RadialGradientBuilder, type RadialGradientLibraryDef, type RawSvgFilter, Rectangle, type RectangleNodeProps, type RenderOptions, type RichTextData, type RichTextLine, type RichTextSegment, type RichTextSegmentStyle, type RiddledFilter, Ring, type RingNodeProps, type RoundEdgesFilter, type SaturateFilter, type SegmentCurveType, type SepiaFilter, type SerializedAnimationTimeline, type SerializedClipMaskGroup, type SerializedGroup, type SerializedMarkerDef, type SerializedShape, type SerializedSymbolDef, type SerializedVariantAxis, type SerializedViewbox, ShapeBuilder, type ShapeFilter, type ShapeMetadata, ShapeReference, type SharpenFilter, type SpecularLightingFilter, SpeechBubble, Spiral, type SpiralNodeProps, type SpotLightFilter, Square, type SquareNodeProps, Star, type StarNodeProps, type StepPosition, type StepsParams, type StringifyOptions, type StrokeType, type SvgPrimitiveChainFilter, Switch, type SymbolInstanceNodeProps, type SymbolLibraryDef, type TemplateVariable, type TemplateVariableMode, type TemplateVariableSource, type TemplateVariableType, Text, type TextNodeProps, Timeline, Track, type TransferFunc, Triangle, type TriangleNodeProps, type ValidationError, type ValidationResult, type VariableMap, Video, View, type Viewbox, type WarpFilter, type WarpType, type WatercolorFilter, type XrayFilter, collectReferencedLibraryIds, computeArrowVertices, computeCloudPath, computeCrossVertices, computeDashArray, computeGearPath, computeGearVertices, computeHeartPath, computeLightningVertices, computePolygonVertices, computeRectanglePath, computeRingPath, computeSpeechBubbleVertices, computeSpiralPath, computeSplinePath, computeStarVertices, createDocument, createShape, createViewbox, defaultVariableMode, escXml, extractVariables, filterAttr, generateCode, generateCssCode, generateD3Code, generateId, generatePatternSvgContent, generateReactCode, generateSvgCode, generateVueCode, getBuiltInMarkerDefs, getEasingCubicBezier, getEffectivePrecision, getMarkerDescriptors, getPatternElements, linearGradient, migrateSnapshot, parseDocument, parseVariableArgs, pattern, radialGradient, renderAnimationElements, renderBuiltinMarkerDefs, renderCircle, renderEllipse, renderFilterDefs, renderFilterLibraryDef, renderFilterPrimitive, renderFilterPrimitivesForType, renderImage, renderLibraryDef, renderLibraryDefs, renderLine, renderLinearGradientLibraryDef, renderMarkerLibraryDef, renderPatternLibraryDef, renderPolygonShape, renderPolyline, renderRadialGradientLibraryDef, renderRectangle, renderReferencedLibraryDefs, renderShape, renderSpline, renderSvgPrimitiveChainFilter, renderSymbolLibraryDef, renderText, renderToSvg, roundCoord, roundNumberString, roundSerializedShape, roundSnapshot, stringifyDocument, substituteString, substituteVariables, validateSnapshot, verticesToPath };