@pixerate/editor 0.264.1 → 0.266.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 (60) hide show
  1. package/dist/agent/index.cjs +4 -3
  2. package/dist/agent/index.js +3 -2
  3. package/dist/animation-editor/index.cjs +60 -61
  4. package/dist/animation-editor/index.js +4 -5
  5. package/dist/brushes/index.cjs +73 -60
  6. package/dist/brushes/index.d.cts +1 -0
  7. package/dist/brushes/index.d.ts +1 -0
  8. package/dist/brushes/index.js +17 -4
  9. package/dist/brushes/preview.d.cts +59 -0
  10. package/dist/brushes/preview.d.ts +59 -0
  11. package/dist/brushes/tools.d.cts +12 -5
  12. package/dist/brushes/tools.d.ts +12 -5
  13. package/dist/{brushstrokeRender-3MOI7PH4.js → brushstrokeRender-4UB6NRJW.js} +11 -4
  14. package/dist/{brushstrokeRender-SMMPIJF2.cjs → brushstrokeRender-JQ2XQRUD.cjs} +22 -15
  15. package/dist/canvas/brushstroke.d.cts +6 -1
  16. package/dist/canvas/brushstroke.d.ts +6 -1
  17. package/dist/canvas/index.cjs +18 -18
  18. package/dist/canvas/index.js +4 -4
  19. package/dist/{chunk-TMDDMJCR.js → chunk-472INMWH.js} +4 -2
  20. package/dist/chunk-55ALHYJY.js +289 -0
  21. package/dist/{chunk-F3KKR6DD.cjs → chunk-5OE4ZZ6V.cjs} +30 -30
  22. package/dist/{chunk-BY5EBP26.cjs → chunk-677777GH.cjs} +3 -3
  23. package/dist/{chunk-NHA26O5X.cjs → chunk-7KNW3WXZ.cjs} +14 -12
  24. package/dist/{chunk-G5ADO47G.cjs → chunk-7NQOGWLM.cjs} +3 -2
  25. package/dist/{chunk-WWI6FLH2.js → chunk-7PW6VCNW.js} +2 -2
  26. package/dist/{chunk-CECCP2V7.js → chunk-BLR4KWYQ.js} +1 -1
  27. package/dist/chunk-DEBIFWY6.cjs +77 -0
  28. package/dist/{chunk-KXNZNOEF.cjs → chunk-DGXTEPCU.cjs} +94 -94
  29. package/dist/{chunk-3CI7FRMK.js → chunk-DVPQFMH6.js} +13 -1
  30. package/dist/chunk-E2Z4UARJ.cjs +289 -0
  31. package/dist/chunk-HAEB3MZD.js +664 -0
  32. package/dist/{chunk-EE7SAYBF.js → chunk-J4SGJCPW.js} +3 -3
  33. package/dist/{chunk-A2IS7EHE.cjs → chunk-JBZRVLXV.cjs} +14 -2
  34. package/dist/chunk-KIJIONZF.cjs +664 -0
  35. package/dist/{chunk-V7MJ4HIN.cjs → chunk-NOP4Y5AB.cjs} +23 -23
  36. package/dist/{chunk-FQC5TDB6.cjs → chunk-O53MOGXG.cjs} +35 -35
  37. package/dist/{chunk-LPFQHVCO.js → chunk-PXXXRCME.js} +1 -284
  38. package/dist/{chunk-4OJC4MCD.js → chunk-Q6RVVJW6.js} +1 -1
  39. package/dist/{chunk-T7QSEKDY.cjs → chunk-QJVOJUTD.cjs} +4 -287
  40. package/dist/{chunk-HAUDEVMC.js → chunk-WY23AUCA.js} +2 -2
  41. package/dist/{chunk-JEML4FSA.js → chunk-XDNWQMHY.js} +3 -2
  42. package/dist/{chunk-ROBSFJ6F.js → chunk-Z2Z2OHRM.js} +1 -1
  43. package/dist/{chunk-USJX5SW4.cjs → chunk-ZHRVCW3M.cjs} +12 -12
  44. package/dist/chunk-ZS7LB2MV.js +77 -0
  45. package/dist/commands/index.cjs +26 -656
  46. package/dist/commands/index.js +18 -648
  47. package/dist/image-editor/index.cjs +788 -790
  48. package/dist/image-editor/index.js +6 -8
  49. package/dist/paint-editor/index.cjs +88 -84
  50. package/dist/paint-editor/index.js +12 -8
  51. package/dist/vector/contract.d.cts +52 -0
  52. package/dist/vector/contract.d.ts +52 -0
  53. package/dist/vector/index.cjs +1168 -971
  54. package/dist/vector/index.d.cts +1 -0
  55. package/dist/vector/index.d.ts +1 -0
  56. package/dist/vector/index.js +204 -7
  57. package/package.json +1 -1
  58. package/skills/pixerate-brushes/SKILL.md +7 -2
  59. package/dist/chunk-FJBQTZS4.js +0 -17
  60. package/dist/chunk-LRTR4ASZ.cjs +0 -17
@@ -16,7 +16,7 @@ import {
16
16
  resolveCategory,
17
17
  resolveEngine,
18
18
  withKeptIssues
19
- } from "./chunk-EE7SAYBF.js";
19
+ } from "./chunk-J4SGJCPW.js";
20
20
 
21
21
  // src/brushes/patch.ts
