@pixerate/editor 0.248.0 → 0.249.0

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