@pixerate/editor 0.35.0 → 0.36.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.
@@ -19,6 +19,22 @@ interface Vec2 {
19
19
  * - `symmetric`: handles stay on one line with equal lengths.
20
20
  */
21
21
  type VectorAnchorType = 'corner' | 'smooth' | 'symmetric';
22
+ /**
23
+ * Live corner shapes: `round` (an arc tangent to both sides), `inverted` (an arc centred on
24
+ * the corner, cut into the shape) and `chamfer` (a straight bevel).
25
+ */
26
+ type VectorCornerKind = 'round' | 'inverted' | 'chamfer';
27
+ declare const VECTOR_CORNER_KINDS: readonly VectorCornerKind[];
28
+ /**
29
+ * A live corner: drawn rounded (or cut) at render, hit-test, bounds, boolean, outline and export
30
+ * time while the stored anchor stays sharp. The radius shrinks to fit when the sides are short:
31
+ * the cut reaches at most halfway along each side.
32
+ */
33
+ interface VectorCorner {
34
+ radius: number;
35
+ /** Default `round`. */
36
+ kind?: VectorCornerKind;
37
+ }
22
38
  /**
23
39
  * One anchor of a subpath. Handles are absolute document positions; a missing (or `null`)
24
40
  * handle sits on the anchor, so a segment with no handles at either end is a straight line.
@@ -32,6 +48,8 @@ interface VectorAnchor {
32
48
  out?: Vec2 | null;
33
49
  /** Default `corner`. */
34
50
  type?: VectorAnchorType;
51
+ /** Live corner radius. Ignored on smooth / symmetric anchors and the ends of open subpaths. */
52
+ corner?: VectorCorner | null;
35
53
  }
36
54
  /** A chain of anchors joined by line or cubic Bézier segments. */
