@pixerate/editor 0.246.0 → 0.249.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.
Files changed (105) hide show
  1. package/README.md +1 -0
  2. package/dist/animation-editor/index.cjs +64 -61
  3. package/dist/animation-editor/index.js +8 -5
  4. package/dist/{brushstrokeRender-ZDHMXJAE.cjs → brushstrokeRender-GCKK7V2I.cjs} +14 -11
  5. package/dist/{brushstrokeRender-AKUI3SEJ.js → brushstrokeRender-T3JZST44.js} +7 -4
  6. package/dist/canvas/index.cjs +8 -8
  7. package/dist/canvas/index.js +1 -1
  8. package/dist/{chunk-UVPD55UZ.cjs → chunk-2SMMZDMG.cjs} +35 -35
  9. package/dist/chunk-2VJAVXLI.js +192 -0
  10. package/dist/{chunk-OLNIPTB3.cjs → chunk-2VX55NFM.cjs} +1 -320
  11. package/dist/chunk-3K6HWEXZ.cjs +92 -0
  12. package/dist/{chunk-UOOK7HTX.js → chunk-3PPJRMIG.js} +1 -1
  13. package/dist/chunk-4D6KP5BV.js +92 -0
  14. package/dist/chunk-5RH3VXAK.js +269 -0
  15. package/dist/{chunk-LDPLEZ5T.js → chunk-6BIDVPED.js} +1 -1
  16. package/dist/{chunk-2ONK3ERD.cjs → chunk-75K3W4D6.cjs} +20 -20
  17. package/dist/chunk-BOHDJJ2O.cjs +192 -0
  18. package/dist/{chunk-2PBZBRP5.js → chunk-D5KGAO4Z.js} +10 -92
  19. package/dist/{chunk-DQWPMGH2.js → chunk-DOIU7VJG.js} +1 -1
  20. package/dist/{chunk-HB4ICNNA.cjs → chunk-DPYAO5U6.cjs} +42 -42
  21. package/dist/chunk-EJLRBS5Q.js +301 -0
  22. package/dist/{chunk-Q2UYUWAZ.cjs → chunk-H4AOUUBE.cjs} +679 -164
  23. package/dist/{chunk-PQ3H2AAN.cjs → chunk-I7NJPHWV.cjs} +122 -204
  24. package/dist/{chunk-FK5LTDOO.cjs → chunk-IOFVM3L3.cjs} +7 -7
  25. package/dist/{chunk-42TWUPNJ.js → chunk-IRSTHLQQ.js} +1 -320
  26. package/dist/{chunk-VDAWA546.js → chunk-J7T5QZ45.js} +614 -99
  27. package/dist/{chunk-VMROIWLL.cjs → chunk-KBYB7OWB.cjs} +3 -3
  28. package/dist/{chunk-5MFDD7SP.cjs → chunk-KYX7NZ5V.cjs} +1 -1
  29. package/dist/chunk-LJRCU3BJ.cjs +301 -0
  30. package/dist/{chunk-XTWXBQD4.cjs → chunk-LP2MCSBE.cjs} +593 -236
  31. package/dist/{chunk-A23PSOBB.js → chunk-O75V4ZS3.js} +1 -1
  32. package/dist/chunk-OTTT5N3K.js +322 -0
  33. package/dist/{chunk-N6WUB3Y5.js → chunk-PZP2SZIZ.js} +2 -2
  34. package/dist/{chunk-4PMCMWQS.js → chunk-UBRJOIR5.js} +367 -10
  35. package/dist/chunk-W5M3J7PV.cjs +322 -0
  36. package/dist/{chunk-4P6H35HU.js → chunk-WA44NKPF.js} +2 -2
  37. package/dist/{chunk-CEPKXLBS.cjs → chunk-WLJZZHUZ.cjs} +23 -23
  38. package/dist/{chunk-P3NIPIKS.js → chunk-WQCNC4DK.js} +1 -1
  39. package/dist/chunk-ZEYMKDYS.cjs +269 -0
  40. package/dist/image-editor/effect-tools.d.cts +37 -4
  41. package/dist/image-editor/effect-tools.d.ts +37 -4
  42. package/dist/image-editor/index.cjs +1340 -1828
  43. package/dist/image-editor/index.d.cts +1 -1
  44. package/dist/image-editor/index.d.ts +1 -1
  45. package/dist/image-editor/index.js +298 -786
  46. package/dist/paint/index.cjs +8 -5
  47. package/dist/paint/index.js +13 -10
  48. package/dist/paint-editor/controller.d.cts +71 -2
  49. package/dist/paint-editor/controller.d.ts +71 -2
  50. package/dist/paint-editor/index.cjs +901 -589
  51. package/dist/paint-editor/index.d.cts +3 -0
  52. package/dist/paint-editor/index.d.ts +3 -0
  53. package/dist/paint-editor/index.js +365 -53
  54. package/dist/paint-editor/procedural.d.cts +82 -5
  55. package/dist/paint-editor/procedural.d.ts +82 -5
  56. package/dist/paint-editor/sticker-art.d.cts +55 -0
  57. package/dist/paint-editor/sticker-art.d.ts +55 -0
  58. package/dist/paint-editor/stickers.d.cts +30 -17
  59. package/dist/paint-editor/stickers.d.ts +30 -17
  60. package/dist/paint-editor/stroke.d.cts +4 -0
  61. package/dist/paint-editor/stroke.d.ts +4 -0
  62. package/dist/paint-editor/tools.d.cts +1 -1
  63. package/dist/paint-editor/tools.d.ts +1 -1
  64. package/dist/paint-editor/ui.d.cts +25 -4
  65. package/dist/paint-editor/ui.d.ts +25 -4
  66. package/dist/{image-editor/layers/effects-ui.d.cts → raster/effects/ui.d.cts} +32 -5
  67. package/dist/{image-editor/layers/effects-ui.d.ts → raster/effects/ui.d.ts} +32 -5
  68. package/dist/raster/index.cjs +17 -3
  69. package/dist/raster/index.d.cts +1 -0
  70. package/dist/raster/index.d.ts +1 -0
  71. package/dist/raster/index.js +23 -9
  72. package/dist/stickers/browser.d.cts +48 -0
  73. package/dist/stickers/browser.d.ts +48 -0
  74. package/dist/stickers/combine.d.cts +10 -0
  75. package/dist/stickers/combine.d.ts +10 -0
  76. package/dist/stickers/conformance.d.cts +18 -0
  77. package/dist/stickers/conformance.d.ts +18 -0
  78. package/dist/stickers/editor.d.cts +14 -0
  79. package/dist/stickers/editor.d.ts +14 -0
  80. package/dist/stickers/errors.d.cts +6 -0
  81. package/dist/stickers/errors.d.ts +6 -0
  82. package/dist/stickers/fake.d.cts +16 -0
  83. package/dist/stickers/fake.d.ts +16 -0
  84. package/dist/stickers/helpers.d.cts +51 -0
  85. package/dist/stickers/helpers.d.ts +51 -0
  86. package/dist/stickers/index.cjs +331 -0
  87. package/dist/stickers/index.d.cts +16 -0
  88. package/dist/stickers/index.d.ts +16 -0
  89. package/dist/stickers/index.js +331 -0
  90. package/dist/stickers/stamps.d.cts +13 -0
  91. package/dist/stickers/stamps.d.ts +13 -0
  92. package/dist/stickers/tools.d.cts +25 -0
  93. package/dist/stickers/tools.d.ts +25 -0
  94. package/dist/stickers/types.d.cts +123 -0
  95. package/dist/stickers/types.d.ts +123 -0
  96. package/dist/vector/index.cjs +978 -975
  97. package/dist/vector/index.js +9 -6
  98. package/package.json +11 -1
  99. package/skills/README.md +1 -0
  100. package/skills/pixerate-paint-editor/SKILL.md +26 -32
  101. package/skills/pixerate-paint-editor/references/gradient-paint.md +23 -0
  102. package/skills/pixerate-paint-editor/references/layer-effects.md +28 -0
  103. package/skills/pixerate-paint-editor/references/light-paint.md +10 -2
  104. package/skills/pixerate-paint-editor/references/particle-brushes.md +66 -0
  105. package/skills/pixerate-stickers/SKILL.md +45 -0
