@svgsketch/core 0.6.0 → 1.0.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
@@ -136,6 +136,32 @@ interface AnimationTrack {
136
136
  locked: boolean;
137
137
  /** SVG path data for motion-path animation (property should be 'pathMotion'). */
138
138
  motionPath?: string;
139
+ /**
140
+ * When set, the motion path was authored as a reference to another shape
141
+ * (SVG `<mpath href="#shapeId"/>`). `motionPath` still holds the resolved
142
+ * path data string (kept in sync with the referenced shape's geometry) so
143
+ * the runtime renderer doesn't need to dereference; the `mode` field
144
+ * controls how that data is interpreted and whether export can round-trip
145
+ * the reference as `<mpath>`.
146
+ *
147
+ * - `'trackShape'` — motionPath is displacement-relative to the animated
148
+ * element's center, so the overlay and playback render on top of the
149
+ * referenced shape's absolute canvas position ("follow this shape").
150
+ * Exports as inline `path=` because `<mpath>` would double-offset.
151
+ * - `'curveTemplate'` — motionPath is normalized so `M 0,0` is the
152
+ * animation's starting displacement ("trace this curve from wherever
153
+ * the element is"). Exports spec-correctly as `<mpath href>` since
154
+ * the referenced shape's `d` (normalized to origin) matches the stored
155
+ * motionPath byte-for-byte, enabling reuse across animations.
156
+ *
157
+ * Missing `mode` (legacy data) defaults to `'trackShape'` for back-compat.
158
+ *
159
+ * @see https://svgwg.org/specs/animations/#MPathElement
160
+ */
161
+ motionPathRef?: {
162
+ shapeId: string;
163
+ mode?: 'trackShape' | 'curveTemplate';
164
+ };
139
165
  /** Trigger to begin the animation (defaults to '0s'). */
140
166
  beginTrigger?: AnimationTrigger;
141
167
  /** Trigger to end the animation. */
@@ -206,6 +232,12 @@ interface SerializedAnimationTimeline {
206
232
  locked?: boolean;
207
233
  motionPath?: string;
208
234
  motionPathMatrix?: number[];
235
+ /** See `AnimationTrack.motionPathRef`. Persists the authoring reference to
236
+ * another shape's geometry so a round-trip re-emits `<mpath href>`. */
237
+ motionPathRef?: {
238
+ shapeId: string;
239
+ mode?: 'trackShape' | 'curveTemplate';
240
+ };
209
241
  beginTrigger?: AnimationTrigger;
210
242
  endTrigger?: AnimationTrigger;
211
243
  cycleDuration?: number;
@@ -237,6 +269,43 @@ interface SerializedAnimationTimeline {
237
269
  x: number;
238
270
  y: number;
239
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;
240
309
  keyframes: {
241
310
  time: number;
242
311
  value: number | string;
@@ -280,7 +349,7 @@ interface AnimatablePropertyDescriptor {
280
349
  * Only enums referenced by SerializedShape or HistorySnapshot live here.
281
350
  * Editor-only enums (Mode, ControlPointPosition, etc.) stay in the editor.
282
351
  */
283
- declare enum SplineCurveType {
352
+ declare enum PathCurveType {
284
353
  LINEAR = "linear",
285
354
  QUADRATIC = "quadratic",
286
355
  CUBIC = "cubic",
@@ -289,7 +358,7 @@ declare enum SplineCurveType {
289
358
  BASIS = "basis",
290
359
  MIXED = "mixed"
291
360
  }
292
- declare enum SplinePointType {
361
+ declare enum PathPointType {
293
362
  SMOOTH = "smooth",
294
363
  CORNER = "corner",
295
364
  SYMMETRIC = "symmetric"
@@ -387,6 +456,14 @@ interface RadialGradient {
387
456
  r: number;
388
457
  ry: number;
389
458
  rotation: number;
459
+ /**
460
+ * Focal-circle radius (SVG 2 §14.2.3.1 `fr`). When present and > 0, the
461
+ * gradient's first stop is rendered along this circle (not at a single
462
+ * focal point) — produces a "donut" radial gradient. Same coordinate
463
+ * space as `r` (i.e. governed by `gradientUnits`). Defaults to 0
464
+ * when omitted, matching the spec's initial value and pre-SVG-2 behaviour.
465
+ */
466
+ fr?: number;
390
467
  stops: GradientStop[];
391
468
  spreadMethod: GradientSpreadMethod;
392
469
  opacity: number;
@@ -531,7 +608,7 @@ interface CustomPatternDef {
531
608
  /** Tile height in userSpaceOnUse coordinates. */
532
609
  height: number;
533
610
  }
534
- 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';
611
+ 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';
535
612
  type BlurQuality = 'normal' | 'high';
536
613
  interface BaseFilter {
537
614
  id: string;
@@ -799,14 +876,265 @@ interface RawSvgFilter extends BaseFilter {
799
876
  floodOpacity?: string;
800
877
  lightingColor?: string;
801
878
  }
802
- 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;
803
- type SegmentCurveType = 'LINEAR' | 'CUBIC' | 'QUADRATIC' | 'ARC';
804
- interface SplinePoint {
879
+ 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;
880
+ /** Common attributes on every filter primitive (FE1 §7.2). */
881
+ interface BaseFilterPrimitive {
882
+ /** Editor-only stable id; not serialized to SVG. */
883
+ id: string;
884
+ /** SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha |
885
+ * FillPaint | StrokePaint | <filter-primitive-reference>. Omitted ⇒
886
+ * defaults to previous primitive's result (or SourceGraphic if first). */
887
+ in?: string;
888
+ /** Custom result name for forward references. Omitted ⇒ implicit. */
889
+ result?: string;
890
+ /** Filter primitive subregion (FE1 §7.3). */
891
+ x?: string;
892
+ y?: string;
893
+ width?: string;
894
+ height?: string;
895
+ /** Per-primitive override of color-interpolation-filters. */
896
+ colorInterpolationFilters?: 'auto' | 'sRGB' | 'linearRGB';
897
+ /** Carry of attributes the editor doesn't model (style, class, data-*,
898
+ * unknown spec attrs). Re-emitted verbatim. Keys exclude attrs already
899
+ * modeled on this primitive. */
900
+ unknownAttrs?: Record<string, string>;
901
+ /** SMIL animation children attached to this primitive — preserved
902
+ * verbatim. Each entry is the outerHTML of an <animate>, <set>,
903
+ * <animateTransform>, or <animateMotion> element. */
904
+ animations?: string[];
905
+ }
906
+ /** Blend modes per Compositing 1 §3 + the FE1-specific extensions. */
907
+ 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';
908
+ interface FeBlendPrimitive extends BaseFilterPrimitive {
909
+ type: 'feBlend';
910
+ in2?: string;
911
+ mode?: FilterBlendMode;
912
+ /** FE1 extension — boolean attribute, presence-based. */
913
+ noComposite?: boolean;
914
+ }
915
+ interface FeColorMatrixPrimitive extends BaseFilterPrimitive {
916
+ type: 'feColorMatrix';
917
+ matrixType?: 'matrix' | 'saturate' | 'hueRotate' | 'luminanceToAlpha';
918
+ /** Verbatim attribute string so we preserve the exact author spelling
919
+ * (matrix arg counts, whitespace inside). Omitted ⇒ spec defaults
920
+ * apply (matrix=identity, saturate=1, hueRotate=0). */
921
+ values?: string;
922
+ }
923
+ type TransferFunc = {
924
+ type: 'identity';
925
+ } | {
926
+ type: 'table' | 'discrete';
927
+ tableValues: number[];
928
+ } | {
929
+ type: 'linear';
930
+ slope?: number;
931
+ intercept?: number;
932
+ } | {
933
+ type: 'gamma';
934
+ amplitude?: number;
935
+ exponent?: number;
936
+ offset?: number;
937
+ };
938
+ interface FeComponentTransferPrimitive extends BaseFilterPrimitive {
939
+ type: 'feComponentTransfer';
940
+ funcR?: TransferFunc;
941
+ funcG?: TransferFunc;
942
+ funcB?: TransferFunc;
943
+ funcA?: TransferFunc;
944
+ }
945
+ interface FeCompositePrimitive extends BaseFilterPrimitive {
946
+ type: 'feComposite';
947
+ in2?: string;
948
+ operator?: 'over' | 'in' | 'out' | 'atop' | 'xor' | 'lighter' | 'arithmetic';
949
+ k1?: number;
950
+ k2?: number;
951
+ k3?: number;
952
+ k4?: number;
953
+ }
954
+ interface FeConvolveMatrixPrimitive extends BaseFilterPrimitive {
955
+ type: 'feConvolveMatrix';
956
+ /** <number-optional-number>; preserved as authored (e.g. "3" or "3 3"). */
957
+ order?: string;
958
+ /** Space-separated kernel values, preserved as authored. */
959
+ kernelMatrix?: string;
960
+ divisor?: number;
961
+ bias?: number;
962
+ targetX?: number;
963
+ targetY?: number;
964
+ edgeMode?: 'duplicate' | 'wrap' | 'none';
965
+ /** <number-optional-number>; preserved as authored. */
966
+ kernelUnitLength?: string;
967
+ preserveAlpha?: boolean;
968
+ }
969
+ /** Light source elements (FE1 §16) — never appear at <filter> top level,
970
+ * only as children of feDiffuseLighting/feSpecularLighting. */
971
+ type FilterLightSource = {
972
+ kind: 'feDistantLight';
973
+ azimuth?: number;
974
+ elevation?: number;
975
+ } | {
976
+ kind: 'fePointLight';
977
+ x?: number;
978
+ y?: number;
979
+ z?: number;
980
+ } | {
981
+ kind: 'feSpotLight';
982
+ x?: number;
983
+ y?: number;
984
+ z?: number;
985
+ pointsAtX?: number;
986
+ pointsAtY?: number;
987
+ pointsAtZ?: number;
988
+ specularExponent?: number;
989
+ limitingConeAngle?: number;
990
+ };
991
+ interface FeDiffuseLightingPrimitive extends BaseFilterPrimitive {
992
+ type: 'feDiffuseLighting';
993
+ surfaceScale?: number;
994
+ diffuseConstant?: number;
995
+ /** <number-optional-number>; preserved as authored. */
996
+ kernelUnitLength?: string;
997
+ lightingColor?: string;
998
+ lightSource?: FilterLightSource;
999
+ }
1000
+ interface FeSpecularLightingPrimitive extends BaseFilterPrimitive {
1001
+ type: 'feSpecularLighting';
1002
+ surfaceScale?: number;
1003
+ specularConstant?: number;
1004
+ specularExponent?: number;
1005
+ kernelUnitLength?: string;
1006
+ lightingColor?: string;
1007
+ lightSource?: FilterLightSource;
1008
+ }
1009
+ interface FeDisplacementMapPrimitive extends BaseFilterPrimitive {
1010
+ type: 'feDisplacementMap';
1011
+ in2?: string;
1012
+ scale?: number;
1013
+ xChannelSelector?: 'R' | 'G' | 'B' | 'A';
1014
+ yChannelSelector?: 'R' | 'G' | 'B' | 'A';
1015
+ }
1016
+ interface FeDropShadowPrimitive extends BaseFilterPrimitive {
1017
+ type: 'feDropShadow';
1018
+ dx?: number;
1019
+ dy?: number;
1020
+ /** <number-optional-number>; preserved as authored. */
1021
+ stdDeviation?: string;
1022
+ floodColor?: string;
1023
+ /** Numeric value or the literal 'inherit'. */
1024
+ floodOpacity?: string;
1025
+ }
1026
+ interface FeFloodPrimitive extends BaseFilterPrimitive {
1027
+ type: 'feFlood';
1028
+ floodColor?: string;
1029
+ floodOpacity?: string;
1030
+ }
1031
+ interface FeGaussianBlurPrimitive extends BaseFilterPrimitive {
1032
+ type: 'feGaussianBlur';
1033
+ /** <number-optional-number>; preserved as authored (e.g. "3" or "3 1"). */
1034
+ stdDeviation?: string;
1035
+ edgeMode?: 'duplicate' | 'wrap' | 'none';
1036
+ }
1037
+ interface FeImagePrimitive extends BaseFilterPrimitive {
1038
+ type: 'feImage';
1039
+ /** Canonical (SVG 2). */
1040
+ href?: string;
1041
+ /** Back-compat alias re-emitted only when the original used xlink:href
1042
+ * and no href was authored. */
1043
+ xlinkHref?: string;
1044
+ preserveAspectRatio?: string;
1045
+ crossorigin?: 'anonymous' | 'use-credentials';
1046
+ }
1047
+ interface FeMergePrimitive extends BaseFilterPrimitive {
1048
+ type: 'feMerge';
1049
+ /** <feMergeNode> children inlined. */
1050
+ nodes: {
1051
+ in?: string;
1052
+ }[];
1053
+ }
1054
+ interface FeMorphologyPrimitive extends BaseFilterPrimitive {
1055
+ type: 'feMorphology';
1056
+ operator?: 'erode' | 'dilate';
1057
+ /** <number-optional-number>; preserved as authored. */
1058
+ radius?: string;
1059
+ }
1060
+ interface FeOffsetPrimitive extends BaseFilterPrimitive {
1061
+ type: 'feOffset';
1062
+ dx?: number;
1063
+ dy?: number;
1064
+ }
1065
+ interface FeTilePrimitive extends BaseFilterPrimitive {
1066
+ type: 'feTile';
1067
+ }
1068
+ interface FeTurbulencePrimitive extends BaseFilterPrimitive {
1069
+ type: 'feTurbulence';
1070
+ /** <number-optional-number>; preserved as authored. */
1071
+ baseFrequency?: string;
1072
+ numOctaves?: number;
1073
+ seed?: number;
1074
+ stitchTiles?: 'stitch' | 'noStitch';
1075
+ turbulenceType?: 'fractalNoise' | 'turbulence';
1076
+ }
1077
+ type FilterPrimitive = FeBlendPrimitive | FeColorMatrixPrimitive | FeComponentTransferPrimitive | FeCompositePrimitive | FeConvolveMatrixPrimitive | FeDiffuseLightingPrimitive | FeSpecularLightingPrimitive | FeDisplacementMapPrimitive | FeDropShadowPrimitive | FeFloodPrimitive | FeGaussianBlurPrimitive | FeImagePrimitive | FeMergePrimitive | FeMorphologyPrimitive | FeOffsetPrimitive | FeTilePrimitive | FeTurbulencePrimitive;
1078
+ type FilterPrimitiveType = FilterPrimitive['type'];
1079
+ /**
1080
+ * A `<filter>` element modeled as an ordered list of editable primitives.
1081
+ *
1082
+ * This variant is the parser's default when no curated stylized preset
1083
+ * matches — it preserves every spec primitive 1:1 so imported third-party
1084
+ * SVG round-trips with semantic equivalence and remains editable in the
1085
+ * filters panel. Distinct from `RawSvgFilter` (which is opaque XML
1086
+ * passthrough); this one walks the primitives.
1087
+ */
1088
+ interface SvgPrimitiveChainFilter extends BaseFilter {
1089
+ type: 'svg-primitive-chain';
1090
+ /** <filter> wrapper attributes — all optional; omitted ⇒ UA spec default. */
1091
+ filterUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1092
+ primitiveUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1093
+ x?: string;
1094
+ y?: string;
1095
+ width?: string;
1096
+ height?: string;
1097
+ filterColorInterpolation?: 'auto' | 'sRGB' | 'linearRGB';
1098
+ /** Inheritable presentation attrs author placed on <filter> so child
1099
+ * primitives can resolve them via the CSS `inherit` keyword. */
1100
+ floodColor?: string;
1101
+ floodOpacity?: string;
1102
+ lightingColor?: string;
1103
+ /** <title> child text, captured for a11y/round-trip. */
1104
+ filterTitle?: string;
1105
+ filterDescription?: string;
1106
+ /** SMIL animation children directly on <filter> (rare). */
1107
+ filterAnimations?: string[];
1108
+ /** The primitive chain. Order is significant — implicit input chains
1109
+ * match document order. */
1110
+ primitives: FilterPrimitive[];
1111
+ }
1112
+ /**
1113
+ * Per-segment command hint, recording the SVG path command the segment
1114
+ * was authored with. Lets the serializer emit the original command form
1115
+ * (H, V, S, T, A) when the current geometry still satisfies its
1116
+ * constraints — and auto-demote to L/C/Q when a user edit invalidates
1117
+ * the shorthand condition. Replaces the old `originalD` round-trip
1118
+ * cache with a property of the geometry itself.
1119
+ *
1120
+ * - LINEAR → `L` (default for handle-less segments)
1121
+ * - HORIZONTAL → `H`; valid when `from.y === to.y`
1122
+ * - VERTICAL → `V`; valid when `from.x === to.x`
1123
+ * - CUBIC → `C`
1124
+ * - SMOOTH_CUBIC → `S`; valid when `to.handleIn` reflects the previous
1125
+ * segment's exit-tangent about the previous endpoint
1126
+ * - QUADRATIC → `Q`
1127
+ * - SMOOTH_QUADRATIC → `T`; valid when the implicit control reflects the
1128
+ * previous quadratic's control about the current point
1129
+ * - ARC → `A`
1130
+ */
1131
+ type SegmentCurveType = 'LINEAR' | 'HORIZONTAL' | 'VERTICAL' | 'CUBIC' | 'SMOOTH_CUBIC' | 'QUADRATIC' | 'SMOOTH_QUADRATIC' | 'ARC';
1132
+ interface PathPoint {
805
1133
  x: number;
806
1134
  y: number;
807
1135
  handleIn?: Point;
808
1136
  handleOut?: Point;
809
- pointType: SplinePointType;
1137
+ pointType: PathPointType;
810
1138
  isSubpathStart?: boolean;
811
1139
  segmentType?: SegmentCurveType;
812
1140
  arcParams?: ArcParams$1;
@@ -818,6 +1146,12 @@ interface ArcParams$1 {
818
1146
  largeArc: boolean;
819
1147
  sweep: boolean;
820
1148
  }
1149
+ /**
1150
+ * Hyperlink target per SVG 2 §16.2. Kept for UI convenience — the four
1151
+ * well-known keywords plus any authored `<XML-Name>` (custom named
1152
+ * browsing context). Hyperlink shapes themselves store target as a plain
1153
+ * string so arbitrary names round-trip.
1154
+ */
821
1155
  type LinkTarget = '_self' | '_blank' | '_parent' | '_top';
822
1156
  type AriaRole = '' | 'img' | 'button' | 'link' | 'presentation' | 'none' | 'graphics-document' | 'graphics-object' | 'graphics-symbol';
823
1157
  interface ShapeMetadata {
@@ -827,9 +1161,38 @@ interface ShapeMetadata {
827
1161
  description: string;
828
1162
  role: AriaRole;
829
1163
  ariaLabel: string;
830
- linkUrl: string;
831
- linkTarget: LinkTarget;
832
1164
  customData: Record<string, string>;
1165
+ /**
1166
+ * Hyperlink target — when set, the shape is rendered inside an SVG `<a>`
1167
+ * element with `href="${linkUrl}"`. Round-trips through SVG import/export.
1168
+ */
1169
+ linkUrl?: string;
1170
+ /** Hyperlink target window — maps to `<a target="...">`. */
1171
+ linkTarget?: LinkTarget;
1172
+ /**
1173
+ * Lossless carrier for any `<metadata>` elements that appeared as children
1174
+ * of this shape's SVG element. Stored as a serialized string containing
1175
+ * one or more complete `<metadata ...>...</metadata>` blocks in document
1176
+ * order. Preserves element-level attributes (id, lang, class, style,
1177
+ * xml:space), arbitrary child elements from any namespace, character data,
1178
+ * mixed content, and multiple sibling blocks.
1179
+ *
1180
+ * Spec: SVG 2 §5.8 — content model is "Any elements or character data",
1181
+ * and the element may appear on any container or graphical element.
1182
+ */
1183
+ rawMetadata?: string;
1184
+ /**
1185
+ * Lossless carrier for the inner XML of the `<desc>` element when it
1186
+ * contains foreign XML (per SVG 2 §5.7 — the spec example shows
1187
+ * `<myfoo:…>` elements inside `<desc>`). Populated only when `<desc>`
1188
+ * has non-text children; plain-prose desc uses `description` alone.
1189
+ *
1190
+ * Emit rule: if the textContent of `rawDescription` still equals the
1191
+ * current `description` value, emit the raw (foreign XML round-trips).
1192
+ * If `description` has been edited and the textual views diverge, emit
1193
+ * plain text from `description` (user intent takes precedence).
1194
+ */
1195
+ rawDescription?: string;
833
1196
  }
834
1197
  /**
835
1198
  * Provider attribution metadata for an image shape sourced from a third-party
@@ -868,6 +1231,29 @@ interface DocumentMetadata {
868
1231
  licenseUrl: string;
869
1232
  language: string;
870
1233
  customMetadata: Record<string, string>;
1234
+ /**
1235
+ * Lossless carrier for any `<metadata>` elements that appeared as direct
1236
+ * children of the root `<svg>`. Stored as a serialized string containing
1237
+ * one or more complete `<metadata ...>...</metadata>` blocks in document
1238
+ * order. Preserves element-level attributes, arbitrary child elements
1239
+ * from any namespace (RDF, XMP, Inkscape, custom), character data and
1240
+ * mixed content, and multiple sibling blocks.
1241
+ *
1242
+ * Typed fields above (`author`, `keywords`, `license`, `licenseUrl`,
1243
+ * `customMetadata`) are a structured view over a designated managed
1244
+ * `<rdf:Description>` inside this carrier. On export the managed
1245
+ * description is spliced into the preserved raw; foreign siblings and
1246
+ * non-RDF content survive untouched.
1247
+ *
1248
+ * Spec: SVG 2 §5.8.
1249
+ */
1250
+ rawMetadata?: string;
1251
+ /**
1252
+ * Lossless carrier for the inner XML of the document-level `<desc>`
1253
+ * element when it contains foreign XML (SVG 2 §5.7). Mirrors
1254
+ * `ShapeMetadata.rawDescription`; see there for the emit rule.
1255
+ */
1256
+ rawDescription?: string;
871
1257
  /**
872
1258
  * Decimal precision for coordinate values when the document is
873
1259
  * serialized — file save, cloud sync, undo capture, and SVG export.
@@ -949,6 +1335,24 @@ interface DocumentStyle {
949
1335
  }
950
1336
  /** Type of a template variable's value. */
951
1337
  type TemplateVariableType = 'string' | 'color' | 'number';
1338
+ /**
1339
+ * How the variable participates in export. Two genuinely different
1340
+ * substitution mechanisms — declaring intent up-front lets the export
1341
+ * pipeline pick the right one.
1342
+ *
1343
+ * - `live` → emitted as `var(--name, fallback)` references; the
1344
+ * variable definition rides along in a `<style>` block,
1345
+ * so consumers can re-theme the SVG at runtime via the
1346
+ * CSS cascade.
1347
+ * - `stamped` → resolved to its literal value at export time. Used
1348
+ * for `{{name}}` template-style stamping, and for
1349
+ * attributes (`width`, `x`, geometry) where `var()`
1350
+ * in attribute values has uneven interop.
1351
+ *
1352
+ * Defaults to `live` for `color` (well-supported in browsers), `stamped`
1353
+ * for `number`/`string` (where attribute-level var() is unreliable).
1354
+ */
1355
+ type TemplateVariableMode = 'live' | 'stamped';
952
1356
  /**
953
1357
  * Where a TemplateVariable came from. `user` is hand-authored in the
954
1358
  * Variables panel; `palette` is auto-generated by the palette-token
@@ -995,7 +1399,19 @@ interface TemplateVariable {
995
1399
  * settings palette.
996
1400
  */
997
1401
  source?: TemplateVariableSource;
1402
+ /**
1403
+ * Substitution mode at export time. When omitted, callers should
1404
+ * apply the type-based default in `defaultVariableMode()`:
1405
+ * `color` → `live`, `number`/`string` → `stamped`.
1406
+ */
1407
+ mode?: TemplateVariableMode;
998
1408
  }
1409
+ /**
1410
+ * Type-based default substitution mode. Color variables work reliably as
1411
+ * runtime `var()` references in browsers; numbers and strings are far
1412
+ * better baked into literal attribute values at export time.
1413
+ */
1414
+ declare function defaultVariableMode(type: TemplateVariableType): TemplateVariableMode;
999
1415
  interface Guide {
1000
1416
  id: string;
1001
1417
  orientation: 'horizontal' | 'vertical';
@@ -1015,261 +1431,11 @@ interface Measurement {
1015
1431
  }
1016
1432
 
1017
1433
  /**
1018
- * Typed property interfaces for every node type in the scene graph.
1019
- *
1020
- * This is the **single source of truth** for shape property types across
1021
- * the entire SVGSketch stack (editor, API worker, server renderer, etc.).
1434
+ * @svgsketch/core Serialized document types.
1022
1435
  *
1023
- * Each shape type declares the exact set of properties it owns.
1024
- * These interfaces drive:
1025
- * - Compile-time type safety on `SceneNode.get()` / `.set()` calls
1026
- * - The `NodeTypePropsMap` lookup used by `SceneNode.create()`
1027
- * - Schema defaults and validators in the editor's `node-schema.ts`
1028
- * - Serialization format for the `.svgs` document format
1029
- */
1030
-
1031
- interface CommonNodeProps {
1032
- fillColor: string;
1033
- borderColor: string;
1034
- borderWidth: number;
1035
- opacity: number;
1036
- fillOpacity: number;
1037
- strokeOpacity: number;
1038
- rotation: number;
1039
- skewX: number;
1040
- skewY: number;
1041
- customPivot: Point | null;
1042
- locked: boolean;
1043
- visible: boolean;
1044
- fillType: string;
1045
- fillGradient: unknown | null;
1046
- strokeType: string;
1047
- strokeGradient: unknown | null;
1048
- fillRule: 'nonzero' | 'evenodd';
1049
- strokeLinejoin: 'miter' | 'round' | 'bevel';
1050
- strokeLinecap: 'butt' | 'round' | 'square';
1051
- strokeMiterlimit: number;
1052
- lineStyle: string;
1053
- dashLength: number;
1054
- gapLength: number;
1055
- dashOffset: number;
1056
- strokeDasharray: string | null;
1057
- filters: unknown[];
1058
- filterColorInterpolation: 'auto' | 'sRGB' | 'linearRGB' | null;
1059
- filterUnits: 'userSpaceOnUse' | 'objectBoundingBox' | null;
1060
- primitiveUnits: 'userSpaceOnUse' | 'objectBoundingBox' | null;
1061
- filterX: string | null;
1062
- filterY: string | null;
1063
- filterWidth: string | null;
1064
- filterHeight: string | null;
1065
- rawTransform: string | null;
1066
- metadata: unknown | null;
1067
- cssClipPath: string | null;
1068
- cssMaskProperties: Record<string, string> | null;
1069
- groupId: string | null;
1070
- }
1071
- type CornerShapeValue = 'round' | 'notch' | 'bevel' | 'scoop';
1072
- interface RectangleNodeProps extends CommonNodeProps {
1073
- x: number;
1074
- y: number;
1075
- width: number;
1076
- height: number;
1077
- cornerRadius: number;
1078
- cornerShape: CornerShapeValue;
1079
- cornerMode: 'uniform' | 'non-uniform';
1080
- cornerRadiusTL: number;
1081
- cornerRadiusTR: number;
1082
- cornerRadiusBL: number;
1083
- cornerRadiusBR: number;
1084
- cornerShapeTL: CornerShapeValue;
1085
- cornerShapeTR: CornerShapeValue;
1086
- cornerShapeBL: CornerShapeValue;
1087
- cornerShapeBR: CornerShapeValue;
1088
- }
1089
- type SquareNodeProps = RectangleNodeProps;
1090
- interface CircleNodeProps extends CommonNodeProps {
1091
- x: number;
1092
- y: number;
1093
- radius: number;
1094
- }
1095
- interface EllipseNodeProps extends CommonNodeProps {
1096
- x: number;
1097
- y: number;
1098
- rx: number;
1099
- ry: number;
1100
- }
1101
- type LineEndpointValue = 'none' | 'arrow' | 'open-arrow' | 'circle' | 'diamond' | 'square';
1102
- interface LineNodeProps extends CommonNodeProps {
1103
- x1: number;
1104
- y1: number;
1105
- x2: number;
1106
- y2: number;
1107
- startEndpoint: LineEndpointValue;
1108
- endEndpoint: LineEndpointValue;
1109
- }
1110
- interface TextNodeProps extends CommonNodeProps {
1111
- x: number;
1112
- y: number;
1113
- width: number;
1114
- height: number;
1115
- textX: number;
1116
- textY: number;
1117
- fontSize: number;
1118
- text: string;
1119
- fontFamily: string;
1120
- fontWeight: string;
1121
- fontStyle: string;
1122
- textDecoration: Record<string, boolean>;
1123
- textTransform: string;
1124
- baselineShift: string;
1125
- dominantBaseline: string;
1126
- writingMode: string;
1127
- textAnchor: string;
1128
- letterSpacing: number;
1129
- wordSpacing: number;
1130
- lineHeight: number;
1131
- inlineSize: number;
1132
- overflowWrap: string;
1133
- whiteSpace: string;
1134
- textDirection: string;
1135
- unicodeBidi: string;
1136
- scaleX: number;
1137
- scaleY: number;
1138
- scaleAnchor: Point | null;
1139
- useRichText: boolean;
1140
- richTextData: unknown | null;
1141
- charOffsets: {
1142
- x: number;
1143
- y: number;
1144
- rotate: number;
1145
- }[] | null;
1146
- fontVariationSettings: Record<string, number>;
1147
- isTextPath: boolean;
1148
- textPathPoints: unknown[] | null;
1149
- textPathStartOffset: number;
1150
- textPathSide: 'left' | 'right';
1151
- shapeInsideRef: string | null;
1152
- shapePadding: number;
1153
- }
1154
- interface ImageNodeProps extends CommonNodeProps {
1155
- x: number;
1156
- y: number;
1157
- width: number;
1158
- height: number;
1159
- href: string;
1160
- originalWidth: number;
1161
- originalHeight: number;
1162
- preserveAspectRatio: boolean;
1163
- imageOpacity: number;
1164
- }
1165
- interface SplineNodeProps extends CommonNodeProps {
1166
- x: number;
1167
- y: number;
1168
- width: number;
1169
- height: number;
1170
- splinePoints: unknown[];
1171
- splineArcParams: unknown[];
1172
- splineControlBounds: {
1173
- x: number;
1174
- y: number;
1175
- width: number;
1176
- height: number;
1177
- } | null;
1178
- startEndpoint: LineEndpointValue;
1179
- endEndpoint: LineEndpointValue;
1180
- }
1181
- interface PolylineNodeProps extends CommonNodeProps {
1182
- x: number;
1183
- y: number;
1184
- width: number;
1185
- height: number;
1186
- polylinePoints: Point[];
1187
- polylineClosed: boolean;
1188
- }
1189
- interface PolygonBaseNodeProps extends CommonNodeProps {
1190
- cx: number;
1191
- cy: number;
1192
- radius: number;
1193
- cornerRadius: number;
1194
- shiftAngle: number;
1195
- }
1196
- interface TriangleNodeProps extends PolygonBaseNodeProps {
1197
- sides: 3;
1198
- }
1199
- interface NGonNodeProps extends PolygonBaseNodeProps {
1200
- sides: number;
1201
- }
1202
- interface StarNodeProps extends PolygonBaseNodeProps {
1203
- arms: number;
1204
- innerRadiusPercent: number;
1205
- }
1206
- interface CrossNodeProps extends PolygonBaseNodeProps {
1207
- armWidthPercent: number;
1208
- }
1209
- interface RingNodeProps extends PolygonBaseNodeProps {
1210
- innerRadiusPercent: number;
1211
- }
1212
- interface SpiralNodeProps extends PolygonBaseNodeProps {
1213
- turns: number;
1214
- thicknessPercent: number;
1215
- spiralDirection: number;
1216
- }
1217
- interface GearNodeProps extends PolygonBaseNodeProps {
1218
- teeth: number;
1219
- toothDepthPercent: number;
1220
- holeRadiusPercent: number;
1221
- }
1222
- interface ArrowNodeProps extends PolygonBaseNodeProps {
1223
- headWidthPercent: number;
1224
- headLengthPercent: number;
1225
- shaftWidthPercent: number;
1226
- }
1227
- interface SymbolInstanceNodeProps extends CommonNodeProps {
1228
- x: number;
1229
- y: number;
1230
- width: number;
1231
- height: number;
1232
- symbolId: string;
1233
- }
1234
- interface GroupNodeProps {
1235
- groupId: string | null;
1236
- }
1237
- type DocumentNodeProps = Record<string, never>;
1238
- /**
1239
- * Maps each node type string to its typed property interface.
1240
- * Used by `SceneNode.create()` for compile-time type safety.
1241
- */
1242
- interface NodeTypePropsMap {
1243
- rectangle: RectangleNodeProps;
1244
- square: SquareNodeProps;
1245
- circle: CircleNodeProps;
1246
- ellipse: EllipseNodeProps;
1247
- line: LineNodeProps;
1248
- text: TextNodeProps;
1249
- image: ImageNodeProps;
1250
- spline: SplineNodeProps;
1251
- polyline: PolylineNodeProps;
1252
- triangle: TriangleNodeProps;
1253
- ngon: NGonNodeProps;
1254
- star: StarNodeProps;
1255
- cross: CrossNodeProps;
1256
- ring: RingNodeProps;
1257
- spiral: SpiralNodeProps;
1258
- gear: GearNodeProps;
1259
- arrow: ArrowNodeProps;
1260
- 'symbol-instance': SymbolInstanceNodeProps;
1261
- group: GroupNodeProps;
1262
- document: DocumentNodeProps;
1263
- }
1264
- /** Union of all node prop types. */
1265
- type AnyNodeProps = RectangleNodeProps | SquareNodeProps | CircleNodeProps | EllipseNodeProps | LineNodeProps | TextNodeProps | ImageNodeProps | SplineNodeProps | PolylineNodeProps | TriangleNodeProps | NGonNodeProps | StarNodeProps | CrossNodeProps | RingNodeProps | SpiralNodeProps | GearNodeProps | ArrowNodeProps | SymbolInstanceNodeProps | GroupNodeProps | DocumentNodeProps;
1266
-
1267
- /**
1268
- * @svgsketch/core — Serialized document types.
1269
- *
1270
- * These types define the .svgs document format. SerializedShape and
1271
- * HistorySnapshot are the canonical data structures for persisting
1272
- * SVGSketch documents.
1436
+ * These types define the .svgs document format. SerializedShape and
1437
+ * HistorySnapshot are the canonical data structures for persisting
1438
+ * SVGSketch documents.
1273
1439
  */
1274
1440
 
1275
1441
  interface SerializedShape {
@@ -1319,11 +1485,31 @@ interface SerializedShape {
1319
1485
  textDirection?: 'ltr' | 'rtl';
1320
1486
  unicodeBidi?: 'normal' | 'embed' | 'bidi-override' | 'isolate' | 'isolate-override' | 'plaintext';
1321
1487
  fontVariationSettings?: Record<string, number>;
1322
- charOffsets?: {
1488
+ /**
1489
+ * Per-glyph positioning data, mirroring SVG 2 §11.2's five attribute
1490
+ * lists (`x`, `y`, `dx`, `dy`, `rotate`).
1491
+ *
1492
+ * - `x`/`y` are absolute user coordinates; `null` means "no
1493
+ * override at this glyph — the cursor advances naturally".
1494
+ * - `dx`/`dy` are additive shifts on top of natural advance.
1495
+ * - `rotate` is per-glyph rotation in degrees.
1496
+ *
1497
+ * For backward compatibility, the legacy three-field shape
1498
+ * `{x, y, rotate}` (produced before the spec-aligned model shipped)
1499
+ * is still accepted on read; its `x`/`y` are interpreted as the
1500
+ * additive shifts (`dx`/`dy`).
1501
+ */
1502
+ charOffsets?: ({
1503
+ x: number | null;
1504
+ y: number | null;
1505
+ dx: number;
1506
+ dy: number;
1507
+ rotate: number;
1508
+ } | {
1323
1509
  x: number;
1324
1510
  y: number;
1325
1511
  rotate: number;
1326
- }[];
1512
+ })[];
1327
1513
  linePositions?: {
1328
1514
  x: number;
1329
1515
  dy: number;
@@ -1352,9 +1538,29 @@ interface SerializedShape {
1352
1538
  borderColor?: string;
1353
1539
  borderWidth?: number | string;
1354
1540
  strokeOpacity?: number;
1541
+ /**
1542
+ * Inherit `fill` from the ancestor cascade rather than emit an explicit
1543
+ * attribute. Set at import for shapes inside `<defs>`/`<symbol>` that
1544
+ * have no own `fill` — they're reachable only via `<use>`, whose shadow
1545
+ * tree inherits paint from the `<use>` element itself (SVG 2 §5.5.4).
1546
+ * Baking the SVG-default black onto the inner shape would block the
1547
+ * `<use fill="…">` cascade and render the instance override dead.
1548
+ */
1549
+ inheritFill?: boolean;
1550
+ /** See {@link inheritFill}. */
1551
+ inheritStroke?: boolean;
1355
1552
  /** CSS `paint-order` (SVG 2). Canonical SVG token string, e.g.
1356
1553
  * 'stroke fill markers'. Omitted when equivalent to default 'normal'. */
1357
1554
  paintOrder?: string;
1555
+ /**
1556
+ * CSS Transforms 2 §6.2 — `transform-box` reference box. SVG
1557
+ * default is `view-box`; persisted on the shape so authored values
1558
+ * (`fill-box`, `stroke-box`) survive round-trip. The editor bakes
1559
+ * `transform-origin` into a numeric pivot at import using the
1560
+ * resolved box, so this field exists for export fidelity rather
1561
+ * than rendering.
1562
+ */
1563
+ transformBox?: 'view-box' | 'fill-box' | 'stroke-box' | 'content-box' | 'border-box';
1358
1564
  /** Marker id applied as `marker-start` (rendered `url(#id)` in SVG). */
1359
1565
  markerStart?: string;
1360
1566
  /** Marker id applied as `marker-mid`. */
@@ -1412,30 +1618,112 @@ interface SerializedShape {
1412
1618
  * overrides the SVG visibility attribute.
1413
1619
  */
1414
1620
  visibility?: 'visible' | 'hidden' | 'collapse';
1621
+ /**
1622
+ * Structural role of the shape in the exported SVG.
1623
+ * - `'normal'` / absent — rendered inline in document order (default).
1624
+ * - `'motionOnly'` — emitted inside `<defs>` as an `<mpath>` reference
1625
+ * target; not rendered. Used for `<path>` elements imported from
1626
+ * `<defs>` that serve only as animateMotion paths.
1627
+ * @see https://svgwg.org/specs/animations/#MPathElement
1628
+ */
1629
+ displayMode?: 'normal' | 'motionOnly';
1415
1630
  fillType?: FillType;
1631
+ /**
1632
+ * @deprecated from v2 for linear/radial kinds — canonical storage is a
1633
+ * `LinearGradientLibraryDef` / `RadialGradientLibraryDef` keyed by
1634
+ * `fillLibraryId`. Still used for `PatternFill` until Phase 3 promotes
1635
+ * patterns, and retained as a runtime shadow copy of the library def so
1636
+ * legacy readers keep working through the transition.
1637
+ */
1416
1638
  fillGradient?: LinearGradient | RadialGradient | PatternFill;
1639
+ /**
1640
+ * Reference into the unified library (v2+). When `fillType` is
1641
+ * `'linear-gradient'` or `'radial-gradient'`, `fillLibraryId` points at
1642
+ * the canonical `LinearGradientLibraryDef` / `RadialGradientLibraryDef`.
1643
+ * For `'pattern'` this field is unused in v2 (patterns still live on
1644
+ * `fillGradient`) and will be populated in Phase 3. For `'solid'` /
1645
+ * `'none'` this field is ignored.
1646
+ */
1647
+ fillLibraryId?: string;
1417
1648
  strokeType?: StrokeType;
1649
+ /** @deprecated see `fillGradient`. */
1418
1650
  strokeGradient?: LinearGradient | RadialGradient | PatternFill;
1651
+ /** See `fillLibraryId`. */
1652
+ strokeLibraryId?: string;
1653
+ /**
1654
+ * @deprecated from v2 — canonical storage is a `FilterLibraryDef` keyed
1655
+ * by entries in `filterLibraryIds`. Retained as a runtime shadow copy of
1656
+ * the library def so legacy readers and the editor's filter-manager keep
1657
+ * working through the transition.
1658
+ */
1419
1659
  filters?: ShapeFilter[];
1660
+ /**
1661
+ * Ordered list of library filter-def ids applied to this shape. On
1662
+ * export each id emits `url(#id)`; the `filter` CSS property chains the
1663
+ * list serially (CSS Filter Effects §Filter Property). Today the list
1664
+ * always has length 0 or 1 — the editor wraps a shape's primitive chain
1665
+ * in a single compound `FilterLibraryDef`. Future phases may split
1666
+ * independent filter chains into multiple library entries.
1667
+ */
1668
+ filterLibraryIds?: string[];
1669
+ /** @deprecated v2 — scope fields live on `FilterLibraryDef` from Phase 4 on. */
1420
1670
  filterColorInterpolation?: 'auto' | 'sRGB' | 'linearRGB';
1671
+ /** @deprecated v2 — see `filterColorInterpolation`. */
1421
1672
  filterUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1673
+ /** @deprecated v2 — see `filterColorInterpolation`. */
1422
1674
  primitiveUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1675
+ /** @deprecated v2 — lives on `FilterLibraryDef` from Phase 4 on. */
1423
1676
  filterX?: string;
1677
+ /** @deprecated v2 — see `filterX`. */
1424
1678
  filterY?: string;
1679
+ /** @deprecated v2 — see `filterX`. */
1425
1680
  filterWidth?: string;
1681
+ /** @deprecated v2 — see `filterX`. */
1426
1682
  filterHeight?: string;
1427
1683
  rawTransform?: string;
1428
- splinePoints?: SplinePoint[];
1429
- splineCurveType?: SplineCurveType;
1430
- splineClosed?: boolean;
1431
- splineTension?: number;
1432
- splineArcParams?: ArcParams$1[];
1684
+ ancestorTransform?: number[];
1685
+ pathPoints?: PathPoint[];
1686
+ pathCurveType?: PathCurveType;
1687
+ pathClosed?: boolean;
1688
+ pathTension?: number;
1689
+ pathArcParams?: ArcParams$1[];
1690
+ /**
1691
+ * SVG 2 §6 `pathLength` — author's stated total length of the path.
1692
+ * Used to scale distance-along-a-path computations (text-on-path,
1693
+ * `<animateMotion>`, `stroke-dasharray`) by `pathLength / actualLength`.
1694
+ * A non-negative number; negative values are an error per spec.
1695
+ */
1696
+ pathLength?: number;
1697
+ /**
1698
+ * CSS Vector Effects — `vector-effect` property. `non-scaling-stroke`
1699
+ * keeps stroke width constant under zoom/transforms (heavily used in
1700
+ * CAD/diagram SVGs). Applies to any graphic element, not just paths;
1701
+ * persists at the SerializedShape state level so all shape types can
1702
+ * round-trip it.
1703
+ */
1704
+ vectorEffect?: 'none' | 'non-scaling-stroke' | 'non-scaling-size' | 'non-rotation' | 'fixed-position';
1433
1705
  polylinePoints?: Point[];
1434
1706
  polylineClosed?: boolean;
1435
1707
  href?: string;
1436
1708
  originalWidth?: number;
1437
1709
  originalHeight?: number;
1710
+ /**
1711
+ * Editor-internal flag controlling whether interactive resize keeps
1712
+ * the image's natural aspect ratio. NOT the SVG `preserveAspectRatio`
1713
+ * attribute — this is purely a UX behavior switch on the resize
1714
+ * handles. Persisted so the user's setting survives reload.
1715
+ */
1438
1716
  preserveAspectRatio?: boolean;
1717
+ /**
1718
+ * SVG 2 §8.7 — verbatim `preserveAspectRatio` attribute value
1719
+ * (e.g. `'xMidYMid slice'`, `'defer xMidYMid meet'`, `'none'`). When
1720
+ * unset, the spec default applies. The editor canvas always renders
1721
+ * `<image>` with `preserveAspectRatio="none"` so the visible box
1722
+ * matches the resize handles; this field carries the author's
1723
+ * intent through round-trip and is restored on export by
1724
+ * `SvgExportFinalizer`.
1725
+ */
1726
+ specPreserveAspectRatio?: string;
1439
1727
  imageOpacity?: number;
1440
1728
  mediaKind?: 'audio' | 'video';
1441
1729
  mediaMimeType?: string;
@@ -1471,12 +1759,36 @@ interface SerializedShape {
1471
1759
  * soundtracks / captioned video versions.
1472
1760
  */
1473
1761
  systemLanguage?: string;
1762
+ /**
1763
+ * Space-separated list of required IRI references that the user agent
1764
+ * must support for this shape to be rendered. SVG 2 §15.4 conditional
1765
+ * processing — typically `http://www.w3.org/TR/SVG11/feature#…` strings.
1766
+ * Persisted alongside `systemLanguage` so `<switch>` content round-trips.
1767
+ */
1768
+ requiredExtensions?: string;
1474
1769
  shapeInsideRef?: string;
1475
1770
  shapePadding?: number;
1476
1771
  isTextPath?: boolean;
1477
- textPathPoints?: SplinePoint[];
1772
+ textPathPoints?: PathPoint[];
1773
+ /**
1774
+ * Curve type used to interpolate `textPathPoints` into a renderable
1775
+ * path. Mirrors `pathCurveType` for plain path shapes; persisted
1776
+ * separately so author-set text-path curves don't have to share the
1777
+ * shape's geometry curve type.
1778
+ */
1779
+ textPathCurveType?: PathCurveType;
1478
1780
  textPathStartOffset?: number;
1781
+ textPathStartOffsetUnit?: '%' | 'user';
1479
1782
  textPathSide?: 'left' | 'right';
1783
+ textPathMethod?: 'align' | 'stretch';
1784
+ textPathSpacing?: 'auto' | 'exact';
1785
+ textPathLengthAdjust?: 'spacing' | 'spacingAndGlyphs';
1786
+ textPathLength?: number;
1787
+ textPathLengthUnit?: '%' | 'user';
1788
+ textPathInlineFormat?: 'defs-path' | 'path-attr';
1789
+ textPathRefShapeId?: string;
1790
+ /** Transient: import-time href target id, resolved away by ImportExportManager. */
1791
+ textPathImportRefId?: string;
1480
1792
  fillRule?: 'nonzero' | 'evenodd';
1481
1793
  strokeLinejoin?: 'miter' | 'round' | 'bevel';
1482
1794
  strokeLinecap?: 'butt' | 'round' | 'square';
@@ -1503,6 +1815,48 @@ interface SerializedShape {
1503
1815
  * variant (`def.shapes`). Only meaningful on `symbol-instance` shapes.
1504
1816
  */
1505
1817
  variantKey?: string;
1818
+ /**
1819
+ * Per-instance presentation cascade (SVG 2 §5.5.4): attributes set on
1820
+ * the source `<use>` element that are inherited into the symbol shadow
1821
+ * tree on render and re-emitted on export. Keyed by the SVG attribute
1822
+ * name in its canonical kebab-case form (`fill`, `stroke-width`,
1823
+ * `color-interpolation-filters`, `paint-order`, etc.). Values are the
1824
+ * verbatim attribute string — numeric parsing happens at the edit /
1825
+ * render boundary, not at storage time.
1826
+ *
1827
+ * The map is the single source of truth: importing a `<use>` stores
1828
+ * every presentation-class attribute the author wrote, applying it
1829
+ * mirrors every entry onto the wrapper `<g>`, and exporting emits
1830
+ * every entry back onto the `<use>`. No whitelist — any attribute the
1831
+ * SVG cascade honors round-trips.
1832
+ *
1833
+ * Special case: `transform` is composed with the editor's geometry
1834
+ * (position / rotation / skew / scale) rather than applied raw to the
1835
+ * wrapper. See `SymbolInstance.buildTransformString`.
1836
+ *
1837
+ * Legacy (pre-refactor) documents may carry camelCase keys
1838
+ * (`fillOpacity`, `strokeWidth`, …). `SymbolInstance.createFromSerialized`
1839
+ * normalises them to kebab-case on load; no runtime readers of this
1840
+ * field should assume either form.
1841
+ *
1842
+ * Only meaningful on `symbol-instance` shapes.
1843
+ */
1844
+ instancePresentation?: Record<string, string>;
1845
+ /**
1846
+ * Id of the canvas shape this `shape-reference` (Linked Copy) targets.
1847
+ * A Linked Copy renders as a live clone of another top-level shape and
1848
+ * exports to `<use href="#targetShapeId">` per SVG 2 §5.5. Only
1849
+ * meaningful on shapes of type `shape-reference`.
1850
+ */
1851
+ targetShapeId?: string;
1852
+ /**
1853
+ * For `shape-reference` shapes: x/y offset from the source's reference
1854
+ * point. Maps to the `x`/`y` on the exported `<use>` per SVG 2 §5.5.2
1855
+ * (an additional translate applied to the use element), so the instance
1856
+ * tracks the source's position natively.
1857
+ */
1858
+ offsetX?: number;
1859
+ offsetY?: number;
1506
1860
  /**
1507
1861
  * Map of geometry-property name → CSS custom-property name (without
1508
1862
  * the leading `--`) the property is bound to.
@@ -1552,6 +1906,44 @@ interface SerializedShape {
1552
1906
  topWidthPercent?: number;
1553
1907
  /** Document shape: wave amplitude as a % of height. */
1554
1908
  waveAmplitudePercent?: number;
1909
+ /** View shape: viewBox X component (animatable axis of the 4-tuple). */
1910
+ viewBoxX?: number;
1911
+ /** View shape: viewBox Y component (animatable axis of the 4-tuple). */
1912
+ viewBoxY?: number;
1913
+ /** View shape: viewBox width component (animatable axis of the 4-tuple). */
1914
+ viewBoxWidth?: number;
1915
+ /** View shape: viewBox height component (animatable axis of the 4-tuple). */
1916
+ viewBoxHeight?: number;
1917
+ /** View shape: name used as `<view id="...">` and fragment URL target. */
1918
+ viewName?: string;
1919
+ /** View shape: optional preserveAspectRatio (SVG 2 §7.8 — animatable). */
1920
+ viewPreserveAspectRatio?: string;
1921
+ /** View shape: SVG 1.1 §16.5 zoomAndPan. */
1922
+ viewZoomAndPan?: 'disable' | 'magnify';
1923
+ /** View shape: deprecated SVG 1.1 viewTarget — preserved verbatim. */
1924
+ viewTarget?: string;
1925
+ /** View shape: when true, this View's viewBox becomes the root SVG viewBox. */
1926
+ isHomeView?: boolean;
1927
+ /** SvgShape: viewBox X component (animatable). */
1928
+ svgViewBoxX?: number;
1929
+ /** SvgShape: viewBox Y component (animatable). */
1930
+ svgViewBoxY?: number;
1931
+ /** SvgShape: viewBox width component (animatable). */
1932
+ svgViewBoxWidth?: number;
1933
+ /** SvgShape: viewBox height component (animatable). */
1934
+ svgViewBoxHeight?: number;
1935
+ /** SvgShape: preserveAspectRatio (SVG 2 §7.8 — animatable, discrete). */
1936
+ svgPreserveAspectRatio?: string;
1937
+ /** SvgShape: outermost = intrinsic doc size, embedded = viewport rect width. */
1938
+ svgWidth?: number;
1939
+ /** SvgShape: outermost = intrinsic doc size, embedded = viewport rect height. */
1940
+ svgHeight?: number;
1941
+ /** SvgShape: x position (no effect on outermost per §5.1.4 ¶3, embedded only). */
1942
+ svgX?: number;
1943
+ /** SvgShape: y position (no effect on outermost per §5.1.4 ¶3, embedded only). */
1944
+ svgY?: number;
1945
+ /** SvgShape: marks the singleton root <svg> shape (one per document). */
1946
+ isRootSvg?: boolean;
1555
1947
  };
1556
1948
  }
1557
1949
  type SerializedViewbox = Viewbox;
@@ -1576,7 +1968,7 @@ type SerializedViewbox = Viewbox;
1576
1968
  * (version - 1) snapshots into the new format.
1577
1969
  * c. Register it in the migrateSnapshot() chain.
1578
1970
  */
1579
- declare const CURRENT_SCHEMA_VERSION = 1;
1971
+ declare const CURRENT_SCHEMA_VERSION = 2;
1580
1972
  interface HistorySnapshot {
1581
1973
  /**
1582
1974
  * Schema version — written on save, read on load to trigger migrations.
@@ -1606,15 +1998,30 @@ interface HistorySnapshot {
1606
1998
  templateVariables?: TemplateVariable[];
1607
1999
  /** Animation timeline (tracks, keyframes, easing). */
1608
2000
  animationTimeline?: SerializedAnimationTimeline;
1609
- /** User-defined custom patterns stored in the document. */
1610
- customPatterns?: CustomPatternDef[];
1611
- /** Symbol definitions (reusable component templates). */
1612
- symbols?: SerializedSymbolDef[];
1613
2001
  /**
1614
- * Marker definitions (reusable vertex-attached graphics: arrowheads, dots,
1615
- * etc.). Built-in markers are reconstituted at load time by MarkerManager
1616
- * and are NOT persisted here only user-authored defs are stored.
2002
+ * Unified library of reusable `<defs>` content. Authoritative from v2 onward
2003
+ * for symbols and markers (and, as later phases land, gradients, patterns,
2004
+ * and filters too). Built-in markers are reconstituted at load time by
2005
+ * MarkerManager and are NOT persisted here — only user-authored defs are.
2006
+ */
2007
+ library?: LibraryDef[];
2008
+ /**
2009
+ * Raw XML fragments for `<mask>` / `<clipPath>` defs that live in editor
2010
+ * defs but have no typed entry in `library`. Populated by paste pipelines
2011
+ * that clone source paint-server defs verbatim (preserving original ids so
2012
+ * `url(#id)` refs resolve). Without this field, the save/reload cycle
2013
+ * drops the masks entirely because `library` has no kind for them; shapes
2014
+ * that reference those ids render without their mask.
2015
+ *
2016
+ * Each entry is a serialised fragment (`<mask id="…">…</mask>`) ready to
2017
+ * `innerHTML`-append into editor defs on restore.
1617
2018
  */
2019
+ rawPaintServerDefs?: string[];
2020
+ /** @deprecated v2 — use `library`. Read-only: v1 docs migrate into `library`. */
2021
+ customPatterns?: CustomPatternDef[];
2022
+ /** @deprecated v2 — use `library`. Read-only: v1 docs migrate into `library`. */
2023
+ symbols?: SerializedSymbolDef[];
2024
+ /** @deprecated v2 — use `library`. Read-only: v1 docs migrate into `library`. */
1618
2025
  markers?: SerializedMarkerDef[];
1619
2026
  }
1620
2027
  /**
@@ -1627,213 +2034,581 @@ interface SerializedVariantAxis {
1627
2034
  name: string;
1628
2035
  values: string[];
1629
2036
  }
1630
- /**
1631
- * A reusable symbol definition. Contains the shapes that make up the
1632
- * symbol template, plus metadata for the symbols panel.
1633
- *
1634
- * **Variants:** when `variantAxes` is present, the symbol carries
1635
- * multiple alternative shape arrays keyed by variant combination
1636
- * (e.g. `state=hover,size=md`). The base `shapes` field is always
1637
- * the **default variant** — the combination where every axis is at
1638
- * its first value. Other variants live in `variants[variantKey]`.
1639
- * Variant resolution falls back to `shapes` whenever `variantKey`
1640
- * is missing or empty.
1641
- */
1642
- interface SerializedSymbolDef {
1643
- /** Unique identifier for this symbol definition. */
1644
- id: string;
1645
- /** Human-readable name shown in the symbols panel. */
1646
- name: string;
1647
- /** SVG viewBox string ("minX minY width height"). */
1648
- viewBox: string;
1649
- /**
1650
- * Default variant shapes. When `variantAxes` is present, this represents
1651
- * the variant where every axis is at its first value.
1652
- */
1653
- shapes: SerializedShape[];
1654
- /** Groups within the symbol. */
1655
- groups?: SerializedGroup[];
1656
- /** Base64 data-URI thumbnail for the symbols panel. */
1657
- thumbnail?: string;
1658
- /**
1659
- * Ordered list of variant axes available on this symbol. The order is
1660
- * stable so that variant keys can be canonicalized as
1661
- * `axis1=val1,axis2=val2`.
1662
- */
1663
- variantAxes?: SerializedVariantAxis[];
1664
- /**
1665
- * Non-default variant shape arrays keyed by canonical axis combination
1666
- * string (e.g. `state=hover,size=md`). Missing keys fall back to the
1667
- * base `shapes` array.
1668
- */
1669
- variants?: Record<string, SerializedShape[]>;
1670
- /**
1671
- * Per-variant thumbnails as base64 data URIs, keyed by canonical
1672
- * variant combination string. The empty string `""` keys the default
1673
- * variant (which also lives in `thumbnail` for backwards compatibility).
1674
- * Used by the variant matrix view to show real previews of each cell.
1675
- */
1676
- variantThumbnails?: Record<string, string>;
2037
+ /**
2038
+ * A reusable symbol definition. Contains the shapes that make up the
2039
+ * symbol template, plus metadata for the symbols panel.
2040
+ *
2041
+ * **Variants:** when `variantAxes` is present, the symbol carries
2042
+ * multiple alternative shape arrays keyed by variant combination
2043
+ * (e.g. `state=hover,size=md`). The base `shapes` field is always
2044
+ * the **default variant** — the combination where every axis is at
2045
+ * its first value. Other variants live in `variants[variantKey]`.
2046
+ * Variant resolution falls back to `shapes` whenever `variantKey`
2047
+ * is missing or empty.
2048
+ */
2049
+ type SerializedSymbolDef = SymbolLibraryDef;
2050
+ /**
2051
+ * A reusable `<marker>` definition (SVG 2 §11.6). Markers are vertex-attached
2052
+ * graphics arrowheads, vertex dots, decorations — referenced via
2053
+ * `marker-start` / `marker-mid` / `marker-end` attributes on stroked shapes.
2054
+ *
2055
+ * The browser handles per-vertex positioning, scaling (via `markerUnits`),
2056
+ * and orientation (via `orient`, including tangent-aware `auto` mode on
2057
+ * curved paths). MarkerManager only maintains the DOM `<defs>` entries in
2058
+ * sync with this serialized state.
2059
+ *
2060
+ * Simpler than `SerializedSymbolDef` — markers have no variants, no instance
2061
+ * overrides, and no placed instances (they attach via attribute references).
2062
+ */
2063
+ type SerializedMarkerDef = MarkerLibraryDef;
2064
+ interface SerializedGroup {
2065
+ id: string;
2066
+ parentId: string | null;
2067
+ /** CSS transform-origin value (e.g. "50px 50px") for group animations */
2068
+ transformOrigin?: string;
2069
+ /**
2070
+ * SVG `<g>` transform attribute (e.g. "matrix(...)" or "scale(2,1)").
2071
+ * Preserved verbatim from import so the group carries its ancestor/own
2072
+ * transform through serialization (clipboard, undo/redo, collab).
2073
+ * Shapes inside stay in the group's local frame the browser composes
2074
+ * `groupTransform × child` natively at render.
2075
+ */
2076
+ transform?: string;
2077
+ /**
2078
+ * Zero-based position of this group among its parent container's
2079
+ * children (including both sibling groups and sibling shape nodes).
2080
+ * Used during restoration to correctly interleave groups and shapes
2081
+ * so that SVG document order (painting order) is preserved.
2082
+ */
2083
+ siblingIndex?: number;
2084
+ /** Plugin that owns this group (e.g. 'svgsketch-charts') */
2085
+ pluginId?: string;
2086
+ /** Serialized plugin-specific state (JSON string) */
2087
+ pluginData?: string;
2088
+ /** Additional custom data-* attributes set by plugins */
2089
+ attributes?: Record<string, string>;
2090
+ fill?: string;
2091
+ fillOpacity?: string;
2092
+ strokeOpacity?: string;
2093
+ opacity?: string;
2094
+ filter?: string;
2095
+ cssFilter?: string;
2096
+ mixBlendMode?: string;
2097
+ clipPath?: string;
2098
+ mask?: string;
2099
+ /**
2100
+ * Lossless carrier for any `<metadata>` elements that appeared as
2101
+ * children of this group's source `<g>` element. Same semantics as
2102
+ * `ShapeMetadata.rawMetadata` / `DocumentMetadata.rawMetadata` — see
2103
+ * SVG 2 §5.8 (`<metadata>` can appear on any container).
2104
+ */
2105
+ rawMetadata?: string;
2106
+ }
2107
+ /** Serialized clip or mask group */
2108
+ interface SerializedClipMaskGroup {
2109
+ id: string;
2110
+ type: 'clip' | 'mask';
2111
+ /**
2112
+ * @deprecated Use `clipShapeIds` instead. Kept for backward compatibility
2113
+ * when reading older documents that used a single clip/mask shape.
2114
+ */
2115
+ clipShapeId?: string;
2116
+ /** IDs of shape(s) that form the clip/mask definition. */
2117
+ clipShapeIds: string[];
2118
+ /** IDs of the content shapes being clipped/masked. */
2119
+ contentShapeIds: string[];
2120
+ parentId: string | null;
2121
+ /**
2122
+ * Position of the clip/mask group among its parent container's children,
2123
+ * so that SVG document order (painting order) is preserved across
2124
+ * save / restore.
2125
+ */
2126
+ siblingIndex?: number;
2127
+ /**
2128
+ * Coordinate system for the `<mask>` bounds (`x`, `y`, `width`, `height`).
2129
+ * @see CSS Masking Module §9.1 — `maskUnits`
2130
+ * @default 'objectBoundingBox'
2131
+ */
2132
+ maskUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
2133
+ /**
2134
+ * Coordinate system for the **contents** of a `<mask>`.
2135
+ * @see CSS Masking Module §9.1 — `maskContentUnits`
2136
+ * @default 'userSpaceOnUse'
2137
+ */
2138
+ maskContentUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
2139
+ /**
2140
+ * Coordinate system for the contents of a `<clipPath>`.
2141
+ * @see CSS Masking Module §6.1 — `clipPathUnits`
2142
+ * @default 'userSpaceOnUse'
2143
+ */
2144
+ clipPathUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
2145
+ /**
2146
+ * Explicit mask bounds (`x`, `y`, `width`, `height`).
2147
+ * When omitted the browser defaults apply (−10% / 120%).
2148
+ */
2149
+ maskBounds?: {
2150
+ x: string;
2151
+ y: string;
2152
+ width: string;
2153
+ height: string;
2154
+ };
2155
+ /**
2156
+ * Whether the mask uses luminance or alpha channel.
2157
+ * @see CSS Masking Module §9.2 — `mask-type`
2158
+ * @default 'luminance'
2159
+ */
2160
+ maskType?: 'luminance' | 'alpha';
2161
+ /**
2162
+ * Raw SVG markup for imported mask/clip definitions that cannot be
2163
+ * decomposed into editor `Shape` objects (e.g. multi-element masks
2164
+ * with gradients, patterns, or nested groups). When present the
2165
+ * editor preserves the original `<mask>` / `<clipPath>` verbatim
2166
+ * and `clipShapeIds` may be empty.
2167
+ */
2168
+ rawDefinition?: string;
2169
+ }
2170
+
2171
+ /**
2172
+ * @svgsketch/core — Library (defs) types.
2173
+ *
2174
+ * A `LibraryDef` is any reusable element that lives in an SVG `<defs>` and is
2175
+ * referenced from shapes via `url(#id)`. The library is the authoritative store
2176
+ * for these definitions; shapes carry only ID references.
2177
+ *
2178
+ * Kinds covered here:
2179
+ * - symbol (SVG 2 §5.5, referenced by `<use href="#id">`)
2180
+ * - marker (SVG 2 §13.7, referenced by `marker-start/-mid/-end`)
2181
+ * - linear-gradient / radial-gradient (SVG 2 §14, referenced by fill/stroke)
2182
+ * - pattern (SVG 2 §14.3, referenced by fill/stroke)
2183
+ * - filter (CSS Filter Effects §Filter Property, referenced by `filter`)
2184
+ *
2185
+ * ClipPath, mask, and <style> are deliberately out of scope for this pass.
2186
+ */
2187
+
2188
+ /** Discriminator for the `LibraryDef` union. */
2189
+ type LibraryKind = 'symbol' | 'marker' | 'linear-gradient' | 'radial-gradient' | 'pattern' | 'filter';
2190
+ /**
2191
+ * Common fields shared by every kind of library def. ID prefix convention:
2192
+ * sym- / mkr- / grd- / pat- / flt-
2193
+ */
2194
+ interface LibraryDefBase {
2195
+ /** Unique identifier, prefixed by kind (see convention above). */
2196
+ id: string;
2197
+ /** Kind discriminator — required on every def. */
2198
+ kind: LibraryKind;
2199
+ /** Human-readable name shown in the library panel. */
2200
+ name: string;
2201
+ /** Base64 data-URI thumbnail, rendered by the kind's thumbnail generator. */
2202
+ thumbnail?: string;
2203
+ /**
2204
+ * Editor-shipped seed that isn't deletable, renamable, or user-editable
2205
+ * (today: built-in markers). Only set when the kind actually has built-ins.
2206
+ */
2207
+ builtIn?: boolean;
2208
+ /**
2209
+ * Original id from the imported source SVG. Runtime `id` is always a fresh
2210
+ * GUID; `sourceId` lets export restore human-friendly ids when uncontested.
2211
+ */
2212
+ sourceId?: string;
2213
+ }
2214
+ /**
2215
+ * Reusable component template. Shapes inside are edited via symbol isolation
2216
+ * mode and placed onto the canvas as `SymbolInstance` shapes (which emit as
2217
+ * `<use href="#id">` on export — SVG 2 §5.5).
2218
+ */
2219
+ interface SymbolLibraryDef extends LibraryDefBase {
2220
+ kind: 'symbol';
2221
+ /**
2222
+ * Source SVG element form for round-trip fidelity. Most symbols are
2223
+ * authored as `<symbol>` (SVG 2 §5.5.1); `<defs><g id="X"/>` referenced
2224
+ * by `<use href="#X"/>` is a legally distinct pattern that the editor
2225
+ * also models as a SymbolLibraryDef but must export as `<g>` to remain
2226
+ * spec-faithful — `<symbol>` would silently introduce viewport-
2227
+ * establishment (SVG 2 §5.5.2) and `overflow: hidden` defaulting that
2228
+ * the source `<g>` does not have. Default `'symbol'` for backward
2229
+ * compatibility with documents authored before this field existed.
2230
+ */
2231
+ defKind?: 'symbol' | 'group';
2232
+ viewBox: string;
2233
+ /**
2234
+ * Wrapper attributes from the source `<g id="X">` def root that apply to
2235
+ * the def's contents (transform, opacity, fill cascade, mask, filter,
2236
+ * clip-path). Re-emitted on the exported `<g id="X">` when `defKind === 'group'`
2237
+ * — `<symbol>` doesn't legally accept these attributes per SVG 2 §5.5.1.
2238
+ * Without this, `<use href="#X"/>` would silently render the children at
2239
+ * their unwrapped local coords / paint, losing every non-id attribute on
2240
+ * the source `<g>` def root.
2241
+ */
2242
+ wrapperAttrs?: Record<string, string>;
2243
+ /**
2244
+ * Default variant shapes. When `variantAxes` is present this represents the
2245
+ * variant where every axis is at its first value.
2246
+ */
2247
+ shapes: SerializedShape[];
2248
+ groups?: SerializedGroup[];
2249
+ /**
2250
+ * Ordered list of variant axes. The order is stable so variant keys can be
2251
+ * canonicalized as `axis1=val1,axis2=val2`.
2252
+ */
2253
+ variantAxes?: SerializedVariantAxis[];
2254
+ /** Non-default variant shape arrays keyed by canonical axis combination. */
2255
+ variants?: Record<string, SerializedShape[]>;
2256
+ /** Per-variant thumbnails keyed by canonical variant string. */
2257
+ variantThumbnails?: Record<string, string>;
2258
+ }
2259
+ /**
2260
+ * Vertex-attached graphic (arrowheads, dots, decorations). Referenced via
2261
+ * `marker-start` / `marker-mid` / `marker-end` on stroked shapes — SVG 2
2262
+ * §13.7.2 specifies each attribute accepts a single `<marker-ref>`.
2263
+ */
2264
+ interface MarkerLibraryDef extends LibraryDefBase {
2265
+ kind: 'marker';
2266
+ viewBox: string;
2267
+ /** X reference point — where the marker's tip aligns with the host vertex. */
2268
+ refX: number;
2269
+ refY: number;
2270
+ markerWidth: number;
2271
+ markerHeight: number;
2272
+ /**
2273
+ * `strokeWidth` scales with the host's stroke; `userSpaceOnUse` renders at
2274
+ * fixed size regardless of stroke.
2275
+ */
2276
+ markerUnits: 'strokeWidth' | 'userSpaceOnUse';
2277
+ /**
2278
+ * `auto` rotates to match path tangent; `auto-start-reverse` reverses the
2279
+ * start marker; a number is a fixed rotation in degrees.
2280
+ */
2281
+ orient: 'auto' | 'auto-start-reverse' | number;
2282
+ /**
2283
+ * Inner geometry (authoritative for user markers). Built-ins render from
2284
+ * the descriptor registry and carry `shapes: []`.
2285
+ */
2286
+ shapes: SerializedShape[];
2287
+ groups?: SerializedGroup[];
2288
+ /**
2289
+ * Animation tracks scoped to the marker's inner shapes. Emitted as SMIL
2290
+ * `<animate>` children of the exported `<marker>`.
2291
+ */
2292
+ animations?: SerializedAnimationTimeline['tracks'];
2293
+ }
2294
+ /**
2295
+ * Linear gradient def (SVG 2 §14.6). Referenced via `fill="url(#id)"` or
2296
+ * `stroke="url(#id)"`. Inner geometry is the existing `LinearGradient` shape,
2297
+ * minus the fields that live on `LibraryDefBase` (`id`, `sourceId`).
2298
+ */
2299
+ interface LinearGradientLibraryDef extends LibraryDefBase {
2300
+ kind: 'linear-gradient';
2301
+ gradient: Omit<LinearGradient, 'id' | 'sourceId'>;
2302
+ }
2303
+ /** Radial gradient def (SVG 2 §14.7). See `LinearGradientLibraryDef`. */
2304
+ interface RadialGradientLibraryDef extends LibraryDefBase {
2305
+ kind: 'radial-gradient';
2306
+ gradient: Omit<RadialGradient, 'id' | 'sourceId'>;
2307
+ }
2308
+ /**
2309
+ * Pattern def (SVG 2 §14.3). Subsumes today's `CustomPatternDef` (user-created
2310
+ * reusable tiles) and the per-shape `PatternFill` — both collapse into one
2311
+ * persisted representation keyed by `LibraryDefBase.id`.
2312
+ *
2313
+ * `customPatternId` is stripped because once the pattern IS the library entry,
2314
+ * the back-reference is redundant.
2315
+ */
2316
+ interface PatternLibraryDef extends LibraryDefBase {
2317
+ kind: 'pattern';
2318
+ pattern: Omit<PatternFill, 'id' | 'sourceId' | 'customPatternId'>;
2319
+ }
2320
+ /**
2321
+ * Filter def (CSS Filter Effects). Referenced via `filter="url(#id)"`. When a
2322
+ * shape chains multiple filters, the CSS `filter` property accepts a
2323
+ * space-separated list (`<filter-value-list>`) and composes them serially —
2324
+ * each url()'s input is the previous url()'s output.
2325
+ *
2326
+ * Filter region and unit attributes live on `<filter>` itself (per the spec),
2327
+ * so they move here from the per-shape state.
2328
+ */
2329
+ interface FilterLibraryDef extends LibraryDefBase {
2330
+ kind: 'filter';
2331
+ /** Ordered primitive chain (same editable model used per-shape today). */
2332
+ filters: ShapeFilter[];
2333
+ colorInterpolation?: 'auto' | 'sRGB' | 'linearRGB';
2334
+ filterUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
2335
+ primitiveUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
2336
+ x?: string;
2337
+ y?: string;
2338
+ width?: string;
2339
+ height?: string;
2340
+ }
2341
+ /** Discriminated union over `kind`. */
2342
+ type LibraryDef = SymbolLibraryDef | MarkerLibraryDef | LinearGradientLibraryDef | RadialGradientLibraryDef | PatternLibraryDef | FilterLibraryDef;
2343
+ /**
2344
+ * Narrow helper — picks the library-def type for a given kind. Useful for
2345
+ * `getByKind('symbol')` return types.
2346
+ */
2347
+ type LibraryDefOfKind<K extends LibraryKind> = Extract<LibraryDef, {
2348
+ kind: K;
2349
+ }>;
2350
+
2351
+ /**
2352
+ * Typed property interfaces for every node type in the scene graph.
2353
+ *
2354
+ * This is the **single source of truth** for shape property types across
2355
+ * the entire SVGSketch stack (editor, API worker, server renderer, etc.).
2356
+ *
2357
+ * Each shape type declares the exact set of properties it owns.
2358
+ * These interfaces drive:
2359
+ * - Compile-time type safety on `SceneNode.get()` / `.set()` calls
2360
+ * - The `NodeTypePropsMap` lookup used by `SceneNode.create()`
2361
+ * - Schema defaults and validators in the editor's `node-schema.ts`
2362
+ * - Serialization format for the `.svgs` document format
2363
+ */
2364
+
2365
+ interface CommonNodeProps {
2366
+ fillColor: string;
2367
+ borderColor: string;
2368
+ borderWidth: number;
2369
+ opacity: number;
2370
+ fillOpacity: number;
2371
+ strokeOpacity: number;
2372
+ rotation: number;
2373
+ skewX: number;
2374
+ skewY: number;
2375
+ customPivot: Point | null;
2376
+ locked: boolean;
2377
+ visible: boolean;
2378
+ fillType: string;
2379
+ fillGradient: unknown | null;
2380
+ strokeType: string;
2381
+ strokeGradient: unknown | null;
2382
+ fillRule: 'nonzero' | 'evenodd';
2383
+ strokeLinejoin: 'miter' | 'round' | 'bevel';
2384
+ strokeLinecap: 'butt' | 'round' | 'square';
2385
+ strokeMiterlimit: number;
2386
+ lineStyle: string;
2387
+ dashLength: number;
2388
+ gapLength: number;
2389
+ dashOffset: number;
2390
+ strokeDasharray: string | null;
2391
+ filters: unknown[];
2392
+ filterColorInterpolation: 'auto' | 'sRGB' | 'linearRGB' | null;
2393
+ filterUnits: 'userSpaceOnUse' | 'objectBoundingBox' | null;
2394
+ primitiveUnits: 'userSpaceOnUse' | 'objectBoundingBox' | null;
2395
+ filterX: string | null;
2396
+ filterY: string | null;
2397
+ filterWidth: string | null;
2398
+ filterHeight: string | null;
2399
+ rawTransform: string | null;
2400
+ ancestorTransform: number[] | null;
2401
+ metadata: unknown | null;
2402
+ cssClipPath: string | null;
2403
+ cssMaskProperties: Record<string, string> | null;
2404
+ groupId: string | null;
2405
+ }
2406
+ type CornerShapeValue = 'round' | 'notch' | 'bevel' | 'scoop';
2407
+ interface RectangleNodeProps extends CommonNodeProps {
2408
+ x: number;
2409
+ y: number;
2410
+ width: number;
2411
+ height: number;
2412
+ cornerRadius: number;
2413
+ cornerShape: CornerShapeValue;
2414
+ cornerMode: 'uniform' | 'non-uniform';
2415
+ cornerRadiusTL: number;
2416
+ cornerRadiusTR: number;
2417
+ cornerRadiusBL: number;
2418
+ cornerRadiusBR: number;
2419
+ cornerShapeTL: CornerShapeValue;
2420
+ cornerShapeTR: CornerShapeValue;
2421
+ cornerShapeBL: CornerShapeValue;
2422
+ cornerShapeBR: CornerShapeValue;
2423
+ }
2424
+ type SquareNodeProps = RectangleNodeProps;
2425
+ interface CircleNodeProps extends CommonNodeProps {
2426
+ x: number;
2427
+ y: number;
2428
+ radius: number;
2429
+ }
2430
+ interface EllipseNodeProps extends CommonNodeProps {
2431
+ x: number;
2432
+ y: number;
2433
+ rx: number;
2434
+ ry: number;
2435
+ }
2436
+ type LineEndpointValue = 'none' | 'arrow' | 'open-arrow' | 'circle' | 'diamond' | 'square';
2437
+ interface LineNodeProps extends CommonNodeProps {
2438
+ x1: number;
2439
+ y1: number;
2440
+ x2: number;
2441
+ y2: number;
2442
+ startEndpoint: LineEndpointValue;
2443
+ endEndpoint: LineEndpointValue;
2444
+ }
2445
+ interface TextNodeProps extends CommonNodeProps {
2446
+ x: number;
2447
+ y: number;
2448
+ width: number;
2449
+ height: number;
2450
+ textX: number;
2451
+ textY: number;
2452
+ fontSize: number;
2453
+ text: string;
2454
+ fontFamily: string;
2455
+ fontWeight: string;
2456
+ fontStyle: string;
2457
+ textDecoration: Record<string, boolean>;
2458
+ textTransform: string;
2459
+ baselineShift: string;
2460
+ dominantBaseline: string;
2461
+ writingMode: string;
2462
+ textAnchor: string;
2463
+ letterSpacing: number;
2464
+ wordSpacing: number;
2465
+ lineHeight: number;
2466
+ inlineSize: number;
2467
+ overflowWrap: string;
2468
+ whiteSpace: string;
2469
+ textDirection: string;
2470
+ unicodeBidi: string;
2471
+ scaleX: number;
2472
+ scaleY: number;
2473
+ scaleAnchor: Point | null;
2474
+ useRichText: boolean;
2475
+ richTextData: unknown | null;
2476
+ /**
2477
+ * Per-glyph positioning data — see `SerializedShape['state'].charOffsets`
2478
+ * in `serialized.ts` for full semantics. Legacy `{x, y, rotate}` form
2479
+ * accepted on read for back-compat with pre-spec-aligned saves.
2480
+ */
2481
+ charOffsets: ({
2482
+ x: number | null;
2483
+ y: number | null;
2484
+ dx: number;
2485
+ dy: number;
2486
+ rotate: number;
2487
+ } | {
2488
+ x: number;
2489
+ y: number;
2490
+ rotate: number;
2491
+ })[] | null;
2492
+ fontVariationSettings: Record<string, number>;
2493
+ isTextPath: boolean;
2494
+ textPathPoints: unknown[] | null;
2495
+ textPathStartOffset: number;
2496
+ textPathSide: 'left' | 'right';
2497
+ shapeInsideRef: string | null;
2498
+ shapePadding: number;
2499
+ }
2500
+ interface ImageNodeProps extends CommonNodeProps {
2501
+ x: number;
2502
+ y: number;
2503
+ width: number;
2504
+ height: number;
2505
+ href: string;
2506
+ originalWidth: number;
2507
+ originalHeight: number;
2508
+ preserveAspectRatio: boolean;
2509
+ imageOpacity: number;
2510
+ }
2511
+ interface PathNodeProps extends CommonNodeProps {
2512
+ x: number;
2513
+ y: number;
2514
+ width: number;
2515
+ height: number;
2516
+ pathPoints: unknown[];
2517
+ pathArcParams: unknown[];
2518
+ pathControlBounds: {
2519
+ x: number;
2520
+ y: number;
2521
+ width: number;
2522
+ height: number;
2523
+ } | null;
2524
+ startEndpoint: LineEndpointValue;
2525
+ endEndpoint: LineEndpointValue;
2526
+ }
2527
+ interface PolylineNodeProps extends CommonNodeProps {
2528
+ x: number;
2529
+ y: number;
2530
+ width: number;
2531
+ height: number;
2532
+ polylinePoints: Point[];
2533
+ polylineClosed: boolean;
2534
+ }
2535
+ interface PolygonBaseNodeProps extends CommonNodeProps {
2536
+ cx: number;
2537
+ cy: number;
2538
+ radius: number;
2539
+ cornerRadius: number;
2540
+ shiftAngle: number;
2541
+ }
2542
+ interface TriangleNodeProps extends PolygonBaseNodeProps {
2543
+ sides: 3;
2544
+ }
2545
+ interface NGonNodeProps extends PolygonBaseNodeProps {
2546
+ sides: number;
2547
+ }
2548
+ interface StarNodeProps extends PolygonBaseNodeProps {
2549
+ arms: number;
2550
+ innerRadiusPercent: number;
2551
+ }
2552
+ interface CrossNodeProps extends PolygonBaseNodeProps {
2553
+ armWidthPercent: number;
2554
+ }
2555
+ interface RingNodeProps extends PolygonBaseNodeProps {
2556
+ innerRadiusPercent: number;
2557
+ }
2558
+ interface SpiralNodeProps extends PolygonBaseNodeProps {
2559
+ turns: number;
2560
+ thicknessPercent: number;
2561
+ spiralDirection: number;
2562
+ }
2563
+ interface GearNodeProps extends PolygonBaseNodeProps {
2564
+ teeth: number;
2565
+ toothDepthPercent: number;
2566
+ holeRadiusPercent: number;
2567
+ }
2568
+ interface ArrowNodeProps extends PolygonBaseNodeProps {
2569
+ headWidthPercent: number;
2570
+ headLengthPercent: number;
2571
+ shaftWidthPercent: number;
1677
2572
  }
1678
- /**
1679
- * A reusable `<marker>` definition (SVG 2 §11.6). Markers are vertex-attached
1680
- * graphics — arrowheads, vertex dots, decorations — referenced via
1681
- * `marker-start` / `marker-mid` / `marker-end` attributes on stroked shapes.
1682
- *
1683
- * The browser handles per-vertex positioning, scaling (via `markerUnits`),
1684
- * and orientation (via `orient`, including tangent-aware `auto` mode on
1685
- * curved paths). MarkerManager only maintains the DOM `<defs>` entries in
1686
- * sync with this serialized state.
1687
- *
1688
- * Simpler than `SerializedSymbolDef` — markers have no variants, no instance
1689
- * overrides, and no placed instances (they attach via attribute references).
1690
- */
1691
- interface SerializedMarkerDef {
1692
- /**
1693
- * Unique identifier.
1694
- * - Built-in markers use stable ids: `mkr-builtin-arrow`, `mkr-builtin-open-arrow`,
1695
- * `mkr-builtin-circle`, `mkr-builtin-diamond`, `mkr-builtin-square`.
1696
- * - User-created markers use `mkr-<guid>`.
1697
- */
1698
- id: string;
1699
- /** Human-readable name shown in the markers panel. */
1700
- name: string;
1701
- /** SVG viewBox string ("minX minY width height"). */
1702
- viewBox: string;
1703
- /** X reference point — where the marker's "tip" aligns with the host vertex. */
1704
- refX: number;
1705
- refY: number;
1706
- markerWidth: number;
1707
- markerHeight: number;
1708
- /**
1709
- * `strokeWidth` scales the marker with the host's stroke-width (default,
1710
- * typical for arrows). `userSpaceOnUse` renders at fixed size regardless
1711
- * of stroke.
1712
- */
1713
- markerUnits: 'strokeWidth' | 'userSpaceOnUse';
1714
- /**
1715
- * `auto` rotates to match the path tangent at each vertex.
1716
- * `auto-start-reverse` reverses the start marker (so arrowheads don't
1717
- * point inward at path starts). A number is a fixed rotation in degrees.
1718
- */
1719
- orient: 'auto' | 'auto-start-reverse' | number;
1720
- /**
1721
- * Inner geometry. For user markers this is the authoritative source —
1722
- * edited via isolation mode and re-rendered into the DOM `<marker>` child.
1723
- * For built-ins this is `[]` in v1; built-ins render from the descriptor
1724
- * registry (`getMarkerDescriptors()`) and are not editable.
1725
- */
1726
- shapes: SerializedShape[];
1727
- /** Groups within the marker (mirrors `SerializedSymbolDef.groups`). */
1728
- groups?: SerializedGroup[];
1729
- /** Base64 data-URI thumbnail for the markers panel. */
1730
- thumbnail?: string;
1731
- /**
1732
- * Animation tracks scoped to the marker's inner shapes. Each track's
1733
- * `shapeId` references an id in `shapes`. During isolation editing these
1734
- * tracks are merged into the document timeline (tagged `scope:
1735
- * 'marker:<id>'`) so the user can edit them; on save they're extracted
1736
- * back here. On SVG export the tracks render as SMIL `<animate>` elements
1737
- * inside the `<marker>` DOM so they play at every attached vertex.
1738
- */
1739
- animations?: SerializedAnimationTimeline['tracks'];
1740
- /**
1741
- * True for editor-shipped built-ins (arrow, open-arrow, circle, diamond,
1742
- * square). Built-ins are non-deletable, non-renamable, and non-editable.
1743
- */
1744
- builtIn?: boolean;
2573
+ interface SymbolInstanceNodeProps extends CommonNodeProps {
2574
+ x: number;
2575
+ y: number;
2576
+ width: number;
2577
+ height: number;
2578
+ symbolId: string;
1745
2579
  }
1746
- interface SerializedGroup {
1747
- id: string;
1748
- parentId: string | null;
1749
- /** CSS transform-origin value (e.g. "50px 50px") for group animations */
1750
- transformOrigin?: string;
1751
- /**
1752
- * Zero-based position of this group among its parent container's
1753
- * children (including both sibling groups and sibling shape nodes).
1754
- * Used during restoration to correctly interleave groups and shapes
1755
- * so that SVG document order (painting order) is preserved.
1756
- */
1757
- siblingIndex?: number;
1758
- /** Plugin that owns this group (e.g. 'svgsketch-charts') */
1759
- pluginId?: string;
1760
- /** Serialized plugin-specific state (JSON string) */
1761
- pluginData?: string;
1762
- /** Additional custom data-* attributes set by plugins */
1763
- attributes?: Record<string, string>;
1764
- fill?: string;
1765
- fillOpacity?: string;
1766
- strokeOpacity?: string;
1767
- opacity?: string;
1768
- filter?: string;
1769
- cssFilter?: string;
1770
- mixBlendMode?: string;
1771
- clipPath?: string;
1772
- mask?: string;
2580
+ interface GroupNodeProps {
2581
+ groupId: string | null;
1773
2582
  }
1774
- /** Serialized clip or mask group */
1775
- interface SerializedClipMaskGroup {
1776
- id: string;
1777
- type: 'clip' | 'mask';
1778
- /**
1779
- * @deprecated Use `clipShapeIds` instead. Kept for backward compatibility
1780
- * when reading older documents that used a single clip/mask shape.
1781
- */
1782
- clipShapeId?: string;
1783
- /** IDs of shape(s) that form the clip/mask definition. */
1784
- clipShapeIds: string[];
1785
- /** IDs of the content shapes being clipped/masked. */
1786
- contentShapeIds: string[];
1787
- parentId: string | null;
1788
- /**
1789
- * Position of the clip/mask group among its parent container's children,
1790
- * so that SVG document order (painting order) is preserved across
1791
- * save / restore.
1792
- */
1793
- siblingIndex?: number;
1794
- /**
1795
- * Coordinate system for the `<mask>` bounds (`x`, `y`, `width`, `height`).
1796
- * @see CSS Masking Module §9.1 — `maskUnits`
1797
- * @default 'objectBoundingBox'
1798
- */
1799
- maskUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1800
- /**
1801
- * Coordinate system for the **contents** of a `<mask>`.
1802
- * @see CSS Masking Module §9.1 — `maskContentUnits`
1803
- * @default 'userSpaceOnUse'
1804
- */
1805
- maskContentUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1806
- /**
1807
- * Coordinate system for the contents of a `<clipPath>`.
1808
- * @see CSS Masking Module §6.1 — `clipPathUnits`
1809
- * @default 'userSpaceOnUse'
1810
- */
1811
- clipPathUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
1812
- /**
1813
- * Explicit mask bounds (`x`, `y`, `width`, `height`).
1814
- * When omitted the browser defaults apply (−10% / 120%).
1815
- */
1816
- maskBounds?: {
1817
- x: string;
1818
- y: string;
1819
- width: string;
1820
- height: string;
1821
- };
1822
- /**
1823
- * Whether the mask uses luminance or alpha channel.
1824
- * @see CSS Masking Module §9.2 — `mask-type`
1825
- * @default 'luminance'
1826
- */
1827
- maskType?: 'luminance' | 'alpha';
1828
- /**
1829
- * Raw SVG markup for imported mask/clip definitions that cannot be
1830
- * decomposed into editor `Shape` objects (e.g. multi-element masks
1831
- * with gradients, patterns, or nested groups). When present the
1832
- * editor preserves the original `<mask>` / `<clipPath>` verbatim
1833
- * and `clipShapeIds` may be empty.
1834
- */
1835
- rawDefinition?: string;
2583
+ type DocumentNodeProps = Record<string, never>;
2584
+ /**
2585
+ * Maps each node type string to its typed property interface.
2586
+ * Used by `SceneNode.create()` for compile-time type safety.
2587
+ */
2588
+ interface NodeTypePropsMap {
2589
+ rectangle: RectangleNodeProps;
2590
+ square: SquareNodeProps;
2591
+ circle: CircleNodeProps;
2592
+ ellipse: EllipseNodeProps;
2593
+ line: LineNodeProps;
2594
+ text: TextNodeProps;
2595
+ image: ImageNodeProps;
2596
+ path: PathNodeProps;
2597
+ polyline: PolylineNodeProps;
2598
+ triangle: TriangleNodeProps;
2599
+ ngon: NGonNodeProps;
2600
+ star: StarNodeProps;
2601
+ cross: CrossNodeProps;
2602
+ ring: RingNodeProps;
2603
+ spiral: SpiralNodeProps;
2604
+ gear: GearNodeProps;
2605
+ arrow: ArrowNodeProps;
2606
+ 'symbol-instance': SymbolInstanceNodeProps;
2607
+ group: GroupNodeProps;
2608
+ document: DocumentNodeProps;
1836
2609
  }
2610
+ /** Union of all node prop types. */
2611
+ type AnyNodeProps = RectangleNodeProps | SquareNodeProps | CircleNodeProps | EllipseNodeProps | LineNodeProps | TextNodeProps | ImageNodeProps | PathNodeProps | PolylineNodeProps | TriangleNodeProps | NGonNodeProps | StarNodeProps | CrossNodeProps | RingNodeProps | SpiralNodeProps | GearNodeProps | ArrowNodeProps | SymbolInstanceNodeProps | GroupNodeProps | DocumentNodeProps;
1837
2612
 
1838
2613
  /**
1839
2614
  * @svgsketch/core — Schema migrations.
@@ -1870,17 +2645,6 @@ interface SerializedClipMaskGroup {
1870
2645
  * It must return the transformed snapshot (typically the same object).
1871
2646
  */
1872
2647
  type Migration = (snapshot: HistorySnapshot) => HistorySnapshot;
1873
- /**
1874
- * Registry of schema migrations, keyed by **source** version.
1875
- *
1876
- * Entry `N: fn` means "`fn` transforms a version-N snapshot into a
1877
- * version-(N+1) snapshot." The dispatcher in {@link migrateSnapshot}
1878
- * walks this registry from the snapshot's current version up to
1879
- * {@link CURRENT_SCHEMA_VERSION}.
1880
- *
1881
- * This object is exported so tests (and diagnostic tooling) can read
1882
- * the registered migrations, but it should not be mutated at runtime.
1883
- */
1884
2648
  declare const MIGRATIONS: Readonly<Record<number, Migration>>;
1885
2649
  /**
1886
2650
  * Migrate a snapshot from any older schema version to the current version.
@@ -2239,6 +3003,28 @@ declare function renderToSvg(snapshot: HistorySnapshot, options?: RenderOptions)
2239
3003
  * @packageDocumentation
2240
3004
  */
2241
3005
 
3006
+ /**
3007
+ * Render a single `FilterPrimitive` to its SVG element string.
3008
+ *
3009
+ * Walks every modeled spec attribute and re-emits it. Author-preserved
3010
+ * attributes (e.g. <number-optional-number> spellings, kernelMatrix
3011
+ * whitespace) are stored as strings on the primitive and emitted verbatim,
3012
+ * so import → render produces semantically equivalent output.
3013
+ *
3014
+ * `unknownAttrs` are emitted last (alphabetised) so re-export is stable.
3015
+ * `animations` children are appended inside the element.
3016
+ */
3017
+ declare function renderFilterPrimitive(p: FilterPrimitive): string;
3018
+ /**
3019
+ * Render an `SvgPrimitiveChainFilter` as a complete `<filter>` element.
3020
+ *
3021
+ * Wrapper attributes are author-faithful: omitted ⇒ unset on the element ⇒
3022
+ * UA spec defaults apply (filterUnits=objectBoundingBox, primitiveUnits=
3023
+ * userSpaceOnUse, region -10%/-10%/120%/120%, color-interpolation-filters=
3024
+ * linearRGB). The chain is emitted in document order with no synthetic
3025
+ * `in`/`result` rewriting.
3026
+ */
3027
+ declare function renderSvgPrimitiveChainFilter(filterId: string, f: SvgPrimitiveChainFilter): string;
2242
3028
  /**
2243
3029
  * Render SVG filter primitive string(s) for a single filter.
2244
3030
  *
@@ -2260,14 +3046,25 @@ declare function renderFilterPrimitivesForType(filter: ShapeFilter, input: strin
2260
3046
  /**
2261
3047
  * Generate `<filter>` definition strings for all shapes that have filters.
2262
3048
  *
3049
+ * Phase 4: filters are library-first. Each distinct `filterLibraryIds`
3050
+ * entry emits exactly one `<filter>` in the output — two shapes sharing
3051
+ * the same library filter id produce one `<filter>`, not two. Falls back
3052
+ * to the legacy `filter-${shape.id}` id when a shape has inline filters
3053
+ * but no library ids set (shapes that haven't re-serialized since the
3054
+ * migration, or callers working against an in-memory object).
3055
+ *
2263
3056
  * @returns Concatenated `<filter>` elements to include in `<defs>`.
2264
3057
  */
2265
3058
  declare function renderFilterDefs(shapes: SerializedShape[]): string;
2266
3059
  /**
2267
3060
  * Get the `filter="url(#...)"` attribute value for a shape, or empty string
2268
3061
  * if the shape has no enabled filters.
3062
+ *
3063
+ * Phase 4: reads from `filterLibraryIds` when set, joining multiple ids as
3064
+ * a space-separated `<filter-value-list>` (CSS Filter Effects §Filter
3065
+ * Property). Falls back to the legacy shape-derived id for unmigrated input.
2269
3066
  */
2270
- declare function filterAttr(shapeId: string, filters: ShapeFilter[] | undefined): string;
3067
+ declare function filterAttr(shapeId: string, filters: ShapeFilter[] | undefined, filterLibraryIds?: string[]): string;
2271
3068
 
2272
3069
  /**
2273
3070
  * Shape renderers — convert SerializedShape → SVG element string.
@@ -2287,6 +3084,31 @@ declare function renderImage(shape: SerializedShape): string;
2287
3084
  declare function renderPolygonShape(shape: SerializedShape): string;
2288
3085
  /** Render any SerializedShape to an SVG element string. */
2289
3086
  declare function renderShape(shape: SerializedShape): string;
3087
+ /**
3088
+ * Walk shapes to find referenced marker ids. Returns two sets:
3089
+ * - `ids`: raw marker ids from `state.markerStart` / `markerMid` /
3090
+ * `markerEnd` — can be built-in ids (`mkr-builtin-arrow`,
3091
+ * `line-marker-arrow`) or user marker ids.
3092
+ * - `legacyEndpoints`: endpoint names from `state.startEndpoint` /
3093
+ * `endEndpoint` (e.g. `'arrow'`, `'circle'`). Lines emit these as a
3094
+ * shortcut to built-in markers without explicit `marker-*` attrs.
3095
+ */
3096
+ interface MarkerReferenceSets {
3097
+ ids: Set<string>;
3098
+ legacyEndpoints: Set<string>;
3099
+ }
3100
+ /**
3101
+ * Emit only built-in marker `<marker>` definitions referenced by a shape
3102
+ * collection. Split out of `renderMarkerDefs` so the library-first
3103
+ * pipeline can compose built-in handling with
3104
+ * `renderReferencedLibraryDefs` (which covers user-authored markers via
3105
+ * `snapshot.library`).
3106
+ *
3107
+ * Takes a pre-collected `MarkerReferenceSets` so callers can avoid walking
3108
+ * shapes twice when they need both the reference sets and the built-in
3109
+ * defs.
3110
+ */
3111
+ declare function renderBuiltinMarkerDefs(referenced: MarkerReferenceSets | SerializedShape[]): string;
2290
3112
 
2291
3113
  /**
2292
3114
  * Pure geometry functions for computing shape vertices and paths.
@@ -2535,6 +3357,95 @@ declare function getBuiltInMarkerDefs(): SerializedMarkerDef[];
2535
3357
  */
2536
3358
  declare function renderAnimationElements(timeline: SerializedAnimationTimeline): Map<string, string[]>;
2537
3359
 
3360
+ /**
3361
+ * Library renderers — convert `LibraryDef` entries into SVG `<defs>` strings.
3362
+ *
3363
+ * This is the headless/string-based renderer for library defs. The editor's
3364
+ * live `<defs>` rendering is handled by the kind-specific managers
3365
+ * (SymbolManager, MarkerManager, GradientManager, FilterManager) writing D3
3366
+ * DOM nodes; this module is the equivalent path for the CLI/SDK export pipe.
3367
+ *
3368
+ * Implementations delegate to the existing per-shape renderers where
3369
+ * possible — library defs carry the same render-affecting data as the
3370
+ * inline payloads those renderers were built for, with `LibraryDefBase`
3371
+ * metadata (id, name, thumbnail) peeled off at the outer call.
3372
+ *
3373
+ * @packageDocumentation
3374
+ */
3375
+
3376
+ /**
3377
+ * Deterministic emission order for `<defs>` contents. Put paint servers
3378
+ * (gradients, patterns) and filters **before** symbols/markers so that when a
3379
+ * symbol or marker's inner shapes reference a library paint or filter by
3380
+ * `url(#id)`, the forward reference resolves in parsers that do a single
3381
+ * forward pass.
3382
+ *
3383
+ * This matches the plan's export ordering rule: symbols and markers can
3384
+ * reference any other library kind, but not vice versa.
3385
+ */
3386
+ declare const LIBRARY_EMIT_ORDER: readonly LibraryKind[];
3387
+ /** Top-level dispatch. Picks the right kind-renderer for a library def. */
3388
+ declare function renderLibraryDef(def: LibraryDef): string;
3389
+ declare function renderSymbolLibraryDef(def: SymbolLibraryDef): string;
3390
+ declare function renderMarkerLibraryDef(def: MarkerLibraryDef): string;
3391
+ declare function renderLinearGradientLibraryDef(def: LinearGradientLibraryDef): string;
3392
+ declare function renderRadialGradientLibraryDef(def: RadialGradientLibraryDef): string;
3393
+ declare function renderPatternLibraryDef(def: PatternLibraryDef): string;
3394
+ declare function renderFilterLibraryDef(def: FilterLibraryDef): string;
3395
+ /**
3396
+ * Render every library def as a single `<defs>`-body string, in the
3397
+ * canonical order defined by `LIBRARY_EMIT_ORDER`. Useful for callers that
3398
+ * want to emit the entire library regardless of which defs are actually
3399
+ * referenced — the editor's export finalizer uses a reference-walker
3400
+ * instead, but standalone SVG producers (e.g. CLI fixture generation) may
3401
+ * prefer this unconditional emission.
3402
+ */
3403
+ declare function renderLibraryDefs(defs: readonly LibraryDef[]): string;
3404
+ /**
3405
+ * Collect every library-def id referenced by a shape collection. Covers
3406
+ * all the ways a shape points at a library entry:
3407
+ *
3408
+ * - `fillLibraryId` / `strokeLibraryId` (gradient / pattern paint servers)
3409
+ * - `filterLibraryIds[]` (filter chain)
3410
+ * - `markerStart` / `markerMid` / `markerEnd` (vertex markers)
3411
+ * - `symbolId` (symbol instances)
3412
+ *
3413
+ * Ids for built-in markers (e.g. `mkr-builtin-arrow`, `line-marker-arrow`)
3414
+ * are included in the result — callers that emit built-ins from the
3415
+ * descriptor registry should still look here for the reference signal.
3416
+ *
3417
+ * Does NOT include `url(#...)` strings parsed out of inline fill/stroke
3418
+ * CSS text — the library-first pipeline assumes shapes set `fillLibraryId`
3419
+ * explicitly when they reference a library def.
3420
+ */
3421
+ declare function collectReferencedLibraryIds(shapes: readonly SerializedShape[]): Set<string>;
3422
+ /**
3423
+ * Library-first `<defs>` emission: walks shapes and emits one `<defs>`
3424
+ * entry per unique paint-server / filter / user-marker referenced by the
3425
+ * scene. Built-in markers (which live in the descriptor registry, not
3426
+ * `snapshot.library`) are NOT emitted by this function — callers should
3427
+ * compose with `renderBuiltinMarkerDefs` or similar.
3428
+ *
3429
+ * Two input sources are merged, with library-first precedence:
3430
+ *
3431
+ * 1. **Library refs**: shapes set `fillLibraryId`, `strokeLibraryId`,
3432
+ * `filterLibraryIds`, `markerStart/Mid/End`, or `symbolId` pointing
3433
+ * into `library`. The library entry is authoritative for the def.
3434
+ * 2. **Legacy inline payloads**: shapes with `fillGradient` /
3435
+ * `strokeGradient` / `filters[]` but NO matching library ref. A
3436
+ * transient library def is synthesized from the inline data on the
3437
+ * fly so renders remain correct for snapshots that bypass the
3438
+ * migrator (e.g. older tests, hand-built snapshots via the SDK).
3439
+ *
3440
+ * Dedup is by emitted id. A shape that has both a library ref AND an
3441
+ * inline payload with the same id emits the library entry once.
3442
+ *
3443
+ * Defs are emitted in `LIBRARY_EMIT_ORDER` so cross-kind references
3444
+ * (e.g. a `<symbol>` whose inner shapes reference a gradient) resolve
3445
+ * during single-pass parsing.
3446
+ */
3447
+ declare function renderReferencedLibraryDefs(shapes: readonly SerializedShape[], library: readonly LibraryDef[]): string;
3448
+
2538
3449
  /**
2539
3450
  * Code generation dispatcher — routes to format-specific generators.
2540
3451
  */
@@ -2836,6 +3747,26 @@ declare abstract class ShapeBuilder<T extends ShapeBuilder<T>> {
2836
3747
  locked(value?: boolean): T;
2837
3748
  /** Set visibility. */
2838
3749
  visible(value?: boolean): T;
3750
+ /**
3751
+ * Set the shape's structural role in the exported SVG.
3752
+ *
3753
+ * - `'normal'` (default) — rendered inline in document order.
3754
+ * - `'motionOnly'` — emitted inside `<defs>` as an `<mpath>` reference
3755
+ * target and NOT rendered. Pair with `Track.motionPathRef(shapeId,
3756
+ * 'curveTemplate')` so the animation's `<mpath>` resolves to this
3757
+ * shape's origin-normalized `d`. The exporter automatically
3758
+ * translates the shape's `d` so its first moveto is at `M 0,0`,
3759
+ * the canonical "curve template" form that lets multiple animations
3760
+ * share one motion-path `<defs>` entry.
3761
+ *
3762
+ * @see https://svgwg.org/specs/animations/#MPathElement
3763
+ */
3764
+ displayMode(mode: 'normal' | 'motionOnly'): T;
3765
+ /**
3766
+ * Convenience alias for `.displayMode('motionOnly')` — marks this shape
3767
+ * as an `<mpath>` reference target (not rendered; placed in `<defs>`).
3768
+ */
3769
+ motionOnly(): T;
2839
3770
  /** Set a solid fill color. */
2840
3771
  fill(color: string, opacity?: number): T;
2841
3772
  /** Set fill to none (transparent). */
@@ -3242,26 +4173,26 @@ declare class Arrow extends PolygonShapeBuilder<Arrow> {
3242
4173
  /** Set the arrow shaft width as a percent (0–100). */
3243
4174
  shaftWidth(percent: number): Arrow;
3244
4175
  }
3245
- declare class Spline extends ShapeBuilder<Spline> {
3246
- constructor(points?: (Point | SplinePoint)[]);
4176
+ declare class Path extends ShapeBuilder<Path> {
4177
+ constructor(points?: (Point | PathPoint)[]);
3247
4178
  /** Set the spline points. */
3248
- points(pts: (Point | SplinePoint)[]): Spline;
4179
+ points(pts: (Point | PathPoint)[]): Path;
3249
4180
  /** Add a point to the spline. */
3250
- addPoint(x: number, y: number): Spline;
4181
+ addPoint(x: number, y: number): Path;
3251
4182
  /** Set the curve type. */
3252
- curveType(type: SplineCurveType): Spline;
4183
+ curveType(type: PathCurveType): Path;
3253
4184
  /** Set whether the spline is closed. */
3254
- closed(value?: boolean): Spline;
4185
+ closed(value?: boolean): Path;
3255
4186
  /** Set the tension for Catmull-Rom curves (0–1). */
3256
- tension(value: number): Spline;
4187
+ tension(value: number): Path;
3257
4188
  /** Set arc params for ARC curve type. */
3258
- arcParams(params: ArcParams$1[]): Spline;
4189
+ arcParams(params: ArcParams$1[]): Path;
3259
4190
  /** Set the start endpoint marker. */
3260
- markerStart(style: EndpointStyle): Spline;
4191
+ markerStart(style: EndpointStyle): Path;
3261
4192
  /** Set the end endpoint marker. */
3262
- markerEnd(style: EndpointStyle): Spline;
4193
+ markerEnd(style: EndpointStyle): Path;
3263
4194
  /** Convenience: set both markers. */
3264
- markers(start: EndpointStyle, end: EndpointStyle): Spline;
4195
+ markers(start: EndpointStyle, end: EndpointStyle): Path;
3265
4196
  }
3266
4197
  declare class Polyline extends ShapeBuilder<Polyline> {
3267
4198
  constructor(points?: Point[]);
@@ -3365,6 +4296,42 @@ declare class Track {
3365
4296
  locked(): Track;
3366
4297
  /** Set an SVG path for motion-path animation. */
3367
4298
  motionPath(path: string): Track;
4299
+ /**
4300
+ * Link this motion-path track to another shape's geometry as an
4301
+ * `<mpath href="#shapeId"/>` reference. The track's `motionPath` is
4302
+ * expected to have been set (or will be) to the referenced shape's
4303
+ * path data — the two fields together model SVG Animations §19.2
4304
+ * semantics where `<mpath>` supersedes inline `path=` on export.
4305
+ *
4306
+ * The `mode` controls how the reference is interpreted:
4307
+ * - `'trackShape'` (default) — the motion path is displacement-
4308
+ * relative to the animated element's center, so playback and
4309
+ * editor overlay render on top of the referenced shape's absolute
4310
+ * position. Exports as inline `path=` (spec-correct).
4311
+ * - `'curveTemplate'` — the motion path's first point is `M 0,0`,
4312
+ * matching how `<mpath>` semantics want a reusable curve-template.
4313
+ * Exports as `<mpath href="#shapeId"/>` pointing at a `<defs>` path
4314
+ * with the same origin-normalized `d` — reusable across animations.
4315
+ *
4316
+ * Pair with `.motionPath(d)` where `d` is in the form the mode expects:
4317
+ * absolute-minus-element-center for trackShape, origin-normalized for
4318
+ * curveTemplate.
4319
+ *
4320
+ * @example
4321
+ * ```ts
4322
+ * const curve = new Path(...).id('curve');
4323
+ * doc.add(curve);
4324
+ *
4325
+ * const track = new Track('rect-1', 'pathMotion')
4326
+ * .motionPath('M0,0 C 50,-100 150,-100 200,0') // origin-normalized
4327
+ * .motionPathRef('curve', 'curveTemplate') // emits <mpath href="#curve"/>
4328
+ * .keyframe(0, 0)
4329
+ * .keyframe(3, 1);
4330
+ * ```
4331
+ *
4332
+ * @see https://svgwg.org/specs/animations/#MPathElement
4333
+ */
4334
+ motionPathRef(shapeId: string, mode?: 'trackShape' | 'curveTemplate'): Track;
3368
4335
  /**
3369
4336
  * Set the begin trigger for this track.
3370
4337
  *
@@ -3784,4 +4751,4 @@ declare class Document {
3784
4751
  private _ensureMetadata;
3785
4752
  }
3786
4753
 
3787
- 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 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, type LicenseType, type LightSource, Line, type LineEndpointValue, type LineNodeProps, type LinearEasingPoint, type LinearGradient, LinearGradientBuilder, type LinkTarget, MARKER_HEIGHT, MARKER_VIEWBOX, MARKER_WIDTH, MAX_COORDINATE_PRECISION, MIGRATIONS, type MarkerDescriptor, 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 PatternParams, type PatternSvgContentResult, type PatternType, type PixelateFilter, type Point, type PointLightFilter, type PolygonBaseNodeProps, Polyline, type PolylineNodeProps, type RadialGradient, RadialGradientBuilder, 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 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, 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, renderCircle, renderEllipse, renderFilterDefs, renderFilterPrimitivesForType, renderImage, renderLine, renderPolygonShape, renderPolyline, renderRectangle, renderShape, renderSpline, renderText, renderToSvg, roundCoord, roundNumberString, roundSerializedShape, roundSnapshot, stringifyDocument, substituteString, substituteVariables, validateSnapshot, verticesToPath };
4754
+ 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 BaseFilterPrimitive, 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 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, 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, 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, type SharpenFilter, type SpecularLightingFilter, Spiral, type SpiralNodeProps, type SpotLightFilter, Square, type SquareNodeProps, Star, type StarNodeProps, type StepPosition, type StepsParams, type StringifyOptions, type StrokeType, type SvgPrimitiveChainFilter, 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, 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 };