@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,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7;
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
var _chunkZEYMKDYScjs = require('./chunk-ZEYMKDYS.cjs');
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
|
|
@@ -20,7 +21,21 @@
|
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
var _chunkI7NJPHWVcjs = require('./chunk-I7NJPHWV.cjs');
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
var _chunk3K6HWEXZcjs = require('./chunk-3K6HWEXZ.cjs');
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
var _chunkW5M3J7PVcjs = require('./chunk-W5M3J7PV.cjs');
|
|
24
39
|
|
|
25
40
|
|
|
26
41
|
|
|
@@ -229,7 +244,7 @@ function normalizePaper(raw = {}, base) {
|
|
|
229
244
|
preset: typeof r.preset === "string" && r.preset ? r.preset : b.preset,
|
|
230
245
|
name: typeof r.name === "string" && r.name.trim() ? r.name.trim() : b.name,
|
|
231
246
|
family: PAPER_FAMILIES.includes(r.family) ? r.family : b.family,
|
|
232
|
-
pattern:
|
|
247
|
+
pattern: _chunkI7NJPHWVcjs.GRAIN_PATTERNS.includes(r.pattern) ? r.pattern : b.pattern,
|
|
233
248
|
seed: typeof r.seed === "number" && Number.isFinite(r.seed) ? Math.round(Math.abs(r.seed)) % 2147483647 : b.seed,
|
|
234
249
|
color: typeof r.color === "string" && HEX.test(r.color) ? r.color.toLowerCase() : b.color,
|
|
235
250
|
scale: clampNum(r.scale, 0.25, 8, b.scale),
|
|
@@ -251,7 +266,7 @@ function hexToRgb8(hex) {
|
|
|
251
266
|
const n = parseInt(hex.slice(1, 7), 16);
|
|
252
267
|
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
253
268
|
}
|
|
254
|
-
function renderPaper(paper, rect, grain = new (0,
|
|
269
|
+
function renderPaper(paper, rect, grain = new (0, _chunkI7NJPHWVcjs.PaperGrain)(paper), light) {
|
|
255
270
|
const [r, g, b] = hexToRgb8(paper.color);
|
|
256
271
|
const out = new Uint8ClampedArray(rect.width * rect.height * 4);
|
|
257
272
|
const shade = grain.flat ? 0 : paper.shading * 0.16;
|
|
@@ -413,22 +428,22 @@ var PenDabWalker = (_class2 = class {
|
|
|
413
428
|
const i = this.index++;
|
|
414
429
|
const seed = this.seed;
|
|
415
430
|
let diameter = this.diameter(s);
|
|
416
|
-
if (dyn.sizeJitter) diameter *= Math.max(0.05, 1 + dyn.sizeJitter *
|
|
431
|
+
if (dyn.sizeJitter) diameter *= Math.max(0.05, 1 + dyn.sizeJitter * _chunk3K6HWEXZcjs.randSigned.call(void 0, seed, i, 1 /* Size */));
|
|
417
432
|
const base = tip.angle * Math.PI / 180;
|
|
418
433
|
let angle;
|
|
419
434
|
if (rotation === "stroke") angle = this.dir + base;
|
|
420
435
|
else if (rotation === "barrel" && s.twist !== null) angle = this.mapAngle(base - s.twist * Math.PI / 180);
|
|
421
436
|
else if (dyn.tiltRoundness > 0 && s.lean > 0.02) angle = this.mapAngle(base - s.azimuth);
|
|
422
437
|
else angle = this.mapAngle(base);
|
|
423
|
-
if (dyn.angleJitter) angle += dyn.angleJitter * Math.PI *
|
|
438
|
+
if (dyn.angleJitter) angle += dyn.angleJitter * Math.PI * _chunk3K6HWEXZcjs.randSigned.call(void 0, seed, i, 2 /* Angle */);
|
|
424
439
|
let opacity = tip.pressureOpacity ? s.pressure : 1;
|
|
425
440
|
opacity *= 1 - dyn.tiltOpacity * s.lean * 0.8;
|
|
426
441
|
if (s.speed !== null && dyn.velocityOpacity) opacity *= Math.max(0, 1 + dyn.velocityOpacity * (Math.min(1, s.speed / FULL_SPEED) - 0.5));
|
|
427
|
-
if (dyn.opacityJitter) opacity *= 1 - dyn.opacityJitter * (
|
|
442
|
+
if (dyn.opacityJitter) opacity *= 1 - dyn.opacityJitter * (_chunk3K6HWEXZcjs.randSigned.call(void 0, seed, i, 3 /* Opacity */) * 0.5 + 0.5);
|
|
428
443
|
const flow = tip.flow * (1 - dyn.pressureFlow + dyn.pressureFlow * s.pressure);
|
|
429
444
|
let { x, y } = s;
|
|
430
445
|
if (dyn.scatter) {
|
|
431
|
-
const off = dyn.scatter * diameter *
|
|
446
|
+
const off = dyn.scatter * diameter * _chunk3K6HWEXZcjs.randSigned.call(void 0, seed, i, 4 /* Scatter */);
|
|
432
447
|
x += Math.sin(this.dir) * off;
|
|
433
448
|
y += Math.cos(this.dir) * off;
|
|
434
449
|
}
|
|
@@ -518,7 +533,7 @@ var DryStroke = (_class3 = class {
|
|
|
518
533
|
}
|
|
519
534
|
|
|
520
535
|
|
|
521
|
-
__init12() {this.coverage = new (0,
|
|
536
|
+
__init12() {this.coverage = new (0, _chunkI7NJPHWVcjs.CoverageMap)()}
|
|
522
537
|
__init13() {this.dabCount = 0}
|
|
523
538
|
|
|
524
539
|
|
|
@@ -553,16 +568,16 @@ var DryStroke = (_class3 = class {
|
|
|
553
568
|
const hardness = this.brush.tip.hardness;
|
|
554
569
|
const grain = this.options.grain;
|
|
555
570
|
for (const d of dabs) {
|
|
556
|
-
const rect =
|
|
571
|
+
const rect = _chunkI7NJPHWVcjs.dabRect.call(void 0, d, hardness);
|
|
557
572
|
const n = rect.width * rect.height;
|
|
558
573
|
if (this.buf.length < n) this.buf = new Float32Array(n);
|
|
559
574
|
const vals = this.buf.subarray(0, n);
|
|
560
|
-
|
|
575
|
+
_chunkI7NJPHWVcjs.rasterizeDab.call(void 0, d, hardness, rect, vals);
|
|
561
576
|
if (this.depth > 0 && grain) {
|
|
562
577
|
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
563
578
|
const y = rect.y + yy + 0.5;
|
|
564
579
|
for (let xx = 0; xx < rect.width; xx++, k++) {
|
|
565
|
-
if (vals[k] > 0) vals[k] *=
|
|
580
|
+
if (vals[k] > 0) vals[k] *= _chunkI7NJPHWVcjs.grainCatch.call(void 0, grain.at(rect.x + xx + 0.5, y), this.depth, d.pressure);
|
|
566
581
|
}
|
|
567
582
|
}
|
|
568
583
|
}
|
|
@@ -586,14 +601,129 @@ function toStrokePoint(p) {
|
|
|
586
601
|
return { x: p.x, y: p.y, pressure: pressureOf(p), ...typeof p.t === "number" ? { t: p.t } : {} };
|
|
587
602
|
}
|
|
588
603
|
|
|
604
|
+
// src/paint-editor/sticker-art.ts
|
|
605
|
+
var STICKER_ART_SIZE = 256;
|
|
606
|
+
var defaultStickerRasterizer = async (asset, size) => {
|
|
607
|
+
if (asset.kind === "image") {
|
|
608
|
+
const parsed = _chunkW5M3J7PVcjs.parseDataUrl.call(void 0, asset.url);
|
|
609
|
+
if (parsed && parsed.mime === "image/png") {
|
|
610
|
+
const png = _chunkW5M3J7PVcjs.decodePng.call(void 0, parsed.bytes);
|
|
611
|
+
return { width: png.width, height: png.height, data: new Uint8ClampedArray(png.data) };
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
const g = globalThis;
|
|
615
|
+
if (!g.createImageBitmap || !g.OffscreenCanvas) {
|
|
616
|
+
throw new (0, _chunkZEYMKDYScjs.StickerError)("unsupported_format", `This environment can't draw ${asset.kind === "svg" ? "SVG" : "non-PNG"} sticker art; pass rasterizeSticker in the paint editor's options (or use a provider that offers png).`);
|
|
617
|
+
}
|
|
618
|
+
const blob = asset.kind === "svg" ? new Blob([asset.svg], { type: "image/svg+xml" }) : await (await g.fetch(asset.url)).blob();
|
|
619
|
+
const bitmap = await g.createImageBitmap(blob);
|
|
620
|
+
const scale = size / Math.max(bitmap.width, bitmap.height, 1);
|
|
621
|
+
const w = Math.max(1, Math.round(bitmap.width * scale));
|
|
622
|
+
const h = Math.max(1, Math.round(bitmap.height * scale));
|
|
623
|
+
const canvas = new g.OffscreenCanvas(w, h);
|
|
624
|
+
const ctx = canvas.getContext("2d");
|
|
625
|
+
ctx.drawImage(bitmap, 0, 0, w, h);
|
|
626
|
+
const img = ctx.getImageData(0, 0, w, h);
|
|
627
|
+
return { width: w, height: h, data: img.data };
|
|
628
|
+
};
|
|
629
|
+
var StickerArtCache = (_class4 = class {constructor() { _class4.prototype.__init18.call(this);_class4.prototype.__init19.call(this); }
|
|
630
|
+
__init18() {this.entries = /* @__PURE__ */ new Map()}
|
|
631
|
+
/** The art for `ref` when it has loaded (editor stamps never need any). */
|
|
632
|
+
__init19() {this.get = (ref) => {
|
|
633
|
+
const e = this.entries.get(ref);
|
|
634
|
+
return _optionalChain([e, 'optionalAccess', _8 => _8.status]) === "ready" ? e.art : void 0;
|
|
635
|
+
}}
|
|
636
|
+
/** `ready`, `loading`, `failed` (with the reason) or `none` (never asked for). Editor stamps are always `ready`. */
|
|
637
|
+
status(ref) {
|
|
638
|
+
if (_chunkZEYMKDYScjs.editorStampOf.call(void 0, ref)) return { status: "ready" };
|
|
639
|
+
const e = this.entries.get(ref);
|
|
640
|
+
if (!e) return { status: "none" };
|
|
641
|
+
return e.status === "failed" ? { status: "failed", error: e.error } : { status: e.status };
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Loads and rasterises `ref` from `provider` once (later calls share the load). Unknown refs
|
|
645
|
+
* reject with the closest known ones; failures are kept so they are reported, and retried on
|
|
646
|
+
* the next call.
|
|
647
|
+
*/
|
|
648
|
+
ensure(provider, ref, rasterize) {
|
|
649
|
+
if (_chunkZEYMKDYScjs.editorStampOf.call(void 0, ref)) return Promise.resolve(null);
|
|
650
|
+
const e = this.entries.get(ref);
|
|
651
|
+
if (_optionalChain([e, 'optionalAccess', _9 => _9.status]) === "ready") return Promise.resolve(e.art);
|
|
652
|
+
if (_optionalChain([e, 'optionalAccess', _10 => _10.status]) === "loading") return e.promise;
|
|
653
|
+
const promise = (async () => {
|
|
654
|
+
const d = await _chunkZEYMKDYScjs.describeStickerRef.call(void 0, provider, ref);
|
|
655
|
+
const id = _chunkZEYMKDYScjs.stickerIdFor.call(void 0, provider, ref);
|
|
656
|
+
const max = _nullishCoalesce(provider.capabilities.maxSize, () => ( STICKER_ART_SIZE));
|
|
657
|
+
const size = Math.min(STICKER_ART_SIZE, max);
|
|
658
|
+
const asset = await provider.load(id, d.formats.includes("png") ? { format: "png", size } : { format: _nullishCoalesce(d.formats[0], () => ( "svg")), size });
|
|
659
|
+
const px = await rasterize(asset, size);
|
|
660
|
+
if (!(px.width > 0 && px.height > 0) || px.data.length !== px.width * px.height * 4) throw new (0, _chunkZEYMKDYScjs.StickerError)("load_failed", `The art for "${ref}" came back empty or the wrong size.`);
|
|
661
|
+
return { ...px, tintable: d.tintable };
|
|
662
|
+
})();
|
|
663
|
+
this.entries.set(ref, { status: "loading", promise });
|
|
664
|
+
return promise.then(
|
|
665
|
+
(art) => {
|
|
666
|
+
this.entries.set(ref, { status: "ready", art });
|
|
667
|
+
return art;
|
|
668
|
+
},
|
|
669
|
+
(err) => {
|
|
670
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
671
|
+
this.entries.set(ref, { status: "failed", error: message });
|
|
672
|
+
throw err;
|
|
673
|
+
}
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
/** Forgets every load (a new provider). */
|
|
677
|
+
clear() {
|
|
678
|
+
this.entries.clear();
|
|
679
|
+
}
|
|
680
|
+
}, _class4);
|
|
681
|
+
function sampleArt(art, x, y, out) {
|
|
682
|
+
const { width: w, height: h, data } = art;
|
|
683
|
+
const fx = x - 0.5;
|
|
684
|
+
const fy = y - 0.5;
|
|
685
|
+
const x0 = Math.floor(fx);
|
|
686
|
+
const y0 = Math.floor(fy);
|
|
687
|
+
const tx = fx - x0;
|
|
688
|
+
const ty = fy - y0;
|
|
689
|
+
let r = 0;
|
|
690
|
+
let g = 0;
|
|
691
|
+
let b = 0;
|
|
692
|
+
let a = 0;
|
|
693
|
+
for (let k = 0; k < 4; k++) {
|
|
694
|
+
const xx = x0 + (k & 1);
|
|
695
|
+
const yy = y0 + (k >> 1);
|
|
696
|
+
if (xx < 0 || yy < 0 || xx >= w || yy >= h) continue;
|
|
697
|
+
const wgt = (k & 1 ? tx : 1 - tx) * (k >> 1 ? ty : 1 - ty);
|
|
698
|
+
const i = (yy * w + xx) * 4;
|
|
699
|
+
const al = data[i + 3] * wgt;
|
|
700
|
+
r += data[i] * al;
|
|
701
|
+
g += data[i + 1] * al;
|
|
702
|
+
b += data[i + 2] * al;
|
|
703
|
+
a += al;
|
|
704
|
+
}
|
|
705
|
+
out[0] = a > 0 ? r / a / 255 : 0;
|
|
706
|
+
out[1] = a > 0 ? g / a / 255 : 0;
|
|
707
|
+
out[2] = a > 0 ? b / a / 255 : 0;
|
|
708
|
+
out[3] = a / 255;
|
|
709
|
+
return out;
|
|
710
|
+
}
|
|
711
|
+
|
|
589
712
|
// src/paint-editor/stickers.ts
|
|
590
|
-
var
|
|
591
|
-
var DEFAULT_STICKER = { stamps: ["star"], density: 0.4, sizeJitter: 0.4, rotationJitter: 1, scatter: 0.5, colorJitter: 0.2 };
|
|
713
|
+
var MAX_STICKER_STAMPS = 16;
|
|
714
|
+
var DEFAULT_STICKER = { stamps: ["editor:star"], density: 0.4, sizeJitter: 0.4, rotationJitter: 1, scatter: 0.5, colorJitter: 0.2 };
|
|
592
715
|
var unit2 = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
|
|
593
716
|
function normalizeStickerSettings(raw = {}, base = DEFAULT_STICKER) {
|
|
594
|
-
const
|
|
717
|
+
const refs = (list) => list.flatMap((s) => {
|
|
718
|
+
try {
|
|
719
|
+
return [_chunkZEYMKDYScjs.normalizeStickerRef.call(void 0, s)];
|
|
720
|
+
} catch (e3) {
|
|
721
|
+
return [];
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
const stamps = Array.isArray(raw.stamps) ? refs(raw.stamps) : refs(base.stamps);
|
|
595
725
|
return {
|
|
596
|
-
stamps: stamps.length ? [...new Set(stamps)] :
|
|
726
|
+
stamps: stamps.length ? [...new Set(stamps)].slice(0, MAX_STICKER_STAMPS) : refs(base.stamps.length ? base.stamps : DEFAULT_STICKER.stamps),
|
|
597
727
|
density: unit2(raw.density, base.density),
|
|
598
728
|
sizeJitter: unit2(raw.sizeJitter, base.sizeJitter),
|
|
599
729
|
rotationJitter: unit2(raw.rotationJitter, base.rotationJitter),
|
|
@@ -601,59 +731,6 @@ function normalizeStickerSettings(raw = {}, base = DEFAULT_STICKER) {
|
|
|
601
731
|
colorJitter: unit2(raw.colorJitter, base.colorJitter)
|
|
602
732
|
};
|
|
603
733
|
}
|
|
604
|
-
function stampCoverage(kind, u, v, t) {
|
|
605
|
-
const r = Math.hypot(u, v);
|
|
606
|
-
const a = Math.atan2(v, u);
|
|
607
|
-
const edge = (d) => Math.min(1, Math.max(0, d * 24 + 0.5));
|
|
608
|
-
switch (kind) {
|
|
609
|
-
case "dot":
|
|
610
|
-
return edge(0.95 - r);
|
|
611
|
-
case "ring":
|
|
612
|
-
return edge(Math.min(0.95 - r, r - 0.6));
|
|
613
|
-
case "star": {
|
|
614
|
-
const f = (a + Math.PI / 2) * 5 / (2 * Math.PI) % 1;
|
|
615
|
-
const notch = Math.min(f < 0 ? f + 1 : f, 1 - (f < 0 ? f + 1 : f)) * 2;
|
|
616
|
-
return edge(0.95 - 0.55 * notch - r);
|
|
617
|
-
}
|
|
618
|
-
case "sparkle": {
|
|
619
|
-
const q = Math.pow(Math.abs(u) / 0.95, 0.6) + Math.pow(Math.abs(v) / 0.95, 0.6);
|
|
620
|
-
return edge((1 - q) * 0.4);
|
|
621
|
-
}
|
|
622
|
-
case "heart": {
|
|
623
|
-
const x = u * 1.1;
|
|
624
|
-
const y = -v * 1.1 + 0.15;
|
|
625
|
-
const q = x * x + y * y - 0.55;
|
|
626
|
-
return edge(-(q * q * q - x * x * y * y * y) * 3);
|
|
627
|
-
}
|
|
628
|
-
case "leaf": {
|
|
629
|
-
const w = 0.42 * Math.sqrt(Math.max(0, 1 - u * u));
|
|
630
|
-
const inside = edge(w - Math.abs(v + 0.15 * u * u));
|
|
631
|
-
const rib = Math.abs(v + 0.15 * u * u) < 0.03 && Math.abs(u) < 0.85 ? 0.65 : 1;
|
|
632
|
-
return inside * rib;
|
|
633
|
-
}
|
|
634
|
-
case "flower": {
|
|
635
|
-
const petals = 0.6 + 0.35 * Math.abs(Math.cos(2.5 * a));
|
|
636
|
-
const body = edge(petals - r);
|
|
637
|
-
return r < 0.22 ? Math.max(body, 1) * 0.85 : body;
|
|
638
|
-
}
|
|
639
|
-
case "confetti": {
|
|
640
|
-
return edge(Math.min(0.9 - Math.abs(u), 0.35 - Math.abs(v)));
|
|
641
|
-
}
|
|
642
|
-
case "splat": {
|
|
643
|
-
let rr = 0.55;
|
|
644
|
-
for (let k = 1; k <= 3; k++) rr += 0.08 * Math.sin(a * (k + 2) + _chunkPQ3H2AANcjs.hash2.call(void 0, k, 1, t) * 6.28) / k;
|
|
645
|
-
let c = edge(rr - r);
|
|
646
|
-
for (let k = 0; k < 4; k++) {
|
|
647
|
-
const ang = _chunkPQ3H2AANcjs.hash2.call(void 0, k, 7, t) * Math.PI * 2;
|
|
648
|
-
const dist = 0.72 + 0.2 * _chunkPQ3H2AANcjs.hash2.call(void 0, k, 9, t);
|
|
649
|
-
const dx = u - Math.cos(ang) * dist;
|
|
650
|
-
const dy = v - Math.sin(ang) * dist;
|
|
651
|
-
c = Math.max(c, edge(0.08 + 0.06 * _chunkPQ3H2AANcjs.hash2.call(void 0, k, 11, t) - Math.hypot(dx, dy)));
|
|
652
|
-
}
|
|
653
|
-
return c;
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
734
|
function hexRgb(hex) {
|
|
658
735
|
const n = parseInt(hex.slice(1, 7), 16);
|
|
659
736
|
return [(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255];
|
|
@@ -664,7 +741,22 @@ function stickerRect(s) {
|
|
|
664
741
|
const y0 = Math.floor(s.y - r);
|
|
665
742
|
return { x: x0, y: y0, width: Math.ceil(s.x + r) - x0, height: Math.ceil(s.y + r) - y0 };
|
|
666
743
|
}
|
|
667
|
-
function
|
|
744
|
+
function stickerStamp(s) {
|
|
745
|
+
if (s.ref) {
|
|
746
|
+
try {
|
|
747
|
+
return _chunkZEYMKDYScjs.editorStampOf.call(void 0, s.ref);
|
|
748
|
+
} catch (e4) {
|
|
749
|
+
return null;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return s.stamp && _chunkZEYMKDYScjs.STAMP_KINDS.includes(s.stamp) ? s.stamp : null;
|
|
753
|
+
}
|
|
754
|
+
function drawSticker(medium, s, art) {
|
|
755
|
+
const kind = stickerStamp(s);
|
|
756
|
+
if (!kind) {
|
|
757
|
+
const a2 = _optionalChain([art, 'optionalCall', _11 => _11(s.ref)]);
|
|
758
|
+
return a2 ? drawArtSticker(medium, s, a2) : stickerRect(s);
|
|
759
|
+
}
|
|
668
760
|
const rect = stickerRect(s);
|
|
669
761
|
const n = rect.width * rect.height;
|
|
670
762
|
const cov = new Float32Array(n);
|
|
@@ -682,11 +774,11 @@ function drawSticker(medium, s) {
|
|
|
682
774
|
const v = (-dx * sa + dy * ca) / rad;
|
|
683
775
|
if (u < -1.05 || u > 1.05 || v < -1.05 || v > 1.05) continue;
|
|
684
776
|
let c = 0;
|
|
685
|
-
for (let k = 0; k < 4; k++) c += stampCoverage(
|
|
777
|
+
for (let k = 0; k < 4; k++) c += _chunkZEYMKDYScjs.stampCoverage.call(void 0, kind, u + ((k & 1) - 0.5) / rad / 2, v + ((k >> 1) - 0.5) / rad / 2, s.seed);
|
|
686
778
|
c /= 4;
|
|
687
779
|
if (c <= 0) continue;
|
|
688
780
|
cov[p] = c;
|
|
689
|
-
const shade = 1 + 0.12 * (-(u + v) / 2) + 0.06 * (
|
|
781
|
+
const shade = 1 + 0.12 * (-(u + v) / 2) + 0.06 * (_chunk3K6HWEXZcjs.hash2.call(void 0, px, rect.y + yy, s.seed) - 0.5);
|
|
690
782
|
field[p * 3] = Math.min(1, Math.max(0, r * shade));
|
|
691
783
|
field[p * 3 + 1] = Math.min(1, Math.max(0, g * shade));
|
|
692
784
|
field[p * 3 + 2] = Math.min(1, Math.max(0, b * shade));
|
|
@@ -695,11 +787,40 @@ function drawSticker(medium, s) {
|
|
|
695
787
|
medium.deposit(rect, cov, s.opacity, [r, g, b], null, field);
|
|
696
788
|
return rect;
|
|
697
789
|
}
|
|
790
|
+
function drawArtSticker(medium, s, art) {
|
|
791
|
+
const rect = stickerRect(s);
|
|
792
|
+
const n = rect.width * rect.height;
|
|
793
|
+
const cov = new Float32Array(n);
|
|
794
|
+
const field = new Float32Array(n * 3);
|
|
795
|
+
const a = s.rotation * Math.PI / 180;
|
|
796
|
+
const ca = Math.cos(a);
|
|
797
|
+
const sa = Math.sin(a);
|
|
798
|
+
const scale = Math.max(art.width, art.height) / s.size;
|
|
799
|
+
const [r, g, b] = hexRgb(s.color);
|
|
800
|
+
const px = [0, 0, 0, 0];
|
|
801
|
+
for (let yy = 0, p = 0; yy < rect.height; yy++) {
|
|
802
|
+
for (let xx = 0; xx < rect.width; xx++, p++) {
|
|
803
|
+
const dx = rect.x + xx + 0.5 - s.x;
|
|
804
|
+
const dy = rect.y + yy + 0.5 - s.y;
|
|
805
|
+
const ax = (dx * ca + dy * sa) * scale + art.width / 2;
|
|
806
|
+
const ay = (-dx * sa + dy * ca) * scale + art.height / 2;
|
|
807
|
+
if (ax < -1 || ay < -1 || ax > art.width + 1 || ay > art.height + 1) continue;
|
|
808
|
+
sampleArt(art, ax, ay, px);
|
|
809
|
+
if (!(px[3] > 0)) continue;
|
|
810
|
+
cov[p] = px[3];
|
|
811
|
+
field[p * 3] = art.tintable ? r : px[0];
|
|
812
|
+
field[p * 3 + 1] = art.tintable ? g : px[1];
|
|
813
|
+
field[p * 3 + 2] = art.tintable ? b : px[2];
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
medium.deposit(rect, cov, s.opacity, [r, g, b], null, field);
|
|
817
|
+
return rect;
|
|
818
|
+
}
|
|
698
819
|
function jitterColor(hex, amount, seed, i) {
|
|
699
820
|
const [r, g, b] = hexRgb(hex);
|
|
700
821
|
const lch = _chunk7AHBW2CQcjs.oklabToOklch.call(void 0, _chunk7AHBW2CQcjs.rgbToOklab.call(void 0, { r, g, b, a: 1 }));
|
|
701
|
-
const l = Math.min(1, Math.max(0, lch.l + (
|
|
702
|
-
const h = lch.h + (
|
|
822
|
+
const l = Math.min(1, Math.max(0, lch.l + (_chunk3K6HWEXZcjs.rand01.call(void 0, seed, i, 61) - 0.5) * amount * 0.3));
|
|
823
|
+
const h = lch.h + (_chunk3K6HWEXZcjs.rand01.call(void 0, seed, i, 63) - 0.5) * amount * 80;
|
|
703
824
|
const at = (c) => _chunk7AHBW2CQcjs.oklabToRgb.call(void 0, _chunk7AHBW2CQcjs.oklchToOklab.call(void 0, { l, c, h, alpha: 1 }));
|
|
704
825
|
const inGamut = (o) => [o.r, o.g, o.b].every((v) => v >= -1e-4 && v <= 1 + 1e-4);
|
|
705
826
|
let out = at(lch.c);
|
|
@@ -715,8 +836,8 @@ function jitterColor(hex, amount, seed, i) {
|
|
|
715
836
|
}
|
|
716
837
|
return "#" + [out.r, out.g, out.b].map((c) => Math.round(Math.min(1, Math.max(0, c)) * 255).toString(16).padStart(2, "0")).join("");
|
|
717
838
|
}
|
|
718
|
-
var StickerSpray = (
|
|
719
|
-
constructor(init) {;
|
|
839
|
+
var StickerSpray = (_class5 = class {
|
|
840
|
+
constructor(init) {;_class5.prototype.__init20.call(this);_class5.prototype.__init21.call(this);_class5.prototype.__init22.call(this);_class5.prototype.__init23.call(this);_class5.prototype.__init24.call(this);
|
|
720
841
|
this.init = init;
|
|
721
842
|
const b = init.brush;
|
|
722
843
|
this.smoother = new PenSmoother(b.tip.smoothing, b.pressureSmoothing);
|
|
@@ -724,18 +845,20 @@ var StickerSpray = (_class4 = class {
|
|
|
724
845
|
const spacing = Math.max(0.05, 1 / Math.max(0.05, b.sticker.density * 4));
|
|
725
846
|
const walk = { ...b, tip: { ...b.tip, spacing }, dynamics: { ...b.dynamics, scatter: 0, sizeJitter: 0, angleJitter: 0 } };
|
|
726
847
|
this.walkers = this.copies.map((c, i) => new PenDabWalker(walk, init.seed + i * 7919 | 0, c.linear));
|
|
727
|
-
this.medium = new (0,
|
|
848
|
+
this.medium = new (0, _chunkI7NJPHWVcjs.TileMedium)(init.target, {});
|
|
728
849
|
this.next = init.nextId;
|
|
729
850
|
}
|
|
730
851
|
|
|
731
|
-
|
|
732
|
-
|
|
852
|
+
__init20() {this.dabCount = 0}
|
|
853
|
+
__init21() {this.stickers = []}
|
|
854
|
+
/** Refs the spray picked but could not draw because their art had not loaded. */
|
|
855
|
+
__init22() {this.skipped = /* @__PURE__ */ new Set()}
|
|
733
856
|
|
|
734
857
|
|
|
735
858
|
|
|
736
859
|
|
|
737
|
-
|
|
738
|
-
|
|
860
|
+
__init23() {this.lastRaw = null}
|
|
861
|
+
__init24() {this.lastFed = null}
|
|
739
862
|
|
|
740
863
|
push(points) {
|
|
741
864
|
const rects = [];
|
|
@@ -767,28 +890,36 @@ var StickerSpray = (_class4 = class {
|
|
|
767
890
|
const st = this.init.brush.sticker;
|
|
768
891
|
const i = this.next;
|
|
769
892
|
const seed = this.init.seed;
|
|
770
|
-
const size = d.radius * 2 * (1 - st.sizeJitter * 0.7 *
|
|
893
|
+
const size = d.radius * 2 * (1 - st.sizeJitter * 0.7 * _chunk3K6HWEXZcjs.rand01.call(void 0, seed, i, 51));
|
|
771
894
|
const off = st.scatter * d.radius * 2;
|
|
772
|
-
const a =
|
|
773
|
-
const dist =
|
|
895
|
+
const a = _chunk3K6HWEXZcjs.rand01.call(void 0, seed, i, 53) * Math.PI * 2;
|
|
896
|
+
const dist = _chunk3K6HWEXZcjs.rand01.call(void 0, seed, i, 55) * off;
|
|
774
897
|
const base = this.colorAt(d, Math.cos(a) * dist, Math.sin(a) * dist);
|
|
775
898
|
if (!(base.alpha > 0)) {
|
|
776
899
|
this.next++;
|
|
777
900
|
return;
|
|
778
901
|
}
|
|
902
|
+
const ref = _nullishCoalesce(st.stamps[Math.floor(_chunk3K6HWEXZcjs.rand01.call(void 0, seed, i, 57) * st.stamps.length)], () => ( "editor:dot"));
|
|
903
|
+
const stamp = stickerStamp({ ref });
|
|
904
|
+
if (!stamp && !_optionalChain([this, 'access', _12 => _12.init, 'access', _13 => _13.art, 'optionalCall', _14 => _14(ref)])) {
|
|
905
|
+
this.skipped.add(ref);
|
|
906
|
+
this.next++;
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
779
909
|
const sticker = {
|
|
780
910
|
id: `st${this.next++}`,
|
|
781
|
-
|
|
911
|
+
ref,
|
|
912
|
+
...stamp ? { stamp } : {},
|
|
782
913
|
x: Math.round((d.x + Math.cos(a) * dist) * 100) / 100,
|
|
783
914
|
y: Math.round((d.y + Math.sin(a) * dist) * 100) / 100,
|
|
784
915
|
size: Math.max(2, Math.round(size * 10) / 10),
|
|
785
|
-
rotation: Math.round((-d.angle * 180 / Math.PI + (
|
|
916
|
+
rotation: Math.round((-d.angle * 180 / Math.PI + (_chunk3K6HWEXZcjs.rand01.call(void 0, seed, i, 59) * 2 - 1) * 180 * st.rotationJitter) * 10) / 10,
|
|
786
917
|
color: st.colorJitter > 0 ? jitterColor(base.color, st.colorJitter, seed, i) : base.color,
|
|
787
918
|
opacity: Math.round(Math.min(1, d.opacity * this.init.brush.tip.opacity * base.alpha) * 1e3) / 1e3,
|
|
788
|
-
seed: Math.floor(
|
|
919
|
+
seed: Math.floor(_chunk3K6HWEXZcjs.rand01.call(void 0, seed, i, 65) * 1e9)
|
|
789
920
|
};
|
|
790
921
|
this.stickers.push(sticker);
|
|
791
|
-
rects.push(drawSticker(this.medium, sticker));
|
|
922
|
+
rects.push(drawSticker(this.medium, sticker, this.init.art));
|
|
792
923
|
this.dabCount++;
|
|
793
924
|
}
|
|
794
925
|
|
|
@@ -802,21 +933,29 @@ var StickerSpray = (_class4 = class {
|
|
|
802
933
|
}
|
|
803
934
|
const g = this.init.paint;
|
|
804
935
|
if (!g) return { color: this.init.color, alpha: 1 };
|
|
805
|
-
this.sampler ??= new (0,
|
|
936
|
+
this.sampler ??= new (0, _chunkI7NJPHWVcjs.PaintGradientSampler)(g, this.init.seed);
|
|
806
937
|
const s = g.map.by === "across-tip" ? this.sampler.sample(((dx * Math.sin(d.direction) + dy * Math.cos(d.direction)) / Math.max(0.5, d.radius) + 1) / 2) : this.sampler.dab(d);
|
|
807
938
|
return { color: "#" + s.rgb.map((c) => Math.round(Math.min(1, Math.max(0, c)) * 255).toString(16).padStart(2, "0")).join(""), alpha: s.alpha };
|
|
808
939
|
}
|
|
809
|
-
},
|
|
810
|
-
function renderStickers(stickers, target) {
|
|
811
|
-
const medium = new (0,
|
|
812
|
-
for (const s of stickers) drawSticker(medium, s);
|
|
940
|
+
}, _class5);
|
|
941
|
+
function renderStickers(stickers, target, art) {
|
|
942
|
+
const medium = new (0, _chunkI7NJPHWVcjs.TileMedium)(target, {});
|
|
943
|
+
for (const s of stickers) drawSticker(medium, s, art);
|
|
813
944
|
}
|
|
814
945
|
function normalizeStickerUpdate(u) {
|
|
815
946
|
const out = {};
|
|
947
|
+
if (u.ref !== void 0 && u.stamp !== void 0) throw new Error("Give ref or stamp, not both (stamp is the older name for an editor stamp).");
|
|
816
948
|
if (u.stamp !== void 0) {
|
|
817
|
-
if (!STAMP_KINDS.includes(u.stamp)) throw new Error(`stamp ${JSON.stringify(u.stamp)} is not a stamp; use ${STAMP_KINDS.join(", ")}.`);
|
|
949
|
+
if (!_chunkZEYMKDYScjs.STAMP_KINDS.includes(u.stamp)) throw new Error(`stamp ${JSON.stringify(u.stamp)} is not a stamp; use ${_chunkZEYMKDYScjs.STAMP_KINDS.join(", ")}, or ref for any sticker (find_stickers).`);
|
|
950
|
+
out.ref = `editor:${u.stamp}`;
|
|
818
951
|
out.stamp = u.stamp;
|
|
819
952
|
}
|
|
953
|
+
if (u.ref !== void 0) {
|
|
954
|
+
out.ref = _chunkZEYMKDYScjs.normalizeStickerRef.call(void 0, u.ref);
|
|
955
|
+
const stamp = stickerStamp({ ref: out.ref });
|
|
956
|
+
if (stamp) out.stamp = stamp;
|
|
957
|
+
else out.stamp = void 0;
|
|
958
|
+
}
|
|
820
959
|
for (const k of ["x", "y"]) if (u[k] !== void 0) {
|
|
821
960
|
if (!Number.isFinite(u[k])) throw new Error(`${k} must be a number of pixels.`);
|
|
822
961
|
out[k] = u[k];
|
|
@@ -839,7 +978,7 @@ function normalizeStickerUpdate(u) {
|
|
|
839
978
|
}
|
|
840
979
|
return out;
|
|
841
980
|
}
|
|
842
|
-
function stickerSurface(stickers, base, dirty) {
|
|
981
|
+
function stickerSurface(stickers, base, dirty, art) {
|
|
843
982
|
const only = base && dirty ? new Set(dirty.flatMap((r) => _chunk474IQG74cjs.tilesInRect.call(void 0, r).map(({ tx, ty }) => _chunk474IQG74cjs.tileKey.call(void 0, tx, ty)))) : null;
|
|
844
983
|
const live = /* @__PURE__ */ new Map();
|
|
845
984
|
let scratch = null;
|
|
@@ -857,7 +996,7 @@ function stickerSurface(stickers, base, dirty) {
|
|
|
857
996
|
}
|
|
858
997
|
};
|
|
859
998
|
const reaches = (s) => !only || _chunk474IQG74cjs.tilesInRect.call(void 0, stickerRect(s)).some(({ tx, ty }) => only.has(_chunk474IQG74cjs.tileKey.call(void 0, tx, ty)));
|
|
860
|
-
renderStickers(stickers.filter(reaches), target);
|
|
999
|
+
renderStickers(stickers.filter(reaches), target, art);
|
|
861
1000
|
const tiles = /* @__PURE__ */ new Map();
|
|
862
1001
|
if (only && base) {
|
|
863
1002
|
for (const [k, t] of base.tiles) if (!only.has(k)) tiles.set(k, t);
|
|
@@ -868,7 +1007,7 @@ function stickerSurface(stickers, base, dirty) {
|
|
|
868
1007
|
}
|
|
869
1008
|
return new (0, _chunk474IQG74cjs.TiledSurface)(4, tiles, 0);
|
|
870
1009
|
}
|
|
871
|
-
function stickerAt(stickers, x, y) {
|
|
1010
|
+
function stickerAt(stickers, x, y, art) {
|
|
872
1011
|
for (let i = stickers.length - 1; i >= 0; i--) {
|
|
873
1012
|
const s = stickers[i];
|
|
874
1013
|
const rad = s.size / 2;
|
|
@@ -878,21 +1017,30 @@ function stickerAt(stickers, x, y) {
|
|
|
878
1017
|
const u = (dx * Math.cos(a) + dy * Math.sin(a)) / rad;
|
|
879
1018
|
const v = (-dx * Math.sin(a) + dy * Math.cos(a)) / rad;
|
|
880
1019
|
if (Math.abs(u) > 1.05 || Math.abs(v) > 1.05) continue;
|
|
881
|
-
if (s.size < 16
|
|
1020
|
+
if (s.size < 16) return s;
|
|
1021
|
+
const kind = stickerStamp(s);
|
|
1022
|
+
if (kind) {
|
|
1023
|
+
if (_chunkZEYMKDYScjs.stampCoverage.call(void 0, kind, u, v, s.seed) > 0.25) return s;
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
const pic = _optionalChain([art, 'optionalCall', _15 => _15(s.ref)]);
|
|
1027
|
+
if (!pic) return s;
|
|
1028
|
+
const scale = Math.max(pic.width, pic.height) / 2;
|
|
1029
|
+
if (sampleArt(pic, u * scale + pic.width / 2, v * scale + pic.height / 2, [0, 0, 0, 0])[3] > 0.25) return s;
|
|
882
1030
|
}
|
|
883
1031
|
return null;
|
|
884
1032
|
}
|
|
885
1033
|
|
|
886
1034
|
// src/paint-editor/procedural.ts
|
|
887
1035
|
var STEP_PX = 1.5;
|
|
888
|
-
var MarkStroke = (
|
|
889
|
-
constructor(brush, options) {;
|
|
1036
|
+
var MarkStroke = (_class6 = class {
|
|
1037
|
+
constructor(brush, options) {;_class6.prototype.__init25.call(this);_class6.prototype.__init26.call(this);_class6.prototype.__init27.call(this);_class6.prototype.__init28.call(this);_class6.prototype.__init29.call(this);_class6.prototype.__init30.call(this);_class6.prototype.__init31.call(this);_class6.prototype.__init32.call(this);
|
|
890
1038
|
this.brush = brush;
|
|
891
1039
|
this.options = options;
|
|
892
|
-
this.sampler = options.paint ? new (0,
|
|
893
|
-
this.tipTable = _optionalChain([this, 'access',
|
|
1040
|
+
this.sampler = options.paint ? new (0, _chunkI7NJPHWVcjs.PaintGradientSampler)(options.paint, _nullishCoalesce(options.seed, () => ( 0))) : null;
|
|
1041
|
+
this.tipTable = _optionalChain([this, 'access', _16 => _16.sampler, 'optionalAccess', _17 => _17.acrossTip]) ? this.sampler.tipTable(_chunkI7NJPHWVcjs.TIP_GRADIENT_STEPS) : null;
|
|
894
1042
|
this.smoother = new PenSmoother(brush.tip.smoothing, brush.pressureSmoothing);
|
|
895
|
-
this.copies = _optionalChain([options, 'access',
|
|
1043
|
+
this.copies = _optionalChain([options, 'access', _18 => _18.copies, 'optionalAccess', _19 => _19.length]) ? options.copies : [IDENTITY_COPY];
|
|
896
1044
|
this.seed = _nullishCoalesce(options.seed, () => ( 0));
|
|
897
1045
|
const fine = { ...brush, tip: { ...brush.tip, spacing: Math.max(0.01, Math.min(0.25, STEP_PX / Math.max(1, brush.tip.size))) } };
|
|
898
1046
|
this.walkers = this.copies.map((c, i) => new PenDabWalker(fine, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear));
|
|
@@ -900,22 +1048,22 @@ var MarkStroke = (_class5 = class {
|
|
|
900
1048
|
}
|
|
901
1049
|
|
|
902
1050
|
|
|
903
|
-
|
|
904
|
-
|
|
1051
|
+
__init25() {this.coverage = new (0, _chunkI7NJPHWVcjs.CoverageMap)()}
|
|
1052
|
+
__init26() {this.dabCount = 0}
|
|
905
1053
|
|
|
906
1054
|
|
|
907
1055
|
|
|
908
1056
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1057
|
+
__init27() {this.buf = new Float32Array(0)}
|
|
1058
|
+
__init28() {this.field = new Float32Array(0)}
|
|
1059
|
+
__init29() {this.lastRaw = null}
|
|
1060
|
+
__init30() {this.lastFed = null}
|
|
913
1061
|
|
|
914
1062
|
|
|
915
1063
|
|
|
916
1064
|
/** The pen dab the marks being made belong to, and its gradient colour. */
|
|
917
|
-
|
|
918
|
-
|
|
1065
|
+
__init31() {this.pen = null}
|
|
1066
|
+
__init32() {this.penColor = { rgb: [0, 0, 0], alpha: 1 }}
|
|
919
1067
|
push(points) {
|
|
920
1068
|
const rects = [];
|
|
921
1069
|
for (const raw of points) {
|
|
@@ -961,26 +1109,73 @@ var MarkStroke = (_class5 = class {
|
|
|
961
1109
|
if (!(r > 0.05) || !(alpha > 0)) return;
|
|
962
1110
|
const dab = { x, y, radius: Math.max(0.5, r), alpha: Math.min(1, alpha), opacity: Math.min(1, opacity), angle: 0, roundness: 1 };
|
|
963
1111
|
const hardness = this.brush.tip.hardness;
|
|
964
|
-
const rect =
|
|
1112
|
+
const rect = _chunkI7NJPHWVcjs.dabRect.call(void 0, dab, hardness);
|
|
965
1113
|
const n = rect.width * rect.height;
|
|
966
1114
|
if (n <= 0) return;
|
|
1115
|
+
const vals = this.scratch(n);
|
|
1116
|
+
_chunkI7NJPHWVcjs.rasterizeDab.call(void 0, dab, hardness, rect, vals);
|
|
1117
|
+
this.lay(rect, vals, dab.opacity, pressure, x, y, rects);
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Stamps a textured mark: `kind` from the sticker stamps over a square of half-size `r`, turned
|
|
1121
|
+
* `rotation` radians clockwise, with flow `alpha` towards `opacity`. Small marks are supersampled.
|
|
1122
|
+
*/
|
|
1123
|
+
stamp(x, y, r, kind, rotation, seed, alpha, opacity, pressure, rects) {
|
|
1124
|
+
if (!(r > 0.05) || !(alpha > 0)) return;
|
|
1125
|
+
const reach = Math.max(0.5, r) * Math.SQRT2 + 1;
|
|
1126
|
+
const rect = { x: Math.floor(x - reach), y: Math.floor(y - reach), width: 0, height: 0 };
|
|
1127
|
+
rect.width = Math.ceil(x + reach) - rect.x;
|
|
1128
|
+
rect.height = Math.ceil(y + reach) - rect.y;
|
|
1129
|
+
const n = rect.width * rect.height;
|
|
1130
|
+
const vals = this.scratch(n);
|
|
1131
|
+
const ss = r < 10 ? 3 : 1;
|
|
1132
|
+
const c = Math.cos(rotation);
|
|
1133
|
+
const s = Math.sin(rotation);
|
|
1134
|
+
const inv = 1 / Math.max(0.5, r);
|
|
1135
|
+
const a = Math.min(1, alpha);
|
|
1136
|
+
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
1137
|
+
for (let xx = 0; xx < rect.width; xx++, k++) {
|
|
1138
|
+
let sum = 0;
|
|
1139
|
+
for (let sy = 0; sy < ss; sy++) {
|
|
1140
|
+
for (let sx = 0; sx < ss; sx++) {
|
|
1141
|
+
const dx = rect.x + xx + (sx + 0.5) / ss - x;
|
|
1142
|
+
const dy = rect.y + yy + (sy + 0.5) / ss - y;
|
|
1143
|
+
sum += _chunkZEYMKDYScjs.stampCoverage.call(void 0, kind, (dx * c + dy * s) * inv, (dy * c - dx * s) * inv, seed);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
vals[k] = sum / (ss * ss) * a;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
this.lay(rect, vals, Math.min(1, opacity), pressure, x, y, rects);
|
|
1150
|
+
}
|
|
1151
|
+
/** A scratch buffer of `n` values (reused; valid until the next mark). */
|
|
1152
|
+
scratch(n) {
|
|
967
1153
|
if (this.buf.length < n) this.buf = new Float32Array(n);
|
|
968
1154
|
const vals = this.buf.subarray(0, n);
|
|
969
|
-
|
|
1155
|
+
vals.fill(0);
|
|
1156
|
+
return vals;
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Lays coverage `vals` over `rect` towards `opacity`: paper grain, then effect paint or the
|
|
1160
|
+
* colour of a mark at (x, y) (gradient paint), into the stroke's coverage.
|
|
1161
|
+
*/
|
|
1162
|
+
lay(rect, vals, opacity, pressure, x, y, rects) {
|
|
1163
|
+
const n = rect.width * rect.height;
|
|
1164
|
+
if (n <= 0) return;
|
|
970
1165
|
const grain = this.options.grain;
|
|
971
1166
|
if (this.depth > 0 && grain) {
|
|
972
1167
|
for (let yy = 0, k = 0; yy < rect.height; yy++)
|
|
973
|
-
for (let xx = 0; xx < rect.width; xx++, k++) if (vals[k] > 0) vals[k] *=
|
|
1168
|
+
for (let xx = 0; xx < rect.width; xx++, k++) if (vals[k] > 0) vals[k] *= _chunkI7NJPHWVcjs.grainCatch.call(void 0, grain.at(rect.x + xx + 0.5, rect.y + yy + 0.5), this.depth, pressure);
|
|
974
1169
|
}
|
|
975
1170
|
if (this.options.effect) {
|
|
976
1171
|
if (this.field.length < n * 3) this.field = new Float32Array(n * 3);
|
|
977
1172
|
const field = this.field.subarray(0, n * 3);
|
|
978
1173
|
sampleEffectField(this.options.effect, rect, vals, field, this.pen);
|
|
979
|
-
this.coverage.accumulate(rect, vals,
|
|
1174
|
+
this.coverage.accumulate(rect, vals, opacity, null, field);
|
|
980
1175
|
} else {
|
|
981
1176
|
const color = this.markColor(x, y);
|
|
982
1177
|
if (color && color.alpha < 1) for (let k = 0; k < n; k++) vals[k] *= color.alpha;
|
|
983
|
-
this.coverage.accumulate(rect, vals,
|
|
1178
|
+
this.coverage.accumulate(rect, vals, opacity, color ? color.rgb : null);
|
|
984
1179
|
}
|
|
985
1180
|
rects.push(rect);
|
|
986
1181
|
this.dabCount++;
|
|
@@ -992,15 +1187,42 @@ var MarkStroke = (_class5 = class {
|
|
|
992
1187
|
const n = Math.max(1, Math.ceil(len / step));
|
|
993
1188
|
for (let i = 1; i <= n; i++) this.mark(x0 + (x1 - x0) * i / n, y0 + (y1 - y0) * i / n, r, alpha, opacity, pressure, rects);
|
|
994
1189
|
}
|
|
995
|
-
},
|
|
996
|
-
var PARTICLE_KINDS = ["string", "spring", "orbit", "flow"];
|
|
997
|
-
var PARTICLE_RENDERS = ["dot", "line", "sequence"];
|
|
998
|
-
var
|
|
1190
|
+
}, _class6);
|
|
1191
|
+
var PARTICLE_KINDS = ["string", "spring", "orbit", "flow", "elastic", "fuzzy"];
|
|
1192
|
+
var PARTICLE_RENDERS = ["dot", "line", "sequence", "ribbon"];
|
|
1193
|
+
var RIBBON_PAIRS = ["adjacent", "first-last"];
|
|
1194
|
+
var DOT_TEXTURE_ORDERS = ["sequence", "random"];
|
|
1195
|
+
var DOT_ROTATIONS = ["follow", "random", "fixed"];
|
|
1196
|
+
var MAX_DOT_TEXTURES = 4;
|
|
1197
|
+
var DEFAULT_PARTICLE = {
|
|
1198
|
+
kind: "spring",
|
|
1199
|
+
render: "line",
|
|
1200
|
+
count: 12,
|
|
1201
|
+
size: 0.08,
|
|
1202
|
+
spread: 0.5,
|
|
1203
|
+
stiffness: 0.4,
|
|
1204
|
+
damping: 0.25,
|
|
1205
|
+
speed: 0.5,
|
|
1206
|
+
gravity: 0,
|
|
1207
|
+
life: 0.5,
|
|
1208
|
+
interval: 0.3,
|
|
1209
|
+
ribbonFill: 0.5,
|
|
1210
|
+
ribbonPairs: "adjacent",
|
|
1211
|
+
waveAmplitude: 0,
|
|
1212
|
+
waveLength: 60,
|
|
1213
|
+
waveSpeed: 0,
|
|
1214
|
+
wavePhaseJitter: 0,
|
|
1215
|
+
dotTextures: [],
|
|
1216
|
+
dotTextureOrder: "sequence",
|
|
1217
|
+
dotRotation: "random"
|
|
1218
|
+
};
|
|
999
1219
|
var unit3 = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
|
|
1220
|
+
var oneOf = (v, all, d) => all.includes(v) ? v : d;
|
|
1000
1221
|
function normalizeParticle(raw = {}, base = DEFAULT_PARTICLE) {
|
|
1222
|
+
const textures = Array.isArray(raw.dotTextures) ? raw.dotTextures.filter((t) => _chunkZEYMKDYScjs.STAMP_KINDS.includes(t)).slice(0, MAX_DOT_TEXTURES) : [..._nullishCoalesce(base.dotTextures, () => ( []))];
|
|
1001
1223
|
return {
|
|
1002
|
-
kind:
|
|
1003
|
-
render:
|
|
1224
|
+
kind: oneOf(raw.kind, PARTICLE_KINDS, base.kind),
|
|
1225
|
+
render: oneOf(raw.render, PARTICLE_RENDERS, base.render),
|
|
1004
1226
|
count: typeof raw.count === "number" && Number.isFinite(raw.count) ? Math.min(64, Math.max(1, Math.round(raw.count))) : base.count,
|
|
1005
1227
|
size: unit3(raw.size, base.size),
|
|
1006
1228
|
spread: unit3(raw.spread, base.spread),
|
|
@@ -1009,9 +1231,61 @@ function normalizeParticle(raw = {}, base = DEFAULT_PARTICLE) {
|
|
|
1009
1231
|
speed: unit3(raw.speed, base.speed),
|
|
1010
1232
|
gravity: typeof raw.gravity === "number" && Number.isFinite(raw.gravity) ? Math.min(1, Math.max(-1, raw.gravity)) : base.gravity,
|
|
1011
1233
|
life: unit3(raw.life, base.life),
|
|
1012
|
-
interval: unit3(raw.interval, base.interval)
|
|
1234
|
+
interval: unit3(raw.interval, base.interval),
|
|
1235
|
+
ribbonFill: unit3(raw.ribbonFill, _nullishCoalesce(base.ribbonFill, () => ( DEFAULT_PARTICLE.ribbonFill))),
|
|
1236
|
+
ribbonPairs: oneOf(raw.ribbonPairs, RIBBON_PAIRS, _nullishCoalesce(base.ribbonPairs, () => ( DEFAULT_PARTICLE.ribbonPairs))),
|
|
1237
|
+
waveAmplitude: unit3(raw.waveAmplitude, _nullishCoalesce(base.waveAmplitude, () => ( 0))),
|
|
1238
|
+
waveLength: typeof raw.waveLength === "number" && Number.isFinite(raw.waveLength) ? Math.min(2e3, Math.max(4, raw.waveLength)) : _nullishCoalesce(base.waveLength, () => ( DEFAULT_PARTICLE.waveLength)),
|
|
1239
|
+
waveSpeed: unit3(raw.waveSpeed, _nullishCoalesce(base.waveSpeed, () => ( 0))),
|
|
1240
|
+
wavePhaseJitter: unit3(raw.wavePhaseJitter, _nullishCoalesce(base.wavePhaseJitter, () => ( 0))),
|
|
1241
|
+
dotTextures: textures,
|
|
1242
|
+
dotTextureOrder: oneOf(raw.dotTextureOrder, DOT_TEXTURE_ORDERS, _nullishCoalesce(base.dotTextureOrder, () => ( DEFAULT_PARTICLE.dotTextureOrder))),
|
|
1243
|
+
dotRotation: oneOf(raw.dotRotation, DOT_ROTATIONS, _nullishCoalesce(base.dotRotation, () => ( DEFAULT_PARTICLE.dotRotation)))
|
|
1013
1244
|
};
|
|
1014
1245
|
}
|
|
1246
|
+
var FUZZY_AMPLITUDE = 0.12;
|
|
1247
|
+
var NOMINAL_MS_PER_PX = 2;
|
|
1248
|
+
var RIBBON_SUB = 4;
|
|
1249
|
+
function chainDamp(damp, k) {
|
|
1250
|
+
return Math.min(damp, 1 / (1 + 0.8 * Math.sqrt(Math.max(0, k))) ** 2);
|
|
1251
|
+
}
|
|
1252
|
+
function addPolygonArea(pts, rect, out, weight = 1) {
|
|
1253
|
+
const n = pts.length >> 1;
|
|
1254
|
+
if (n < 3) return;
|
|
1255
|
+
let y0 = Infinity;
|
|
1256
|
+
let y1 = -Infinity;
|
|
1257
|
+
for (let i = 1; i < pts.length; i += 2) {
|
|
1258
|
+
if (pts[i] < y0) y0 = pts[i];
|
|
1259
|
+
if (pts[i] > y1) y1 = pts[i];
|
|
1260
|
+
}
|
|
1261
|
+
const r0 = Math.max(0, Math.floor(y0) - rect.y);
|
|
1262
|
+
const r1 = Math.min(rect.height - 1, Math.floor(y1) - rect.y);
|
|
1263
|
+
const xs = [];
|
|
1264
|
+
const w = weight / RIBBON_SUB;
|
|
1265
|
+
for (let row = r0; row <= r1; row++) {
|
|
1266
|
+
const base = row * rect.width;
|
|
1267
|
+
for (let sub = 0; sub < RIBBON_SUB; sub++) {
|
|
1268
|
+
const y = rect.y + row + (sub + 0.5) / RIBBON_SUB;
|
|
1269
|
+
xs.length = 0;
|
|
1270
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
1271
|
+
const yi = pts[i * 2 + 1];
|
|
1272
|
+
const yj = pts[j * 2 + 1];
|
|
1273
|
+
if (yi <= y !== yj <= y) xs.push(pts[i * 2] + (y - yi) / (yj - yi) * (pts[j * 2] - pts[i * 2]));
|
|
1274
|
+
}
|
|
1275
|
+
if (xs.length < 2) continue;
|
|
1276
|
+
xs.sort((a, b) => a - b);
|
|
1277
|
+
for (let k = 0; k + 1 < xs.length; k += 2) {
|
|
1278
|
+
const a = Math.max(rect.x, xs[k]);
|
|
1279
|
+
const b = Math.min(rect.x + rect.width, xs[k + 1]);
|
|
1280
|
+
if (!(b > a)) continue;
|
|
1281
|
+
for (let px = Math.floor(a); px < b; px++) {
|
|
1282
|
+
const cover = Math.min(b, px + 1) - Math.max(a, px);
|
|
1283
|
+
if (cover > 0) out[base + px - rect.x] += cover * w;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1015
1289
|
function curl(x, y, seed) {
|
|
1016
1290
|
const n = (u, v) => {
|
|
1017
1291
|
const x0 = Math.floor(u);
|
|
@@ -1020,7 +1294,7 @@ function curl(x, y, seed) {
|
|
|
1020
1294
|
const fy = v - y0;
|
|
1021
1295
|
const sx = fx * fx * (3 - 2 * fx);
|
|
1022
1296
|
const sy = fy * fy * (3 - 2 * fy);
|
|
1023
|
-
const h = (a2, b2) =>
|
|
1297
|
+
const h = (a2, b2) => _chunk3K6HWEXZcjs.rand01.call(void 0, seed, a2 * 73856093 + b2 * 19349663, 41);
|
|
1024
1298
|
const a = h(x0, y0);
|
|
1025
1299
|
const b = h(x0 + 1, y0);
|
|
1026
1300
|
const c = h(x0, y0 + 1);
|
|
@@ -1030,36 +1304,85 @@ function curl(x, y, seed) {
|
|
|
1030
1304
|
const e = 0.01;
|
|
1031
1305
|
return [(n(x, y + e) - n(x, y - e)) / (2 * e), -(n(x + e, y) - n(x - e, y)) / (2 * e)];
|
|
1032
1306
|
}
|
|
1033
|
-
var ParticleStroke = (
|
|
1307
|
+
var ParticleStroke = (_class7 = class extends MarkStroke {
|
|
1034
1308
|
|
|
1309
|
+
/** Ribbon pairs per copy: particles in their order around the pen (non-flow kinds). */
|
|
1035
1310
|
|
|
1036
|
-
|
|
1311
|
+
|
|
1312
|
+
__init33() {this.spawn = 0}
|
|
1313
|
+
/** Textured dots drawn so far, per copy (sequence order, random picks). */
|
|
1314
|
+
|
|
1315
|
+
/** Ribbon fill: the area each pixel has had so far this stroke (telescoped into the coverage). */
|
|
1316
|
+
__init34() {this.filled = /* @__PURE__ */ new Map()}
|
|
1317
|
+
__init35() {this.pts = []}
|
|
1037
1318
|
constructor(brush, options) {
|
|
1038
|
-
super(brush, options);
|
|
1319
|
+
super(brush, options);_class7.prototype.__init33.call(this);_class7.prototype.__init34.call(this);_class7.prototype.__init35.call(this);;
|
|
1039
1320
|
this.s = brush.particle;
|
|
1040
1321
|
this.sets = this.copies.map(() => []);
|
|
1322
|
+
this.orders = this.copies.map(() => []);
|
|
1323
|
+
this.dots = this.copies.map(() => 0);
|
|
1324
|
+
}
|
|
1325
|
+
/** Strand kinds: a chain of masses behind each particle. */
|
|
1326
|
+
get strands() {
|
|
1327
|
+
return this.s.kind === "string" || this.s.kind === "elastic" || this.s.kind === "fuzzy";
|
|
1328
|
+
}
|
|
1329
|
+
newParticle(x, y, ox, oy, k, phase, i, copy) {
|
|
1330
|
+
const s = this.s;
|
|
1331
|
+
const fuzzy = s.kind === "fuzzy";
|
|
1332
|
+
const jitter = fuzzy ? 1 : s.wavePhaseJitter;
|
|
1333
|
+
return {
|
|
1334
|
+
x,
|
|
1335
|
+
y,
|
|
1336
|
+
vx: 0,
|
|
1337
|
+
vy: 0,
|
|
1338
|
+
ox,
|
|
1339
|
+
oy,
|
|
1340
|
+
k,
|
|
1341
|
+
phase,
|
|
1342
|
+
age: 0,
|
|
1343
|
+
run: 0,
|
|
1344
|
+
bead: 0,
|
|
1345
|
+
alive: true,
|
|
1346
|
+
wavePhase: jitter > 0 ? jitter * Math.PI * 2 * _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 43 + copy) : 0,
|
|
1347
|
+
waveScale: fuzzy ? 0.6 + 0.8 * _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 47 + copy) : 1,
|
|
1348
|
+
dx: x,
|
|
1349
|
+
dy: y,
|
|
1350
|
+
px: NaN,
|
|
1351
|
+
py: NaN,
|
|
1352
|
+
fade: 1
|
|
1353
|
+
};
|
|
1041
1354
|
}
|
|
1042
1355
|
init(copy, d) {
|
|
1043
1356
|
const s = this.s;
|
|
1044
1357
|
const list = this.sets[copy];
|
|
1045
1358
|
const size = Math.max(1, d.radius * 2);
|
|
1046
1359
|
for (let i = 0; i < (s.kind === "flow" ? 0 : s.count); i++) {
|
|
1047
|
-
const r =
|
|
1048
|
-
const a =
|
|
1360
|
+
const r = _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 3 + copy) * s.spread * size * 0.5;
|
|
1361
|
+
const a = _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 5 + copy) * Math.PI * 2;
|
|
1049
1362
|
const ox = Math.cos(a) * r;
|
|
1050
1363
|
const oy = Math.sin(a) * r;
|
|
1051
|
-
const p =
|
|
1052
|
-
if (
|
|
1364
|
+
const p = this.newParticle(d.x + ox, d.y + oy, ox, oy, 0.6 + 0.8 * _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 7), a, i, copy);
|
|
1365
|
+
if (this.strands) p.strand = Array.from({ length: 6 }, () => ({ x: d.x + ox, y: d.y + oy, vx: 0, vy: 0 }));
|
|
1053
1366
|
if (s.kind === "orbit") {
|
|
1054
1367
|
p.ox = Math.max(1, r + size * 0.15);
|
|
1055
1368
|
p.oy = 0;
|
|
1056
1369
|
}
|
|
1057
1370
|
list.push(p);
|
|
1058
1371
|
}
|
|
1372
|
+
this.orders[copy] = list.map((_, i) => i).sort((i, j) => list[i].phase - list[j].phase || i - j);
|
|
1373
|
+
}
|
|
1374
|
+
/** The sideways wave of particle `p` at pen dab `d` (px along the normal to the pen's direction). */
|
|
1375
|
+
wave(p, d, size) {
|
|
1376
|
+
const s = this.s;
|
|
1377
|
+
const amp = s.kind === "fuzzy" ? Math.max(FUZZY_AMPLITUDE, s.waveAmplitude) : s.waveAmplitude;
|
|
1378
|
+
if (!(amp > 0)) return 0;
|
|
1379
|
+
const ms = _nullishCoalesce(d.time, () => ( d.travel * NOMINAL_MS_PER_PX));
|
|
1380
|
+
const phase = 2 * Math.PI * d.travel / (s.waveLength * p.waveScale) - s.waveSpeed * 0.025 * ms + p.wavePhase;
|
|
1381
|
+
return amp * size * Math.sin(phase);
|
|
1059
1382
|
}
|
|
1060
1383
|
advance(copy, d, rects) {
|
|
1061
1384
|
const s = this.s;
|
|
1062
|
-
|
|
1385
|
+
let list = this.sets[copy];
|
|
1063
1386
|
if (d.index === 0 && !list.length) this.init(copy, d);
|
|
1064
1387
|
const size = Math.max(1, d.radius * 2);
|
|
1065
1388
|
const markR = Math.max(0.5, size * s.size / 2);
|
|
@@ -1068,22 +1391,22 @@ var ParticleStroke = (_class6 = class extends MarkStroke {
|
|
|
1068
1391
|
const g = s.gravity * 0.15;
|
|
1069
1392
|
const op = d.opacity;
|
|
1070
1393
|
const al = Math.max(0.05, d.alpha);
|
|
1394
|
+
const nx = Math.sin(d.direction);
|
|
1395
|
+
const ny = Math.cos(d.direction);
|
|
1071
1396
|
if (s.kind === "flow") {
|
|
1072
1397
|
this.spawn += s.count / 8;
|
|
1073
1398
|
while (this.spawn >= 1) {
|
|
1074
1399
|
this.spawn -= 1;
|
|
1075
1400
|
const i = this.dabCount + list.length * 31 + Math.floor(d.index);
|
|
1076
|
-
const a =
|
|
1077
|
-
const r =
|
|
1078
|
-
list.push(
|
|
1401
|
+
const a = _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 11 + copy) * Math.PI * 2;
|
|
1402
|
+
const r = _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 13 + copy) * s.spread * size * 0.5;
|
|
1403
|
+
list.push(this.newParticle(d.x + Math.cos(a) * r, d.y + Math.sin(a) * r, 0, 0, 1, a, i, copy));
|
|
1079
1404
|
}
|
|
1080
1405
|
}
|
|
1081
1406
|
const lifeSteps = 8 + 120 * s.life;
|
|
1082
1407
|
for (let i = 0; i < list.length; i++) {
|
|
1083
1408
|
const p = list[i];
|
|
1084
1409
|
if (!p.alive) continue;
|
|
1085
|
-
const px = p.x;
|
|
1086
|
-
const py = p.y;
|
|
1087
1410
|
switch (s.kind) {
|
|
1088
1411
|
case "spring": {
|
|
1089
1412
|
p.vx = (p.vx + (d.x + p.ox - p.x) * k * p.k) * damp;
|
|
@@ -1092,13 +1415,38 @@ var ParticleStroke = (_class6 = class extends MarkStroke {
|
|
|
1092
1415
|
p.y += p.vy;
|
|
1093
1416
|
break;
|
|
1094
1417
|
}
|
|
1095
|
-
case "string":
|
|
1418
|
+
case "string":
|
|
1419
|
+
case "fuzzy": {
|
|
1096
1420
|
const strand = p.strand;
|
|
1421
|
+
const dm = s.kind === "fuzzy" ? chainDamp(damp, k * p.k) : damp;
|
|
1097
1422
|
let ax = d.x + p.ox;
|
|
1098
1423
|
let ay = d.y + p.oy;
|
|
1099
1424
|
for (const m of strand) {
|
|
1100
|
-
m.vx = (m.vx + (ax - m.x) * k * p.k + 0) *
|
|
1101
|
-
m.vy = (m.vy + (ay - m.y) * k * p.k + g) *
|
|
1425
|
+
m.vx = (m.vx + (ax - m.x) * k * p.k + 0) * dm;
|
|
1426
|
+
m.vy = (m.vy + (ay - m.y) * k * p.k + g) * dm;
|
|
1427
|
+
m.x += m.vx;
|
|
1428
|
+
m.y += m.vy;
|
|
1429
|
+
ax = m.x;
|
|
1430
|
+
ay = m.y;
|
|
1431
|
+
}
|
|
1432
|
+
p.x = strand[strand.length - 1].x;
|
|
1433
|
+
p.y = strand[strand.length - 1].y;
|
|
1434
|
+
break;
|
|
1435
|
+
}
|
|
1436
|
+
case "elastic": {
|
|
1437
|
+
const strand = p.strand;
|
|
1438
|
+
const rest = size * 0.12;
|
|
1439
|
+
const ke = Math.min(0.9, (0.1 + 0.6 * s.stiffness) * p.k);
|
|
1440
|
+
const dm = chainDamp(damp, ke);
|
|
1441
|
+
let ax = d.x + p.ox;
|
|
1442
|
+
let ay = d.y + p.oy;
|
|
1443
|
+
for (const m of strand) {
|
|
1444
|
+
const ex = ax - m.x;
|
|
1445
|
+
const ey = ay - m.y;
|
|
1446
|
+
const len = Math.hypot(ex, ey);
|
|
1447
|
+
const pull = len > rest ? (len - rest) / len : 0;
|
|
1448
|
+
m.vx = (m.vx + ex * pull * ke) * dm;
|
|
1449
|
+
m.vy = (m.vy + ey * pull * ke + g) * dm;
|
|
1102
1450
|
m.x += m.vx;
|
|
1103
1451
|
m.y += m.vy;
|
|
1104
1452
|
ax = m.x;
|
|
@@ -1109,7 +1457,7 @@ var ParticleStroke = (_class6 = class extends MarkStroke {
|
|
|
1109
1457
|
break;
|
|
1110
1458
|
}
|
|
1111
1459
|
case "orbit": {
|
|
1112
|
-
p.phase += (0.05 + 0.3 * s.speed) * (i % 2 ? -1 : 1) * (0.7 + 0.6 *
|
|
1460
|
+
p.phase += (0.05 + 0.3 * s.speed) * (i % 2 ? -1 : 1) * (0.7 + 0.6 * _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 17));
|
|
1113
1461
|
p.x = d.x + Math.cos(p.phase) * p.ox;
|
|
1114
1462
|
p.y = d.y + Math.sin(p.phase) * p.ox + g * p.ox;
|
|
1115
1463
|
break;
|
|
@@ -1127,11 +1475,21 @@ var ParticleStroke = (_class6 = class extends MarkStroke {
|
|
|
1127
1475
|
break;
|
|
1128
1476
|
}
|
|
1129
1477
|
}
|
|
1478
|
+
const w = this.wave(p, d, size);
|
|
1479
|
+
const qx = w ? p.x + nx * w : p.x;
|
|
1480
|
+
const qy = w ? p.y + ny * w : p.y;
|
|
1481
|
+
const px = p.dx;
|
|
1482
|
+
const py = p.dy;
|
|
1483
|
+
p.px = p.dx;
|
|
1484
|
+
p.py = p.dy;
|
|
1485
|
+
p.dx = qx;
|
|
1486
|
+
p.dy = qy;
|
|
1130
1487
|
const fade = s.kind === "flow" ? 1 - p.age / lifeSteps : 1;
|
|
1131
|
-
|
|
1488
|
+
p.fade = fade;
|
|
1489
|
+
const moved = Math.hypot(qx - px, qy - py);
|
|
1132
1490
|
if (d.index === 0 && s.kind !== "flow") continue;
|
|
1133
|
-
if (s.render === "dot") this.
|
|
1134
|
-
else if (s.render === "line") this.segment(px, py,
|
|
1491
|
+
if (s.render === "dot") this.dot(copy, qx, qy, qx - px, qy - py, markR * fade, al * fade, op, d, rects);
|
|
1492
|
+
else if (s.render === "line" || s.render === "ribbon") this.segment(px, py, qx, qy, markR * fade, al * fade, op, d.pressure, rects);
|
|
1135
1493
|
else {
|
|
1136
1494
|
p.run += moved;
|
|
1137
1495
|
const gap = Math.max(markR * 2, size * (0.05 + s.interval));
|
|
@@ -1139,15 +1497,103 @@ var ParticleStroke = (_class6 = class extends MarkStroke {
|
|
|
1139
1497
|
p.run -= gap;
|
|
1140
1498
|
p.bead++;
|
|
1141
1499
|
const t = moved > 0 ? 1 - p.run / Math.max(moved, 1e-6) : 1;
|
|
1142
|
-
const bx = px + (
|
|
1143
|
-
const by = py + (
|
|
1144
|
-
this.
|
|
1500
|
+
const bx = px + (qx - px) * Math.min(1, Math.max(0, t));
|
|
1501
|
+
const by = py + (qy - py) * Math.min(1, Math.max(0, t));
|
|
1502
|
+
this.dot(copy, bx, by, qx - px, qy - py, markR * (0.7 + 0.6 * (p.bead % 3 / 2)) * fade, al * fade, op, d, rects);
|
|
1145
1503
|
}
|
|
1146
1504
|
}
|
|
1147
1505
|
}
|
|
1148
|
-
if (s.
|
|
1506
|
+
if (s.render === "ribbon" && !(d.index === 0 && s.kind !== "flow")) this.ribbon(copy, list, op, al, d, rects);
|
|
1507
|
+
if (s.kind === "flow" && list.length > 512) {
|
|
1508
|
+
list = list.filter((p) => p.alive);
|
|
1509
|
+
this.sets[copy] = list;
|
|
1510
|
+
}
|
|
1149
1511
|
}
|
|
1150
|
-
|
|
1512
|
+
/** A dot (or bead): round, or a textured stamp turned by the particle's motion (mx, my), at random or to the tip angle. */
|
|
1513
|
+
dot(copy, x, y, mx, my, r, alpha, opacity, d, rects) {
|
|
1514
|
+
const s = this.s;
|
|
1515
|
+
const textures = s.dotTextures;
|
|
1516
|
+
if (!textures.length) return this.mark(x, y, r, alpha, opacity, d.pressure, rects);
|
|
1517
|
+
const n = this.dots[copy]++;
|
|
1518
|
+
const pick = s.dotTextureOrder === "random" ? Math.min(textures.length - 1, Math.floor(_chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, n, 31 + copy) * textures.length)) : n % textures.length;
|
|
1519
|
+
const rotation = s.dotRotation === "random" ? _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, n, 37 + copy) * Math.PI * 2 : s.dotRotation === "follow" ? mx || my ? Math.atan2(my, mx) : -d.direction : -this.brush.tip.angle * Math.PI / 180;
|
|
1520
|
+
this.stamp(x, y, r, textures[pick], rotation, this.seed + n * 2654435761 >>> 0, alpha, opacity, d.pressure, rects);
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Ribbon fill for one step: the band between each pair of joined particles, from where they
|
|
1524
|
+
* were drawn last step to where they are drawn now. Bands of one step, and of consecutive steps,
|
|
1525
|
+
* share edges exactly, so the fill has no seams; it is telescoped into the coverage
|
|
1526
|
+
* (`telescope`), so it does not build up at the joins.
|
|
1527
|
+
*/
|
|
1528
|
+
ribbon(copy, list, opacity, alpha, d, rects) {
|
|
1529
|
+
const s = this.s;
|
|
1530
|
+
if (!(s.ribbonFill > 0)) return;
|
|
1531
|
+
const live = (p) => !!p && p.alive && !Number.isNaN(p.px);
|
|
1532
|
+
let order;
|
|
1533
|
+
if (s.kind === "flow") order = list.filter(live);
|
|
1534
|
+
else order = this.orders[copy].map((i) => list[i]).filter(live);
|
|
1535
|
+
if (order.length < 2) return;
|
|
1536
|
+
const pairs = [];
|
|
1537
|
+
if (s.ribbonPairs === "first-last") pairs.push([order[0], order[order.length - 1]]);
|
|
1538
|
+
else for (let i = 0; i + 1 < order.length; i++) pairs.push([order[i], order[i + 1]]);
|
|
1539
|
+
const pts = this.pts;
|
|
1540
|
+
const ceil = Math.min(1, opacity * s.ribbonFill);
|
|
1541
|
+
for (const [a, b] of pairs) {
|
|
1542
|
+
pts.length = 0;
|
|
1543
|
+
pts.push(a.px, a.py, a.dx, a.dy, b.dx, b.dy, b.px, b.py);
|
|
1544
|
+
let x0 = Infinity;
|
|
1545
|
+
let y0 = Infinity;
|
|
1546
|
+
let x1 = -Infinity;
|
|
1547
|
+
let y1 = -Infinity;
|
|
1548
|
+
for (let i = 0; i < 8; i += 2) {
|
|
1549
|
+
x0 = Math.min(x0, pts[i]);
|
|
1550
|
+
x1 = Math.max(x1, pts[i]);
|
|
1551
|
+
y0 = Math.min(y0, pts[i + 1]);
|
|
1552
|
+
y1 = Math.max(y1, pts[i + 1]);
|
|
1553
|
+
}
|
|
1554
|
+
const rect = { x: Math.floor(x0), y: Math.floor(y0), width: Math.floor(x1) - Math.floor(x0) + 1, height: Math.floor(y1) - Math.floor(y0) + 1 };
|
|
1555
|
+
const area = this.scratch(rect.width * rect.height);
|
|
1556
|
+
addPolygonArea(pts, rect, area, Math.min(a.fade, b.fade) * alpha);
|
|
1557
|
+
if (this.telescope(rect, area)) this.lay(rect, area, ceil, d.pressure, (a.dx + b.dx) / 2, (a.dy + b.dy) / 2, rects);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Turns the area newly filled over `rect` into coverage to lay towards the fill's ceiling: the
|
|
1562
|
+
* share of what was left unfilled, so after any number of bands (in any grouping) a pixel's
|
|
1563
|
+
* coverage is the ceiling times the area filled there. False when nothing was added.
|
|
1564
|
+
*/
|
|
1565
|
+
telescope(rect, area) {
|
|
1566
|
+
let any = false;
|
|
1567
|
+
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
1568
|
+
const gy = rect.y + yy;
|
|
1569
|
+
const ty = Math.floor(gy / _chunk474IQG74cjs.TILE);
|
|
1570
|
+
let t;
|
|
1571
|
+
let tx = NaN;
|
|
1572
|
+
for (let xx = 0; xx < rect.width; xx++, k++) {
|
|
1573
|
+
const add = area[k];
|
|
1574
|
+
if (!(add > 0)) continue;
|
|
1575
|
+
const gx = rect.x + xx;
|
|
1576
|
+
const ntx = Math.floor(gx / _chunk474IQG74cjs.TILE);
|
|
1577
|
+
if (ntx !== tx || !t) {
|
|
1578
|
+
tx = ntx;
|
|
1579
|
+
const key = _chunk474IQG74cjs.tileKey.call(void 0, tx, ty);
|
|
1580
|
+
t = this.filled.get(key);
|
|
1581
|
+
if (!t) {
|
|
1582
|
+
t = new Float32Array(_chunk474IQG74cjs.TILE * _chunk474IQG74cjs.TILE);
|
|
1583
|
+
this.filled.set(key, t);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
const ti = (gy - ty * _chunk474IQG74cjs.TILE) * _chunk474IQG74cjs.TILE + (gx - tx * _chunk474IQG74cjs.TILE);
|
|
1587
|
+
const before = t[ti];
|
|
1588
|
+
const after = Math.min(1, before + add);
|
|
1589
|
+
t[ti] = after;
|
|
1590
|
+
area[k] = before < 1 ? (after - before) / (1 - before) : 0;
|
|
1591
|
+
any = true;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
return any;
|
|
1595
|
+
}
|
|
1596
|
+
}, _class7);
|
|
1151
1597
|
var DEFAULT_BRISTLE = { count: 32, stiffness: 0.5, splay: 0.5, thickness: 0.06, load: 0.6, jitter: 0.4 };
|
|
1152
1598
|
function normalizeBristle(raw = {}, base = DEFAULT_BRISTLE) {
|
|
1153
1599
|
return {
|
|
@@ -1168,16 +1614,16 @@ var BristleStroke = class extends MarkStroke {
|
|
|
1168
1614
|
const s = this.s;
|
|
1169
1615
|
this.tufts = this.copies.map(
|
|
1170
1616
|
(_, c) => Array.from({ length: s.count }, (_2, i) => {
|
|
1171
|
-
const a =
|
|
1172
|
-
const r = Math.sqrt(
|
|
1617
|
+
const a = _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 21 + c) * Math.PI * 2;
|
|
1618
|
+
const r = Math.sqrt(_chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 23 + c));
|
|
1173
1619
|
return {
|
|
1174
1620
|
u: Math.cos(a) * r,
|
|
1175
1621
|
v: Math.sin(a) * r,
|
|
1176
1622
|
x: 0,
|
|
1177
1623
|
y: 0,
|
|
1178
|
-
paint: 1 - s.jitter * 0.4 *
|
|
1179
|
-
thirst: 1 + s.jitter * (
|
|
1180
|
-
w: 1 + s.jitter * 0.6 * (
|
|
1624
|
+
paint: 1 - s.jitter * 0.4 * _chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 25 + c),
|
|
1625
|
+
thirst: 1 + s.jitter * (_chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 27 + c) * 2 - 1),
|
|
1626
|
+
w: 1 + s.jitter * 0.6 * (_chunk3K6HWEXZcjs.rand01.call(void 0, this.seed, i, 29 + c) - 0.5),
|
|
1181
1627
|
started: false
|
|
1182
1628
|
};
|
|
1183
1629
|
})
|
|
@@ -1382,12 +1828,12 @@ function normalizePaintBrush(raw = {}, base) {
|
|
|
1382
1828
|
if (rb.dirty !== void 0) mixerIn.cleanEachStroke = !rb.dirty;
|
|
1383
1829
|
if (rb.mixing !== void 0) mixerIn.mixing = rb.mixing;
|
|
1384
1830
|
}
|
|
1385
|
-
const mixer =
|
|
1831
|
+
const mixer = _chunkI7NJPHWVcjs.normalizeMixer.call(void 0, mixerIn);
|
|
1386
1832
|
let behavior = normalizeBehavior(rb, b.behavior);
|
|
1387
1833
|
if (engine === "mixer") behavior = { ...behavior, pickup: mixer.wet, mix: mixer.mix, dirty: !mixer.cleanEachStroke, mixing: mixer.mixing };
|
|
1388
1834
|
let paint = _nullishCoalesce(b.paint, () => ( null));
|
|
1389
1835
|
if (raw.paint !== void 0) {
|
|
1390
|
-
const p =
|
|
1836
|
+
const p = _chunkI7NJPHWVcjs.readPaintSource.call(void 0, raw.paint);
|
|
1391
1837
|
paint = p && p.type === "gradient" ? p : null;
|
|
1392
1838
|
} else if (rb.multicolor !== void 0) {
|
|
1393
1839
|
const mc = normalizeMultiColor(rb.multicolor, _nullishCoalesce(paintToMultiColor(paint), () => ( DEFAULT_MULTI_COLOR)));
|
|
@@ -1399,7 +1845,7 @@ function normalizePaintBrush(raw = {}, base) {
|
|
|
1399
1845
|
name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim().slice(0, 80) : b.name,
|
|
1400
1846
|
category: PAINT_BRUSH_CATEGORIES.includes(raw.category) ? raw.category : b.category,
|
|
1401
1847
|
engine,
|
|
1402
|
-
tip:
|
|
1848
|
+
tip: _chunkI7NJPHWVcjs.normalizeBrush.call(void 0, { ...b.tip, ..._nullishCoalesce(raw.tip, () => ( {})) }),
|
|
1403
1849
|
grain: unit4(raw.grain, b.grain),
|
|
1404
1850
|
pressureSmoothing: range(raw.pressureSmoothing, 0, 0.95, b.pressureSmoothing),
|
|
1405
1851
|
rotation: BRUSH_ROTATIONS.includes(raw.rotation) ? raw.rotation : b.rotation,
|
|
@@ -1407,8 +1853,8 @@ function normalizePaintBrush(raw = {}, base) {
|
|
|
1407
1853
|
mixer,
|
|
1408
1854
|
loadsColor: typeof raw.loadsColor === "boolean" ? raw.loadsColor : b.loadsColor,
|
|
1409
1855
|
behavior,
|
|
1410
|
-
blender:
|
|
1411
|
-
smudge:
|
|
1856
|
+
blender: _chunkI7NJPHWVcjs.normalizeBlender.call(void 0, _nullishCoalesce(raw.blender, () => ( {})), b.blender),
|
|
1857
|
+
smudge: _chunkI7NJPHWVcjs.normalizeSmudge.call(void 0, _nullishCoalesce(raw.smudge, () => ( {})), b.smudge),
|
|
1412
1858
|
wet: normalizeWetBrush(_nullishCoalesce(raw.wet, () => ( {})), _nullishCoalesce(b.wet, () => ( DEFAULT_WET_BRUSH))),
|
|
1413
1859
|
impasto: normalizeImpasto(_nullishCoalesce(raw.impasto, () => ( {})), _nullishCoalesce(b.impasto, () => ( DEFAULT_IMPASTO))),
|
|
1414
1860
|
particle: normalizeParticle(_nullishCoalesce(raw.particle, () => ( {})), _nullishCoalesce(b.particle, () => ( DEFAULT_PARTICLE))),
|
|
@@ -1424,16 +1870,16 @@ var BASE_BRUSH = {
|
|
|
1424
1870
|
name: "Round",
|
|
1425
1871
|
category: "custom",
|
|
1426
1872
|
engine: "dab",
|
|
1427
|
-
tip: { ...
|
|
1873
|
+
tip: { ..._chunkI7NJPHWVcjs.DEFAULT_BRUSH },
|
|
1428
1874
|
grain: 0,
|
|
1429
1875
|
pressureSmoothing: 0,
|
|
1430
1876
|
rotation: "fixed",
|
|
1431
1877
|
dynamics: { ...DEFAULT_DYNAMICS },
|
|
1432
|
-
mixer: { ...
|
|
1878
|
+
mixer: { ..._chunkI7NJPHWVcjs.DEFAULT_MIXER },
|
|
1433
1879
|
loadsColor: true,
|
|
1434
1880
|
behavior: { ...DEFAULT_BEHAVIOR, multicolor: { ...DEFAULT_MULTI_COLOR, colors: [] } },
|
|
1435
|
-
blender: { ...
|
|
1436
|
-
smudge: { ...
|
|
1881
|
+
blender: { ..._chunkI7NJPHWVcjs.DEFAULT_BLENDER },
|
|
1882
|
+
smudge: { ..._chunkI7NJPHWVcjs.DEFAULT_SMUDGE },
|
|
1437
1883
|
wet: { ...DEFAULT_WET_BRUSH },
|
|
1438
1884
|
impasto: { ...DEFAULT_IMPASTO },
|
|
1439
1885
|
particle: { ...DEFAULT_PARTICLE },
|
|
@@ -1897,6 +2343,66 @@ var BUILTIN_BRUSHES = [
|
|
|
1897
2343
|
particle: { kind: "flow", render: "dot", count: 8, size: 0.06, spread: 0.7, speed: 0.9, life: 0.3 },
|
|
1898
2344
|
light: { amount: 1 }
|
|
1899
2345
|
}),
|
|
2346
|
+
builtin({
|
|
2347
|
+
// Silk of light: strands dragged behind the pen on slow waves, the bands between them filled.
|
|
2348
|
+
id: "light-ribbon",
|
|
2349
|
+
name: "Light ribbon",
|
|
2350
|
+
category: "light",
|
|
2351
|
+
engine: "particle",
|
|
2352
|
+
tip: { size: 80, hardness: 0.8, opacity: 0.9, flow: 1, smoothing: 0.35, pressureSize: false, pressureOpacity: false },
|
|
2353
|
+
particle: { kind: "string", render: "ribbon", count: 5, size: 0.015, spread: 1, stiffness: 0.05, damping: 0.3, ribbonFill: 0.45, waveAmplitude: 0.25, waveLength: 220, wavePhaseJitter: 0.25 },
|
|
2354
|
+
light: { amount: 0.8 }
|
|
2355
|
+
}),
|
|
2356
|
+
builtin({
|
|
2357
|
+
// Flames: short-lived bands thrown off the pen, rising and curling in the flow.
|
|
2358
|
+
id: "flame-ribbon",
|
|
2359
|
+
name: "Flame ribbon",
|
|
2360
|
+
category: "light",
|
|
2361
|
+
engine: "particle",
|
|
2362
|
+
tip: { size: 50, hardness: 0.6, opacity: 0.85, flow: 1, smoothing: 0.25, pressureSize: true, pressureOpacity: false },
|
|
2363
|
+
particle: { kind: "flow", render: "ribbon", count: 4, size: 0.012, spread: 0.5, speed: 0.6, gravity: -0.6, life: 0.2, ribbonFill: 0.5 },
|
|
2364
|
+
light: { amount: 1 }
|
|
2365
|
+
}),
|
|
2366
|
+
builtin({
|
|
2367
|
+
// A neon tube that lags and snaps back, with a slow shimmer.
|
|
2368
|
+
id: "neon-strand",
|
|
2369
|
+
name: "Neon strand",
|
|
2370
|
+
category: "light",
|
|
2371
|
+
engine: "particle",
|
|
2372
|
+
tip: { size: 40, hardness: 0.9, opacity: 1, flow: 1, smoothing: 0.4, pressureSize: false, pressureOpacity: false },
|
|
2373
|
+
particle: { kind: "elastic", render: "line", count: 3, size: 0.05, spread: 0.25, stiffness: 0.6, damping: 0.3, waveAmplitude: 0.06, waveLength: 120 },
|
|
2374
|
+
light: { amount: 1 }
|
|
2375
|
+
}),
|
|
2376
|
+
builtin({
|
|
2377
|
+
// Smoke lit from within: thin bands thrown into a slow, rising flow.
|
|
2378
|
+
id: "smoke-ribbon",
|
|
2379
|
+
name: "Smoke ribbon",
|
|
2380
|
+
category: "light",
|
|
2381
|
+
engine: "particle",
|
|
2382
|
+
tip: { size: 70, hardness: 0.3, opacity: 0.45, flow: 1, smoothing: 0.3, pressureSize: true, pressureOpacity: false },
|
|
2383
|
+
particle: { kind: "flow", render: "ribbon", count: 3, size: 5e-3, spread: 0.5, speed: 0.15, gravity: -0.15, life: 0.35, ribbonFill: 0.25, waveAmplitude: 0.1, waveLength: 140, wavePhaseJitter: 1 },
|
|
2384
|
+
light: { amount: 0.3 }
|
|
2385
|
+
}),
|
|
2386
|
+
builtin({
|
|
2387
|
+
// Out-of-focus lights: soft discs and rings spaced along springy paths.
|
|
2388
|
+
id: "bokeh-dots",
|
|
2389
|
+
name: "Bokeh dots",
|
|
2390
|
+
category: "light",
|
|
2391
|
+
engine: "particle",
|
|
2392
|
+
tip: { size: 80, hardness: 0.7, opacity: 0.6, flow: 1, smoothing: 0.3, pressureSize: true, pressureOpacity: false },
|
|
2393
|
+
particle: { kind: "spring", render: "sequence", count: 3, size: 0.3, spread: 1, stiffness: 0.15, damping: 0.4, interval: 1, dotTextures: ["dot", "dot", "ring"], dotTextureOrder: "random" },
|
|
2394
|
+
light: { amount: 0.9 }
|
|
2395
|
+
}),
|
|
2396
|
+
builtin({
|
|
2397
|
+
// Sparks: twinkles and stars thrown into the flow, spaced along it.
|
|
2398
|
+
id: "twinkle-sparks",
|
|
2399
|
+
name: "Twinkle sparks",
|
|
2400
|
+
category: "light",
|
|
2401
|
+
engine: "particle",
|
|
2402
|
+
tip: { size: 50, hardness: 0.8, opacity: 1, flow: 1, smoothing: 0.1, pressureSize: true, pressureOpacity: false },
|
|
2403
|
+
particle: { kind: "flow", render: "sequence", count: 3, size: 0.25, spread: 0.8, speed: 0.9, life: 0.35, interval: 0.6, dotTextures: ["sparkle", "sparkle", "star"], dotTextureOrder: "random", dotRotation: "random" },
|
|
2404
|
+
light: { amount: 1 }
|
|
2405
|
+
}),
|
|
1900
2406
|
builtin({
|
|
1901
2407
|
id: "glow-wash",
|
|
1902
2408
|
name: "Glow wash",
|
|
@@ -2117,4 +2623,13 @@ function parseBrushLibrary(raw, problems = []) {
|
|
|
2117
2623
|
|
|
2118
2624
|
|
|
2119
2625
|
|
|
2120
|
-
|
|
2626
|
+
|
|
2627
|
+
|
|
2628
|
+
|
|
2629
|
+
|
|
2630
|
+
|
|
2631
|
+
|
|
2632
|
+
|
|
2633
|
+
|
|
2634
|
+
|
|
2635
|
+
exports.EFFECT_STRIP_HEIGHT = EFFECT_STRIP_HEIGHT; exports.EFFECT_MAP_REPEATS = EFFECT_MAP_REPEATS; exports.effectPaintSize = effectPaintSize; exports.readEffectStrokeMap = readEffectStrokeMap; exports.effectPaintKey = effectPaintKey; exports.isPaintEffectPaint = isPaintEffectPaint; exports.readPaintEffectPaint = readPaintEffectPaint; exports.sampleEffectField = sampleEffectField; exports.sampleEffectAt = sampleEffectAt; exports.effectDabField = effectDabField; exports.PAPER_FAMILIES = PAPER_FAMILIES; exports.PAPER_LIBRARY = PAPER_LIBRARY; exports.DEFAULT_PAPER = DEFAULT_PAPER; exports.paperPreset = paperPreset; exports.clonePaper = clonePaper; exports.normalizePaper = normalizePaper; exports.hexToRgb8 = hexToRgb8; exports.renderPaper = renderPaper; exports.penOrientation = penOrientation; exports.tiltToOrientation = tiltToOrientation; exports.PenSmoother = PenSmoother; exports.IDENTITY_COPY = IDENTITY_COPY; exports.PenDabWalker = PenDabWalker; exports.DryStroke = DryStroke; exports.mixerTip = mixerTip; exports.toStrokePoint = toStrokePoint; exports.STICKER_ART_SIZE = STICKER_ART_SIZE; exports.defaultStickerRasterizer = defaultStickerRasterizer; exports.StickerArtCache = StickerArtCache; exports.sampleArt = sampleArt; exports.MAX_STICKER_STAMPS = MAX_STICKER_STAMPS; exports.DEFAULT_STICKER = DEFAULT_STICKER; exports.normalizeStickerSettings = normalizeStickerSettings; exports.stickerRect = stickerRect; exports.stickerStamp = stickerStamp; exports.drawSticker = drawSticker; exports.StickerSpray = StickerSpray; exports.renderStickers = renderStickers; exports.normalizeStickerUpdate = normalizeStickerUpdate; exports.stickerSurface = stickerSurface; exports.stickerAt = stickerAt; exports.PARTICLE_KINDS = PARTICLE_KINDS; exports.PARTICLE_RENDERS = PARTICLE_RENDERS; exports.RIBBON_PAIRS = RIBBON_PAIRS; exports.DOT_TEXTURE_ORDERS = DOT_TEXTURE_ORDERS; exports.DOT_ROTATIONS = DOT_ROTATIONS; exports.MAX_DOT_TEXTURES = MAX_DOT_TEXTURES; exports.DEFAULT_PARTICLE = DEFAULT_PARTICLE; exports.normalizeParticle = normalizeParticle; exports.addPolygonArea = addPolygonArea; exports.ParticleStroke = ParticleStroke; exports.DEFAULT_BRISTLE = DEFAULT_BRISTLE; exports.normalizeBristle = normalizeBristle; exports.BristleStroke = BristleStroke; exports.PAINT_BRUSH_ENGINES = PAINT_BRUSH_ENGINES; exports.PAINT_BRUSH_CATEGORIES = PAINT_BRUSH_CATEGORIES; exports.WET_TOOLS = WET_TOOLS; exports.WET_MEDIA = WET_MEDIA; exports.DEFAULT_WET_BRUSH = DEFAULT_WET_BRUSH; exports.normalizeWetBrush = normalizeWetBrush; exports.IMPASTO_TOOLS = IMPASTO_TOOLS; exports.DEFAULT_IMPASTO = DEFAULT_IMPASTO; exports.DEFAULT_LIGHT = DEFAULT_LIGHT; exports.normalizeLight = normalizeLight; exports.normalizeImpasto = normalizeImpasto; exports.MULTI_COLOR_MODES = MULTI_COLOR_MODES; exports.DEFAULT_MULTI_COLOR = DEFAULT_MULTI_COLOR; exports.DEFAULT_BEHAVIOR = DEFAULT_BEHAVIOR; exports.BRUSH_ROTATIONS = BRUSH_ROTATIONS; exports.DEFAULT_DYNAMICS = DEFAULT_DYNAMICS; exports.normalizeDynamics = normalizeDynamics; exports.BRUSH_ID = BRUSH_ID; exports.normalizeMultiColor = normalizeMultiColor; exports.normalizeBehavior = normalizeBehavior; exports.isWetCapable = isWetCapable; exports.isWetBrush = isWetBrush; exports.usesPaintExchange = usesPaintExchange; exports.brushTakesPaint = brushTakesPaint; exports.paintToMultiColor = paintToMultiColor; exports.multiColorToPaint = multiColorToPaint; exports.normalizePaintBrush = normalizePaintBrush; exports.BUILTIN_BRUSHES = BUILTIN_BRUSHES; exports.DEFAULT_BRUSH_ID = DEFAULT_BRUSH_ID; exports.brushToJSON = brushToJSON; exports.parseBrushLibrary = parseBrushLibrary;
|