37
55
  interface VectorSubpath {
@@ -44,6 +62,19 @@ type VectorPaint = string | CanvasGradientDef | null;
44
62
  type VectorFillRule = 'nonzero' | 'evenodd';
45
63
  type VectorLineCap = 'butt' | 'round' | 'square';
46
64
  type VectorLineJoin = 'miter' | 'round' | 'bevel';
65
+ /**
66
+ * Where the stroke sits on the outline: centred on it, inside the shape or outside it. Only
67
+ * shapes whose subpaths are all closed have an inside; open paths always stroke centred.
68
+ */
69
+ type VectorStrokeAlign = 'center' | 'inside' | 'outside';
70
+ /** Arrowheads and end markers for the ends of open paths. */
71
+ type VectorArrowhead = 'triangle' | 'arrow' | 'open' | 'circle' | 'square' | 'bar';
72
+ declare const VECTOR_ARROWHEADS: readonly VectorArrowhead[];
73
+ /**
74
+ * `extend`: the head's tip sits past the end point and the path keeps its length; `tip`: the
75
+ * tip sits on the end point and the stroke is shortened under the head.
76
+ */
77
+ type VectorArrowAlign = 'extend' | 'tip';
47
78
  /** Paint and stroke settings of a path. */
48
79
  interface VectorStyle {
49
80
  fill?: VectorPaint;
@@ -55,6 +86,18 @@ interface VectorStyle {
55
86
  strokeDasharray?: number[];
56
87
  /** Default `nonzero`. */
57
88
  fillRule?: VectorFillRule;
89
+ /** Default `center`. */
90
+ strokeAlign?: VectorStrokeAlign;
91
+ /** Head at the start of the first subpath when it is open, or none. */
92
+ startArrow?: VectorArrowhead | null;
93
+ /** Head at the end of the last subpath when it is open, or none. */
94
+ endArrow?: VectorArrowhead | null;
95
+ /** Default `extend`. */
96
+ arrowAlign?: VectorArrowAlign;
97
+ /** Size of the start head as a multiple of the stroke width (default 1: a head 4 widths long). */
98
+ startArrowScale?: number;
99
+ /** Size of the end head (default 1). */
100
+ endArrowScale?: number;
58
101
  }
59
102
  interface VectorNodeBase {
60
103
  id: string;
@@ -141,8 +184,10 @@ interface VectorDefaults extends VectorStyle {
141
184
  starPoints?: number;
142
185
  /** Inner radius of the star tool as a fraction of the outer one (default 0.5). */
143
186
  starInnerRatio?: number;
144
- /** Corner radius of the rectangle tool (default 0). */
187
+ /** Live corner radius the rectangle, polygon and star tools give their corners (default 0). */
145
188
  cornerRadius?: number;
189
+ /** Corner kind of those tools (default `round`). */
190
+ cornerKind?: VectorCornerKind;
146
191
  }
147
192
  type VectorAlign = 'left' | 'center' | 'right' | 'top' | 'middle' | 'bottom';
148
193
  type VectorDistribute = 'horizontal' | 'vertical';
@@ -173,8 +218,13 @@ declare function hasPaint(paint: VectorPaint | undefined): boolean;
173
218
  declare function subpathSegmentCount(sp: VectorSubpath): number;
174
219
  /** Control points of segment `i` of a subpath: 2 for a line, 4 for a cubic. */
175
220
  declare function subpathSegment(sp: VectorSubpath, i: number): Point[];
176
- /** Absolute `M` / `L` / `C` / `Z` commands of subpaths. */
177
- declare function subpathsToBezier(subpaths: readonly VectorSubpath[]): BezierPath;
221
+ /**
222
+ * Absolute `M` / `L` / `C` / `Z` commands of subpaths, with live corners cut
223
+ * (`expandVectorCorners`). Pass `{ corners: false }` for the stored anchors as they are.
224
+ */
225
+ declare function subpathsToBezier(subpaths: readonly VectorSubpath[], options?: {
226
+ corners?: boolean;
227
+ }): BezierPath;
178
228
  /** The node's outline as Bézier commands. Groups have none. */
179
229
  declare function vectorNodeToBezier(node: VectorNode): BezierPath;
180
230
  /** SVG path data (`d`) of a path node or subpaths. */
@@ -216,10 +266,16 @@ declare function boundsIntersect(a: VectorBounds, b: VectorBounds): boolean;
216
266
  /** A box from two corners in any order. */
217
267
  declare function boundsFromPoints(a: Vec2, b: Vec2): VectorBounds;
218
268
  /**
219
- * Whether `p` hits a node: inside its fill (when it has one) or within half its stroke
220
- * width plus `tolerance` of its outline. A group is hit when any visible child is.
269
+ * Whether `p` hits a node: inside its fill (when it has one), on its stroke as drawn (its
270
+ * alignment and arrowheads respected) or within `tolerance` of either. A group is hit when
271
+ * any visible child is.
221
272
  */
222
273
  declare function hitTestVectorNode(node: VectorNode, p: Vec2, tolerance?: number, parent?: AffineMatrix): boolean;
274
+ /**
275
+ * The area a path node's stroke paints (alignment, caps, joins, dashes and arrowheads
276
+ * included), as a filled path in the space `parent` maps to. Empty without a stroke.
277
+ */
278
+ declare function vectorStrokeOutline(node: VectorPathNode, parent?: AffineMatrix): BezierPath;
223
279
  /** The topmost node hit by `p` (skipping hidden and locked ones), or null. */
224
280
  declare function hitTestVectorNodes(nodes: readonly VectorNode[], p: Vec2, tolerance?: number): VectorNode | null;
225
281
  interface NearestSegment {
@@ -302,8 +358,11 @@ declare function removeAnchors(sp: VectorSubpath, indices: readonly number[]): V
302
358
  declare function reverseSubpath(sp: VectorSubpath): VectorSubpath;
303
359
  /** Handle length that makes a cubic approximate a quarter circle. */
304
360
  declare const KAPPA = 0.5522847498307936;
305
- /** A rectangle, optionally with rounded corners (clamped to half the shorter side). */
306
- declare function rectSubpath(b: VectorBounds, radius?: number): VectorSubpath;
361
+ /**
362
+ * A rectangle. A `radius` becomes a live corner on each of its four anchors (drawn round, and
363
+ * clamped to half the shorter side, when the path is turned into curves).
364
+ */
365
+ declare function rectSubpath(b: VectorBounds, radius?: number, kind?: VectorCornerKind): VectorSubpath;
307
366
  /** An ellipse inscribed in a box (four smooth anchors). */
308
367
  declare function ellipseSubpath(b: VectorBounds): VectorSubpath;
309
368
  /** A regular polygon inscribed in a box, first vertex at the top. */
@@ -315,14 +374,6 @@ declare function lineSubpath(a: Vec2, b: Vec2): VectorSubpath;
315
374
  /** Rounds every coordinate to `precision` decimals (stable JSON and SVG output). */
316
375
  declare function roundSubpaths(subpaths: readonly VectorSubpath[], precision?: number): VectorSubpath[];
317
376
 
318
- /**
319
- * SVG export and import for vector documents. Import is DOM-free (works in Node and
320
- * workers): it reads `<svg>`, `<g>`, `<path>`, `<rect>`, `<circle>`, `<ellipse>`, `<line>`,
321
- * `<polyline>`, `<polygon>`, linear / radial gradients, presentation attributes, `style`
322
- * declarations and `transform`s. Text, images, clip paths, masks, filters and `<use>` are
323
- * skipped.
324
- */
325
-
326
377
  interface VectorSvgExportOptions {
327
378
  /** Decimal places for coordinates (default 3). */
328
379
  precision?: number;
@@ -334,12 +385,43 @@ interface VectorSvgExportOptions {
334
385
  idPrefix?: string;
335
386
  /** Indent nested elements (default true). */
336
387
  pretty?: boolean;
388
+ /**
389
+ * How strokes with an inside / outside alignment or arrowheads are written: `clip` (default)
390
+ * as a double-width stroke clipped or masked by the shape plus filled heads, `outline` as
391
+ * one filled path of the area the stroke paints.
392
+ */
393
+ strokes?: 'clip' | 'outline';
337
394
  }
395
+ /** `data-vector-corners`: the live corners of subpaths as `subpath.index:radius[:kind]`, space separated. */
396
+ declare function vectorCornersAttribute(subpaths: readonly VectorSubpath[], precision?: number): string;
397
+ /** Puts `data-vector-corners` back on subpaths (malformed entries are ignored). */
398
+ declare function applyVectorCornersAttribute(subpaths: VectorSubpath[], value: string): VectorSubpath[];
338
399
  /** A paint as an SVG attribute value plus the gradient def it needs (if any). */
339
400
  declare function vectorPaintToSvg(paint: VectorPaint | undefined, gradientId: string): {
340
401
  value: string;
341
402
  gradient: SvgGradientDef | null;
342
403
  };
404
+ /** The parts of an aligned or arrowed stroke (see `VectorRenderPath.strokeParts`). */
405
+ interface VectorRenderStrokeParts {
406
+ align: VectorStrokeAlign;
407
+ /** The line the stroke follows (shortened under `tip`-aligned heads). */
408
+ d: string;
409
+ /** Width to draw it with: twice the stroke width when aligned, half of it being clipped away. */
410
+ width: number;
411
+ /**
412
+ * Inside: a `<clipPath id>` holding the shape (`d`, `clip-rule` = `fillRule`). Outside: a
413
+ * `<mask id>` in user space over `bounds`, white with the shape (`d`) in black.
414
+ */
415
+ clip: {
416
+ kind: 'clip' | 'mask';
417
+ id: string;
418
+ bounds: VectorBounds;
419
+ } | null;
420
+ /** Arrowhead outlines (fill with `stroke`, nonzero). */
421
+ heads: string[];
422
+ }
423
+ /** The stroke parts of a path whose stroke needs more than one element, in its own space (undefined otherwise). */
424
+ declare function vectorStrokeSvgParts(node: VectorPathNode, clipId: string, precision?: number): VectorRenderStrokeParts | undefined;
343
425
  /** Serializes a vector document as a standalone SVG string. */
344
426
  declare function vectorDocumentToSvg(doc: VectorDocument, options?: VectorSvgExportOptions): string;
345
427
  interface VectorSvgImportOptions {
@@ -351,6 +433,64 @@ declare function parseSvgTransform(value: string | undefined): AffineMatrix;
351
433
  /** Parses SVG markup into a vector document. Throws when there is no `<svg>` element. */
352
434
  declare function parseVectorSvg(svg: string, options?: VectorSvgImportOptions): VectorDocument;
353
435
 
436
+ /**
437
+ * A corner a live radius can cut: an anchor that is not smooth, where two sides (straight or
438
+ * curved) meet at an angle. Positions are in the path node's own space.
439
+ */
440
+ interface VectorCornerInfo {
441
+ subpath: number;
442
+ index: number;
443
+ /** Where the sides meet. */
444
+ at: Vec2;
445
+ /** Unit directions the sides leave the corner in: towards the previous anchor, then the next one. */
446
+ u: Vec2;
447
+ v: Vec2;
448
+ /** The sides' lengths (along curves), in the same order. */
449
+ lu: number;
450
+ lv: number;
451
+ /** Cosine and sine of the angle between the sides. */
452
+ cos: number;
453
+ sin: number;
454
+ /** The angle between the sides in degrees (90 at a rectangle's corners). */
455
+ angle: number;
456
+ /** The largest radius that fits: its cut then reaches halfway along the shorter side. */
457
+ maxRadius: number;
458
+ }
459
+ /** The corner at anchor `index` of a subpath, or null when the anchor makes none (an open end, smooth, or straight on). */
460
+ declare function vectorCornerAt(sp: VectorSubpath, index: number, subpath?: number): VectorCornerInfo | null;
461
+ /** Every corner of the subpaths that a live radius can cut, in anchor order. */
462
+ declare function vectorCorners(subpaths: readonly VectorSubpath[]): VectorCornerInfo[];
463
+ /** How far from the corner a round cut of radius `r` meets each side: r / tan(angle / 2). */
464
+ declare const cornerSetback: (c: Pick<VectorCornerInfo, "cos" | "sin">, r: number) => number;
465
+ /** `radius` clamped to what the corner can draw (0 for negative or non-finite radii). */
466
+ declare const fitCornerRadius: (c: Pick<VectorCornerInfo, "maxRadius">, radius: number) => number;
467
+ /** The point `k` along the corner's bisector, measured in (u + v): a round cut of radius r is centred at k = r / sin. */
468
+ declare const cornerBisectorPoint: (c: VectorCornerInfo, k: number) => Vec2;
469
+ /** How much the radius grows when the round cut's centre moves by `d` (its part along the bisector, in radius units). */
470
+ declare const cornerRadiusChange: (c: VectorCornerInfo, d: Vec2) => number;
471
+ /** True when any anchor of the subpaths has a live corner radius. */
472
+ declare function hasVectorCorners(subpaths: readonly VectorSubpath[]): boolean;
473
+ /** One subpath with its corners cut; `sources[i]` is the stored anchor each output anchor comes from. */
474
+ declare function expandVectorCornersOf(sp: VectorSubpath, subpath?: number): {
475
+ subpath: VectorSubpath;
476
+ sources: number[];
477
+ };
478
+ /**
479
+ * The subpaths with every live corner cut (round, inverted or chamfer), each radius no larger
480
+ * than fits. A cut corner becomes two anchors and curved sides are trimmed to what the cuts
481
+ * leave of them. Subpaths without corners come back unchanged.
482
+ */
483
+ declare function expandVectorCorners(subpaths: readonly VectorSubpath[]): VectorSubpath[];
484
+ /**
485
+ * Sets (or clears, with radius 0) the live corner of anchors. `kind` keeps each anchor's own
486
+ * kind when omitted. Anchors that make no corner keep the radius too, so it applies once they do.
487
+ */
488
+ declare function setAnchorCorner(a: VectorAnchor, radius: number, kind?: VectorCornerKind): VectorAnchor;
489
+ /** The next corner kind (Alt-clicking a corner widget cycles round → inverted → chamfer). */
490
+ declare function nextVectorCornerKind(kind: VectorCornerKind | undefined): VectorCornerKind;
491
+ /** Every anchor of a subpath given the same live corner (radius 0 clears them). */
492
+ declare function setSubpathCorners(sp: VectorSubpath, radius: number, kind?: VectorCornerKind): VectorSubpath;
493
+
354
494
  /**
355
495
  * What a guide line shows: `align` lines run from a target through the snapped point or box,
356
496
  * `construction` lines from where a drawn point leaves, `spacing` marks equal gaps and `size`
@@ -632,6 +772,8 @@ interface VectorHover {
632
772
  point: Vec2;
633
773
  };
634
774
  transformHandle?: VectorTransformHandle;
775
+ /** A live corner widget (direct tool): the corner's anchor. */
776
+ corner?: VectorAnchorRef;
635
777
  }
636
778
  /** The drag in progress, for overlays and status text. */
637
779
  type VectorInteraction = {
@@ -659,6 +801,10 @@ type VectorInteraction = {
659
801
  } | {
660
802
  type: 'bend';
661
803
  ref: VectorSegmentRef;
804
+ } | {
805
+ type: 'corner';
806
+ ref: VectorAnchorRef;
807
+ radius: number;
662
808
  } | {
663
809
  type: 'draw';
664
810
  tool: VectorTool;
@@ -691,7 +837,7 @@ interface VectorEditorState {
691
837
  /** The selection box, rotated with the selection when its nodes share a rotation. */
692
838
  selectionFrame: VectorSelectionFrame | null;
693
839
  viewport: VectorViewport;
694
- defaults: Readonly<Required<Pick<VectorDefaults, 'polygonSides' | 'starPoints' | 'starInnerRatio' | 'cornerRadius'>> & VectorStyle>;
840
+ defaults: Readonly<Required<Pick<VectorDefaults, 'polygonSides' | 'starPoints' | 'starInnerRatio' | 'cornerRadius'>> & Pick<VectorDefaults, 'cornerKind'> & VectorStyle>;
695
841
  snap: VectorSnapOptions;
696
842
  editing: VectorPathEditOptions;
697
843
  /** Smart guides of the snap in progress, in document units (null when there are none). */
@@ -738,12 +884,16 @@ interface VectorShapeInput extends VectorStyle {
738
884
  y: number;
739
885
  width: number;
740
886
  height: number;
887
+ /** Live corner radius of a rectangle, polygon or star (default: the editor default). */
741
888
  cornerRadius?: number;
889
+ cornerKind?: VectorCornerKind;
742
890
  sides?: number;
743
891
  points?: number;
744
892
  innerRatio?: number;
745
893
  name?: string;
746
894
  }
895
+ /** Every field of `VectorStyle`, in the order style panels and commands list them. */
896
+ declare const VECTOR_STYLE_KEYS: readonly ["fill", "stroke", "strokeWidth", "strokeLinecap", "strokeLinejoin", "strokeDasharray", "fillRule", "strokeAlign", "startArrow", "endArrow", "arrowAlign", "startArrowScale", "endArrowScale"];
747
897
  /** Clipboard payload type written by `copy()`. */
748
898
  declare const VECTOR_CLIPBOARD_TYPE = "pixerate/vector";
749
899
  /** Screen distance of the rotation handle above the selection box. */
@@ -757,6 +907,29 @@ declare function getVisibleAnchors(state: Pick<VectorEditorState, 'document' | '
757
907
  * (direct tool), or of the last anchor of the pen path.
758
908
  */
759
909
  declare function getVisibleHandles(state: Pick<VectorEditorState, 'document' | 'selection' | 'editingId' | 'tool' | 'pen' | 'selectedAnchors'>): VectorHandleRef[];
910
+ /** Live corner widgets sit at least this far inside their corner (screen px along each side of a right angle). */
911
+ declare const VECTOR_CORNER_WIDGET_INSET = 10;
912
+ /** A live corner widget of the direct tool: drag it to round the corners, Alt-click to change their kind. */
913
+ interface VectorCornerWidget {
914
+ ref: VectorAnchorRef;
915
+ /** Document position of the widget. */
916
+ x: number;
917
+ y: number;
918
+ /** The radius stored on the anchor and the radius drawn (no larger than fits). */
919
+ radius: number;
920
+ drawnRadius: number;
921
+ kind: VectorCornerKind;
922
+ /** The corner in its node's own space. */
923
+ corner: VectorCornerInfo;
924
+ }
925
+ /**
926
+ * The live corner widgets the direct tool shows: on each editable path, at its selected corner
927
+ * anchors (or at every corner when none of its anchors is selected). Corners whose sides are
928
+ * shorter than three insets on screen hide theirs. Dragging one sets the radius of all of them.
929
+ * Ported from ArtCraft vectorcraft `crates/tools/src/corners.rs` (MIT OR Apache-2.0, see
930
+ * THIRD_PARTY_NOTICES.md), as is the `corner` drag below.
931
+ */
932
+ declare function getVectorCornerWidgets(state: Pick<VectorEditorState, 'document' | 'selection' | 'editingId' | 'tool' | 'pen' | 'selectedAnchors' | 'viewport'>): VectorCornerWidget[];
760
933
  /** Looks up an anchor (positions in its node's own space). */
761
934
  declare function getAnchor(doc: VectorDocument, ref: VectorAnchorRef): VectorAnchor | undefined;
762
935
  /** An anchor with its position and handles in document space (its node's transforms applied). */
@@ -958,6 +1131,31 @@ declare class VectorEditorController {
958
1131
  }, ids?: readonly string[], options?: {
959
1132
  label?: string;
960
1133
  }): VectorActionResult;
1134
+ /**
1135
+ * Sets the live corner radius (and optionally the kind) of anchors: `refs`, else the selected
1136
+ * anchors (direct tool), else every anchor of the `ids` / selected paths. Radius 0 makes the
1137
+ * corners sharp again. Corners shrink to fit when drawn, so any radius is accepted.
1138
+ */
1139
+ setCornerRadius(radius: number, options?: {
1140
+ kind?: VectorCornerKind;
1141
+ refs?: readonly VectorAnchorRef[];
1142
+ ids?: readonly string[];
1143
+ }): VectorActionResult;
1144
+ /** Sets the live corner kind of the same anchors as `setCornerRadius`, keeping their radii. */
1145
+ setCornerKind(kind: VectorCornerKind, options?: {
1146
+ refs?: readonly VectorAnchorRef[];
1147
+ ids?: readonly string[];
1148
+ }): VectorActionResult;
1149
+ /** Anchors a corner change applies to (see `setCornerRadius`). */
1150
+ private cornerTargets;
1151
+ /**
1152
+ * Outline Stroke: replaces each selected (or given) path's stroke with a filled path of the
1153
+ * area it paints (alignment, joins, caps, dashes and arrowheads included), placed above a copy
1154
+ * of the path that keeps the fill (left out when there is none). Returns the new paths' ids.
1155
+ */
1156
+ outlineStroke(options?: {
1157
+ ids?: readonly string[];
1158
+ }): string[];
961
1159
  rename(id: string, name: string): VectorActionResult;
962
1160
  setVisible(id: string, visible: boolean): VectorActionResult;
963
1161
  setLocked(id: string, locked: boolean): VectorActionResult;
@@ -1197,6 +1395,8 @@ declare class VectorEditorController {
1197
1395
  private tolerance;
1198
1396
  private hitTransformHandle;
1199
1397
  private hitHandle;
1398
+ private cornerView;
1399
+ private hitCornerWidget;
1200
1400
  private hitAnchor;
1201
1401
  /** Deepest unlocked visible path under `p`. */
1202
1402
  private hitPath;
@@ -1258,6 +1458,13 @@ interface VectorRenderPath {
1258
1458
  strokeDasharray?: string;
1259
1459
  fillRule: 'nonzero' | 'evenodd';
1260
1460
  opacity: number;
1461
+ /**
1462
+ * Set when the stroke takes more than one element: an inside / outside alignment or
1463
+ * arrowheads. Draw `d` with the fill only, then `stroke.d` with the stroke (at
1464
+ * `stroke.width`, clipped or masked as `stroke.clip` says), then each head filled with
1465
+ * `stroke`; group them under `id`, `transform` and `opacity`.
1466
+ */
1467
+ strokeParts?: VectorRenderStrokeParts;
1261
1468
  }
1262
1469
  interface VectorRenderGroup {
1263
1470
  kind: 'group';
@@ -1299,6 +1506,17 @@ interface VectorRenderHandle {
1299
1506
  anchorY: number;
1300
1507
  hovered: boolean;
1301
1508
  }
1509
+ /** A live corner widget in screen pixels. */
1510
+ interface VectorRenderCornerWidget {
1511
+ ref: VectorAnchorRef;
1512
+ x: number;
1513
+ y: number;
1514
+ radius: number;
1515
+ kind: VectorCornerKind;
1516
+ hovered: boolean;
1517
+ /** Its corners are being dragged. */
1518
+ active: boolean;
1519
+ }
1302
1520
  /** A smart guide line in screen pixels. */
1303
1521
  interface VectorRenderGuideLine {
1304
1522
  kind: VectorGuideKind;
@@ -1363,6 +1581,11 @@ interface VectorOverlayRenderData {
1363
1581
  } | null;
1364
1582
  /** Where the scissors would cut (screen space). */
1365
1583
  cutPoint: Vec2 | null;
1584
+ /**
1585
+ * Live corner widgets of the direct tool (screen space): drag one to round its corners,
1586
+ * Alt-click to cycle round / inverted / chamfer, click to pick its corner alone.
1587
+ */
1588
+ cornerWidgets: VectorRenderCornerWidget[];
1366
1589
  /** A short status, e.g. "W 120 × H 80" or "45°". */
1367
1590
  status: string | null;
1368
1591
  }
@@ -1387,6 +1610,8 @@ declare const VECTOR_OVERLAY_THEME: {
1387
1610
  readonly transformHandleSize: 8;
1388
1611
  readonly anchorSize: 7;
1389
1612
  readonly handleRadius: 3.5;
1613
+ /** Radius of a live corner widget (a ring with a dot). */
1614
+ readonly cornerWidgetRadius: 4;
1390
1615
  };
1391
1616
  interface ModifierEventLike {
1392
1617
  shiftKey?: boolean;
@@ -1426,21 +1651,48 @@ interface VectorSelectionStyle {
1426
1651
  stroke: VectorPaint;
1427
1652
  strokeWidth: number;
1428
1653
  opacity: number;
1654
+ strokeAlign: VectorStrokeAlign;
1655
+ startArrow: VectorArrowhead | null;
1656
+ endArrow: VectorArrowhead | null;
1657
+ arrowAlign: VectorArrowAlign;
1658
+ startArrowScale: number;
1659
+ endArrowScale: number;
1660
+ /**
1661
+ * Live corners of the selected anchors (direct tool) or of every corner of the selected
1662
+ * paths: the first one's radius and kind, and how many corners there are (0: none to round).
1663
+ */
1664
+ cornerRadius: number;
1665
+ cornerKind: VectorCornerKind;
1666
+ corners: number;
1667
+ /** Some selected path is open, so arrowheads apply. */
1668
+ hasOpenPath: boolean;
1429
1669
  mixed: {
1430
1670
  fill: boolean;
1431
1671
  stroke: boolean;
1432
1672
  strokeWidth: boolean;
1433
1673
  opacity: boolean;
1674
+ strokeAlign: boolean;
1675
+ startArrow: boolean;
1676
+ endArrow: boolean;
1677
+ arrowAlign: boolean;
1678
+ startArrowScale: boolean;
1679
+ endArrowScale: boolean;
1680
+ cornerRadius: boolean;
1681
+ cornerKind: boolean;
1434
1682
  };
1435
1683
  /** Ids of the paths the style applies to. */
1436
1684
  pathIds: string[];
1437
1685
  }
1438
- declare function getVectorSelectionStyle(state: Pick<VectorEditorState, 'document' | 'selection'>): VectorSelectionStyle | null;
1686
+ declare function getVectorSelectionStyle(state: Pick<VectorEditorState, 'document' | 'selection'> & Partial<Pick<VectorEditorState, 'selectedAnchors' | 'tool'>>): VectorSelectionStyle | null;
1687
+ /** Labels of the stroke alignments, corner kinds and arrowheads, for style panels. */
1688
+ declare const VECTOR_STROKE_ALIGN_LABELS: Readonly<Record<VectorStrokeAlign, string>>;
1689
+ declare const VECTOR_CORNER_KIND_LABELS: Readonly<Record<VectorCornerKind, string>>;
1690
+ declare const VECTOR_ARROWHEAD_LABELS: Readonly<Record<VectorArrowhead, string>>;
1439
1691
  /** A paint as `#rrggbb` for `<input type="color">`, or null for none, gradients and other CSS colours. */
1440
1692
  declare function vectorPaintToHex(paint: VectorPaint | undefined): string | null;
1441
1693
  /** A path-editing button of the bundled toolbars. */
1442
1694
  interface VectorPathAction {
1443
- id: 'join' | 'average' | 'cut' | 'clean' | 'smooth';
1695
+ id: 'join' | 'average' | 'cut' | 'clean' | 'smooth' | 'outline';
1444
1696
  label: string;
1445
1697
  title: string;
1446
1698
  /** Shortcut after Cmd / Ctrl, if any. */
@@ -1449,7 +1701,7 @@ interface VectorPathAction {
1449
1701
  enabled: (selected: number, points: number) => boolean;
1450
1702
  run: (controller: VectorEditorController) => unknown;
1451
1703
  }
1452
- /** Join, Average, Cut at Points, Remove Redundant Points and Smooth, as the toolbars show them. */
1704
+ /** Join, Average, Cut at Points, Remove Redundant Points, Smooth and Outline Stroke, as the toolbars show them. */
1453
1705
  declare const VECTOR_PATH_ACTIONS: readonly VectorPathAction[];
1454
1706
  /** The on / off path-editing settings the toolbars toggle. */
1455
1707
  declare const VECTOR_EDIT_TOGGLES: readonly {
@@ -1677,4 +1929,58 @@ declare function vectorInkShapeName(shape: VectorInkShape): string;
1677
1929
  */
1678
1930
  declare function recognizeInkShape(points: readonly Point[], options?: RecognizeInkOptions): VectorInkShape | null;
1679
1931
 
1680
- export { type AddVectorNodeOptions, AffineMatrix, DEFAULT_VECTOR_PATH_EDIT, DEFAULT_VECTOR_SNAP, IDENTITY_MATRIX, KAPPA, LazyMouse, type NearestSegment, type RecognizeInkOptions, SvgGradientDef, VECTOR_CLIPBOARD_TYPE, VECTOR_CONSTRUCTION_ANGLES, VECTOR_EDIT_TOGGLES, VECTOR_INK_MAX_CORNERS, VECTOR_OVERLAY_THEME, VECTOR_PATH_ACTIONS, VECTOR_PENCIL_STRING_PX, VECTOR_ROTATE_HANDLE_OFFSET, VECTOR_TOOLS, VECTOR_TOOL_GLYPHS, VECTOR_TOOL_SHORTCUTS, VECTOR_TRANSFORM_HANDLES, type Vec2, type VectorActionResult, type VectorAlign, type VectorAnchor, type VectorAnchorRef, type VectorAnchorType, type VectorArrange, type VectorAverageAxis, type VectorBooleanOperation, type VectorBounds, type VectorCommandOptions, type VectorDefaults, type VectorDistribute, type VectorDocument, VectorEditorController, type VectorEditorOptions, type VectorEditorState, type VectorFillRule, type VectorGroupNode, type VectorGuideKind, type VectorGuideLabel, type VectorGuideLine, type VectorHandleRef, type VectorHover, type VectorInkShape, type VectorInteraction, type VectorKeyInput, type VectorLineCap, type VectorLineJoin, type VectorMatrix, type VectorModifiers, type VectorNode, type VectorNodeListing, type VectorOverlayRenderData, type VectorPaint, type VectorPathAction, type VectorPathEditOptions, type VectorPathNode, type VectorPointSnap, type VectorPointerInput, type VectorRectSnap, type VectorRenderAnchor, type VectorRenderGroup, type VectorRenderGuideLabel, type VectorRenderGuideLine, type VectorRenderHandle, type VectorRenderNode, type VectorRenderPath, type VectorScaleSnap, type VectorSceneRenderData, type VectorSegmentRef, type VectorSelectionBoxGeometry, type VectorSelectionFrame, type VectorSelectionStyle, type VectorShapeInput, type VectorSnapGuides, type VectorSnapKind, type VectorSnapLeave, type VectorSnapOptions, VectorSnapTargets, type VectorStyle, type VectorSubpath, type VectorSvgExportOptions, type VectorSvgImportOptions, type VectorTool, type VectorTransformHandle, type VectorViewport, applyMatrix, applyMatrixLinear, bendSegment, bezierToSubpaths, boundsFromPoints, boundsIntersect, cloneAnchor, cloneSubpath, cloneVectorDocument, cloneVectorNode, collectPathNodes, constrainToLeave, convertAnchor, createVectorCommands, curvatureMoveAnchor, cutSubpathAt, decomposeRigid, ellipseSubpath, eraseFromFill, eraseFromOutline, eraserRegion, findVectorNode, getAnchor, getAnchorWorld, getEditablePathIds, getTransformHandlePositions, getVectorOverlayRenderData, getVectorSceneRenderData, getVectorSelectionBoxGeometry, getVectorSelectionFrame, getVectorSelectionStyle, getVisibleAnchors, getVisibleHandles, hasPaint, hitTestVectorNode, hitTestVectorNodes, inferAnchorType, insertAnchor, invertMatrix, isIdentityMatrix, isVectorTextTarget, joinSubpaths, knifePath, lineSubpath, locateVectorNode, matrixRotation, moveAnchorHandle, multiplyMatrices, nearestSegment, nodeMatrix, parseSvgTransform, parseVectorSvg, polygonSubpath, polylineBounds, recognizeInkShape, rectSubpath, removeAnchorKeepingShape, removeAnchors, removeAnchorsKeepingShape, removeRedundantPoints, reverseSubpath, rotateMatrix, roundSubpaths, scaleFor, scaleMatrix, simplifyPolyline, smoothSubpath, splitIntoFaces, splitSubpathAt, starSubpath, subpathPointAt, subpathSegment, subpathSegmentCount, subpathsToBezier, toVectorKeyInput, toVectorModifiers, toVectorPointerInput, transformVectorNode, translateAnchor, translateMatrix, unionBounds, vectorDocumentToSvg, vectorInkShapeName, vectorNodeBounds, vectorNodeRotation, vectorNodeToBezier, vectorPaintToHex, vectorPaintToSvg, vectorParentMatrix, vectorPathData, vectorPathWorldBezier, vectorResizeCursor, vectorToolLabel, vectorWorldMatrix, walkVectorNodes };
1932
+ /** One arrowhead: a filled outline (nonzero) painted with the stroke's paint. */
1933
+ interface VectorArrowheadShape {
1934
+ end: 'start' | 'end';
1935
+ kind: VectorArrowhead;
1936
+ tip: Vec2;
1937
+ /** Unit direction the head points in. */
1938
+ dir: Vec2;
1939
+ /** Distance from the tip back to where the stroke ends under the head. */
1940
+ inset: number;
1941
+ path: BezierPath;
1942
+ }
1943
+ /** What the stroke of a path draws. */
1944
+ interface VectorStrokeParts {
1945
+ /** Where the stroke sits (`center` for open shapes, whatever the style says). */
1946
+ align: VectorStrokeAlign;
1947
+ /** The line the stroke follows: the outline, shortened under `tip`-aligned heads. */
1948
+ line: BezierPath;
1949
+ /** The stroke width to draw `line` with: twice the style's width for inside / outside (half is clipped away). */
1950
+ drawWidth: number;
1951
+ heads: VectorArrowheadShape[];
1952
+ }
1953
+ /** True when the path has subpaths and all of them are closed (only such shapes have an inside). */
1954
+ declare function isClosedBezierShape(path: BezierPath): boolean;
1955
+ /** The alignment a stroke is drawn with: the style's, or `center` for open shapes. */
1956
+ declare function effectiveStrokeAlign(style: Pick<VectorStyle, 'strokeAlign'>, closedShape: boolean): VectorStrokeAlign;
1957
+ /** True when the style asks for more than a plain centred stroke (an alignment or arrowheads). */
1958
+ declare function hasStrokeExtras(style: VectorStyle): boolean;
1959
+ /** The weight of a head: the stroke width times its scale (at least 0.25). A head is 4 weights long and wide. */
1960
+ declare function arrowheadWeight(style: VectorStyle, end: 'start' | 'end'): number;
1961
+ /** Distance from the tip where the stroke ends, for a stroke whose cap reaches `cap` past its end. */
1962
+ declare function arrowheadInset(kind: VectorArrowhead, hw: number, cap: number): number;
1963
+ /** The outline of a `kind` head of weight `hw` with its tip at `tip`, pointing along unit `dir`. */
1964
+ declare function arrowheadPath(kind: VectorArrowhead, tip: Vec2, dir: Vec2, hw: number): BezierPath;
1965
+ /**
1966
+ * The stroke of `path` as `style` draws it: its alignment, the line it follows (shortened under
1967
+ * `tip`-aligned heads) and its arrowheads. Heads go on the start of the first subpath and the
1968
+ * end of the last one, when those are open.
1969
+ */
1970
+ declare function vectorStrokeParts(path: BezierPath, style: VectorStyle): VectorStrokeParts;
1971
+ /**
1972
+ * The area the stroke paints, as one filled path: the outlined stroke (joins, caps and dashes
1973
+ * as SVG) clipped by the alignment (against the fill, read with the style's `fillRule`), plus
1974
+ * the arrowheads.
1975
+ */
1976
+ declare function vectorStrokeOutlinePath(path: BezierPath, style: VectorStyle): BezierPath;
1977
+ /**
1978
+ * Whether point `p` hits the stroke of `path` (`tolerance` added on every side): within half
1979
+ * the width of the outline for a centred stroke, within the whole width on the inside or the
1980
+ * outside of the fill for an aligned one, or on an arrowhead.
1981
+ */
1982
+ declare function hitTestVectorStroke(path: BezierPath, p: Vec2, style: VectorStyle, tolerance?: number): boolean;
1983
+ /** How far the stroke can reach past the outline (for padding bounds and masks). */
1984
+ declare function vectorStrokeReach(style: VectorStyle): number;
1985
+
1986
+ export { type AddVectorNodeOptions, AffineMatrix, DEFAULT_VECTOR_PATH_EDIT, DEFAULT_VECTOR_SNAP, IDENTITY_MATRIX, KAPPA, LazyMouse, type NearestSegment, type RecognizeInkOptions, SvgGradientDef, VECTOR_ARROWHEADS, VECTOR_ARROWHEAD_LABELS, VECTOR_CLIPBOARD_TYPE, VECTOR_CONSTRUCTION_ANGLES, VECTOR_CORNER_KINDS, VECTOR_CORNER_KIND_LABELS, VECTOR_CORNER_WIDGET_INSET, VECTOR_EDIT_TOGGLES, VECTOR_INK_MAX_CORNERS, VECTOR_OVERLAY_THEME, VECTOR_PATH_ACTIONS, VECTOR_PENCIL_STRING_PX, VECTOR_ROTATE_HANDLE_OFFSET, VECTOR_STROKE_ALIGN_LABELS, VECTOR_STYLE_KEYS, VECTOR_TOOLS, VECTOR_TOOL_GLYPHS, VECTOR_TOOL_SHORTCUTS, VECTOR_TRANSFORM_HANDLES, type Vec2, type VectorActionResult, type VectorAlign, type VectorAnchor, type VectorAnchorRef, type VectorAnchorType, type VectorArrange, type VectorArrowAlign, type VectorArrowhead, type VectorArrowheadShape, type VectorAverageAxis, type VectorBooleanOperation, type VectorBounds, type VectorCommandOptions, type VectorCorner, type VectorCornerInfo, type VectorCornerKind, type VectorCornerWidget, type VectorDefaults, type VectorDistribute, type VectorDocument, VectorEditorController, type VectorEditorOptions, type VectorEditorState, type VectorFillRule, type VectorGroupNode, type VectorGuideKind, type VectorGuideLabel, type VectorGuideLine, type VectorHandleRef, type VectorHover, type VectorInkShape, type VectorInteraction, type VectorKeyInput, type VectorLineCap, type VectorLineJoin, type VectorMatrix, type VectorModifiers, type VectorNode, type VectorNodeListing, type VectorOverlayRenderData, type VectorPaint, type VectorPathAction, type VectorPathEditOptions, type VectorPathNode, type VectorPointSnap, type VectorPointerInput, type VectorRectSnap, type VectorRenderAnchor, type VectorRenderCornerWidget, type VectorRenderGroup, type VectorRenderGuideLabel, type VectorRenderGuideLine, type VectorRenderHandle, type VectorRenderNode, type VectorRenderPath, type VectorRenderStrokeParts, type VectorScaleSnap, type VectorSceneRenderData, type VectorSegmentRef, type VectorSelectionBoxGeometry, type VectorSelectionFrame, type VectorSelectionStyle, type VectorShapeInput, type VectorSnapGuides, type VectorSnapKind, type VectorSnapLeave, type VectorSnapOptions, VectorSnapTargets, type VectorStrokeAlign, type VectorStrokeParts, type VectorStyle, type VectorSubpath, type VectorSvgExportOptions, type VectorSvgImportOptions, type VectorTool, type VectorTransformHandle, type VectorViewport, applyMatrix, applyMatrixLinear, applyVectorCornersAttribute, arrowheadInset, arrowheadPath, arrowheadWeight, bendSegment, bezierToSubpaths, boundsFromPoints, boundsIntersect, cloneAnchor, cloneSubpath, cloneVectorDocument, cloneVectorNode, collectPathNodes, constrainToLeave, convertAnchor, cornerBisectorPoint, cornerRadiusChange, cornerSetback, createVectorCommands, curvatureMoveAnchor, cutSubpathAt, decomposeRigid, effectiveStrokeAlign, ellipseSubpath, eraseFromFill, eraseFromOutline, eraserRegion, expandVectorCorners, expandVectorCornersOf, findVectorNode, fitCornerRadius, getAnchor, getAnchorWorld, getEditablePathIds, getTransformHandlePositions, getVectorCornerWidgets, getVectorOverlayRenderData, getVectorSceneRenderData, getVectorSelectionBoxGeometry, getVectorSelectionFrame, getVectorSelectionStyle, getVisibleAnchors, getVisibleHandles, hasPaint, hasStrokeExtras, hasVectorCorners, hitTestVectorNode, hitTestVectorNodes, hitTestVectorStroke, inferAnchorType, insertAnchor, invertMatrix, isClosedBezierShape, isIdentityMatrix, isVectorTextTarget, joinSubpaths, knifePath, lineSubpath, locateVectorNode, matrixRotation, moveAnchorHandle, multiplyMatrices, nearestSegment, nextVectorCornerKind, nodeMatrix, parseSvgTransform, parseVectorSvg, polygonSubpath, polylineBounds, recognizeInkShape, rectSubpath, removeAnchorKeepingShape, removeAnchors, removeAnchorsKeepingShape, removeRedundantPoints, reverseSubpath, rotateMatrix, roundSubpaths, scaleFor, scaleMatrix, setAnchorCorner, setSubpathCorners, simplifyPolyline, smoothSubpath, splitIntoFaces, splitSubpathAt, starSubpath, subpathPointAt, subpathSegment, subpathSegmentCount, subpathsToBezier, toVectorKeyInput, toVectorModifiers, toVectorPointerInput, transformVectorNode, translateAnchor, translateMatrix, unionBounds, vectorCornerAt, vectorCorners, vectorCornersAttribute, vectorDocumentToSvg, vectorInkShapeName, vectorNodeBounds, vectorNodeRotation, vectorNodeToBezier, vectorPaintToHex, vectorPaintToSvg, vectorParentMatrix, vectorPathData, vectorPathWorldBezier, vectorResizeCursor, vectorStrokeOutline, vectorStrokeOutlinePath, vectorStrokeParts, vectorStrokeReach, vectorStrokeSvgParts, vectorToolLabel, vectorWorldMatrix, walkVectorNodes };