@weasel-js/path-tools 0.0.0-stage → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,713 @@
1
+ import { PathEditExtension, FeaturePreset, EditableShape, BlendEffect, BendAlongEffect, RepeatAlongEffect, PathNode, Tool, SurfaceContribution, EditAnchorsDep } from '@weasel-js/core';
2
+ import { DrawCommand } from '@weasel-js/renderer';
3
+ import { AnchorSet, PathConstraintKind, PolygonPath, PathConstraint, PathWarp, Affine, DistortMode, EnvelopeMapping, TrimResult } from '@weasel-js/geom';
4
+ import * as _weasel_js_routing from '@weasel-js/routing';
5
+ import { Action, ActionDeps, ToolKeybinding } from '@weasel-js/routing';
6
+ export { ActionParamSchema } from '@weasel-js/routing';
7
+ import { CursorSpec } from '@weasel-js/cursor';
8
+
9
+ /**
10
+ * The balance lines path edit can draw over the open path: one per curved
11
+ * segment, from its first handle's tip to its second's, with the grip
12
+ * `balanceHandles` drags at the middle, pressed as `balance:N`.
13
+ */
14
+
15
+ /** Chrome-caps id the balance lines and their grips are drawn and hit-tested
16
+ * under. Off by default. */
17
+ declare const PATH_BALANCE_CHROME_ID = "path-edit.balance";
18
+ /** How the balance lines are drawn. */
19
+ interface PathEditBalanceStyle {
20
+ /** Color of the line between a segment's handle tips and of its grip's rim. */
21
+ color?: string;
22
+ /** Fill of the grip. */
23
+ gripFill?: string;
24
+ /** Radius of the grip, in screen px. Default 4. */
25
+ gripRadiusPx?: number;
26
+ }
27
+ type ToScreen$1 = (p: {
28
+ x: number;
29
+ y: number;
30
+ }) => {
31
+ x: number;
32
+ y: number;
33
+ };
34
+ /** Draw commands for `set`'s balance lines and their grips, in screen space. */
35
+ declare function balanceCommands(set: AnchorSet, toScreen: ToScreen$1, style?: PathEditBalanceStyle): DrawCommand[];
36
+ /** The balance lines as a path-edit extension: drawn, and their grips
37
+ * pressed, while chrome-caps shows {@link PATH_BALANCE_CHROME_ID}. */
38
+ declare function createBalanceExtension(style?: PathEditBalanceStyle): PathEditExtension;
39
+
40
+ /**
41
+ * The curvature comb path edit can draw over the open path.
42
+ */
43
+
44
+ /** Chrome-caps id the curvature comb is drawn under. Off by default. */
45
+ declare const PATH_COMB_CHROME_ID = "path-edit.comb";
46
+ /** How the curvature comb is drawn. */
47
+ interface PathEditCombOptions {
48
+ /** Tooth length per unit of curvature, in world units: a tooth over a
49
+ * stretch of radius r is `scale / r` long. Default 2000. */
50
+ scale?: number;
51
+ /** Teeth per segment, ends included. Default 24. */
52
+ samplesPerSegment?: number;
53
+ /** Color of the teeth and of the line through their tips. */
54
+ color?: string;
55
+ }
56
+ type ToScreen = (p: {
57
+ x: number;
58
+ y: number;
59
+ }) => {
60
+ x: number;
61
+ y: number;
62
+ };
63
+ /** Draw commands for `set`'s curvature comb, in screen space. */
64
+ declare function combCommands(set: AnchorSet, toScreen: ToScreen, opts?: PathEditCombOptions): DrawCommand[];
65
+ /** The comb as a path-edit extension, drawn while chrome-caps shows
66
+ * {@link PATH_COMB_CHROME_ID}. `options` is read every frame. */
67
+ declare function createCombExtension(options?: () => PathEditCombOptions | undefined): PathEditExtension;
68
+
69
+ /**
70
+ * The small marks the path-edit overlay draws for a path's constraints, in
71
+ * screen pixels, and where a click finds them: a letter beside a horizontal
72
+ * or vertical segment, paired strokes beside parallel ones, a foot beside
73
+ * perpendicular ones, ticks across equal ones, a dimension bar beside a fixed
74
+ * length, a pin by a fixed anchor, and a ring by coincident ones. Marks sit
75
+ * on the inside of the shape, toward the centroid of its anchors, so a click
76
+ * on one lands on the shape rather than on empty canvas.
77
+ */
78
+
79
+ /** Colors for the constraint marks. */
80
+ interface ConstraintGlyphStyle {
81
+ /** A constraint that holds. */
82
+ stroke: string;
83
+ /** One that does not: it conflicts with the others. */
84
+ conflictStroke: string;
85
+ }
86
+
87
+ /**
88
+ * The package's behavior as `<SceneCanvas features>` presets: one per tool
89
+ * family, and `pathTools` for all of them. Each assumes core's `paths`
90
+ * preset, which opens a path for editing.
91
+ */
92
+
93
+ /** The Simplify brush, a path-edit tool that refits the curve it passes over. */
94
+ declare const simplifyBrushPreset: FeaturePreset;
95
+ /** The `handleLock.angle` and `handleLock.length` toggles. */
96
+ declare const handleLocksPreset: FeaturePreset;
97
+ /** Bridge, on whole paths and on two selected anchors. */
98
+ declare const bridgePreset: FeaturePreset;
99
+ /** `trimPath`, which `useTrimTool` binds. */
100
+ declare const trimPreset: FeaturePreset;
101
+ /** `extendToMeet`, which `useExtendTool` binds. */
102
+ declare const extendPreset: FeaturePreset;
103
+ /** `smudgeBrush`, which `useSmudgeBrushTool` binds. */
104
+ declare const smudgePreset: FeaturePreset;
105
+ /** Harmonize curvature. */
106
+ declare const harmonizePreset: FeaturePreset;
107
+ /** The curvature comb over the open path, drawn as `options` says, read every
108
+ * frame. Off until chrome-caps shows `path-edit.comb`. */
109
+ declare function createCurvatureCombPreset(options?: () => PathEditCombOptions | undefined): FeaturePreset;
110
+ /** The curvature comb with its default look. */
111
+ declare const curvatureCombPreset: FeaturePreset;
112
+ /**
113
+ * Balance handles: a line between each curved segment's handle tips with a
114
+ * grip to drag (`balanceHandles`) or double-click (`equalizeHandles`), drawn
115
+ * in `style`. Off until chrome-caps shows `path-edit.balance`. It refines
116
+ * `paths`, so a grip's double-click goes ahead of entering path edit.
117
+ */
118
+ declare function createBalancePreset(style?: PathEditBalanceStyle): FeaturePreset;
119
+ /** Balance handles with their default look. */
120
+ declare const balancePreset: FeaturePreset;
121
+ /** Path constraints: their actions, their marks in `style`'s colors, and
122
+ * every edit of a constrained path finished so they hold. */
123
+ declare function createConstraintsPreset(style?: Partial<ConstraintGlyphStyle>): FeaturePreset;
124
+ /** Path constraints with their default colors. */
125
+ declare const constraintsPreset: FeaturePreset;
126
+ /** Blend, Bend along, and Repeat along, live, and the actions that edit and
127
+ * expand them. The scene must hold `withPathEffectsRegistry`'s derivations. */
128
+ declare const pathEffectsPreset: FeaturePreset;
129
+ /** `expandWarp` and `configureWarp`; the warp tools bring their own drags. */
130
+ declare const warpPreset: FeaturePreset;
131
+ /** Every preset above, the comb, balance, and constraints with their defaults. */
132
+ declare const pathTools: FeaturePreset;
133
+
134
+ /**
135
+ * Add and remove geometric constraints on the anchors selected in path edit.
136
+ * Neither has a default binding: a consumer binds each kind it offers, with
137
+ * the kind as a param (see `<SceneCanvas tune>`).
138
+ */
139
+
140
+ /** Params for `constrainAnchors`. */
141
+ interface ConstrainAnchorsParams {
142
+ kind: PathConstraintKind;
143
+ /** For `length`: the length to hold. Default: each pair's length now. */
144
+ length?: number;
145
+ }
146
+ /**
147
+ * The constraints of `kind` that `anchors`, in the order they were selected,
148
+ * ask for: each anchor for `fixed`; each consecutive pair for `horizontal`,
149
+ * `vertical`, `length`, and `coincident`; and for the kinds relating two
150
+ * segments, three anchors as two segments sharing the middle one or four as
151
+ * two pairs. Empty when the anchors cannot make that kind.
152
+ */
153
+ declare function constraintsForAnchors(kind: PathConstraintKind, anchors: readonly number[], path: PolygonPath, length?: number): PathConstraint[];
154
+ /**
155
+ * Delete the constraint selected in path edit, as a command. Delete and
156
+ * Backspace reach it through `deleteAnchors`, which deletes whichever of the
157
+ * two is selected, so the keys have one binding.
158
+ */
159
+ declare const deleteConstraintAction: Action & {
160
+ requires: string[];
161
+ };
162
+ /**
163
+ * Constrain the selected anchors: params `{ kind, length? }`, read as
164
+ * {@link constraintsForAnchors} reads them. The path moves the least that
165
+ * makes every constraint hold; a constraint that conflicts with the rest is
166
+ * kept all the same, left unsolved, and shown as a conflict.
167
+ */
168
+ declare const constrainAnchorsAction: Action & {
169
+ requires: string[];
170
+ };
171
+ /**
172
+ * Remove the constraints whose anchors are all selected — only those of
173
+ * `kind` when the params name one.
174
+ */
175
+ declare const unconstrainAnchorsAction: Action & {
176
+ requires: string[];
177
+ };
178
+
179
+ /** The path-edit tool under which a plain drag brushes. */
180
+ declare const SIMPLIFY_BRUSH_TOOL = "simplifyBrush";
181
+ /** The brush's radius on screen when no param names one. */
182
+ declare const SIMPLIFY_BRUSH_RADIUS_PX = 12;
183
+ /** Params the brush reads on every move, so a thunk can change them mid-stroke. */
184
+ interface SimplifyBrushParams {
185
+ /** Brush radius in screen pixels. */
186
+ radiusPx?: number;
187
+ /** How far the refit may stray from the original, in world units, as for
188
+ * the Simplify command. */
189
+ tolerance?: number;
190
+ }
191
+ /** The kit's brush-ring cursor drawn `radiusPx` in radius on screen. */
192
+ declare function brushRingCursor(radiusPx: number): CursorSpec;
193
+ /**
194
+ * The Simplify command, brushed on. While path edit's
195
+ * `simplifyBrush` tool is on, a plain drag gathers every anchor a round brush
196
+ * passes over, and each unbroken stretch of them along a subpath is refitted
197
+ * as one span by Simplify's own fitter (`simplifyAnchorsAt`) at `tolerance`.
198
+ * Only anchors the shape does not need go, so brushing again goes further.
199
+ * The path previews the result while the brush is down and commits as one
200
+ * undo step on release.
201
+ */
202
+ declare const simplifyBrushAction: Action & {
203
+ requires: string[];
204
+ };
205
+ /** The bar toggle for the brush: `pathEditTool.simplifyBrush`. */
206
+ declare const simplifyBrushToolAction: Action & {
207
+ requires: string[];
208
+ };
209
+
210
+ /**
211
+ * The Smudge brush's drag: the selected paths' outlines under a round brush
212
+ * follow the pointer, as one undo entry per stroke.
213
+ */
214
+
215
+ /** The brush's radius in screen px when no param gives one. */
216
+ declare const DEFAULT_SMUDGE_RADIUS_PX = 40;
217
+ /** How much of the pointer's motion the outline under the brush's center follows,
218
+ * when no param gives it. */
219
+ declare const DEFAULT_SMUDGE_STRENGTH = 0.6;
220
+ /** The params `smudgeBrush` reads, each on every pointer move. */
221
+ interface SmudgeBrushParams {
222
+ /** The brush's radius, in screen px. */
223
+ radiusPx?: number;
224
+ /** `1` moves the outline under the brush's center as far as the pointer; less, less. */
225
+ strength?: number;
226
+ }
227
+ /**
228
+ * @experimental A drag that pushes the outline of every selected path along with
229
+ * the pointer (`smudgePath` in `@weasel-js/geom`). Each pointer move is one dab from
230
+ * where the last one ended: points under the brush move with it, most at its center
231
+ * and not at all at its rim, and a long segment the brush meets gets anchors added
232
+ * so it can bend there. `params.radiusPx` is the brush's radius on screen, so it
233
+ * covers the same part of the canvas at every zoom, and `params.strength` how closely
234
+ * the outline follows; both are read on every move. The cursor is a ring the size of
235
+ * the brush. The stroke commits as one undo entry; canceling it leaves the paths as
236
+ * they were.
237
+ */
238
+ declare const smudgeBrushAction: Action & {
239
+ requires: string[];
240
+ };
241
+
242
+ /**
243
+ * A warp a node is holding: the path it warped, the warp, and the tolerance
244
+ * the result was refitted to, kept on the node as `data.warp` beside the
245
+ * `data.path` (or polygon pose) they produced. The geometry stays what every
246
+ * reader uses; the warp only says how to make it again, so it can be edited
247
+ * until it is expanded away.
248
+ *
249
+ * The warp lives in its own frame, fixed when it was made. `frame` carries
250
+ * that frame onto the stored path, so moving, resizing or rotating the node
251
+ * keeps the warp without touching it. A writer that changes the geometry some
252
+ * other way leaves a warp that no longer reproduces it, and such a warp is
253
+ * ignored, the way a stale shape generator is.
254
+ */
255
+
256
+ /** What `data.warp` holds. */
257
+ interface HeldPathWarp {
258
+ /** Shared by every node warped together, so one handle drives them all. */
259
+ id: string;
260
+ /** The path before warping, in the warp's frame. */
261
+ source: PolygonPath;
262
+ warp: PathWarp;
263
+ /** How far the refitted result may stray from the exact warp. */
264
+ tolerance: number;
265
+ /** From the warp's frame to the frame the node stores its path in. */
266
+ frame: Affine;
267
+ }
268
+ /** A held warp that still reproduces its node, and where its frame lands in
269
+ * world space now. */
270
+ interface ResolvedPathWarp {
271
+ held: HeldPathWarp;
272
+ /** From the warp's frame to world space. */
273
+ toWorld: Affine;
274
+ }
275
+ /** The warp a node's `data` holds, whether or not it still matches. */
276
+ declare function heldPathWarpOf(data: unknown): HeldPathWarp | null;
277
+ /** `data` without its warp: the shape as plain geometry. */
278
+ declare function withoutPathWarp<T>(data: T): T;
279
+ /**
280
+ * The warp `node` holds and its frame in world space, or null when it holds
281
+ * none or the one it holds no longer reproduces its geometry. A node whose
282
+ * stored path was only scaled and moved since — a polygon pose dragged, say —
283
+ * still resolves: the box-to-box map between the two is folded into `frame`.
284
+ */
285
+ declare function resolvePathWarp(node: EditableShape | null | undefined): ResolvedPathWarp | null;
286
+
287
+ /**
288
+ * What every warp action shares: finding the selected paths' warps of one
289
+ * kind, making fresh ones where a path holds none, and writing a changed warp
290
+ * back as the geometry it makes plus the warp itself.
291
+ */
292
+
293
+ /** Which warp a tool or action works with. */
294
+ type WarpKind = PathWarp['kind'];
295
+ /** The settings a warp is made or remade with. Each applies only to the kinds
296
+ * it names; absent ones leave a held warp as it is. */
297
+ interface WarpSettings {
298
+ /** A distort's map. Default `'free'`. */
299
+ mode?: DistortMode;
300
+ /** An envelope's interpolation. Default `'bicubic'`. */
301
+ mapping?: EnvelopeMapping;
302
+ /** An envelope's patch rows and columns. Default 3 each. */
303
+ rows?: number;
304
+ cols?: number;
305
+ /** How far, in world units, the refitted result may stray from the exact
306
+ * warp. Default {@link DEFAULT_WARP_TOLERANCE}. */
307
+ tolerance?: number;
308
+ }
309
+ /** The refit tolerance of a warp made without one. */
310
+ declare const DEFAULT_WARP_TOLERANCE = 0.5;
311
+ /** The patch rows and columns of an envelope made without them. */
312
+ declare const DEFAULT_ENVELOPE_SIZE = 3;
313
+ /**
314
+ * `shape` (a node's pose and data) warped by `warp`, whose controls are in
315
+ * world space, and holding it — for a scene that opens on a warp already
316
+ * made. Null when `shape` holds no editable polygon.
317
+ */
318
+ declare function withPathWarp<S extends {
319
+ pose: unknown;
320
+ data: unknown;
321
+ }>(shape: S, warp: PathWarp, opts?: {
322
+ id?: string;
323
+ tolerance?: number;
324
+ }): {
325
+ pose: unknown;
326
+ data: unknown;
327
+ } | null;
328
+
329
+ /**
330
+ * The params this package's actions read, merged into routing's
331
+ * `ActionParamSchema` so `<SceneCanvas tune>` types them.
332
+ */
333
+
334
+ /** A path effect's settings as params; a blend's `reverse` also takes
335
+ * `'auto'`, handing the direction back to `autoAlign`. */
336
+ type SettingsOf<E> = {
337
+ [K in Exclude<keyof E, 'kind'>]?: E[K];
338
+ };
339
+ type BlendParams = Omit<SettingsOf<BlendEffect>, 'reverse'> & {
340
+ reverse?: boolean | 'auto';
341
+ };
342
+ type EditPathEffectParams = BlendParams & SettingsOf<BendAlongEffect> & SettingsOf<RepeatAlongEffect> & {
343
+ ids?: readonly string[];
344
+ };
345
+ declare module '@weasel-js/routing' {
346
+ interface ActionParamSchema {
347
+ blend: BlendParams;
348
+ bendAlong: SettingsOf<BendAlongEffect>;
349
+ repeatAlong: SettingsOf<RepeatAlongEffect>;
350
+ editPathEffect: EditPathEffectParams;
351
+ simplifyBrush: SimplifyBrushParams;
352
+ smudgeBrush: SmudgeBrushParams;
353
+ bridgePaths: {
354
+ tension?: number;
355
+ };
356
+ bridgeAnchors: {
357
+ tension?: number;
358
+ };
359
+ constrainAnchors: ConstrainAnchorsParams;
360
+ unconstrainAnchors: {
361
+ kind?: PathConstraintKind;
362
+ };
363
+ 'distort.drag': WarpSettings;
364
+ 'envelope.drag': WarpSettings;
365
+ 'puppet.drag': WarpSettings;
366
+ 'puppet.addPin': WarpSettings;
367
+ configureWarp: WarpSettings & {
368
+ kind?: WarpKind;
369
+ };
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Toggles for the locks every path-edit handle drag holds without a
375
+ * modifier: its angle, its length, or both, which freezes it. They set the
376
+ * `editAnchors` dep's `handleLocks`, so a bar, the command palette, and
377
+ * `<SceneCanvas tune>`'s `handleLock` param, which they start from, all
378
+ * reach the one value the drag reads.
379
+ */
380
+
381
+ /** Hold every handle drag to the handle's angle, as Shift does. */
382
+ declare const handleLockAngleAction: Action & {
383
+ requires: string[];
384
+ };
385
+ /** Hold every handle drag to the handle's length, as Mod (Cmd or Ctrl) does. */
386
+ declare const handleLockLengthAction: Action & {
387
+ requires: string[];
388
+ };
389
+
390
+ /**
391
+ * Bridge: join open path ends with a curve that leaves each end along the
392
+ * direction its path was heading, on whole paths or on the two anchors
393
+ * selected in path edit.
394
+ */
395
+
396
+ /** How long Bridge makes each handle, as a fraction of the gap, when its
397
+ * params name no `tension`. */
398
+ declare const DEFAULT_BRIDGE_TENSION = 0.4;
399
+ /** A bridge's `params.tension`, or the default. Negative reads as `0`. */
400
+ declare function bridgeTensionOf(params: Record<string, unknown> | undefined): number;
401
+ /**
402
+ * @experimental Bridge open paths: as `joinPaths`, but the gap is spanned by
403
+ * a curve leaving each end along the direction its path was heading, each
404
+ * handle `params.tension` times the gap long (default
405
+ * {@link DEFAULT_BRIDGE_TENSION}). Two paths become one. In path edit,
406
+ * `bridgeAnchors` bridges the two selected anchors instead.
407
+ */
408
+ declare const bridgePathsAction: Action & {
409
+ requires: string[];
410
+ };
411
+ /**
412
+ * @experimental Bridge the two selected anchors, each the end of an open
413
+ * subpath, as `joinAnchors` does, but with a curve leaving each end along the
414
+ * direction its path was heading, each handle `params.tension` times the gap
415
+ * long (`bridgePaths`'s default when absent). The anchor selection is
416
+ * cleared.
417
+ */
418
+ declare const bridgeAnchorsAction: Action & {
419
+ requires: string[];
420
+ };
421
+
422
+ /** Trim segment: cut a stroke back to the crossings on either side of a click. */
423
+
424
+ /** What a trim at the press in `params` would do: the stroke it reaches, and
425
+ * what `trimPathAt` makes of it. Null when it reaches none it can trim.
426
+ * `params` as {@link trimPathAction} reads them; a hover's pointer serves
427
+ * as the press, which is how a tool previews the piece. */
428
+ declare function planTrim(deps: ActionDeps, params: unknown): {
429
+ target: PathNode;
430
+ result: TrimResult;
431
+ } | null;
432
+ /**
433
+ * @experimental Trim segment: remove the piece of the stroke under the press
434
+ * between the nearest crossings on either side — with any other node's
435
+ * outline, or with itself — as `trimPathAt` cuts it. The topmost stroke
436
+ * within `radiusPx` of the press (default 6) is the one trimmed; a stroke
437
+ * with nothing left is deleted. Params: `pressX`, `pressY` in world space,
438
+ * which a click binding supplies.
439
+ */
440
+ declare const trimPathAction: Action & {
441
+ requires: string[];
442
+ };
443
+
444
+ /** Extend to next path: carry an open end along its tangent until it meets a stroke. */
445
+
446
+ /**
447
+ * @experimental Extend to next path: carry each open end of the selected
448
+ * paths along its tangent to the first stroke it meets (`extendToMeet`). In
449
+ * path edit, the selected end anchors of the edited path, or all its open
450
+ * ends when none is selected. Given a press (`pressX`, `pressY`, as a click
451
+ * binding supplies), the open end nearest it of the topmost stroke within
452
+ * `radiusPx` instead. An end that meets nothing stays put. One undo step.
453
+ */
454
+ declare const extendToMeetAction: Action & {
455
+ requires: string[];
456
+ };
457
+
458
+ /**
459
+ * Make the selected smooth anchors curvature-continuous by adjusting their
460
+ * handle lengths, or every smooth anchor of the path while none is selected.
461
+ */
462
+ declare const harmonizeAnchorsAction: _weasel_js_routing.Action & {
463
+ requires: string[];
464
+ };
465
+
466
+ /**
467
+ * The balance grip on each curved segment of the path being edited, midway
468
+ * along the line joining its two handle tips:
469
+ *
470
+ * - `balanceHandles` — drag the grip to scale both handles together, each
471
+ * along its own direction, so the segment fills out toward its corner or
472
+ * flattens toward its chord without turning at either end.
473
+ * - `equalizeHandles` — double-click the grip to give both handles the same
474
+ * proportion of the way to that corner.
475
+ *
476
+ * The grips are the `balance:N` affordances path edit lays out, shown and
477
+ * hit-tested only while chrome-caps shows `path-edit.balance`. N is the flat
478
+ * index of the anchor the segment starts at.
479
+ *
480
+ * Under a `pathSymmetry` dep a grip drag moves every image of both handles,
481
+ * as `editAnchors` moves a dragged handle's. Both keep each handle's angle, so an angle lock holds through them. A length
482
+ * lock in force for handle drags (the `editAnchors` dep's `handleLocks`, or Mod)
483
+ * holds the drag still, as it would a handle drag with the angle held too.
484
+ */
485
+
486
+ /** Drag a segment's balance grip to scale both its handles together. */
487
+ declare const balanceHandlesAction: Action & {
488
+ requires: string[];
489
+ };
490
+ /** Double-click a segment's balance grip to even out its handles' proportions. */
491
+ declare const equalizeHandlesAction: Action & {
492
+ requires: string[];
493
+ };
494
+
495
+ /**
496
+ * The path-effect actions: make a live blend, bend, or repeat from the
497
+ * selection; change one's settings; and expand one into ordinary paths.
498
+ */
499
+
500
+ /** The `group` every path-effect action is in, for an `<ActionBar>`. */
501
+ declare const PATH_EFFECTS_GROUP = "pathEffects";
502
+ /**
503
+ * Steps between the first two selected shapes, in the order they were
504
+ * selected: `params.steps` of them, each shape, fill, stroke and turn
505
+ * interpolated. The blend is live — editing either source moves its steps —
506
+ * and goes just under the upper source. Its other params are
507
+ * `BlendEffect`'s.
508
+ */
509
+ declare const blendAction: Action & {
510
+ requires: string[];
511
+ };
512
+ /**
513
+ * The first selected shape bent along the second, live: editing the spine
514
+ * re-bends it. Params are `BendAlongEffect`'s.
515
+ */
516
+ declare const bendAlongAction: Action & {
517
+ requires: string[];
518
+ };
519
+ /**
520
+ * Copies of the first selected shape along the second, live. Params are
521
+ * `RepeatAlongEffect`'s.
522
+ */
523
+ declare const repeatAlongAction: Action & {
524
+ requires: string[];
525
+ };
526
+ /**
527
+ * Change the settings of path effects: `params.ids` when given, else the
528
+ * selected ones. Every other param is a setting, laid over each effect's
529
+ * own, and one that would change nothing commits nothing. Consecutive edits
530
+ * of one effect coalesce, so a slider dragged through many values is one
531
+ * undo step where the scene coalesces.
532
+ */
533
+ declare const editPathEffectAction: Action & {
534
+ requires: string[];
535
+ };
536
+ /**
537
+ * Turn each selected path effect into the ordinary paths it shows, in its
538
+ * slot and in its paint, and select them. Its sources stay; the paths no
539
+ * longer follow them.
540
+ */
541
+ declare const expandPathEffectAction: Action & {
542
+ requires: string[];
543
+ };
544
+
545
+ /**
546
+ * The warp actions. A warp tool binds the per-kind ones (`<kind>.drag`,
547
+ * `puppet.addPin`, `puppet.removePin`) and owns them; `expandWarp` and
548
+ * `configureWarp` work on whatever warp the selection holds and ship with
549
+ * the `paths` preset.
550
+ */
551
+
552
+ /** What a press on a warp control hands the drag that follows. */
553
+ interface WarpHandleScratch {
554
+ /** The warp the control belongs to, or null for one shown over a selection
555
+ * holding none yet, which the drag makes. */
556
+ warpId: string | null;
557
+ /** The control's index, as `warpControls` counts them. */
558
+ index: number;
559
+ }
560
+ /** The scratch a control press carried, or null when the press was elsewhere. */
561
+ declare function warpHandleScratchOf(hit: unknown): WarpHandleScratch | null;
562
+ /**
563
+ * Drop the warp from each selected path, keeping the geometry it made: the
564
+ * shape becomes plain geometry that path editing and other warps start from.
565
+ */
566
+ declare const expandWarpAction: Action;
567
+ /**
568
+ * Remake the selection's warps under new settings (`params`, a
569
+ * {@link WarpSettings}, plus an optional `kind` limiting it to one kind of
570
+ * warp): switch a distort between free and perspective, an envelope between
571
+ * its mappings or to a finer grid, or refit at another tolerance. One undo step.
572
+ */
573
+ declare const configureWarpAction: Action;
574
+
575
+ /** Options for a tool that acts on the stroke under a click. */
576
+ interface StrokeClickToolOptions {
577
+ /** Override the default keybinding. Pass `null` to omit. */
578
+ keybinding?: ToolKeybinding | null;
579
+ /** How far from a stroke a click may land and still reach it, in screen
580
+ * pixels. Read on every click. Default 6. */
581
+ radiusPx?: number | (() => number);
582
+ }
583
+
584
+ /** Options for `useTrimTool`; the default keybinding is `{ key: 'Y' }`. */
585
+ type UseTrimToolOptions = StrokeClickToolOptions;
586
+ /**
587
+ * Trim segment tool. A click on a stroke removes its piece between the
588
+ * crossings on either side — a declarative shell over the `trimPath` action,
589
+ * which owns the hit-test and the commit. While it is up, the piece under the
590
+ * pointer is drawn dashed, through the same `planTrim` the click commits.
591
+ */
592
+ declare function useTrimTool(options?: UseTrimToolOptions): Tool;
593
+
594
+ /** Options for `useExtendTool`; the default keybinding is `{ key: 'U' }`. */
595
+ type UseExtendToolOptions = StrokeClickToolOptions;
596
+ /**
597
+ * Extend to next path tool. A click near an open end of a stroke carries
598
+ * that end along its tangent to the next stroke it meets — a declarative
599
+ * shell over the `extendToMeet` action.
600
+ */
601
+ declare function useExtendTool(options?: UseExtendToolOptions): Tool;
602
+
603
+ /** Options for `useSmudgeBrushTool`. */
604
+ interface UseSmudgeBrushToolOptions {
605
+ /** Override the default keybinding (`{ key: 'S' }`). Pass `null` to omit. */
606
+ keybinding?: ToolKeybinding | null;
607
+ }
608
+ /**
609
+ * Smudge brush tool. A round brush that pushes the outline of the selected
610
+ * paths along with the pointer — a declarative shell whose one binding routes a
611
+ * drag to the `smudgeBrush` action, which owns the stroke, its preview, its ring
612
+ * cursor, and its one undo entry. The brush's radius (screen px) and strength are
613
+ * that action's params: `tune={{ smudgeBrush: { params: () => ({ radiusPx, strength }) } }}`.
614
+ */
615
+ declare function useSmudgeBrushTool(options?: UseSmudgeBrushToolOptions): Tool;
616
+
617
+ /** A warp tool: a `Tool` that also registers the layer showing its controls. */
618
+ type WarpTool = Tool & Pick<SurfaceContribution, 'attach'>;
619
+ /** Options every warp tool takes. */
620
+ interface WarpToolOptions {
621
+ /** Palette label. */
622
+ label?: string;
623
+ /** Override the default keybinding (Distort `F`, Envelope `M`, Puppet Warp
624
+ * `B`). Pass `null` to omit. */
625
+ keybinding?: ToolKeybinding | null;
626
+ /** How far, in world units, a warped path's refitted curves may stray from
627
+ * the exact warp. Default 0.5. */
628
+ tolerance?: number;
629
+ }
630
+ /** Options for {@link useDistortTool}. */
631
+ interface UseDistortToolOptions extends WarpToolOptions {
632
+ /** The map a new distort starts with: `'free'` (bilinear, the default) or
633
+ * `'perspective'` (projective). */
634
+ mode?: DistortMode;
635
+ }
636
+ /** Options for {@link useEnvelopeTool}. */
637
+ interface UseEnvelopeToolOptions extends WarpToolOptions {
638
+ /** Patch rows and columns of a new envelope's mesh. Default 3 each. */
639
+ rows?: number;
640
+ cols?: number;
641
+ /** How a new envelope interpolates its mesh. Default `'bicubic'`. */
642
+ mapping?: EnvelopeMapping;
643
+ }
644
+ /** Options for {@link usePuppetTool}. */
645
+ type UsePuppetToolOptions = WarpToolOptions;
646
+ /**
647
+ * Distort the selected paths by their box's four corners, each dragged on its
648
+ * own. The first drag gives the selection a distort, kept on each path as
649
+ * `data.warp` until it is expanded (`expandWarp`); selecting the paths again
650
+ * with this tool shows its corners where they were left. `configureWarp`
651
+ * switches a held distort between free and perspective.
652
+ */
653
+ declare function useDistortTool(options?: UseDistortToolOptions): WarpTool;
654
+ /**
655
+ * Warp the selected paths through a mesh of control points over their box:
656
+ * drag any point and the shape bends smoothly around it. The mesh is held on
657
+ * each path until it is expanded, and `configureWarp` changes its grid or its
658
+ * interpolation.
659
+ */
660
+ declare function useEnvelopeTool(options?: UseEnvelopeToolOptions): WarpTool;
661
+ /**
662
+ * Pin the selected paths where they are clicked, and drag a pin to bend them:
663
+ * the rest of the shape follows as rigidly as the pins allow, and a pin left
664
+ * alone holds its place. Alt-click a pin to take it out. The pins are held on
665
+ * each path until it is expanded.
666
+ */
667
+ declare function usePuppetTool(options?: UsePuppetToolOptions): WarpTool;
668
+
669
+ /** The id of the layer showing a `kind` warp's controls. A binding reaches
670
+ * its controls through `affordance:layer:<id>`. */
671
+ declare const warpLayerId: (kind: WarpKind) => string;
672
+
673
+ /**
674
+ * Path constraints in path edit: their marks on the open path, a click
675
+ * selecting one, Delete removing it, and every edit finished so they hold.
676
+ */
677
+
678
+ /** Owner id of the constraint marks, as `EditAnchorsDep.selectedMark` names them. */
679
+ declare const CONSTRAINTS_EXTENSION_ID = "constraints";
680
+ /**
681
+ * Replace the open path's constraints with `constraints` as one history
682
+ * entry, moving it the least that makes them all hold. When they cannot all
683
+ * hold the path stays as it is and the list is stored all the same, the
684
+ * conflict left for the marks to show. Clears the selected mark, since the
685
+ * list is renumbered. False when the dep cannot store.
686
+ */
687
+ declare function setConstraints(dep: EditAnchorsDep, constraints: readonly PathConstraint[], label: string): boolean;
688
+ /** The constraint selected in path edit, as an index into the open path's list, or null. */
689
+ declare function selectedConstraintOf(dep: EditAnchorsDep): number | null;
690
+ /** The constraints extension, its marks drawn in `style`'s colors. */
691
+ declare function createConstraintsExtension(style?: Partial<ConstraintGlyphStyle>): PathEditExtension;
692
+
693
+ /**
694
+ * A node's path constraints: kept as `data.constraints`, numbered by the
695
+ * anchors of its editable polygon, and solved in the frame that polygon is
696
+ * drawn in, so `horizontal` on a rotated `data.path` node turns with it.
697
+ */
698
+
699
+ /** The constraints a node's data holds, or none. */
700
+ declare function constraintsOf(data: unknown): readonly PathConstraint[];
701
+ /** Radians the frame `horizontal` and `vertical` read is turned from the world's: a `data.path` node's rotation. */
702
+ declare function constraintAxisOf(node: EditableShape | null | undefined): number;
703
+ /**
704
+ * Indices of `node`'s constraints that do not hold in its committed path:
705
+ * the ones that conflict with the rest. Edits leave them out of the solve,
706
+ * and so does a whole-shape transform — resize, rotate, flip — which carries
707
+ * the list unchanged: a constraint the transform breaks, such as a set
708
+ * length under a scale or an equal length under a non-uniform one, is
709
+ * reported here rather than solved back.
710
+ */
711
+ declare function constraintConflictsOf(node: EditableShape | null | undefined): number[];
712
+
713
+ export { CONSTRAINTS_EXTENSION_ID, type ConstrainAnchorsParams, type ConstraintGlyphStyle, DEFAULT_BRIDGE_TENSION, DEFAULT_ENVELOPE_SIZE, DEFAULT_SMUDGE_RADIUS_PX, DEFAULT_SMUDGE_STRENGTH, DEFAULT_WARP_TOLERANCE, type HeldPathWarp, PATH_BALANCE_CHROME_ID, PATH_COMB_CHROME_ID, PATH_EFFECTS_GROUP, type PathEditBalanceStyle, type PathEditCombOptions, type ResolvedPathWarp, SIMPLIFY_BRUSH_RADIUS_PX, SIMPLIFY_BRUSH_TOOL, type SimplifyBrushParams, type SmudgeBrushParams, type StrokeClickToolOptions, type UseDistortToolOptions, type UseEnvelopeToolOptions, type UseExtendToolOptions, type UsePuppetToolOptions, type UseSmudgeBrushToolOptions, type UseTrimToolOptions, type WarpHandleScratch, type WarpKind, type WarpSettings, type WarpTool, balanceCommands, balanceHandlesAction, balancePreset, bendAlongAction, blendAction, bridgeAnchorsAction, bridgePathsAction, bridgePreset, bridgeTensionOf, brushRingCursor, combCommands, configureWarpAction, constrainAnchorsAction, constraintAxisOf, constraintConflictsOf, constraintsForAnchors, constraintsOf, constraintsPreset, createBalanceExtension, createBalancePreset, createCombExtension, createConstraintsExtension, createConstraintsPreset, createCurvatureCombPreset, curvatureCombPreset, deleteConstraintAction, editPathEffectAction, equalizeHandlesAction, expandPathEffectAction, expandWarpAction, extendPreset, extendToMeetAction, handleLockAngleAction, handleLockLengthAction, handleLocksPreset, harmonizeAnchorsAction, harmonizePreset, heldPathWarpOf, pathEffectsPreset, pathTools, planTrim, repeatAlongAction, resolvePathWarp, selectedConstraintOf, setConstraints, simplifyBrushAction, simplifyBrushPreset, simplifyBrushToolAction, smudgeBrushAction, smudgePreset, trimPathAction, trimPreset, unconstrainAnchorsAction, useDistortTool, useEnvelopeTool, useExtendTool, usePuppetTool, useSmudgeBrushTool, useTrimTool, warpHandleScratchOf, warpLayerId, warpPreset, withPathWarp, withoutPathWarp };