22
22
  var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
@@ -2,8 +2,8 @@
2
2
  var PLATFORMS = ["mac", "windows", "linux"];
3
3
  function detectPlatform() {
4
4
  const nav = typeof navigator !== "undefined" ? navigator : void 0;
5
- const text = `${_nullishCoalesce(_optionalChain([nav, 'optionalAccess', _2 => _2.platform]), () => ( ""))} ${_nullishCoalesce(_optionalChain([nav, 'optionalAccess', _3 => _3.userAgent]), () => ( ""))}`;
6
- if (/Mac|iPod|iPhone|iPad/.test(_optionalChain([nav, 'optionalAccess', _4 => _4.platform]) || _optionalChain([nav, 'optionalAccess', _5 => _5.userAgent]) || "")) return "mac";
5
+ const text = `${_nullishCoalesce(_optionalChain([nav, 'optionalAccess', _ => _.platform]), () => ( ""))} ${_nullishCoalesce(_optionalChain([nav, 'optionalAccess', _2 => _2.userAgent]), () => ( ""))}`;
6
+ if (/Mac|iPod|iPhone|iPad/.test(_optionalChain([nav, 'optionalAccess', _3 => _3.platform]) || _optionalChain([nav, 'optionalAccess', _4 => _4.userAgent]) || "")) return "mac";
7
7
  if (/Win/.test(text)) return "windows";
8
8
  return "linux";
9
9
  }
@@ -222,7 +222,7 @@ function isEditableEventTarget(event) {
222
222
  if (!target) target = typeof document !== "undefined" ? document.activeElement : null;
223
223
  if (!target || typeof target.tagName !== "string") return false;
224
224
  const tag = target.tagName.toUpperCase();
225
- return !!(tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || target.isContentEditable || _optionalChain([target, 'access', _6 => _6.getAttribute, 'optionalCall', _7 => _7("contenteditable")]) === "true" || _optionalChain([target, 'access', _8 => _8.closest, 'optionalCall', _9 => _9('[contenteditable="true"]')]) || _optionalChain([target, 'access', _10 => _10.closest, 'optionalCall', _11 => _11(".ProseMirror")]));
225
+ return !!(tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || target.isContentEditable || _optionalChain([target, 'access', _5 => _5.getAttribute, 'optionalCall', _6 => _6("contenteditable")]) === "true" || _optionalChain([target, 'access', _7 => _7.closest, 'optionalCall', _8 => _8('[contenteditable="true"]')]) || _optionalChain([target, 'access', _9 => _9.closest, 'optionalCall', _10 => _10(".ProseMirror")]));
226
226
  }
227
227
 
228
228
  // src/commands/shortcuts.ts
@@ -392,289 +392,6 @@ function eitherKey(chord) {
392
392
  return [(chord.mod || chord.ctrl || chord.meta) && "Mod", chord.alt && "Alt", chord.shift && "Shift", chord.key].filter(Boolean).join("+");
393
393
  }
394
394
 
