@pixerate/editor 0.248.0 → 0.250.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/animation-editor/index.cjs +118 -114
- package/dist/animation-editor/index.js +11 -7
- package/dist/{brushstrokeRender-QLCXROJK.js → brushstrokeRender-2FHFLSEG.js} +8 -4
- package/dist/{brushstrokeRender-DTDPFBLC.cjs → brushstrokeRender-QGRXOKDA.cjs} +15 -11
- package/dist/canvas/index.cjs +71 -15
- package/dist/canvas/index.d.cts +1 -0
- package/dist/canvas/index.d.ts +1 -0
- package/dist/canvas/index.js +58 -2
- package/dist/canvas/stickers.d.cts +35 -0
- package/dist/canvas/stickers.d.ts +35 -0
- package/dist/{chunk-RXZL4NG5.js → chunk-226QDRO3.js} +1 -1
- package/dist/{chunk-SC2RZ5EF.js → chunk-2VJAVXLI.js} +2 -2
- package/dist/{chunk-OLNIPTB3.cjs → chunk-2VX55NFM.cjs} +1 -320
- package/dist/chunk-3K6HWEXZ.cjs +92 -0
- package/dist/{chunk-UOOK7HTX.js → chunk-3PPJRMIG.js} +1 -1
- package/dist/{chunk-ZFSLEOSQ.js → chunk-3TWOCSCY.js} +11 -9
- package/dist/chunk-4D6KP5BV.js +92 -0
- package/dist/chunk-4JNWA3VT.cjs +302 -0
- package/dist/{chunk-L3JFOTBQ.js → chunk-5E2Q7ZHI.js} +1 -1
- package/dist/{chunk-2ONK3ERD.cjs → chunk-75K3W4D6.cjs} +20 -20
- package/dist/{chunk-AU6MWQKZ.js → chunk-ABL7IWFZ.js} +1 -1
- package/dist/chunk-ATK6ABN3.cjs +303 -0
- package/dist/{chunk-7T7JWTVE.cjs → chunk-BOHDJJ2O.cjs} +8 -8
- package/dist/{chunk-2PBZBRP5.js → chunk-D5KGAO4Z.js} +10 -92
- package/dist/{chunk-HB4ICNNA.cjs → chunk-DPYAO5U6.cjs} +42 -42
- package/dist/{chunk-6G6ZDDDB.cjs → chunk-GT77U7QG.cjs} +303 -149
- package/dist/{chunk-PQ3H2AAN.cjs → chunk-I7NJPHWV.cjs} +122 -204
- package/dist/{chunk-42TWUPNJ.js → chunk-IRSTHLQQ.js} +1 -320
- package/dist/{chunk-GHCSC2WP.cjs → chunk-ISIO63Q5.cjs} +21 -15
- package/dist/{chunk-OFH6Q67U.js → chunk-JA57JIT5.js} +9 -3
- package/dist/{chunk-VMROIWLL.cjs → chunk-KBYB7OWB.cjs} +3 -3
- package/dist/{chunk-Q2HA52V4.js → chunk-KDLBJ6QR.js} +2 -2
- package/dist/{chunk-WVS5KQDH.cjs → chunk-M2VKFE5L.cjs} +246 -244
- package/dist/{chunk-5GLYUSNT.js → chunk-NOHJP5TK.js} +1 -1
- package/dist/{chunk-XNRBMYNB.js → chunk-NTRAVM2I.js} +1 -1
- package/dist/{chunk-VNBUDVD4.js → chunk-OTEPAQJX.js} +228 -74
- package/dist/chunk-OTTT5N3K.js +322 -0
- package/dist/{chunk-QOBCBGGI.cjs → chunk-QKXO6JPP.cjs} +14 -14
- package/dist/{chunk-NZ3O3A5C.js → chunk-SMSGP2HQ.js} +1 -1
- package/dist/chunk-SZTI6EER.js +13 -0
- package/dist/chunk-U4NUOKBT.js +303 -0
- package/dist/chunk-U67EN7GG.cjs +13 -0
- package/dist/chunk-W5M3J7PV.cjs +322 -0
- package/dist/{chunk-4P6H35HU.js → chunk-WA44NKPF.js} +2 -2
- package/dist/chunk-WKH5ZAUA.js +302 -0
- package/dist/{chunk-L6REDLNB.cjs → chunk-WPUXGDH4.cjs} +7 -7
- package/dist/{chunk-P3NIPIKS.js → chunk-WQCNC4DK.js} +1 -1
- package/dist/{chunk-IBDU6EGZ.cjs → chunk-X7WRL5ZZ.cjs} +35 -35
- package/dist/{chunk-XWTRATIM.cjs → chunk-YM6ZBTXG.cjs} +23 -23
- package/dist/{chunk-TPWB4Y6L.cjs → chunk-YW43M56C.cjs} +1 -1
- package/dist/{chunk-K5DS2JTA.cjs → chunk-Z3BRH4JK.cjs} +6 -6
- package/dist/{chunk-XNZFVYC2.cjs → chunk-ZBCT5MEA.cjs} +7 -7
- package/dist/effects/helpers.d.cts +6 -0
- package/dist/effects/helpers.d.ts +6 -0
- package/dist/effects/index.cjs +62 -60
- package/dist/effects/index.js +5 -3
- package/dist/effects/tools.d.cts +6 -0
- package/dist/effects/tools.d.ts +6 -0
- package/dist/image-editor/effects.d.cts +1 -1
- package/dist/image-editor/effects.d.ts +1 -1
- package/dist/image-editor/index.cjs +1097 -1069
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +58 -30
- package/dist/image-editor/stickers.d.cts +9 -0
- package/dist/image-editor/stickers.d.ts +9 -0
- package/dist/paint/index.cjs +8 -5
- package/dist/paint/index.js +13 -10
- package/dist/paint-editor/controller.d.cts +37 -1
- package/dist/paint-editor/controller.d.ts +37 -1
- package/dist/paint-editor/index.cjs +753 -609
- package/dist/paint-editor/index.d.cts +3 -0
- package/dist/paint-editor/index.d.ts +3 -0
- package/dist/paint-editor/index.js +187 -43
- package/dist/paint-editor/sticker-art.d.cts +55 -0
- package/dist/paint-editor/sticker-art.d.ts +55 -0
- package/dist/paint-editor/stickers.d.cts +30 -17
- package/dist/paint-editor/stickers.d.ts +30 -17
- package/dist/paint-editor/stroke.d.cts +4 -0
- package/dist/paint-editor/stroke.d.ts +4 -0
- package/dist/paint-editor/ui.d.cts +10 -2
- package/dist/paint-editor/ui.d.ts +10 -2
- package/dist/raster/index.cjs +6 -4
- package/dist/raster/index.js +12 -10
- package/dist/stickers/browser.d.cts +48 -0
- package/dist/stickers/browser.d.ts +48 -0
- package/dist/stickers/combine.d.cts +10 -0
- package/dist/stickers/combine.d.ts +10 -0
- package/dist/stickers/conformance.d.cts +18 -0
- package/dist/stickers/conformance.d.ts +18 -0
- package/dist/stickers/editor.d.cts +14 -0
- package/dist/stickers/editor.d.ts +14 -0
- package/dist/stickers/errors.d.cts +6 -0
- package/dist/stickers/errors.d.ts +6 -0
- package/dist/stickers/fake.d.cts +16 -0
- package/dist/stickers/fake.d.ts +16 -0
- package/dist/stickers/helpers.d.cts +51 -0
- package/dist/stickers/helpers.d.ts +51 -0
- package/dist/stickers/index.cjs +337 -0
- package/dist/stickers/index.d.cts +16 -0
- package/dist/stickers/index.d.ts +16 -0
- package/dist/stickers/index.js +337 -0
- package/dist/stickers/stamps.d.cts +13 -0
- package/dist/stickers/stamps.d.ts +13 -0
- package/dist/stickers/tools.d.cts +81 -0
- package/dist/stickers/tools.d.ts +81 -0
- package/dist/stickers/types.d.cts +123 -0
- package/dist/stickers/types.d.ts +123 -0
- package/dist/vector/index.cjs +1018 -981
- package/dist/vector/index.d.cts +1 -0
- package/dist/vector/index.d.ts +1 -0
- package/dist/vector/index.js +44 -7
- package/dist/vector/stickers.d.cts +11 -0
- package/dist/vector/stickers.d.ts +11 -0
- package/dist/video-editor/index.cjs +344 -344
- package/dist/video-editor/index.js +4 -4
- package/package.json +11 -1
- package/skills/README.md +1 -0
- package/skills/pixerate-image-editor/SKILL.md +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +8 -5
- package/skills/pixerate-stickers/SKILL.md +57 -0
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
STAMP_KINDS,
|
|
3
|
+
describeStickerRef,
|
|
4
|
+
editorStampOf,
|
|
5
|
+
normalizeStickerRef,
|
|
6
|
+
stampCoverage,
|
|
7
|
+
stickerIdFor
|
|
8
|
+
} from "./chunk-WKH5ZAUA.js";
|
|
9
|
+
import {
|
|
10
|
+
StickerError
|
|
11
|
+
} from "./chunk-SZTI6EER.js";
|
|
1
12
|
import {
|
|
2
13
|
CoverageMap,
|
|
3
14
|
DEFAULT_BLENDER,
|
|
@@ -11,16 +22,22 @@ import {
|
|
|
11
22
|
TileMedium,
|
|
12
23
|
dabRect,
|
|
13
24
|
grainCatch,
|
|
14
|
-
hash2,
|
|
15
25
|
normalizeBlender,
|
|
16
26
|
normalizeBrush,
|
|
17
27
|
normalizeMixer,
|
|
18
28
|
normalizeSmudge,
|
|
19
|
-
rand01,
|
|
20
|
-
randSigned,
|
|
21
29
|
rasterizeDab,
|
|
22
30
|
readPaintSource
|
|
23
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-D5KGAO4Z.js";
|
|
32
|
+
import {
|
|
33
|
+
hash2,
|
|
34
|
+
rand01,
|
|
35
|
+
randSigned
|
|
36
|
+
} from "./chunk-4D6KP5BV.js";
|
|
37
|
+
import {
|
|
38
|
+
decodePng,
|
|
39
|
+
parseDataUrl
|
|
40
|
+
} from "./chunk-OTTT5N3K.js";
|
|
24
41
|
import {
|
|
25
42
|
TILE,
|
|
26
43
|
TiledSurface,
|
|
@@ -586,14 +603,129 @@ function toStrokePoint(p) {
|
|
|
586
603
|
return { x: p.x, y: p.y, pressure: pressureOf(p), ...typeof p.t === "number" ? { t: p.t } : {} };
|
|
587
604
|
}
|
|
588
605
|
|
|
606
|
+
// src/paint-editor/sticker-art.ts
|
|
607
|
+
var STICKER_ART_SIZE = 256;
|
|
608
|
+
var defaultStickerRasterizer = async (asset, size) => {
|
|
609
|
+
if (asset.kind === "image") {
|
|
610
|
+
const parsed = parseDataUrl(asset.url);
|
|
611
|
+
if (parsed && parsed.mime === "image/png") {
|
|
612
|
+
const png = decodePng(parsed.bytes);
|
|
613
|
+
return { width: png.width, height: png.height, data: new Uint8ClampedArray(png.data) };
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
const g = globalThis;
|
|
617
|
+
if (!g.createImageBitmap || !g.OffscreenCanvas) {
|
|
618
|
+
throw new StickerError("unsupported_format", `This environment can't draw ${asset.kind === "svg" ? "SVG" : "non-PNG"} sticker art; pass rasterizeSticker in the paint editor's options (or use a provider that offers png).`);
|
|
619
|
+
}
|
|
620
|
+
const blob = asset.kind === "svg" ? new Blob([asset.svg], { type: "image/svg+xml" }) : await (await g.fetch(asset.url)).blob();
|
|
621
|
+
const bitmap = await g.createImageBitmap(blob);
|
|
622
|
+
const scale = size / Math.max(bitmap.width, bitmap.height, 1);
|
|
623
|
+
const w = Math.max(1, Math.round(bitmap.width * scale));
|
|
624
|
+
const h = Math.max(1, Math.round(bitmap.height * scale));
|
|
625
|
+
const canvas = new g.OffscreenCanvas(w, h);
|
|
626
|
+
const ctx = canvas.getContext("2d");
|
|
627
|
+
ctx.drawImage(bitmap, 0, 0, w, h);
|
|
628
|
+
const img = ctx.getImageData(0, 0, w, h);
|
|
629
|
+
return { width: w, height: h, data: img.data };
|
|
630
|
+
};
|
|
631
|
+
var StickerArtCache = class {
|
|
632
|
+
entries = /* @__PURE__ */ new Map();
|
|
633
|
+
/** The art for `ref` when it has loaded (editor stamps never need any). */
|
|
634
|
+
get = (ref) => {
|
|
635
|
+
const e = this.entries.get(ref);
|
|
636
|
+
return e?.status === "ready" ? e.art : void 0;
|
|
637
|
+
};
|
|
638
|
+
/** `ready`, `loading`, `failed` (with the reason) or `none` (never asked for). Editor stamps are always `ready`. */
|
|
639
|
+
status(ref) {
|
|
640
|
+
if (editorStampOf(ref)) return { status: "ready" };
|
|
641
|
+
const e = this.entries.get(ref);
|
|
642
|
+
if (!e) return { status: "none" };
|
|
643
|
+
return e.status === "failed" ? { status: "failed", error: e.error } : { status: e.status };
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Loads and rasterises `ref` from `provider` once (later calls share the load). Unknown refs
|
|
647
|
+
* reject with the closest known ones; failures are kept so they are reported, and retried on
|
|
648
|
+
* the next call.
|
|
649
|
+
*/
|
|
650
|
+
ensure(provider, ref, rasterize) {
|
|
651
|
+
if (editorStampOf(ref)) return Promise.resolve(null);
|
|
652
|
+
const e = this.entries.get(ref);
|
|
653
|
+
if (e?.status === "ready") return Promise.resolve(e.art);
|
|
654
|
+
if (e?.status === "loading") return e.promise;
|
|
655
|
+
const promise = (async () => {
|
|
656
|
+
const d = await describeStickerRef(provider, ref);
|
|
657
|
+
const id = stickerIdFor(provider, ref);
|
|
658
|
+
const max = provider.capabilities.maxSize ?? STICKER_ART_SIZE;
|
|
659
|
+
const size = Math.min(STICKER_ART_SIZE, max);
|
|
660
|
+
const asset = await provider.load(id, d.formats.includes("png") ? { format: "png", size } : { format: d.formats[0] ?? "svg", size });
|
|
661
|
+
const px = await rasterize(asset, size);
|
|
662
|
+
if (!(px.width > 0 && px.height > 0) || px.data.length !== px.width * px.height * 4) throw new StickerError("load_failed", `The art for "${ref}" came back empty or the wrong size.`);
|
|
663
|
+
return { ...px, tintable: d.tintable };
|
|
664
|
+
})();
|
|
665
|
+
this.entries.set(ref, { status: "loading", promise });
|
|
666
|
+
return promise.then(
|
|
667
|
+
(art) => {
|
|
668
|
+
this.entries.set(ref, { status: "ready", art });
|
|
669
|
+
return art;
|
|
670
|
+
},
|
|
671
|
+
(err) => {
|
|
672
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
673
|
+
this.entries.set(ref, { status: "failed", error: message });
|
|
674
|
+
throw err;
|
|
675
|
+
}
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
/** Forgets every load (a new provider). */
|
|
679
|
+
clear() {
|
|
680
|
+
this.entries.clear();
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
function sampleArt(art, x, y, out) {
|
|
684
|
+
const { width: w, height: h, data } = art;
|
|
685
|
+
const fx = x - 0.5;
|
|
686
|
+
const fy = y - 0.5;
|
|
687
|
+
const x0 = Math.floor(fx);
|
|
688
|
+
const y0 = Math.floor(fy);
|
|
689
|
+
const tx = fx - x0;
|
|
690
|
+
const ty = fy - y0;
|
|
691
|
+
let r = 0;
|
|
692
|
+
let g = 0;
|
|
693
|
+
let b = 0;
|
|
694
|
+
let a = 0;
|
|
695
|
+
for (let k = 0; k < 4; k++) {
|
|
696
|
+
const xx = x0 + (k & 1);
|
|
697
|
+
const yy = y0 + (k >> 1);
|
|
698
|
+
if (xx < 0 || yy < 0 || xx >= w || yy >= h) continue;
|
|
699
|
+
const wgt = (k & 1 ? tx : 1 - tx) * (k >> 1 ? ty : 1 - ty);
|
|
700
|
+
const i = (yy * w + xx) * 4;
|
|
701
|
+
const al = data[i + 3] * wgt;
|
|
702
|
+
r += data[i] * al;
|
|
703
|
+
g += data[i + 1] * al;
|
|
704
|
+
b += data[i + 2] * al;
|
|
705
|
+
a += al;
|
|
706
|
+
}
|
|
707
|
+
out[0] = a > 0 ? r / a / 255 : 0;
|
|
708
|
+
out[1] = a > 0 ? g / a / 255 : 0;
|
|
709
|
+
out[2] = a > 0 ? b / a / 255 : 0;
|
|
710
|
+
out[3] = a / 255;
|
|
711
|
+
return out;
|
|
712
|
+
}
|
|
713
|
+
|
|
589
714
|
// src/paint-editor/stickers.ts
|
|
590
|
-
var
|
|
591
|
-
var DEFAULT_STICKER = { stamps: ["star"], density: 0.4, sizeJitter: 0.4, rotationJitter: 1, scatter: 0.5, colorJitter: 0.2 };
|
|
715
|
+
var MAX_STICKER_STAMPS = 16;
|
|
716
|
+
var DEFAULT_STICKER = { stamps: ["editor:star"], density: 0.4, sizeJitter: 0.4, rotationJitter: 1, scatter: 0.5, colorJitter: 0.2 };
|
|
592
717
|
var unit2 = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
|
|
593
718
|
function normalizeStickerSettings(raw = {}, base = DEFAULT_STICKER) {
|
|
594
|
-
const
|
|
719
|
+
const refs = (list) => list.flatMap((s) => {
|
|
720
|
+
try {
|
|
721
|
+
return [normalizeStickerRef(s)];
|
|
722
|
+
} catch {
|
|
723
|
+
return [];
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
const stamps = Array.isArray(raw.stamps) ? refs(raw.stamps) : refs(base.stamps);
|
|
595
727
|
return {
|
|
596
|
-
stamps: stamps.length ? [...new Set(stamps)] :
|
|
728
|
+
stamps: stamps.length ? [...new Set(stamps)].slice(0, MAX_STICKER_STAMPS) : refs(base.stamps.length ? base.stamps : DEFAULT_STICKER.stamps),
|
|
597
729
|
density: unit2(raw.density, base.density),
|
|
598
730
|
sizeJitter: unit2(raw.sizeJitter, base.sizeJitter),
|
|
599
731
|
rotationJitter: unit2(raw.rotationJitter, base.rotationJitter),
|
|
@@ -601,59 +733,6 @@ function normalizeStickerSettings(raw = {}, base = DEFAULT_STICKER) {
|
|
|
601
733
|
colorJitter: unit2(raw.colorJitter, base.colorJitter)
|
|
602
734
|
};
|
|
603
735
|
}
|
|
604
|
-
function stampCoverage(kind, u, v, t) {
|
|
605
|
-
const r = Math.hypot(u, v);
|
|
606
|
-
const a = Math.atan2(v, u);
|
|
607
|
-
const edge = (d) => Math.min(1, Math.max(0, d * 24 + 0.5));
|
|
608
|
-
switch (kind) {
|
|
609
|
-
case "dot":
|
|
610
|
-
return edge(0.95 - r);
|
|
611
|
-
case "ring":
|
|
612
|
-
return edge(Math.min(0.95 - r, r - 0.6));
|
|
613
|
-
case "star": {
|
|
614
|
-
const f = (a + Math.PI / 2) * 5 / (2 * Math.PI) % 1;
|
|
615
|
-
const notch = Math.min(f < 0 ? f + 1 : f, 1 - (f < 0 ? f + 1 : f)) * 2;
|
|
616
|
-
return edge(0.95 - 0.55 * notch - r);
|
|
617
|
-
}
|
|
618
|
-
case "sparkle": {
|
|
619
|
-
const q = Math.pow(Math.abs(u) / 0.95, 0.6) + Math.pow(Math.abs(v) / 0.95, 0.6);
|
|
620
|
-
return edge((1 - q) * 0.4);
|
|
621
|
-
}
|
|
622
|
-
case "heart": {
|
|
623
|
-
const x = u * 1.1;
|
|
624
|
-
const y = -v * 1.1 + 0.15;
|
|
625
|
-
const q = x * x + y * y - 0.55;
|
|
626
|
-
return edge(-(q * q * q - x * x * y * y * y) * 3);
|
|
627
|
-
}
|
|
628
|
-
case "leaf": {
|
|
629
|
-
const w = 0.42 * Math.sqrt(Math.max(0, 1 - u * u));
|
|
630
|
-
const inside = edge(w - Math.abs(v + 0.15 * u * u));
|
|
631
|
-
const rib = Math.abs(v + 0.15 * u * u) < 0.03 && Math.abs(u) < 0.85 ? 0.65 : 1;
|
|
632
|
-
return inside * rib;
|
|
633
|
-
}
|
|
634
|
-
case "flower": {
|
|
635
|
-
const petals = 0.6 + 0.35 * Math.abs(Math.cos(2.5 * a));
|
|
636
|
-
const body = edge(petals - r);
|
|
637
|
-
return r < 0.22 ? Math.max(body, 1) * 0.85 : body;
|
|
638
|
-
}
|
|
639
|
-
case "confetti": {
|
|
640
|
-
return edge(Math.min(0.9 - Math.abs(u), 0.35 - Math.abs(v)));
|
|
641
|
-
}
|
|
642
|
-
case "splat": {
|
|
643
|
-
let rr = 0.55;
|
|
644
|
-
for (let k = 1; k <= 3; k++) rr += 0.08 * Math.sin(a * (k + 2) + hash2(k, 1, t) * 6.28) / k;
|
|
645
|
-
let c = edge(rr - r);
|
|
646
|
-
for (let k = 0; k < 4; k++) {
|
|
647
|
-
const ang = hash2(k, 7, t) * Math.PI * 2;
|
|
648
|
-
const dist = 0.72 + 0.2 * hash2(k, 9, t);
|
|
649
|
-
const dx = u - Math.cos(ang) * dist;
|
|
650
|
-
const dy = v - Math.sin(ang) * dist;
|
|
651
|
-
c = Math.max(c, edge(0.08 + 0.06 * hash2(k, 11, t) - Math.hypot(dx, dy)));
|
|
652
|
-
}
|
|
653
|
-
return c;
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
736
|
function hexRgb(hex) {
|
|
658
737
|
const n = parseInt(hex.slice(1, 7), 16);
|
|
659
738
|
return [(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255];
|
|
@@ -664,7 +743,22 @@ function stickerRect(s) {
|
|
|
664
743
|
const y0 = Math.floor(s.y - r);
|
|
665
744
|
return { x: x0, y: y0, width: Math.ceil(s.x + r) - x0, height: Math.ceil(s.y + r) - y0 };
|
|
666
745
|
}
|
|
667
|
-
function
|
|
746
|
+
function stickerStamp(s) {
|
|
747
|
+
if (s.ref) {
|
|
748
|
+
try {
|
|
749
|
+
return editorStampOf(s.ref);
|
|
750
|
+
} catch {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return s.stamp && STAMP_KINDS.includes(s.stamp) ? s.stamp : null;
|
|
755
|
+
}
|
|
756
|
+
function drawSticker(medium, s, art) {
|
|
757
|
+
const kind = stickerStamp(s);
|
|
758
|
+
if (!kind) {
|
|
759
|
+
const a2 = art?.(s.ref);
|
|
760
|
+
return a2 ? drawArtSticker(medium, s, a2) : stickerRect(s);
|
|
761
|
+
}
|
|
668
762
|
const rect = stickerRect(s);
|
|
669
763
|
const n = rect.width * rect.height;
|
|
670
764
|
const cov = new Float32Array(n);
|
|
@@ -682,7 +776,7 @@ function drawSticker(medium, s) {
|
|
|
682
776
|
const v = (-dx * sa + dy * ca) / rad;
|
|
683
777
|
if (u < -1.05 || u > 1.05 || v < -1.05 || v > 1.05) continue;
|
|
684
778
|
let c = 0;
|
|
685
|
-
for (let k = 0; k < 4; k++) c += stampCoverage(
|
|
779
|
+
for (let k = 0; k < 4; k++) c += stampCoverage(kind, u + ((k & 1) - 0.5) / rad / 2, v + ((k >> 1) - 0.5) / rad / 2, s.seed);
|
|
686
780
|
c /= 4;
|
|
687
781
|
if (c <= 0) continue;
|
|
688
782
|
cov[p] = c;
|
|
@@ -695,6 +789,35 @@ function drawSticker(medium, s) {
|
|
|
695
789
|
medium.deposit(rect, cov, s.opacity, [r, g, b], null, field);
|
|
696
790
|
return rect;
|
|
697
791
|
}
|
|
792
|
+
function drawArtSticker(medium, s, art) {
|
|
793
|
+
const rect = stickerRect(s);
|
|
794
|
+
const n = rect.width * rect.height;
|
|
795
|
+
const cov = new Float32Array(n);
|
|
796
|
+
const field = new Float32Array(n * 3);
|
|
797
|
+
const a = s.rotation * Math.PI / 180;
|
|
798
|
+
const ca = Math.cos(a);
|
|
799
|
+
const sa = Math.sin(a);
|
|
800
|
+
const scale = Math.max(art.width, art.height) / s.size;
|
|
801
|
+
const [r, g, b] = hexRgb(s.color);
|
|
802
|
+
const px = [0, 0, 0, 0];
|
|
803
|
+
for (let yy = 0, p = 0; yy < rect.height; yy++) {
|
|
804
|
+
for (let xx = 0; xx < rect.width; xx++, p++) {
|
|
805
|
+
const dx = rect.x + xx + 0.5 - s.x;
|
|
806
|
+
const dy = rect.y + yy + 0.5 - s.y;
|
|
807
|
+
const ax = (dx * ca + dy * sa) * scale + art.width / 2;
|
|
808
|
+
const ay = (-dx * sa + dy * ca) * scale + art.height / 2;
|
|
809
|
+
if (ax < -1 || ay < -1 || ax > art.width + 1 || ay > art.height + 1) continue;
|
|
810
|
+
sampleArt(art, ax, ay, px);
|
|
811
|
+
if (!(px[3] > 0)) continue;
|
|
812
|
+
cov[p] = px[3];
|
|
813
|
+
field[p * 3] = art.tintable ? r : px[0];
|
|
814
|
+
field[p * 3 + 1] = art.tintable ? g : px[1];
|
|
815
|
+
field[p * 3 + 2] = art.tintable ? b : px[2];
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
medium.deposit(rect, cov, s.opacity, [r, g, b], null, field);
|
|
819
|
+
return rect;
|
|
820
|
+
}
|
|
698
821
|
function jitterColor(hex, amount, seed, i) {
|
|
699
822
|
const [r, g, b] = hexRgb(hex);
|
|
700
823
|
const lch = oklabToOklch(rgbToOklab({ r, g, b, a: 1 }));
|
|
@@ -730,6 +853,8 @@ var StickerSpray = class {
|
|
|
730
853
|
init;
|
|
731
854
|
dabCount = 0;
|
|
732
855
|
stickers = [];
|
|
856
|
+
/** Refs the spray picked but could not draw because their art had not loaded. */
|
|
857
|
+
skipped = /* @__PURE__ */ new Set();
|
|
733
858
|
smoother;
|
|
734
859
|
walkers;
|
|
735
860
|
copies;
|
|
@@ -776,9 +901,17 @@ var StickerSpray = class {
|
|
|
776
901
|
this.next++;
|
|
777
902
|
return;
|
|
778
903
|
}
|
|
904
|
+
const ref = st.stamps[Math.floor(rand01(seed, i, 57) * st.stamps.length)] ?? "editor:dot";
|
|
905
|
+
const stamp = stickerStamp({ ref });
|
|
906
|
+
if (!stamp && !this.init.art?.(ref)) {
|
|
907
|
+
this.skipped.add(ref);
|
|
908
|
+
this.next++;
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
779
911
|
const sticker = {
|
|
780
912
|
id: `st${this.next++}`,
|
|
781
|
-
|
|
913
|
+
ref,
|
|
914
|
+
...stamp ? { stamp } : {},
|
|
782
915
|
x: Math.round((d.x + Math.cos(a) * dist) * 100) / 100,
|
|
783
916
|
y: Math.round((d.y + Math.sin(a) * dist) * 100) / 100,
|
|
784
917
|
size: Math.max(2, Math.round(size * 10) / 10),
|
|
@@ -788,7 +921,7 @@ var StickerSpray = class {
|
|
|
788
921
|
seed: Math.floor(rand01(seed, i, 65) * 1e9)
|
|
789
922
|
};
|
|
790
923
|
this.stickers.push(sticker);
|
|
791
|
-
rects.push(drawSticker(this.medium, sticker));
|
|
924
|
+
rects.push(drawSticker(this.medium, sticker, this.init.art));
|
|
792
925
|
this.dabCount++;
|
|
793
926
|
}
|
|
794
927
|
sampler;
|
|
@@ -807,16 +940,24 @@ var StickerSpray = class {
|
|
|
807
940
|
return { color: "#" + s.rgb.map((c) => Math.round(Math.min(1, Math.max(0, c)) * 255).toString(16).padStart(2, "0")).join(""), alpha: s.alpha };
|
|
808
941
|
}
|
|
809
942
|
};
|
|
810
|
-
function renderStickers(stickers, target) {
|
|
943
|
+
function renderStickers(stickers, target, art) {
|
|
811
944
|
const medium = new TileMedium(target, {});
|
|
812
|
-
for (const s of stickers) drawSticker(medium, s);
|
|
945
|
+
for (const s of stickers) drawSticker(medium, s, art);
|
|
813
946
|
}
|
|
814
947
|
function normalizeStickerUpdate(u) {
|
|
815
948
|
const out = {};
|
|
949
|
+
if (u.ref !== void 0 && u.stamp !== void 0) throw new Error("Give ref or stamp, not both (stamp is the older name for an editor stamp).");
|
|
816
950
|
if (u.stamp !== void 0) {
|
|
817
|
-
if (!STAMP_KINDS.includes(u.stamp)) throw new Error(`stamp ${JSON.stringify(u.stamp)} is not a stamp; use ${STAMP_KINDS.join(", ")}.`);
|
|
951
|
+
if (!STAMP_KINDS.includes(u.stamp)) throw new Error(`stamp ${JSON.stringify(u.stamp)} is not a stamp; use ${STAMP_KINDS.join(", ")}, or ref for any sticker (find_stickers).`);
|
|
952
|
+
out.ref = `editor:${u.stamp}`;
|
|
818
953
|
out.stamp = u.stamp;
|
|
819
954
|
}
|
|
955
|
+
if (u.ref !== void 0) {
|
|
956
|
+
out.ref = normalizeStickerRef(u.ref);
|
|
957
|
+
const stamp = stickerStamp({ ref: out.ref });
|
|
958
|
+
if (stamp) out.stamp = stamp;
|
|
959
|
+
else out.stamp = void 0;
|
|
960
|
+
}
|
|
820
961
|
for (const k of ["x", "y"]) if (u[k] !== void 0) {
|
|
821
962
|
if (!Number.isFinite(u[k])) throw new Error(`${k} must be a number of pixels.`);
|
|
822
963
|
out[k] = u[k];
|
|
@@ -839,7 +980,7 @@ function normalizeStickerUpdate(u) {
|
|
|
839
980
|
}
|
|
840
981
|
return out;
|
|
841
982
|
}
|
|
842
|
-
function stickerSurface(stickers, base, dirty) {
|
|
983
|
+
function stickerSurface(stickers, base, dirty, art) {
|
|
843
984
|
const only = base && dirty ? new Set(dirty.flatMap((r) => tilesInRect(r).map(({ tx, ty }) => tileKey(tx, ty)))) : null;
|
|
844
985
|
const live = /* @__PURE__ */ new Map();
|
|
845
986
|
let scratch = null;
|
|
@@ -857,7 +998,7 @@ function stickerSurface(stickers, base, dirty) {
|
|
|
857
998
|
}
|
|
858
999
|
};
|
|
859
1000
|
const reaches = (s) => !only || tilesInRect(stickerRect(s)).some(({ tx, ty }) => only.has(tileKey(tx, ty)));
|
|
860
|
-
renderStickers(stickers.filter(reaches), target);
|
|
1001
|
+
renderStickers(stickers.filter(reaches), target, art);
|
|
861
1002
|
const tiles = /* @__PURE__ */ new Map();
|
|
862
1003
|
if (only && base) {
|
|
863
1004
|
for (const [k, t] of base.tiles) if (!only.has(k)) tiles.set(k, t);
|
|
@@ -868,7 +1009,7 @@ function stickerSurface(stickers, base, dirty) {
|
|
|
868
1009
|
}
|
|
869
1010
|
return new TiledSurface(4, tiles, 0);
|
|
870
1011
|
}
|
|
871
|
-
function stickerAt(stickers, x, y) {
|
|
1012
|
+
function stickerAt(stickers, x, y, art) {
|
|
872
1013
|
for (let i = stickers.length - 1; i >= 0; i--) {
|
|
873
1014
|
const s = stickers[i];
|
|
874
1015
|
const rad = s.size / 2;
|
|
@@ -878,7 +1019,16 @@ function stickerAt(stickers, x, y) {
|
|
|
878
1019
|
const u = (dx * Math.cos(a) + dy * Math.sin(a)) / rad;
|
|
879
1020
|
const v = (-dx * Math.sin(a) + dy * Math.cos(a)) / rad;
|
|
880
1021
|
if (Math.abs(u) > 1.05 || Math.abs(v) > 1.05) continue;
|
|
881
|
-
if (s.size < 16
|
|
1022
|
+
if (s.size < 16) return s;
|
|
1023
|
+
const kind = stickerStamp(s);
|
|
1024
|
+
if (kind) {
|
|
1025
|
+
if (stampCoverage(kind, u, v, s.seed) > 0.25) return s;
|
|
1026
|
+
continue;
|
|
1027
|
+
}
|
|
1028
|
+
const pic = art?.(s.ref);
|
|
1029
|
+
if (!pic) return s;
|
|
1030
|
+
const scale = Math.max(pic.width, pic.height) / 2;
|
|
1031
|
+
if (sampleArt(pic, u * scale + pic.width / 2, v * scale + pic.height / 2, [0, 0, 0, 0])[3] > 0.25) return s;
|
|
882
1032
|
}
|
|
883
1033
|
return null;
|
|
884
1034
|
}
|
|
@@ -2425,11 +2575,15 @@ export {
|
|
|
2425
2575
|
DryStroke,
|
|
2426
2576
|
mixerTip,
|
|
2427
2577
|
toStrokePoint,
|
|
2428
|
-
|
|
2578
|
+
STICKER_ART_SIZE,
|
|
2579
|
+
defaultStickerRasterizer,
|
|
2580
|
+
StickerArtCache,
|
|
2581
|
+
sampleArt,
|
|
2582
|
+
MAX_STICKER_STAMPS,
|
|
2429
2583
|
DEFAULT_STICKER,
|
|
2430
2584
|
normalizeStickerSettings,
|
|
2431
|
-
stampCoverage,
|
|
2432
2585
|
stickerRect,
|
|
2586
|
+
stickerStamp,
|
|
2433
2587
|
drawSticker,
|
|
2434
2588
|
StickerSpray,
|
|
2435
2589
|
renderStickers,
|