@@ -6,8 +6,12 @@
6
6
  * rules. `string`: strands of masses on springs, dragged behind the pen like hair or wet string;
7
7
  * `spring`: each particle tied to the pen by a spring, overshooting and wobbling; `orbit`:
8
8
  * particles circling the pen (spirograph curls); `flow`: particles thrown off the pen and carried
9
- * by a swirling flow field until they fade. Each is drawn as `dot`s, a continuous `line`, or a
10
- * `sequence` of beads spaced along its path.
9
+ * by a swirling flow field until they fade; `elastic`: strands whose masses keep a rest length,
10
+ * stretching when the pen is fast and snapping back; `fuzzy`: strings that wind, each strand
11
+ * waving out of step with the others. Each is drawn as `dot`s (round, or stamped with up to four
12
+ * textures), a continuous `line`, a `sequence` of beads spaced along its path, or a `ribbon`:
13
+ * the area between neighbouring particles' paths filled, with their paths as its edges. Any kind
14
+ * can wave: each particle's drawn place moves sideways on a sine along the pen's path.
11
15
  * - **Bristle brushes** (`engine: 'bristle'`): a tuft of bristles, each its own thin line. Pressure
12
16
  * splays the tuft, tilt flattens it, and bristles lag behind the tip by their stiffness, so they
13
17
  * bend into curves at turns; each bristle carries its own paint and runs dry at its own pace, so
@@ -19,11 +23,12 @@
19
23
  */
20
24
  import { CoverageMap } from '../paint/brush.cjs';
21
25
  import { type PaintGradientSource } from '../paint/gradient-paint.cjs';
22
- import type { RasterRect } from '../raster/surface.cjs';
26
+ import { type RasterRect } from '../raster/surface.cjs';
23
27
  import type { PaintBrush } from './brushes.cjs';
24
28
  import { type EffectPaintPixels } from './effect-paint.cjs';
25
29
  import { PenDabWalker, PenSmoother, type PenDab, type PenPoint, type StrokeCopy } from './engine.cjs';
26
30
  import { type PaperGrain } from './paper.cjs';