395
- // src/canvas/arrangeShortcuts.ts
396
- var DEFAULT_ARRANGE_SHORTCUTS = [
397
- { action: "alignLeft", code: "KeyA", alt: true, label: "Alt+A" },
398
- { action: "alignCenter", code: "KeyH", alt: true, label: "Alt+H" },
399
- { action: "alignRight", code: "KeyD", alt: true, label: "Alt+D" },
400
- { action: "alignTop", code: "KeyW", alt: true, label: "Alt+W" },
401
- { action: "alignMiddle", code: "KeyV", alt: true, label: "Alt+V" },
402
- { action: "alignBottom", code: "KeyS", alt: true, label: "Alt+S" },
403
- { action: "distributeHorizontal", code: "KeyH", alt: true, shift: true, label: "Alt+Shift+H" },
404
- { action: "distributeVertical", code: "KeyV", alt: true, shift: true, label: "Alt+Shift+V" },
405
- { action: "lock", code: "KeyL", mod: true, label: "Mod+L" },
406
- { action: "unlock", code: "KeyL", mod: true, alt: true, label: "Mod+Alt+L" },
407
- { action: "bringForward", code: "BracketRight", mod: true, label: "Mod+]" },
408
- { action: "sendBackward", code: "BracketLeft", mod: true, label: "Mod+[" },
409
- { action: "bringToFront", code: "BracketRight", mod: true, alt: true, label: "Mod+Alt+]" },
410
- { action: "sendToBack", code: "BracketLeft", mod: true, alt: true, label: "Mod+Alt+[" },
411
- { action: "nextScene", code: "PageDown", label: "PageDown" },
412
- { action: "previousScene", code: "PageUp", label: "PageUp" }
413
- ];
414
- var maps = /* @__PURE__ */ new WeakMap();
415
- function arrangeShortcutMap(bindings) {
416
- let map = maps.get(bindings);
417
- if (!map) {
418
- map = new ShortcutMap(
419
- bindings.map((b) => ({
420
- command: b.action,
421
- chord: { key: b.code, mod: b.mod, alt: b.alt, shift: b.shift }
422
- })),
423
- { modifierMode: "either" }
424
- );
425
- maps.set(bindings, map);
426
- }
427
- return map;
428
- }
429
- function matchArrangeShortcut(event, bindings = DEFAULT_ARRANGE_SHORTCUTS) {
430
- return _nullishCoalesce(_optionalChain([arrangeShortcutMap, 'call', _12 => _12(bindings), 'access', _13 => _13.resolve, 'call', _14 => _14(event), 'optionalAccess', _15 => _15.command]), () => ( null));
431
- }
432
-
433
- // src/canvas/gestures.ts
434
- function gestureRandom(seed) {
435
- let a = seed >>> 0;
436
- return () => {
437
- a = a + 1831565813 >>> 0;
438
- let t = a;
439
- t = Math.imul(t ^ t >>> 15, t | 1);
440
- t ^= t + Math.imul(t ^ t >>> 7, t | 61);
441
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
442
- };
443
- }
444
- function gestureSeed(value) {
445
- const text = _nullishCoalesce(JSON.stringify(value), () => ( ""));
446
- let h = 2166136261;
447
- for (let i = 0; i < text.length; i++) {
448
- h ^= text.charCodeAt(i);
449
- h = Math.imul(h, 16777619);
450
- }
451
- return h >>> 0;
452
- }
453
- function gestureUnion(rects) {
454
- if (!rects.length) throw new Error("Pass at least one rect.");
455
- const x = Math.min(...rects.map((r) => r.x));
456
- const y = Math.min(...rects.map((r) => r.y));
457
- const right = Math.max(...rects.map((r) => r.x + r.width));
458
- const bottom = Math.max(...rects.map((r) => r.y + r.height));
459
- return { x, y, width: right - x, height: bottom - y };
460
- }
461
- var clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
462
- var centre = (r) => [r.x + r.width / 2, r.y + r.height / 2];
463
- function smoothNoise(rand, octaves = 3) {
464
- const waves = Array.from({ length: octaves }, (_, i) => ({ f: (i + 1) * (0.6 + rand() * 0.8), phase: rand() * Math.PI * 2, amp: 1 / (i + 1) }));
465
- const total = waves.reduce((sum, w) => sum + w.amp, 0);
466
- return (t) => waves.reduce((sum, w) => sum + w.amp * Math.sin(2 * Math.PI * w.f * t + w.phase), 0) / total;
467
- }
468
- function handPressure(rand) {
469
- const r = (lo, hi) => Math.round((lo + rand() * (hi - lo)) * 100) / 100;
470
- return [r(0.35, 0.55), r(0.8, 0.95), r(0.9, 1), r(0.75, 0.95), r(0.4, 0.65)];
471
- }
472
- var round = (p) => [Math.round(p[0] * 100) / 100, Math.round(p[1] * 100) / 100];
473
- function wobblyLine(a, b, rand, amp, bow = 0) {
474
- const dx = b[0] - a[0];
475
- const dy = b[1] - a[1];
476
- const len = Math.hypot(dx, dy);
477
- if (len === 0) return [a];
478
- const nx = -dy / len;
479
- const ny = dx / len;
480
- const noise = smoothNoise(rand);
481
- const n = clamp(Math.ceil(len / 4), 8, 200);
482
- return Array.from({ length: n + 1 }, (_, i) => {
483
- const t = i / n;
484
- const off = bow * 4 * t * (1 - t) + amp * noise(t) * Math.sqrt(Math.sin(Math.PI * t));
485
- return [a[0] + dx * t + nx * off, a[1] + dy * t + ny * off];
486
- });
487
- }
488
- function circleGesture(rect, seed, options = {}) {
489
- const rand = gestureRandom(seed);
490
- const pad = Math.max(0, _nullishCoalesce(options.padding, () => ( 8)));
491
- const [cx, cy] = centre(rect);
492
- const tilt = (rand() - 0.5) * 0.08;
493
- const c = Math.abs(Math.cos(tilt));
494
- const s = Math.abs(Math.sin(tilt));
495
- const a = (rect.width / 2 * c + rect.height / 2 * s) * Math.SQRT2 + pad;
496
- const b = (rect.width / 2 * s + rect.height / 2 * c) * Math.SQRT2 + pad;
497
- const dir = rand() < 0.7 ? -1 : 1;
498
- const start = -Math.PI * 0.75 + (rand() - 0.5) * 0.6;
499
- const sweep = Math.PI * 2 + Math.PI * (0.1 + rand() * 0.12);
500
- const jitter = 0.03 + rand() * 0.03;
501
- const drift = 0.04 + rand() * 0.05;
502
- const noise = smoothNoise(rand, 4);
503
- const perimeter = Math.PI * (3 * (a + b) - Math.sqrt((3 * a + b) * (a + 3 * b)));
504
- const n = clamp(Math.ceil(perimeter * (sweep / (Math.PI * 2)) / 5), 48, 360);
505
- const points = Array.from({ length: n + 1 }, (_, i) => {
506
- const t = i / n;
507
- const angle = start + dir * sweep * t;
508
- const grow = 1 + jitter * (0.5 + 0.5 * noise(t)) + drift * t * t;
509
- const ex = a * grow * Math.cos(angle);
510
- const ey = b * grow * Math.sin(angle);
511
- return round([cx + ex * Math.cos(tilt) - ey * Math.sin(tilt), cy + ex * Math.sin(tilt) + ey * Math.cos(tilt)]);
512
- });
513
- return { points, pressure: handPressure(rand) };
514
- }
515
- function underlineGesture(rect, seed, options = {}) {
516
- const rand = gestureRandom(seed);
517
- const offset = Math.max(0, _nullishCoalesce(options.offset, () => ( 4)));
518
- const amp = options.wave ? clamp(rect.width * 0.02, 2, 4) : 0;
519
- const shake = Math.min(1.5, offset * 0.4);
520
- const base = rect.y + rect.height + offset + amp + shake;
521
- const slope = Math.min(6, rect.width * 0.03);
522
- const x0 = rect.x - rect.width * (0.01 + rand() * 0.04);
523
- const x1 = rect.x + rect.width * (0.96 + rand() * 0.08);
524
- const line = wobblyLine([x0, base + rand() * slope], [x1, base + rand() * slope], rand, shake, (rand() - 0.5) * 2 * shake);
525
- const wavelength = clamp(rect.width / 8, 12, 28);
526
- const phase = rand() * Math.PI * 2;
527
- const points = amp ? line.map(([x, y]) => [x, y + amp * Math.sin(2 * Math.PI * (x - x0) / wavelength + phase)]) : line;
528
- return { points: points.map(round), pressure: handPressure(rand) };
529
- }
530
- function gestureEdgePoint(rect, toward, gap = 0) {
531
- const [cx, cy] = centre(rect);
532
- const dx = toward[0] - cx;
533
- const dy = toward[1] - cy;
534
- const len = Math.hypot(dx, dy);
535
- if (len === 0) return [cx, cy];
536
- const t = Math.min(dx ? rect.width / 2 / Math.abs(dx) : Infinity, dy ? rect.height / 2 / Math.abs(dy) : Infinity);
537
- return [cx + dx * t + dx / len * gap, cy + dy * t + dy / len * gap];
538
- }
539
- var isRect = (end) => !Array.isArray(end);
540
- function arrowGesture(from, to, seed, options = {}) {
541
- const rand = gestureRandom(seed);
542
- const gap = Math.max(0, _nullishCoalesce(options.gap, () => ( 6)));
543
- const fromCentre = isRect(from) ? centre(from) : from;
544
- const toCentre = isRect(to) ? centre(to) : to;
545
- const start = isRect(from) ? gestureEdgePoint(from, toCentre, gap) : from;
546
- const tip = isRect(to) ? gestureEdgePoint(to, fromCentre, gap) : to;
547
- const dx = tip[0] - start[0];
548
- const dy = tip[1] - start[1];
549
- const len = Math.hypot(dx, dy);
550
- if (len < 4) throw new Error("The arrow's ends are too close together (or overlap): pass ends at least a few canvas units apart.");
551
- const curve = clamp(_nullishCoalesce(options.curve, () => ( (0.08 + rand() * 0.08) * (rand() < 0.5 ? -1 : 1))), -1, 1);
552
- const nx = -dy / len;
553
- const ny = dx / len;
554
- const control = [(start[0] + tip[0]) / 2 + nx * curve * len, (start[1] + tip[1]) / 2 + ny * curve * len];
555
- const noise = smoothNoise(rand);
556
- const amp = Math.min(2, len * 0.01);
557
- const n = clamp(Math.ceil(len / 4), 12, 200);
558
- const shaft = Array.from({ length: n + 1 }, (_, i) => {
559
- const t = i / n;
560
- const u = 1 - t;
561
- const x = u * u * start[0] + 2 * u * t * control[0] + t * t * tip[0];
562
- const y = u * u * start[1] + 2 * u * t * control[1] + t * t * tip[1];
563
- const off = amp * noise(t) * Math.sqrt(Math.sin(Math.PI * t));
564
- return [x + nx * off, y + ny * off];
565
- });
566
- const tx = tip[0] - control[0];
567
- const ty = tip[1] - control[1];
568
- const tl = Math.hypot(tx, ty) || 1;
569
- const head = clamp(len * 0.15, 8, 22);
570
- const barb = (angle2, length) => {
571
- const c = Math.cos(angle2);
572
- const s = Math.sin(angle2);
573
- const bx = -(tx / tl) * c + ty / tl * s;
574
- const by = -(ty / tl) * c - tx / tl * s;
575
- return [1 / 3, 2 / 3, 1].map((f) => [tip[0] + bx * length * f, tip[1] + by * length * f]);
576
- };
577
- const clear = (pts) => !isRect(to) || pts.every(([x, y]) => x <= to.x || x >= to.x + to.width || y <= to.y || y >= to.y + to.height);
578
- const fit = (angle2) => {
579
- const length = head * (0.85 + rand() * 0.3);
580
- for (let k = 1; k > 0.05; k -= 0.15) {
581
- const pts = barb(angle2 * k, length);
582
- if (clear(pts)) return pts;
583
- }
584
- return barb(0, length);
585
- };
586
- const angle = () => (25 + rand() * 8) * Math.PI / 180;
587
- const first = fit(angle());
588
- const second = fit(-angle());
589
- const points = [...shaft, ...first, ...first.slice(0, -1).reverse(), tip, ...second];
590
- return { points: points.map(round), pressure: handPressure(rand) };
591
- }
592
- function bracketGesture(rect, side, seed, options = {}) {
593
- const rand = gestureRandom(seed);
594
- const pad = Math.max(0, _nullishCoalesce(options.padding, () => ( 8)));
595
- const vertical = side === "left" || side === "right";
596
- const span = vertical ? rect.height : rect.width;
597
- const depth = Math.max(1, _nullishCoalesce(options.depth, () => ( clamp(span * 0.08, 6, 20))));
598
- const from = vertical ? rect.y : rect.x;
599
- const edge = side === "left" ? rect.x - pad : side === "right" ? rect.x + rect.width + pad : side === "top" ? rect.y - pad : rect.y + rect.height + pad;
600
- const out = side === "left" || side === "top" ? -1 : 1;
601
- const at = (s, d) => vertical ? [edge + out * d, from + s * span] : [from + s * span, edge + out * d];
602
- const noise = smoothNoise(rand);
603
- const shake = Math.min(1, depth * 0.06);
604
- const n = clamp(Math.ceil(span / 4), 24, 240);
605
- let points;
606
- if (options.shape === "square") {
607
- const arm = depth * (0.8 + rand() * 0.2);
608
- const spine = Array.from({ length: n + 1 }, (_, i) => at(i / n, depth + shake * (1 + noise(i / n))));
609
- points = [at(0, depth - arm), at(0, depth * 0.5), ...spine, at(1, depth * 0.5), at(1, depth - arm * (0.85 + rand() * 0.15))];
610
- } else {
611
- const e = clamp(depth / Math.max(span, 1), 0.04, 0.2);
612
- const brace = (s) => {
613
- const u = s <= 0.5 ? s : 1 - s;
614
- if (u < e) return depth / 2 * Math.sin(Math.PI / 2 * u / e);
615
- if (u < 0.5 - e) return depth / 2;
616
- return depth / 2 + depth / 2 * (1 - Math.cos(Math.PI / 2 * (u - (0.5 - e)) / e));
617
- };
618
- points = Array.from({ length: n + 1 }, (_, i) => {
619
- const s = i / n;
620
- return at(s, brace(s) + shake * (1 + noise(s)) * Math.sin(Math.PI * s));
621
- });
622
- }
623
- return { points: points.map(round), pressure: handPressure(rand) };
624
- }
625
- function strikeGesture(rect, seed) {
626
- const rand = gestureRandom(seed);
627
- const [, cy] = centre(rect);
628
- const slope = rect.height * 0.08;
629
- const x0 = rect.x - rect.width * (0.01 + rand() * 0.03);
630
- const x1 = rect.x + rect.width * (1.01 + rand() * 0.03);
631
- const y0 = cy + (rand() - 0.5) * rect.height * 0.1 + slope * (rand() - 0.5);
632
- const y1 = cy + (rand() - 0.5) * rect.height * 0.1 + slope * (rand() - 0.5);
633
- const points = wobblyLine([x0, y0], [x1, y1], rand, Math.min(1.5, rect.height * 0.05));
634
- return { points: points.map(round), pressure: handPressure(rand) };
635
- }
636
- function crossGesture(rect, seed) {
637
- const rand = gestureRandom(seed);
638
- const over = () => 0.02 + rand() * 0.04;
639
- const left = () => rect.x - rect.width * over();
640
- const right = () => rect.x + rect.width * (1 + over());
641
- const top = () => rect.y - rect.height * over();
642
- const bottom = () => rect.y + rect.height * (1 + over());
643
- const amp = Math.min(1.5, Math.min(rect.width, rect.height) * 0.03);
644
- const first = wobblyLine([left(), top()], [right(), bottom()], rand, amp);
645
- const second = wobblyLine([right(), top()], [left(), bottom()], rand, amp);
646
- const mid1 = Math.floor(first.length / 2);
647
- const mid2 = Math.floor(second.length / 2);
648
- const points = [...first, ...first.slice(mid1, -1).reverse(), ...second.slice(1, mid2 + 1).reverse(), ...second];
649
- return { points: points.map(round), pressure: handPressure(rand) };
650
- }
651
- function checkGesture(at, seed, options = {}) {
652
- const rand = gestureRandom(seed);
653
- const [cx, cy] = isRect(at) ? centre(at) : at;
654
- const s = Math.max(4, _nullishCoalesce(options.size, () => ( (isRect(at) ? clamp(Math.min(at.width, at.height) * 0.6, 12, 48) : 20))));
655
- const turn = (rand() - 0.5) * 12 * Math.PI / 180;
656
- const place = ([x, y]) => [cx + s * (x * Math.cos(turn) - y * Math.sin(turn)), cy + s * (x * Math.sin(turn) + y * Math.cos(turn))];
657
- const p0 = [-0.42 + rand() * 0.08, -0.05 + rand() * 0.08];
658
- const p1 = [-0.12 + rand() * 0.06, 0.38 + rand() * 0.06];
659
- const p2 = [0.48 + rand() * 0.06, -0.5 + rand() * 0.06];
660
- const short = wobblyLine(place(p0), place(p1), rand, 0, -s * 0.03);
661
- const long = wobblyLine(place(p1), place(p2), rand, Math.min(1, s * 0.02), s * 0.06);
662
- return { points: [...short, ...long.slice(1)].map(round), pressure: [0.5, 0.95, 0.9, 0.7, 0.35] };
663
- }
664
-
665
-
666
-
667
-
668
-
669
-
670
-
671
-
672
-
673
-
674
-
675
-
676
-
677
-
678
395
 
