@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.
- package/README.md +1 -0
- package/dist/animation-editor/index.cjs +64 -61
- package/dist/animation-editor/index.js +8 -5
- package/dist/{brushstrokeRender-ZDHMXJAE.cjs → brushstrokeRender-GCKK7V2I.cjs} +14 -11
- package/dist/{brushstrokeRender-AKUI3SEJ.js → brushstrokeRender-T3JZST44.js} +7 -4
- package/dist/canvas/index.cjs +8 -8
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-UVPD55UZ.cjs → chunk-2SMMZDMG.cjs} +35 -35
- package/dist/chunk-2VJAVXLI.js +192 -0
- package/dist/{chunk-OLNIPTB3.cjs → chunk-2VX55NFM.cjs} +1 -320
- package/dist/chunk-3K6HWEXZ.cjs +92 -0
- package/dist/{chunk-UOOK7HTX.js → chunk-3PPJRMIG.js} +1 -1
- package/dist/chunk-4D6KP5BV.js +92 -0
- package/dist/chunk-5RH3VXAK.js +269 -0
- package/dist/{chunk-LDPLEZ5T.js → chunk-6BIDVPED.js} +1 -1
- package/dist/{chunk-2ONK3ERD.cjs → chunk-75K3W4D6.cjs} +20 -20
- package/dist/chunk-BOHDJJ2O.cjs +192 -0
- package/dist/{chunk-2PBZBRP5.js → chunk-D5KGAO4Z.js} +10 -92
- package/dist/{chunk-DQWPMGH2.js → chunk-DOIU7VJG.js} +1 -1
- package/dist/{chunk-HB4ICNNA.cjs → chunk-DPYAO5U6.cjs} +42 -42
- package/dist/chunk-EJLRBS5Q.js +301 -0
- package/dist/{chunk-Q2UYUWAZ.cjs → chunk-H4AOUUBE.cjs} +679 -164
- package/dist/{chunk-PQ3H2AAN.cjs → chunk-I7NJPHWV.cjs} +122 -204
- package/dist/{chunk-FK5LTDOO.cjs → chunk-IOFVM3L3.cjs} +7 -7
- package/dist/{chunk-42TWUPNJ.js → chunk-IRSTHLQQ.js} +1 -320
- package/dist/{chunk-VDAWA546.js → chunk-J7T5QZ45.js} +614 -99
- package/dist/{chunk-VMROIWLL.cjs → chunk-KBYB7OWB.cjs} +3 -3
- package/dist/{chunk-5MFDD7SP.cjs → chunk-KYX7NZ5V.cjs} +1 -1
- package/dist/chunk-LJRCU3BJ.cjs +301 -0
- package/dist/{chunk-XTWXBQD4.cjs → chunk-LP2MCSBE.cjs} +593 -236
- package/dist/{chunk-A23PSOBB.js → chunk-O75V4ZS3.js} +1 -1
- package/dist/chunk-OTTT5N3K.js +322 -0
- package/dist/{chunk-N6WUB3Y5.js → chunk-PZP2SZIZ.js} +2 -2
- package/dist/{chunk-4PMCMWQS.js → chunk-UBRJOIR5.js} +367 -10
- package/dist/chunk-W5M3J7PV.cjs +322 -0
- package/dist/{chunk-4P6H35HU.js → chunk-WA44NKPF.js} +2 -2
- package/dist/{chunk-CEPKXLBS.cjs → chunk-WLJZZHUZ.cjs} +23 -23
- package/dist/{chunk-P3NIPIKS.js → chunk-WQCNC4DK.js} +1 -1
- package/dist/chunk-ZEYMKDYS.cjs +269 -0
- package/dist/image-editor/effect-tools.d.cts +37 -4
- package/dist/image-editor/effect-tools.d.ts +37 -4
- package/dist/image-editor/index.cjs +1340 -1828
- package/dist/image-editor/index.d.cts +1 -1
- package/dist/image-editor/index.d.ts +1 -1
- package/dist/image-editor/index.js +298 -786
- package/dist/paint/index.cjs +8 -5
- package/dist/paint/index.js +13 -10
- package/dist/paint-editor/controller.d.cts +71 -2
- package/dist/paint-editor/controller.d.ts +71 -2
- package/dist/paint-editor/index.cjs +901 -589
- package/dist/paint-editor/index.d.cts +3 -0
- package/dist/paint-editor/index.d.ts +3 -0
- package/dist/paint-editor/index.js +365 -53
- package/dist/paint-editor/procedural.d.cts +82 -5
- package/dist/paint-editor/procedural.d.ts +82 -5
- package/dist/paint-editor/sticker-art.d.cts +55 -0
- package/dist/paint-editor/sticker-art.d.ts +55 -0
- package/dist/paint-editor/stickers.d.cts +30 -17
- package/dist/paint-editor/stickers.d.ts +30 -17
- package/dist/paint-editor/stroke.d.cts +4 -0
- package/dist/paint-editor/stroke.d.ts +4 -0
- package/dist/paint-editor/tools.d.cts +1 -1
- package/dist/paint-editor/tools.d.ts +1 -1
- package/dist/paint-editor/ui.d.cts +25 -4
- package/dist/paint-editor/ui.d.ts +25 -4
- package/dist/{image-editor/layers/effects-ui.d.cts → raster/effects/ui.d.cts} +32 -5
- package/dist/{image-editor/layers/effects-ui.d.ts → raster/effects/ui.d.ts} +32 -5
- package/dist/raster/index.cjs +17 -3
- package/dist/raster/index.d.cts +1 -0
- package/dist/raster/index.d.ts +1 -0
- package/dist/raster/index.js +23 -9
- package/dist/stickers/browser.d.cts +48 -0
- package/dist/stickers/browser.d.ts +48 -0
- package/dist/stickers/combine.d.cts +10 -0
- package/dist/stickers/combine.d.ts +10 -0
- package/dist/stickers/conformance.d.cts +18 -0
- package/dist/stickers/conformance.d.ts +18 -0
- package/dist/stickers/editor.d.cts +14 -0
- package/dist/stickers/editor.d.ts +14 -0
- package/dist/stickers/errors.d.cts +6 -0
- package/dist/stickers/errors.d.ts +6 -0
- package/dist/stickers/fake.d.cts +16 -0
- package/dist/stickers/fake.d.ts +16 -0
- package/dist/stickers/helpers.d.cts +51 -0
- package/dist/stickers/helpers.d.ts +51 -0
- package/dist/stickers/index.cjs +331 -0
- package/dist/stickers/index.d.cts +16 -0
- package/dist/stickers/index.d.ts +16 -0
- package/dist/stickers/index.js +331 -0
- package/dist/stickers/stamps.d.cts +13 -0
- package/dist/stickers/stamps.d.ts +13 -0
- package/dist/stickers/tools.d.cts +25 -0
- package/dist/stickers/tools.d.ts +25 -0
- package/dist/stickers/types.d.cts +123 -0
- package/dist/stickers/types.d.ts +123 -0
- package/dist/vector/index.cjs +978 -975
- package/dist/vector/index.js +9 -6
- package/package.json +11 -1
- package/skills/README.md +1 -0
- package/skills/pixerate-paint-editor/SKILL.md +26 -32
- package/skills/pixerate-paint-editor/references/gradient-paint.md +23 -0
- package/skills/pixerate-paint-editor/references/layer-effects.md +28 -0
- package/skills/pixerate-paint-editor/references/light-paint.md +10 -2
- package/skills/pixerate-paint-editor/references/particle-brushes.md +66 -0
- package/skills/pixerate-stickers/SKILL.md +45 -0
|
@@ -1,23 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StickerBrowser,
|
|
3
|
+
editorStickers
|
|
4
|
+
} from "../chunk-EJLRBS5Q.js";
|
|
1
5
|
import {
|
|
2
6
|
toVideoFfmpeg
|
|
3
7
|
} from "../chunk-L3JFOTBQ.js";
|
|
4
8
|
import {
|
|
9
|
+
createLayerEffectTools,
|
|
5
10
|
deserializeLayers,
|
|
6
11
|
exportPsd,
|
|
7
12
|
resolveExternalAssets,
|
|
8
13
|
serializeLayers,
|
|
9
14
|
serializeLayersExternal
|
|
10
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-UBRJOIR5.js";
|
|
11
16
|
import "../chunk-3CI7FRMK.js";
|
|
12
17
|
import "../chunk-ZNA3IQZF.js";
|
|
13
18
|
import {
|
|
19
|
+
LAYER_EFFECT_KINDS,
|
|
20
|
+
LayerEffectError,
|
|
14
21
|
RasterCompositor,
|
|
22
|
+
defaultLayerEffect,
|
|
15
23
|
findLayer,
|
|
16
24
|
flattenLayers,
|
|
17
25
|
insertLayer,
|
|
26
|
+
isLayerEffectKind,
|
|
18
27
|
isLayerLocked,
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
layerEffectLabel,
|
|
29
|
+
mapLayer,
|
|
30
|
+
mergeLayerEffect,
|
|
31
|
+
newEffectId,
|
|
32
|
+
validateLayerEffects
|
|
33
|
+
} from "../chunk-3PPJRMIG.js";
|
|
21
34
|
import "../chunk-OHKOFKBY.js";
|
|
22
35
|
import "../chunk-ZIF4UJJ6.js";
|
|
23
36
|
import {
|
|
@@ -44,7 +57,7 @@ import {
|
|
|
44
57
|
pigmentOf,
|
|
45
58
|
pointerPressure,
|
|
46
59
|
wetSupport
|
|
47
|
-
} from "../chunk-
|
|
60
|
+
} from "../chunk-WQCNC4DK.js";
|
|
48
61
|
import "../chunk-HVQVHUTV.js";
|
|
49
62
|
import {
|
|
50
63
|
writeZip
|
|
@@ -55,7 +68,7 @@ import {
|
|
|
55
68
|
realPresenceClock,
|
|
56
69
|
tweenPresenceCursor
|
|
57
70
|
} from "../chunk-IVSWRVB4.js";
|
|
58
|
-
import "../chunk-
|
|
71
|
+
import "../chunk-PZP2SZIZ.js";
|
|
59
72
|
import {
|
|
60
73
|
BRUSH_ID,
|
|
61
74
|
BRUSH_ROTATIONS,
|
|
@@ -72,11 +85,15 @@ import {
|
|
|
72
85
|
DEFAULT_PARTICLE,
|
|
73
86
|
DEFAULT_STICKER,
|
|
74
87
|
DEFAULT_WET_BRUSH,
|
|
88
|
+
DOT_ROTATIONS,
|
|
89
|
+
DOT_TEXTURE_ORDERS,
|
|
75
90
|
DryStroke,
|
|
76
91
|
EFFECT_MAP_REPEATS,
|
|
77
92
|
EFFECT_STRIP_HEIGHT,
|
|
78
93
|
IDENTITY_COPY,
|
|
79
94
|
IMPASTO_TOOLS,
|
|
95
|
+
MAX_DOT_TEXTURES,
|
|
96
|
+
MAX_STICKER_STAMPS,
|
|
80
97
|
MULTI_COLOR_MODES,
|
|
81
98
|
PAINT_BRUSH_CATEGORIES,
|
|
82
99
|
PAINT_BRUSH_ENGINES,
|
|
@@ -87,13 +104,17 @@ import {
|
|
|
87
104
|
ParticleStroke,
|
|
88
105
|
PenDabWalker,
|
|
89
106
|
PenSmoother,
|
|
90
|
-
|
|
107
|
+
RIBBON_PAIRS,
|
|
108
|
+
STICKER_ART_SIZE,
|
|
109
|
+
StickerArtCache,
|
|
91
110
|
StickerSpray,
|
|
92
111
|
WET_MEDIA,
|
|
93
112
|
WET_TOOLS,
|
|
113
|
+
addPolygonArea,
|
|
94
114
|
brushTakesPaint,
|
|
95
115
|
brushToJSON,
|
|
96
116
|
clonePaper,
|
|
117
|
+
defaultStickerRasterizer,
|
|
97
118
|
drawSticker,
|
|
98
119
|
effectDabField,
|
|
99
120
|
effectPaintKey,
|
|
@@ -124,16 +145,25 @@ import {
|
|
|
124
145
|
readPaintEffectPaint,
|
|
125
146
|
renderPaper,
|
|
126
147
|
renderStickers,
|
|
148
|
+
sampleArt,
|
|
127
149
|
sampleEffectAt,
|
|
128
150
|
sampleEffectField,
|
|
129
|
-
stampCoverage,
|
|
130
151
|
stickerAt,
|
|
131
152
|
stickerRect,
|
|
153
|
+
stickerStamp,
|
|
132
154
|
stickerSurface,
|
|
133
155
|
tiltToOrientation,
|
|
134
156
|
toStrokePoint,
|
|
135
157
|
usesPaintExchange
|
|
136
|
-
} from "../chunk-
|
|
158
|
+
} from "../chunk-J7T5QZ45.js";
|
|
159
|
+
import {
|
|
160
|
+
STAMP_KINDS,
|
|
161
|
+
StickersSlot,
|
|
162
|
+
createStickerTools,
|
|
163
|
+
editorStampOf,
|
|
164
|
+
normalizeStickerRef,
|
|
165
|
+
stampCoverage
|
|
166
|
+
} from "../chunk-5RH3VXAK.js";
|
|
137
167
|
import "../chunk-M6DNZNVY.js";
|
|
138
168
|
import "../chunk-WEIK3UYB.js";
|
|
139
169
|
import "../chunk-PWBZH3FK.js";
|
|
@@ -174,7 +204,6 @@ import {
|
|
|
174
204
|
PaperGrain,
|
|
175
205
|
SmudgeTip,
|
|
176
206
|
TileMedium,
|
|
177
|
-
TileableNoise,
|
|
178
207
|
addPaintGradientStop,
|
|
179
208
|
applyStrokeToTile,
|
|
180
209
|
blenderDab,
|
|
@@ -184,46 +213,51 @@ import {
|
|
|
184
213
|
exchangeRates,
|
|
185
214
|
grainCatch,
|
|
186
215
|
grainHeights,
|
|
187
|
-
hash2,
|
|
188
216
|
hexToPaintRgb,
|
|
189
217
|
isGradientPaint,
|
|
190
218
|
loadMixer,
|
|
191
|
-
mix32,
|
|
192
219
|
mixerRates,
|
|
193
220
|
normalizeHexColor,
|
|
194
221
|
paintGradientMappingFor,
|
|
195
222
|
paintSourceColor,
|
|
196
223
|
paintSourceCss,
|
|
197
224
|
parsePaintSource,
|
|
198
|
-
rand01,
|
|
199
|
-
randSigned,
|
|
200
225
|
rasterizeDab,
|
|
201
226
|
readPaintSource,
|
|
202
227
|
removePaintGradientStop,
|
|
203
228
|
resolvePaintGradient,
|
|
204
229
|
reversePaintGradient,
|
|
205
230
|
scalePaintGradient,
|
|
206
|
-
seedFromString,
|
|
207
231
|
solidPaint,
|
|
208
232
|
updatePaintGradientStop
|
|
209
|
-
} from "../chunk-
|
|
233
|
+
} from "../chunk-D5KGAO4Z.js";
|
|
234
|
+
import {
|
|
235
|
+
TileableNoise,
|
|
236
|
+
hash2,
|
|
237
|
+
mix32,
|
|
238
|
+
rand01,
|
|
239
|
+
randSigned,
|
|
240
|
+
seedFromString
|
|
241
|
+
} from "../chunk-4D6KP5BV.js";
|
|
210
242
|
import "../chunk-ODBT55Q7.js";
|
|
211
243
|
import {
|
|
212
244
|
BLEND_MODES,
|
|
213
245
|
PAINTERLY_BLEND_MODES,
|
|
246
|
+
isBlendMode,
|
|
247
|
+
isPainterlyBlendMode,
|
|
248
|
+
mixPigment8,
|
|
249
|
+
mixPigments,
|
|
250
|
+
standardBlendMode
|
|
251
|
+
} from "../chunk-IRSTHLQQ.js";
|
|
252
|
+
import {
|
|
214
253
|
base64ToBytes,
|
|
215
254
|
bytesToBase64,
|
|
216
255
|
decodePng,
|
|
217
256
|
encodePng,
|
|
218
|
-
isBlendMode,
|
|
219
|
-
isPainterlyBlendMode,
|
|
220
257
|
isPng,
|
|
221
|
-
mixPigment8,
|
|
222
|
-
mixPigments,
|
|
223
258
|
parseDataUrl,
|
|
224
|
-
pngDataUrl
|
|
225
|
-
|
|
226
|
-
} from "../chunk-42TWUPNJ.js";
|
|
259
|
+
pngDataUrl
|
|
260
|
+
} from "../chunk-OTTT5N3K.js";
|
|
227
261
|
import {
|
|
228
262
|
TILE,
|
|
229
263
|
TiledSurface,
|
|
@@ -1291,7 +1325,7 @@ var PaintStrokeSession = class _PaintStrokeSession {
|
|
|
1291
1325
|
};
|
|
1292
1326
|
if (this.wetDriver) {
|
|
1293
1327
|
} else if (init.sticker) {
|
|
1294
|
-
this.stickerSpray = new StickerSpray({ brush, target: this.tileTarget(), color: init.colorHex, seed: init.seed, copies: this.copies, nextId: init.sticker.nextId, paint: init.paint ?? null, effect });
|
|
1328
|
+
this.stickerSpray = new StickerSpray({ brush, target: this.tileTarget(), color: init.colorHex, seed: init.seed, copies: this.copies, nextId: init.sticker.nextId, paint: init.paint ?? null, effect, art: init.sticker.art });
|
|
1295
1329
|
} else if (init.thick) {
|
|
1296
1330
|
const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
|
|
1297
1331
|
this.thickDriver = new ThickStrokeDriver({ brush, target: this.tileTarget(), channels: init.thick.channels, color: rgb(init.color), load: init.mixerLoad, seed: init.seed, copies: this.copies, paint: init.paint ?? null, effect });
|
|
@@ -1501,6 +1535,7 @@ var PaintStrokeSession = class _PaintStrokeSession {
|
|
|
1501
1535
|
const surface = changed ? new TiledSurface(ch, tiles, this.base.defaultValue) : null;
|
|
1502
1536
|
const dabs = this.dry ? this.dry.dabCount : this.thickDriver ? this.thickDriver.dabCount : this.stickerSpray ? this.stickerSpray.dabCount : this.wet.dabCount;
|
|
1503
1537
|
this.result = { layerId: this.layerId, bounds: changed ? this.bounds : null, dabs, strokeId: null };
|
|
1538
|
+
if (this.stickerSpray?.skipped.size) this.result.skippedStickers = [...this.stickerSpray.skipped];
|
|
1504
1539
|
const carried = this.wet?.load ?? this.thickDriver?.load;
|
|
1505
1540
|
if (carried) this.result.mixerLoad = this.init.brush.behavior.dirty ? carried : cleanMixer(carried);
|
|
1506
1541
|
this.host.commit(this, surface, false);
|
|
@@ -3500,7 +3535,9 @@ function liveStrokeBounds(stroke) {
|
|
|
3500
3535
|
if (q.y > y1) y1 = q.y;
|
|
3501
3536
|
}
|
|
3502
3537
|
}
|
|
3503
|
-
const
|
|
3538
|
+
const particle = stroke.brush.engine === "particle" ? stroke.brush.particle : null;
|
|
3539
|
+
const wave = particle ? Math.max(particle.waveAmplitude ?? 0, particle.kind === "fuzzy" ? 0.12 : 0) : 0;
|
|
3540
|
+
const pad = stroke.brush.tip.size * (particle ? 2 + wave : 1) + 2;
|
|
3504
3541
|
return { x: Math.floor(x0 - pad), y: Math.floor(y0 - pad), width: Math.ceil(x1 - x0 + 2 * pad), height: Math.ceil(y1 - y0 + 2 * pad) };
|
|
3505
3542
|
}
|
|
3506
3543
|
|
|
@@ -4032,6 +4069,14 @@ function effectLayersToJSON(map, keep) {
|
|
|
4032
4069
|
}
|
|
4033
4070
|
|
|
4034
4071
|
// src/paint-editor/controller.ts
|
|
4072
|
+
function effectGuard(fn) {
|
|
4073
|
+
try {
|
|
4074
|
+
return fn();
|
|
4075
|
+
} catch (e) {
|
|
4076
|
+
if (e instanceof LayerEffectError) throw new PaintEditorError(e.message);
|
|
4077
|
+
throw e;
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4035
4080
|
var PaintEditorError = class extends Error {
|
|
4036
4081
|
constructor(message) {
|
|
4037
4082
|
super(message);
|
|
@@ -4137,10 +4182,16 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
4137
4182
|
wetOp = null;
|
|
4138
4183
|
/** The effects provider slot (see `setEffectsProvider`). */
|
|
4139
4184
|
effects = new EffectsSlot();
|
|
4185
|
+
/** The sticker library slot (see `setStickersProvider`). */
|
|
4186
|
+
stickers = new StickersSlot(editorStickers());
|
|
4187
|
+
stickerArt = new StickerArtCache();
|
|
4188
|
+
rasterizeSticker;
|
|
4140
4189
|
effectsRenderer = new PaintEffectsRenderer();
|
|
4141
4190
|
paperEffectNodeCache = null;
|
|
4142
4191
|
constructor(options = {}) {
|
|
4143
4192
|
this.historyLimit = Math.max(1, options.historyLimit ?? 200);
|
|
4193
|
+
this.rasterizeSticker = options.rasterizeSticker ?? defaultStickerRasterizer;
|
|
4194
|
+
if (options.stickers) this.stickers.set(options.stickers);
|
|
4144
4195
|
this.doc = createPaintDocument({ width: options.width, height: options.height, dpi: options.dpi, paper: this.resolvePaper(options.paper) });
|
|
4145
4196
|
this.userBrushes = (options.brushes ?? []).map((b) => normalizePaintBrush({ ...b, builtin: false }));
|
|
4146
4197
|
const start = this.findBrush(options.brushId ?? DEFAULT_BRUSH_ID) ?? this.findBrush(DEFAULT_BRUSH_ID);
|
|
@@ -4557,6 +4608,7 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
4557
4608
|
active: l.id === this.doc.activeLayerId,
|
|
4558
4609
|
bounds,
|
|
4559
4610
|
...this.doc.liveStrokes?.[l.id] ? { liveStrokes: this.doc.liveStrokes[l.id].length } : {},
|
|
4611
|
+
...l.effects?.items.length ? { effects: l.effects.items.length } : {},
|
|
4560
4612
|
parentId,
|
|
4561
4613
|
depth
|
|
4562
4614
|
};
|
|
@@ -4630,6 +4682,94 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
4630
4682
|
this.commit("Layer properties", { ...this.doc, layers: mapLayer(this.doc.layers, id, () => next) });
|
|
4631
4683
|
return this.describeLayer(next);
|
|
4632
4684
|
}
|
|
4685
|
+
// --- Layer effects (layer styles) ---------------------------------------------
|
|
4686
|
+
/** A layer's live effects (an empty, enabled list when it has none). */
|
|
4687
|
+
getLayerEffects(id) {
|
|
4688
|
+
return this.requireLayer(id).effects ?? { enabled: true, items: [] };
|
|
4689
|
+
}
|
|
4690
|
+
/**
|
|
4691
|
+
* Adds a live effect of `kind` (outer and inner glow, drop and inner shadow, stroke, bevel &
|
|
4692
|
+
* emboss, satin, colour / gradient / pattern overlay) with Photoshop's defaults and `settings`
|
|
4693
|
+
* applied, at `index` in the layer's list (default the end). The effect is drawn from the
|
|
4694
|
+
* layer's pixels when it is composited, so it follows later painting. One undo step.
|
|
4695
|
+
*/
|
|
4696
|
+
addLayerEffect(id, kind, settings = {}, index) {
|
|
4697
|
+
if (!isLayerEffectKind(kind)) throw new PaintEditorError(`Unknown effect kind "${String(kind)}". Kinds: ${LAYER_EFFECT_KINDS.join(", ")}.`);
|
|
4698
|
+
const current = this.effectsLayer(id, "add effects").effects ?? { enabled: true, items: [] };
|
|
4699
|
+
const ids = new Set(current.items.map((e) => e.id));
|
|
4700
|
+
let effectId = newEffectId();
|
|
4701
|
+
while (ids.has(effectId)) effectId = newEffectId();
|
|
4702
|
+
const { id: _id, kind: _kind, ...rest } = settings;
|
|
4703
|
+
const effect = effectGuard(() => mergeLayerEffect(defaultLayerEffect(kind, effectId), rest));
|
|
4704
|
+
const items = [...current.items];
|
|
4705
|
+
const at = index === void 0 ? items.length : Math.max(0, Math.min(items.length, Math.floor(index)));
|
|
4706
|
+
items.splice(at, 0, effect);
|
|
4707
|
+
this.writeLayerEffects(id, { ...current, items }, `Add ${layerEffectLabel(kind)}`, true);
|
|
4708
|
+
return { effect, effects: this.getLayerEffects(id) };
|
|
4709
|
+
}
|
|
4710
|
+
/**
|
|
4711
|
+
* Changes one effect: only the given settings (nested objects replace whole; `null` removes an
|
|
4712
|
+
* optional contour or texture). One undo step, or with `commitToHistory` false folded into the
|
|
4713
|
+
* last change of this effect (a slider drag). Returns the layer's effects.
|
|
4714
|
+
*/
|
|
4715
|
+
updateLayerEffect(id, effectId, changes, commitToHistory = true) {
|
|
4716
|
+
const current = this.effectsLayer(id, "change its effects").effects;
|
|
4717
|
+
const i = this.requireEffect(id, effectId);
|
|
4718
|
+
const items = [...current.items];
|
|
4719
|
+
items[i] = effectGuard(() => mergeLayerEffect(items[i], changes));
|
|
4720
|
+
this.writeLayerEffects(id, { ...current, items }, `Change ${layerEffectLabel(items[i].kind)}`, commitToHistory);
|
|
4721
|
+
return this.getLayerEffects(id);
|
|
4722
|
+
}
|
|
4723
|
+
/** Removes one effect (one undo step). Returns the layer's remaining effects. */
|
|
4724
|
+
removeLayerEffect(id, effectId) {
|
|
4725
|
+
const current = this.effectsLayer(id, "change its effects").effects;
|
|
4726
|
+
const i = this.requireEffect(id, effectId);
|
|
4727
|
+
this.writeLayerEffects(id, { ...current, items: current.items.filter((e) => e.id !== effectId) }, `Remove ${layerEffectLabel(current.items[i].kind)}`, true);
|
|
4728
|
+
return this.getLayerEffects(id);
|
|
4729
|
+
}
|
|
4730
|
+
/** Turns all of a layer's effects on or off and, when given, sets Scale Effects (0.01..10). One undo step. */
|
|
4731
|
+
setLayerEffectsEnabled(id, enabled, scale, commitToHistory = true) {
|
|
4732
|
+
const current = this.effectsLayer(id, "change its effects").effects ?? { enabled: true, items: [] };
|
|
4733
|
+
if (scale !== void 0 && !(Number.isFinite(scale) && scale >= 0.01 && scale <= 10)) throw new PaintEditorError(`scale must be from 0.01 to 10 (1 = 100 %), got ${scale}.`);
|
|
4734
|
+
const next = { ...current, enabled };
|
|
4735
|
+
if (scale !== void 0) {
|
|
4736
|
+
if (scale === 1) delete next.scale;
|
|
4737
|
+
else next.scale = scale;
|
|
4738
|
+
}
|
|
4739
|
+
this.writeLayerEffects(id, next, "Layer effects", commitToHistory);
|
|
4740
|
+
return this.getLayerEffects(id);
|
|
4741
|
+
}
|
|
4742
|
+
/** Replaces a layer's effects, validated (`null` removes them). One undo step. Returns the effects. */
|
|
4743
|
+
setLayerEffects(id, effects, commitToHistory = true) {
|
|
4744
|
+
this.effectsLayer(id, "change its effects");
|
|
4745
|
+
if (effects) effectGuard(() => validateLayerEffects(effects));
|
|
4746
|
+
this.writeLayerEffects(id, effects, "Layer effects", commitToHistory);
|
|
4747
|
+
return this.getLayerEffects(id);
|
|
4748
|
+
}
|
|
4749
|
+
/** Document patterns for pattern effects besides the built-in ones: none (paint documents bring none). */
|
|
4750
|
+
getDocumentPatterns() {
|
|
4751
|
+
return [];
|
|
4752
|
+
}
|
|
4753
|
+
effectsLayer(id, action) {
|
|
4754
|
+
this.requireIdle("changing layer effects");
|
|
4755
|
+
const l = this.requireLayer(id);
|
|
4756
|
+
if (isLayerLocked(l, "all")) throw new PaintEditorError(`Layer "${l.name}" is fully locked, so it can't ${action}; unlock it first (locks {all: false}).`);
|
|
4757
|
+
return l;
|
|
4758
|
+
}
|
|
4759
|
+
requireEffect(id, effectId) {
|
|
4760
|
+
const l = this.requireLayer(id);
|
|
4761
|
+
const items = l.effects?.items ?? [];
|
|
4762
|
+
const i = items.findIndex((e) => e.id === effectId);
|
|
4763
|
+
if (i === -1) throw new PaintEditorError(`Layer "${l.name}" has no effect "${effectId}". Effects: ${items.map((e) => `${e.id} (${e.kind})`).join(", ") || "none"}; call list_layer_effects.`);
|
|
4764
|
+
return i;
|
|
4765
|
+
}
|
|
4766
|
+
/** Writes a layer's effects (dropped when empty, enabled and unscaled), as an undo step or folded into the last one. */
|
|
4767
|
+
writeLayerEffects(id, effects, label, commitToHistory) {
|
|
4768
|
+
const next = { ...this.requireLayer(id) };
|
|
4769
|
+
if (effects && (effects.items.length || effects.psd || effects.scale !== void 0 || !effects.enabled)) next.effects = effects;
|
|
4770
|
+
else delete next.effects;
|
|
4771
|
+
this.commitOrAmend(label, { ...this.doc, layers: mapLayer(this.doc.layers, id, () => next) }, commitToHistory);
|
|
4772
|
+
}
|
|
4633
4773
|
removeLayer(id) {
|
|
4634
4774
|
this.requireIdle("removing a layer");
|
|
4635
4775
|
const l = this.requireLayer(id);
|
|
@@ -5210,6 +5350,7 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
5210
5350
|
else delete next.builtin;
|
|
5211
5351
|
this.brush = next;
|
|
5212
5352
|
this.emit([]);
|
|
5353
|
+
if (next.engine === "sticker" && next.sticker.stamps.some((r) => !editorStampOf(r))) void this.prepareStickers(next.sticker.stamps).catch(() => this.emit([]));
|
|
5213
5354
|
return this.brush;
|
|
5214
5355
|
}
|
|
5215
5356
|
/** Saves the active brush (or `brush`) into the user library under `id` / `name`. */
|
|
@@ -5535,7 +5676,7 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
5535
5676
|
thick: brush.engine === "impasto" ? { channels: doc.thick?.[layer.id] ?? emptyThickChannels() } : void 0,
|
|
5536
5677
|
// Light paint: a twin of the stroke paints the light channel (laying, dimming, moving light).
|
|
5537
5678
|
light: !wet && brush.engine !== "sticker" && (brush.light.amount > 0 || doc.light?.[layer.id]) ? { surface: doc.light?.[layer.id] ?? emptyLight() } : null,
|
|
5538
|
-
sticker: brush.engine === "sticker" ? { nextId: this.nextStickerNumber(doc) } : void 0,
|
|
5679
|
+
sticker: brush.engine === "sticker" ? { nextId: this.nextStickerNumber(doc), art: this.stickerArt.get } : void 0,
|
|
5539
5680
|
paint: effect ? null : this.strokeGradient(init, brush, color),
|
|
5540
5681
|
effect
|
|
5541
5682
|
});
|
|
@@ -6332,9 +6473,19 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
6332
6473
|
const stickers = {};
|
|
6333
6474
|
for (const [id, list] of Object.entries(ext.stickers)) {
|
|
6334
6475
|
if (!findLayer(state.layers, id) || !Array.isArray(list)) continue;
|
|
6335
|
-
const ok = list.
|
|
6476
|
+
const ok = list.flatMap((x) => {
|
|
6477
|
+
if (!x || typeof x.id !== "string" || !Number.isFinite(x.x) || !Number.isFinite(x.y) || !(x.size > 0)) return [];
|
|
6478
|
+
try {
|
|
6479
|
+
const ref2 = normalizeStickerRef(x.ref ?? x.stamp);
|
|
6480
|
+
const stamp = editorStampOf(ref2);
|
|
6481
|
+
const { stamp: _old, ...rest } = x;
|
|
6482
|
+
return [{ ...rest, ref: ref2, ...stamp ? { stamp } : {} }];
|
|
6483
|
+
} catch {
|
|
6484
|
+
return [];
|
|
6485
|
+
}
|
|
6486
|
+
});
|
|
6336
6487
|
if (ok.length !== list.length) problems.push(`Some stickers of layer "${id}" could not be read; they were dropped.`);
|
|
6337
|
-
stickers[id] = ok
|
|
6488
|
+
stickers[id] = ok;
|
|
6338
6489
|
}
|
|
6339
6490
|
if (Object.keys(stickers).length) state = { ...state, stickers };
|
|
6340
6491
|
}
|
|
@@ -6438,6 +6589,8 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
6438
6589
|
delete this.extensions.paperEffect;
|
|
6439
6590
|
this.viewCompositor.clear();
|
|
6440
6591
|
this.emit();
|
|
6592
|
+
const refs = Object.values(this.doc.stickers ?? {}).flatMap((list) => list.map((x) => x.ref));
|
|
6593
|
+
if (refs.some((r) => !editorStampOf(r))) void this.prepareStickers(refs).catch(() => this.emit([]));
|
|
6441
6594
|
return loaded.problems;
|
|
6442
6595
|
}
|
|
6443
6596
|
/** Opens a saved document (clears the history). Returns what could not be read. */
|
|
@@ -6765,6 +6918,56 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
6765
6918
|
if (!stickers) throw new PaintEditorError(`Layer "${l.name}" has no stickers; spray some with a sticker brush (list_brushes category sticker).`);
|
|
6766
6919
|
return { layer: l, stickers };
|
|
6767
6920
|
}
|
|
6921
|
+
// --- The sticker library ---------------------------------------------------------
|
|
6922
|
+
/** The sticker library: the editor's own stamps unless a host set its own. */
|
|
6923
|
+
get stickersProvider() {
|
|
6924
|
+
return this.stickers.provider;
|
|
6925
|
+
}
|
|
6926
|
+
/**
|
|
6927
|
+
* Sets the sticker library (`null` goes back to the editor's own stamps, `editorStickers()`);
|
|
6928
|
+
* to offer both, pass `combineStickerProviders([editorStickers(), yours])`. Loaded art is
|
|
6929
|
+
* forgotten. Not an edit: no undo step.
|
|
6930
|
+
*/
|
|
6931
|
+
setStickersProvider(provider) {
|
|
6932
|
+
if ((provider ?? this.stickers.fallback) === this.stickers.provider) return;
|
|
6933
|
+
this.stickers.set(provider);
|
|
6934
|
+
this.stickerArt.clear();
|
|
6935
|
+
this.emit([]);
|
|
6936
|
+
}
|
|
6937
|
+
/**
|
|
6938
|
+
* Loads the art of `refs` (provider stickers; editor stamps need none) so sprays and placements
|
|
6939
|
+
* can draw them. Rejects with a `PaintEditorError` naming an unknown ref and the closest known
|
|
6940
|
+
* ones, or a sticker whose art failed. Emits when art arrives, so views redraw.
|
|
6941
|
+
*/
|
|
6942
|
+
async prepareStickers(refs) {
|
|
6943
|
+
const list = [...new Set(refs.map((r) => this.readStickerRef(r)))].filter((r) => !editorStampOf(r));
|
|
6944
|
+
try {
|
|
6945
|
+
await Promise.all(list.map((r) => this.stickerArt.ensure(this.stickers.provider, r, this.rasterizeSticker)));
|
|
6946
|
+
} catch (e) {
|
|
6947
|
+
throw new PaintEditorError(e instanceof Error ? e.message : String(e));
|
|
6948
|
+
} finally {
|
|
6949
|
+
if (list.length) this.emit([]);
|
|
6950
|
+
}
|
|
6951
|
+
}
|
|
6952
|
+
/** Whether a sticker's art is ready to draw: `ready` (always for editor stamps), `loading`, `failed` (with why) or `none`. */
|
|
6953
|
+
stickerArtStatus(ref2) {
|
|
6954
|
+
return this.stickerArt.status(this.readStickerRef(ref2));
|
|
6955
|
+
}
|
|
6956
|
+
readStickerRef(ref2) {
|
|
6957
|
+
try {
|
|
6958
|
+
return normalizeStickerRef(ref2);
|
|
6959
|
+
} catch (e) {
|
|
6960
|
+
throw new PaintEditorError(e.message);
|
|
6961
|
+
}
|
|
6962
|
+
}
|
|
6963
|
+
/** Refuses to redraw stickers whose art has not loaded (they would vanish), naming them and what to call. */
|
|
6964
|
+
requireStickerArt(stickers) {
|
|
6965
|
+
const missing = [...new Set(stickers.filter((s) => !stickerStamp(s) && !this.stickerArt.get(s.ref)).map((s) => s.ref))];
|
|
6966
|
+
if (missing.length) {
|
|
6967
|
+
for (const r of missing) void this.stickerArt.ensure(this.stickers.provider, r, this.rasterizeSticker).then(() => this.emit([]), () => this.emit([]));
|
|
6968
|
+
throw new PaintEditorError(`The art for ${missing.map((r) => `"${r}"`).join(", ")} has not loaded yet; it is loading now (prepareStickers), so try again when it has.`);
|
|
6969
|
+
}
|
|
6970
|
+
}
|
|
6768
6971
|
/** A layer's stickers, bottom first. */
|
|
6769
6972
|
listStickers(layerId) {
|
|
6770
6973
|
const id = layerId ?? this.doc.activeLayerId;
|
|
@@ -6778,6 +6981,7 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
6778
6981
|
*/
|
|
6779
6982
|
commitStickers(label, layer, stickers, dirty) {
|
|
6780
6983
|
if (isLayerLocked(layer, "pixels")) throw new PaintEditorError(`Layer "${layer.name}" has its pixels locked; unlock it first.`);
|
|
6984
|
+
this.requireStickerArt(stickers);
|
|
6781
6985
|
const before = this.previewBase() ?? this.doc;
|
|
6782
6986
|
this.stickerPreview = null;
|
|
6783
6987
|
const surface = this.redrawStickers(layer, stickers, dirty);
|
|
@@ -6786,7 +6990,7 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
6786
6990
|
}
|
|
6787
6991
|
redrawStickers(layer, stickers, dirty) {
|
|
6788
6992
|
const partial = dirty && !layer.offset.x && !layer.offset.y;
|
|
6789
|
-
return partial ? stickerSurface(stickers, layer.surface, dirty) : stickerSurface(stickers);
|
|
6993
|
+
return partial ? stickerSurface(stickers, layer.surface, dirty, this.stickerArt.get) : stickerSurface(stickers, void 0, void 0, this.stickerArt.get);
|
|
6790
6994
|
}
|
|
6791
6995
|
/** The document from before the sticker preview on screen, or `null` when none is (anything else changed the document since). */
|
|
6792
6996
|
previewBase() {
|
|
@@ -6805,7 +7009,7 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
6805
7009
|
const id = layerId ?? this.doc.activeLayerId;
|
|
6806
7010
|
if (!id) return null;
|
|
6807
7011
|
this.requireLayer(id);
|
|
6808
|
-
const hit = stickerAt(this.doc.stickers?.[id] ?? [], x, y);
|
|
7012
|
+
const hit = stickerAt(this.doc.stickers?.[id] ?? [], x, y, this.stickerArt.get);
|
|
6809
7013
|
return hit ? { ...hit } : null;
|
|
6810
7014
|
}
|
|
6811
7015
|
/** Picks a sticker for the panel and canvas (`null` for none). Editor state, not an undo step. */
|
|
@@ -6859,7 +7063,7 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
6859
7063
|
*/
|
|
6860
7064
|
addStickers(layerId, input) {
|
|
6861
7065
|
const layer = this.wetLayer(layerId, "add stickers to");
|
|
6862
|
-
if (!input.length) throw new PaintEditorError("Pass at least one sticker (
|
|
7066
|
+
if (!input.length) throw new PaintEditorError("Pass at least one sticker (ref, x, y).");
|
|
6863
7067
|
if (input.length > MAX_ADD_STICKERS) throw new PaintEditorError(`At most ${MAX_ADD_STICKERS} stickers per call; split them over several calls.`);
|
|
6864
7068
|
const existing = this.doc.stickers?.[layer.id];
|
|
6865
7069
|
if (!existing?.length) {
|
|
@@ -6867,7 +7071,8 @@ var PaintEditorController = class _PaintEditorController {
|
|
|
6867
7071
|
}
|
|
6868
7072
|
let n = this.nextStickerNumber();
|
|
6869
7073
|
const added = input.map((raw, i) => {
|
|
6870
|
-
|
|
7074
|
+
if (raw.ref === void 0 && raw.stamp === void 0) throw new PaintEditorError(`Sticker ${i} needs ref (a sticker ref from find_stickers, e.g. "editor:star").`);
|
|
7075
|
+
for (const k of ["x", "y"]) if (raw[k] === void 0) throw new PaintEditorError(`Sticker ${i} needs ${k}.`);
|
|
6871
7076
|
let u;
|
|
6872
7077
|
try {
|
|
6873
7078
|
u = this.readStickerUpdate(raw);
|
|
@@ -7932,7 +8137,7 @@ function createPaintStickerTools(c) {
|
|
|
7932
8137
|
{
|
|
7933
8138
|
name: "list_stickers",
|
|
7934
8139
|
title: "List stickers",
|
|
7935
|
-
description: "Lists a layer\u2019s stickers bottom first: id, stamp, x, y (centre, document pixels), size (diameter px), rotation (degrees clockwise), color, opacity. Empty for a layer without stickers. Changes nothing.",
|
|
8140
|
+
description: "Lists a layer\u2019s stickers bottom first: id, ref (provider:id; stamp too for the editor\u2019s own), x, y (centre, document pixels), size (diameter px), rotation (degrees clockwise), color, opacity. Empty for a layer without stickers. Changes nothing.",
|
|
7936
8141
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID }, additionalProperties: false },
|
|
7937
8142
|
annotations: { title: "List stickers", ...READ },
|
|
7938
8143
|
coordinates: { out: ["stickers[]"] },
|
|
@@ -7959,7 +8164,7 @@ function createPaintStickerTools(c) {
|
|
|
7959
8164
|
{
|
|
7960
8165
|
name: "add_stickers",
|
|
7961
8166
|
title: "Place stickers",
|
|
7962
|
-
description: "Places stickers exactly where you say, on top of a sticker layer or onto an empty layer (which becomes a sticker layer). Use it for deliberate placement; spray with paint_stroke and a sticker brush for a random scatter. One undo step. Returns the new stickers with their ids, for update_sticker, arrange_stickers and remove_stickers.",
|
|
8167
|
+
description: "Places stickers exactly where you say, on top of a sticker layer or onto an empty layer (which becomes a sticker layer): any sticker from the sticker library by ref (find_stickers), its art loaded first; tintable ones take color. Use it for deliberate placement; spray with paint_stroke and a sticker brush for a random scatter. An unknown ref is refused with the closest ones. One undo step. Returns the new stickers with their ids, for update_sticker, arrange_stickers and remove_stickers.",
|
|
7963
8168
|
inputSchema: {
|
|
7964
8169
|
type: "object",
|
|
7965
8170
|
properties: {
|
|
@@ -7972,7 +8177,8 @@ function createPaintStickerTools(c) {
|
|
|
7972
8177
|
items: {
|
|
7973
8178
|
type: "object",
|
|
7974
8179
|
properties: {
|
|
7975
|
-
|
|
8180
|
+
ref: { type: "string", minLength: 1, description: "The sticker: a ref provider:id from find_stickers (e.g. editor:star). Give ref or stamp." },
|
|
8181
|
+
stamp: { type: "string", enum: [...STAMP_KINDS], description: "Older form: an editor stamp (same as ref editor:<stamp>)." },
|
|
7976
8182
|
x: { type: "number", description: "Centre x in document pixels." },
|
|
7977
8183
|
y: { type: "number", description: "Centre y in document pixels." },
|
|
7978
8184
|
size: { type: "number", minimum: 2, maximum: 2048, description: "Diameter in pixels (default 48)." },
|
|
@@ -7981,7 +8187,7 @@ function createPaintStickerTools(c) {
|
|
|
7981
8187
|
opacity: { type: "number", minimum: 0, maximum: 1, description: "Opacity 0..1 (default 1)." },
|
|
7982
8188
|
seed: { type: "integer", minimum: 0, description: "Texture seed (default from the new id); splat and confetti shapes vary with it." }
|
|
7983
8189
|
},
|
|
7984
|
-
required: ["
|
|
8190
|
+
required: ["x", "y"],
|
|
7985
8191
|
additionalProperties: false
|
|
7986
8192
|
}
|
|
7987
8193
|
}
|
|
@@ -7991,7 +8197,14 @@ function createPaintStickerTools(c) {
|
|
|
7991
8197
|
},
|
|
7992
8198
|
annotations: { title: "Place stickers", ...WRITE },
|
|
7993
8199
|
coordinates: { in: ["stickers[]"], out: ["stickers[]"] },
|
|
7994
|
-
handler: ({ layerId, stickers }) =>
|
|
8200
|
+
handler: async ({ layerId, stickers }) => {
|
|
8201
|
+
const list = stickers;
|
|
8202
|
+
list.forEach((x, i) => {
|
|
8203
|
+
if (x.ref === void 0 && x.stamp === void 0) throw new Error(`Sticker ${i} needs ref (a sticker ref from find_stickers, e.g. "editor:star").`);
|
|
8204
|
+
});
|
|
8205
|
+
await c.prepareStickers(list.map((x) => x.ref ?? `editor:${x.stamp}`));
|
|
8206
|
+
return { layerId: layerId ?? c.document.activeLayerId, stickers: c.addStickers(layerId, list) };
|
|
8207
|
+
}
|
|
7995
8208
|
},
|
|
7996
8209
|
{
|
|
7997
8210
|
name: "update_sticker",
|
|
@@ -8002,7 +8215,8 @@ function createPaintStickerTools(c) {
|
|
|
8002
8215
|
properties: {
|
|
8003
8216
|
layerId: LAYER_ID,
|
|
8004
8217
|
id: { type: "string", description: "Sticker id from list_stickers." },
|
|
8005
|
-
|
|
8218
|
+
ref: { type: "string", minLength: 1, description: "Another sticker: a ref provider:id from find_stickers." },
|
|
8219
|
+
stamp: { type: "string", enum: [...STAMP_KINDS], description: "Older form: another editor stamp (same as ref editor:<stamp>)." },
|
|
8006
8220
|
x: { type: "number", description: "Centre x in document pixels." },
|
|
8007
8221
|
y: { type: "number", description: "Centre y in document pixels." },
|
|
8008
8222
|
size: { type: "number", minimum: 2, maximum: 2048, description: "Diameter in pixels." },
|
|
@@ -8015,7 +8229,11 @@ function createPaintStickerTools(c) {
|
|
|
8015
8229
|
},
|
|
8016
8230
|
annotations: { title: "Change a sticker", ...WRITE },
|
|
8017
8231
|
coordinates: { in: [""], out: [""] },
|
|
8018
|
-
handler: ({ layerId, id, ...update }) =>
|
|
8232
|
+
handler: async ({ layerId, id, ...update }) => {
|
|
8233
|
+
const refs = c.listStickers(layerId).map((s) => s.ref);
|
|
8234
|
+
await c.prepareStickers(update.ref ? [...refs, update.ref] : refs);
|
|
8235
|
+
return c.updateSticker(layerId, id, update);
|
|
8236
|
+
}
|
|
8019
8237
|
},
|
|
8020
8238
|
{
|
|
8021
8239
|
name: "arrange_stickers",
|
|
@@ -8032,7 +8250,10 @@ function createPaintStickerTools(c) {
|
|
|
8032
8250
|
additionalProperties: false
|
|
8033
8251
|
},
|
|
8034
8252
|
annotations: { title: "Bring stickers forward or back", ...WRITE },
|
|
8035
|
-
handler: ({ layerId, ids, to }) =>
|
|
8253
|
+
handler: async ({ layerId, ids, to }) => {
|
|
8254
|
+
await c.prepareStickers(c.listStickers(layerId).map((s) => s.ref));
|
|
8255
|
+
return { order: c.arrangeStickers(layerId, ids, to) };
|
|
8256
|
+
}
|
|
8036
8257
|
},
|
|
8037
8258
|
{
|
|
8038
8259
|
name: "remove_stickers",
|
|
@@ -8040,7 +8261,10 @@ function createPaintStickerTools(c) {
|
|
|
8040
8261
|
description: "Deletes stickers by id, or every sticker on the layer when ids is missing. One undo step. Returns the ids removed.",
|
|
8041
8262
|
inputSchema: { type: "object", properties: { layerId: LAYER_ID, ids: { type: "array", items: { type: "string", description: "Sticker id." }, description: "Sticker ids (default all)." } }, additionalProperties: false },
|
|
8042
8263
|
annotations: { title: "Delete stickers", ...DESTRUCTIVE },
|
|
8043
|
-
handler: ({ layerId, ids }) =>
|
|
8264
|
+
handler: async ({ layerId, ids }) => {
|
|
8265
|
+
await c.prepareStickers(c.listStickers(layerId).map((s) => s.ref));
|
|
8266
|
+
return { removed: c.removeStickers(layerId, ids) };
|
|
8267
|
+
}
|
|
8044
8268
|
}
|
|
8045
8269
|
];
|
|
8046
8270
|
}
|
|
@@ -9001,17 +9225,39 @@ var PARTICLE_BRUSH = {
|
|
|
9001
9225
|
type: "object",
|
|
9002
9226
|
description: "Particle engine settings (procedural brushes). Missing fields keep their current values.",
|
|
9003
9227
|
properties: {
|
|
9004
|
-
kind: {
|
|
9005
|
-
|
|
9228
|
+
kind: {
|
|
9229
|
+
type: "string",
|
|
9230
|
+
enum: [...PARTICLE_KINDS],
|
|
9231
|
+
description: "string: strands of masses on springs dragged behind the pen (hair, fur, wet string); spring: particles on springs to the pen, overshooting and wobbling; orbit: particles circling the pen (curls); flow: particles thrown off the pen into a swirling flow until they fade; elastic: strands whose links keep a rest length, stretching when the pen is fast and snapping back; fuzzy: winding strings, each strand waving out of step with the others (always waves by at least 0.12 of the tip size)."
|
|
9232
|
+
},
|
|
9233
|
+
render: {
|
|
9234
|
+
type: "string",
|
|
9235
|
+
enum: [...PARTICLE_RENDERS],
|
|
9236
|
+
description: "dot: a mark at each step (round, or dotTextures); line: each particle draws a continuous line; sequence: beads spaced along each path (round, or dotTextures); ribbon: the band between neighbouring particles' paths filled (ribbonFill), with the paths drawn as its edges at the mark size (flame, silk, smoke)."
|
|
9237
|
+
},
|
|
9006
9238
|
count: { type: "integer", minimum: 1, maximum: 64, description: "Particles (flow: how many are thrown per tip of travel)." },
|
|
9007
|
-
size: { type: "number", minimum: 0, maximum: 1, description: "Mark size as a fraction of the tip size." },
|
|
9008
|
-
spread: { type: "number", minimum: 0, maximum: 1, description: "How far apart the particles start, as a fraction of the tip size." },
|
|
9009
|
-
stiffness: { type: "number", minimum: 0, maximum: 1, description: "Spring and
|
|
9239
|
+
size: { type: "number", minimum: 0, maximum: 1, description: "Mark size as a fraction of the tip size (ribbon: the width of its edges)." },
|
|
9240
|
+
spread: { type: "number", minimum: 0, maximum: 1, description: "How far apart the particles start, as a fraction of the tip size (ribbon: how wide it is)." },
|
|
9241
|
+
stiffness: { type: "number", minimum: 0, maximum: 1, description: "Spring, string and elastic stiffness: stiff follows closely (elastic: snaps back faster), soft swings wide." },
|
|
9010
9242
|
damping: { type: "number", minimum: 0, maximum: 1, description: "How quickly motion dies down." },
|
|
9011
9243
|
speed: { type: "number", minimum: 0, maximum: 1, description: "Orbit and flow speed." },
|
|
9012
9244
|
gravity: { type: "number", minimum: -1, maximum: 1, description: "Pull downwards (negative: upwards)." },
|
|
9013
9245
|
life: { type: "number", minimum: 0, maximum: 1, description: "Flow particles: how long they live." },
|
|
9014
|
-
interval: { type: "number", minimum: 0, maximum: 1, description: "Sequence: spacing of the beads." }
|
|
9246
|
+
interval: { type: "number", minimum: 0, maximum: 1, description: "Sequence: spacing of the beads." },
|
|
9247
|
+
ribbonFill: { type: "number", minimum: 0, maximum: 1, description: "Ribbon: opacity of the fill between the paths, relative to their edges (default 0.5; 0 draws only the edges)." },
|
|
9248
|
+
ribbonPairs: { type: "string", enum: [...RIBBON_PAIRS], description: "Ribbon: adjacent (default) joins each particle to its neighbour around the pen; first-last makes one band between the outermost two." },
|
|
9249
|
+
waveAmplitude: { type: "number", minimum: 0, maximum: 1, description: "Wave: how far each particle's drawn place swings sideways to the stroke, as a fraction of the tip size (default 0: no wave). Works with every kind and render." },
|
|
9250
|
+
waveLength: { type: "number", minimum: 4, maximum: 2e3, description: "Wave: wavelength in px of pen travel (default 60)." },
|
|
9251
|
+
waveSpeed: { type: "number", minimum: 0, maximum: 1, description: "Wave: how fast the waves run, by stroke time (0 default: they stand still on the path; 1: about four a second, so slow strokes wave more). Strokes without times run at a nominal 0.5 px/ms." },
|
|
9252
|
+
wavePhaseJitter: { type: "number", minimum: 0, maximum: 1, description: "Wave: how far out of step the particles' waves are (default 0: all in step, a wavy band; 1: random phases, tangled strands)." },
|
|
9253
|
+
dotTextures: {
|
|
9254
|
+
type: "array",
|
|
9255
|
+
maxItems: MAX_DOT_TEXTURES,
|
|
9256
|
+
items: { type: "string", enum: [...STAMP_KINDS], description: "A stamp." },
|
|
9257
|
+
description: `Dot and sequence renders: up to ${MAX_DOT_TEXTURES} sticker stamps (list_stickers) drawn instead of round marks; repeats are allowed (they weight the order). Empty (default): round marks.`
|
|
9258
|
+
},
|
|
9259
|
+
dotTextureOrder: { type: "string", enum: [...DOT_TEXTURE_ORDERS], description: "Textured dots: sequence (default) uses the stamps in turn; random picks one per dot (seeded, so replays are exact)." },
|
|
9260
|
+
dotRotation: { type: "string", enum: [...DOT_ROTATIONS], description: "Textured dots: follow turns each with its particle's motion; random (default) turns each at random; fixed uses the tip angle." }
|
|
9015
9261
|
},
|
|
9016
9262
|
additionalProperties: false
|
|
9017
9263
|
};
|
|
@@ -9032,7 +9278,13 @@ var STICKER_BRUSH = {
|
|
|
9032
9278
|
type: "object",
|
|
9033
9279
|
description: "Sticker engine settings: stamps sprayed along the stroke as editable stickers. Missing fields keep their current values.",
|
|
9034
9280
|
properties: {
|
|
9035
|
-
stamps: {
|
|
9281
|
+
stamps: {
|
|
9282
|
+
type: "array",
|
|
9283
|
+
minItems: 1,
|
|
9284
|
+
maxItems: MAX_STICKER_STAMPS,
|
|
9285
|
+
items: { type: "string", minLength: 1, description: "A sticker ref provider:id from find_stickers (e.g. editor:star); a bare editor stamp (star) means editor:star." },
|
|
9286
|
+
description: `The stickers to spray, one picked at random per sticker: refs from find_stickers (the editor's own: ${STAMP_KINDS.map((k) => `editor:${k}`).join(", ")}). Each is checked against the sticker library and an unknown ref is refused with the closest ones. A provider's sticker is drawn from its art (tinted to the paint colour when tintable), loaded before the stroke.`
|
|
9287
|
+
},
|
|
9036
9288
|
density: { type: "number", minimum: 0, maximum: 1, description: "How closely stickers follow each other: about density \xD7 4 stickers per tip diameter of travel (0.25 \u2248 one per diameter, 1 \u2248 four). Default 0.4." },
|
|
9037
9289
|
sizeJitter: { type: "number", minimum: 0, maximum: 1, description: "Random size change." },
|
|
9038
9290
|
rotationJitter: { type: "number", minimum: 0, maximum: 1, description: "Random turn as a fraction of \xB1180\xB0." },
|
|
@@ -9431,7 +9683,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
9431
9683
|
add({
|
|
9432
9684
|
name: "list_brushes",
|
|
9433
9685
|
title: "List brushes",
|
|
9434
|
-
description: "Lists the brush library: built-in dry media (pencils, pastels, charcoal, airbrush, marker, ink, erasers), paint brushes (dirty round, multi-colour flat, palette dabber), blending tools (blender, smudge, pigment smudge, Mixer Brush), light paint (category light: glow gel, neon marker, light airbrush, spark trail, glow wash, highlighter; light is the amount they lay) and saved user brushes, with id, name, category, engine, size, grain response, rotation mode, whether it can pick up paint (wetCapable), its pick-up ratio, dirty and multi-colour mode, plus the active brush id.",
|
|
9686
|
+
description: "Lists the brush library: built-in dry media (pencils, pastels, charcoal, airbrush, marker, ink, erasers), paint brushes (dirty round, multi-colour flat, palette dabber), blending tools (blender, smudge, pigment smudge, Mixer Brush), light paint (category light: glow gel, neon marker, light airbrush, spark trail, light ribbon, flame ribbon, neon strand, smoke ribbon, bokeh dots, twinkle sparks, glow wash, highlighter; light is the amount they lay) and saved user brushes, with id, name, category, engine, size, grain response, rotation mode, whether it can pick up paint (wetCapable), its pick-up ratio, dirty and multi-colour mode, plus the active brush id.",
|
|
9435
9687
|
inputSchema: EMPTY3,
|
|
9436
9688
|
annotations: { title: "List brushes", ...READ6 },
|
|
9437
9689
|
handler: () => {
|
|
@@ -9459,7 +9711,11 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
9459
9711
|
description: "Chooses the active brush (id) and / or changes its settings; strokes without a brush use it. Editor state, not an undo step. Changes stay on the active brush until save_brush stores them. Returns the active brush.",
|
|
9460
9712
|
inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brushes to start from." }, ...BRUSH_FIELDS }, additionalProperties: false },
|
|
9461
9713
|
annotations: { title: "Set the brush", ...SET4 },
|
|
9462
|
-
handler: (a) =>
|
|
9714
|
+
handler: async (a) => {
|
|
9715
|
+
const stamps = a.sticker?.stamps;
|
|
9716
|
+
if (stamps) await c.prepareStickers(stamps);
|
|
9717
|
+
return brushToJSON(c.setBrush(a));
|
|
9718
|
+
}
|
|
9463
9719
|
});
|
|
9464
9720
|
add({
|
|
9465
9721
|
name: "save_brush",
|
|
@@ -9635,6 +9891,9 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
9635
9891
|
coordinates: { in: ["points[]"], out: ["bounds"] },
|
|
9636
9892
|
handler: async (a) => {
|
|
9637
9893
|
await c.wetIdle();
|
|
9894
|
+
const base = a.brushId ? c.getBrush(a.brushId) : c.getState().brush;
|
|
9895
|
+
const over = a.brush;
|
|
9896
|
+
if ((over?.engine ?? base?.engine) === "sticker") await c.prepareStickers(over?.sticker?.stamps ?? base?.sticker.stamps ?? []);
|
|
9638
9897
|
const stroke = { points: a.points, layerId: a.layerId, brushId: a.brushId, brush: a.brush, color: a.color, paint: a.paint, seed: a.seed, snapToPerspective: a.snapToPerspective };
|
|
9639
9898
|
const r = await act({ kind: "stroke", stroke }, () => c.paintStroke(stroke));
|
|
9640
9899
|
return r.mixerLoad ? { ...r, mixerLoad: loadResult(r.mixerLoad) } : r;
|
|
@@ -9943,6 +10202,20 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
9943
10202
|
tools.push(...createPaintReplayTools(c));
|
|
9944
10203
|
tools.push(...createPaintStickerTools(c));
|
|
9945
10204
|
tools.push(...createPigmentTools());
|
|
10205
|
+
tools.push(...createStickerTools({ provider: () => c.stickersProvider }));
|
|
10206
|
+
tools.push(
|
|
10207
|
+
...createLayerEffectTools(
|
|
10208
|
+
{
|
|
10209
|
+
requireLayer: (id) => void c.getLayerEffects(id),
|
|
10210
|
+
getLayerEffects: (id) => c.getLayerEffects(id),
|
|
10211
|
+
addLayerEffect: (id, kind, settings, index) => c.addLayerEffect(id, kind, settings, index),
|
|
10212
|
+
updateLayerEffect: (id, effectId, changes) => c.updateLayerEffect(id, effectId, changes),
|
|
10213
|
+
removeLayerEffect: (id, effectId) => c.removeLayerEffect(id, effectId),
|
|
10214
|
+
setLayerEffectsEnabled: (id, enabled, scale) => c.setLayerEffectsEnabled(id, enabled, scale)
|
|
10215
|
+
},
|
|
10216
|
+
{ layers: "a pixel, stroke, sticker or group layer", error: (m) => new PaintEditorError(m) }
|
|
10217
|
+
)
|
|
10218
|
+
);
|
|
9946
10219
|
const exclude = new Set(options.exclude ?? []);
|
|
9947
10220
|
const description = "Natural-media painting: paper and grain, dry and wet brushes, the brush library, strokes as data, pigment mixing, stencils, guides, layers and export.";
|
|
9948
10221
|
return withPaintPlayback({
|
|
@@ -10103,7 +10376,7 @@ var PaintGesture = class {
|
|
|
10103
10376
|
}
|
|
10104
10377
|
const brush = this.controller.getState().brush;
|
|
10105
10378
|
const size = Math.min(2048, Math.max(2, Math.round(brush.tip.size)));
|
|
10106
|
-
const [added] = this.controller.addStickers(void 0, [{
|
|
10379
|
+
const [added] = this.controller.addStickers(void 0, [{ ref: brush.sticker.stamps[0] ?? "editor:star", x: round2(p.x), y: round2(p.y), size }]);
|
|
10107
10380
|
this.controller.selectSticker(added.id);
|
|
10108
10381
|
} catch (err) {
|
|
10109
10382
|
this.error = err instanceof Error ? err.message : String(err);
|
|
@@ -10413,7 +10686,12 @@ function engineControls(brush) {
|
|
|
10413
10686
|
{ path: "particle.speed", label: "Speed", min: 0, max: 1, step: 0.01 },
|
|
10414
10687
|
{ path: "particle.gravity", label: "Gravity", min: -1, max: 1, step: 0.01 },
|
|
10415
10688
|
{ path: "particle.life", label: "Life", min: 0, max: 1, step: 0.01 },
|
|
10416
|
-
{ path: "particle.interval", label: "Bead spacing", min: 0, max: 1, step: 0.01 }
|
|
10689
|
+
{ path: "particle.interval", label: "Bead spacing", min: 0, max: 1, step: 0.01 },
|
|
10690
|
+
{ path: "particle.ribbonFill", label: "Ribbon fill", min: 0, max: 1, step: 0.01 },
|
|
10691
|
+
{ path: "particle.waveAmplitude", label: "Wave", min: 0, max: 1, step: 0.01 },
|
|
10692
|
+
{ path: "particle.waveLength", label: "Wavelength", min: 4, max: 400, step: 1 },
|
|
10693
|
+
{ path: "particle.waveSpeed", label: "Wave speed", min: 0, max: 1, step: 0.01 },
|
|
10694
|
+
{ path: "particle.wavePhaseJitter", label: "Wave scatter", min: 0, max: 1, step: 0.01 }
|
|
10417
10695
|
],
|
|
10418
10696
|
mixingPath: null,
|
|
10419
10697
|
dirty: false,
|
|
@@ -10628,13 +10906,29 @@ var LIGHT_SLIDERS = [
|
|
|
10628
10906
|
{ path: "elevation", label: "Light height", min: 5, max: 90, step: 1 },
|
|
10629
10907
|
{ path: "relief", label: "Relief", min: 0, max: 1, step: 0.01 }
|
|
10630
10908
|
];
|
|
10631
|
-
var PARTICLE_KIND_LABELS = { string: "Strings", spring: "Springs", orbit: "Orbits", flow: "Flow" };
|
|
10632
|
-
var PARTICLE_RENDER_LABELS = { dot: "Dots", line: "Lines", sequence: "Beads" };
|
|
10909
|
+
var PARTICLE_KIND_LABELS = { string: "Strings", spring: "Springs", orbit: "Orbits", flow: "Flow", elastic: "Elastic", fuzzy: "Fuzzy" };
|
|
10910
|
+
var PARTICLE_RENDER_LABELS = { dot: "Dots", line: "Lines", sequence: "Beads", ribbon: "Ribbon" };
|
|
10911
|
+
var RIBBON_PAIR_LABELS = { adjacent: "Neighbours", "first-last": "Outermost" };
|
|
10912
|
+
var DOT_TEXTURE_ORDER_LABELS = { sequence: "In turn", random: "Random" };
|
|
10913
|
+
var DOT_ROTATION_LABELS = { follow: "Follow motion", random: "Random", fixed: "Tip angle" };
|
|
10633
10914
|
var STAMP_LABELS = { dot: "Dot", star: "Star", heart: "Heart", leaf: "Leaf", flower: "Flower", confetti: "Confetti", splat: "Splat", sparkle: "Sparkle", ring: "Ring" };
|
|
10915
|
+
function toggleStickerRef(refs, ref2) {
|
|
10916
|
+
if (refs.includes(ref2)) return refs.length > 1 ? refs.filter((r) => r !== ref2) : [...refs];
|
|
10917
|
+
return refs.length < MAX_STICKER_STAMPS ? [...refs, ref2] : [...refs];
|
|
10918
|
+
}
|
|
10919
|
+
function stickerRefLabel(ref2) {
|
|
10920
|
+
const stamp = ref2.startsWith("editor:") ? ref2.slice(7) : null;
|
|
10921
|
+
if (stamp && STAMP_LABELS[stamp]) return STAMP_LABELS[stamp];
|
|
10922
|
+
return ref2.slice(ref2.indexOf(":") + 1);
|
|
10923
|
+
}
|
|
10634
10924
|
function toggleStamp(stamps, stamp) {
|
|
10635
10925
|
const next = stamps.includes(stamp) ? stamps.filter((s) => s !== stamp) : [...stamps, stamp];
|
|
10636
10926
|
return next.length ? next : [stamp];
|
|
10637
10927
|
}
|
|
10928
|
+
function toggleDotTexture(textures, stamp) {
|
|
10929
|
+
if (textures.includes(stamp)) return textures.filter((s) => s !== stamp);
|
|
10930
|
+
return textures.length < MAX_DOT_TEXTURES ? [...textures, stamp] : [...textures];
|
|
10931
|
+
}
|
|
10638
10932
|
var STROKE_SLIDERS = [
|
|
10639
10933
|
{ path: "tip.size", label: "Size", min: 1, max: 400, step: 1 },
|
|
10640
10934
|
{ path: "tip.opacity", label: "Opacity", min: 0, max: 1, step: 0.01 },
|
|
@@ -10957,6 +11251,10 @@ export {
|
|
|
10957
11251
|
DEFAULT_VIEW,
|
|
10958
11252
|
DEFAULT_WET_BRUSH,
|
|
10959
11253
|
DEFAULT_WET_PARAMS,
|
|
11254
|
+
DOT_ROTATIONS,
|
|
11255
|
+
DOT_ROTATION_LABELS,
|
|
11256
|
+
DOT_TEXTURE_ORDERS,
|
|
11257
|
+
DOT_TEXTURE_ORDER_LABELS,
|
|
10960
11258
|
DryStroke,
|
|
10961
11259
|
EFFECT_MAP_REPEATS,
|
|
10962
11260
|
EFFECT_STRIP_HEIGHT,
|
|
@@ -10974,8 +11272,10 @@ export {
|
|
|
10974
11272
|
MAX_BRUSH_SIZE,
|
|
10975
11273
|
MAX_CANVAS_SIDE,
|
|
10976
11274
|
MAX_COORDINATE,
|
|
11275
|
+
MAX_DOT_TEXTURES,
|
|
10977
11276
|
MAX_IMAGE_SIDE,
|
|
10978
11277
|
MAX_LIVE_EFFECT_SOURCES,
|
|
11278
|
+
MAX_STICKER_STAMPS,
|
|
10979
11279
|
MAX_ZOOM,
|
|
10980
11280
|
MIN_CANVAS_SIDE,
|
|
10981
11281
|
MIN_ZOOM,
|
|
@@ -11033,15 +11333,20 @@ export {
|
|
|
11033
11333
|
PenDabWalker,
|
|
11034
11334
|
PenSmoother,
|
|
11035
11335
|
PerspectiveSnapper,
|
|
11336
|
+
RIBBON_PAIRS,
|
|
11337
|
+
RIBBON_PAIR_LABELS,
|
|
11036
11338
|
SNAP_DECIDE_DISTANCE,
|
|
11037
11339
|
STAMP_KINDS,
|
|
11038
11340
|
STAMP_LABELS,
|
|
11039
11341
|
STENCIL_KINDS,
|
|
11040
11342
|
STENCIL_SHAPES,
|
|
11343
|
+
STICKER_ART_SIZE,
|
|
11041
11344
|
STICKER_SLIDERS,
|
|
11042
11345
|
STROKE_SLIDERS,
|
|
11043
11346
|
SYMMETRY_MODES,
|
|
11044
11347
|
StencilSnapper,
|
|
11348
|
+
StickerArtCache,
|
|
11349
|
+
StickerBrowser,
|
|
11045
11350
|
StickerSpray,
|
|
11046
11351
|
TRACING_NODE_ID,
|
|
11047
11352
|
ThickStrokeDriver,
|
|
@@ -11061,6 +11366,7 @@ export {
|
|
|
11061
11366
|
WET_TOOL_LABELS,
|
|
11062
11367
|
WetStrokeDriver,
|
|
11063
11368
|
addPaintGradientStop,
|
|
11369
|
+
addPolygonArea,
|
|
11064
11370
|
affineCopy,
|
|
11065
11371
|
applyAffine,
|
|
11066
11372
|
backlightOf,
|
|
@@ -11088,6 +11394,7 @@ export {
|
|
|
11088
11394
|
decodeImageBlob,
|
|
11089
11395
|
defaultGuides,
|
|
11090
11396
|
defaultImageEncoder,
|
|
11397
|
+
defaultStickerRasterizer,
|
|
11091
11398
|
deserializePaintDocument,
|
|
11092
11399
|
deserializePaintDocumentAsync,
|
|
11093
11400
|
documentExtensions,
|
|
@@ -11206,6 +11513,7 @@ export {
|
|
|
11206
11513
|
rgbToHexColor,
|
|
11207
11514
|
rgbToHsl,
|
|
11208
11515
|
rgbToHsv,
|
|
11516
|
+
sampleArt,
|
|
11209
11517
|
sampleEffectAt,
|
|
11210
11518
|
sampleEffectField,
|
|
11211
11519
|
samplePressure,
|
|
@@ -11223,6 +11531,8 @@ export {
|
|
|
11223
11531
|
stencilOutline,
|
|
11224
11532
|
stickerAt,
|
|
11225
11533
|
stickerRect,
|
|
11534
|
+
stickerRefLabel,
|
|
11535
|
+
stickerStamp,
|
|
11226
11536
|
stickerSurface,
|
|
11227
11537
|
strokeBounds,
|
|
11228
11538
|
strokeDuration,
|
|
@@ -11238,7 +11548,9 @@ export {
|
|
|
11238
11548
|
timeLapseVideo,
|
|
11239
11549
|
timeLapseZip,
|
|
11240
11550
|
toStrokePoint,
|
|
11551
|
+
toggleDotTexture,
|
|
11241
11552
|
toggleStamp,
|
|
11553
|
+
toggleStickerRef,
|
|
11242
11554
|
translateStencil,
|
|
11243
11555
|
updatePaintGradientStop,
|
|
11244
11556
|
usesPaintExchange,
|