@pixerate/editor 0.108.0 → 0.110.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/dist/animation/index.cjs +5 -5
- package/dist/animation/index.cjs.map +1 -1
- package/dist/animation/index.js +9 -9
- package/dist/animation-editor/index.cjs +59 -59
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +2 -1
- package/dist/animation-editor/index.d.ts +2 -1
- package/dist/animation-editor/index.js +29 -29
- package/dist/blending-DXl06NSx.d.ts +486 -0
- package/dist/blending-aOE6Y3UE.d.cts +486 -0
- package/dist/canvas/index.cjs +27 -27
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.js +11 -11
- package/dist/{chunk-2FGRTYJN.cjs → chunk-477UVMNR.cjs} +3 -3
- package/dist/{chunk-2FGRTYJN.cjs.map → chunk-477UVMNR.cjs.map} +1 -1
- package/dist/chunk-7VOHOPLW.cjs +1136 -0
- package/dist/chunk-7VOHOPLW.cjs.map +1 -0
- package/dist/{chunk-HUQ7EHVI.js → chunk-BLWCAQCW.js} +723 -1975
- package/dist/chunk-BLWCAQCW.js.map +1 -0
- package/dist/{chunk-SOROZ2BF.js → chunk-DMRSJBJF.js} +1939 -318
- package/dist/chunk-DMRSJBJF.js.map +1 -0
- package/dist/chunk-FTBZPI77.cjs +1 -0
- package/dist/chunk-FTBZPI77.cjs.map +1 -0
- package/dist/{chunk-WMBIJCHA.js → chunk-HNS7UHCM.js} +5 -1
- package/dist/{chunk-WMBIJCHA.js.map → chunk-HNS7UHCM.js.map} +1 -1
- package/dist/chunk-JLYX4V57.cjs +2001 -0
- package/dist/chunk-JLYX4V57.cjs.map +1 -0
- package/dist/chunk-KB2YBCVS.js +2001 -0
- package/dist/chunk-KB2YBCVS.js.map +1 -0
- package/dist/{chunk-G4BIYE6R.js → chunk-LQEEDHOP.js} +40 -2
- package/dist/chunk-LQEEDHOP.js.map +1 -0
- package/dist/{chunk-FRD3FUXI.cjs → chunk-MGL4U5WA.cjs} +2144 -523
- package/dist/chunk-MGL4U5WA.cjs.map +1 -0
- package/dist/{chunk-T3QZ6S47.cjs → chunk-POGBUYWE.cjs} +131 -93
- package/dist/chunk-POGBUYWE.cjs.map +1 -0
- package/dist/chunk-VKK5VS2T.js +1 -0
- package/dist/{chunk-UTEVPQTS.cjs → chunk-W3GXSUSQ.cjs} +746 -1998
- package/dist/chunk-W3GXSUSQ.cjs.map +1 -0
- package/dist/{chunk-SZ6KMZNM.cjs → chunk-XIOMMGPD.cjs} +6 -2
- package/dist/chunk-XIOMMGPD.cjs.map +1 -0
- package/dist/{chunk-JK6M6V7G.js → chunk-Z3YWVUWT.js} +4 -4
- package/dist/{chunk-3PHA3UKI.js → chunk-Z4BC6M74.js} +523 -121
- package/dist/chunk-Z4BC6M74.js.map +1 -0
- package/dist/{export-a9bnF7Cl.d.ts → export-CO2ryu3I.d.ts} +419 -18
- package/dist/{export-JGWQEPJn.d.cts → export-DRiLzP_j.d.cts} +419 -18
- package/dist/image-editor/index.cjs +1665 -1113
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +78 -14
- package/dist/image-editor/index.d.ts +78 -14
- package/dist/image-editor/index.js +843 -291
- package/dist/image-editor/index.js.map +1 -1
- package/dist/paint/index.cjs +28 -4
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +3 -89
- package/dist/paint/index.d.ts +3 -89
- package/dist/paint/index.js +27 -3
- package/dist/paint-editor/index.cjs +1056 -287
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +304 -22
- package/dist/paint-editor/index.d.ts +304 -22
- package/dist/paint-editor/index.js +852 -83
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/raster/index.cjs +7 -3
- package/dist/raster/index.cjs.map +1 -1
- package/dist/raster/index.d.cts +3 -129
- package/dist/raster/index.d.ts +3 -129
- package/dist/raster/index.js +6 -2
- package/dist/{compositor-D92URMlm.d.cts → render-BEriFuqK.d.cts} +136 -2
- package/dist/{compositor-Kt_M4ruo.d.ts → render-tjzKaik-.d.ts} +136 -2
- package/dist/{surface-CkKOHGPm.d.cts → surface-C8RRg_Bh.d.cts} +109 -1
- package/dist/{surface-CkKOHGPm.d.ts → surface-C8RRg_Bh.d.ts} +109 -1
- package/dist/{svg-SseJTIrA.d.ts → svg-D_cfkhlB.d.cts} +3 -629
- package/dist/{svg-ClVIG4T7.d.cts → svg-wIaKLrU0.d.ts} +3 -629
- package/dist/types-DtL_qLFz.d.ts +630 -0
- package/dist/types-DyQq-WPY.d.cts +630 -0
- package/dist/vector/index.cjs +563 -563
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +4 -2
- package/dist/vector/index.d.ts +4 -2
- package/dist/vector/index.js +69 -69
- package/dist/video-editor/index.cjs +3 -3
- package/dist/video-editor/index.js +2 -2
- package/package.json +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +49 -13
- package/dist/chunk-3PHA3UKI.js.map +0 -1
- package/dist/chunk-6BU5WU4R.cjs +0 -1
- package/dist/chunk-6BU5WU4R.cjs.map +0 -1
- package/dist/chunk-DWGZUSES.cjs +0 -694
- package/dist/chunk-DWGZUSES.cjs.map +0 -1
- package/dist/chunk-FRD3FUXI.cjs.map +0 -1
- package/dist/chunk-G4BIYE6R.js.map +0 -1
- package/dist/chunk-HUFQD4CB.cjs +0 -734
- package/dist/chunk-HUFQD4CB.cjs.map +0 -1
- package/dist/chunk-HUQ7EHVI.js.map +0 -1
- package/dist/chunk-KKREERP2.js +0 -694
- package/dist/chunk-KKREERP2.js.map +0 -1
- package/dist/chunk-SOROZ2BF.js.map +0 -1
- package/dist/chunk-SZ6KMZNM.cjs.map +0 -1
- package/dist/chunk-T3QZ6S47.cjs.map +0 -1
- package/dist/chunk-UTEVPQTS.cjs.map +0 -1
- package/dist/chunk-XYBJKUAU.js +0 -1
- package/dist/mixer-5ziHU8OS.d.cts +0 -282
- package/dist/mixer-DNqiYXYQ.d.ts +0 -282
- /package/dist/{chunk-XYBJKUAU.js.map → chunk-VKK5VS2T.js.map} +0 -0
- /package/dist/{chunk-JK6M6V7G.js.map → chunk-Z3YWVUWT.js.map} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
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; var _class8; var _class9; var _class10; var _class11;
|
|
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; var _class8; var _class9; var _class10; var _class11; var _class12;
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunkMGL4U5WAcjs = require('../chunk-MGL4U5WA.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
@@ -17,7 +17,9 @@ var _chunkFRD3FUXIcjs = require('../chunk-FRD3FUXI.cjs');
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
var _chunkPOGBUYWEcjs = require('../chunk-POGBUYWE.cjs');
|
|
21
23
|
require('../chunk-MUUXNRU4.cjs');
|
|
22
24
|
|
|
23
25
|
|
|
@@ -35,11 +37,18 @@ require('../chunk-MUUXNRU4.cjs');
|
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
|
|
38
|
-
var _chunkHUFQD4CBcjs = require('../chunk-HUFQD4CB.cjs');
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
var _chunk7VOHOPLWcjs = require('../chunk-7VOHOPLW.cjs');
|
|
51
|
+
|
|
43
52
|
|
|
44
53
|
|
|
45
54
|
|
|
@@ -53,14 +62,23 @@ var _chunkHUFQD4CBcjs = require('../chunk-HUFQD4CB.cjs');
|
|
|
53
62
|
|
|
54
63
|
|
|
55
64
|
|
|
56
|
-
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
var _chunkXIOMMGPDcjs = require('../chunk-XIOMMGPD.cjs');
|
|
57
72
|
|
|
58
73
|
|
|
59
74
|
|
|
60
75
|
|
|
61
76
|
|
|
62
77
|
var _chunkEGFUVXKKcjs = require('../chunk-EGFUVXKK.cjs');
|
|
63
|
-
require('../chunk-
|
|
78
|
+
require('../chunk-W3GXSUSQ.cjs');
|
|
79
|
+
require('../chunk-XGD3FSNC.cjs');
|
|
80
|
+
require('../chunk-MR3Z4OQI.cjs');
|
|
81
|
+
require('../chunk-A6PHCAGX.cjs');
|
|
64
82
|
|
|
65
83
|
// src/paint-editor/noise.ts
|
|
66
84
|
function mix32(h) {
|
|
@@ -409,7 +427,7 @@ function newPaintLayerId() {
|
|
|
409
427
|
return `pl${Date.now().toString(36)}${(nextId++).toString(36)}`;
|
|
410
428
|
}
|
|
411
429
|
function createPaintLayer(name, id = newPaintLayerId()) {
|
|
412
|
-
return { type: "pixel", id, name, visible: true, opacity: 1, blend: "normal", surface:
|
|
430
|
+
return { type: "pixel", id, name, visible: true, opacity: 1, blend: "normal", surface: _chunkXIOMMGPDcjs.emptySurface.call(void 0, 4), offset: { x: 0, y: 0 } };
|
|
413
431
|
}
|
|
414
432
|
var PaintDocumentError = class extends Error {
|
|
415
433
|
constructor(message) {
|
|
@@ -435,8 +453,11 @@ function createPaintDocument(options = {}) {
|
|
|
435
453
|
}
|
|
436
454
|
|
|
437
455
|
// src/paint-editor/brushes.ts
|
|
438
|
-
var PAINT_BRUSH_ENGINES = ["dab", "eraser", "mixer"];
|
|
439
|
-
var PAINT_BRUSH_CATEGORIES = ["pencil", "pastel", "charcoal", "airbrush", "marker", "ink", "eraser", "blender", "smudge", "mixer", "custom"];
|
|
456
|
+
var PAINT_BRUSH_ENGINES = ["dab", "eraser", "mixer", "blender", "smudge"];
|
|
457
|
+
var PAINT_BRUSH_CATEGORIES = ["pencil", "pastel", "charcoal", "airbrush", "marker", "ink", "paint", "eraser", "blender", "smudge", "mixer", "custom"];
|
|
458
|
+
var MULTI_COLOR_MODES = ["off", "tip", "dab"];
|
|
459
|
+
var DEFAULT_MULTI_COLOR = { mode: "off", colors: [], order: "sequence", length: 12, softness: 1 };
|
|
460
|
+
var DEFAULT_BEHAVIOR = { pickup: 0, mix: 0.5, dirty: false, mixing: "pigment", multicolor: DEFAULT_MULTI_COLOR };
|
|
440
461
|
var BRUSH_ROTATIONS = ["fixed", "stroke", "barrel"];
|
|
441
462
|
var DEFAULT_DYNAMICS = {
|
|
442
463
|
minSize: 0,
|
|
@@ -469,21 +490,62 @@ function normalizeDynamics(raw = {}, base = DEFAULT_DYNAMICS) {
|
|
|
469
490
|
};
|
|
470
491
|
}
|
|
471
492
|
var BRUSH_ID = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
493
|
+
var HEX2 = /^#[0-9a-f]{6}$/i;
|
|
494
|
+
function normalizeMultiColor(raw = {}, base = DEFAULT_MULTI_COLOR) {
|
|
495
|
+
const colors = Array.isArray(raw.colors) ? raw.colors.filter((c) => typeof c === "string" && HEX2.test(c.trim())).map((c) => c.trim().toLowerCase()).slice(0, 8) : base.colors;
|
|
496
|
+
return {
|
|
497
|
+
mode: MULTI_COLOR_MODES.includes(raw.mode) ? raw.mode : base.mode,
|
|
498
|
+
colors: [...colors],
|
|
499
|
+
order: raw.order === "random" || raw.order === "sequence" ? raw.order : base.order,
|
|
500
|
+
length: typeof raw.length === "number" && Number.isFinite(raw.length) ? Math.min(500, Math.max(1, Math.round(raw.length))) : base.length,
|
|
501
|
+
softness: unit2(raw.softness, base.softness)
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function normalizeBehavior(raw = {}, base = DEFAULT_BEHAVIOR) {
|
|
505
|
+
return {
|
|
506
|
+
pickup: unit2(raw.pickup, base.pickup),
|
|
507
|
+
mix: unit2(raw.mix, base.mix),
|
|
508
|
+
dirty: typeof raw.dirty === "boolean" ? raw.dirty : base.dirty,
|
|
509
|
+
mixing: raw.mixing === "rgb" || raw.mixing === "pigment" ? raw.mixing : base.mixing,
|
|
510
|
+
multicolor: normalizeMultiColor(_nullishCoalesce(raw.multicolor, () => ( {})), base.multicolor)
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
function isWetCapable(brush) {
|
|
514
|
+
return brush.engine === "dab" || brush.engine === "mixer";
|
|
515
|
+
}
|
|
516
|
+
function usesPaintExchange(brush) {
|
|
517
|
+
return brush.engine === "dab" && (brush.behavior.pickup > 0 || brush.behavior.multicolor.mode !== "off");
|
|
518
|
+
}
|
|
472
519
|
function normalizePaintBrush(raw = {}, base) {
|
|
473
520
|
const b = _nullishCoalesce(base, () => ( BASE_BRUSH));
|
|
474
521
|
const id = typeof raw.id === "string" && BRUSH_ID.test(raw.id) ? raw.id : b.id;
|
|
522
|
+
const engine = PAINT_BRUSH_ENGINES.includes(raw.engine) ? raw.engine : b.engine;
|
|
523
|
+
const rb = _nullishCoalesce(raw.behavior, () => ( {}));
|
|
524
|
+
const mixerIn = { ...b.mixer, ..._nullishCoalesce(raw.mixer, () => ( {})) };
|
|
525
|
+
if (engine === "mixer") {
|
|
526
|
+
if (rb.pickup !== void 0) mixerIn.wet = rb.pickup;
|
|
527
|
+
if (rb.mix !== void 0) mixerIn.mix = rb.mix;
|
|
528
|
+
if (rb.dirty !== void 0) mixerIn.cleanEachStroke = !rb.dirty;
|
|
529
|
+
if (rb.mixing !== void 0) mixerIn.mixing = rb.mixing;
|
|
530
|
+
}
|
|
531
|
+
const mixer = _chunk7VOHOPLWcjs.normalizeMixer.call(void 0, mixerIn);
|
|
532
|
+
let behavior = normalizeBehavior(rb, b.behavior);
|
|
533
|
+
if (engine === "mixer") behavior = { ...behavior, pickup: mixer.wet, mix: mixer.mix, dirty: !mixer.cleanEachStroke, mixing: mixer.mixing };
|
|
475
534
|
return {
|
|
476
535
|
id,
|
|
477
536
|
name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim().slice(0, 80) : b.name,
|
|
478
537
|
category: PAINT_BRUSH_CATEGORIES.includes(raw.category) ? raw.category : b.category,
|
|
479
|
-
engine
|
|
480
|
-
tip:
|
|
538
|
+
engine,
|
|
539
|
+
tip: _chunk7VOHOPLWcjs.normalizeBrush.call(void 0, { ...b.tip, ..._nullishCoalesce(raw.tip, () => ( {})) }),
|
|
481
540
|
grain: unit2(raw.grain, b.grain),
|
|
482
541
|
pressureSmoothing: range(raw.pressureSmoothing, 0, 0.95, b.pressureSmoothing),
|
|
483
542
|
rotation: BRUSH_ROTATIONS.includes(raw.rotation) ? raw.rotation : b.rotation,
|
|
484
543
|
dynamics: normalizeDynamics(_nullishCoalesce(raw.dynamics, () => ( {})), b.dynamics),
|
|
485
|
-
mixer
|
|
544
|
+
mixer,
|
|
486
545
|
loadsColor: typeof raw.loadsColor === "boolean" ? raw.loadsColor : b.loadsColor,
|
|
546
|
+
behavior,
|
|
547
|
+
blender: _chunk7VOHOPLWcjs.normalizeBlender.call(void 0, _nullishCoalesce(raw.blender, () => ( {})), b.blender),
|
|
548
|
+
smudge: _chunk7VOHOPLWcjs.normalizeSmudge.call(void 0, _nullishCoalesce(raw.smudge, () => ( {})), b.smudge),
|
|
487
549
|
...raw.builtin ? { builtin: true } : {}
|
|
488
550
|
};
|
|
489
551
|
}
|
|
@@ -492,13 +554,16 @@ var BASE_BRUSH = {
|
|
|
492
554
|
name: "Round",
|
|
493
555
|
category: "custom",
|
|
494
556
|
engine: "dab",
|
|
495
|
-
tip: { ...
|
|
557
|
+
tip: { ..._chunk7VOHOPLWcjs.DEFAULT_BRUSH },
|
|
496
558
|
grain: 0,
|
|
497
559
|
pressureSmoothing: 0,
|
|
498
560
|
rotation: "fixed",
|
|
499
561
|
dynamics: { ...DEFAULT_DYNAMICS },
|
|
500
|
-
mixer: { ...
|
|
501
|
-
loadsColor: true
|
|
562
|
+
mixer: { ..._chunk7VOHOPLWcjs.DEFAULT_MIXER },
|
|
563
|
+
loadsColor: true,
|
|
564
|
+
behavior: { ...DEFAULT_BEHAVIOR, multicolor: { ...DEFAULT_MULTI_COLOR, colors: [] } },
|
|
565
|
+
blender: { ..._chunk7VOHOPLWcjs.DEFAULT_BLENDER },
|
|
566
|
+
smudge: { ..._chunk7VOHOPLWcjs.DEFAULT_SMUDGE }
|
|
502
567
|
};
|
|
503
568
|
var builtin = (init) => ({ ...normalizePaintBrush(init), builtin: true });
|
|
504
569
|
var BUILTIN_BRUSHES = [
|
|
@@ -612,19 +677,54 @@ var BUILTIN_BRUSHES = [
|
|
|
612
677
|
id: "blender",
|
|
613
678
|
name: "Blender",
|
|
614
679
|
category: "blender",
|
|
615
|
-
engine: "
|
|
680
|
+
engine: "blender",
|
|
616
681
|
loadsColor: false,
|
|
617
|
-
tip: { size: 34, hardness: 0.4, spacing: 0.
|
|
618
|
-
|
|
682
|
+
tip: { size: 34, hardness: 0.4, spacing: 0.1, opacity: 1, flow: 1, smoothing: 0.2, pressureSize: false, pressureOpacity: true },
|
|
683
|
+
blender: { strength: 0.5, distance: 0.35, mixing: "pigment" }
|
|
619
684
|
}),
|
|
620
685
|
builtin({
|
|
621
686
|
id: "smudge",
|
|
622
687
|
name: "Smudge",
|
|
623
688
|
category: "smudge",
|
|
624
|
-
engine: "
|
|
689
|
+
engine: "smudge",
|
|
625
690
|
loadsColor: false,
|
|
626
|
-
tip: { size: 26, hardness: 0.6, spacing: 0.06, opacity: 1, flow:
|
|
627
|
-
|
|
691
|
+
tip: { size: 26, hardness: 0.6, spacing: 0.06, opacity: 1, flow: 1, smoothing: 0.2, pressureSize: false, pressureOpacity: true },
|
|
692
|
+
smudge: { strength: 0.75, length: 0.85, mixing: "rgb" }
|
|
693
|
+
}),
|
|
694
|
+
builtin({
|
|
695
|
+
id: "wet-smudge",
|
|
696
|
+
name: "Pigment smudge",
|
|
697
|
+
category: "smudge",
|
|
698
|
+
engine: "smudge",
|
|
699
|
+
loadsColor: false,
|
|
700
|
+
tip: { size: 30, hardness: 0.5, spacing: 0.06, opacity: 1, flow: 1, smoothing: 0.2, pressureSize: true, pressureOpacity: true },
|
|
701
|
+
smudge: { strength: 0.7, length: 0.9, mixing: "pigment" },
|
|
702
|
+
dynamics: { minSize: 0.6 }
|
|
703
|
+
}),
|
|
704
|
+
builtin({
|
|
705
|
+
id: "dirty-round",
|
|
706
|
+
name: "Dirty round",
|
|
707
|
+
category: "paint",
|
|
708
|
+
tip: { size: 22, hardness: 0.65, spacing: 0.06, opacity: 1, flow: 0.7, smoothing: 0.2, pressureSize: true, pressureOpacity: false },
|
|
709
|
+
behavior: { pickup: 0.55, mix: 0.6, dirty: true, mixing: "pigment" },
|
|
710
|
+
dynamics: { minSize: 0.5 }
|
|
711
|
+
}),
|
|
712
|
+
builtin({
|
|
713
|
+
id: "multicolor-flat",
|
|
714
|
+
name: "Multi-colour flat",
|
|
715
|
+
category: "paint",
|
|
716
|
+
rotation: "stroke",
|
|
717
|
+
tip: { size: 30, hardness: 0.75, spacing: 0.05, angle: 90, roundness: 0.3, opacity: 1, flow: 0.85, smoothing: 0.2, pressureSize: true, pressureOpacity: false },
|
|
718
|
+
behavior: { pickup: 0.15, mix: 0.4, mixing: "pigment", multicolor: { mode: "tip", softness: 0.7 } },
|
|
719
|
+
dynamics: { minSize: 0.6 }
|
|
720
|
+
}),
|
|
721
|
+
builtin({
|
|
722
|
+
id: "palette-dabber",
|
|
723
|
+
name: "Palette dabber",
|
|
724
|
+
category: "paint",
|
|
725
|
+
tip: { size: 18, hardness: 0.7, spacing: 0.35, opacity: 1, flow: 0.9, smoothing: 0.1, pressureSize: true, pressureOpacity: false },
|
|
726
|
+
behavior: { multicolor: { mode: "dab", order: "sequence", length: 6, softness: 0.4 } },
|
|
727
|
+
dynamics: { minSize: 0.5, sizeJitter: 0.15, scatter: 0.3 }
|
|
628
728
|
}),
|
|
629
729
|
builtin({
|
|
630
730
|
id: "mixer-brush",
|
|
@@ -804,7 +904,9 @@ var PenDabWalker = (_class4 = class {
|
|
|
804
904
|
opacity: Math.min(1, Math.max(0, opacity)),
|
|
805
905
|
angle,
|
|
806
906
|
roundness: Math.min(1, Math.max(0.01, tip.roundness * (1 - dyn.tiltRoundness * s.lean * 0.8))),
|
|
807
|
-
pressure: s.pressure
|
|
907
|
+
pressure: s.pressure,
|
|
908
|
+
direction: this.dir,
|
|
909
|
+
index: i
|
|
808
910
|
};
|
|
809
911
|
}
|
|
810
912
|
push(p, out) {
|
|
@@ -874,7 +976,7 @@ var DryStroke = (_class5 = class {
|
|
|
874
976
|
}
|
|
875
977
|
|
|
876
978
|
|
|
877
|
-
__init12() {this.coverage = new (0,
|
|
979
|
+
__init12() {this.coverage = new (0, _chunk7VOHOPLWcjs.CoverageMap)()}
|
|
878
980
|
__init13() {this.dabCount = 0}
|
|
879
981
|
|
|
880
982
|
|
|
@@ -908,11 +1010,11 @@ var DryStroke = (_class5 = class {
|
|
|
908
1010
|
const hardness = this.brush.tip.hardness;
|
|
909
1011
|
const grain = this.options.grain;
|
|
910
1012
|
for (const d of dabs) {
|
|
911
|
-
const rect =
|
|
1013
|
+
const rect = _chunk7VOHOPLWcjs.dabRect.call(void 0, d, hardness);
|
|
912
1014
|
const n = rect.width * rect.height;
|
|
913
1015
|
if (this.buf.length < n) this.buf = new Float32Array(n);
|
|
914
1016
|
const vals = this.buf.subarray(0, n);
|
|
915
|
-
|
|
1017
|
+
_chunk7VOHOPLWcjs.rasterizeDab.call(void 0, d, hardness, rect, vals);
|
|
916
1018
|
if (this.depth > 0 && grain) {
|
|
917
1019
|
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
918
1020
|
const y = rect.y + yy + 0.5;
|
|
@@ -935,9 +1037,251 @@ function toStrokePoint(p) {
|
|
|
935
1037
|
return { x: p.x, y: p.y, pressure: pressureOf(p), ...typeof p.t === "number" ? { t: p.t } : {} };
|
|
936
1038
|
}
|
|
937
1039
|
|
|
1040
|
+
// src/paint-editor/dab-stroke.ts
|
|
1041
|
+
var GRADIENT_STEPS = 32;
|
|
1042
|
+
function multiColorPalette(mc, color, secondary) {
|
|
1043
|
+
if (mc.colors.length >= 2) {
|
|
1044
|
+
return mc.colors.map((h) => {
|
|
1045
|
+
const n = parseInt(h.slice(1), 16);
|
|
1046
|
+
return [(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255];
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
return [[...color], [...secondary]];
|
|
1050
|
+
}
|
|
1051
|
+
function soften(f, softness) {
|
|
1052
|
+
if (softness >= 1) return f;
|
|
1053
|
+
const w = Math.max(1e-3, softness);
|
|
1054
|
+
return Math.min(1, Math.max(0, (f - 0.5) / w + 0.5));
|
|
1055
|
+
}
|
|
1056
|
+
function mixRgb(a, b, t, mixing) {
|
|
1057
|
+
if (t <= 0) return [...a];
|
|
1058
|
+
if (t >= 1) return [...b];
|
|
1059
|
+
if (mixing === "pigment") {
|
|
1060
|
+
const o = [0, 0, 0];
|
|
1061
|
+
const q = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255);
|
|
1062
|
+
_chunkXIOMMGPDcjs.mixPigment8.call(void 0, q(a[0]), q(a[1]), q(a[2]), q(b[0]), q(b[1]), q(b[2]), t, o);
|
|
1063
|
+
return [o[0], o[1], o[2]];
|
|
1064
|
+
}
|
|
1065
|
+
return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t];
|
|
1066
|
+
}
|
|
1067
|
+
function multiColorGradient(palette, softness, mixing) {
|
|
1068
|
+
const n = palette.length;
|
|
1069
|
+
const out = [];
|
|
1070
|
+
for (let j = 0; j < GRADIENT_STEPS; j++) {
|
|
1071
|
+
const f = j / (GRADIENT_STEPS - 1) * (n - 1);
|
|
1072
|
+
const i = Math.min(n - 2, Math.floor(f));
|
|
1073
|
+
out.push(mixRgb(palette[i], palette[i + 1], soften(f - i, softness), mixing));
|
|
1074
|
+
}
|
|
1075
|
+
return out;
|
|
1076
|
+
}
|
|
1077
|
+
function multiColorForDab(mc, palette, index, seed, mixing) {
|
|
1078
|
+
const n = palette.length;
|
|
1079
|
+
if (mc.order === "random") {
|
|
1080
|
+
const run = Math.floor(index / mc.length);
|
|
1081
|
+
return [...palette[Math.min(n - 1, Math.floor(rand01(seed, run, 11) * n))]];
|
|
1082
|
+
}
|
|
1083
|
+
const f = index / mc.length % n;
|
|
1084
|
+
const i = Math.floor(f);
|
|
1085
|
+
return mixRgb(palette[i], palette[(i + 1) % n], soften(f - i, mc.softness), mixing);
|
|
1086
|
+
}
|
|
1087
|
+
var PaintDabStroke = (_class6 = class {
|
|
1088
|
+
constructor(brush, options) {;_class6.prototype.__init17.call(this);_class6.prototype.__init18.call(this);_class6.prototype.__init19.call(this);_class6.prototype.__init20.call(this);_class6.prototype.__init21.call(this);_class6.prototype.__init22.call(this);_class6.prototype.__init23.call(this);_class6.prototype.__init24.call(this);
|
|
1089
|
+
this.brush = brush;
|
|
1090
|
+
this.options = options;
|
|
1091
|
+
this.smoother = new PenSmoother(brush.tip.smoothing, brush.pressureSmoothing);
|
|
1092
|
+
this.copies = _optionalChain([options, 'access', _4 => _4.copies, 'optionalAccess', _5 => _5.length]) ? options.copies : [IDENTITY_COPY];
|
|
1093
|
+
const exchanging = brush.engine === "mixer" || brush.engine === "dab";
|
|
1094
|
+
const rates = brush.engine === "mixer" ? _chunk7VOHOPLWcjs.mixerRates.call(void 0, brush.mixer) : _chunk7VOHOPLWcjs.exchangeRates.call(void 0, brush.behavior.pickup, brush.behavior.mix, 1, brush.behavior.mixing);
|
|
1095
|
+
this.mixing = brush.engine === "mixer" ? brush.mixer.mixing : brush.behavior.mixing;
|
|
1096
|
+
this.states = this.copies.map((c, i) => ({
|
|
1097
|
+
walker: new PenDabWalker(brush, (_nullishCoalesce(options.seed, () => ( 0))) + i * 7919 | 0, c.linear),
|
|
1098
|
+
exchange: exchanging ? new (0, _chunk7VOHOPLWcjs.PaintExchange)(rates, options.load) : null,
|
|
1099
|
+
smudge: brush.engine === "smudge" ? new (0, _chunk7VOHOPLWcjs.SmudgeTip)(brush.smudge, brush.tip.size * (1 + brush.dynamics.tiltSize * 1.5)) : null
|
|
1100
|
+
}));
|
|
1101
|
+
this.medium = new (0, _chunk7VOHOPLWcjs.TileMedium)(options.target, brush.engine === "dab" ? { blend: brush.tip.blend } : {});
|
|
1102
|
+
this.depth = options.grain && !options.grain.flat ? Math.min(1, Math.max(0, options.paperDepth * brush.grain)) : 0;
|
|
1103
|
+
this.coverage = brush.engine === "dab" ? new (0, _chunk7VOHOPLWcjs.CoverageMap)() : null;
|
|
1104
|
+
const mc = brush.behavior.multicolor;
|
|
1105
|
+
this.palette = exchanging && mc.mode !== "off" ? multiColorPalette(mc, options.color, options.secondary) : null;
|
|
1106
|
+
this.gradient = this.palette && mc.mode === "tip" ? multiColorGradient(this.palette, mc.softness, this.mixing) : null;
|
|
1107
|
+
this.scratch = brush.engine === "blender" ? _chunk7VOHOPLWcjs.createBlenderScratch.call(void 0, ) : null;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
__init17() {this.dabCount = 0}
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
__init18() {this.fieldLut = []}
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
__init19() {this.tip = new Float32Array(0)}
|
|
1124
|
+
__init20() {this.cov = new Float32Array(0)}
|
|
1125
|
+
__init21() {this.field = new Float32Array(0)}
|
|
1126
|
+
__init22() {this.paint = [0, 0, 0]}
|
|
1127
|
+
__init23() {this.lastRaw = null}
|
|
1128
|
+
__init24() {this.lastFed = null}
|
|
1129
|
+
/** What copy 0's brush carries after the dabs so far (mixer and wet-capable dab brushes). */
|
|
1130
|
+
get load() {
|
|
1131
|
+
return _nullishCoalesce(_optionalChain([this, 'access', _6 => _6.states, 'access', _7 => _7[0], 'access', _8 => _8.exchange, 'optionalAccess', _9 => _9.load]), () => ( null));
|
|
1132
|
+
}
|
|
1133
|
+
push(points) {
|
|
1134
|
+
const rects = [];
|
|
1135
|
+
for (const raw of points) {
|
|
1136
|
+
this.lastRaw = raw;
|
|
1137
|
+
const p = this.smoother.push(raw);
|
|
1138
|
+
this.lastFed = p;
|
|
1139
|
+
this.copies.forEach((c, i) => {
|
|
1140
|
+
const dabs = [];
|
|
1141
|
+
this.states[i].walker.push(c.map(p), dabs);
|
|
1142
|
+
this.paintDabs(i, dabs, rects);
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
return rects;
|
|
1146
|
+
}
|
|
1147
|
+
/** Ends the stroke: the smoothed path catches up with the last raw sample; a tap paints one dab. */
|
|
1148
|
+
finish() {
|
|
1149
|
+
const rects = [];
|
|
1150
|
+
const raw = this.lastRaw;
|
|
1151
|
+
const fed = this.lastFed;
|
|
1152
|
+
this.copies.forEach((c, i) => {
|
|
1153
|
+
const dabs = [];
|
|
1154
|
+
if (raw && fed && (raw.x !== fed.x || raw.y !== fed.y)) this.states[i].walker.push(c.map({ ...raw, pressure: fed.pressure }), dabs);
|
|
1155
|
+
this.states[i].walker.finish(dabs);
|
|
1156
|
+
this.paintDabs(i, dabs, rects);
|
|
1157
|
+
});
|
|
1158
|
+
return rects;
|
|
1159
|
+
}
|
|
1160
|
+
paintDabs(copy, dabs, rects) {
|
|
1161
|
+
for (const d of dabs) {
|
|
1162
|
+
const rect = _chunk7VOHOPLWcjs.dabRect.call(void 0, d, this.brush.tip.hardness);
|
|
1163
|
+
if (rect.width <= 0 || rect.height <= 0) continue;
|
|
1164
|
+
this.dab(copy, d, rect);
|
|
1165
|
+
rects.push(rect);
|
|
1166
|
+
this.dabCount++;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
/** The tip's pure coverage (`tip`) and, with grain, what the paper catches of it (`cov`). */
|
|
1170
|
+
rasterize(d, rect) {
|
|
1171
|
+
const n = rect.width * rect.height;
|
|
1172
|
+
if (this.tip.length < n) {
|
|
1173
|
+
this.tip = new Float32Array(n);
|
|
1174
|
+
this.cov = new Float32Array(n);
|
|
1175
|
+
}
|
|
1176
|
+
const tip = this.tip.subarray(0, n);
|
|
1177
|
+
tip.fill(0);
|
|
1178
|
+
_chunk7VOHOPLWcjs.rasterizeDab.call(void 0, { ...d, alpha: 1 }, this.brush.tip.hardness, rect, tip);
|
|
1179
|
+
if (!(this.depth > 0 && this.options.grain)) return { tip, cov: tip };
|
|
1180
|
+
const cov = this.cov.subarray(0, n);
|
|
1181
|
+
const grain = this.options.grain;
|
|
1182
|
+
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
1183
|
+
const y = rect.y + yy + 0.5;
|
|
1184
|
+
for (let xx = 0; xx < rect.width; xx++, k++) cov[k] = tip[k] > 0 ? tip[k] * grainCatch(grain.at(rect.x + xx + 0.5, y), this.depth, d.pressure) : 0;
|
|
1185
|
+
}
|
|
1186
|
+
return { tip, cov };
|
|
1187
|
+
}
|
|
1188
|
+
dab(copy, d, rect) {
|
|
1189
|
+
const brush = this.brush;
|
|
1190
|
+
const { tip, cov } = this.rasterize(d, rect);
|
|
1191
|
+
const st = this.states[copy];
|
|
1192
|
+
if (brush.engine === "blender") {
|
|
1193
|
+
_chunk7VOHOPLWcjs.blenderDab.call(void 0, this.medium, rect, cov, d.opacity * d.alpha * brush.tip.opacity, d.radius, brush.blender, this.scratch);
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
if (brush.engine === "smudge") {
|
|
1197
|
+
st.smudge.dab(this.medium, { x: d.x, y: d.y, radius: d.radius, opacity: d.opacity * d.alpha * brush.tip.opacity }, rect, cov);
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
const ex = st.exchange;
|
|
1201
|
+
ex.pickUp(this.medium.sample(rect, tip));
|
|
1202
|
+
const mc = brush.behavior.multicolor;
|
|
1203
|
+
if (this.palette && mc.mode === "dab") {
|
|
1204
|
+
const c = multiColorForDab(mc, this.palette, d.index, _nullishCoalesce(this.options.seed, () => ( 0)), this.mixing);
|
|
1205
|
+
ex.setReservoirColor(c[0], c[1], c[2]);
|
|
1206
|
+
}
|
|
1207
|
+
let field = null;
|
|
1208
|
+
let total;
|
|
1209
|
+
if (this.gradient) {
|
|
1210
|
+
total = this.tipField(ex, d, rect);
|
|
1211
|
+
field = this.field;
|
|
1212
|
+
} else total = ex.paint(this.paint);
|
|
1213
|
+
if (total > 0) {
|
|
1214
|
+
if (this.coverage) this.depositWithCeiling(d, rect, cov, field, ex);
|
|
1215
|
+
else {
|
|
1216
|
+
const dep = Math.min(1, total) * d.alpha * brush.tip.opacity * d.opacity;
|
|
1217
|
+
if (dep > 0) this.medium.deposit(rect, cov, dep, this.paint, ex.paintPigment, field);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
ex.drain();
|
|
1221
|
+
}
|
|
1222
|
+
/** Fills `this.field` with the tip gradient (mixed with the carried paint) per pixel; returns the paint weight. */
|
|
1223
|
+
tipField(ex, d, rect) {
|
|
1224
|
+
const g = this.gradient;
|
|
1225
|
+
const lut = this.fieldLut;
|
|
1226
|
+
let total = 0;
|
|
1227
|
+
for (let j = 0; j < g.length; j++) {
|
|
1228
|
+
ex.setReservoirColor(g[j][0], g[j][1], g[j][2]);
|
|
1229
|
+
const out = _nullishCoalesce(lut[j], () => ( [0, 0, 0]));
|
|
1230
|
+
total = ex.paint(out);
|
|
1231
|
+
lut[j] = out;
|
|
1232
|
+
}
|
|
1233
|
+
const n = rect.width * rect.height;
|
|
1234
|
+
if (this.field.length < n * 3) this.field = new Float32Array(n * 3);
|
|
1235
|
+
const f = this.field;
|
|
1236
|
+
const nx = Math.sin(d.direction);
|
|
1237
|
+
const ny = Math.cos(d.direction);
|
|
1238
|
+
const r = Math.max(0.5, d.radius);
|
|
1239
|
+
const last = g.length - 1;
|
|
1240
|
+
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
1241
|
+
const py = rect.y + yy + 0.5 - d.y;
|
|
1242
|
+
for (let xx = 0; xx < rect.width; xx++, k++) {
|
|
1243
|
+
const u = ((rect.x + xx + 0.5 - d.x) * nx + py * ny) / r;
|
|
1244
|
+
const j = Math.min(last, Math.max(0, Math.round((u + 1) / 2 * last)));
|
|
1245
|
+
f[k * 3] = lut[j][0];
|
|
1246
|
+
f[k * 3 + 1] = lut[j][1];
|
|
1247
|
+
f[k * 3 + 2] = lut[j][2];
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
return total;
|
|
1251
|
+
}
|
|
1252
|
+
/** A dab brush's deposit: only what this dab adds to the stroke's coverage, under its opacity ceiling. */
|
|
1253
|
+
depositWithCeiling(d, rect, cov, field, ex) {
|
|
1254
|
+
const map = this.coverage;
|
|
1255
|
+
const n = rect.width * rect.height;
|
|
1256
|
+
const before = new Float32Array(n);
|
|
1257
|
+
const vals = new Float32Array(n);
|
|
1258
|
+
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
1259
|
+
for (let xx = 0; xx < rect.width; xx++, k++) {
|
|
1260
|
+
if (cov[k] <= 0) continue;
|
|
1261
|
+
before[k] = map.get(rect.x + xx, rect.y + yy);
|
|
1262
|
+
vals[k] = cov[k] * d.alpha;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
map.accumulate(rect, vals, d.opacity);
|
|
1266
|
+
const o = this.brush.tip.opacity;
|
|
1267
|
+
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
1268
|
+
for (let xx = 0; xx < rect.width; xx++, k++) {
|
|
1269
|
+
if (cov[k] <= 0) {
|
|
1270
|
+
vals[k] = 0;
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
const c0 = before[k] * o;
|
|
1274
|
+
const c1 = map.get(rect.x + xx, rect.y + yy) * o;
|
|
1275
|
+
vals[k] = c1 > c0 && c0 < 1 ? (c1 - c0) / (1 - c0) : 0;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
this.medium.deposit(rect, vals, 1, this.paint, ex.paintPigment, field);
|
|
1279
|
+
}
|
|
1280
|
+
}, _class6);
|
|
1281
|
+
|
|
938
1282
|
// src/paint-editor/stroke.ts
|
|
939
1283
|
function defaultTile(surface) {
|
|
940
|
-
const data = new Uint8ClampedArray(
|
|
1284
|
+
const data = new Uint8ClampedArray(_chunkXIOMMGPDcjs.TILE * _chunkXIOMMGPDcjs.TILE * surface.channels);
|
|
941
1285
|
if (surface.defaultValue) data.fill(surface.defaultValue);
|
|
942
1286
|
return data;
|
|
943
1287
|
}
|
|
@@ -954,8 +1298,8 @@ function union(a, b) {
|
|
|
954
1298
|
const y = Math.min(a.y, b.y);
|
|
955
1299
|
return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
|
|
956
1300
|
}
|
|
957
|
-
var PaintStrokeSession = (
|
|
958
|
-
constructor(host, init) {;
|
|
1301
|
+
var PaintStrokeSession = (_class7 = class {
|
|
1302
|
+
constructor(host, init) {;_class7.prototype.__init25.call(this);_class7.prototype.__init26.call(this);_class7.prototype.__init27.call(this);_class7.prototype.__init28.call(this);_class7.prototype.__init29.call(this);_class7.prototype.__init30.call(this);_class7.prototype.__init31.call(this);_class7.prototype.__init32.call(this);_class7.prototype.__init33.call(this);
|
|
959
1303
|
this.host = host;
|
|
960
1304
|
this.init = init;
|
|
961
1305
|
this.layerId = init.layerId;
|
|
@@ -973,10 +1317,18 @@ var PaintStrokeSession = (_class6 = class {
|
|
|
973
1317
|
selection: null,
|
|
974
1318
|
offset: init.offset
|
|
975
1319
|
};
|
|
976
|
-
if (brush.engine === "mixer") {
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1320
|
+
if (brush.engine === "mixer" || brush.engine === "blender" || brush.engine === "smudge" || usesPaintExchange(brush)) {
|
|
1321
|
+
const rgb = (c) => [c[0] / 255, c[1] / 255, c[2] / 255];
|
|
1322
|
+
this.wet = new PaintDabStroke(brush, {
|
|
1323
|
+
target: this.tileTarget(),
|
|
1324
|
+
color: rgb(init.color),
|
|
1325
|
+
secondary: rgb(_nullishCoalesce(init.secondary, () => ( init.background))),
|
|
1326
|
+
load: init.mixerLoad,
|
|
1327
|
+
grain: init.grain,
|
|
1328
|
+
paperDepth: init.paperDepth,
|
|
1329
|
+
seed: init.seed,
|
|
1330
|
+
copies: this.copies
|
|
1331
|
+
});
|
|
980
1332
|
} else {
|
|
981
1333
|
this.dry = new DryStroke(brush, { grain: init.grain, paperDepth: init.paperDepth, seed: init.seed, copies: this.copies });
|
|
982
1334
|
}
|
|
@@ -985,30 +1337,29 @@ var PaintStrokeSession = (_class6 = class {
|
|
|
985
1337
|
|
|
986
1338
|
|
|
987
1339
|
/** The raw input so far (what a replay feeds back in). */
|
|
988
|
-
|
|
1340
|
+
__init25() {this.points = []}
|
|
989
1341
|
|
|
990
1342
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
__init22() {this.mixerSmoother = null}
|
|
1343
|
+
__init26() {this.touched = /* @__PURE__ */ new Set()}
|
|
1344
|
+
__init27() {this.fresh = /* @__PURE__ */ new Set()}
|
|
1345
|
+
__init28() {this.dry = null}
|
|
1346
|
+
__init29() {this.wet = null}
|
|
996
1347
|
|
|
997
1348
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1349
|
+
__init30() {this.bounds = null}
|
|
1350
|
+
__init31() {this.lastRaw = null}
|
|
1351
|
+
__init32() {this.closed = false}
|
|
1352
|
+
__init33() {this.result = null}
|
|
1353
|
+
tileTarget() {
|
|
1003
1354
|
return {
|
|
1004
1355
|
offset: this.init.offset,
|
|
1005
1356
|
lockTransparency: this.init.lockTransparency,
|
|
1006
1357
|
selection: null,
|
|
1007
|
-
readTile: (tx, ty) => _nullishCoalesce(_optionalChain([this, 'access',
|
|
1358
|
+
readTile: (tx, ty) => _nullishCoalesce(_optionalChain([this, 'access', _10 => _10.live, 'access', _11 => _11.get, 'call', _12 => _12(_chunkXIOMMGPDcjs.tileKey.call(void 0, tx, ty)), 'optionalAccess', _13 => _13.data]), () => ( null)),
|
|
1008
1359
|
writeTile: (tx, ty) => {
|
|
1009
|
-
const key =
|
|
1360
|
+
const key = _chunkXIOMMGPDcjs.tileKey.call(void 0, tx, ty);
|
|
1010
1361
|
if (!this.touched.has(key)) {
|
|
1011
|
-
const src = _nullishCoalesce(_optionalChain([this, 'access',
|
|
1362
|
+
const src = _nullishCoalesce(_optionalChain([this, 'access', _14 => _14.base, 'access', _15 => _15.tiles, 'access', _16 => _16.get, 'call', _17 => _17(key), 'optionalAccess', _18 => _18.data]), () => ( defaultTile(this.base)));
|
|
1012
1363
|
this.live.set(key, { data: new Uint8ClampedArray(src), uniform: null });
|
|
1013
1364
|
this.touched.add(key);
|
|
1014
1365
|
}
|
|
@@ -1027,15 +1378,7 @@ var PaintStrokeSession = (_class6 = class {
|
|
|
1027
1378
|
if (filter) points = points.map(filter);
|
|
1028
1379
|
for (const p of points) this.points.push(p);
|
|
1029
1380
|
this.lastRaw = points[points.length - 1];
|
|
1030
|
-
|
|
1031
|
-
else {
|
|
1032
|
-
const rects = [];
|
|
1033
|
-
for (const raw of points) {
|
|
1034
|
-
const p = toStrokePoint(this.mixerSmoother.push(raw));
|
|
1035
|
-
this.copies.forEach((c, i) => rects.push(...this.mixers[i].push([toStrokePoint(c.map(p))])));
|
|
1036
|
-
}
|
|
1037
|
-
this.update(rects);
|
|
1038
|
-
}
|
|
1381
|
+
this.update(this.dry ? this.dry.push(points) : this.wet.push(points));
|
|
1039
1382
|
}
|
|
1040
1383
|
update(rects) {
|
|
1041
1384
|
if (!rects.length) return;
|
|
@@ -1044,57 +1387,47 @@ var PaintStrokeSession = (_class6 = class {
|
|
|
1044
1387
|
if (!this.dry) {
|
|
1045
1388
|
for (const key of this.fresh) this.live.set(key, { data: this.live.get(key).data, uniform: null });
|
|
1046
1389
|
this.fresh.clear();
|
|
1047
|
-
this.host.update(this.layerId, new (0,
|
|
1390
|
+
this.host.update(this.layerId, new (0, _chunkXIOMMGPDcjs.TiledSurface)(ch, new Map(this.live), this.base.defaultValue), rects);
|
|
1048
1391
|
return;
|
|
1049
1392
|
}
|
|
1050
1393
|
const off = this.init.offset;
|
|
1051
1394
|
const regions = /* @__PURE__ */ new Map();
|
|
1052
1395
|
for (const r of rects) {
|
|
1053
|
-
for (const t of
|
|
1054
|
-
const key =
|
|
1396
|
+
for (const t of _chunkXIOMMGPDcjs.tilesInRect.call(void 0, { x: r.x - off.x, y: r.y - off.y, width: r.width, height: r.height })) {
|
|
1397
|
+
const key = _chunkXIOMMGPDcjs.tileKey.call(void 0, t.tx, t.ty);
|
|
1055
1398
|
const cur = regions.get(key);
|
|
1056
1399
|
regions.set(key, { tx: t.tx, ty: t.ty, r: cur ? union(cur.r, r) : r });
|
|
1057
1400
|
}
|
|
1058
1401
|
}
|
|
1059
1402
|
for (const [key, { tx, ty, r }] of regions) {
|
|
1060
|
-
const src = _nullishCoalesce(_optionalChain([this, 'access',
|
|
1061
|
-
const prev = this.touched.has(key) ? _optionalChain([this, 'access',
|
|
1403
|
+
const src = _nullishCoalesce(_optionalChain([this, 'access', _19 => _19.base, 'access', _20 => _20.tiles, 'access', _21 => _21.get, 'call', _22 => _22(key), 'optionalAccess', _23 => _23.data]), () => ( defaultTile(this.base)));
|
|
1404
|
+
const prev = this.touched.has(key) ? _optionalChain([this, 'access', _24 => _24.live, 'access', _25 => _25.get, 'call', _26 => _26(key), 'optionalAccess', _27 => _27.data]) : void 0;
|
|
1062
1405
|
this.touched.add(key);
|
|
1063
|
-
const data =
|
|
1406
|
+
const data = _chunk7VOHOPLWcjs.applyStrokeToTile.call(void 0, this.dry.coverage, src, ch, tx, ty, this.apply, prev ? { into: prev, region: r } : {});
|
|
1064
1407
|
this.live.set(key, { data, uniform: null });
|
|
1065
1408
|
}
|
|
1066
|
-
this.host.update(this.layerId, new (0,
|
|
1409
|
+
this.host.update(this.layerId, new (0, _chunkXIOMMGPDcjs.TiledSurface)(ch, new Map(this.live), this.base.defaultValue), rects);
|
|
1067
1410
|
}
|
|
1068
1411
|
/** Ends the stroke (one undo step) and returns what changed. */
|
|
1069
1412
|
end() {
|
|
1070
1413
|
if (this.closed) throw new Error("This stroke has already ended.");
|
|
1071
|
-
|
|
1072
|
-
else {
|
|
1073
|
-
const rects = [];
|
|
1074
|
-
const last = this.lastRaw ? toStrokePoint(this.lastRaw) : void 0;
|
|
1075
|
-
this.copies.forEach((c, i) => rects.push(...this.mixers[i].finish(last ? toStrokePoint(c.map(last)) : void 0)));
|
|
1076
|
-
this.update(rects);
|
|
1077
|
-
}
|
|
1414
|
+
this.update(this.dry ? this.dry.finish() : this.wet.finish());
|
|
1078
1415
|
this.closed = true;
|
|
1079
1416
|
const ch = this.base.channels;
|
|
1080
1417
|
const tiles = new Map(this.base.tiles);
|
|
1081
1418
|
let changed = false;
|
|
1082
1419
|
for (const key of this.touched) {
|
|
1083
|
-
const tile =
|
|
1420
|
+
const tile = _chunkXIOMMGPDcjs.finishTile.call(void 0, this.live.get(key).data, ch, this.base.defaultValue);
|
|
1084
1421
|
const prev = this.base.tiles.get(key);
|
|
1085
1422
|
if (tile) tiles.set(key, tile);
|
|
1086
1423
|
else tiles.delete(key);
|
|
1087
1424
|
if (!sameTile(prev, tile)) changed = true;
|
|
1088
1425
|
}
|
|
1089
|
-
const surface = changed ? new (0,
|
|
1090
|
-
const dabs = this.dry ? this.dry.dabCount : this.
|
|
1426
|
+
const surface = changed ? new (0, _chunkXIOMMGPDcjs.TiledSurface)(ch, tiles, this.base.defaultValue) : null;
|
|
1427
|
+
const dabs = this.dry ? this.dry.dabCount : this.wet.dabCount;
|
|
1091
1428
|
this.result = { layerId: this.layerId, bounds: changed ? this.bounds : null, dabs, strokeId: null };
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
let load = this.mixers[0].load;
|
|
1095
|
-
if (brush.mixer.cleanEachStroke) load = _chunkHUFQD4CBcjs.cleanMixer.call(void 0, load);
|
|
1096
|
-
this.result.mixerLoad = load;
|
|
1097
|
-
}
|
|
1429
|
+
const carried = _optionalChain([this, 'access', _28 => _28.wet, 'optionalAccess', _29 => _29.load]);
|
|
1430
|
+
if (carried) this.result.mixerLoad = this.init.brush.behavior.dirty ? carried : _chunk7VOHOPLWcjs.cleanMixer.call(void 0, carried);
|
|
1098
1431
|
this.host.commit(this, surface, false);
|
|
1099
1432
|
return this.result;
|
|
1100
1433
|
}
|
|
@@ -1104,12 +1437,17 @@ var PaintStrokeSession = (_class6 = class {
|
|
|
1104
1437
|
this.closed = true;
|
|
1105
1438
|
this.host.commit(this, null, true);
|
|
1106
1439
|
}
|
|
1107
|
-
},
|
|
1440
|
+
}, _class7);
|
|
1108
1441
|
function mixerLoadForStroke(brush, current, color) {
|
|
1109
1442
|
if (!brush.loadsColor) return { reservoir: null, amount: 0, pickup: brush.mixer.cleanEachStroke ? null : current.pickup };
|
|
1110
|
-
if (brush.mixer.loadEachStroke || !current.reservoir) return
|
|
1443
|
+
if (brush.mixer.loadEachStroke || !current.reservoir) return _chunk7VOHOPLWcjs.loadMixer.call(void 0, current, color);
|
|
1111
1444
|
return current;
|
|
1112
1445
|
}
|
|
1446
|
+
function brushLoadForStroke(brush, current, color) {
|
|
1447
|
+
if (brush.engine === "mixer") return mixerLoadForStroke(brush, current, color);
|
|
1448
|
+
if (usesPaintExchange(brush)) return { reservoir: [color[0], color[1], color[2]], amount: 1, pickup: brush.behavior.dirty ? current.pickup : null };
|
|
1449
|
+
return _chunk7VOHOPLWcjs.EMPTY_MIXER_LOAD;
|
|
1450
|
+
}
|
|
1113
1451
|
|
|
1114
1452
|
// src/paint-editor/strokes.ts
|
|
1115
1453
|
var IDENTITY_AFFINE = [1, 0, 0, 1, 0, 0];
|
|
@@ -1155,6 +1493,17 @@ function readPoint(raw) {
|
|
|
1155
1493
|
function readAffine(raw) {
|
|
1156
1494
|
return Array.isArray(raw) && raw.length === 6 && raw.every(finite) ? raw : null;
|
|
1157
1495
|
}
|
|
1496
|
+
function readRgb(raw) {
|
|
1497
|
+
return Array.isArray(raw) && raw.length === 3 && raw.every(finite) ? raw.map((v) => Math.min(1, Math.max(0, v))) : null;
|
|
1498
|
+
}
|
|
1499
|
+
function readLoad(raw) {
|
|
1500
|
+
if (!raw || typeof raw !== "object") return null;
|
|
1501
|
+
const r = raw;
|
|
1502
|
+
const reservoir = readRgb(r.reservoir);
|
|
1503
|
+
const pickup = readRgb(r.pickup);
|
|
1504
|
+
if (!reservoir && !pickup) return null;
|
|
1505
|
+
return { reservoir, amount: reservoir && finite(r.amount) ? Math.min(1, Math.max(0, r.amount)) : 0, pickup };
|
|
1506
|
+
}
|
|
1158
1507
|
function normalizeBrushStroke(raw) {
|
|
1159
1508
|
if (!raw || typeof raw !== "object") return null;
|
|
1160
1509
|
const r = raw;
|
|
@@ -1171,6 +1520,8 @@ function normalizeBrushStroke(raw) {
|
|
|
1171
1520
|
};
|
|
1172
1521
|
const copies = Array.isArray(r.copies) ? r.copies.map(readAffine).filter((m) => m !== null) : [];
|
|
1173
1522
|
if (copies.length) out.copies = copies;
|
|
1523
|
+
const load = readLoad(r.load);
|
|
1524
|
+
if (load) out.load = load;
|
|
1174
1525
|
return out;
|
|
1175
1526
|
}
|
|
1176
1527
|
function strokeBounds(points) {
|
|
@@ -1207,7 +1558,7 @@ function varyStroke(stroke, m, v) {
|
|
|
1207
1558
|
});
|
|
1208
1559
|
const brush = s !== 1 ? normalizePaintBrush({ ...stroke.brush, tip: { ...stroke.brush.tip, size: stroke.brush.tip.size * s } }) : stroke.brush;
|
|
1209
1560
|
const out = { ...stroke, brush, points };
|
|
1210
|
-
if (_optionalChain([stroke, 'access',
|
|
1561
|
+
if (_optionalChain([stroke, 'access', _30 => _30.copies, 'optionalAccess', _31 => _31.length])) {
|
|
1211
1562
|
const inv = invertAffine(m);
|
|
1212
1563
|
out.copies = stroke.copies.map((c) => composeAffine(m, composeAffine(c, inv)));
|
|
1213
1564
|
}
|
|
@@ -1274,7 +1625,7 @@ var PROFILE = {
|
|
|
1274
1625
|
}
|
|
1275
1626
|
};
|
|
1276
1627
|
function createPaintCompositor() {
|
|
1277
|
-
return new (0,
|
|
1628
|
+
return new (0, _chunkPOGBUYWEcjs.RasterCompositor)(PROFILE);
|
|
1278
1629
|
}
|
|
1279
1630
|
function downsampleRgba(data, width, height, tw, th) {
|
|
1280
1631
|
tw = Math.max(1, Math.round(tw));
|
|
@@ -1322,7 +1673,7 @@ function downsampleRgba(data, width, height, tw, th) {
|
|
|
1322
1673
|
// src/paint-editor/serialize.ts
|
|
1323
1674
|
var PAINT_FORMAT = "pixerate-paint";
|
|
1324
1675
|
var PAINT_SCHEMA_VERSION = 1;
|
|
1325
|
-
var KNOWN = /* @__PURE__ */ new Set(["format", "version", "width", "height", "dpi", "paper", "layers", "assets", "activeLayerId", "strokes", "guides", "swatches"]);
|
|
1676
|
+
var KNOWN = /* @__PURE__ */ new Set(["format", "version", "width", "height", "dpi", "paper", "layers", "assets", "activeLayerId", "strokes", "guides", "swatches", "mixingPad"]);
|
|
1326
1677
|
function documentExtensions(raw) {
|
|
1327
1678
|
const out = {};
|
|
1328
1679
|
for (const [k, v] of Object.entries(raw)) if (!KNOWN.has(k)) out[k] = v;
|
|
@@ -1342,14 +1693,15 @@ function header(state, options) {
|
|
|
1342
1693
|
if (options.strokes !== false && state.strokes.length) out.strokes = JSON.parse(JSON.stringify(state.strokes));
|
|
1343
1694
|
if (options.guides !== void 0) out.guides = JSON.parse(JSON.stringify(options.guides));
|
|
1344
1695
|
if (options.swatches !== void 0) out.swatches = JSON.parse(JSON.stringify(options.swatches));
|
|
1696
|
+
if (options.mixingPad !== void 0) out.mixingPad = JSON.parse(JSON.stringify(options.mixingPad));
|
|
1345
1697
|
return out;
|
|
1346
1698
|
}
|
|
1347
1699
|
function serializePaintDocument(state, options = {}) {
|
|
1348
|
-
const { layers, assets } =
|
|
1700
|
+
const { layers, assets } = _chunkMGL4U5WAcjs.serializeLayers.call(void 0, state.layers);
|
|
1349
1701
|
return { ...header(state, options), layers, assets };
|
|
1350
1702
|
}
|
|
1351
1703
|
async function serializePaintDocumentExternal(state, store, options = {}) {
|
|
1352
|
-
const { layers, assets } = await
|
|
1704
|
+
const { layers, assets } = await _chunkMGL4U5WAcjs.serializeLayersExternal.call(void 0, state.layers, store);
|
|
1353
1705
|
return { ...header(state, options), layers, assets };
|
|
1354
1706
|
}
|
|
1355
1707
|
function paintLayersOnly(layers, problems) {
|
|
@@ -1357,7 +1709,7 @@ function paintLayersOnly(layers, problems) {
|
|
|
1357
1709
|
for (const l of layers) {
|
|
1358
1710
|
if (l.type === "pixel") {
|
|
1359
1711
|
const { filters, source, ...rest } = l;
|
|
1360
|
-
if (_optionalChain([filters, 'optionalAccess',
|
|
1712
|
+
if (_optionalChain([filters, 'optionalAccess', _32 => _32.length])) problems.push(`Layer "${l.name}": its filters are an image editor feature and were dropped.`);
|
|
1361
1713
|
if (source) problems.push(`Layer "${l.name}" refers to an image editor source image; it loads empty.`);
|
|
1362
1714
|
out.push(rest);
|
|
1363
1715
|
} else if (l.type === "group") out.push({ ...l, children: paintLayersOnly(l.children, problems) });
|
|
@@ -1386,16 +1738,16 @@ function deserializePaintDocument(raw) {
|
|
|
1386
1738
|
const canvas = normalizeCanvas({ width: r.width, height: r.height, dpi: _nullishCoalesce(r.dpi, () => ( void 0)) });
|
|
1387
1739
|
const paper = normalizePaper(_nullishCoalesce(r.paper, () => ( {})));
|
|
1388
1740
|
const assets = r.assets && typeof r.assets === "object" ? r.assets : {};
|
|
1389
|
-
const layers = paintLayersOnly(
|
|
1741
|
+
const layers = paintLayersOnly(_chunkMGL4U5WAcjs.deserializeLayers.call(void 0, r.layers, { assets, problems }), problems);
|
|
1390
1742
|
const wanted = typeof r.activeLayerId === "string" ? r.activeLayerId : null;
|
|
1391
|
-
const activeLayerId = wanted &&
|
|
1392
|
-
return { state: { canvas, paper, layers, activeLayerId, strokes: readStrokes(r.strokes, problems) }, extensions: documentExtensions(r), guides: r.guides, swatches: r.swatches, problems };
|
|
1743
|
+
const activeLayerId = wanted && _chunkPOGBUYWEcjs.findLayer.call(void 0, layers, wanted) ? wanted : _nullishCoalesce(_optionalChain([_chunkPOGBUYWEcjs.flattenLayers.call(void 0, layers), 'access', _33 => _33.filter, 'call', _34 => _34((l) => l.type === "pixel"), 'access', _35 => _35.pop, 'call', _36 => _36(), 'optionalAccess', _37 => _37.id]), () => ( null));
|
|
1744
|
+
return { state: { canvas, paper, layers, activeLayerId, strokes: readStrokes(r.strokes, problems) }, extensions: documentExtensions(r), guides: r.guides, swatches: r.swatches, mixingPad: r.mixingPad, problems };
|
|
1393
1745
|
}
|
|
1394
1746
|
async function deserializePaintDocumentAsync(raw, store) {
|
|
1395
1747
|
if (!raw || typeof raw !== "object") throw new Error("Not a paint document: expected a JSON object.");
|
|
1396
1748
|
const r = raw;
|
|
1397
1749
|
const problems = [];
|
|
1398
|
-
const assets = await
|
|
1750
|
+
const assets = await _chunkMGL4U5WAcjs.resolveExternalAssets.call(void 0, _nullishCoalesce(r.assets, () => ( {})), store, problems);
|
|
1399
1751
|
const loaded = deserializePaintDocument({ ...r, assets });
|
|
1400
1752
|
return { ...loaded, problems: [...problems, ...loaded.problems] };
|
|
1401
1753
|
}
|
|
@@ -1527,7 +1879,7 @@ async function decodeImageBlob(blob) {
|
|
|
1527
1879
|
if (!ctx) throw new Error("No 2D context to decode with.");
|
|
1528
1880
|
ctx.drawImage(bitmap, 0, 0);
|
|
1529
1881
|
const data = new Uint8ClampedArray(ctx.getImageData(0, 0, bitmap.width, bitmap.height).data);
|
|
1530
|
-
_optionalChain([bitmap, 'access',
|
|
1882
|
+
_optionalChain([bitmap, 'access', _38 => _38.close, 'optionalCall', _39 => _39()]);
|
|
1531
1883
|
return { width: bitmap.width, height: bitmap.height, data };
|
|
1532
1884
|
}
|
|
1533
1885
|
function downloadBytes(bytes, fileName, mimeType) {
|
|
@@ -1574,7 +1926,7 @@ function paintTestStroke(surface, brush, paper, color, width, height) {
|
|
|
1574
1926
|
colorHex: color,
|
|
1575
1927
|
affineCopies: [],
|
|
1576
1928
|
copies: [IDENTITY_COPY],
|
|
1577
|
-
mixerLoad:
|
|
1929
|
+
mixerLoad: brushLoadForStroke(brush, _chunk7VOHOPLWcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255])
|
|
1578
1930
|
}
|
|
1579
1931
|
);
|
|
1580
1932
|
session.push(thumbnailStroke(width, height));
|
|
@@ -1587,13 +1939,13 @@ function renderBrushThumbnail(brush, options) {
|
|
|
1587
1939
|
const maxSize = height * 0.42;
|
|
1588
1940
|
const b = brush.tip.size > maxSize ? normalizePaintBrush({ tip: { ...brush.tip, size: maxSize } }, brush) : brush;
|
|
1589
1941
|
const rgba = [...hexToRgb8(options.color), 255];
|
|
1590
|
-
let surface =
|
|
1942
|
+
let surface = _chunkXIOMMGPDcjs.emptySurface.call(void 0, 4);
|
|
1591
1943
|
if (b.engine === "eraser") {
|
|
1592
|
-
surface =
|
|
1593
|
-
} else if (b.engine === "mixer" && !b.loadsColor) {
|
|
1944
|
+
surface = _chunkXIOMMGPDcjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height }, rgba);
|
|
1945
|
+
} else if (b.engine === "blender" || b.engine === "smudge" || b.engine === "mixer" && !b.loadsColor || b.behavior.pickup > 0) {
|
|
1594
1946
|
const half = Math.ceil(height / 2);
|
|
1595
|
-
surface =
|
|
1596
|
-
surface =
|
|
1947
|
+
surface = _chunkXIOMMGPDcjs.fillRect.call(void 0, surface, { x: 0, y: 0, width, height: half }, rgba);
|
|
1948
|
+
surface = _chunkXIOMMGPDcjs.fillRect.call(void 0, surface, { x: 0, y: half, width, height: height - half }, [232, 196, 64, 255]);
|
|
1597
1949
|
}
|
|
1598
1950
|
surface = paintTestStroke(surface, b, options.paper, options.color, width, height);
|
|
1599
1951
|
const layer = { type: "pixel", id: "thumbnail", name: "thumbnail", visible: true, opacity: 1, blend: "normal", surface, offset: { x: 0, y: 0 } };
|
|
@@ -1725,13 +2077,13 @@ function perspectiveDirections(g, p) {
|
|
|
1725
2077
|
return out;
|
|
1726
2078
|
}
|
|
1727
2079
|
var SNAP_DECIDE_DISTANCE = 6;
|
|
1728
|
-
var PerspectiveSnapper = (
|
|
1729
|
-
constructor(guide) {;
|
|
2080
|
+
var PerspectiveSnapper = (_class8 = class {
|
|
2081
|
+
constructor(guide) {;_class8.prototype.__init34.call(this);_class8.prototype.__init35.call(this);
|
|
1730
2082
|
this.guide = guide;
|
|
1731
2083
|
}
|
|
1732
2084
|
|
|
1733
|
-
|
|
1734
|
-
|
|
2085
|
+
__init34() {this.start = null}
|
|
2086
|
+
__init35() {this.dir = null}
|
|
1735
2087
|
/** The line the stroke follows, once chosen. */
|
|
1736
2088
|
get line() {
|
|
1737
2089
|
return this.start && this.dir ? { from: this.start, direction: this.dir } : null;
|
|
@@ -1764,7 +2116,7 @@ var PerspectiveSnapper = (_class7 = class {
|
|
|
1764
2116
|
const t = (p.x - s.x) * d.x + (p.y - s.y) * d.y;
|
|
1765
2117
|
return { ...p, x: s.x + d.x * t, y: s.y + d.y * t };
|
|
1766
2118
|
}
|
|
1767
|
-
},
|
|
2119
|
+
}, _class8);
|
|
1768
2120
|
function perspectiveGuideLines(g, size, count = 12) {
|
|
1769
2121
|
const out = [];
|
|
1770
2122
|
const far = Math.hypot(size.width, size.height) * 4;
|
|
@@ -1783,9 +2135,9 @@ function perspectiveGuideLines(g, size, count = 12) {
|
|
|
1783
2135
|
}
|
|
1784
2136
|
|
|
1785
2137
|
// src/paint-editor/color.ts
|
|
1786
|
-
var
|
|
2138
|
+
var HEX3 = /^#?([0-9a-f]{6})$/i;
|
|
1787
2139
|
function parseHexColor(value, what = "color") {
|
|
1788
|
-
const m = typeof value === "string" ?
|
|
2140
|
+
const m = typeof value === "string" ? HEX3.exec(value.trim()) : null;
|
|
1789
2141
|
if (!m) throw new Error(`${what} is ${JSON.stringify(value)}; use #rrggbb, e.g. "#2a4b8d".`);
|
|
1790
2142
|
const n = parseInt(m[1], 16);
|
|
1791
2143
|
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
@@ -1913,17 +2265,25 @@ var PAD_KNIFE = normalizePaintBrush({
|
|
|
1913
2265
|
id: "pad-knife",
|
|
1914
2266
|
name: "Palette knife",
|
|
1915
2267
|
category: "smudge",
|
|
1916
|
-
engine: "
|
|
2268
|
+
engine: "smudge",
|
|
1917
2269
|
loadsColor: false,
|
|
1918
|
-
tip: { size: 34, hardness: 0.9, spacing: 0.08, roundness: 0.35, angle: 90, opacity: 1, flow:
|
|
1919
|
-
|
|
2270
|
+
tip: { size: 34, hardness: 0.9, spacing: 0.08, roundness: 0.35, angle: 90, opacity: 1, flow: 1, pressureSize: false, pressureOpacity: false },
|
|
2271
|
+
// A knife drags streaks of paint and folds them into each other, mixing them as pigment.
|
|
2272
|
+
smudge: { strength: 0.6, length: 0.8, mixing: "pigment" }
|
|
2273
|
+
});
|
|
2274
|
+
var PAD_BLOB = normalizePaintBrush({
|
|
2275
|
+
id: "pad-blob",
|
|
2276
|
+
name: "Pad blob",
|
|
2277
|
+
category: "custom",
|
|
2278
|
+
engine: "dab",
|
|
2279
|
+
tip: { size: 20, hardness: 1, spacing: 0.1, opacity: 1, flow: 1, pressureSize: false, pressureOpacity: false }
|
|
1920
2280
|
});
|
|
1921
|
-
var MixingPad = (
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2281
|
+
var MixingPad = (_class9 = class {constructor() { _class9.prototype.__init36.call(this);_class9.prototype.__init37.call(this);_class9.prototype.__init38.call(this);_class9.prototype.__init39.call(this); }
|
|
2282
|
+
__init36() {this.width = MIXING_PAD_WIDTH}
|
|
2283
|
+
__init37() {this.height = MIXING_PAD_HEIGHT}
|
|
2284
|
+
__init38() {this.surface = _chunkXIOMMGPDcjs.emptySurface.call(void 0, 4)}
|
|
1925
2285
|
/** Increments on every change (for redrawing). */
|
|
1926
|
-
|
|
2286
|
+
__init39() {this.version = 0}
|
|
1927
2287
|
/** Paints (`paint`, with `color`) or smears (`knife`) through `points` in pad pixels. */
|
|
1928
2288
|
stroke(points, options) {
|
|
1929
2289
|
if (!points.length) throw new Error("points is empty; give at least one {x, y} in pad pixels.");
|
|
@@ -1934,7 +2294,11 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.cal
|
|
|
1934
2294
|
}
|
|
1935
2295
|
let brush = options.tool === "knife" ? PAD_KNIFE : PAD_PAINT;
|
|
1936
2296
|
if (options.size !== void 0) brush = normalizePaintBrush({ tip: { ...brush.tip, size: options.size } }, brush);
|
|
1937
|
-
|
|
2297
|
+
return this.run(brush, points, options.color);
|
|
2298
|
+
}
|
|
2299
|
+
/** Paints `points` with `brush` in `color` on the pad. */
|
|
2300
|
+
run(brush, points, color) {
|
|
2301
|
+
const [r, g, b] = hexToRgb8(color);
|
|
1938
2302
|
let result = null;
|
|
1939
2303
|
const session = new PaintStrokeSession(
|
|
1940
2304
|
{ update: () => {
|
|
@@ -1950,10 +2314,10 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.cal
|
|
|
1950
2314
|
grain: null,
|
|
1951
2315
|
paperDepth: 0,
|
|
1952
2316
|
seed: 1,
|
|
1953
|
-
colorHex:
|
|
2317
|
+
colorHex: color,
|
|
1954
2318
|
affineCopies: [],
|
|
1955
2319
|
copies: [IDENTITY_COPY],
|
|
1956
|
-
mixerLoad:
|
|
2320
|
+
mixerLoad: brushLoadForStroke(brush, _chunk7VOHOPLWcjs.EMPTY_MIXER_LOAD, [r / 255, g / 255, b / 255])
|
|
1957
2321
|
}
|
|
1958
2322
|
);
|
|
1959
2323
|
session.push(points);
|
|
@@ -1972,7 +2336,7 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.cal
|
|
|
1972
2336
|
const y0 = Math.max(0, Math.floor(y) - r);
|
|
1973
2337
|
const x1 = Math.min(this.width, Math.floor(x) + r + 1);
|
|
1974
2338
|
const y1 = Math.min(this.height, Math.floor(y) + r + 1);
|
|
1975
|
-
const px =
|
|
2339
|
+
const px = _chunkXIOMMGPDcjs.readRegion.call(void 0, this.surface, { x: x0, y: y0, width: x1 - x0, height: y1 - y0 });
|
|
1976
2340
|
let R = 0;
|
|
1977
2341
|
let G = 0;
|
|
1978
2342
|
let B = 0;
|
|
@@ -1989,12 +2353,88 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.cal
|
|
|
1989
2353
|
return `#${hex(R)}${hex(G)}${hex(B)}`;
|
|
1990
2354
|
}
|
|
1991
2355
|
clear() {
|
|
1992
|
-
this.surface =
|
|
2356
|
+
this.surface = _chunkXIOMMGPDcjs.emptySurface.call(void 0, 4);
|
|
2357
|
+
this.version++;
|
|
2358
|
+
}
|
|
2359
|
+
/**
|
|
2360
|
+
* Mixes paints the way a painter does on a palette: blobs whose areas are in proportion to
|
|
2361
|
+
* their parts, side by side around (x, y), spiral knife passes that fold them together, and then the centre worked until it is fully mixed: a soft-edged core
|
|
2362
|
+
* of the Kubelka-Munk mix of the parts (`mixPigments`), with partly mixed streaks around it.
|
|
2363
|
+
* Returns that colour (picked back from the centre) and the pile's bounds.
|
|
2364
|
+
*
|
|
2365
|
+
* The core is laid, not smeared, because smearing alone drifts: the knife samples in RGB and a
|
|
2366
|
+
* mixed colour's scattering is re-estimated from its luminance, so repeated small mixes favour
|
|
2367
|
+
* the lighter paint (see GOTCHAS).
|
|
2368
|
+
*/
|
|
2369
|
+
mix(paints, options = {}) {
|
|
2370
|
+
if (!paints.length || paints.length > 8) throw new Error(`Give 1 to 8 paints to mix; got ${paints.length}.`);
|
|
2371
|
+
const total = paints.reduce((n, p) => n + p.parts, 0);
|
|
2372
|
+
paints.forEach((p, i) => {
|
|
2373
|
+
if (!(Number.isFinite(p.parts) && p.parts >= 0)) throw new Error(`paints[${i}].parts is ${p.parts}; use a number \u2265 0.`);
|
|
2374
|
+
});
|
|
2375
|
+
if (!(total > 0)) throw new Error("Every paint has 0 parts; give at least one paint parts above 0.");
|
|
2376
|
+
const R = _nullishCoalesce(options.radius, () => ( 40));
|
|
2377
|
+
if (!(R >= 12 && R <= 100)) throw new Error(`radius ${R} is out of range; use 12..100 pad px.`);
|
|
2378
|
+
const passes = _nullishCoalesce(options.passes, () => ( 3));
|
|
2379
|
+
if (!(Number.isInteger(passes) && passes >= 1 && passes <= 20)) throw new Error(`passes ${passes} is out of range; use a whole number 1..20.`);
|
|
2380
|
+
const cx = _nullishCoalesce(options.x, () => ( this.width / 2));
|
|
2381
|
+
const cy = _nullishCoalesce(options.y, () => ( this.height / 2));
|
|
2382
|
+
if (!(cx - R >= 0 && cy - R >= 0 && cx + R <= this.width && cy + R <= this.height)) {
|
|
2383
|
+
throw new Error(`A pile of radius ${R} at (${cx}, ${cy}) does not fit on the ${this.width}\xD7${this.height} pad; move it at least ${R} px from every edge or use a smaller radius.`);
|
|
2384
|
+
}
|
|
2385
|
+
const bounds = { x: Math.floor(cx - R), y: Math.floor(cy - R), width: Math.ceil(2 * R), height: Math.ceil(2 * R) };
|
|
2386
|
+
if (options.clear !== false) this.surface = _chunkXIOMMGPDcjs.writeRegion.call(void 0, this.surface, bounds, new Uint8ClampedArray(bounds.width * bounds.height * 4));
|
|
2387
|
+
const used = paints.filter((p) => p.parts > 0);
|
|
2388
|
+
const area = Math.PI * (0.7 * R) ** 2;
|
|
2389
|
+
used.forEach((p, i) => {
|
|
2390
|
+
const r = Math.sqrt(area * (p.parts / total) / Math.PI);
|
|
2391
|
+
const a = i / used.length * Math.PI * 2;
|
|
2392
|
+
const off = used.length === 1 ? 0 : 0.45 * R;
|
|
2393
|
+
const x = Math.min(cx + R - r, Math.max(cx - R + r, cx + Math.cos(a) * off));
|
|
2394
|
+
const y = Math.min(cy + R - r, Math.max(cy - R + r, cy + Math.sin(a) * off));
|
|
2395
|
+
const blob = normalizePaintBrush({ tip: { ...PAD_BLOB.tip, size: Math.max(2, 2 * r) } }, PAD_BLOB);
|
|
2396
|
+
this.run(blob, [{ x, y }], p.color.toLowerCase());
|
|
2397
|
+
});
|
|
2398
|
+
const knife = normalizePaintBrush({ tip: { ...PAD_KNIFE.tip, size: Math.max(12, R * 0.5) } }, PAD_KNIFE);
|
|
2399
|
+
for (let k = 0; k < passes; k++) {
|
|
2400
|
+
const stir = [];
|
|
2401
|
+
const turns = 1.6;
|
|
2402
|
+
for (let t = 0; t <= 48; t++) {
|
|
2403
|
+
const a = t / 48 * Math.PI * 2 * turns + k * 1.3;
|
|
2404
|
+
const rr = R * (0.85 - 0.6 * (t / 48));
|
|
2405
|
+
stir.push({ x: cx + Math.cos(a) * rr, y: cy + Math.sin(a) * rr });
|
|
2406
|
+
}
|
|
2407
|
+
this.run(knife, stir, "#000000");
|
|
2408
|
+
}
|
|
2409
|
+
const mixed = _chunkXIOMMGPDcjs.mixPigments.call(void 0,
|
|
2410
|
+
paints.map((p) => hexToRgb8(p.color).map((v) => v / 255)),
|
|
2411
|
+
paints.map((p) => p.parts)
|
|
2412
|
+
);
|
|
2413
|
+
const core = normalizePaintBrush({ tip: { ...PAD_BLOB.tip, size: R * 1.1, hardness: 0.55 } }, PAD_BLOB);
|
|
2414
|
+
const hex = "#" + mixed.map((v) => Math.round(v * 255).toString(16).padStart(2, "0")).join("");
|
|
2415
|
+
this.run(core, [{ x: cx, y: cy }], hex);
|
|
2416
|
+
return { color: this.pick(cx, cy, 2), bounds };
|
|
2417
|
+
}
|
|
2418
|
+
/** The pad's pixels as a PNG data URL (with alpha), for saving. */
|
|
2419
|
+
toPng() {
|
|
2420
|
+
return _chunkPOGBUYWEcjs.pngDataUrl.call(void 0, this.width, this.height, _chunkXIOMMGPDcjs.readRegion.call(void 0, this.surface, { x: 0, y: 0, width: this.width, height: this.height }));
|
|
2421
|
+
}
|
|
2422
|
+
/** Replaces the pad with a PNG (data URL or base64) of the pad's size, as `toPng` writes. */
|
|
2423
|
+
fromPng(png) {
|
|
2424
|
+
const bytes = png.startsWith("data:") ? _optionalChain([_chunkPOGBUYWEcjs.parseDataUrl.call(void 0, png), 'optionalAccess', _40 => _40.bytes]) : _chunkPOGBUYWEcjs.base64ToBytes.call(void 0, png);
|
|
2425
|
+
if (!bytes || !_chunkPOGBUYWEcjs.isPng.call(void 0, bytes)) throw new Error("The pad image is not a PNG data URL or base64 PNG.");
|
|
2426
|
+
const img = _chunkPOGBUYWEcjs.decodePng.call(void 0, bytes);
|
|
2427
|
+
if (img.width !== this.width || img.height !== this.height) throw new Error(`The pad image is ${img.width}\xD7${img.height}; a mixing pad is ${this.width}\xD7${this.height}.`);
|
|
2428
|
+
this.surface = _chunkXIOMMGPDcjs.surfaceFromPixels.call(void 0, { width: img.width, height: img.height, data: img.data }, 4);
|
|
1993
2429
|
this.version++;
|
|
1994
2430
|
}
|
|
2431
|
+
/** Whether nothing is on the pad. */
|
|
2432
|
+
get empty() {
|
|
2433
|
+
return this.surface.tiles.size === 0;
|
|
2434
|
+
}
|
|
1995
2435
|
/** The pad over white, `width × height` RGBA. */
|
|
1996
2436
|
pixels() {
|
|
1997
|
-
const px =
|
|
2437
|
+
const px = _chunkXIOMMGPDcjs.readRegion.call(void 0, this.surface, { x: 0, y: 0, width: this.width, height: this.height });
|
|
1998
2438
|
for (let i = 0; i < px.length; i += 4) {
|
|
1999
2439
|
const a = px[i + 3] / 255;
|
|
2000
2440
|
px[i] = Math.round(px[i] * a + 255 * (1 - a));
|
|
@@ -2004,7 +2444,7 @@ var MixingPad = (_class8 = class {constructor() { _class8.prototype.__init29.cal
|
|
|
2004
2444
|
}
|
|
2005
2445
|
return px;
|
|
2006
2446
|
}
|
|
2007
|
-
},
|
|
2447
|
+
}, _class9);
|
|
2008
2448
|
|
|
2009
2449
|
// src/paint-editor/controller.ts
|
|
2010
2450
|
var PaintEditorError = class extends Error {
|
|
@@ -2013,9 +2453,9 @@ var PaintEditorError = class extends Error {
|
|
|
2013
2453
|
this.name = "PaintEditorError";
|
|
2014
2454
|
}
|
|
2015
2455
|
};
|
|
2016
|
-
var
|
|
2456
|
+
var HEX4 = /^#[0-9a-f]{6}$/i;
|
|
2017
2457
|
function parseColor(value, what = "color") {
|
|
2018
|
-
if (typeof value !== "string" || !
|
|
2458
|
+
if (typeof value !== "string" || !HEX4.test(value.trim())) throw new PaintEditorError(`${what} is ${JSON.stringify(value)}; use #rrggbb, e.g. "#2a4b8d".`);
|
|
2019
2459
|
return value.trim().toLowerCase();
|
|
2020
2460
|
}
|
|
2021
2461
|
function rgbaOf(hex) {
|
|
@@ -2032,40 +2472,44 @@ function unionRect(a, b) {
|
|
|
2032
2472
|
const y = Math.min(a.y, b.y);
|
|
2033
2473
|
return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
|
|
2034
2474
|
}
|
|
2035
|
-
var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess',
|
|
2036
|
-
var PaintEditorController = (
|
|
2475
|
+
var isPixelLayer = (l) => _optionalChain([l, 'optionalAccess', _41 => _41.type]) === "pixel";
|
|
2476
|
+
var PaintEditorController = (_class10 = class {
|
|
2037
2477
|
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2478
|
+
__init40() {this.extensions = {}}
|
|
2479
|
+
__init41() {this.undoStack = []}
|
|
2480
|
+
__init42() {this.redoStack = []}
|
|
2041
2481
|
|
|
2042
2482
|
|
|
2043
2483
|
|
|
2484
|
+
/** The library list in the state (the same array until the user brushes change, so thumbnails are not redrawn). */
|
|
2485
|
+
__init43() {this.library = null}
|
|
2044
2486
|
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2487
|
+
__init44() {this.secondaryColor = "#ffffff"}
|
|
2488
|
+
__init45() {this.mixerLoad = _chunk7VOHOPLWcjs.EMPTY_MIXER_LOAD}
|
|
2489
|
+
__init46() {this.view = { ...DEFAULT_VIEW, pan: { ...DEFAULT_VIEW.pan } }}
|
|
2048
2490
|
|
|
2049
2491
|
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2492
|
+
__init47() {this.listeners = /* @__PURE__ */ new Set()}
|
|
2493
|
+
__init48() {this.version = 0}
|
|
2494
|
+
__init49() {this.cached = null}
|
|
2495
|
+
__init50() {this.session = null}
|
|
2496
|
+
__init51() {this.live = null}
|
|
2497
|
+
__init52() {this.liveLayers = null}
|
|
2498
|
+
__init53() {this.dirty = "all"}
|
|
2499
|
+
__init54() {this.seedCounter = 1}
|
|
2500
|
+
__init55() {this.strokeCounter = 1}
|
|
2059
2501
|
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2502
|
+
__init56() {this.swatches = DEFAULT_SWATCHES.map((s) => ({ ...s }))}
|
|
2503
|
+
__init57() {this.pad = new MixingPad()}
|
|
2504
|
+
__init58() {this.savedPads = []}
|
|
2505
|
+
__init59() {this.nextPadId = 1}
|
|
2506
|
+
__init60() {this.tracingVersion = 1}
|
|
2507
|
+
__init61() {this.tracingCache = null}
|
|
2508
|
+
__init62() {this.imagePixels = /* @__PURE__ */ new Map()}
|
|
2509
|
+
__init63() {this.nextReferenceId = 1}
|
|
2510
|
+
__init64() {this.viewCompositor = createPaintCompositor()}
|
|
2511
|
+
__init65() {this.exportCompositor = createPaintCompositor()}
|
|
2512
|
+
constructor(options = {}) {;_class10.prototype.__init40.call(this);_class10.prototype.__init41.call(this);_class10.prototype.__init42.call(this);_class10.prototype.__init43.call(this);_class10.prototype.__init44.call(this);_class10.prototype.__init45.call(this);_class10.prototype.__init46.call(this);_class10.prototype.__init47.call(this);_class10.prototype.__init48.call(this);_class10.prototype.__init49.call(this);_class10.prototype.__init50.call(this);_class10.prototype.__init51.call(this);_class10.prototype.__init52.call(this);_class10.prototype.__init53.call(this);_class10.prototype.__init54.call(this);_class10.prototype.__init55.call(this);_class10.prototype.__init56.call(this);_class10.prototype.__init57.call(this);_class10.prototype.__init58.call(this);_class10.prototype.__init59.call(this);_class10.prototype.__init60.call(this);_class10.prototype.__init61.call(this);_class10.prototype.__init62.call(this);_class10.prototype.__init63.call(this);_class10.prototype.__init64.call(this);_class10.prototype.__init65.call(this);
|
|
2069
2513
|
this.historyLimit = Math.max(1, _nullishCoalesce(options.historyLimit, () => ( 200)));
|
|
2070
2514
|
this.doc = createPaintDocument({ width: options.width, height: options.height, dpi: options.dpi, paper: this.resolvePaper(options.paper) });
|
|
2071
2515
|
this.userBrushes = (_nullishCoalesce(options.brushes, () => ( []))).map((b) => normalizePaintBrush({ ...b, builtin: false }));
|
|
@@ -2096,7 +2540,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2096
2540
|
this.cached = {
|
|
2097
2541
|
document: this.doc,
|
|
2098
2542
|
brush: this.brush,
|
|
2099
|
-
brushes: [...BUILTIN_BRUSHES, ...this.userBrushes],
|
|
2543
|
+
brushes: this.library ??= [...BUILTIN_BRUSHES, ...this.userBrushes],
|
|
2100
2544
|
color: this.color,
|
|
2101
2545
|
secondaryColor: this.secondaryColor,
|
|
2102
2546
|
mixerLoad: this.mixerLoad,
|
|
@@ -2104,11 +2548,12 @@ var PaintEditorController = (_class9 = class {
|
|
|
2104
2548
|
hand: this.hand,
|
|
2105
2549
|
canUndo: this.undoStack.length > 0 && !this.session,
|
|
2106
2550
|
canRedo: this.redoStack.length > 0 && !this.session,
|
|
2107
|
-
undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess',
|
|
2108
|
-
redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess',
|
|
2551
|
+
undoLabel: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _42 => _42.label]), () => ( null)),
|
|
2552
|
+
redoLabel: _nullishCoalesce(_optionalChain([next, 'optionalAccess', _43 => _43.label]), () => ( null)),
|
|
2109
2553
|
guides: this.guides,
|
|
2110
2554
|
swatches: this.swatches,
|
|
2111
2555
|
mixingPadVersion: this.pad.version,
|
|
2556
|
+
savedMixingPads: this.savedPads.map(({ id, name }) => ({ id, name })),
|
|
2112
2557
|
stroking: Boolean(this.session),
|
|
2113
2558
|
version: this.version
|
|
2114
2559
|
};
|
|
@@ -2213,7 +2658,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2213
2658
|
}
|
|
2214
2659
|
// --- Layers --------------------------------------------------------------------
|
|
2215
2660
|
getLayer(id) {
|
|
2216
|
-
return _optionalChain([
|
|
2661
|
+
return _optionalChain([_chunkPOGBUYWEcjs.findLayer.call(void 0, this.doc.layers, id), 'optionalAccess', _44 => _44.layer]);
|
|
2217
2662
|
}
|
|
2218
2663
|
/** The active pixel layer (or `undefined`). */
|
|
2219
2664
|
getActiveLayer() {
|
|
@@ -2232,12 +2677,12 @@ var PaintEditorController = (_class9 = class {
|
|
|
2232
2677
|
walk(this.doc.layers, null, 0);
|
|
2233
2678
|
return out;
|
|
2234
2679
|
}
|
|
2235
|
-
describeLayer(l, parentId = _nullishCoalesce(_optionalChain([
|
|
2680
|
+
describeLayer(l, parentId = _nullishCoalesce(_optionalChain([_chunkPOGBUYWEcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _45 => _45.parent, 'optionalAccess', _46 => _46.id]), () => ( null)), depth = _nullishCoalesce(_optionalChain([_chunkPOGBUYWEcjs.findLayer.call(void 0, this.doc.layers, l.id), 'optionalAccess', _47 => _47.path, 'access', _48 => _48.length]), () => ( 0))) {
|
|
2236
2681
|
let bounds = null;
|
|
2237
2682
|
if (l.type === "pixel") {
|
|
2238
|
-
const b =
|
|
2683
|
+
const b = _chunkXIOMMGPDcjs.contentBounds.call(void 0, l.surface);
|
|
2239
2684
|
bounds = b ? { ...b, x: b.x + l.offset.x, y: b.y + l.offset.y } : null;
|
|
2240
|
-
} else for (const c of
|
|
2685
|
+
} else for (const c of _chunkPOGBUYWEcjs.flattenLayers.call(void 0, l.children)) if (c.type === "pixel") bounds = unionRect(bounds, this.describeLayer(c, l.id, depth + 1).bounds);
|
|
2241
2686
|
return {
|
|
2242
2687
|
id: l.id,
|
|
2243
2688
|
name: l.name,
|
|
@@ -2264,7 +2709,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2264
2709
|
if (!id) throw new PaintEditorError(`There is no active layer to ${what}; add one with add_layer.`);
|
|
2265
2710
|
const l = this.requireLayer(id);
|
|
2266
2711
|
if (!isPixelLayer(l)) throw new PaintEditorError(`Layer "${l.name}" is a group; ${what} a pixel layer inside it.`);
|
|
2267
|
-
if (
|
|
2712
|
+
if (_chunkPOGBUYWEcjs.isLayerLocked.call(void 0, l, "pixels")) throw new PaintEditorError(`Layer "${l.name}" has its pixels locked; unlock it (update_layer locks) before you ${what} it.`);
|
|
2268
2713
|
if (!l.visible) throw new PaintEditorError(`Layer "${l.name}" is hidden; show it (update_layer visible true) before you ${what} it.`);
|
|
2269
2714
|
return l;
|
|
2270
2715
|
}
|
|
@@ -2277,9 +2722,9 @@ var PaintEditorController = (_class9 = class {
|
|
|
2277
2722
|
/** Adds an empty pixel layer or group above `aboveId` (default: the active layer) and makes it active. */
|
|
2278
2723
|
addLayer(options = {}) {
|
|
2279
2724
|
this.requireIdle("adding a layer");
|
|
2280
|
-
const count =
|
|
2725
|
+
const count = _chunkPOGBUYWEcjs.flattenLayers.call(void 0, this.doc.layers).length;
|
|
2281
2726
|
const type = _nullishCoalesce(options.type, () => ( "pixel"));
|
|
2282
|
-
const name = _optionalChain([options, 'access',
|
|
2727
|
+
const name = _optionalChain([options, 'access', _49 => _49.name, 'optionalAccess', _50 => _50.trim, 'call', _51 => _51()]) || (type === "group" ? `Group ${count + 1}` : `Layer ${count + 1}`);
|
|
2283
2728
|
const layer = type === "group" ? { type: "group", id: newPaintLayerId(), name, visible: true, opacity: 1, blend: "pass-through", children: [] } : createPaintLayer(name);
|
|
2284
2729
|
let parentId = null;
|
|
2285
2730
|
let index;
|
|
@@ -2289,21 +2734,21 @@ var PaintEditorController = (_class9 = class {
|
|
|
2289
2734
|
if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
|
|
2290
2735
|
parentId = g.id;
|
|
2291
2736
|
} else if (above) {
|
|
2292
|
-
const loc =
|
|
2737
|
+
const loc = _chunkPOGBUYWEcjs.findLayer.call(void 0, this.doc.layers, above);
|
|
2293
2738
|
if (!loc) throw new PaintEditorError(`Unknown layer "${above}". Call list_layers for the ids.`);
|
|
2294
|
-
parentId = _nullishCoalesce(_optionalChain([loc, 'access',
|
|
2739
|
+
parentId = _nullishCoalesce(_optionalChain([loc, 'access', _52 => _52.parent, 'optionalAccess', _53 => _53.id]), () => ( null));
|
|
2295
2740
|
index = loc.index + 1;
|
|
2296
2741
|
}
|
|
2297
|
-
const layers =
|
|
2742
|
+
const layers = _chunkPOGBUYWEcjs.insertLayer.call(void 0, this.doc.layers, layer, parentId, index);
|
|
2298
2743
|
this.commit(type === "group" ? "Add group" : "Add layer", { ...this.doc, layers, activeLayerId: layer.id });
|
|
2299
2744
|
return this.describeLayer(layer);
|
|
2300
2745
|
}
|
|
2301
2746
|
updateLayer(id, update) {
|
|
2302
2747
|
this.requireIdle("changing a layer");
|
|
2303
2748
|
const l = this.requireLayer(id);
|
|
2304
|
-
if (
|
|
2749
|
+
if (_chunkPOGBUYWEcjs.isLayerLocked.call(void 0, l, "all") && Object.keys(update).some((k) => k !== "locks")) throw new PaintEditorError(`Layer "${l.name}" is fully locked; unlock it first (locks {all: false}).`);
|
|
2305
2750
|
if (update.opacity !== void 0 && !(update.opacity >= 0 && update.opacity <= 1)) throw new PaintEditorError(`opacity ${update.opacity} is out of range; use 0..1.`);
|
|
2306
|
-
if (update.blend !== void 0 && !
|
|
2751
|
+
if (update.blend !== void 0 && !_chunkXIOMMGPDcjs.isBlendMode.call(void 0, update.blend) && !(l.type === "group" && update.blend === "pass-through")) {
|
|
2307
2752
|
throw new PaintEditorError(`Unknown blend mode "${update.blend}". Call get_canvas_info for the blend modes.`);
|
|
2308
2753
|
}
|
|
2309
2754
|
if (update.name !== void 0 && !update.name.trim()) throw new PaintEditorError("name is empty; give the layer a name.");
|
|
@@ -2317,66 +2762,66 @@ var PaintEditorController = (_class9 = class {
|
|
|
2317
2762
|
const locks = { ..._nullishCoalesce(l.locks, () => ( {})), ...update.locks };
|
|
2318
2763
|
next.locks = Object.values(locks).some(Boolean) ? locks : void 0;
|
|
2319
2764
|
}
|
|
2320
|
-
this.commit("Layer properties", { ...this.doc, layers:
|
|
2765
|
+
this.commit("Layer properties", { ...this.doc, layers: _chunkPOGBUYWEcjs.mapLayer.call(void 0, this.doc.layers, id, () => next) });
|
|
2321
2766
|
return this.describeLayer(next);
|
|
2322
2767
|
}
|
|
2323
2768
|
removeLayer(id) {
|
|
2324
2769
|
this.requireIdle("removing a layer");
|
|
2325
2770
|
const l = this.requireLayer(id);
|
|
2326
|
-
if (
|
|
2327
|
-
const layers =
|
|
2771
|
+
if (_chunkPOGBUYWEcjs.isLayerLocked.call(void 0, l, "all")) throw new PaintEditorError(`Layer "${l.name}" is fully locked; unlock it before removing it.`);
|
|
2772
|
+
const layers = _chunkPOGBUYWEcjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
|
|
2328
2773
|
let active = this.doc.activeLayerId;
|
|
2329
|
-
if (active && !
|
|
2774
|
+
if (active && !_chunkPOGBUYWEcjs.findLayer.call(void 0, layers, active)) active = _nullishCoalesce(_optionalChain([_chunkPOGBUYWEcjs.flattenLayers.call(void 0, layers), 'access', _54 => _54.filter, 'call', _55 => _55((x) => x.type === "pixel"), 'access', _56 => _56.pop, 'call', _57 => _57(), 'optionalAccess', _58 => _58.id]), () => ( null));
|
|
2330
2775
|
this.commit("Remove layer", { ...this.doc, layers, activeLayerId: active });
|
|
2331
2776
|
return { removed: id, activeLayerId: active };
|
|
2332
2777
|
}
|
|
2333
2778
|
duplicateLayer(id) {
|
|
2334
2779
|
this.requireIdle("duplicating a layer");
|
|
2335
|
-
const loc =
|
|
2780
|
+
const loc = _chunkPOGBUYWEcjs.findLayer.call(void 0, this.doc.layers, id);
|
|
2336
2781
|
if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
|
|
2337
2782
|
const copy = (l) => l.type === "group" ? { ...l, id: newPaintLayerId(), children: l.children.map(copy) } : { ...l, id: newPaintLayerId() };
|
|
2338
2783
|
const dup = { ...copy(loc.layer), name: `${loc.layer.name} copy` };
|
|
2339
|
-
const layers =
|
|
2784
|
+
const layers = _chunkPOGBUYWEcjs.insertLayer.call(void 0, this.doc.layers, dup, _nullishCoalesce(_optionalChain([loc, 'access', _59 => _59.parent, 'optionalAccess', _60 => _60.id]), () => ( null)), loc.index + 1);
|
|
2340
2785
|
this.commit("Duplicate layer", { ...this.doc, layers, activeLayerId: dup.id });
|
|
2341
2786
|
return this.describeLayer(dup);
|
|
2342
2787
|
}
|
|
2343
2788
|
/** Moves a layer to `index` (0 = bottom) within `parentId` (default its own parent; `null` = top level). */
|
|
2344
2789
|
moveLayer(id, index, parentId) {
|
|
2345
2790
|
this.requireIdle("moving a layer");
|
|
2346
|
-
const loc =
|
|
2791
|
+
const loc = _chunkPOGBUYWEcjs.findLayer.call(void 0, this.doc.layers, id);
|
|
2347
2792
|
if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
|
|
2348
|
-
const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access',
|
|
2793
|
+
const target = parentId === void 0 ? _nullishCoalesce(_optionalChain([loc, 'access', _61 => _61.parent, 'optionalAccess', _62 => _62.id]), () => ( null)) : parentId;
|
|
2349
2794
|
if (target) {
|
|
2350
2795
|
const g = this.requireLayer(target);
|
|
2351
2796
|
if (g.type !== "group") throw new PaintEditorError(`Layer "${g.name}" is not a group; pass a group id as parentId.`);
|
|
2352
|
-
if (target === id || loc.layer.type === "group" &&
|
|
2797
|
+
if (target === id || loc.layer.type === "group" && _chunkPOGBUYWEcjs.findLayer.call(void 0, loc.layer.children, target)) throw new PaintEditorError("A group cannot move into itself.");
|
|
2353
2798
|
}
|
|
2354
|
-
const without =
|
|
2355
|
-
const siblings = target ?
|
|
2799
|
+
const without = _chunkPOGBUYWEcjs.mapLayer.call(void 0, this.doc.layers, id, () => null);
|
|
2800
|
+
const siblings = target ? _chunkPOGBUYWEcjs.findLayer.call(void 0, without, target).layer.children : without;
|
|
2356
2801
|
if (!Number.isInteger(index) || index < 0 || index > siblings.length) throw new PaintEditorError(`index ${index} is out of range; use 0..${siblings.length} (0 is the bottom).`);
|
|
2357
|
-
const layers =
|
|
2802
|
+
const layers = _chunkPOGBUYWEcjs.insertLayer.call(void 0, without, loc.layer, target, index);
|
|
2358
2803
|
this.commit("Move layer", { ...this.doc, layers });
|
|
2359
2804
|
return this.describeLayer(loc.layer);
|
|
2360
2805
|
}
|
|
2361
2806
|
/** Merges a pixel layer into the pixel layer below it (keeping the lower one's settings). */
|
|
2362
2807
|
mergeDown(id) {
|
|
2363
2808
|
this.requireIdle("merging");
|
|
2364
|
-
const loc =
|
|
2809
|
+
const loc = _chunkPOGBUYWEcjs.findLayer.call(void 0, this.doc.layers, id);
|
|
2365
2810
|
if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
|
|
2366
2811
|
const siblings = loc.parent ? loc.parent.children : this.doc.layers;
|
|
2367
2812
|
const below = siblings[loc.index - 1];
|
|
2368
2813
|
const upper = loc.layer;
|
|
2369
2814
|
if (!isPixelLayer(upper) || !isPixelLayer(below)) throw new PaintEditorError("Merge down needs a pixel layer directly above another pixel layer in the same group.");
|
|
2370
|
-
if (
|
|
2815
|
+
if (_chunkPOGBUYWEcjs.isLayerLocked.call(void 0, below, "pixels")) throw new PaintEditorError(`Layer "${below.name}" has its pixels locked; unlock it to merge into it.`);
|
|
2371
2816
|
const rect = unionRect(this.describeLayer(below).bounds, this.describeLayer(upper).bounds);
|
|
2372
|
-
let surface =
|
|
2817
|
+
let surface = _chunkXIOMMGPDcjs.emptySurface.call(void 0, 4);
|
|
2373
2818
|
if (rect) {
|
|
2374
2819
|
const base = { ...below, opacity: 1, blend: "normal", visible: true, clipped: void 0, mask: void 0 };
|
|
2375
2820
|
const px = createPaintCompositor().composite([base, upper.visible ? upper : { ...upper, opacity: 0 }], rect, this.sources());
|
|
2376
|
-
surface =
|
|
2821
|
+
surface = _chunkXIOMMGPDcjs.surfaceFromPixels.call(void 0, { width: rect.width, height: rect.height, data: px }, 4, rect.x, rect.y);
|
|
2377
2822
|
}
|
|
2378
2823
|
const merged = { ...below, surface, offset: { x: 0, y: 0 } };
|
|
2379
|
-
const layers =
|
|
2824
|
+
const layers = _chunkPOGBUYWEcjs.mapLayer.call(void 0, _chunkPOGBUYWEcjs.mapLayer.call(void 0, this.doc.layers, upper.id, () => null), below.id, () => merged);
|
|
2380
2825
|
this.commit("Merge down", { ...this.doc, layers, activeLayerId: below.id });
|
|
2381
2826
|
return this.describeLayer(merged);
|
|
2382
2827
|
}
|
|
@@ -2385,7 +2830,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2385
2830
|
this.requireIdle("clearing");
|
|
2386
2831
|
const l = this.paintTarget(layerId, "clear");
|
|
2387
2832
|
const bounds = this.describeLayer(l).bounds;
|
|
2388
|
-
this.commit("Clear layer", { ...this.doc, layers:
|
|
2833
|
+
this.commit("Clear layer", { ...this.doc, layers: _chunkPOGBUYWEcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface: _chunkXIOMMGPDcjs.emptySurface.call(void 0, 4) })) });
|
|
2389
2834
|
return { layerId: l.id, bounds };
|
|
2390
2835
|
}
|
|
2391
2836
|
/**
|
|
@@ -2402,14 +2847,14 @@ var PaintEditorController = (_class9 = class {
|
|
|
2402
2847
|
if (!(grainAmount >= 0 && grainAmount <= 1)) throw new PaintEditorError(`grain ${grainAmount} is out of range; use 0..1.`);
|
|
2403
2848
|
const pressure = _nullishCoalesce(options.pressure, () => ( 0.5));
|
|
2404
2849
|
const blend = _nullishCoalesce(options.blend, () => ( "normal"));
|
|
2405
|
-
if (!
|
|
2850
|
+
if (!_chunkXIOMMGPDcjs.isBlendMode.call(void 0, blend)) throw new PaintEditorError(`Unknown blend mode "${blend}".`);
|
|
2406
2851
|
const { width, height } = this.doc.canvas;
|
|
2407
2852
|
const rect = { x: 0, y: 0, width, height };
|
|
2408
|
-
const coverage = new (0,
|
|
2853
|
+
const coverage = new (0, _chunk7VOHOPLWcjs.CoverageMap)();
|
|
2409
2854
|
const depth = grainAmount * this.doc.paper.depth;
|
|
2410
2855
|
const grain = depth > 0 ? paperGrain(this.doc.paper) : null;
|
|
2411
|
-
for (const { tx, ty } of
|
|
2412
|
-
const r = { x: tx *
|
|
2856
|
+
for (const { tx, ty } of _chunkXIOMMGPDcjs.tilesInRect.call(void 0, rect)) {
|
|
2857
|
+
const r = { x: tx * _chunkXIOMMGPDcjs.TILE, y: ty * _chunkXIOMMGPDcjs.TILE, width: Math.min(_chunkXIOMMGPDcjs.TILE, width - tx * _chunkXIOMMGPDcjs.TILE), height: Math.min(_chunkXIOMMGPDcjs.TILE, height - ty * _chunkXIOMMGPDcjs.TILE) };
|
|
2413
2858
|
const vals = new Float32Array(r.width * r.height);
|
|
2414
2859
|
for (let y = 0, k = 0; y < r.height; y++) for (let x = 0; x < r.width; x++, k++) vals[k] = grain ? grainCatch(grain.at(r.x + x + 0.5, r.y + y + 0.5), depth, pressure) : 1;
|
|
2415
2860
|
coverage.accumulate(r, vals, 1);
|
|
@@ -2420,25 +2865,25 @@ var PaintEditorController = (_class9 = class {
|
|
|
2420
2865
|
background: rgbaOf(this.doc.paper.color),
|
|
2421
2866
|
opacity,
|
|
2422
2867
|
blend,
|
|
2423
|
-
lockTransparency:
|
|
2868
|
+
lockTransparency: _chunkPOGBUYWEcjs.isLayerLocked.call(void 0, l, "transparency"),
|
|
2424
2869
|
selection: null,
|
|
2425
2870
|
offset: l.offset
|
|
2426
2871
|
};
|
|
2427
2872
|
const surface = this.applyCoverage(l, coverage, rect, apply);
|
|
2428
|
-
this.commit("Fill layer", { ...this.doc, layers:
|
|
2873
|
+
this.commit("Fill layer", { ...this.doc, layers: _chunkPOGBUYWEcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })) });
|
|
2429
2874
|
return { layerId: l.id, bounds: rect };
|
|
2430
2875
|
}
|
|
2431
2876
|
applyCoverage(l, coverage, rect, apply) {
|
|
2432
2877
|
const base = l.surface;
|
|
2433
2878
|
const tiles = new Map(base.tiles);
|
|
2434
|
-
for (const { tx, ty } of
|
|
2435
|
-
const key =
|
|
2436
|
-
const src = _nullishCoalesce(_optionalChain([base, 'access',
|
|
2437
|
-
const tile =
|
|
2879
|
+
for (const { tx, ty } of _chunkXIOMMGPDcjs.tilesInRect.call(void 0, { x: rect.x - l.offset.x, y: rect.y - l.offset.y, width: rect.width, height: rect.height })) {
|
|
2880
|
+
const key = _chunkXIOMMGPDcjs.tileKey.call(void 0, tx, ty);
|
|
2881
|
+
const src = _nullishCoalesce(_optionalChain([base, 'access', _63 => _63.tiles, 'access', _64 => _64.get, 'call', _65 => _65(key), 'optionalAccess', _66 => _66.data]), () => ( new Uint8ClampedArray(_chunkXIOMMGPDcjs.TILE * _chunkXIOMMGPDcjs.TILE * 4)));
|
|
2882
|
+
const tile = _chunkXIOMMGPDcjs.finishTile.call(void 0, _chunk7VOHOPLWcjs.applyStrokeToTile.call(void 0, coverage, src, 4, tx, ty, apply), 4, 0);
|
|
2438
2883
|
if (tile) tiles.set(key, tile);
|
|
2439
2884
|
else tiles.delete(key);
|
|
2440
2885
|
}
|
|
2441
|
-
return new (0,
|
|
2886
|
+
return new (0, _chunkXIOMMGPDcjs.TiledSurface)(4, tiles, 0);
|
|
2442
2887
|
}
|
|
2443
2888
|
// --- Brushes -------------------------------------------------------------------
|
|
2444
2889
|
findBrush(id) {
|
|
@@ -2478,6 +2923,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2478
2923
|
const i = this.userBrushes.findIndex((b) => b.id === options.id);
|
|
2479
2924
|
if (i >= 0) this.userBrushes[i] = saved;
|
|
2480
2925
|
else this.userBrushes.push(saved);
|
|
2926
|
+
this.library = null;
|
|
2481
2927
|
this.emit([]);
|
|
2482
2928
|
return saved;
|
|
2483
2929
|
}
|
|
@@ -2486,6 +2932,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2486
2932
|
const i = this.userBrushes.findIndex((b) => b.id === id);
|
|
2487
2933
|
if (i < 0) throw new PaintEditorError(`Unknown brush "${id}". Call list_brushes for the ids.`);
|
|
2488
2934
|
this.userBrushes.splice(i, 1);
|
|
2935
|
+
this.library = null;
|
|
2489
2936
|
this.emit([]);
|
|
2490
2937
|
}
|
|
2491
2938
|
/** The user's saved brushes. */
|
|
@@ -2526,7 +2973,10 @@ var PaintEditorController = (_class9 = class {
|
|
|
2526
2973
|
else this.userBrushes.push(b);
|
|
2527
2974
|
added.push(b.id);
|
|
2528
2975
|
}
|
|
2529
|
-
if (added.length)
|
|
2976
|
+
if (added.length) {
|
|
2977
|
+
this.library = null;
|
|
2978
|
+
this.emit([]);
|
|
2979
|
+
}
|
|
2530
2980
|
return { added, skipped, problems };
|
|
2531
2981
|
}
|
|
2532
2982
|
/** A thumbnail of a brush: a test stroke on the current paper. */
|
|
@@ -2558,7 +3008,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2558
3008
|
if (options.layerId !== void 0) {
|
|
2559
3009
|
const l = this.requireLayer(options.layerId);
|
|
2560
3010
|
if (!isPixelLayer(l)) throw new PaintEditorError(`Layer "${l.name}" is a group; pick from a pixel layer or the composite.`);
|
|
2561
|
-
const [r, g, b, a] =
|
|
3011
|
+
const [r, g, b, a] = _chunkXIOMMGPDcjs.readPixel.call(void 0, l.surface, px - l.offset.x, py - l.offset.y);
|
|
2562
3012
|
return { color: rgbToHex(r, g, b), alpha: Math.round(a / 255 * 1e3) / 1e3 };
|
|
2563
3013
|
}
|
|
2564
3014
|
const d = this.exportCompositor.composite(this.renderLayers({}), { x: px, y: py, width: 1, height: 1 }, this.sources());
|
|
@@ -2568,13 +3018,13 @@ var PaintEditorController = (_class9 = class {
|
|
|
2568
3018
|
/** Fills the Mixer Brush reservoir with a colour (default the editor colour). */
|
|
2569
3019
|
loadMixerBrush(color) {
|
|
2570
3020
|
const [r, g, b] = hexToRgb8(color === void 0 ? this.color : parseColor(color));
|
|
2571
|
-
this.mixerLoad =
|
|
3021
|
+
this.mixerLoad = _chunk7VOHOPLWcjs.loadMixer.call(void 0, this.mixerLoad, [r / 255, g / 255, b / 255]);
|
|
2572
3022
|
this.emit([]);
|
|
2573
3023
|
return this.mixerLoad;
|
|
2574
3024
|
}
|
|
2575
3025
|
/** Empties the pickup well (and with `emptyReservoir` the loaded paint too). */
|
|
2576
3026
|
cleanMixerBrush(emptyReservoir = false) {
|
|
2577
|
-
this.mixerLoad = emptyReservoir ?
|
|
3027
|
+
this.mixerLoad = emptyReservoir ? _chunk7VOHOPLWcjs.EMPTY_MIXER_LOAD : _chunk7VOHOPLWcjs.cleanMixer.call(void 0, this.mixerLoad);
|
|
2578
3028
|
this.emit([]);
|
|
2579
3029
|
return this.mixerLoad;
|
|
2580
3030
|
}
|
|
@@ -2600,6 +3050,14 @@ var PaintEditorController = (_class9 = class {
|
|
|
2600
3050
|
if (init.brush) brush = normalizePaintBrush({ ...init.brush, id: brush.id }, brush);
|
|
2601
3051
|
return brush;
|
|
2602
3052
|
}
|
|
3053
|
+
/**
|
|
3054
|
+
* After a stroke: a Mixer Brush that loads colour keeps its whole load; any other dirty brush
|
|
3055
|
+
* keeps only the paint it carries (the reservoir stays the Mixer Brush's).
|
|
3056
|
+
*/
|
|
3057
|
+
keepLoad(brush, load) {
|
|
3058
|
+
if (brush.engine === "mixer" && brush.loadsColor) this.mixerLoad = load;
|
|
3059
|
+
else if (brush.behavior.dirty) this.mixerLoad = { ...this.mixerLoad, pickup: load.pickup };
|
|
3060
|
+
}
|
|
2603
3061
|
/** Extra copies every new stroke paints (the painting guides add mirror and kaleidoscope copies). */
|
|
2604
3062
|
strokeCopies() {
|
|
2605
3063
|
return symmetryCopies(this.guides.symmetry);
|
|
@@ -2608,18 +3066,18 @@ var PaintEditorController = (_class9 = class {
|
|
|
2608
3066
|
const layer = (() => {
|
|
2609
3067
|
const id = _nullishCoalesce(init.layerId, () => ( doc.activeLayerId));
|
|
2610
3068
|
if (!id) throw new PaintEditorError("There is no active layer to paint on; add one with add_layer.");
|
|
2611
|
-
const loc =
|
|
3069
|
+
const loc = _chunkPOGBUYWEcjs.findLayer.call(void 0, doc.layers, id);
|
|
2612
3070
|
if (!loc) throw new PaintEditorError(`Unknown layer "${id}". Call list_layers for the ids.`);
|
|
2613
3071
|
const l = loc.layer;
|
|
2614
3072
|
if (!isPixelLayer(l)) throw new PaintEditorError(`Layer "${l.name}" is a group; paint on a pixel layer inside it.`);
|
|
2615
|
-
if (
|
|
3073
|
+
if (_chunkPOGBUYWEcjs.isLayerLocked.call(void 0, l, "pixels")) throw new PaintEditorError(`Layer "${l.name}" has its pixels locked; unlock it (update_layer locks) to paint on it.`);
|
|
2616
3074
|
if (!l.visible) throw new PaintEditorError(`Layer "${l.name}" is hidden; show it (update_layer visible true) to paint on it.`);
|
|
2617
3075
|
return l;
|
|
2618
3076
|
})();
|
|
2619
3077
|
const brush = this.strokeBrush(init);
|
|
2620
3078
|
let color = init.color === void 0 ? this.color : parseColor(init.color);
|
|
2621
3079
|
const tracing = this.guides.tracing;
|
|
2622
|
-
if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess',
|
|
3080
|
+
if (init.color === void 0 && init.start && _optionalChain([tracing, 'optionalAccess', _67 => _67.visible]) && tracing.sampleColors) color = _nullishCoalesce(this.sampleTracingColor(init.start.x, init.start.y), () => ( color));
|
|
2623
3081
|
const perspective = this.guides.perspective;
|
|
2624
3082
|
const snapper = init.snapToPerspective && perspective.enabled && perspective.snap ? new PerspectiveSnapper(perspective) : null;
|
|
2625
3083
|
const rgba = rgbaOf(color);
|
|
@@ -2629,7 +3087,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2629
3087
|
layerId: layer.id,
|
|
2630
3088
|
surface: layer.surface,
|
|
2631
3089
|
offset: layer.offset,
|
|
2632
|
-
lockTransparency:
|
|
3090
|
+
lockTransparency: _chunkPOGBUYWEcjs.isLayerLocked.call(void 0, layer, "transparency"),
|
|
2633
3091
|
brush,
|
|
2634
3092
|
color: rgba,
|
|
2635
3093
|
background: rgbaOf(doc.paper.color),
|
|
@@ -2640,7 +3098,8 @@ var PaintEditorController = (_class9 = class {
|
|
|
2640
3098
|
affineCopies: copies,
|
|
2641
3099
|
copies: [IDENTITY_AFFINE, ...copies].map(affineCopy),
|
|
2642
3100
|
inputFilter: snapper ? (p) => snapper.snap(p) : void 0,
|
|
2643
|
-
mixerLoad:
|
|
3101
|
+
mixerLoad: _nullishCoalesce(init.load, () => ( brushLoadForStroke(brush, this.mixerLoad, [rgba[0] / 255, rgba[1] / 255, rgba[2] / 255]))),
|
|
3102
|
+
secondary: rgbaOf(this.secondaryColor)
|
|
2644
3103
|
});
|
|
2645
3104
|
return session;
|
|
2646
3105
|
}
|
|
@@ -2655,6 +3114,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2655
3114
|
seed: init.seed
|
|
2656
3115
|
};
|
|
2657
3116
|
if (init.affineCopies.length) stroke.copies = init.affineCopies.map((m) => [...m]);
|
|
3117
|
+
if (init.mixerLoad.reservoir || init.mixerLoad.pickup) stroke.load = JSON.parse(JSON.stringify(init.mixerLoad));
|
|
2658
3118
|
return stroke;
|
|
2659
3119
|
}
|
|
2660
3120
|
/**
|
|
@@ -2673,7 +3133,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2673
3133
|
this.live = null;
|
|
2674
3134
|
this.liveLayers = null;
|
|
2675
3135
|
const brush = s.init.brush;
|
|
2676
|
-
if (!cancelled && _optionalChain([s, 'access',
|
|
3136
|
+
if (!cancelled && _optionalChain([s, 'access', _68 => _68.result, 'optionalAccess', _69 => _69.mixerLoad])) this.keepLoad(brush, s.result.mixerLoad);
|
|
2677
3137
|
if (cancelled || !surface) {
|
|
2678
3138
|
this.emit();
|
|
2679
3139
|
return;
|
|
@@ -2681,7 +3141,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2681
3141
|
const stroke = this.record(s);
|
|
2682
3142
|
s.result.strokeId = stroke.id;
|
|
2683
3143
|
const l = this.getLayer(s.layerId);
|
|
2684
|
-
this.commit(`${brush.name} stroke`, { ...this.doc, layers:
|
|
3144
|
+
this.commit(`${brush.name} stroke`, { ...this.doc, layers: _chunkPOGBUYWEcjs.mapLayer.call(void 0, this.doc.layers, l.id, () => ({ ...l, surface })), strokes: [...this.doc.strokes, stroke] });
|
|
2685
3145
|
}
|
|
2686
3146
|
};
|
|
2687
3147
|
const session = this.sessionFor(this.doc, { snapToPerspective: true, ...init }, host);
|
|
@@ -2703,8 +3163,8 @@ var PaintEditorController = (_class9 = class {
|
|
|
2703
3163
|
if (cancelled || !surface) return;
|
|
2704
3164
|
const stroke = this.record(s);
|
|
2705
3165
|
s.result.strokeId = stroke.id;
|
|
2706
|
-
const l =
|
|
2707
|
-
out = { ...out, layers:
|
|
3166
|
+
const l = _chunkPOGBUYWEcjs.findLayer.call(void 0, out.layers, s.layerId).layer;
|
|
3167
|
+
out = { ...out, layers: _chunkPOGBUYWEcjs.mapLayer.call(void 0, out.layers, l.id, () => ({ ...l, surface })), strokes: [...out.strokes, stroke] };
|
|
2708
3168
|
}
|
|
2709
3169
|
};
|
|
2710
3170
|
const session = this.sessionFor(doc, init, host);
|
|
@@ -2717,7 +3177,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2717
3177
|
this.requireIdle("painting");
|
|
2718
3178
|
const points = this.checkPoints(init.points);
|
|
2719
3179
|
const { doc, result, brush } = this.runStroke(this.doc, { ...init, start: _nullishCoalesce(init.start, () => ( points[0])) }, points);
|
|
2720
|
-
if (result.mixerLoad
|
|
3180
|
+
if (result.mixerLoad) this.keepLoad(brush, result.mixerLoad);
|
|
2721
3181
|
if (doc !== this.doc) this.commit(`${brush.name} stroke`, doc);
|
|
2722
3182
|
else this.emit([]);
|
|
2723
3183
|
return result;
|
|
@@ -2743,7 +3203,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2743
3203
|
*/
|
|
2744
3204
|
replayStrokes(options) {
|
|
2745
3205
|
this.requireIdle("replaying");
|
|
2746
|
-
if (!_optionalChain([options, 'access',
|
|
3206
|
+
if (!_optionalChain([options, 'access', _70 => _70.strokeIds, 'optionalAccess', _71 => _71.length])) throw new PaintEditorError("strokeIds is empty; pass ids from list_strokes.");
|
|
2747
3207
|
const strokes = options.strokeIds.map((id) => {
|
|
2748
3208
|
const s = this.doc.strokes.find((x) => x.id === id);
|
|
2749
3209
|
if (!s) throw new PaintEditorError(`Unknown stroke "${id}". Call list_strokes for the ids.`);
|
|
@@ -2776,8 +3236,13 @@ var PaintEditorController = (_class9 = class {
|
|
|
2776
3236
|
brush = normalizePaintBrush({ tip: { ...b.tip, size: b.tip.size * (v.brush.tip.size / s.brush.tip.size) } }, b);
|
|
2777
3237
|
}
|
|
2778
3238
|
const layerId = _nullishCoalesce(options.layerId, () => ( s.layerId));
|
|
2779
|
-
if (!
|
|
2780
|
-
|
|
3239
|
+
if (!_chunkPOGBUYWEcjs.findLayer.call(void 0, doc.layers, layerId)) throw new PaintEditorError(`Stroke "${s.id}" was painted on layer "${layerId}", which no longer exists; pass layerId to replay it elsewhere.`);
|
|
3240
|
+
let load = s.load;
|
|
3241
|
+
if (load && options.color !== void 0 && load.reservoir) {
|
|
3242
|
+
const [r, g, b] = hexToRgb8(options.color);
|
|
3243
|
+
load = { ...load, reservoir: [r / 255, g / 255, b / 255] };
|
|
3244
|
+
}
|
|
3245
|
+
const run = this.runStroke(doc, { layerId, color: _nullishCoalesce(options.color, () => ( s.color)), brush, seed: s.seed, copies: _nullishCoalesce(v.copies, () => ( [])), ...load && options.brushId === void 0 ? { load } : {} }, v.points);
|
|
2781
3246
|
doc = run.doc;
|
|
2782
3247
|
bounds = unionRect(bounds, run.result.bounds);
|
|
2783
3248
|
if (run.result.strokeId) ids.push(run.result.strokeId);
|
|
@@ -2795,8 +3260,8 @@ var PaintEditorController = (_class9 = class {
|
|
|
2795
3260
|
currentLayers() {
|
|
2796
3261
|
const live = this.live;
|
|
2797
3262
|
if (!live) return this.doc.layers;
|
|
2798
|
-
if (_optionalChain([this, 'access',
|
|
2799
|
-
const layers =
|
|
3263
|
+
if (_optionalChain([this, 'access', _72 => _72.liveLayers, 'optionalAccess', _73 => _73.key]) === live.surface) return this.liveLayers.layers;
|
|
3264
|
+
const layers = _chunkPOGBUYWEcjs.mapLayer.call(void 0, this.doc.layers, live.layerId, (l) => ({ ...l, surface: live.surface }));
|
|
2800
3265
|
this.liveLayers = { key: live.surface, layers };
|
|
2801
3266
|
return layers;
|
|
2802
3267
|
}
|
|
@@ -2810,7 +3275,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2810
3275
|
tracingNode(t) {
|
|
2811
3276
|
const { width, height } = this.doc.canvas;
|
|
2812
3277
|
const key = this.tracingVersion * 100003 + width * 7 + height;
|
|
2813
|
-
if (_optionalChain([this, 'access',
|
|
3278
|
+
if (_optionalChain([this, 'access', _74 => _74.tracingCache, 'optionalAccess', _75 => _75.key]) === key && this.tracingCache.node.opacity === t.opacity) return this.tracingCache.node;
|
|
2814
3279
|
const src = _nullishCoalesce(this.imagePixels.get(t.src), () => ( this.decodeImage(t.src)));
|
|
2815
3280
|
const image = resampleInto(src, t.rect, width, height);
|
|
2816
3281
|
const node = { type: "image", id: TRACING_NODE_ID, name: "Tracing", visible: true, opacity: t.opacity, blend: "normal", image, version: key + Math.round(t.opacity * 1e3) / 1e4 };
|
|
@@ -2835,7 +3300,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2835
3300
|
*/
|
|
2836
3301
|
compositeTiles(rect, onTile, options = {}) {
|
|
2837
3302
|
const dirty = options.dirty === "all" ? void 0 : options.dirty;
|
|
2838
|
-
this.viewCompositor.compositeTiles(this.renderLayers({}, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access',
|
|
3303
|
+
this.viewCompositor.compositeTiles(this.renderLayers({}, true), rect, this.sources(), onTile, { dirty, checkpointLayerId: _nullishCoalesce(_optionalChain([this, 'access', _76 => _76.live, 'optionalAccess', _77 => _77.layerId]), () => ( this.doc.activeLayerId)) });
|
|
2839
3304
|
}
|
|
2840
3305
|
/** The canvas as canvas-sized RGBA (paper included by default). */
|
|
2841
3306
|
compositePixels(options = {}) {
|
|
@@ -2856,20 +3321,21 @@ var PaintEditorController = (_class9 = class {
|
|
|
2856
3321
|
// --- Save, load and export -------------------------------------------------------
|
|
2857
3322
|
/** The document as JSON with inline PNG assets. */
|
|
2858
3323
|
toJSON(options = {}) {
|
|
2859
|
-
return serializePaintDocument(this.doc, { strokes: options.strokes, extensions: this.extensions, guides: this.guides, swatches: this.swatches });
|
|
3324
|
+
return serializePaintDocument(this.doc, { strokes: options.strokes, extensions: this.extensions, guides: this.guides, swatches: this.swatches, mixingPad: this.mixingPadJSON() });
|
|
2860
3325
|
}
|
|
2861
3326
|
/** The document as JSON with each PNG stored in `store`. */
|
|
2862
3327
|
toJSONExternal(store, options = {}) {
|
|
2863
|
-
return serializePaintDocumentExternal(this.doc, store, { strokes: options.strokes, extensions: this.extensions, guides: this.guides, swatches: this.swatches });
|
|
3328
|
+
return serializePaintDocumentExternal(this.doc, store, { strokes: options.strokes, extensions: this.extensions, guides: this.guides, swatches: this.swatches, mixingPad: this.mixingPadJSON() });
|
|
2864
3329
|
}
|
|
2865
3330
|
adopt(loaded) {
|
|
2866
3331
|
this.extensions = loaded.extensions;
|
|
3332
|
+
this.readMixingPad(loaded.mixingPad, loaded.problems);
|
|
2867
3333
|
this.readGuides(loaded.guides, loaded.state, loaded.problems);
|
|
2868
3334
|
if (Array.isArray(loaded.swatches)) {
|
|
2869
3335
|
this.swatches = loaded.swatches.filter((x) => Boolean(x) && typeof x.color === "string" && /^#[0-9a-f]{6}$/i.test(x.color)).map((x) => typeof x.name === "string" ? { color: x.color.toLowerCase(), name: x.name } : { color: x.color.toLowerCase() });
|
|
2870
3336
|
}
|
|
2871
3337
|
for (const s of loaded.state.strokes) {
|
|
2872
|
-
const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access',
|
|
3338
|
+
const n = Number(_nullishCoalesce(_optionalChain([/^s(\d+)$/, 'access', _78 => _78.exec, 'call', _79 => _79(s.id), 'optionalAccess', _80 => _80[1]]), () => ( 0)));
|
|
2873
3339
|
if (n >= this.strokeCounter) this.strokeCounter = n + 1;
|
|
2874
3340
|
}
|
|
2875
3341
|
this.undoStack = [];
|
|
@@ -2900,7 +3366,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2900
3366
|
/** The canvas as PNG bytes (paper included by default; `scale` below 1 shrinks it). */
|
|
2901
3367
|
exportPng(options = {}) {
|
|
2902
3368
|
const img = this.scaled(options);
|
|
2903
|
-
return
|
|
3369
|
+
return _chunkPOGBUYWEcjs.encodePng.call(void 0, img.width, img.height, img.data);
|
|
2904
3370
|
}
|
|
2905
3371
|
scaled(options) {
|
|
2906
3372
|
const full = this.compositePixels(options);
|
|
@@ -2942,22 +3408,22 @@ var PaintEditorController = (_class9 = class {
|
|
|
2942
3408
|
opacity: 1,
|
|
2943
3409
|
blend: "normal",
|
|
2944
3410
|
locks: { all: true },
|
|
2945
|
-
surface:
|
|
3411
|
+
surface: _chunkXIOMMGPDcjs.surfaceFromPixels.call(void 0, paperPixels, 4),
|
|
2946
3412
|
offset: { x: 0, y: 0 }
|
|
2947
3413
|
};
|
|
2948
3414
|
const merged = this.compositePixels({ paper: true }).data;
|
|
2949
3415
|
const changed = /* @__PURE__ */ new Map();
|
|
2950
3416
|
const toStandard = (layers2) => layers2.map((l) => {
|
|
2951
|
-
const blend = l.blend === "pass-through" ? l.blend :
|
|
3417
|
+
const blend = l.blend === "pass-through" ? l.blend : _chunkXIOMMGPDcjs.standardBlendMode.call(void 0, l.blend);
|
|
2952
3418
|
if (blend !== l.blend) changed.set(l.blend, [..._nullishCoalesce(changed.get(l.blend), () => ( [])), l.name]);
|
|
2953
3419
|
const next = blend === l.blend ? l : { ...l, blend };
|
|
2954
3420
|
return next.type === "group" ? { ...next, children: toStandard(next.children) } : next;
|
|
2955
3421
|
});
|
|
2956
3422
|
const layers = toStandard(this.doc.layers);
|
|
2957
|
-
const result =
|
|
3423
|
+
const result = _chunkMGL4U5WAcjs.exportPsd.call(void 0, { width, height, layers: [paperLayer, ...layers], merged, resolution: dpi });
|
|
2958
3424
|
for (const [mode, names] of changed) {
|
|
2959
|
-
const label = _nullishCoalesce(_optionalChain([
|
|
2960
|
-
const std = _nullishCoalesce(_optionalChain([
|
|
3425
|
+
const label = _nullishCoalesce(_optionalChain([_chunkXIOMMGPDcjs.BLEND_MODES, 'access', _81 => _81.find, 'call', _82 => _82((m) => m.id === mode), 'optionalAccess', _83 => _83.label]), () => ( mode));
|
|
3426
|
+
const std = _nullishCoalesce(_optionalChain([_chunkXIOMMGPDcjs.BLEND_MODES, 'access', _84 => _84.find, 'call', _85 => _85((m) => m.id === _chunkXIOMMGPDcjs.standardBlendMode.call(void 0, mode)), 'optionalAccess', _86 => _86.label]), () => ( _chunkXIOMMGPDcjs.standardBlendMode.call(void 0, mode)));
|
|
2961
3427
|
const list = names.map((n) => `"${n}"`).join(", ");
|
|
2962
3428
|
const one = names.length === 1;
|
|
2963
3429
|
result.warnings.push(`${label} blending has no PSD equivalent; ${list} ${one ? "was" : "were"} written as ${std}, the nearest Photoshop mode, so ${one ? "it looks" : "they look"} different in Photoshop (the merged image is exact).`);
|
|
@@ -2967,7 +3433,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
2967
3433
|
/** `render_preview` as a base64 PNG. */
|
|
2968
3434
|
previewPngBase64(options = {}) {
|
|
2969
3435
|
const img = this.renderPreview(options);
|
|
2970
|
-
return { data:
|
|
3436
|
+
return { data: _chunkPOGBUYWEcjs.bytesToBase64.call(void 0, _chunkPOGBUYWEcjs.encodePng.call(void 0, img.width, img.height, img.data)), width: img.width, height: img.height };
|
|
2971
3437
|
}
|
|
2972
3438
|
// --- Guides --------------------------------------------------------------------
|
|
2973
3439
|
setGuides(next) {
|
|
@@ -3005,17 +3471,17 @@ var PaintEditorController = (_class9 = class {
|
|
|
3005
3471
|
pixels = this.decodeImage(input.png.trim().startsWith("data:") ? input.png.trim() : `data:image/png;base64,${input.png.trim()}`, what);
|
|
3006
3472
|
} else throw new PaintEditorError(`${what}: pass png (a PNG as base64 or a data URL) or pixels.`);
|
|
3007
3473
|
if (pixels.width > MAX_IMAGE_SIDE || pixels.height > MAX_IMAGE_SIDE) throw new PaintEditorError(`${what} is ${pixels.width}\xD7${pixels.height}; the limit is ${MAX_IMAGE_SIDE} px per side.`);
|
|
3008
|
-
const src =
|
|
3474
|
+
const src = _chunkPOGBUYWEcjs.pngDataUrl.call(void 0, pixels.width, pixels.height, pixels.data);
|
|
3009
3475
|
this.imagePixels.set(src, pixels);
|
|
3010
3476
|
return { src, pixels };
|
|
3011
3477
|
}
|
|
3012
3478
|
decodeImage(src, what = "Image") {
|
|
3013
3479
|
const cached = this.imagePixels.get(src);
|
|
3014
3480
|
if (cached) return cached;
|
|
3015
|
-
const parsed =
|
|
3481
|
+
const parsed = _chunkPOGBUYWEcjs.parseDataUrl.call(void 0, src);
|
|
3016
3482
|
if (!parsed) throw new PaintEditorError(`${what} is not a data URL or base64 PNG.`);
|
|
3017
3483
|
try {
|
|
3018
|
-
const png =
|
|
3484
|
+
const png = _chunkPOGBUYWEcjs.decodePng.call(void 0, parsed.bytes);
|
|
3019
3485
|
const px = { width: png.width, height: png.height, data: png.data };
|
|
3020
3486
|
this.imagePixels.set(src, px);
|
|
3021
3487
|
return px;
|
|
@@ -3073,7 +3539,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
3073
3539
|
const { src, pixels } = this.importImage(options, "The reference image");
|
|
3074
3540
|
const ref = {
|
|
3075
3541
|
id: `ref${this.nextReferenceId++}`,
|
|
3076
|
-
name: _optionalChain([options, 'access',
|
|
3542
|
+
name: _optionalChain([options, 'access', _87 => _87.name, 'optionalAccess', _88 => _88.trim, 'call', _89 => _89()]) || `Reference ${this.guides.references.length + 1}`,
|
|
3077
3543
|
src,
|
|
3078
3544
|
width: pixels.width,
|
|
3079
3545
|
height: pixels.height,
|
|
@@ -3152,7 +3618,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
3152
3618
|
try {
|
|
3153
3619
|
const px = this.decodeImage(ref.src, `Reference "${ref.name}"`);
|
|
3154
3620
|
guides.references.push({ id: ref.id, name: String(_nullishCoalesce(ref.name, () => ( ref.id))), src: ref.src, width: px.width, height: px.height, x: Number(ref.x) || 0, y: Number(ref.y) || 0, displayWidth: Number(ref.displayWidth) || 240, visible: ref.visible !== false });
|
|
3155
|
-
const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access',
|
|
3621
|
+
const n = Number(_nullishCoalesce(_optionalChain([/^ref(\d+)$/, 'access', _90 => _90.exec, 'call', _91 => _91(ref.id), 'optionalAccess', _92 => _92[1]]), () => ( 0)));
|
|
3156
3622
|
if (n >= this.nextReferenceId) this.nextReferenceId = n + 1;
|
|
3157
3623
|
} catch (e) {
|
|
3158
3624
|
problems.push(e.message);
|
|
@@ -3172,7 +3638,7 @@ var PaintEditorController = (_class9 = class {
|
|
|
3172
3638
|
}
|
|
3173
3639
|
addSwatch(color, name) {
|
|
3174
3640
|
const c = parseColor(color);
|
|
3175
|
-
this.swatches = [...this.swatches, _optionalChain([name, 'optionalAccess',
|
|
3641
|
+
this.swatches = [...this.swatches, _optionalChain([name, 'optionalAccess', _93 => _93.trim, 'call', _94 => _94()]) ? { color: c, name: name.trim() } : { color: c }];
|
|
3176
3642
|
this.emit([]);
|
|
3177
3643
|
return this.swatches;
|
|
3178
3644
|
}
|
|
@@ -3218,12 +3684,105 @@ var PaintEditorController = (_class9 = class {
|
|
|
3218
3684
|
this.pad.clear();
|
|
3219
3685
|
this.emit([]);
|
|
3220
3686
|
}
|
|
3687
|
+
/**
|
|
3688
|
+
* Mixes paints on the pad like a painter: blobs in proportion to their `parts`, knife passes,
|
|
3689
|
+
* and a fully mixed core of the Kubelka-Munk mix (see `MixingPad.mix`). With `setColor` the
|
|
3690
|
+
* mix becomes the paint colour. Returns the mixed colour and the pile's bounds.
|
|
3691
|
+
*/
|
|
3692
|
+
mixOnPad(paints, options = {}) {
|
|
3693
|
+
const parsed = (_nullishCoalesce(paints, () => ( []))).map((p, i) => ({ color: parseColor(_optionalChain([p, 'optionalAccess', _95 => _95.color]), `paints[${i}].color`), parts: _optionalChain([p, 'optionalAccess', _96 => _96.parts]) }));
|
|
3694
|
+
let r;
|
|
3695
|
+
try {
|
|
3696
|
+
r = this.pad.mix(parsed, options);
|
|
3697
|
+
} catch (e) {
|
|
3698
|
+
throw new PaintEditorError(e.message);
|
|
3699
|
+
}
|
|
3700
|
+
const color = _nullishCoalesce(r.color, () => ( parsed[0].color));
|
|
3701
|
+
this.emit([]);
|
|
3702
|
+
if (options.setColor) this.setColor(color);
|
|
3703
|
+
return { color, bounds: r.bounds };
|
|
3704
|
+
}
|
|
3705
|
+
/** The mixing pad as a PNG data URL (with alpha). */
|
|
3706
|
+
mixingPadPng() {
|
|
3707
|
+
return this.pad.toPng();
|
|
3708
|
+
}
|
|
3709
|
+
/** Replaces the mixing pad with a PNG (data URL or base64, 360 × 220). */
|
|
3710
|
+
setMixingPadPng(png) {
|
|
3711
|
+
try {
|
|
3712
|
+
this.pad.fromPng(png);
|
|
3713
|
+
} catch (e) {
|
|
3714
|
+
throw new PaintEditorError(e.message);
|
|
3715
|
+
}
|
|
3716
|
+
this.emit([]);
|
|
3717
|
+
}
|
|
3718
|
+
/** The mixing pads kept by name. */
|
|
3719
|
+
listMixingPads() {
|
|
3720
|
+
return this.savedPads.map(({ id, name }) => ({ id, name }));
|
|
3721
|
+
}
|
|
3722
|
+
/** Keeps the mixing pad as it is now under `name` (saved with the document). Returns its id. */
|
|
3723
|
+
saveMixingPad(name) {
|
|
3724
|
+
if (this.pad.empty) throw new PaintEditorError("The mixing pad is empty; put paint on it (mixing_pad_stroke or mix_on_pad) before saving it.");
|
|
3725
|
+
const label = (typeof name === "string" && name.trim() ? name.trim() : `Pad ${this.nextPadId}`).slice(0, 80);
|
|
3726
|
+
const pad = { id: `pad${this.nextPadId++}`, name: label, png: this.pad.toPng() };
|
|
3727
|
+
this.savedPads.push(pad);
|
|
3728
|
+
this.emit([]);
|
|
3729
|
+
return { id: pad.id, name: pad.name };
|
|
3730
|
+
}
|
|
3731
|
+
requirePad(id) {
|
|
3732
|
+
const p = this.savedPads.find((x) => x.id === id);
|
|
3733
|
+
if (!p) throw new PaintEditorError(`Unknown mixing pad "${id}". Call list_mixing_pads for the ids.`);
|
|
3734
|
+
return p;
|
|
3735
|
+
}
|
|
3736
|
+
/** Puts a kept pad back on the mixing pad (replacing what is there). */
|
|
3737
|
+
loadMixingPad(id) {
|
|
3738
|
+
const p = this.requirePad(id);
|
|
3739
|
+
this.setMixingPadPng(p.png);
|
|
3740
|
+
return { id: p.id, name: p.name };
|
|
3741
|
+
}
|
|
3742
|
+
/** Forgets a kept pad. */
|
|
3743
|
+
removeMixingPad(id) {
|
|
3744
|
+
const p = this.requirePad(id);
|
|
3745
|
+
this.savedPads = this.savedPads.filter((x) => x !== p);
|
|
3746
|
+
this.emit([]);
|
|
3747
|
+
return { id: p.id, name: p.name };
|
|
3748
|
+
}
|
|
3749
|
+
mixingPadJSON() {
|
|
3750
|
+
if (this.pad.empty && !this.savedPads.length) return void 0;
|
|
3751
|
+
return { ...this.pad.empty ? {} : { current: this.pad.toPng() }, saved: this.savedPads.map((p) => ({ ...p })) };
|
|
3752
|
+
}
|
|
3753
|
+
readMixingPad(raw, problems) {
|
|
3754
|
+
this.savedPads = [];
|
|
3755
|
+
this.nextPadId = 1;
|
|
3756
|
+
this.pad.clear();
|
|
3757
|
+
if (raw === void 0 || raw === null) return;
|
|
3758
|
+
const r = raw;
|
|
3759
|
+
if (typeof r.current === "string") {
|
|
3760
|
+
try {
|
|
3761
|
+
this.pad.fromPng(r.current);
|
|
3762
|
+
} catch (e) {
|
|
3763
|
+
problems.push(`The mixing pad could not be read (${e.message}); it starts empty.`);
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
if (Array.isArray(r.saved)) {
|
|
3767
|
+
r.saved.forEach((p, i) => {
|
|
3768
|
+
const x = p;
|
|
3769
|
+
if (!x || typeof x.png !== "string" || typeof x.name !== "string") {
|
|
3770
|
+
problems.push(`mixingPad.saved[${i}] is not a saved pad; skipped.`);
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3773
|
+
const id = typeof x.id === "string" && /^pad\d+$/.test(x.id) ? x.id : `pad${this.nextPadId}`;
|
|
3774
|
+
const n = Number(id.slice(3));
|
|
3775
|
+
if (n >= this.nextPadId) this.nextPadId = n + 1;
|
|
3776
|
+
this.savedPads.push({ id, name: x.name, png: x.png });
|
|
3777
|
+
});
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3221
3780
|
/** A layer's tile surface (live while stroking), for thumbnails. */
|
|
3222
3781
|
layerSurface(id) {
|
|
3223
|
-
const l = _optionalChain([
|
|
3782
|
+
const l = _optionalChain([_chunkPOGBUYWEcjs.findLayer.call(void 0, this.currentLayers(), id), 'optionalAccess', _97 => _97.layer]);
|
|
3224
3783
|
return isPixelLayer(l) ? l.surface : null;
|
|
3225
3784
|
}
|
|
3226
|
-
},
|
|
3785
|
+
}, _class10);
|
|
3227
3786
|
var MAX_IMAGE_SIDE = 8192;
|
|
3228
3787
|
function resampleInto(src, rect, width, height) {
|
|
3229
3788
|
const out = new Uint8ClampedArray(width * height * 4);
|
|
@@ -3274,8 +3833,8 @@ function strokeSchedule(points) {
|
|
|
3274
3833
|
return total > 0 ? acc.map((d) => d / total) : points.map(() => 1);
|
|
3275
3834
|
}
|
|
3276
3835
|
function strokeDuration(points, max = 1800) {
|
|
3277
|
-
const t0 = _optionalChain([points, 'access',
|
|
3278
|
-
const t1 = _optionalChain([points, 'access',
|
|
3836
|
+
const t0 = _optionalChain([points, 'access', _98 => _98[0], 'optionalAccess', _99 => _99.t]);
|
|
3837
|
+
const t1 = _optionalChain([points, 'access', _100 => _100[points.length - 1], 'optionalAccess', _101 => _101.t]);
|
|
3279
3838
|
let ms;
|
|
3280
3839
|
if (points.every((p) => Number.isFinite(p.t)) && t1 > t0) ms = t1 - t0;
|
|
3281
3840
|
else {
|
|
@@ -3329,7 +3888,7 @@ var PaintDirector = class {
|
|
|
3329
3888
|
}
|
|
3330
3889
|
where(id) {
|
|
3331
3890
|
const a = this.presence.get(id);
|
|
3332
|
-
return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess',
|
|
3891
|
+
return { x: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _102 => _102.x]), () => ( 0)), y: _nullishCoalesce(_optionalChain([a, 'optionalAccess', _103 => _103.y]), () => ( 0)) };
|
|
3333
3892
|
}
|
|
3334
3893
|
/** Glides to `to`; an actor that just appeared starts there instead of the corner. */
|
|
3335
3894
|
async glide(id, to, ms = 380) {
|
|
@@ -3376,8 +3935,8 @@ var PaintDirector = class {
|
|
|
3376
3935
|
}
|
|
3377
3936
|
case "replay": {
|
|
3378
3937
|
await this.say(id, command.note, 500);
|
|
3379
|
-
const source = c.getStrokes().filter((s) => _optionalChain([command, 'access',
|
|
3380
|
-
const first = _optionalChain([source, 'access',
|
|
3938
|
+
const source = c.getStrokes().filter((s) => _optionalChain([command, 'access', _104 => _104.replay, 'access', _105 => _105.strokeIds, 'optionalAccess', _106 => _106.includes, 'call', _107 => _107(s.id)]));
|
|
3939
|
+
const first = _optionalChain([source, 'access', _108 => _108[0], 'optionalAccess', _109 => _109.points, 'access', _110 => _110[0]]);
|
|
3381
3940
|
if (first) await this.glide(id, first);
|
|
3382
3941
|
const result = c.replayStrokes(command.replay);
|
|
3383
3942
|
if (result.bounds) await this.glide(id, centre(result.bounds), 520);
|
|
@@ -3675,7 +4234,7 @@ function createPaintGuideTools(c) {
|
|
|
3675
4234
|
{
|
|
3676
4235
|
name: "mixing_pad_stroke",
|
|
3677
4236
|
title: "Paint on the mixing pad",
|
|
3678
|
-
description: "Paints on the mixing pad (a 360 \xD7 220 scratch canvas, not the painting): tool paint lays down a colour with a pigment Mixer Brush; tool knife smears what is there like a palette knife, mixing it as paint. Points are pad pixels. Not an undo step. Returns the changed bounds; then pick_mixing_pad_color.",
|
|
4237
|
+
description: "Paints on the mixing pad (a 360 \xD7 220 scratch canvas, not the painting): tool paint lays down a colour with a pigment Mixer Brush; tool knife smears what is there like a palette knife, mixing it as paint. Points are pad pixels. Not an undo step. Returns the changed bounds; then pick_mixing_pad_color. For a measured mix in one call use mix_on_pad.",
|
|
3679
4238
|
inputSchema: {
|
|
3680
4239
|
type: "object",
|
|
3681
4240
|
properties: {
|
|
@@ -3730,6 +4289,73 @@ function createPaintGuideTools(c) {
|
|
|
3730
4289
|
return { cleared: true };
|
|
3731
4290
|
}
|
|
3732
4291
|
},
|
|
4292
|
+
{
|
|
4293
|
+
name: "mix_on_pad",
|
|
4294
|
+
title: "Mix paints on the pad",
|
|
4295
|
+
description: "Mixes paints on the mixing pad as a painter would: blobs whose areas follow their parts, worked with the palette knife, and a fully mixed core of the Kubelka-Munk (pigment) mix, so blue and yellow make green and white tints. One call per mix. Not an undo step (the pad is scratch space). Returns the mixed colour #rrggbb and the pile bounds in pad pixels; with setColor it becomes the paint colour. pick_mixing_pad_color reads the streaks around it.",
|
|
4296
|
+
inputSchema: {
|
|
4297
|
+
type: "object",
|
|
4298
|
+
properties: {
|
|
4299
|
+
paints: {
|
|
4300
|
+
type: "array",
|
|
4301
|
+
minItems: 1,
|
|
4302
|
+
maxItems: 8,
|
|
4303
|
+
description: "The paints, 1 to 8.",
|
|
4304
|
+
items: {
|
|
4305
|
+
type: "object",
|
|
4306
|
+
properties: {
|
|
4307
|
+
color: { ...COLOR, description: "Paint colour #rrggbb." },
|
|
4308
|
+
parts: { type: "number", minimum: 0, description: "Parts of this paint, any scale (1 and 3 for a 1:3 mix); at least one above 0." }
|
|
4309
|
+
},
|
|
4310
|
+
required: ["color", "parts"],
|
|
4311
|
+
additionalProperties: false
|
|
4312
|
+
}
|
|
4313
|
+
},
|
|
4314
|
+
x: { type: "number", minimum: 0, maximum: 360, description: "Centre of the pile, pad x (default 180)." },
|
|
4315
|
+
y: { type: "number", minimum: 0, maximum: 220, description: "Centre of the pile, pad y (default 110)." },
|
|
4316
|
+
radius: { type: "number", minimum: 12, maximum: 100, description: "Radius of the pile in pad pixels (default 40); it must fit on the pad." },
|
|
4317
|
+
passes: { type: "integer", minimum: 1, maximum: 20, description: "Palette-knife passes (default 3; more gives finer streaks around the core)." },
|
|
4318
|
+
clear: { type: "boolean", description: "Wipe the pile's area first (default true); false mixes into the paint already there." },
|
|
4319
|
+
setColor: { type: "boolean", description: "Also make the mix the paint colour (default false)." }
|
|
4320
|
+
},
|
|
4321
|
+
required: ["paints"],
|
|
4322
|
+
additionalProperties: false
|
|
4323
|
+
},
|
|
4324
|
+
annotations: { title: "Mix paints on the pad", ...WRITE },
|
|
4325
|
+
handler: ({ paints, x, y, radius, passes, clear, setColor }) => c.mixOnPad(paints, { x, y, radius, passes, clear, setColor })
|
|
4326
|
+
},
|
|
4327
|
+
{
|
|
4328
|
+
name: "save_mixing_pad",
|
|
4329
|
+
title: "Keep the mixing pad",
|
|
4330
|
+
description: "Keeps the mixing pad as it is now under a name, saved with the document, to come back to with load_mixing_pad. Refused while the pad is empty. Returns the kept pad id and name.",
|
|
4331
|
+
inputSchema: { type: "object", properties: { name: { type: "string", minLength: 1, maxLength: 80, description: 'Name (default "Pad n").' } }, additionalProperties: false },
|
|
4332
|
+
annotations: { title: "Keep the mixing pad", ...WRITE },
|
|
4333
|
+
handler: ({ name }) => c.saveMixingPad(name)
|
|
4334
|
+
},
|
|
4335
|
+
{
|
|
4336
|
+
name: "list_mixing_pads",
|
|
4337
|
+
title: "List kept mixing pads",
|
|
4338
|
+
description: "Lists the mixing pads kept with save_mixing_pad (id, name). Changes nothing.",
|
|
4339
|
+
inputSchema: EMPTY,
|
|
4340
|
+
annotations: { title: "List kept mixing pads", ...READ },
|
|
4341
|
+
handler: () => ({ pads: c.listMixingPads() })
|
|
4342
|
+
},
|
|
4343
|
+
{
|
|
4344
|
+
name: "load_mixing_pad",
|
|
4345
|
+
title: "Load a kept mixing pad",
|
|
4346
|
+
description: "Puts a kept pad (id from list_mixing_pads) back on the mixing pad, replacing what is on it. Returns the pad id and name.",
|
|
4347
|
+
inputSchema: { type: "object", properties: { id: { type: "string", description: "Kept pad id from list_mixing_pads." } }, required: ["id"], additionalProperties: false },
|
|
4348
|
+
annotations: { title: "Load a kept mixing pad", ...DESTRUCTIVE },
|
|
4349
|
+
handler: ({ id }) => c.loadMixingPad(id)
|
|
4350
|
+
},
|
|
4351
|
+
{
|
|
4352
|
+
name: "remove_mixing_pad",
|
|
4353
|
+
title: "Remove a kept mixing pad",
|
|
4354
|
+
description: "Forgets a kept pad (id from list_mixing_pads); the pad on screen is untouched. Returns the removed id and name.",
|
|
4355
|
+
inputSchema: { type: "object", properties: { id: { type: "string", description: "Kept pad id from list_mixing_pads." } }, required: ["id"], additionalProperties: false },
|
|
4356
|
+
annotations: { title: "Remove a kept mixing pad", ...DESTRUCTIVE },
|
|
4357
|
+
handler: ({ id }) => c.removeMixingPad(id)
|
|
4358
|
+
},
|
|
3733
4359
|
{
|
|
3734
4360
|
name: "render_mixing_pad",
|
|
3735
4361
|
title: "Render the mixing pad",
|
|
@@ -3740,7 +4366,7 @@ function createPaintGuideTools(c) {
|
|
|
3740
4366
|
const pad = c.mixingPad;
|
|
3741
4367
|
return {
|
|
3742
4368
|
content: [
|
|
3743
|
-
{ type: "image", data:
|
|
4369
|
+
{ type: "image", data: _chunkPOGBUYWEcjs.bytesToBase64.call(void 0, _chunkPOGBUYWEcjs.encodePng.call(void 0, pad.width, pad.height, pad.pixels())), mimeType: "image/png" },
|
|
3744
4370
|
{ type: "text", text: `Mixing pad ${pad.width}\xD7${pad.height}` }
|
|
3745
4371
|
]
|
|
3746
4372
|
};
|
|
@@ -3761,7 +4387,7 @@ var TIP = {
|
|
|
3761
4387
|
type: "object",
|
|
3762
4388
|
description: "The tip (the shared brush engine). Missing fields keep their current values.",
|
|
3763
4389
|
properties: {
|
|
3764
|
-
size: { type: "number", minimum: 1, maximum:
|
|
4390
|
+
size: { type: "number", minimum: 1, maximum: _chunk7VOHOPLWcjs.MAX_BRUSH_SIZE, description: "Diameter in document pixels." },
|
|
3765
4391
|
hardness: { type: "number", minimum: 0, maximum: 1, description: "Edge hardness, 0 (soft) .. 1 (hard)." },
|
|
3766
4392
|
spacing: { type: "number", minimum: 0.01, maximum: 10, description: "Dab spacing as a fraction of the diameter (0.05 is smooth, 1 is dotted)." },
|
|
3767
4393
|
angle: { type: "number", minimum: -360, maximum: 360, description: "Tip angle in degrees, counter-clockwise; with rotation stroke or barrel it is added to the stroke direction or pen rotation." },
|
|
@@ -3773,7 +4399,7 @@ var TIP = {
|
|
|
3773
4399
|
pressureOpacity: { type: "boolean", description: "Pressure scales the opacity." },
|
|
3774
4400
|
blend: {
|
|
3775
4401
|
type: "string",
|
|
3776
|
-
enum:
|
|
4402
|
+
enum: _chunkXIOMMGPDcjs.BLEND_MODES.map((m) => m.id),
|
|
3777
4403
|
description: "How paint combines with the layer. pigment mixes it in like real paint (blue into yellow gives green); multiply darkens like marker ink; watercolor glazes like a transparent wash; tint, highlight and shadow recolour, light and shade (see list_blend_modes)."
|
|
3778
4404
|
}
|
|
3779
4405
|
},
|
|
@@ -3799,28 +4425,79 @@ var DYNAMICS = {
|
|
|
3799
4425
|
};
|
|
3800
4426
|
var MIXER = {
|
|
3801
4427
|
type: "object",
|
|
3802
|
-
description: "Mixer engine settings (Mixer Brush
|
|
4428
|
+
description: "Mixer engine settings (the Mixer Brush). Missing fields keep their current values.",
|
|
3803
4429
|
properties: {
|
|
3804
|
-
wet: { type: "number", minimum: 0, maximum: 1, description: "
|
|
4430
|
+
wet: { type: "number", minimum: 0, maximum: 1, description: "Pick-up ratio: how much canvas colour each dab picks up, 0 (dry) .. 1." },
|
|
3805
4431
|
load: { type: "number", minimum: 0, maximum: 1, description: "How much paint the reservoir holds; below 1 it drains per dab, so long strokes run dry." },
|
|
3806
|
-
mix: { type: "number", minimum: 0, maximum: 1, description: "
|
|
4432
|
+
mix: { type: "number", minimum: 0, maximum: 1, description: "Mix ratio: how far each dab's paint moves from the reservoir towards the picked-up colour." },
|
|
3807
4433
|
loadEachStroke: { type: "boolean", description: "Refill the reservoir with the colour before each stroke." },
|
|
3808
4434
|
cleanEachStroke: { type: "boolean", description: "Empty the pickup well after each stroke." },
|
|
3809
|
-
mixing: { type: "string", enum: [...
|
|
4435
|
+
mixing: { type: "string", enum: [..._chunk7VOHOPLWcjs.MIXING_MODELS], description: "rgb: RGB averages. pigment: mixes like paint (Kubelka-Munk)." }
|
|
4436
|
+
},
|
|
4437
|
+
additionalProperties: false
|
|
4438
|
+
};
|
|
4439
|
+
var MIXING = { type: "string", enum: [..._chunk7VOHOPLWcjs.MIXING_MODELS], description: "pigment: mixes like paint (Kubelka-Munk, blue and yellow make green); rgb: straight RGB averages." };
|
|
4440
|
+
var BEHAVIOR = {
|
|
4441
|
+
type: "object",
|
|
4442
|
+
description: "How the brush handles paint on the canvas (dab and mixer engines; on a mixer brush pickup, mix, dirty and mixing are its mixer wet, mix, !cleanEachStroke and mixing). Missing fields keep their current values.",
|
|
4443
|
+
properties: {
|
|
4444
|
+
pickup: { type: "number", minimum: 0, maximum: 1, description: "Pick-up ratio 0..1: how much of the paint under each dab the brush lifts and carries along (0: none, a dry brush)." },
|
|
4445
|
+
mix: { type: "number", minimum: 0, maximum: 1, description: "Mix ratio 0..1: how much of the carried paint goes into what the brush lays down, against the brush's own colour (scaled by pickup)." },
|
|
4446
|
+
dirty: { type: "boolean", description: "Dirty brush: keep the carried paint after the stroke, so the next stroke starts with the last colour it touched (needs pickup above 0). clean_mixer_brush wipes it." },
|
|
4447
|
+
mixing: MIXING,
|
|
4448
|
+
multicolor: {
|
|
4449
|
+
type: "object",
|
|
4450
|
+
description: "Multi-coloured brush. Missing fields keep their current values.",
|
|
4451
|
+
properties: {
|
|
4452
|
+
mode: { type: "string", enum: [...MULTI_COLOR_MODES], description: "off; tip: the colours lie side by side across the tip (stripes along the stroke, like a brush loaded with several paints); dab: the colour changes along the stroke." },
|
|
4453
|
+
colors: { type: "array", maxItems: 8, items: { ...COLOR2 }, description: "2..8 colours #rrggbb; fewer than 2 uses the paint colour and the secondary colour." },
|
|
4454
|
+
order: { type: "string", enum: ["sequence", "random"], description: "dab mode: sequence runs through the colours in order, blending between them; random picks one per run of dabs (seeded)." },
|
|
4455
|
+
length: { type: "integer", minimum: 1, maximum: 500, description: "dab mode: dabs per colour (default 12)." },
|
|
4456
|
+
softness: { type: "number", minimum: 0, maximum: 1, description: "How softly neighbouring colours blend: 0 hard stripes or steps, 1 a smooth gradient." }
|
|
4457
|
+
},
|
|
4458
|
+
additionalProperties: false
|
|
4459
|
+
}
|
|
4460
|
+
},
|
|
4461
|
+
additionalProperties: false
|
|
4462
|
+
};
|
|
4463
|
+
var BLENDER = {
|
|
4464
|
+
type: "object",
|
|
4465
|
+
description: "Blender engine settings. Missing fields keep their current values.",
|
|
4466
|
+
properties: {
|
|
4467
|
+
strength: { type: "number", minimum: 0, maximum: 1, description: "How far each pixel under the tip moves towards the mix of the paint near it, per dab." },
|
|
4468
|
+
distance: { type: "number", minimum: 0, maximum: 1, description: "Blend distance: how far away colours are mixed in, as a fraction of the tip diameter (0.35 default; higher blends wider and softer)." },
|
|
4469
|
+
mixing: MIXING
|
|
4470
|
+
},
|
|
4471
|
+
additionalProperties: false
|
|
4472
|
+
};
|
|
4473
|
+
var SMUDGE = {
|
|
4474
|
+
type: "object",
|
|
4475
|
+
description: "Smudge engine settings. Missing fields keep their current values.",
|
|
4476
|
+
properties: {
|
|
4477
|
+
strength: { type: "number", minimum: 0, maximum: 1, description: "How strongly the dragged paint covers what is under the tip, per dab." },
|
|
4478
|
+
length: { type: "number", minimum: 0, maximum: 1, description: "How far paint is dragged: the share of the carried paint kept from dab to dab (0.85 default; 1 drags it the whole stroke)." },
|
|
4479
|
+
mixing: { ...MIXING, description: "rgb (default): smeared colours average; pigment: they mix like paint." }
|
|
3810
4480
|
},
|
|
3811
4481
|
additionalProperties: false
|
|
3812
4482
|
};
|
|
3813
4483
|
var BRUSH_FIELDS = {
|
|
3814
4484
|
name: { type: "string", minLength: 1, maxLength: 80, description: "Display name." },
|
|
3815
4485
|
category: { type: "string", enum: [...PAINT_BRUSH_CATEGORIES], description: "Library category." },
|
|
3816
|
-
engine: {
|
|
4486
|
+
engine: {
|
|
4487
|
+
type: "string",
|
|
4488
|
+
enum: [...PAINT_BRUSH_ENGINES],
|
|
4489
|
+
description: "dab: paints dabs (with behavior.pickup or multicolor it paints dab by dab, lifting and mixing paint); eraser: removes paint; mixer: the Mixer Brush (a reservoir plus picked-up paint); blender: mixes the colours under and near the tip; smudge: drags paint along the stroke."
|
|
4490
|
+
},
|
|
3817
4491
|
tip: TIP,
|
|
3818
4492
|
grain: { type: "number", minimum: 0, maximum: 1, description: "Paper grain response: 0 ignores the grain, 1 catches only its peaks at light pressure (pencil, pastel, charcoal). Multiplied by the paper depth." },
|
|
3819
4493
|
pressureSmoothing: { type: "number", minimum: 0, maximum: 0.95, description: "Pressure smoothing, separate from the tip position smoothing." },
|
|
3820
4494
|
rotation: { type: "string", enum: [...BRUSH_ROTATIONS], description: "What turns the tip: fixed (tip.angle), stroke (follows the direction of travel) or barrel (the pen barrel rotation, twist)." },
|
|
3821
4495
|
dynamics: DYNAMICS,
|
|
3822
4496
|
mixer: MIXER,
|
|
3823
|
-
loadsColor: { type: "boolean", description: "Mixer engine: load the colour each stroke (false for
|
|
4497
|
+
loadsColor: { type: "boolean", description: "Mixer engine: load the colour each stroke (false for a mixer that only moves paint)." },
|
|
4498
|
+
behavior: BEHAVIOR,
|
|
4499
|
+
blender: BLENDER,
|
|
4500
|
+
smudge: SMUDGE
|
|
3824
4501
|
};
|
|
3825
4502
|
var POINTS = {
|
|
3826
4503
|
type: "array",
|
|
@@ -3849,7 +4526,20 @@ function loadResult(load) {
|
|
|
3849
4526
|
return { reservoir: hex(load.reservoir), amount: Math.round(load.amount * 1e3) / 1e3, pickup: hex(load.pickup) };
|
|
3850
4527
|
}
|
|
3851
4528
|
function brushSummary(b) {
|
|
3852
|
-
return {
|
|
4529
|
+
return {
|
|
4530
|
+
id: b.id,
|
|
4531
|
+
name: b.name,
|
|
4532
|
+
category: b.category,
|
|
4533
|
+
engine: b.engine,
|
|
4534
|
+
size: b.tip.size,
|
|
4535
|
+
grain: b.grain,
|
|
4536
|
+
rotation: b.rotation,
|
|
4537
|
+
wetCapable: isWetCapable(b),
|
|
4538
|
+
pickup: b.behavior.pickup,
|
|
4539
|
+
dirty: b.behavior.dirty,
|
|
4540
|
+
multicolor: b.behavior.multicolor.mode,
|
|
4541
|
+
builtin: Boolean(b.builtin)
|
|
4542
|
+
};
|
|
3853
4543
|
}
|
|
3854
4544
|
function createPaintEditorToolProvider(controller, options = {}) {
|
|
3855
4545
|
const c = controller;
|
|
@@ -3885,7 +4575,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
3885
4575
|
strokes: d.strokes.length,
|
|
3886
4576
|
undo: s.undoLabel,
|
|
3887
4577
|
redo: s.redoLabel,
|
|
3888
|
-
blendModes:
|
|
4578
|
+
blendModes: _chunkXIOMMGPDcjs.BLEND_MODES.map((m) => m.id)
|
|
3889
4579
|
};
|
|
3890
4580
|
}
|
|
3891
4581
|
});
|
|
@@ -4018,7 +4708,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4018
4708
|
opacity: { type: "number", minimum: 0, maximum: 1, description: "Layer opacity 0..1." },
|
|
4019
4709
|
blend: {
|
|
4020
4710
|
type: "string",
|
|
4021
|
-
enum: [...
|
|
4711
|
+
enum: [..._chunkXIOMMGPDcjs.BLEND_MODES.map((m) => m.id), "pass-through"],
|
|
4022
4712
|
description: "Blend mode (pass-through for groups only). Painterly modes: watercolor (the layer glazes like a transparent wash), tint (recolours keeping lightness), highlight (adds soft coloured light), shadow (shades with ambient fill); see list_blend_modes."
|
|
4023
4713
|
},
|
|
4024
4714
|
clipped: { type: "boolean", description: "Clip to the layer below (paint only shows where it has paint)." },
|
|
@@ -4047,12 +4737,12 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4047
4737
|
inputSchema: EMPTY2,
|
|
4048
4738
|
annotations: { title: "List blend modes", ...READ2 },
|
|
4049
4739
|
handler: () => ({
|
|
4050
|
-
modes:
|
|
4740
|
+
modes: _chunkXIOMMGPDcjs.BLEND_MODES.map((m) => ({
|
|
4051
4741
|
id: m.id,
|
|
4052
4742
|
label: m.label,
|
|
4053
4743
|
group: m.painterly ? "painterly" : m.id === "pigment" ? "pigment" : "standard",
|
|
4054
4744
|
...m.description ? { description: m.description } : {},
|
|
4055
|
-
psd:
|
|
4745
|
+
psd: _chunkXIOMMGPDcjs.standardBlendMode.call(void 0, m.id)
|
|
4056
4746
|
}))
|
|
4057
4747
|
})
|
|
4058
4748
|
});
|
|
@@ -4120,7 +4810,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4120
4810
|
opacity: { type: "number", minimum: 0, maximum: 1, description: "Opacity 0..1 (default 1)." },
|
|
4121
4811
|
grain: { type: "number", minimum: 0, maximum: 1, description: "Paper grain response 0..1 (default 0: flat)." },
|
|
4122
4812
|
pressure: { type: "number", minimum: 0, maximum: 1, description: "With grain: how far into the valleys, 0..1 (default 0.5)." },
|
|
4123
|
-
blend: { type: "string", enum:
|
|
4813
|
+
blend: { type: "string", enum: _chunkXIOMMGPDcjs.BLEND_MODES.map((m) => m.id), description: "Blend mode (default normal; pigment mixes like paint, watercolor glazes; see list_blend_modes)." }
|
|
4124
4814
|
},
|
|
4125
4815
|
additionalProperties: false
|
|
4126
4816
|
},
|
|
@@ -4138,18 +4828,18 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4138
4828
|
add({
|
|
4139
4829
|
name: "list_brushes",
|
|
4140
4830
|
title: "List brushes",
|
|
4141
|
-
description: "Lists the brush library: built-in dry media (pencils, pastels, charcoal, airbrush, marker, ink, erasers, blender, smudge, Mixer Brush) and saved user brushes, with id, name, category, engine, size, grain response and
|
|
4831
|
+
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) 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.",
|
|
4142
4832
|
inputSchema: EMPTY2,
|
|
4143
4833
|
annotations: { title: "List brushes", ...READ2 },
|
|
4144
4834
|
handler: () => {
|
|
4145
4835
|
const s = c.getState();
|
|
4146
|
-
return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access',
|
|
4836
|
+
return { activeBrushId: s.brush.id, activeEdited: !s.brush.builtin && Boolean(_optionalChain([c, 'access', _111 => _111.getBrush, 'call', _112 => _112(s.brush.id), 'optionalAccess', _113 => _113.builtin])), brushes: s.brushes.map(brushSummary) };
|
|
4147
4837
|
}
|
|
4148
4838
|
});
|
|
4149
4839
|
add({
|
|
4150
4840
|
name: "get_brush",
|
|
4151
4841
|
title: "Get a brush",
|
|
4152
|
-
description: "Reads every setting of a brush (tip, grain, pressure smoothing, rotation, dynamics, mixer). Without id, the active brush as edited.",
|
|
4842
|
+
description: "Reads every setting of a brush (tip, grain, pressure smoothing, rotation, dynamics, mixer, behavior: pick-up / mix / dirty / multi-colour, blender, smudge). Without id, the active brush as edited.",
|
|
4153
4843
|
inputSchema: { type: "object", properties: { id: { type: "string", description: "Brush id from list_brushes (default the active brush)." } }, additionalProperties: false },
|
|
4154
4844
|
annotations: { title: "Get a brush", ...READ2 },
|
|
4155
4845
|
handler: ({ id }) => {
|
|
@@ -4241,7 +4931,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4241
4931
|
const t = c.brushThumbnail(_nullishCoalesce(id, () => ( c.getState().brush.id)), { width, height, color });
|
|
4242
4932
|
return {
|
|
4243
4933
|
content: [
|
|
4244
|
-
{ type: "image", data:
|
|
4934
|
+
{ type: "image", data: _chunkPOGBUYWEcjs.bytesToBase64.call(void 0, _chunkPOGBUYWEcjs.encodePng.call(void 0, t.width, t.height, t.data)), mimeType: "image/png" },
|
|
4245
4935
|
{ type: "text", text: `Brush ${_nullishCoalesce(id, () => ( c.getState().brush.id))} ${t.width}\xD7${t.height}` }
|
|
4246
4936
|
]
|
|
4247
4937
|
};
|
|
@@ -4284,7 +4974,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4284
4974
|
add({
|
|
4285
4975
|
name: "get_mixer_brush",
|
|
4286
4976
|
title: "Get the Mixer Brush load",
|
|
4287
|
-
description: "Reads what the
|
|
4977
|
+
description: "Reads what the brush carries between strokes: reservoir #rrggbb or null (the Mixer Brush's loaded paint), amount 0..1 left, pickup #rrggbb or null (paint picked up from the canvas, kept by dirty brushes and a Mixer Brush that does not clean each stroke). Call before painting with mixer-brush when its loadEachStroke is false, or with a dirty brush.",
|
|
4288
4978
|
inputSchema: EMPTY2,
|
|
4289
4979
|
annotations: { title: "Get the Mixer Brush load", ...READ2 },
|
|
4290
4980
|
handler: () => loadResult(c.getState().mixerLoad)
|
|
@@ -4300,7 +4990,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4300
4990
|
add({
|
|
4301
4991
|
name: "clean_mixer_brush",
|
|
4302
4992
|
title: "Clean the Mixer Brush",
|
|
4303
|
-
description: "
|
|
4993
|
+
description: "Cleans the brush: empties the picked-up paint a dirty brush or the Mixer Brush carries (and with emptyReservoir the Mixer Brush paint too). Editor state, not an undo step. Returns the load.",
|
|
4304
4994
|
inputSchema: { type: "object", properties: { emptyReservoir: { type: "boolean", description: "Also drop the loaded paint (default false)." } }, additionalProperties: false },
|
|
4305
4995
|
annotations: { title: "Clean the Mixer Brush", ...SET2 },
|
|
4306
4996
|
handler: ({ emptyReservoir }) => loadResult(c.cleanMixerBrush(emptyReservoir === true))
|
|
@@ -4308,7 +4998,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4308
4998
|
add({
|
|
4309
4999
|
name: "paint_stroke",
|
|
4310
5000
|
title: "Paint a brush stroke",
|
|
4311
|
-
description: "Paints one stroke through points (document pixels, with optional pressure, time, tilt and barrel rotation) on a pixel layer with a library brush or the active one, optionally changed for this stroke. Grain-responsive brushes follow the paper; the mixer engine (mixer-brush
|
|
5001
|
+
description: "Paints one stroke through points (document pixels, with optional pressure, time, tilt and barrel rotation) on a pixel layer with a library brush or the active one, optionally changed for this stroke. Grain-responsive brushes follow the paper; the mixer engine (mixer-brush) picks up and mixes paint already on the layer, the blender mixes nearby colours, the smudge drags paint, and dab brushes with behavior.pickup lift and carry paint. The symmetry guide adds its mirror copies; with a tracing image that samples colours, a stroke without color takes the image colour at its first point. With an agent cursor (a director), the stroke is painted live along the points at the pace of their times. One undo step. Returns the layer id, changed bounds, dab count, the recorded strokeId (for replay_strokes) and, for brushes that pick up paint, mixerLoad: what the brush carries after the stroke.",
|
|
4312
5002
|
inputSchema: {
|
|
4313
5003
|
type: "object",
|
|
4314
5004
|
properties: {
|
|
@@ -4363,7 +5053,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4363
5053
|
color: s.color,
|
|
4364
5054
|
points: ids ? s.points : s.points.length,
|
|
4365
5055
|
seed: s.seed,
|
|
4366
|
-
copies: _nullishCoalesce(_optionalChain([s, 'access',
|
|
5056
|
+
copies: _nullishCoalesce(_optionalChain([s, 'access', _114 => _114.copies, 'optionalAccess', _115 => _115.length]), () => ( 0)),
|
|
4367
5057
|
bounds: { x: Math.floor(Math.min(...xs) - pad), y: Math.floor(Math.min(...ys) - pad), width: Math.ceil(Math.max(...xs) - Math.min(...xs) + 2 * pad), height: Math.ceil(Math.max(...ys) - Math.min(...ys) + 2 * pad) }
|
|
4368
5058
|
};
|
|
4369
5059
|
})
|
|
@@ -4496,7 +5186,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4496
5186
|
annotations: { title: "Export the painting", ...READ2 },
|
|
4497
5187
|
handler: async ({ format, quality, scale, paper }) => {
|
|
4498
5188
|
const bytes = await c.exportImage({ format, quality, scale, paper });
|
|
4499
|
-
return { mimeType: _nullishCoalesce(format, () => ( "image/png")), bytes: bytes.length, data:
|
|
5189
|
+
return { mimeType: _nullishCoalesce(format, () => ( "image/png")), bytes: bytes.length, data: _chunkPOGBUYWEcjs.bytesToBase64.call(void 0, bytes) };
|
|
4500
5190
|
}
|
|
4501
5191
|
});
|
|
4502
5192
|
add({
|
|
@@ -4507,7 +5197,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4507
5197
|
annotations: { title: "Export as PSD", ...READ2 },
|
|
4508
5198
|
handler: () => {
|
|
4509
5199
|
const r = c.exportPsd();
|
|
4510
|
-
return { data:
|
|
5200
|
+
return { data: _chunkPOGBUYWEcjs.bytesToBase64.call(void 0, r.bytes), bytes: r.bytes.length, psb: r.psb, warnings: r.warnings };
|
|
4511
5201
|
}
|
|
4512
5202
|
});
|
|
4513
5203
|
add({
|
|
@@ -4531,7 +5221,7 @@ function createPaintEditorToolProvider(controller, options = {}) {
|
|
|
4531
5221
|
}
|
|
4532
5222
|
});
|
|
4533
5223
|
tools.push(...createPaintGuideTools(c));
|
|
4534
|
-
tools.push(...
|
|
5224
|
+
tools.push(..._chunk7VOHOPLWcjs.createPigmentTools.call(void 0, ));
|
|
4535
5225
|
return { id: _nullishCoalesce(options.id, () => ( "paint-editor")), namespace: options.namespace, tools };
|
|
4536
5226
|
}
|
|
4537
5227
|
|
|
@@ -4542,21 +5232,21 @@ var PAINT_TOOLS = [
|
|
|
4542
5232
|
{ id: "pan", label: "Pan", key: "h" },
|
|
4543
5233
|
{ id: "rotate", label: "Rotate view", key: "r" }
|
|
4544
5234
|
];
|
|
4545
|
-
var PaintGesture = (
|
|
4546
|
-
constructor(controller, box) {;
|
|
5235
|
+
var PaintGesture = (_class11 = class {
|
|
5236
|
+
constructor(controller, box) {;_class11.prototype.__init66.call(this);_class11.prototype.__init67.call(this);_class11.prototype.__init68.call(this);_class11.prototype.__init69.call(this);_class11.prototype.__init70.call(this);_class11.prototype.__init71.call(this);
|
|
4547
5237
|
this.controller = controller;
|
|
4548
5238
|
this.box = box;
|
|
4549
5239
|
}
|
|
4550
5240
|
|
|
4551
5241
|
|
|
4552
|
-
|
|
5242
|
+
__init66() {this.tool = "brush"}
|
|
4553
5243
|
/** The last refusal (a hidden or locked layer), for the editor to show. */
|
|
4554
|
-
|
|
5244
|
+
__init67() {this.error = null}
|
|
4555
5245
|
/** The predicted tail of the current stroke in document pixels (draw it as a thin preview). */
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
5246
|
+
__init68() {this.predicted = []}
|
|
5247
|
+
__init69() {this.mode = null}
|
|
5248
|
+
__init70() {this.penAt = null}
|
|
5249
|
+
__init71() {this.penDown = false}
|
|
4560
5250
|
doc(e) {
|
|
4561
5251
|
const b = this.box();
|
|
4562
5252
|
const s = this.controller.getState();
|
|
@@ -4637,12 +5327,12 @@ var PaintGesture = (_class10 = class {
|
|
|
4637
5327
|
if (!m || m.pointerId !== e.pointerId) return;
|
|
4638
5328
|
this.mode = null;
|
|
4639
5329
|
this.predicted = [];
|
|
4640
|
-
if (m.kind === "stroke") _optionalChain([this, 'access',
|
|
5330
|
+
if (m.kind === "stroke") _optionalChain([this, 'access', _116 => _116.controller, 'access', _117 => _117.activeStroke, 'optionalAccess', _118 => _118.end, 'call', _119 => _119()]);
|
|
4641
5331
|
}
|
|
4642
5332
|
cancel() {
|
|
4643
5333
|
this.penDown = false;
|
|
4644
5334
|
this.predicted = [];
|
|
4645
|
-
if (_optionalChain([this, 'access',
|
|
5335
|
+
if (_optionalChain([this, 'access', _120 => _120.mode, 'optionalAccess', _121 => _121.kind]) === "stroke") _optionalChain([this, 'access', _122 => _122.controller, 'access', _123 => _123.activeStroke, 'optionalAccess', _124 => _124.cancel, 'call', _125 => _125()]);
|
|
4646
5336
|
this.mode = null;
|
|
4647
5337
|
}
|
|
4648
5338
|
get active() {
|
|
@@ -4662,7 +5352,7 @@ var PaintGesture = (_class10 = class {
|
|
|
4662
5352
|
const py = e.clientY - b.top - b.height / 2;
|
|
4663
5353
|
this.controller.setView({ zoom, pan: { x: px - (px - s.view.pan.x) * k, y: py - (py - s.view.pan.y) * k } });
|
|
4664
5354
|
}
|
|
4665
|
-
},
|
|
5355
|
+
}, _class11);
|
|
4666
5356
|
function handlePaintShortcut(controller, gesture, e) {
|
|
4667
5357
|
const mod = e.ctrlKey || e.metaKey;
|
|
4668
5358
|
const key = e.key.toLowerCase();
|
|
@@ -4702,14 +5392,14 @@ function handlePaintShortcut(controller, gesture, e) {
|
|
|
4702
5392
|
}
|
|
4703
5393
|
return false;
|
|
4704
5394
|
}
|
|
4705
|
-
var PaintCanvasPresenter = (
|
|
4706
|
-
constructor(controller) {;
|
|
5395
|
+
var PaintCanvasPresenter = (_class12 = class {
|
|
5396
|
+
constructor(controller) {;_class12.prototype.__init72.call(this);_class12.prototype.__init73.call(this);_class12.prototype.__init74.call(this);
|
|
4707
5397
|
this.controller = controller;
|
|
4708
5398
|
}
|
|
4709
5399
|
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
5400
|
+
__init72() {this.uploaded = /* @__PURE__ */ new Map()}
|
|
5401
|
+
__init73() {this.scratch = null}
|
|
5402
|
+
__init74() {this.size = ""}
|
|
4713
5403
|
/** Draws what changed into `ctx` (a canvas the size of the document); returns the tiles drawn. */
|
|
4714
5404
|
render(ctx) {
|
|
4715
5405
|
const { width, height } = this.controller.document.canvas;
|
|
@@ -4726,16 +5416,16 @@ var PaintCanvasPresenter = (_class11 = class {
|
|
|
4726
5416
|
const key = `${tx},${ty}`;
|
|
4727
5417
|
if (this.uploaded.get(key) === data) return;
|
|
4728
5418
|
this.uploaded.set(key, data);
|
|
4729
|
-
if (!this.scratch) this.scratch = ctx.createImageData(
|
|
5419
|
+
if (!this.scratch) this.scratch = ctx.createImageData(_chunkXIOMMGPDcjs.TILE, _chunkXIOMMGPDcjs.TILE);
|
|
4730
5420
|
this.scratch.data.set(data);
|
|
4731
|
-
const ox = tx *
|
|
4732
|
-
const oy = ty *
|
|
4733
|
-
ctx.putImageData(this.scratch, ox, oy, 0, 0, Math.min(
|
|
5421
|
+
const ox = tx * _chunkXIOMMGPDcjs.TILE;
|
|
5422
|
+
const oy = ty * _chunkXIOMMGPDcjs.TILE;
|
|
5423
|
+
ctx.putImageData(this.scratch, ox, oy, 0, 0, Math.min(_chunkXIOMMGPDcjs.TILE, width - ox), Math.min(_chunkXIOMMGPDcjs.TILE, height - oy));
|
|
4734
5424
|
drawn++;
|
|
4735
5425
|
}, { dirty });
|
|
4736
5426
|
return drawn;
|
|
4737
5427
|
}
|
|
4738
|
-
},
|
|
5428
|
+
}, _class12);
|
|
4739
5429
|
function guideOverlay(controller) {
|
|
4740
5430
|
const s = controller.getState();
|
|
4741
5431
|
const size = s.document.canvas;
|
|
@@ -4770,7 +5460,7 @@ var PAPER_SLIDERS = [
|
|
|
4770
5460
|
];
|
|
4771
5461
|
function readPath(obj, path) {
|
|
4772
5462
|
let v = obj;
|
|
4773
|
-
for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess',
|
|
5463
|
+
for (const k of path.split(".")) v = _optionalChain([v, 'optionalAccess', _126 => _126[k]]);
|
|
4774
5464
|
return typeof v === "number" ? v : 0;
|
|
4775
5465
|
}
|
|
4776
5466
|
function patchPath(obj, path, value) {
|
|
@@ -4812,9 +5502,88 @@ function wheelPick(dx, dy, wheel, color) {
|
|
|
4812
5502
|
return rgbToHexColor(nr, ng, nb);
|
|
4813
5503
|
}
|
|
4814
5504
|
var BLEND_MENU_GROUPS = [
|
|
4815
|
-
{ label: "Standard", modes:
|
|
4816
|
-
{ label: "Paint", modes:
|
|
5505
|
+
{ label: "Standard", modes: _chunkXIOMMGPDcjs.BLEND_MODES.filter((m) => !m.painterly && m.id !== "pigment") },
|
|
5506
|
+
{ label: "Paint", modes: _chunkXIOMMGPDcjs.BLEND_MODES.filter((m) => m.painterly || m.id === "pigment") }
|
|
4817
5507
|
];
|
|
5508
|
+
var PICKUP_SLIDERS = [
|
|
5509
|
+
{ path: "behavior.pickup", label: "Pick-up", min: 0, max: 1, step: 0.01 },
|
|
5510
|
+
{ path: "behavior.mix", label: "Mix", min: 0, max: 1, step: 0.01 }
|
|
5511
|
+
];
|
|
5512
|
+
function brushEngineControls(brush) {
|
|
5513
|
+
switch (brush.engine) {
|
|
5514
|
+
case "blender":
|
|
5515
|
+
return {
|
|
5516
|
+
title: "Blender",
|
|
5517
|
+
sliders: [
|
|
5518
|
+
{ path: "blender.strength", label: "Strength", min: 0, max: 1, step: 0.01 },
|
|
5519
|
+
{ path: "blender.distance", label: "Blend distance", min: 0, max: 1, step: 0.01 }
|
|
5520
|
+
],
|
|
5521
|
+
mixingPath: "blender.mixing",
|
|
5522
|
+
dirty: false,
|
|
5523
|
+
multicolor: false,
|
|
5524
|
+
load: false
|
|
5525
|
+
};
|
|
5526
|
+
case "smudge":
|
|
5527
|
+
return {
|
|
5528
|
+
title: "Smudge",
|
|
5529
|
+
sliders: [
|
|
5530
|
+
{ path: "smudge.strength", label: "Strength", min: 0, max: 1, step: 0.01 },
|
|
5531
|
+
{ path: "smudge.length", label: "Length", min: 0, max: 1, step: 0.01 }
|
|
5532
|
+
],
|
|
5533
|
+
mixingPath: "smudge.mixing",
|
|
5534
|
+
dirty: false,
|
|
5535
|
+
multicolor: false,
|
|
5536
|
+
load: false
|
|
5537
|
+
};
|
|
5538
|
+
case "mixer":
|
|
5539
|
+
return { title: "Mixer Brush", sliders: [...PICKUP_SLIDERS, { path: "mixer.load", label: "Load", min: 0, max: 1, step: 0.01 }], mixingPath: "behavior.mixing", dirty: true, multicolor: true, load: true };
|
|
5540
|
+
case "dab":
|
|
5541
|
+
return { title: "Paint behaviour", sliders: PICKUP_SLIDERS, mixingPath: "behavior.mixing", dirty: true, multicolor: true, load: true };
|
|
5542
|
+
default:
|
|
5543
|
+
return null;
|
|
5544
|
+
}
|
|
5545
|
+
}
|
|
5546
|
+
function multiColorSliders(mode) {
|
|
5547
|
+
if (mode === "off") return [];
|
|
5548
|
+
const soft = { path: "behavior.multicolor.softness", label: "Colour softness", min: 0, max: 1, step: 0.01 };
|
|
5549
|
+
return mode === "dab" ? [soft, { path: "behavior.multicolor.length", label: "Dabs per colour", min: 1, max: 100, step: 1 }] : [soft];
|
|
5550
|
+
}
|
|
5551
|
+
function patchBrushValue(brush, path, value) {
|
|
5552
|
+
const set = (obj, keys) => {
|
|
5553
|
+
const [head2, ...rest2] = keys;
|
|
5554
|
+
if (!rest2.length) return { ...obj, [head2]: value };
|
|
5555
|
+
return { ...obj, [head2]: set(_nullishCoalesce(obj[head2], () => ( {})), rest2) };
|
|
5556
|
+
};
|
|
5557
|
+
const [head, ...rest] = path.split(".");
|
|
5558
|
+
if (!rest.length) return { [head]: value };
|
|
5559
|
+
return { [head]: set({ ..._nullishCoalesce(brush[head], () => ( {})) }, rest) };
|
|
5560
|
+
}
|
|
5561
|
+
function brushLoadColor(load) {
|
|
5562
|
+
const c = _nullishCoalesce(load.pickup, () => ( load.reservoir));
|
|
5563
|
+
return c ? rgbToHexColor(Math.round(c[0] * 255), Math.round(c[1] * 255), Math.round(c[2] * 255)) : null;
|
|
5564
|
+
}
|
|
5565
|
+
var PAD_SAMPLE_SIZES = [1, 3, 5, 9, 15];
|
|
5566
|
+
function padSampleRadius(size) {
|
|
5567
|
+
return Math.max(0, Math.floor((size - 1) / 2));
|
|
5568
|
+
}
|
|
5569
|
+
|
|
5570
|
+
|
|
5571
|
+
|
|
5572
|
+
|
|
5573
|
+
|
|
5574
|
+
|
|
5575
|
+
|
|
5576
|
+
|
|
5577
|
+
|
|
5578
|
+
|
|
5579
|
+
|
|
5580
|
+
|
|
5581
|
+
|
|
5582
|
+
|
|
5583
|
+
|
|
5584
|
+
|
|
5585
|
+
|
|
5586
|
+
|
|
4818
5587
|
|
|
4819
5588
|
|
|
4820
5589
|
|
|
@@ -4962,5 +5731,5 @@ var BLEND_MENU_GROUPS = [
|
|
|
4962
5731
|
|
|
4963
5732
|
|
|
4964
5733
|
|
|
4965
|
-
exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES =
|
|
5734
|
+
exports.BLEND_MENU_GROUPS = BLEND_MENU_GROUPS; exports.BLEND_MODES = _chunkXIOMMGPDcjs.BLEND_MODES; exports.BRUSH_ID = BRUSH_ID; exports.BRUSH_ROTATIONS = BRUSH_ROTATIONS; exports.BRUSH_SLIDERS = BRUSH_SLIDERS; exports.BUILTIN_BRUSHES = BUILTIN_BRUSHES; exports.DEFAULT_BEHAVIOR = DEFAULT_BEHAVIOR; exports.DEFAULT_BRUSH_ID = DEFAULT_BRUSH_ID; exports.DEFAULT_DPI = DEFAULT_DPI; exports.DEFAULT_DYNAMICS = DEFAULT_DYNAMICS; exports.DEFAULT_MULTI_COLOR = DEFAULT_MULTI_COLOR; exports.DEFAULT_PAPER = DEFAULT_PAPER; exports.DEFAULT_SWATCHES = DEFAULT_SWATCHES; exports.DEFAULT_VIEW = DEFAULT_VIEW; exports.DryStroke = DryStroke; exports.GRAIN_PATTERNS = GRAIN_PATTERNS; exports.GRAIN_TILE = GRAIN_TILE; exports.HARMONY_KINDS = HARMONY_KINDS; exports.IDENTITY_AFFINE = IDENTITY_AFFINE; exports.IDENTITY_COPY = IDENTITY_COPY; exports.MAX_BRUSH_SIZE = _chunk7VOHOPLWcjs.MAX_BRUSH_SIZE; exports.MAX_CANVAS_SIDE = MAX_CANVAS_SIDE; exports.MAX_COORDINATE = MAX_COORDINATE; exports.MAX_IMAGE_SIDE = MAX_IMAGE_SIDE; exports.MAX_ZOOM = MAX_ZOOM; exports.MIN_CANVAS_SIDE = MIN_CANVAS_SIDE; exports.MIN_ZOOM = MIN_ZOOM; exports.MIXING_PAD_HEIGHT = MIXING_PAD_HEIGHT; exports.MIXING_PAD_WIDTH = MIXING_PAD_WIDTH; exports.MULTI_COLOR_MODES = MULTI_COLOR_MODES; exports.MixingPad = MixingPad; exports.PAD_SAMPLE_SIZES = PAD_SAMPLE_SIZES; exports.PAINTERLY_BLEND_MODES = _chunkXIOMMGPDcjs.PAINTERLY_BLEND_MODES; exports.PAINT_BRUSH_CATEGORIES = PAINT_BRUSH_CATEGORIES; exports.PAINT_BRUSH_ENGINES = PAINT_BRUSH_ENGINES; exports.PAINT_FORMAT = PAINT_FORMAT; exports.PAINT_SCHEMA_VERSION = PAINT_SCHEMA_VERSION; exports.PAINT_TOOLS = PAINT_TOOLS; exports.PAPER_FAMILIES = PAPER_FAMILIES; exports.PAPER_LIBRARY = PAPER_LIBRARY; exports.PAPER_NODE_ID = PAPER_NODE_ID; exports.PAPER_SLIDERS = PAPER_SLIDERS; exports.PaintCanvasPresenter = PaintCanvasPresenter; exports.PaintDabStroke = PaintDabStroke; exports.PaintDirector = PaintDirector; exports.PaintDocumentError = PaintDocumentError; exports.PaintEditorController = PaintEditorController; exports.PaintEditorError = PaintEditorError; exports.PaintGesture = PaintGesture; exports.PaintPresence = PaintPresence; exports.PaintStrokeSession = PaintStrokeSession; exports.PaperGrain = PaperGrain; exports.PenDabWalker = PenDabWalker; exports.PenSmoother = PenSmoother; exports.PerspectiveSnapper = PerspectiveSnapper; exports.SNAP_DECIDE_DISTANCE = SNAP_DECIDE_DISTANCE; exports.SYMMETRY_MODES = SYMMETRY_MODES; exports.TRACING_NODE_ID = TRACING_NODE_ID; exports.TileableNoise = TileableNoise; exports.affineCopy = affineCopy; exports.applyAffine = applyAffine; exports.brushEngineControls = brushEngineControls; exports.brushLoadColor = brushLoadColor; exports.brushLoadForStroke = brushLoadForStroke; exports.brushToJSON = brushToJSON; exports.clonePaper = clonePaper; exports.colorHarmony = colorHarmony; exports.composeAffine = composeAffine; exports.createPaintCompositor = createPaintCompositor; exports.createPaintDocument = createPaintDocument; exports.createPaintEditorToolProvider = createPaintEditorToolProvider; exports.createPaintLayer = createPaintLayer; exports.decodeImageBlob = decodeImageBlob; exports.defaultGuides = defaultGuides; exports.defaultImageEncoder = defaultImageEncoder; exports.deserializePaintDocument = deserializePaintDocument; exports.deserializePaintDocumentAsync = deserializePaintDocumentAsync; exports.documentExtensions = documentExtensions; exports.documentToScreen = documentToScreen; exports.downloadBytes = downloadBytes; exports.downsampleRgba = downsampleRgba; exports.fitZoom = fitZoom; exports.grainCatch = grainCatch; exports.grainHeights = grainHeights; exports.guideOverlay = guideOverlay; exports.handlePaintShortcut = handlePaintShortcut; exports.hash2 = hash2; exports.hexToRgb8 = hexToRgb8; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.hueToWheel = hueToWheel; exports.invertAffine = invertAffine; exports.isBlendMode = _chunkXIOMMGPDcjs.isBlendMode; exports.isPainterlyBlendMode = _chunkXIOMMGPDcjs.isPainterlyBlendMode; exports.isPalmTouch = isPalmTouch; exports.isWetCapable = isWetCapable; exports.mapPenPoint = mapPenPoint; exports.mix32 = mix32; exports.mixerLoadForStroke = mixerLoadForStroke; exports.mixerTip = mixerTip; exports.multiColorForDab = multiColorForDab; exports.multiColorGradient = multiColorGradient; exports.multiColorPalette = multiColorPalette; exports.multiColorSliders = multiColorSliders; exports.newPaintLayerId = newPaintLayerId; exports.normalizeBehavior = normalizeBehavior; exports.normalizeBrushStroke = normalizeBrushStroke; exports.normalizeCanvas = normalizeCanvas; exports.normalizeDynamics = normalizeDynamics; exports.normalizeMultiColor = normalizeMultiColor; exports.normalizePaintBrush = normalizePaintBrush; exports.normalizePaper = normalizePaper; exports.normalizePerspective = normalizePerspective; exports.normalizeRotation = normalizeRotation; exports.normalizeSymmetry = normalizeSymmetry; exports.normalizeView = normalizeView; exports.padSampleRadius = padSampleRadius; exports.paperGrain = paperGrain; exports.paperKey = paperKey; exports.paperNode = paperNode; exports.paperPreset = paperPreset; exports.parseBrushLibrary = parseBrushLibrary; exports.parseHexColor = parseHexColor; exports.patchBrushValue = patchBrushValue; exports.patchPath = patchPath; exports.penOrientation = penOrientation; exports.perspectiveDirections = perspectiveDirections; exports.perspectiveGuideLines = perspectiveGuideLines; exports.pointerToPenPoint = pointerToPenPoint; exports.rand01 = rand01; exports.randSigned = randSigned; exports.readPath = readPath; exports.renderBrushThumbnail = renderBrushThumbnail; exports.renderColorWheel = renderColorWheel; exports.renderPaper = renderPaper; exports.rgbToHexColor = rgbToHexColor; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.samplePressure = samplePressure; exports.screenToDocument = screenToDocument; exports.seedFromString = seedFromString; exports.serializePaintDocument = serializePaintDocument; exports.serializePaintDocumentExternal = serializePaintDocumentExternal; exports.standardBlendMode = _chunkXIOMMGPDcjs.standardBlendMode; exports.strokeBounds = strokeBounds; exports.strokeDuration = strokeDuration; exports.strokeSchedule = strokeSchedule; exports.sweepPath = sweepPath; exports.symmetryAxisAngles = symmetryAxisAngles; exports.symmetryAxisSegments = symmetryAxisSegments; exports.symmetryCopies = symmetryCopies; exports.thumbnailStroke = thumbnailStroke; exports.tiltToOrientation = tiltToOrientation; exports.toStrokePoint = toStrokePoint; exports.usesPaintExchange = usesPaintExchange; exports.variationAffine = variationAffine; exports.varyStroke = varyStroke; exports.viewCssTransform = viewCssTransform; exports.viewMatrix = viewMatrix; exports.viewPenToDocument = viewPenToDocument; exports.wheelAngle = wheelAngle; exports.wheelPick = wheelPick; exports.wheelPoint = wheelPoint; exports.wheelToHue = wheelToHue;
|
|
4966
5735
|
//# sourceMappingURL=index.cjs.map
|