679
396
 
680
397
 
@@ -692,4 +409,4 @@ function checkGesture(at, seed, options = {}) {
692
409
 
693
410
 
694
411
 
695
- exports.PLATFORMS = PLATFORMS; exports.detectPlatform = detectPlatform; exports.keyToCode = keyToCode; exports.codeToKeyText = codeToKeyText; exports.parseChord = parseChord; exports.chordToString = chordToString; exports.normalizeChord = normalizeChord; exports.effectiveChord = effectiveChord; exports.effectiveChordKey = effectiveChordKey; exports.formatShortcut = formatShortcut; exports.eventCode = eventCode; exports.shortcutCode = shortcutCode; exports.codeFromKey = codeFromKey; exports.isEditableEventTarget = isEditableEventTarget; exports.toShortcutBindings = toShortcutBindings; exports.ShortcutMap = ShortcutMap; exports.DEFAULT_ARRANGE_SHORTCUTS = DEFAULT_ARRANGE_SHORTCUTS; exports.matchArrangeShortcut = matchArrangeShortcut; exports.gestureRandom = gestureRandom; exports.gestureSeed = gestureSeed; exports.gestureUnion = gestureUnion; exports.circleGesture = circleGesture; exports.underlineGesture = underlineGesture; exports.gestureEdgePoint = gestureEdgePoint; exports.arrowGesture = arrowGesture; exports.bracketGesture = bracketGesture; exports.strikeGesture = strikeGesture; exports.crossGesture = crossGesture; exports.checkGesture = checkGesture;
412
+ exports.PLATFORMS = PLATFORMS; exports.detectPlatform = detectPlatform; exports.keyToCode = keyToCode; exports.codeToKeyText = codeToKeyText; exports.parseChord = parseChord; exports.chordToString = chordToString; exports.normalizeChord = normalizeChord; exports.effectiveChord = effectiveChord; exports.effectiveChordKey = effectiveChordKey; exports.formatShortcut = formatShortcut; exports.eventCode = eventCode; exports.shortcutCode = shortcutCode; exports.codeFromKey = codeFromKey; exports.isEditableEventTarget = isEditableEventTarget; exports.toShortcutBindings = toShortcutBindings; exports.ShortcutMap = ShortcutMap;
@@ -108,7 +108,7 @@ import {
108
108
  transformTextRect,
109
109
  translateMatrix,
110
110
  warpPresetMesh
111
- } from "./chunk-WWI6FLH2.js";
111
+ } from "./chunk-7PW6VCNW.js";
112
112
  import {
113
113
  bezierPathBounds,
114
114
  outlineStroke,
@@ -119,7 +119,7 @@ import {
119
119
  } from "./chunk-WEIK3UYB.js";
120
120
  import {
121
121
  parseCssColor
122
- } from "./chunk-3CI7FRMK.js";
122
+ } from "./chunk-DVPQFMH6.js";
123
123
  import {
124
124
  MAX_BRUSH_SIZE
125
125
  } from "./chunk-GCVFEPJG.js";
