@pixerate/editor 0.240.0 → 0.241.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-editor/index.cjs +58 -58
- package/dist/animation-editor/index.js +3 -3
- package/dist/{brushstrokeRender-WB67GMUP.js → brushstrokeRender-MOYGEXOC.js} +2 -2
- package/dist/{brushstrokeRender-MPOM7BFW.cjs → brushstrokeRender-UKADOV5D.cjs} +5 -5
- package/dist/canvas/index.cjs +8 -8
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-NKTNLJUJ.cjs → chunk-5BR7LC24.cjs} +99 -11
- package/dist/{chunk-ZXNO3ZOX.cjs → chunk-7F4G74UQ.cjs} +35 -35
- package/dist/{chunk-AD7GA3TL.cjs → chunk-AFLMXITL.cjs} +23 -23
- package/dist/{chunk-PP6BXVRL.cjs → chunk-HGGJ36HR.cjs} +1 -1
- package/dist/{chunk-BBUE3UJL.cjs → chunk-HW72ABGR.cjs} +86 -86
- package/dist/{chunk-7YGBSFC6.js → chunk-ILM6GYAX.js} +1 -1
- package/dist/{chunk-THXFU3JB.cjs → chunk-KCMV2534.cjs} +2 -2
- package/dist/{chunk-3E36VDMJ.js → chunk-NE6OOKWJ.js} +1 -1
- package/dist/{chunk-RV5DKZHU.js → chunk-QP2B3MID.js} +1 -1
- package/dist/{chunk-UUBO6RB5.js → chunk-UDBDYZET.js} +1 -1
- package/dist/{chunk-PJYG6FCF.js → chunk-XBZK47LV.js} +98 -10
- package/dist/{chunk-XK4SST43.js → chunk-ZDPLZDTT.js} +1 -1
- package/dist/image-editor/index.cjs +775 -775
- package/dist/image-editor/index.js +4 -4
- package/dist/paint-editor/controller.d.cts +67 -0
- package/dist/paint-editor/controller.d.ts +67 -0
- package/dist/paint-editor/effect-paint.d.cts +60 -3
- package/dist/paint-editor/effect-paint.d.ts +60 -3
- package/dist/paint-editor/index.cjs +676 -430
- package/dist/paint-editor/index.js +282 -36
- package/dist/paint-editor/stickers.d.cts +6 -0
- package/dist/paint-editor/stickers.d.ts +6 -0
- package/dist/paint-editor/thick.d.cts +4 -0
- package/dist/paint-editor/thick.d.ts +4 -0
- package/dist/paint-editor/wet.d.cts +8 -0
- package/dist/paint-editor/wet.d.ts +8 -0
- package/dist/vector/index.cjs +962 -962
- package/dist/vector/index.js +4 -4
- package/package.json +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +17 -21
- package/skills/pixerate-paint-editor/references/effect-paint.md +25 -0
|
@@ -36,12 +36,50 @@ import {
|
|
|
36
36
|
} from "./chunk-F67XMVDI.js";
|
|
37
37
|
|
|
38
38
|
// src/paint-editor/effect-paint.ts
|
|
39
|
+
var EFFECT_STRIP_HEIGHT = 256;
|
|
40
|
+
var EFFECT_MAP_REPEATS = ["repeat", "mirror", "clamp"];
|
|
41
|
+
function effectPaintSize(p, canvas) {
|
|
42
|
+
return p.map ? { width: p.map.length, height: EFFECT_STRIP_HEIGHT } : { width: canvas.width, height: canvas.height };
|
|
43
|
+
}
|
|
44
|
+
function readEffectStrokeMap(raw) {
|
|
45
|
+
if (raw === void 0 || raw === null || raw.by === "canvas") return void 0;
|
|
46
|
+
const r = raw;
|
|
47
|
+
if (r.by !== "stroke") throw new Error(`map.by ${JSON.stringify(r.by)} is not a mapping; use "canvas" (fixed to the canvas) or "stroke" (along each stroke).`);
|
|
48
|
+
const length = r.length === void 0 ? 300 : Number(r.length);
|
|
49
|
+
if (!(Number.isFinite(length) && length >= 16 && length <= 4096)) throw new Error(`map.length ${JSON.stringify(r.length)} is out of range; use 16..4096 px of stroke per repeat.`);
|
|
50
|
+
const repeat = r.repeat === void 0 ? "repeat" : r.repeat;
|
|
51
|
+
if (!EFFECT_MAP_REPEATS.includes(repeat)) throw new Error(`map.repeat ${JSON.stringify(r.repeat)} is not a repeat mode; use ${EFFECT_MAP_REPEATS.join(", ")}.`);
|
|
52
|
+
return { by: "stroke", length: Math.round(length), repeat };
|
|
53
|
+
}
|
|
54
|
+
function stripIndex(img, map, dab, x, y) {
|
|
55
|
+
const ca = Math.cos(dab.direction);
|
|
56
|
+
const sa = Math.sin(dab.direction);
|
|
57
|
+
const dx = x - dab.x;
|
|
58
|
+
const dy = y - dab.y;
|
|
59
|
+
let u = (dab.travel + dx * ca - dy * sa) / map.length;
|
|
60
|
+
if (map.repeat === "clamp") u = Math.min(1, Math.max(0, u));
|
|
61
|
+
else if (map.repeat === "mirror") {
|
|
62
|
+
const m = (u % 2 + 2) % 2;
|
|
63
|
+
u = m > 1 ? 2 - m : m;
|
|
64
|
+
} else u = (u % 1 + 1) % 1;
|
|
65
|
+
const v = Math.min(1, Math.max(0, ((dx * sa + dy * ca) / Math.max(0.5, dab.radius) + 1) / 2));
|
|
66
|
+
const px = Math.min(img.width - 1, Math.floor(u * img.width));
|
|
67
|
+
const py = Math.min(img.height - 1, Math.floor(v * img.height));
|
|
68
|
+
return (py * img.width + px) * 4;
|
|
69
|
+
}
|
|
39
70
|
function effectPaintKey(p) {
|
|
40
|
-
return JSON.stringify({ type: "effect", effect: p.effect, provider: p.provider, values: p.values, time: p.time });
|
|
71
|
+
return JSON.stringify({ type: "effect", effect: p.effect, provider: p.provider, values: p.values, time: p.time, ...p.map ? { map: p.map } : {} });
|
|
41
72
|
}
|
|
42
73
|
function isPaintEffectPaint(raw) {
|
|
43
74
|
return Boolean(raw) && typeof raw === "object" && raw.type === "effect";
|
|
44
75
|
}
|
|
76
|
+
function readMapLeniently(raw) {
|
|
77
|
+
try {
|
|
78
|
+
return readEffectStrokeMap(raw);
|
|
79
|
+
} catch {
|
|
80
|
+
return void 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
45
83
|
function readPaintEffectPaint(raw) {
|
|
46
84
|
if (!isPaintEffectPaint(raw)) return null;
|
|
47
85
|
const r = raw;
|
|
@@ -51,11 +89,27 @@ function readPaintEffectPaint(raw) {
|
|
|
51
89
|
effect: r.effect,
|
|
52
90
|
provider: typeof r.provider === "string" ? r.provider : "",
|
|
53
91
|
values: JSON.parse(JSON.stringify(r.values)),
|
|
54
|
-
time: typeof r.time === "number" && Number.isFinite(r.time) && r.time > 0 ? r.time : 0
|
|
92
|
+
time: typeof r.time === "number" && Number.isFinite(r.time) && r.time > 0 ? r.time : 0,
|
|
93
|
+
...readMapLeniently(r.map) ? { map: readMapLeniently(r.map) } : {},
|
|
94
|
+
...r.live === true ? { live: true } : {}
|
|
55
95
|
};
|
|
56
96
|
}
|
|
57
|
-
function sampleEffectField(img, rect, vals, field) {
|
|
97
|
+
function sampleEffectField(img, rect, vals, field, dab) {
|
|
58
98
|
const { width, height, data } = img;
|
|
99
|
+
if (img.map && dab) {
|
|
100
|
+
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
101
|
+
for (let xx = 0; xx < rect.width; xx++, k++) {
|
|
102
|
+
const i = stripIndex(img, img.map, dab, rect.x + xx + 0.5, rect.y + yy + 0.5);
|
|
103
|
+
const f = k * 3;
|
|
104
|
+
const a = data[i + 3];
|
|
105
|
+
if (a < 255) vals[k] *= a / 255;
|
|
106
|
+
field[f] = data[i] / 255;
|
|
107
|
+
field[f + 1] = data[i + 1] / 255;
|
|
108
|
+
field[f + 2] = data[i + 2] / 255;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
59
113
|
for (let yy = 0, k = 0; yy < rect.height; yy++) {
|
|
60
114
|
const y = rect.y + yy;
|
|
61
115
|
const inY = y >= 0 && y < height;
|
|
@@ -76,7 +130,14 @@ function sampleEffectField(img, rect, vals, field) {
|
|
|
76
130
|
}
|
|
77
131
|
}
|
|
78
132
|
}
|
|
79
|
-
function sampleEffectAt(img, x, y, out) {
|
|
133
|
+
function sampleEffectAt(img, x, y, out, dab) {
|
|
134
|
+
if (img.map && dab) {
|
|
135
|
+
const i2 = stripIndex(img, img.map, dab, x, y);
|
|
136
|
+
out[0] = img.data[i2] / 255;
|
|
137
|
+
out[1] = img.data[i2 + 1] / 255;
|
|
138
|
+
out[2] = img.data[i2 + 2] / 255;
|
|
139
|
+
return img.data[i2 + 3] / 255;
|
|
140
|
+
}
|
|
80
141
|
const px = Math.floor(x);
|
|
81
142
|
const py = Math.floor(y);
|
|
82
143
|
if (px < 0 || py < 0 || px >= img.width || py >= img.height) return 0;
|
|
@@ -86,6 +147,20 @@ function sampleEffectAt(img, x, y, out) {
|
|
|
86
147
|
out[2] = img.data[i + 2] / 255;
|
|
87
148
|
return img.data[i + 3] / 255;
|
|
88
149
|
}
|
|
150
|
+
function effectDabField(img, rect, cov, centre, mixed, field, steps = 0, dab = null) {
|
|
151
|
+
sampleEffectField(img, rect, cov, field, dab);
|
|
152
|
+
const d0 = mixed[0] - centre[0];
|
|
153
|
+
const d1 = mixed[1] - centre[1];
|
|
154
|
+
const d2 = mixed[2] - centre[2];
|
|
155
|
+
const n = rect.width * rect.height;
|
|
156
|
+
for (let k = 0; k < n; k++) {
|
|
157
|
+
if (steps) cov[k] = Math.round(cov[k] * steps) / steps;
|
|
158
|
+
const f = k * 3;
|
|
159
|
+
field[f] = Math.min(1, Math.max(0, field[f] + d0));
|
|
160
|
+
field[f + 1] = Math.min(1, Math.max(0, field[f + 1] + d1));
|
|
161
|
+
field[f + 2] = Math.min(1, Math.max(0, field[f + 2] + d2));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
89
164
|
|
|
90
165
|
// src/paint-editor/paper.ts
|
|
91
166
|
var PAPER_FAMILIES = ["watercolor", "drawing", "pastel", "canvas", "panel", "smooth"];
|
|
@@ -490,7 +565,7 @@ var DryStroke = class {
|
|
|
490
565
|
if (this.options.effect) {
|
|
491
566
|
if (this.field.length < n * 3) this.field = new Float32Array(n * 3);
|
|
492
567
|
field = this.field.subarray(0, n * 3);
|
|
493
|
-
sampleEffectField(this.options.effect, rect, vals, field);
|
|
568
|
+
sampleEffectField(this.options.effect, rect, vals, field, d);
|
|
494
569
|
}
|
|
495
570
|
this.coverage.accumulate(rect, vals, d.opacity, null, field);
|
|
496
571
|
rects.push(rect);
|
|
@@ -692,6 +767,10 @@ var StickerSpray = class {
|
|
|
692
767
|
const a = rand01(seed, i, 53) * Math.PI * 2;
|
|
693
768
|
const dist = rand01(seed, i, 55) * off;
|
|
694
769
|
const base = this.colorAt(d, Math.cos(a) * dist, Math.sin(a) * dist);
|
|
770
|
+
if (!(base.alpha > 0)) {
|
|
771
|
+
this.next++;
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
695
774
|
const sticker = {
|
|
696
775
|
id: `st${this.next++}`,
|
|
697
776
|
stamp: st.stamps[Math.floor(rand01(seed, i, 57) * st.stamps.length)] ?? "dot",
|
|
@@ -710,6 +789,12 @@ var StickerSpray = class {
|
|
|
710
789
|
sampler;
|
|
711
790
|
/** A sticker's colour: the paint colour, or gradient paint at its dab (`dx`, `dy` from the dab's centre). */
|
|
712
791
|
colorAt(d, dx, dy) {
|
|
792
|
+
const effect = this.init.effect;
|
|
793
|
+
if (effect) {
|
|
794
|
+
const rgb = [0, 0, 0];
|
|
795
|
+
const alpha = sampleEffectAt(effect, d.x + dx, d.y + dy, rgb, d);
|
|
796
|
+
return { color: "#" + rgb.map((c) => Math.round(c * 255).toString(16).padStart(2, "0")).join(""), alpha };
|
|
797
|
+
}
|
|
713
798
|
const g = this.init.paint;
|
|
714
799
|
if (!g) return { color: this.init.color, alpha: 1 };
|
|
715
800
|
this.sampler ??= new PaintGradientSampler(g, this.init.seed);
|
|
@@ -841,10 +926,8 @@ var MarkStroke = class {
|
|
|
841
926
|
return rects;
|
|
842
927
|
}
|
|
843
928
|
step(copy, d, rects) {
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
if (!this.tipTable) this.sampler.dab(d, this.penColor);
|
|
847
|
-
}
|
|
929
|
+
this.pen = d;
|
|
930
|
+
if (this.sampler && !this.tipTable) this.sampler.dab(d, this.penColor);
|
|
848
931
|
this.advance(copy, d, rects);
|
|
849
932
|
}
|
|
850
933
|
/** The colour of a mark at (x, y): its pen dab's, or across the tip by its offset from the pen. */
|
|
@@ -887,7 +970,7 @@ var MarkStroke = class {
|
|
|
887
970
|
if (this.options.effect) {
|
|
888
971
|
if (this.field.length < n * 3) this.field = new Float32Array(n * 3);
|
|
889
972
|
const field = this.field.subarray(0, n * 3);
|
|
890
|
-
sampleEffectField(this.options.effect, rect, vals, field);
|
|
973
|
+
sampleEffectField(this.options.effect, rect, vals, field, this.pen);
|
|
891
974
|
this.coverage.accumulate(rect, vals, dab.opacity, null, field);
|
|
892
975
|
} else {
|
|
893
976
|
const color = this.markColor(x, y);
|
|
@@ -1888,11 +1971,16 @@ function parseBrushLibrary(raw, problems = []) {
|
|
|
1888
1971
|
}
|
|
1889
1972
|
|
|
1890
1973
|
export {
|
|
1974
|
+
EFFECT_STRIP_HEIGHT,
|
|
1975
|
+
EFFECT_MAP_REPEATS,
|
|
1976
|
+
effectPaintSize,
|
|
1977
|
+
readEffectStrokeMap,
|
|
1891
1978
|
effectPaintKey,
|
|
1892
1979
|
isPaintEffectPaint,
|
|
1893
1980
|
readPaintEffectPaint,
|
|
1894
1981
|
sampleEffectField,
|
|
1895
1982
|
sampleEffectAt,
|
|
1983
|
+
effectDabField,
|
|
1896
1984
|
PAPER_FAMILIES,
|
|
1897
1985
|
PAPER_LIBRARY,
|
|
1898
1986
|
DEFAULT_PAPER,
|