31
+ import { type StampKind } from './stickers.cjs';
27
32
  export interface ProceduralStrokeOptions {
28
33
  grain: PaperGrain | null;
29
34
  paperDepth: number;
@@ -71,13 +76,36 @@ declare abstract class MarkStroke implements CoverageStroke {
71
76
  protected abstract advance(copy: number, d: PenDab, rects: RasterRect[]): void;
72
77
  /** Stamps one round mark of radius `r` at (x, y) with flow `alpha` towards `opacity`. */
73
78
  protected mark(x: number, y: number, r: number, alpha: number, opacity: number, pressure: number, rects: RasterRect[]): void;
79
+ /**
80
+ * Stamps a textured mark: `kind` from the sticker stamps over a square of half-size `r`, turned
81
+ * `rotation` radians clockwise, with flow `alpha` towards `opacity`. Small marks are supersampled.
82
+ */
83
+ protected stamp(x: number, y: number, r: number, kind: StampKind, rotation: number, seed: number, alpha: number, opacity: number, pressure: number, rects: RasterRect[]): void;
84
+ /** A scratch buffer of `n` values (reused; valid until the next mark). */
85
+ protected scratch(n: number): Float32Array;
86
+ /**
87
+ * Lays coverage `vals` over `rect` towards `opacity`: paper grain, then effect paint or the
88
+ * colour of a mark at (x, y) (gradient paint), into the stroke's coverage.
89
+ */
90
+ protected lay(rect: RasterRect, vals: Float32Array, opacity: number, pressure: number, x: number, y: number, rects: RasterRect[]): void;
74
91
  /** Marks along a segment, spaced by a fraction of the radius. */
75
92
  protected segment(x0: number, y0: number, x1: number, y1: number, r: number, alpha: number, opacity: number, pressure: number, rects: RasterRect[]): void;
76
93
  }
77
- export type ParticleKind = 'string' | 'spring' | 'orbit' | 'flow';
94
+ export type ParticleKind = 'string' | 'spring' | 'orbit' | 'flow' | 'elastic' | 'fuzzy';
78
95
  export declare const PARTICLE_KINDS: readonly ParticleKind[];
79
- export type ParticleRender = 'dot' | 'line' | 'sequence';
96
+ export type ParticleRender = 'dot' | 'line' | 'sequence' | 'ribbon';
80
97
  export declare const PARTICLE_RENDERS: readonly ParticleRender[];
98
+ /** Ribbon: which particles' paths are joined (`adjacent`: each to its neighbour; `first-last`: one band between the outermost two). */
99
+ export type RibbonPairs = 'adjacent' | 'first-last';
100
+ export declare const RIBBON_PAIRS: readonly RibbonPairs[];
101
+ /** Textured dots: the stamps in turn, or one picked at random (seeded) per dot. */
102
+ export type DotTextureOrder = 'sequence' | 'random';
103
+ export declare const DOT_TEXTURE_ORDERS: readonly DotTextureOrder[];
104
+ /** Textured dots: turned with the particle's motion, at random, or at the tip angle. */
105
+ export type DotRotation = 'follow' | 'random' | 'fixed';
106
+ export declare const DOT_ROTATIONS: readonly DotRotation[];
107
+ /** Textured dots: at most this many stamps. */
108
+ export declare const MAX_DOT_TEXTURES = 4;
81
109
  /** Particle engine settings (each 0..1 unless noted). */
82
110
  export interface ParticleSettings {
83
111
  kind: ParticleKind;
@@ -100,17 +128,66 @@ export interface ParticleSettings {
100
128
  life: number;
101
129
  /** Sequence: spacing of the beads along each path. */
102
130
  interval: number;
131
+ /** Ribbon: opacity of the fill between the paths, relative to their edges. */
132
+ ribbonFill: number;
133
+ /** Ribbon: which paths are joined. */
134
+ ribbonPairs: RibbonPairs;
135
+ /** Wave: how far each particle's drawn place swings sideways, as a fraction of the tip size (0: no wave). */
136
+ waveAmplitude: number;
137
+ /** Wave: wavelength in px of pen travel, 4..2000. */
138
+ waveLength: number;
139
+ /** Wave: how fast the waves run (0: they stand still on the path; 1: about four a second while the pen moves). */
140
+ waveSpeed: number;
141
+ /** Wave: how far out of step the particles' waves are (0: all in step; 1: random phases). */
142
+ wavePhaseJitter: number;
143
+ /** Dots and beads: up to four sticker stamps drawn instead of round marks (empty: round). */
144
+ dotTextures: StampKind[];
145
+ dotTextureOrder: DotTextureOrder;
146
+ dotRotation: DotRotation;
103
147
  }
104
148
  export declare const DEFAULT_PARTICLE: Readonly<ParticleSettings>;
105
149
  export declare function normalizeParticle(raw?: Partial<ParticleSettings>, base?: ParticleSettings): ParticleSettings;
150
+ /**
151
+ * Adds the area polygon `pts` (x, y pairs, even-odd) covers in each pixel of `rect`, times `weight`, to `out`,
152
+ * exactly across each of `RIBBON_SUB` sub-rows per row. Points on an edge two polygons share
153
+ * count for exactly one of them, so polygons that tile a region add up to it with no seams.
154
+ */
155
+ export declare function addPolygonArea(pts: readonly number[], rect: RasterRect, out: Float32Array, weight?: number): void;
106
156
  /** A particle-brush stroke. */
107
157
  export declare class ParticleStroke extends MarkStroke {
108
158
  private readonly sets;
159
+ /** Ribbon pairs per copy: particles in their order around the pen (non-flow kinds). */
160
+ private readonly orders;
109
161
  private readonly s;
110
162
  private spawn;
163
+ /** Textured dots drawn so far, per copy (sequence order, random picks). */
164
+ private readonly dots;
165
+ /** Ribbon fill: the area each pixel has had so far this stroke (telescoped into the coverage). */
166
+ private readonly filled;
167
+ private pts;
111
168
  constructor(brush: PaintBrush, options: ProceduralStrokeOptions);
169
+ /** Strand kinds: a chain of masses behind each particle. */
170
+ private get strands();
171
+ private newParticle;
112
172
  private init;
173
+ /** The sideways wave of particle `p` at pen dab `d` (px along the normal to the pen's direction). */
174
+ private wave;
113
175
  protected advance(copy: number, d: PenDab, rects: RasterRect[]): void;
176
+ /** A dot (or bead): round, or a textured stamp turned by the particle's motion (mx, my), at random or to the tip angle. */
177
+ private dot;
178
+ /**
179
+ * Ribbon fill for one step: the band between each pair of joined particles, from where they
180
+ * were drawn last step to where they are drawn now. Bands of one step, and of consecutive steps,
181
+ * share edges exactly, so the fill has no seams; it is telescoped into the coverage
182
+ * (`telescope`), so it does not build up at the joins.
183
+ */
184
+ private ribbon;
185
+ /**
186
+ * Turns the area newly filled over `rect` into coverage to lay towards the fill's ceiling: the
187
+ * share of what was left unfilled, so after any number of bands (in any grouping) a pixel's
188
+ * coverage is the ceiling times the area filled there. False when nothing was added.
189
+ */
190
+ private telescope;
114
191
  }
115
192
  /** Bristle engine settings (each 0..1 unless noted). */
116
193
  export interface BristleSettings {
@@ -6,8 +6,12 @@
6
6
  * rules. `string`: strands of masses on springs, dragged behind the pen like hair or wet string;
7
7
  * `spring`: each particle tied to the pen by a spring, overshooting and wobbling; `orbit`:
8
8
  * particles circling the pen (spirograph curls); `flow`: particles thrown off the pen and carried
9
- * by a swirling flow field until they fade. Each is drawn as `dot`s, a continuous `line`, or a
10
- * `sequence` of beads spaced along its path.
9
+ * by a swirling flow field until they fade; `elastic`: strands whose masses keep a rest length,
10
+ * stretching when the pen is fast and snapping back; `fuzzy`: strings that wind, each strand
11
+ * waving out of step with the others. Each is drawn as `dot`s (round, or stamped with up to four
12
+ * textures), a continuous `line`, a `sequence` of beads spaced along its path, or a `ribbon`:
13
+ * the area between neighbouring particles' paths filled, with their paths as its edges. Any kind
14
+ * can wave: each particle's drawn place moves sideways on a sine along the pen's path.
11
15
  * - **Bristle brushes** (`engine: 'bristle'`): a tuft of bristles, each its own thin line. Pressure
12
16
  * splays the tuft, tilt flattens it, and bristles lag behind the tip by their stiffness, so they
13
17
  * bend into curves at turns; each bristle carries its own paint and runs dry at its own pace, so
@@ -19,11 +23,12 @@
19
23
  */
20
24
  import { CoverageMap } from '../paint/brush.js';
21
25
  import { type PaintGradientSource } from '../paint/gradient-paint.js';
22
- import type { RasterRect } from '../raster/surface.js';
26
+ import { type RasterRect } from '../raster/surface.js';
23
27
  import type { PaintBrush } from './brushes.js';
24
28
  import { type EffectPaintPixels } from './effect-paint.js';
25
29
  import { PenDabWalker, PenSmoother, type PenDab, type PenPoint, type StrokeCopy } from './engine.js';
26
30
  import { type PaperGrain } from './paper.js';
31
+ import { type StampKind } from './stickers.js';
27
32
  export interface ProceduralStrokeOptions {
28
33
  grain: PaperGrain | null;
29
34
  paperDepth: number;
@@ -71,13 +76,36 @@ declare abstract class MarkStroke implements CoverageStroke {
71
76
  protected abstract advance(copy: number, d: PenDab, rects: RasterRect[]): void;
72
77
  /** Stamps one round mark of radius `r` at (x, y) with flow `alpha` towards `opacity`. */
73
78
  protected mark(x: number, y: number, r: number, alpha: number, opacity: number, pressure: number, rects: RasterRect[]): void;
79
+ /**
80
+ * Stamps a textured mark: `kind` from the sticker stamps over a square of half-size `r`, turned
81
+ * `rotation` radians clockwise, with flow `alpha` towards `opacity`. Small marks are supersampled.
82
+ */
83
+ protected stamp(x: number, y: number, r: number, kind: StampKind, rotation: number, seed: number, alpha: number, opacity: number, pressure: number, rects: RasterRect[]): void;
84
+ /** A scratch buffer of `n` values (reused; valid until the next mark). */
85
+ protected scratch(n: number): Float32Array;
86
+ /**
87
+ * Lays coverage `vals` over `rect` towards `opacity`: paper grain, then effect paint or the
88
+ * colour of a mark at (x, y) (gradient paint), into the stroke's coverage.
89
+ */
90
+ protected lay(rect: RasterRect, vals: Float32Array, opacity: number, pressure: number, x: number, y: number, rects: RasterRect[]): void;
74
91
  /** Marks along a segment, spaced by a fraction of the radius. */
75
92
  protected segment(x0: number, y0: number, x1: number, y1: number, r: number, alpha: number, opacity: number, pressure: number, rects: RasterRect[]): void;
76
93
  }
77
- export type ParticleKind = 'string' | 'spring' | 'orbit' | 'flow';
94
+ export type ParticleKind = 'string' | 'spring' | 'orbit' | 'flow' | 'elastic' | 'fuzzy';
78
95
  export declare const PARTICLE_KINDS: readonly ParticleKind[];
79
- export type ParticleRender = 'dot' | 'line' | 'sequence';
96
+ export type ParticleRender = 'dot' | 'line' | 'sequence' | 'ribbon';
80
97
  export declare const PARTICLE_RENDERS: readonly ParticleRender[];
98
+ /** Ribbon: which particles' paths are joined (`adjacent`: each to its neighbour; `first-last`: one band between the outermost two). */
99
+ export type RibbonPairs = 'adjacent' | 'first-last';
100
+ export declare const RIBBON_PAIRS: readonly RibbonPairs[];
101
+ /** Textured dots: the stamps in turn, or one picked at random (seeded) per dot. */
102
+ export type DotTextureOrder = 'sequence' | 'random';
103
+ export declare const DOT_TEXTURE_ORDERS: readonly DotTextureOrder[];
104
+ /** Textured dots: turned with the particle's motion, at random, or at the tip angle. */
105
+ export type DotRotation = 'follow' | 'random' | 'fixed';
106
+ export declare const DOT_ROTATIONS: readonly DotRotation[];
107
+ /** Textured dots: at most this many stamps. */
108
+ export declare const MAX_DOT_TEXTURES = 4;
81
109
  /** Particle engine settings (each 0..1 unless noted). */
82
110
  export interface ParticleSettings {
83
111
  kind: ParticleKind;
@@ -100,17 +128,66 @@ export interface ParticleSettings {
100
128
  life: number;
101
129
  /** Sequence: spacing of the beads along each path. */
102
130
  interval: number;
131
+ /** Ribbon: opacity of the fill between the paths, relative to their edges. */
132
+ ribbonFill: number;
133
+ /** Ribbon: which paths are joined. */
134
+ ribbonPairs: RibbonPairs;
135
+ /** Wave: how far each particle's drawn place swings sideways, as a fraction of the tip size (0: no wave). */
136
+ waveAmplitude: number;
137
+ /** Wave: wavelength in px of pen travel, 4..2000. */
138
+ waveLength: number;
139
+ /** Wave: how fast the waves run (0: they stand still on the path; 1: about four a second while the pen moves). */
140
+ waveSpeed: number;
141
+ /** Wave: how far out of step the particles' waves are (0: all in step; 1: random phases). */
142
+ wavePhaseJitter: number;
143
+ /** Dots and beads: up to four sticker stamps drawn instead of round marks (empty: round). */
144
+ dotTextures: StampKind[];
145
+ dotTextureOrder: DotTextureOrder;
146
+ dotRotation: DotRotation;
103
147
  }
104
148
  export declare const DEFAULT_PARTICLE: Readonly<ParticleSettings>;
105
149
  export declare function normalizeParticle(raw?: Partial<ParticleSettings>, base?: ParticleSettings): ParticleSettings;
150
+ /**
151
+ * Adds the area polygon `pts` (x, y pairs, even-odd) covers in each pixel of `rect`, times `weight`, to `out`,
152
+ * exactly across each of `RIBBON_SUB` sub-rows per row. Points on an edge two polygons share
153
+ * count for exactly one of them, so polygons that tile a region add up to it with no seams.
154
+ */
155
+ export declare function addPolygonArea(pts: readonly number[], rect: RasterRect, out: Float32Array, weight?: number): void;
106
156
  /** A particle-brush stroke. */
107
157
  export declare class ParticleStroke extends MarkStroke {
108
158
  private readonly sets;
159
+ /** Ribbon pairs per copy: particles in their order around the pen (non-flow kinds). */
160
+ private readonly orders;
109
161
  private readonly s;
110
162
  private spawn;
163
+ /** Textured dots drawn so far, per copy (sequence order, random picks). */
164
+ private readonly dots;
165
+ /** Ribbon fill: the area each pixel has had so far this stroke (telescoped into the coverage). */
166
+ private readonly filled;
167
+ private pts;
111
168
  constructor(brush: PaintBrush, options: ProceduralStrokeOptions);
169
+ /** Strand kinds: a chain of masses behind each particle. */
170
+ private get strands();
171
+ private newParticle;
112
172
  private init;
173
+ /** The sideways wave of particle `p` at pen dab `d` (px along the normal to the pen's direction). */
174
+ private wave;
113
175
  protected advance(copy: number, d: PenDab, rects: RasterRect[]): void;
176
+ /** A dot (or bead): round, or a textured stamp turned by the particle's motion (mx, my), at random or to the tip angle. */
177
+ private dot;
178
+ /**
179
+ * Ribbon fill for one step: the band between each pair of joined particles, from where they
180
+ * were drawn last step to where they are drawn now. Bands of one step, and of consecutive steps,
181
+ * share edges exactly, so the fill has no seams; it is telescoped into the coverage
182
+ * (`telescope`), so it does not build up at the joins.
183
+ */
184
+ private ribbon;
185
+ /**
186
+ * Turns the area newly filled over `rect` into coverage to lay towards the fill's ceiling: the
187
+ * share of what was left unfilled, so after any number of bands (in any grouping) a pixel's
188
+ * coverage is the ceiling times the area filled there. False when nothing was added.
189
+ */
190
+ private telescope;
114
191
  }
115
192
  /** Bristle engine settings (each 0..1 unless noted). */
116
193
  export interface BristleSettings {
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Art for stickers from a sticker provider (anything but the editor's own procedural stamps): the
3
+ * spray brush draws while a stroke is in progress, so it can't wait for a provider. Each sticker
4
+ * is loaded once, rasterised to RGBA and kept here; drawing reads it synchronously.
5
+ *
6
+ * PNG art (`data:` URLs) is decoded here, in any environment. SVG and `https:` images need a
7
+ * rasteriser: the browser's (`createImageBitmap` and `OffscreenCanvas`) by default, or the
8
+ * host's (`PaintEditorOptions.rasterizeSticker`).
9
+ */
10
+ import type { StickerAsset, StickerProvider, StickerRef } from '../stickers/types.cjs';
11
+ /** Rasterised sticker art (straight RGBA) and whether to recolour it. */
12
+ export interface StickerArt {
13
+ width: number;
14
+ height: number;
15
+ data: Uint8ClampedArray;
16
+ /** Flat art: drawn in the sticker's colour, keeping its alpha. */
17
+ tintable: boolean;
18
+ }
19
+ /** The art for a ref, when it has loaded. */
20
+ export type StickerArtLookup = (ref: StickerRef) => StickerArt | undefined;
21
+ /** Turns a sticker asset into RGBA at about `size` px on its longest side. */
22
+ export type StickerRasterizer = (asset: StickerAsset, size: number) => Promise<{
23
+ width: number;
24
+ height: number;
25
+ data: Uint8ClampedArray;
26
+ }>;
27
+ /** Longest side sticker art is kept at (px); larger stickers are drawn from it, smoothly scaled. */
28
+ export declare const STICKER_ART_SIZE = 256;
29
+ /**
30
+ * Decodes PNG data URLs anywhere; draws SVG and other images with the browser's
31
+ * `createImageBitmap` and `OffscreenCanvas` when present, and otherwise refuses, naming the option
32
+ * that adds a rasteriser.
33
+ */
34
+ export declare const defaultStickerRasterizer: StickerRasterizer;
35
+ /** Loaded sticker art by ref, with the state of each load. */
36
+ export declare class StickerArtCache {
37
+ private readonly entries;
38
+ /** The art for `ref` when it has loaded (editor stamps never need any). */
39
+ get: StickerArtLookup;
40
+ /** `ready`, `loading`, `failed` (with the reason) or `none` (never asked for). Editor stamps are always `ready`. */
41
+ status(ref: StickerRef): {
42
+ status: 'ready' | 'loading' | 'failed' | 'none';
43
+ error?: string;
44
+ };
45
+ /**
46
+ * Loads and rasterises `ref` from `provider` once (later calls share the load). Unknown refs
47
+ * reject with the closest known ones; failures are kept so they are reported, and retried on
48
+ * the next call.
49
+ */
50
+ ensure(provider: StickerProvider, ref: StickerRef, rasterize: StickerRasterizer): Promise<StickerArt | null>;
51
+ /** Forgets every load (a new provider). */
52
+ clear(): void;
53
+ }
54
+ /** Bilinear RGBA sample of `art` at (x, y) in its pixels (straight alpha, colour weighted by alpha). */
55
+ export declare function sampleArt(art: StickerArt, x: number, y: number, out: number[]): number[];
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Art for stickers from a sticker provider (anything but the editor's own procedural stamps): the
3
+ * spray brush draws while a stroke is in progress, so it can't wait for a provider. Each sticker
4
+ * is loaded once, rasterised to RGBA and kept here; drawing reads it synchronously.
5
+ *
6
+ * PNG art (`data:` URLs) is decoded here, in any environment. SVG and `https:` images need a
7
+ * rasteriser: the browser's (`createImageBitmap` and `OffscreenCanvas`) by default, or the
8
+ * host's (`PaintEditorOptions.rasterizeSticker`).
9
+ */
10
+ import type { StickerAsset, StickerProvider, StickerRef } from '../stickers/types.js';
11
+ /** Rasterised sticker art (straight RGBA) and whether to recolour it. */
12
+ export interface StickerArt {
13
+ width: number;
14
+ height: number;
15
+ data: Uint8ClampedArray;
16
+ /** Flat art: drawn in the sticker's colour, keeping its alpha. */
17
+ tintable: boolean;
18
+ }
19
+ /** The art for a ref, when it has loaded. */
20
+ export type StickerArtLookup = (ref: StickerRef) => StickerArt | undefined;
21
+ /** Turns a sticker asset into RGBA at about `size` px on its longest side. */
22
+ export type StickerRasterizer = (asset: StickerAsset, size: number) => Promise<{
23
+ width: number;
24
+ height: number;
25
+ data: Uint8ClampedArray;
26
+ }>;
27
+ /** Longest side sticker art is kept at (px); larger stickers are drawn from it, smoothly scaled. */
28
+ export declare const STICKER_ART_SIZE = 256;
29
+ /**
30
+ * Decodes PNG data URLs anywhere; draws SVG and other images with the browser's
31
+ * `createImageBitmap` and `OffscreenCanvas` when present, and otherwise refuses, naming the option
32
+ * that adds a rasteriser.
33
+ */
34
+ export declare const defaultStickerRasterizer: StickerRasterizer;
35
+ /** Loaded sticker art by ref, with the state of each load. */
36
+ export declare class StickerArtCache {
37
+ private readonly entries;
38
+ /** The art for `ref` when it has loaded (editor stamps never need any). */
39
+ get: StickerArtLookup;
40
+ /** `ready`, `loading`, `failed` (with the reason) or `none` (never asked for). Editor stamps are always `ready`. */
41
+ status(ref: StickerRef): {
42
+ status: 'ready' | 'loading' | 'failed' | 'none';
43
+ error?: string;
44
+ };
45
+ /**
46
+ * Loads and rasterises `ref` from `provider` once (later calls share the load). Unknown refs
47
+ * reject with the closest known ones; failures are kept so they are reported, and retried on
48
+ * the next call.
49
+ */
50
+ ensure(provider: StickerProvider, ref: StickerRef, rasterize: StickerRasterizer): Promise<StickerArt | null>;
51
+ /** Forgets every load (a new provider). */
52
+ clear(): void;
53
+ }
54
+ /** Bilinear RGBA sample of `art` at (x, y) in its pixels (straight alpha, colour weighted by alpha). */
55
+ export declare function sampleArt(art: StickerArt, x: number, y: number, out: number[]): number[];
@@ -14,13 +14,18 @@ import { TileMedium, type PaintTileTarget } from '../paint/exchange.cjs';
14
14
  import { type PaintGradientSource } from '../paint/gradient-paint.cjs';
15
15
  import type { PaintBrush } from './brushes.cjs';
16
16
  import { type PenPoint, type StrokeCopy } from './engine.cjs';
17
+ import { type StampKind } from '../stickers/stamps.cjs';
18
+ import type { StickerRef } from '../stickers/types.cjs';
19
+ import { type StickerArtLookup } from './sticker-art.cjs';
20
+ export { STAMP_KINDS, stampCoverage, type StampKind } from '../stickers/stamps.cjs';
17
21
  import { type EffectPaintPixels } from './effect-paint.cjs';
18
- export type StampKind = 'dot' | 'star' | 'heart' | 'leaf' | 'flower' | 'confetti' | 'splat' | 'sparkle' | 'ring';
19
- export declare const STAMP_KINDS: readonly StampKind[];
20
22
  /** One sticker (document pixels). */
21
23
  export interface Sticker {
22
24
  id: string;
23
- stamp: StampKind;
25
+ /** What it shows: a sticker ref (`provider:id`), e.g. `editor:star` or a host library's sticker. */
26
+ ref: StickerRef;
27
+ /** The editor stamp, when `ref` is one (`editor:star` → `star`); kept for documents and code that read it. */
28
+ stamp?: StampKind;
24
29
  x: number;
25
30
  y: number;
26
31
  /** Diameter in pixels. */
@@ -36,8 +41,11 @@ export interface Sticker {
36
41
  }
37
42
  /** Sticker spray settings (each 0..1 unless noted). */
38
43
  export interface StickerSettings {
39
- /** The stamps to spray (picked at random per sticker). */
40
- stamps: StampKind[];
44
+ /**
45
+ * The stickers to spray (one picked at random per sticker): refs `provider:id`. A bare editor
46
+ * stamp (`"star"`) is read as `editor:star`.
47
+ */
48
+ stamps: StickerRef[];
41
49
  /** How closely stickers follow each other: about `density × 4` per tip diameter of travel (0.25 ≈ one per diameter). */
42
50
  density: number;
43
51
  /** Random size change. */
@@ -49,20 +57,21 @@ export interface StickerSettings {
49
57
  /** Random colour change (hue and lightness). */
50
58
  colorJitter: number;
51
59
  }
60
+ /** At most this many stickers in a sticker brush. */
61
+ export declare const MAX_STICKER_STAMPS = 16;
52
62
  export declare const DEFAULT_STICKER: Readonly<StickerSettings>;
53
63
  export declare function normalizeStickerSettings(raw?: Partial<StickerSettings>, base?: StickerSettings): StickerSettings;
54
- /**
55
- * Coverage of a stamp at a point (u, v) of its unit square (−1..1, y down), 0..1, before shading.
56
- * `t` is the sticker's seed for shapes with random parts (splat, confetti).
57
- */
58
- export declare function stampCoverage(kind: StampKind, u: number, v: number, t: number): number;
59
64
  /** The pixel rectangle a sticker covers. */
60
65
  export declare function stickerRect(s: Sticker): RasterRect;
66
+ /** The editor stamp a sticker shows, or `null` for a provider's sticker. */
67
+ export declare function stickerStamp(s: Pick<Sticker, 'ref' | 'stamp'>): StampKind | null;
61
68
  /**
62
- * Draws one sticker through a `TileMedium` (straight source-over): the stamp's coverage, lit a
63
- * little from the top left and given a fine seeded texture, in its colour and opacity.
69
+ * Draws one sticker through a `TileMedium` (straight source-over). An editor stamp: its coverage,
70
+ * lit a little from the top left and given a fine seeded texture, in its colour and opacity. A
71
+ * provider's sticker: its loaded art (`art`), fitted into the sticker's size and turned, in its
72
+ * own colours or, when tintable, in the sticker's colour; nothing until the art has loaded.
64
73
  */
65
- export declare function drawSticker(medium: TileMedium, s: Sticker): RasterRect;
74
+ export declare function drawSticker(medium: TileMedium, s: Sticker, art?: StickerArtLookup): RasterRect;
66
75
  export interface StickerSprayInit {
67
76
  brush: PaintBrush;
68
77
  target: PaintTileTarget;
@@ -79,12 +88,16 @@ export interface StickerSprayInit {
79
88
  * stays recolourable); none lands where the effect is transparent.
80
89
  */
81
90
  effect?: EffectPaintPixels | null;
91
+ /** Loaded art for provider stickers; stickers without art yet are skipped (see `skipped`). */
92
+ art?: StickerArtLookup;
82
93
  }
83
94
  /** A sticker-spray stroke: drops stickers along the path and draws them as it goes. */
84
95
  export declare class StickerSpray {
85
96
  readonly init: StickerSprayInit;
86
97
  dabCount: number;
87
98
  readonly stickers: Sticker[];
99
+ /** Refs the spray picked but could not draw because their art had not loaded. */
100
+ readonly skipped: Set<string>;
88
101
  private readonly smoother;
89
102
  private readonly walkers;
90
103
  private readonly copies;
@@ -101,7 +114,7 @@ export declare class StickerSpray {
101
114
  private colorAt;
102
115
  }
103
116
  /** A sticker list rendered over a transparent layer, through a tile target. */
104
- export declare function renderStickers(stickers: readonly Sticker[], target: PaintTileTarget): void;
117
+ export declare function renderStickers(stickers: readonly Sticker[], target: PaintTileTarget, art?: StickerArtLookup): void;
105
118
  /** Checks and rounds a sticker change; throws a sentence naming the bad field. */
106
119
  export declare function normalizeStickerUpdate(u: Partial<Omit<Sticker, 'id'>>): Partial<Omit<Sticker, 'id'>>;
107
120
  /**
@@ -110,6 +123,6 @@ export declare function normalizeStickerUpdate(u: Partial<Omit<Sticker, 'id'>>):
110
123
  * drawn again, from the stickers that reach them; the rest are kept. The pixels are the same as a
111
124
  * full redraw, since a tile depends only on the stickers over it.
112
125
  */
113
- export declare function stickerSurface(stickers: readonly Sticker[], base?: TiledSurface, dirty?: readonly RasterRect[]): TiledSurface;
114
- /** The top-most sticker under a point (document pixels), by its stamp's shape, or `null`. */
115
- export declare function stickerAt(stickers: readonly Sticker[], x: number, y: number): Sticker | null;
126
+ export declare function stickerSurface(stickers: readonly Sticker[], base?: TiledSurface, dirty?: readonly RasterRect[], art?: StickerArtLookup): TiledSurface;
127
+ /** The top-most sticker under a point (document pixels), by its stamp's shape (or its art's alpha), or `null`. */
128
+ export declare function stickerAt(stickers: readonly Sticker[], x: number, y: number, art?: StickerArtLookup): Sticker | null;
@@ -14,13 +14,18 @@ import { TileMedium, type PaintTileTarget } from '../paint/exchange.js';
14
14
  import { type PaintGradientSource } from '../paint/gradient-paint.js';
15
15
  import type { PaintBrush } from './brushes.js';
16
16
  import { type PenPoint, type StrokeCopy } from './engine.js';
17
+ import { type StampKind } from '../stickers/stamps.js';
18
+ import type { StickerRef } from '../stickers/types.js';
19
+ import { type StickerArtLookup } from './sticker-art.js';
20
+ export { STAMP_KINDS, stampCoverage, type StampKind } from '../stickers/stamps.js';
17
21
  import { type EffectPaintPixels } from './effect-paint.js';
18
- export type StampKind = 'dot' | 'star' | 'heart' | 'leaf' | 'flower' | 'confetti' | 'splat' | 'sparkle' | 'ring';
19
- export declare const STAMP_KINDS: readonly StampKind[];
20
22
  /** One sticker (document pixels). */
21
23
  export interface Sticker {
22
24
  id: string;
23
- stamp: StampKind;
25
+ /** What it shows: a sticker ref (`provider:id`), e.g. `editor:star` or a host library's sticker. */
26
+ ref: StickerRef;
27
+ /** The editor stamp, when `ref` is one (`editor:star` → `star`); kept for documents and code that read it. */
28
+ stamp?: StampKind;
24
29
  x: number;
25
30
  y: number;
26
31
  /** Diameter in pixels. */
@@ -36,8 +41,11 @@ export interface Sticker {
36
41
  }
37
42
  /** Sticker spray settings (each 0..1 unless noted). */
38
43
  export interface StickerSettings {
39
- /** The stamps to spray (picked at random per sticker). */
40
- stamps: StampKind[];
44
+ /**
45
+ * The stickers to spray (one picked at random per sticker): refs `provider:id`. A bare editor
46
+ * stamp (`"star"`) is read as `editor:star`.
47
+ */
48
+ stamps: StickerRef[];
41
49
  /** How closely stickers follow each other: about `density × 4` per tip diameter of travel (0.25 ≈ one per diameter). */
42
50
  density: number;
43
51
  /** Random size change. */
@@ -49,20 +57,21 @@ export interface StickerSettings {
49
57
  /** Random colour change (hue and lightness). */
50
58
  colorJitter: number;
51
59
  }
60
+ /** At most this many stickers in a sticker brush. */
61
+ export declare const MAX_STICKER_STAMPS = 16;
52
62
  export declare const DEFAULT_STICKER: Readonly<StickerSettings>;
53
63
  export declare function normalizeStickerSettings(raw?: Partial<StickerSettings>, base?: StickerSettings): StickerSettings;
54
- /**
55
- * Coverage of a stamp at a point (u, v) of its unit square (−1..1, y down), 0..1, before shading.
56
- * `t` is the sticker's seed for shapes with random parts (splat, confetti).
57
- */
58
- export declare function stampCoverage(kind: StampKind, u: number, v: number, t: number): number;
59
64
  /** The pixel rectangle a sticker covers. */
60
65
  export declare function stickerRect(s: Sticker): RasterRect;
66
+ /** The editor stamp a sticker shows, or `null` for a provider's sticker. */
67
+ export declare function stickerStamp(s: Pick<Sticker, 'ref' | 'stamp'>): StampKind | null;
61
68
  /**
62
- * Draws one sticker through a `TileMedium` (straight source-over): the stamp's coverage, lit a
63
- * little from the top left and given a fine seeded texture, in its colour and opacity.
69
+ * Draws one sticker through a `TileMedium` (straight source-over). An editor stamp: its coverage,
70
+ * lit a little from the top left and given a fine seeded texture, in its colour and opacity. A
71
+ * provider's sticker: its loaded art (`art`), fitted into the sticker's size and turned, in its
72
+ * own colours or, when tintable, in the sticker's colour; nothing until the art has loaded.
64
73
  */
65
- export declare function drawSticker(medium: TileMedium, s: Sticker): RasterRect;
74
+ export declare function drawSticker(medium: TileMedium, s: Sticker, art?: StickerArtLookup): RasterRect;
66
75
  export interface StickerSprayInit {
67
76
  brush: PaintBrush;
68
77
  target: PaintTileTarget;
@@ -79,12 +88,16 @@ export interface StickerSprayInit {
79
88
  * stays recolourable); none lands where the effect is transparent.
80
89
  */
81
90
  effect?: EffectPaintPixels | null;
91
+ /** Loaded art for provider stickers; stickers without art yet are skipped (see `skipped`). */
92
+ art?: StickerArtLookup;
82
93
  }
83
94
  /** A sticker-spray stroke: drops stickers along the path and draws them as it goes. */
84
95
  export declare class StickerSpray {
85
96
  readonly init: StickerSprayInit;
86
97
  dabCount: number;
87
98
  readonly stickers: Sticker[];
99
+ /** Refs the spray picked but could not draw because their art had not loaded. */
100
+ readonly skipped: Set<string>;
88
101
  private readonly smoother;
89
102
  private readonly walkers;
90
103
  private readonly copies;
@@ -101,7 +114,7 @@ export declare class StickerSpray {
101
114
  private colorAt;
102
115
  }
103
116
  /** A sticker list rendered over a transparent layer, through a tile target. */
104
- export declare function renderStickers(stickers: readonly Sticker[], target: PaintTileTarget): void;
117
+ export declare function renderStickers(stickers: readonly Sticker[], target: PaintTileTarget, art?: StickerArtLookup): void;
105
118
  /** Checks and rounds a sticker change; throws a sentence naming the bad field. */
106
119
  export declare function normalizeStickerUpdate(u: Partial<Omit<Sticker, 'id'>>): Partial<Omit<Sticker, 'id'>>;
107
120
  /**
@@ -110,6 +123,6 @@ export declare function normalizeStickerUpdate(u: Partial<Omit<Sticker, 'id'>>):
110
123
  * drawn again, from the stickers that reach them; the rest are kept. The pixels are the same as a
111
124
  * full redraw, since a tile depends only on the stickers over it.
112
125
  */
113
- export declare function stickerSurface(stickers: readonly Sticker[], base?: TiledSurface, dirty?: readonly RasterRect[]): TiledSurface;
114
- /** The top-most sticker under a point (document pixels), by its stamp's shape, or `null`. */
115
- export declare function stickerAt(stickers: readonly Sticker[], x: number, y: number): Sticker | null;
126
+ export declare function stickerSurface(stickers: readonly Sticker[], base?: TiledSurface, dirty?: readonly RasterRect[], art?: StickerArtLookup): TiledSurface;
127
+ /** The top-most sticker under a point (document pixels), by its stamp's shape (or its art's alpha), or `null`. */
128
+ export declare function stickerAt(stickers: readonly Sticker[], x: number, y: number, art?: StickerArtLookup): Sticker | null;
@@ -20,6 +20,7 @@ import type { Affine } from './strokes.cjs';
20
20
  import type { WetStrokeDriver } from './wet.cjs';
21
21
  import { type ThickChannels } from './thick.cjs';
22
22
  import { type Sticker } from './stickers.cjs';
23
+ import type { StickerArtLookup } from './sticker-art.cjs';
23
24
  export interface StrokeSessionHost {
24
25
  /** Shows the layer's live surface (no history); `rects` are where it changed. */
25
26
  update(layerId: string, surface: TiledSurface, rects: RasterRect[]): void;
@@ -74,6 +75,7 @@ export interface StrokeSessionInit {
74
75
  /** Sticker brushes: the next sticker number on the layer. */
75
76
  sticker?: {
76
77
  nextId: number;
78
+ art?: StickerArtLookup;
77
79
  };
78
80
  /** Gradient paint (resolved: concrete colours), or `null` for the one colour. Recorded with the stroke. */
79
81
  paint?: PaintGradientSource | null;
@@ -104,6 +106,8 @@ export interface PaintStrokeResult {
104
106
  mixerLoad?: MixerLoad;
105
107
  /** Wet brushes: the paint is wet (it keeps moving until it dries; see dry_paint / advance_wet_paint). */
106
108
  wet?: boolean;
109
+ /** Sticker brushes: refs the spray picked but skipped because their art had not loaded yet. */
110
+ skippedStickers?: string[];
107
111
  }
108
112
  export declare class PaintStrokeSession {
109
113
  private readonly host;
@@ -20,6 +20,7 @@ import type { Affine } from './strokes.js';
20
20
  import type { WetStrokeDriver } from './wet.js';
21
21
  import { type ThickChannels } from './thick.js';
22
22
  import { type Sticker } from './stickers.js';
23
+ import type { StickerArtLookup } from './sticker-art.js';
23
24
  export interface StrokeSessionHost {
24
25
  /** Shows the layer's live surface (no history); `rects` are where it changed. */
25
26
  update(layerId: string, surface: TiledSurface, rects: RasterRect[]): void;
@@ -74,6 +75,7 @@ export interface StrokeSessionInit {
74
75
  /** Sticker brushes: the next sticker number on the layer. */
75
76
  sticker?: {
76
77
  nextId: number;
78
+ art?: StickerArtLookup;
77
79
  };
78
80
  /** Gradient paint (resolved: concrete colours), or `null` for the one colour. Recorded with the stroke. */
79
81
  paint?: PaintGradientSource | null;
@@ -104,6 +106,8 @@ export interface PaintStrokeResult {
104
106
  mixerLoad?: MixerLoad;
105
107
  /** Wet brushes: the paint is wet (it keeps moving until it dries; see dry_paint / advance_wet_paint). */
106
108
  wet?: boolean;
109
+ /** Sticker brushes: refs the spray picked but skipped because their art had not loaded yet. */
110
+ skippedStickers?: string[];
107
111
  }
108
112
  export declare class PaintStrokeSession {
109
113
  private readonly host;
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import type { AgentToolProvider } from '../tools/registry.cjs';
8
8
  import { type PaintOrigin } from './hosted.cjs';
9
- import type { PaintEditorController } from './controller.cjs';
9
+ import { type PaintEditorController } from './controller.cjs';
10
10
  import type { PaintDirector } from './presence.cjs';
11
11
  import type { PresenceActorInfo } from '../animation/presence.cjs';
12
12
  export interface PaintEditorToolProviderOptions {