@@ -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 ??= import("./brushstrokeRender-3MOI7PH4.js").catch((error) => {
77
+ loading ??= import("./brushstrokeRender-4UB6NRJW.js").catch((error) => {
78
78
  loading = null;
79
79
  throw error;
80
80
  });
@@ -117,7 +117,8 @@ async function renderCanvasBrushSwatch(brush, options = {}, spec) {
117
117
  return (await loadCanvasBrushstrokeRenderer()).brushSwatchNow(brush, options, spec);
118
118
  }
119
119
  var renderCanvasBrushPreview = async (brush, { width, height, color }) => {
120
- const url = await renderCanvasBrushSwatch(brush.id, { width, height, color, scale: 1 }, brush);
120
+ const { light: _light, ...plain } = brush;
121
+ const url = await renderCanvasBrushSwatch(brush.id, { width, height, color, scale: 1 }, plain);
121
122
  return { data: url.replace(/^data:image\/png;base64,/, ""), mimeType: "image/png" };
122
123
  };
123
124
 
@@ -18,7 +18,7 @@ import {
18
18
  unionBounds,
19
19
  vectorGradientPoints,
20
20
  widthProfileAt
21
- } from "./chunk-WWI6FLH2.js";
21
+ } from "./chunk-7PW6VCNW.js";
22
22
  import {
23
23
  segmentLength,
24
24
  segmentParamAtLength,
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
 
10
- var _chunkBY5EBP26cjs = require('./chunk-BY5EBP26.cjs');
10
+ var _chunk677777GHcjs = require('./chunk-677777GH.cjs');
11
11
 
12
12
 
13
13
  var _chunkCVFAAZXEcjs = require('./chunk-CVFAAZXE.cjs');
@@ -51,7 +51,7 @@ var _chunkGF2RBSDMcjs = require('./chunk-GF2RBSDM.cjs');
51
51
  var _chunkNM3G4VQTcjs = require('./chunk-NM3G4VQT.cjs');
52
52
 
53
53
 
54
- var _chunkLRTR4ASZcjs = require('./chunk-LRTR4ASZ.cjs');
54
+ var _chunkJBZRVLXVcjs = require('./chunk-JBZRVLXV.cjs');
55
55
 
56
56
 
57
57
 
@@ -2536,11 +2536,11 @@ function vectorExtrudeFaces(path, params) {
2536
2536
 
2537
2537
  // src/vector/brushstroke.ts
2538
2538
  var VECTOR_BRUSHSTROKE_SCALE = 2;
2539
- var PRESETS = _chunkBY5EBP26cjs.listPresets.call(void 0, _chunkBY5EBP26cjs.VECTOR_PROFILE).map((spec) => _chunkBY5EBP26cjs.BUILTIN_BRUSHES.find((b) => b.id === spec.id));
2539
+ var PRESETS = _chunk677777GHcjs.listPresets.call(void 0, _chunk677777GHcjs.VECTOR_PROFILE).map((spec) => _chunk677777GHcjs.BUILTIN_BRUSHES.find((b) => b.id === spec.id));
2540
2540
  function admitted(spec) {
2541
2541
  try {
2542
- const brush = _chunkBY5EBP26cjs.normalizeBrushSpec.call(void 0, spec);
2543
- return _chunkBY5EBP26cjs.checkBrush.call(void 0, brush, _chunkBY5EBP26cjs.VECTOR_PROFILE).ok && _chunkPXDIAYB6cjs.isBrushstrokeBrush.call(void 0, _chunkBY5EBP26cjs.resolveBrush.call(void 0, brush)) ? brush : null;
2542
+ const brush = _chunk677777GHcjs.normalizeBrushSpec.call(void 0, spec);
2543
+ return _chunk677777GHcjs.checkBrush.call(void 0, brush, _chunk677777GHcjs.VECTOR_PROFILE).ok && _chunkPXDIAYB6cjs.isBrushstrokeBrush.call(void 0, _chunk677777GHcjs.resolveBrush.call(void 0, brush)) ? brush : null;
2544
2544
  } catch (e4) {
2545
2545
  return null;
2546
2546
  }
@@ -2549,7 +2549,7 @@ function vectorBrushstrokeBrushes(user = []) {
2549
2549
  const out = [...PRESETS];
2550
2550
  for (const raw of user) {
2551
2551
  const brush = admitted(raw);
2552
- if (brush && !out.some((b) => b.id === brush.id)) out.push(_chunkBY5EBP26cjs.resolveBrush.call(void 0, brush));
2552
+ if (brush && !out.some((b) => b.id === brush.id)) out.push(_chunk677777GHcjs.resolveBrush.call(void 0, brush));
2553
2553
  }
2554
2554
  return out;
2555
2555
  }
@@ -2559,7 +2559,7 @@ function vectorBrushstrokeBrush(id) {
2559
2559
  function vectorBrushstrokeBrushOf(brush) {
2560
2560
  if (brush.spec) {
2561
2561
  const saved = admitted(brush.spec);
2562
- return saved && saved.id === brush.brushId ? _chunkBY5EBP26cjs.resolveBrush.call(void 0, saved) : null;
2562
+ return saved && saved.id === brush.brushId ? _chunk677777GHcjs.resolveBrush.call(void 0, saved) : null;
2563
2563
  }
2564
2564
  return vectorBrushstrokeBrush(brush.brushId);
2565
2565
  }
@@ -2567,15 +2567,15 @@ function vectorBrushstrokeBrushError(id, user = []) {
2567
2567
  if (vectorBrushstrokeBrush(id)) return null;
2568
2568
  const saved = user.find((b) => b.id === id);
2569
2569
  const ids = vectorBrushstrokeBrushes(user).map((b) => b.id);
2570
- const reasons = (b) => _chunkBY5EBP26cjs.checkBrush.call(void 0, b, _chunkBY5EBP26cjs.VECTOR_PROFILE).issues.filter((i) => i.severity === "error").map((i) => `${i.reason} ${i.fix}`).join(" ") || "it is not a dry dab brush.";
2570
+ const reasons = (b) => _chunk677777GHcjs.checkBrush.call(void 0, b, _chunk677777GHcjs.VECTOR_PROFILE).issues.filter((i) => i.severity === "error").map((i) => `${i.reason} ${i.fix}`).join(" ") || "it is not a dry dab brush.";
2571
2571
  if (saved) return admitted(saved) ? null : `Brush "${id}" (${saved.name}) can't paint a brushstroke: ${reasons(saved)} Use one of: ${ids.join(", ")}.`;
2572
- const preset = _chunkBY5EBP26cjs.BRUSH_PRESETS.find((b) => b.id === id);
2572
+ const preset = _chunk677777GHcjs.BRUSH_PRESETS.find((b) => b.id === id);
2573
2573
  if (preset) return `Brush "${id}" (${preset.name}) can't paint a brushstroke: ${reasons(preset)} Use one of: ${ids.join(", ")}.`;
2574
- return `Unknown brush "${id}". ${_chunkBY5EBP26cjs.closest.call(void 0, id, ids)}Use one of: ${ids.join(", ")} (vector.listBrushes lists them).`;
2574
+ return `Unknown brush "${id}". ${_chunk677777GHcjs.closest.call(void 0, id, ids)}Use one of: ${ids.join(", ")} (vector.listBrushes lists them).`;
2575
2575
  }
2576
2576
  function vectorBrushstrokeDefaultColour(id, user = [], scheme = "light") {
2577
- const brush = _nullishCoalesce(_chunkBY5EBP26cjs.BRUSH_PRESETS.find((b) => b.id === id), () => ( user.find((b) => b.id === id)));
2578
- return brush ? _chunkLRTR4ASZcjs.brushColourHex.call(void 0, _optionalChain([brush, 'access', _55 => _55.colour, 'optionalAccess', _56 => _56.default]), scheme) : null;
2577
+ const brush = _nullishCoalesce(_chunk677777GHcjs.BRUSH_PRESETS.find((b) => b.id === id), () => ( user.find((b) => b.id === id)));
2578
+ return brush ? _chunkJBZRVLXVcjs.brushColourHex.call(void 0, _optionalChain([brush, 'access', _55 => _55.colour, 'optionalAccess', _56 => _56.default]), scheme) : null;
2579
2579
  }
2580
2580
  function sanitizeVectorBrushstroke(value, user = []) {
2581
2581
  if (!value || typeof value !== "object") return null;
@@ -0,0 +1,77 @@
1
+ import {
2
+ PAINT_PROFILE
3
+ } from "./chunk-J4SGJCPW.js";
4
+ import {
5
+ brushColourHex
6
+ } from "./chunk-DVPQFMH6.js";
7
+ import {
8
+ isDualColor
9
+ } from "./chunk-VR6OGHU5.js";
10
+ import {
11
+ formatHex,
12
+ toSrgbGamut
13
+ } from "./chunk-JC2SHA4A.js";
14
+ import {
15
+ contrastRatio,
16
+ oklabToOklch,
17
+ oklabToRgb,
18
+ oklchToOklab,
19
+ parseColor,
20
+ relativeLuminance,
21
+ rgbToOklab
22
+ } from "./chunk-MHLU6GRJ.js";
23
+
24
+ // src/brushes/preview.ts
25
+ var BRUSH_PREVIEW_DARK_PAPER = "#141414";
26
+ var BRUSH_PREVIEW_MIN_CONTRAST = 3;
27
+ var BRUSH_PREVIEW_FALLBACKS = {
28
+ dry: { light: "#3f3f46", dark: "#e4e4e7" },
29
+ ink: { light: "#1e293b", dark: "#e2e8f0" },
30
+ paint: { light: "#1d4ed8", dark: "#93c5fd" },
31
+ spray: { light: "#0f766e", dark: "#5eead4" },
32
+ other: { light: "#334155", dark: "#cbd5e1" },
33
+ tools: { light: "#475569", dark: "#cbd5e1" }
34
+ };
35
+ function brushPreviewsOnDark(brush) {
36
+ return (brush.light?.amount ?? 0) > 0 && brush.tip?.blend !== "multiply";
37
+ }
38
+ var hexOf = (c) => brushColourHex(c, "light") ?? "#ffffff";
39
+ function brushPreviewStrength(brush) {
40
+ const opacity = brush.tip.opacity ?? 1;
41
+ const flow = brush.tip.flow ?? 1;
42
+ const grain = brush.behaviour?.grain ?? 0;
43
+ return Math.max(0.25, Math.min(1, 0.85 * opacity * (0.6 + 0.4 * flow) * (1 - 0.3 * grain)));
44
+ }
45
+ var over = (fg, bg, alpha) => ({ r: fg.r * alpha + bg.r * (1 - alpha), g: fg.g * alpha + bg.g * (1 - alpha), b: fg.b * alpha + bg.b * (1 - alpha), a: 1 });
46
+ function brushPreviewColours(brush, options = {}) {
47
+ const profile = options.profile ?? PAINT_PROFILE;
48
+ let background = profile.light === "full" && brushPreviewsOnDark(brush) ? BRUSH_PREVIEW_DARK_PAPER : hexOf(options.paper ?? "#ffffff");
49
+ if (!options.keepPaper && brush.tip.blend === "multiply" && relativeLuminance(parseColor(background)) < 0.18) background = "#ffffff";
50
+ const bg = parseColor(background);
51
+ const scheme = relativeLuminance(bg) < 0.18 ? "dark" : "light";
52
+ const own = brush.kind === "mark" ? brush.colour?.default : void 0;
53
+ const ownHex = typeof own === "string" || isDualColor(own) ? brushColourHex(own, scheme) : null;
54
+ if (ownHex && brush.tip.blend === "multiply" && (brush.light?.amount ?? 0) > 0 && scheme === "light") return { background, color: ownHex, scheme };
55
+ const group = brush.kind === "tool" ? "tools" : brush.medium ?? "other";
56
+ const color = ownHex ?? brushColourHex(BRUSH_PREVIEW_FALLBACKS[group] ?? BRUSH_PREVIEW_FALLBACKS.other, scheme);
57
+ const alpha = brushPreviewStrength(brush);
58
+ const reads = (c) => contrastRatio(over(c, bg, alpha), bg) >= BRUSH_PREVIEW_MIN_CONTRAST;
59
+ const fg = parseColor(color);
60
+ if (reads(fg)) return { background, color, scheme };
61
+ const lch = oklabToOklch(rgbToOklab(fg));
62
+ const step = scheme === "dark" ? 0.01 : -0.01;
63
+ for (let l = lch.l + step; l >= 0 && l <= 1; l += step) {
64
+ const hex = formatHex(toSrgbGamut(oklabToRgb(oklchToOklab({ ...lch, l }))));
65
+ if (reads(parseColor(hex))) return { background, color: hex, scheme };
66
+ }
67
+ return { background, color: scheme === "dark" ? "#ffffff" : "#000000", scheme };
68
+ }
69
+
70
+ export {
71
+ BRUSH_PREVIEW_DARK_PAPER,
72
+ BRUSH_PREVIEW_MIN_CONTRAST,
73
+ BRUSH_PREVIEW_FALLBACKS,
74
+ brushPreviewsOnDark,
75
+ brushPreviewStrength,
76
+ brushPreviewColours
77
+ };