@snowcone-app/canvas 0.15.0 → 0.17.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 (73) hide show
  1. package/dist/{CanvasStateV1-BQD8fCBU.js → CanvasStateV1-C6i6vU6p.js} +63 -63
  2. package/dist/{CanvasStateV1-BQD8fCBU.js.map → CanvasStateV1-C6i6vU6p.js.map} +1 -1
  3. package/dist/EditorCanvasImpl-DkgE5-C2.js +68 -0
  4. package/dist/EditorCanvasImpl-DkgE5-C2.js.map +1 -0
  5. package/dist/EditorContext-CyanYzo2.js +1131 -0
  6. package/dist/EditorContext-CyanYzo2.js.map +1 -0
  7. package/dist/{ImportManager-eotl7r5d.js → ElementFactory-C05JJkRp.js} +1510 -5121
  8. package/dist/ElementFactory-C05JJkRp.js.map +1 -0
  9. package/dist/{HybridHistoryManager-NL3zyEl4.js → HybridHistoryManager-Bht98XRv.js} +98 -98
  10. package/dist/{HybridHistoryManager-NL3zyEl4.js.map → HybridHistoryManager-Bht98XRv.js.map} +1 -1
  11. package/dist/ImportManager-kRYfIX-D.js +3617 -0
  12. package/dist/ImportManager-kRYfIX-D.js.map +1 -0
  13. package/dist/SnowconeCanvas-C3eZ9PP8.js +1047 -0
  14. package/dist/SnowconeCanvas-C3eZ9PP8.js.map +1 -0
  15. package/dist/ThemeContext-Rjz25x9X.js +75 -0
  16. package/dist/ThemeContext-Rjz25x9X.js.map +1 -0
  17. package/dist/UnifiedFontService-BAtqqkU4.js +1478 -0
  18. package/dist/UnifiedFontService-BAtqqkU4.js.map +1 -0
  19. package/dist/advanced.mjs +210 -207
  20. package/dist/advanced.mjs.map +1 -1
  21. package/dist/api/embed.d.ts +8 -4
  22. package/dist/api/testing.d.ts +1 -0
  23. package/dist/components/editor/EditorBuy.d.ts +49 -0
  24. package/dist/components/editor/EditorCanvas.d.ts +30 -0
  25. package/dist/components/editor/EditorCanvasImpl.d.ts +33 -0
  26. package/dist/components/editor/EditorPreview.d.ts +39 -0
  27. package/dist/components/editor/EditorRoot.d.ts +86 -0
  28. package/dist/components/editor/EditorTextField.d.ts +22 -0
  29. package/dist/components/editor/RootInternals.d.ts +77 -0
  30. package/dist/components/editor/designStateStore.d.ts +45 -0
  31. package/dist/components/editor/index.d.ts +23 -0
  32. package/dist/components/embed-realtime/RealtimeCanvas.d.ts +1 -1
  33. package/dist/components/embed-realtime/RealtimeEmbed.d.ts +5 -78
  34. package/dist/components/embed-realtime/RealtimeMockup.d.ts +5 -34
  35. package/dist/components/embed-realtime/context.d.ts +12 -2
  36. package/dist/components/embed-realtime/validateEmbed.d.ts +17 -3
  37. package/dist/contexts/EditorContext.d.ts +1 -0
  38. package/dist/design/design-builder.d.ts +81 -6
  39. package/dist/editorError-DMENTZ-3.js +19 -0
  40. package/dist/editorError-DMENTZ-3.js.map +1 -0
  41. package/dist/editorErrors-DbIEtCTt.js +29 -0
  42. package/dist/editorErrors-DbIEtCTt.js.map +1 -0
  43. package/dist/embed-Bdj4PKUA.js +737 -0
  44. package/dist/embed-Bdj4PKUA.js.map +1 -0
  45. package/dist/embed.mjs +38 -230
  46. package/dist/embed.mjs.map +1 -1
  47. package/dist/errors/editorError.d.ts +57 -0
  48. package/dist/iconify-D6eVIEy4.js +1089 -0
  49. package/dist/iconify-D6eVIEy4.js.map +1 -0
  50. package/dist/index.mjs +48 -46
  51. package/dist/index.mjs.map +1 -1
  52. package/dist/internals.mjs +105 -104
  53. package/dist/internals.mjs.map +1 -1
  54. package/dist/rendering/PieceGuideRenderer.d.ts +2 -16
  55. package/dist/template-fields-GOM4MNfq.js +643 -0
  56. package/dist/template-fields-GOM4MNfq.js.map +1 -0
  57. package/dist/testing/editorErrors.d.ts +30 -0
  58. package/dist/testing.mjs +28 -23
  59. package/dist/testing.mjs.map +1 -1
  60. package/dist/{usePieceGuideBundle-Cyl695jv.js → usePieceGuideBundle-CGERAQJl.js} +2 -2
  61. package/dist/{usePieceGuideBundle-Cyl695jv.js.map → usePieceGuideBundle-CGERAQJl.js.map} +1 -1
  62. package/dist/utils/inkLuminance.d.ts +38 -0
  63. package/dist/validation-DEd6EOCP.js +19947 -0
  64. package/dist/validation-DEd6EOCP.js.map +1 -0
  65. package/dist/workers/export-worker.bundle.string.d.ts +1 -1
  66. package/package.json +9 -4
  67. package/dist/ImportManager-eotl7r5d.js.map +0 -1
  68. package/dist/ThemeContext-Cl1JPVLZ.js +0 -1158
  69. package/dist/ThemeContext-Cl1JPVLZ.js.map +0 -1
  70. package/dist/template-fields-coO73lV3.js +0 -1632
  71. package/dist/template-fields-coO73lV3.js.map +0 -1
  72. package/dist/validation-BahKiJWj.js +0 -22973
  73. package/dist/validation-BahKiJWj.js.map +0 -1
@@ -1,8 +1,9 @@
1
- import { j as w, A as b, C as I, q as R, m as W, I as A, k as E, R as H, S as O, T as F, W as L, s as z, t as X, u as B, v as K, w as Y, x as J, y as _, z as j, B as q, F as N } from "./ImportManager-eotl7r5d.js";
2
- import { ab as p } from "./HybridHistoryManager-NL3zyEl4.js";
3
- import { ac as G, ad as U, ae as m, af as Q, a1 as Z, ag as $, ah as x, ai as D, aj as rr, ak as or, al as sr, am as ar, an as ir, ao as er, ap as nr, aq as tr, ar as hr, as as dr, at as cr, c as fr, au as pr, av as gr, aw as lr, ax as ur, ay as kr, az as Tr, aA as yr, aB as Mr, aC as vr, aD as Cr, aE as Sr, aF as Pr, aG as wr, aH as br, aI as Ir, aJ as Rr, aK as Wr } from "./HybridHistoryManager-NL3zyEl4.js";
4
- import { A as Er, e as Hr, C as Or, S as Fr } from "./CanvasStateV1-BQD8fCBU.js";
5
- function M(r, o) {
1
+ import { A as b, e as w, C as I, I as R, f as W, R as A, S as E, T as H } from "./ImportManager-kRYfIX-D.js";
2
+ import { D as p } from "./HybridHistoryManager-Bht98XRv.js";
3
+ import { E as F, H as L, J as X, K, L as Y, M as z, N as _, O as B, Q as J, U as N, W as V, V as U, X as Q, Y as Z, Z as $, _ as j, $ as q, a0 as G, a1 as m, c as x, a2 as D, a3 as rr, a4 as or, a5 as sr, a6 as ir, a7 as ar, a8 as er, a9 as nr, aa as tr, ab as hr, ac as dr, ad as cr, ae as fr, af as pr, ag as gr, ah as lr, ai as ur } from "./HybridHistoryManager-Bht98XRv.js";
4
+ import { D as kr, E as Mr, W as yr, c as Cr, a as vr, b as Sr, g as Pr, i as br, r as wr, d as Ir, e as Rr, t as Wr, u as Ar } from "./ElementFactory-C05JJkRp.js";
5
+ import { A as Hr, e as Or, C as Fr, S as Lr } from "./CanvasStateV1-C6i6vU6p.js";
6
+ function y(r, o) {
6
7
  return !r.needsCropPixelConversion || r.cropWidth === void 0 ? r : {
7
8
  ...r,
8
9
  cropX: (r.cropX ?? 0) * o.width,
@@ -12,19 +13,19 @@ function M(r, o) {
12
13
  needsCropPixelConversion: !1
13
14
  };
14
15
  }
15
- function v(r, o, c) {
16
+ function C(r, o, c) {
16
17
  var e, n;
17
18
  r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180);
18
- let i = 1, h = 1;
19
- if (o.flipHorizontal && (i = -1), o.flipVertical && (h = -1), (i !== 1 || h !== 1) && r.scale(i, h), o.opacity !== void 0 && o.opacity !== 1 && (r.globalAlpha = o.opacity), o.borderRadius && o.borderRadius > 0) {
20
- const a = Math.min(
19
+ let a = 1, h = 1;
20
+ if (o.flipHorizontal && (a = -1), o.flipVertical && (h = -1), (a !== 1 || h !== 1) && r.scale(a, h), o.opacity !== void 0 && o.opacity !== 1 && (r.globalAlpha = o.opacity), o.borderRadius && o.borderRadius > 0) {
21
+ const i = Math.min(
21
22
  o.borderRadius / 100 * Math.min(o.width, o.height),
22
23
  o.width / 2,
23
24
  o.height / 2
24
25
  );
25
26
  r.beginPath();
26
27
  const s = -o.width / 2, t = -o.height / 2, d = o.width, f = o.height;
27
- r.moveTo(s + a, t), r.lineTo(s + d - a, t), r.arcTo(s + d, t, s + d, t + a, a), r.lineTo(s + d, t + f - a), r.arcTo(s + d, t + f, s + d - a, t + f, a), r.lineTo(s + a, t + f), r.arcTo(s, t + f, s, t + f - a, a), r.lineTo(s, t + a), r.arcTo(s, t, s + a, t, a), r.closePath(), r.clip();
28
+ r.moveTo(s + i, t), r.lineTo(s + d - i, t), r.arcTo(s + d, t, s + d, t + i, i), r.lineTo(s + d, t + f - i), r.arcTo(s + d, t + f, s + d - i, t + f, i), r.lineTo(s + i, t + f), r.arcTo(s, t + f, s, t + f - i, i), r.lineTo(s, t + i), r.arcTo(s, t, s + i, t, i), r.closePath(), r.clip();
28
29
  }
29
30
  if (o.cropX !== void 0 && o.cropWidth !== void 0 ? r.drawImage(
30
31
  c,
@@ -37,7 +38,7 @@ function v(r, o, c) {
37
38
  o.width,
38
39
  o.height
39
40
  ) : r.drawImage(c, -o.width / 2, -o.height / 2, o.width, o.height), r.restore(), (e = o.stroke) != null && e.enabled) {
40
- const a = ((n = o.knockoutParts) == null ? void 0 : n.stroke) === !0, s = {
41
+ const i = ((n = o.knockoutParts) == null ? void 0 : n.stroke) === !0, s = {
41
42
  x: o.x,
42
43
  y: o.y,
43
44
  rotation: o.rotation,
@@ -50,7 +51,7 @@ function v(r, o, c) {
50
51
  borderRadius: o.borderRadius || 0
51
52
  }
52
53
  };
53
- if (a) {
54
+ if (i) {
54
55
  const t = r.canvas;
55
56
  let d;
56
57
  if (typeof OffscreenCanvas < "u")
@@ -71,20 +72,20 @@ function v(r, o, c) {
71
72
  p(r, s);
72
73
  }
73
74
  }
74
- function k(r, o) {
75
+ function T(r, o) {
75
76
  if (typeof OffscreenCanvas < "u")
76
77
  return new OffscreenCanvas(r, o);
77
78
  const c = document.createElement("canvas");
78
79
  return c.width = r, c.height = o, c;
79
80
  }
80
- function C(r, o) {
81
+ function v(r, o) {
81
82
  var e;
82
- const c = o.opacity ?? 1, i = !!((e = o.stroke) != null && e.enabled);
83
- c < 1 && i ? T(r, o, c) : g(r, o, c);
83
+ const c = o.opacity ?? 1, a = !!((e = o.stroke) != null && e.enabled);
84
+ c < 1 && a ? k(r, o, c) : g(r, o, c);
84
85
  }
85
- function T(r, o, c) {
86
+ function k(r, o, c) {
86
87
  var f;
87
- const i = o.transformData, e = (((f = o.stroke) == null ? void 0 : f.width) || 2) + 2, n = Math.ceil(i.width + e * 2), a = Math.ceil(i.height + e * 2), s = k(n, a), t = s.getContext("2d");
88
+ const a = o.transformData, e = (((f = o.stroke) == null ? void 0 : f.width) || 2) + 2, n = Math.ceil(a.width + e * 2), i = Math.ceil(a.height + e * 2), s = T(n, i), t = s.getContext("2d");
88
89
  if (!t) {
89
90
  g(r, o, c);
90
91
  return;
@@ -92,138 +93,138 @@ function T(r, o, c) {
92
93
  const d = {
93
94
  ...o,
94
95
  x: n / 2,
95
- y: a / 2
96
+ y: i / 2
96
97
  };
97
- g(t, d, 1), r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180), r.globalAlpha = c, r.drawImage(s, -n / 2, -a / 2), r.restore();
98
+ g(t, d, 1), r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180), r.globalAlpha = c, r.drawImage(s, -n / 2, -i / 2), r.restore();
98
99
  }
99
100
  function g(r, o, c) {
100
101
  var e;
101
- const i = o.transformData, h = i.fillOpacity ?? 1;
102
- if (r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180), r.globalAlpha = c * h, r.fillStyle = i.fillColor || "#3b82f6", r.beginPath(), u(r, i), r.fill(), r.restore(), (e = o.stroke) != null && e.enabled) {
102
+ const a = o.transformData, h = a.fillOpacity ?? 1;
103
+ if (r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180), r.globalAlpha = c * h, r.fillStyle = a.fillColor || "#3b82f6", r.beginPath(), u(r, a), r.fill(), r.restore(), (e = o.stroke) != null && e.enabled) {
103
104
  r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180);
104
105
  const n = o.stroke;
105
- r.globalAlpha = c * (n.opacity ?? 1), r.strokeStyle = n.color || "#000000", r.lineWidth = n.width || 2, r.lineCap = n.lineCap || "round", r.lineJoin = n.lineJoin || "round", r.beginPath(), u(r, i), r.stroke(), r.restore();
106
+ r.globalAlpha = c * (n.opacity ?? 1), r.strokeStyle = n.color || "#000000", r.lineWidth = n.width || 2, r.lineCap = n.lineCap || "round", r.lineJoin = n.lineJoin || "round", r.beginPath(), u(r, a), r.stroke(), r.restore();
106
107
  }
107
108
  }
108
109
  function u(r, o) {
109
- const { shapeType: c, width: i, height: h } = o;
110
+ const { shapeType: c, width: a, height: h } = o;
110
111
  switch (c) {
111
112
  case "rectangle": {
112
- const e = o.borderRadius || 0, n = -i / 2, a = -h / 2;
113
+ const e = o.borderRadius || 0, n = -a / 2, i = -h / 2;
113
114
  if (e > 0) {
114
- const s = Math.min(e / 100 * Math.min(i, h), i / 2, h / 2);
115
- r.roundRect(n, a, i, h, s);
115
+ const s = Math.min(e / 100 * Math.min(a, h), a / 2, h / 2);
116
+ r.roundRect(n, i, a, h, s);
116
117
  } else
117
- r.rect(n, a, i, h);
118
+ r.rect(n, i, a, h);
118
119
  break;
119
120
  }
120
121
  case "circle": {
121
- const e = Math.min(i, h) / 2;
122
+ const e = Math.min(a, h) / 2;
122
123
  r.arc(0, 0, e, 0, Math.PI * 2);
123
124
  break;
124
125
  }
125
126
  case "ellipse": {
126
- r.ellipse(0, 0, i / 2, h / 2, 0, 0, Math.PI * 2);
127
+ r.ellipse(0, 0, a / 2, h / 2, 0, 0, Math.PI * 2);
127
128
  break;
128
129
  }
129
130
  case "triangle": {
130
- const e = i / 2, n = h / 2;
131
+ const e = a / 2, n = h / 2;
131
132
  r.moveTo(0, -n), r.lineTo(e, n), r.lineTo(-e, n), r.closePath();
132
133
  break;
133
134
  }
134
135
  case "polygon": {
135
- const e = o.sides || 5, n = Math.min(i, h) / 2;
136
- for (let a = 0; a < e; a++) {
137
- const s = a * 2 * Math.PI / e - Math.PI / 2, t = n * Math.cos(s), d = n * Math.sin(s);
138
- a === 0 ? r.moveTo(t, d) : r.lineTo(t, d);
136
+ const e = o.sides || 5, n = Math.min(a, h) / 2;
137
+ for (let i = 0; i < e; i++) {
138
+ const s = i * 2 * Math.PI / e - Math.PI / 2, t = n * Math.cos(s), d = n * Math.sin(s);
139
+ i === 0 ? r.moveTo(t, d) : r.lineTo(t, d);
139
140
  }
140
141
  r.closePath();
141
142
  break;
142
143
  }
143
144
  case "star": {
144
- const e = o.points || 5, n = Math.min(i, h) / 2, a = n * (o.innerRadius || 0.4);
145
+ const e = o.points || 5, n = Math.min(a, h) / 2, i = n * (o.innerRadius || 0.4);
145
146
  for (let s = 0; s < e * 2; s++) {
146
- const t = s * Math.PI / e - Math.PI / 2, d = s % 2 === 0 ? n : a, f = d * Math.cos(t), l = d * Math.sin(t);
147
+ const t = s * Math.PI / e - Math.PI / 2, d = s % 2 === 0 ? n : i, f = d * Math.cos(t), l = d * Math.sin(t);
147
148
  s === 0 ? r.moveTo(f, l) : r.lineTo(f, l);
148
149
  }
149
150
  r.closePath();
150
151
  break;
151
152
  }
152
153
  case "line": {
153
- const e = i / 2, n = h / 2;
154
- r.rect(-e, -n, i, h);
154
+ const e = a / 2, n = h / 2;
155
+ r.rect(-e, -n, a, h);
155
156
  break;
156
157
  }
157
158
  default:
158
- r.rect(-i / 2, -h / 2, i, h);
159
+ r.rect(-a / 2, -h / 2, a, h);
159
160
  }
160
161
  }
161
162
  export {
162
- w as AlignmentSnapSystem,
163
- Er as AnyElementConfigSchema,
164
- Hr as AnyTransformDataSchema,
165
- G as ArchTransform,
166
- U as ArtboardManager,
167
- b as ArtboardRenderer,
168
- m as AscendTransform,
163
+ b as AlignmentSnapSystem,
164
+ Hr as AnyElementConfigSchema,
165
+ Or as AnyTransformDataSchema,
166
+ F as ArchTransform,
167
+ L as ArtboardManager,
168
+ w as ArtboardRenderer,
169
+ X as AscendTransform,
169
170
  I as CanvasRenderer,
170
- Or as CanvasStateV1Schema,
171
- Q as CircleTransform,
172
- Z as CustomTransform,
173
- R as DEFAULT_MAX_BITMAP_DIMENSION,
174
- $ as ElementStore,
175
- W as ExportManager,
176
- x as FlagTransform,
177
- D as HybridHistoryManager,
178
- A as ImportManager,
179
- E as InteractionStateMachine,
180
- rr as LeanTransform,
181
- or as LogLevel,
182
- H as ResizePipeline,
183
- Fr as SerializedArtboardSchema,
184
- O as SpacingSystem,
185
- F as TransformHandles,
186
- sr as WaveTransform,
187
- L as WorkerExportManager,
188
- ar as applySpaceLayoutRules,
189
- ir as applyStrokeStyle,
190
- er as buildFontString,
191
- nr as calculateFixedCornerPosition,
192
- tr as calculateResizeHandles,
193
- hr as calculateRotationHandlePosition,
194
- z as clearImageBitmapCache,
195
- X as clearMaskCache,
196
- B as clearRegisteredBitmapKeys,
197
- dr as createCirclePath,
198
- cr as createImagePath,
199
- fr as createLogger,
200
- pr as createRectPath,
201
- gr as createTextPath,
202
- lr as getFontMetrics,
203
- K as getSharedWorkerExportManager,
204
- ur as hitTestCircle,
205
- kr as hitTestRect,
206
- Y as invalidateMaskCache,
207
- Tr as logger,
208
- yr as measureTextWidth,
209
- J as removeFromImageBitmapCache,
210
- Mr as renderCustomTransform,
211
- v as renderImageElement,
171
+ Fr as CanvasStateV1Schema,
172
+ K as CircleTransform,
173
+ Y as CustomTransform,
174
+ kr as DEFAULT_MAX_BITMAP_DIMENSION,
175
+ z as ElementStore,
176
+ Mr as ExportManager,
177
+ _ as FlagTransform,
178
+ B as HybridHistoryManager,
179
+ R as ImportManager,
180
+ W as InteractionStateMachine,
181
+ J as LeanTransform,
182
+ N as LogLevel,
183
+ A as ResizePipeline,
184
+ Lr as SerializedArtboardSchema,
185
+ E as SpacingSystem,
186
+ H as TransformHandles,
187
+ V as WaveTransform,
188
+ yr as WorkerExportManager,
189
+ U as applySpaceLayoutRules,
190
+ Q as applyStrokeStyle,
191
+ Z as buildFontString,
192
+ $ as calculateFixedCornerPosition,
193
+ j as calculateResizeHandles,
194
+ q as calculateRotationHandlePosition,
195
+ Cr as clearImageBitmapCache,
196
+ vr as clearMaskCache,
197
+ Sr as clearRegisteredBitmapKeys,
198
+ G as createCirclePath,
199
+ m as createImagePath,
200
+ x as createLogger,
201
+ D as createRectPath,
202
+ rr as createTextPath,
203
+ or as getFontMetrics,
204
+ Pr as getSharedWorkerExportManager,
205
+ sr as hitTestCircle,
206
+ ir as hitTestRect,
207
+ br as invalidateMaskCache,
208
+ ar as logger,
209
+ er as measureTextWidth,
210
+ wr as removeFromImageBitmapCache,
211
+ nr as renderCustomTransform,
212
+ C as renderImageElement,
212
213
  p as renderImageStroke,
213
- vr as renderMultilineText,
214
- Cr as renderPathStroke,
215
- Sr as renderRichTextFillOnly,
216
- C as renderShapeElement,
217
- Pr as renderTextElement,
218
- wr as renderTextFillOnly,
219
- br as renderTextStroke,
220
- _ as renderWithKnockout,
221
- j as renderWithMasks,
222
- M as resolveServerCrop,
223
- Ir as splitRichTextIntoLines,
224
- q as terminateSharedWorkerExportManager,
225
- N as unregisterElementBitmaps,
226
- Rr as wrapRichTextSpans,
227
- Wr as wrapText
214
+ tr as renderMultilineText,
215
+ hr as renderPathStroke,
216
+ dr as renderRichTextFillOnly,
217
+ v as renderShapeElement,
218
+ cr as renderTextElement,
219
+ fr as renderTextFillOnly,
220
+ pr as renderTextStroke,
221
+ Ir as renderWithKnockout,
222
+ Rr as renderWithMasks,
223
+ y as resolveServerCrop,
224
+ gr as splitRichTextIntoLines,
225
+ Wr as terminateSharedWorkerExportManager,
226
+ Ar as unregisterElementBitmaps,
227
+ lr as wrapRichTextSpans,
228
+ ur as wrapText
228
229
  };
229
230
  //# sourceMappingURL=internals.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"internals.mjs","sources":["../src/rendering/image-renderer.ts","../src/rendering/shape-renderer.ts"],"sourcesContent":["/**\n * Image Renderer - Image element rendering with crop, flip, border radius, and stroke.\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n */\n\nimport type { ImageElementConfig } from '../types/index.js';\nimport { renderImageStroke } from './StrokeRenderer.js';\nimport type { RenderContext, SerializedImageElement } from './renderer-types.js';\n\n/**\n * Convert a server-render image element's crop rectangle from FRACTIONS (0–1)\n * to source pixels, using the fetched bitmap's real dimensions.\n *\n * The server-render serializers (`serializeStateForServer`,\n * `flattenImageElement`) store crop as fractions and stamp\n * `needsCropPixelConversion` because they have no bitmap at serialize time. The\n * export worker holds the bitmap and calls this right before drawing. Without\n * it, `drawImage` reads e.g. `cropWidth=1` as a 1px source rect and stretches a\n * single corner pixel across the whole element — the layer renders as a solid\n * black/transparent block. Mirrors the client-side conversion in\n * `element-serializer` (which runs at serialize time because the client DOES\n * have the bitmap). No-op unless the flag is set and a crop is present, so the\n * already-pixel client path is untouched and the conversion can't run twice.\n */\nexport function resolveServerCrop(\n el: SerializedImageElement,\n bitmap: { width: number; height: number }\n): SerializedImageElement {\n if (!el.needsCropPixelConversion || el.cropWidth === undefined) return el;\n return {\n ...el,\n cropX: (el.cropX ?? 0) * bitmap.width,\n cropY: (el.cropY ?? 0) * bitmap.height,\n cropWidth: el.cropWidth * bitmap.width,\n cropHeight: (el.cropHeight ?? 1) * bitmap.height,\n needsCropPixelConversion: false,\n };\n}\n\n/**\n * Render an image element using ImageBitmap\n * Works in both main thread and worker\n */\nexport function renderImageElement(\n ctx: RenderContext,\n elementData: SerializedImageElement,\n imageBitmap: ImageBitmap\n): void {\n ctx.save();\n\n // Translate to element position\n ctx.translate(elementData.x, elementData.y);\n\n // Apply rotation (negative for clockwise)\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Apply flip transformations\n let scaleX = 1;\n let scaleY = 1;\n if (elementData.flipHorizontal) scaleX = -1;\n if (elementData.flipVertical) scaleY = -1;\n if (scaleX !== 1 || scaleY !== 1) {\n ctx.scale(scaleX, scaleY);\n }\n\n // Apply opacity if specified\n if (elementData.opacity !== undefined && elementData.opacity !== 1) {\n ctx.globalAlpha = elementData.opacity;\n }\n\n // Apply border radius if specified (borderRadius is stored as percentage 0-100)\n if (elementData.borderRadius && elementData.borderRadius > 0) {\n const radius = Math.min(\n (elementData.borderRadius / 100) * Math.min(elementData.width, elementData.height),\n elementData.width / 2,\n elementData.height / 2\n );\n\n // Create clipping path for rounded corners\n ctx.beginPath();\n const x = -elementData.width / 2;\n const y = -elementData.height / 2;\n const w = elementData.width;\n const h = elementData.height;\n\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + w - radius, y);\n ctx.arcTo(x + w, y, x + w, y + radius, radius);\n ctx.lineTo(x + w, y + h - radius);\n ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius);\n ctx.lineTo(x + radius, y + h);\n ctx.arcTo(x, y + h, x, y + h - radius, radius);\n ctx.lineTo(x, y + radius);\n ctx.arcTo(x, y, x + radius, y, radius);\n ctx.closePath();\n ctx.clip();\n }\n\n // Draw the image\n if (elementData.cropX !== undefined && elementData.cropWidth !== undefined) {\n // Draw with crop\n ctx.drawImage(\n imageBitmap,\n elementData.cropX,\n elementData.cropY || 0,\n elementData.cropWidth,\n elementData.cropHeight || imageBitmap.height,\n -elementData.width / 2,\n -elementData.height / 2,\n elementData.width,\n elementData.height\n );\n } else {\n // Draw without crop (centered)\n ctx.drawImage(imageBitmap, -elementData.width / 2, -elementData.height / 2, elementData.width, elementData.height);\n }\n\n ctx.restore();\n\n // Render stroke if enabled (after restore to apply fresh transforms)\n if (elementData.stroke?.enabled) {\n const hasKnockoutStroke = elementData.knockoutParts?.stroke === true;\n\n const imageConfig: ImageElementConfig = {\n transformType: 'image',\n x: elementData.x,\n y: elementData.y,\n rotation: elementData.rotation,\n stroke: elementData.stroke,\n knockoutParts: elementData.knockoutParts,\n transformData: {\n type: 'image',\n width: elementData.width,\n height: elementData.height,\n borderRadius: elementData.borderRadius || 0,\n },\n };\n\n if (hasKnockoutStroke) {\n // For knockout stroke, use offscreen canvas approach\n const canvas = ctx.canvas;\n let offscreen: HTMLCanvasElement | OffscreenCanvas;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n offscreen = new OffscreenCanvas(canvas.width, canvas.height);\n } else if (typeof document !== 'undefined') {\n offscreen = document.createElement('canvas');\n offscreen.width = canvas.width;\n offscreen.height = canvas.height;\n } else {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n // Render the stroke to the offscreen canvas with knockout flag\n renderImageStroke(offCtx, imageConfig, { isKnockout: true });\n\n // Composite with destination-out\n ctx.save();\n ctx.globalCompositeOperation = 'destination-out';\n ctx.drawImage(offscreen as CanvasImageSource, 0, 0);\n ctx.restore();\n } else {\n // Normal stroke\n renderImageStroke(ctx, imageConfig);\n }\n }\n}\n","/**\n * Shape Renderer - Shape element rendering (rectangle, circle, ellipse, triangle, etc.)\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n *\n * Opacity strategy: When a shape has both element-level opacity AND a stroke,\n * we render fill+stroke at full opacity on a temporary canvas, then composite\n * the result at the element's opacity. This prevents fill/stroke overlap from\n * compounding (e.g., 50% fill + 50% stroke overlap ≠ 75% opaque).\n */\n\nimport type { RenderContext, SerializedShapeElement } from './renderer-types.js';\n\ntype CanvasLike = HTMLCanvasElement | OffscreenCanvas;\n\nfunction createTempCanvas(width: number, height: number): CanvasLike {\n if (typeof OffscreenCanvas !== 'undefined') {\n return new OffscreenCanvas(width, height);\n }\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\n/**\n * Render a shape element\n * Works in both main thread and worker\n */\nexport function renderShapeElement(ctx: RenderContext, elementData: SerializedShapeElement): void {\n const elementOpacity = elementData.opacity ?? 1;\n const hasStroke = !!elementData.stroke?.enabled;\n const needsOffscreen = elementOpacity < 1 && hasStroke;\n\n if (needsOffscreen) {\n // Render fill+stroke at full opacity on a temp canvas, then composite\n renderShapeWithOffscreen(ctx, elementData, elementOpacity);\n } else {\n // No compounding risk — render directly\n renderShapeDirect(ctx, elementData, elementOpacity);\n }\n}\n\n/**\n * Render shape via temporary canvas to avoid fill/stroke opacity compounding.\n */\nfunction renderShapeWithOffscreen(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const td = elementData.transformData;\n const strokeWidth = elementData.stroke?.width || 2;\n // Pad temp canvas to fit the stroke (strokes extend beyond the shape bounds)\n const padding = strokeWidth + 2;\n const offW = Math.ceil(td.width + padding * 2);\n const offH = Math.ceil(td.height + padding * 2);\n\n const offCanvas = createTempCanvas(offW, offH);\n const offCtx = offCanvas.getContext('2d') as RenderContext;\n if (!offCtx) {\n // Fallback to direct render\n renderShapeDirect(ctx, elementData, elementOpacity);\n return;\n }\n\n // Render at center of temp canvas with full opacity (elementOpacity = 1)\n const tempData: SerializedShapeElement = {\n ...elementData,\n x: offW / 2,\n y: offH / 2,\n opacity: 1,\n };\n renderShapeDirect(offCtx, tempData, 1);\n\n // Composite temp canvas onto main canvas at element opacity\n ctx.save();\n\n // Position: elementData.(x,y) is the shape center, temp canvas center is (offW/2, offH/2)\n // We need to account for rotation around the element center\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n ctx.globalAlpha = elementOpacity;\n ctx.drawImage(offCanvas, -offW / 2, -offH / 2);\n ctx.restore();\n}\n\n/**\n * Render shape directly onto ctx (no offscreen). Used when there's no\n * compounding risk, or as the inner render for the offscreen path.\n */\nfunction renderShapeDirect(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const transformData = elementData.transformData;\n const fillOpacity = transformData.fillOpacity ?? 1;\n\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Fill\n ctx.globalAlpha = elementOpacity * fillOpacity;\n ctx.fillStyle = transformData.fillColor || '#3b82f6';\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.fill();\n ctx.restore();\n\n // Stroke\n if (elementData.stroke?.enabled) {\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n const stroke = elementData.stroke;\n ctx.globalAlpha = elementOpacity * (stroke.opacity ?? 1);\n ctx.strokeStyle = stroke.color || '#000000';\n ctx.lineWidth = stroke.width || 2;\n ctx.lineCap = stroke.lineCap || 'round';\n ctx.lineJoin = stroke.lineJoin || 'round';\n\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.stroke();\n ctx.restore();\n }\n}\n\n/**\n * Trace the shape path (without fill/stroke) — reusable for both fill and stroke passes.\n */\nfunction traceShapePath(\n ctx: RenderContext,\n transformData: SerializedShapeElement['transformData']\n): void {\n const { shapeType, width, height } = transformData;\n\n switch (shapeType) {\n case 'rectangle': {\n const borderRadius = transformData.borderRadius || 0;\n const x = -width / 2;\n const y = -height / 2;\n\n if (borderRadius > 0) {\n const radius = Math.min((borderRadius / 100) * Math.min(width, height), width / 2, height / 2);\n ctx.roundRect(x, y, width, height, radius);\n } else {\n ctx.rect(x, y, width, height);\n }\n break;\n }\n\n case 'circle': {\n const radius = Math.min(width, height) / 2;\n ctx.arc(0, 0, radius, 0, Math.PI * 2);\n break;\n }\n\n case 'ellipse': {\n ctx.ellipse(0, 0, width / 2, height / 2, 0, 0, Math.PI * 2);\n break;\n }\n\n case 'triangle': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.moveTo(0, -halfHeight);\n ctx.lineTo(halfWidth, halfHeight);\n ctx.lineTo(-halfWidth, halfHeight);\n ctx.closePath();\n break;\n }\n\n case 'polygon': {\n const sides = transformData.sides || 5;\n const radius = Math.min(width, height) / 2;\n for (let i = 0; i < sides; i++) {\n const angle = (i * 2 * Math.PI) / sides - Math.PI / 2;\n const px = radius * Math.cos(angle);\n const py = radius * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'star': {\n const points = transformData.points || 5;\n const outerRadius = Math.min(width, height) / 2;\n const innerRadius = outerRadius * (transformData.innerRadius || 0.4);\n for (let i = 0; i < points * 2; i++) {\n const angle = (i * Math.PI) / points - Math.PI / 2;\n const r = i % 2 === 0 ? outerRadius : innerRadius;\n const px = r * Math.cos(angle);\n const py = r * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'line': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.rect(-halfWidth, -halfHeight, width, height);\n break;\n }\n\n default:\n ctx.rect(-width / 2, -height / 2, width, height);\n }\n}\n"],"names":["resolveServerCrop","el","bitmap","renderImageElement","ctx","elementData","imageBitmap","scaleX","scaleY","radius","x","y","w","h","_a","hasKnockoutStroke","_b","imageConfig","canvas","offscreen","renderImageStroke","offCtx","createTempCanvas","width","height","renderShapeElement","elementOpacity","hasStroke","renderShapeWithOffscreen","renderShapeDirect","td","padding","offW","offH","offCanvas","tempData","transformData","fillOpacity","traceShapePath","stroke","shapeType","borderRadius","halfWidth","halfHeight","sides","i","angle","px","py","points","outerRadius","innerRadius","r"],"mappings":"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"}
1
+ {"version":3,"file":"internals.mjs","sources":["../src/rendering/image-renderer.ts","../src/rendering/shape-renderer.ts"],"sourcesContent":["/**\n * Image Renderer - Image element rendering with crop, flip, border radius, and stroke.\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n */\n\nimport type { ImageElementConfig } from '../types/index.js';\nimport { renderImageStroke } from './StrokeRenderer.js';\nimport type { RenderContext, SerializedImageElement } from './renderer-types.js';\n\n/**\n * Convert a server-render image element's crop rectangle from FRACTIONS (0–1)\n * to source pixels, using the fetched bitmap's real dimensions.\n *\n * The server-render serializers (`serializeStateForServer`,\n * `flattenImageElement`) store crop as fractions and stamp\n * `needsCropPixelConversion` because they have no bitmap at serialize time. The\n * export worker holds the bitmap and calls this right before drawing. Without\n * it, `drawImage` reads e.g. `cropWidth=1` as a 1px source rect and stretches a\n * single corner pixel across the whole element — the layer renders as a solid\n * black/transparent block. Mirrors the client-side conversion in\n * `element-serializer` (which runs at serialize time because the client DOES\n * have the bitmap). No-op unless the flag is set and a crop is present, so the\n * already-pixel client path is untouched and the conversion can't run twice.\n */\nexport function resolveServerCrop(\n el: SerializedImageElement,\n bitmap: { width: number; height: number }\n): SerializedImageElement {\n if (!el.needsCropPixelConversion || el.cropWidth === undefined) return el;\n return {\n ...el,\n cropX: (el.cropX ?? 0) * bitmap.width,\n cropY: (el.cropY ?? 0) * bitmap.height,\n cropWidth: el.cropWidth * bitmap.width,\n cropHeight: (el.cropHeight ?? 1) * bitmap.height,\n needsCropPixelConversion: false,\n };\n}\n\n/**\n * Render an image element using ImageBitmap\n * Works in both main thread and worker\n */\nexport function renderImageElement(\n ctx: RenderContext,\n elementData: SerializedImageElement,\n imageBitmap: ImageBitmap\n): void {\n ctx.save();\n\n // Translate to element position\n ctx.translate(elementData.x, elementData.y);\n\n // Apply rotation (negative for clockwise)\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Apply flip transformations\n let scaleX = 1;\n let scaleY = 1;\n if (elementData.flipHorizontal) scaleX = -1;\n if (elementData.flipVertical) scaleY = -1;\n if (scaleX !== 1 || scaleY !== 1) {\n ctx.scale(scaleX, scaleY);\n }\n\n // Apply opacity if specified\n if (elementData.opacity !== undefined && elementData.opacity !== 1) {\n ctx.globalAlpha = elementData.opacity;\n }\n\n // Apply border radius if specified (borderRadius is stored as percentage 0-100)\n if (elementData.borderRadius && elementData.borderRadius > 0) {\n const radius = Math.min(\n (elementData.borderRadius / 100) * Math.min(elementData.width, elementData.height),\n elementData.width / 2,\n elementData.height / 2\n );\n\n // Create clipping path for rounded corners\n ctx.beginPath();\n const x = -elementData.width / 2;\n const y = -elementData.height / 2;\n const w = elementData.width;\n const h = elementData.height;\n\n ctx.moveTo(x + radius, y);\n ctx.lineTo(x + w - radius, y);\n ctx.arcTo(x + w, y, x + w, y + radius, radius);\n ctx.lineTo(x + w, y + h - radius);\n ctx.arcTo(x + w, y + h, x + w - radius, y + h, radius);\n ctx.lineTo(x + radius, y + h);\n ctx.arcTo(x, y + h, x, y + h - radius, radius);\n ctx.lineTo(x, y + radius);\n ctx.arcTo(x, y, x + radius, y, radius);\n ctx.closePath();\n ctx.clip();\n }\n\n // Draw the image\n if (elementData.cropX !== undefined && elementData.cropWidth !== undefined) {\n // Draw with crop\n ctx.drawImage(\n imageBitmap,\n elementData.cropX,\n elementData.cropY || 0,\n elementData.cropWidth,\n elementData.cropHeight || imageBitmap.height,\n -elementData.width / 2,\n -elementData.height / 2,\n elementData.width,\n elementData.height\n );\n } else {\n // Draw without crop (centered)\n ctx.drawImage(imageBitmap, -elementData.width / 2, -elementData.height / 2, elementData.width, elementData.height);\n }\n\n ctx.restore();\n\n // Render stroke if enabled (after restore to apply fresh transforms)\n if (elementData.stroke?.enabled) {\n const hasKnockoutStroke = elementData.knockoutParts?.stroke === true;\n\n const imageConfig: ImageElementConfig = {\n transformType: 'image',\n x: elementData.x,\n y: elementData.y,\n rotation: elementData.rotation,\n stroke: elementData.stroke,\n knockoutParts: elementData.knockoutParts,\n transformData: {\n type: 'image',\n width: elementData.width,\n height: elementData.height,\n borderRadius: elementData.borderRadius || 0,\n },\n };\n\n if (hasKnockoutStroke) {\n // For knockout stroke, use offscreen canvas approach\n const canvas = ctx.canvas;\n let offscreen: HTMLCanvasElement | OffscreenCanvas;\n\n if (typeof OffscreenCanvas !== 'undefined') {\n offscreen = new OffscreenCanvas(canvas.width, canvas.height);\n } else if (typeof document !== 'undefined') {\n offscreen = document.createElement('canvas');\n offscreen.width = canvas.width;\n offscreen.height = canvas.height;\n } else {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) {\n renderImageStroke(ctx, imageConfig);\n return;\n }\n\n // Render the stroke to the offscreen canvas with knockout flag\n renderImageStroke(offCtx, imageConfig, { isKnockout: true });\n\n // Composite with destination-out\n ctx.save();\n ctx.globalCompositeOperation = 'destination-out';\n ctx.drawImage(offscreen as CanvasImageSource, 0, 0);\n ctx.restore();\n } else {\n // Normal stroke\n renderImageStroke(ctx, imageConfig);\n }\n }\n}\n","/**\n * Shape Renderer - Shape element rendering (rectangle, circle, ellipse, triangle, etc.)\n *\n * Works in both main thread and Web Worker (via OffscreenCanvas).\n *\n * Opacity strategy: When a shape has both element-level opacity AND a stroke,\n * we render fill+stroke at full opacity on a temporary canvas, then composite\n * the result at the element's opacity. This prevents fill/stroke overlap from\n * compounding (e.g., 50% fill + 50% stroke overlap ≠ 75% opaque).\n */\n\nimport type { RenderContext, SerializedShapeElement } from './renderer-types.js';\n\ntype CanvasLike = HTMLCanvasElement | OffscreenCanvas;\n\nfunction createTempCanvas(width: number, height: number): CanvasLike {\n if (typeof OffscreenCanvas !== 'undefined') {\n return new OffscreenCanvas(width, height);\n }\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\n/**\n * Render a shape element\n * Works in both main thread and worker\n */\nexport function renderShapeElement(ctx: RenderContext, elementData: SerializedShapeElement): void {\n const elementOpacity = elementData.opacity ?? 1;\n const hasStroke = !!elementData.stroke?.enabled;\n const needsOffscreen = elementOpacity < 1 && hasStroke;\n\n if (needsOffscreen) {\n // Render fill+stroke at full opacity on a temp canvas, then composite\n renderShapeWithOffscreen(ctx, elementData, elementOpacity);\n } else {\n // No compounding risk — render directly\n renderShapeDirect(ctx, elementData, elementOpacity);\n }\n}\n\n/**\n * Render shape via temporary canvas to avoid fill/stroke opacity compounding.\n */\nfunction renderShapeWithOffscreen(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const td = elementData.transformData;\n const strokeWidth = elementData.stroke?.width || 2;\n // Pad temp canvas to fit the stroke (strokes extend beyond the shape bounds)\n const padding = strokeWidth + 2;\n const offW = Math.ceil(td.width + padding * 2);\n const offH = Math.ceil(td.height + padding * 2);\n\n const offCanvas = createTempCanvas(offW, offH);\n const offCtx = offCanvas.getContext('2d') as RenderContext;\n if (!offCtx) {\n // Fallback to direct render\n renderShapeDirect(ctx, elementData, elementOpacity);\n return;\n }\n\n // Render at center of temp canvas with full opacity (elementOpacity = 1)\n const tempData: SerializedShapeElement = {\n ...elementData,\n x: offW / 2,\n y: offH / 2,\n opacity: 1,\n };\n renderShapeDirect(offCtx, tempData, 1);\n\n // Composite temp canvas onto main canvas at element opacity\n ctx.save();\n\n // Position: elementData.(x,y) is the shape center, temp canvas center is (offW/2, offH/2)\n // We need to account for rotation around the element center\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n ctx.globalAlpha = elementOpacity;\n ctx.drawImage(offCanvas, -offW / 2, -offH / 2);\n ctx.restore();\n}\n\n/**\n * Render shape directly onto ctx (no offscreen). Used when there's no\n * compounding risk, or as the inner render for the offscreen path.\n */\nfunction renderShapeDirect(\n ctx: RenderContext,\n elementData: SerializedShapeElement,\n elementOpacity: number\n): void {\n const transformData = elementData.transformData;\n const fillOpacity = transformData.fillOpacity ?? 1;\n\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n // Fill\n ctx.globalAlpha = elementOpacity * fillOpacity;\n ctx.fillStyle = transformData.fillColor || '#3b82f6';\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.fill();\n ctx.restore();\n\n // Stroke\n if (elementData.stroke?.enabled) {\n ctx.save();\n ctx.translate(elementData.x, elementData.y);\n if (elementData.rotation) {\n ctx.rotate((-elementData.rotation * Math.PI) / 180);\n }\n\n const stroke = elementData.stroke;\n ctx.globalAlpha = elementOpacity * (stroke.opacity ?? 1);\n ctx.strokeStyle = stroke.color || '#000000';\n ctx.lineWidth = stroke.width || 2;\n ctx.lineCap = stroke.lineCap || 'round';\n ctx.lineJoin = stroke.lineJoin || 'round';\n\n ctx.beginPath();\n traceShapePath(ctx, transformData);\n ctx.stroke();\n ctx.restore();\n }\n}\n\n/**\n * Trace the shape path (without fill/stroke) — reusable for both fill and stroke passes.\n */\nfunction traceShapePath(\n ctx: RenderContext,\n transformData: SerializedShapeElement['transformData']\n): void {\n const { shapeType, width, height } = transformData;\n\n switch (shapeType) {\n case 'rectangle': {\n const borderRadius = transformData.borderRadius || 0;\n const x = -width / 2;\n const y = -height / 2;\n\n if (borderRadius > 0) {\n const radius = Math.min((borderRadius / 100) * Math.min(width, height), width / 2, height / 2);\n ctx.roundRect(x, y, width, height, radius);\n } else {\n ctx.rect(x, y, width, height);\n }\n break;\n }\n\n case 'circle': {\n const radius = Math.min(width, height) / 2;\n ctx.arc(0, 0, radius, 0, Math.PI * 2);\n break;\n }\n\n case 'ellipse': {\n ctx.ellipse(0, 0, width / 2, height / 2, 0, 0, Math.PI * 2);\n break;\n }\n\n case 'triangle': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.moveTo(0, -halfHeight);\n ctx.lineTo(halfWidth, halfHeight);\n ctx.lineTo(-halfWidth, halfHeight);\n ctx.closePath();\n break;\n }\n\n case 'polygon': {\n const sides = transformData.sides || 5;\n const radius = Math.min(width, height) / 2;\n for (let i = 0; i < sides; i++) {\n const angle = (i * 2 * Math.PI) / sides - Math.PI / 2;\n const px = radius * Math.cos(angle);\n const py = radius * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'star': {\n const points = transformData.points || 5;\n const outerRadius = Math.min(width, height) / 2;\n const innerRadius = outerRadius * (transformData.innerRadius || 0.4);\n for (let i = 0; i < points * 2; i++) {\n const angle = (i * Math.PI) / points - Math.PI / 2;\n const r = i % 2 === 0 ? outerRadius : innerRadius;\n const px = r * Math.cos(angle);\n const py = r * Math.sin(angle);\n if (i === 0) {\n ctx.moveTo(px, py);\n } else {\n ctx.lineTo(px, py);\n }\n }\n ctx.closePath();\n break;\n }\n\n case 'line': {\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n ctx.rect(-halfWidth, -halfHeight, width, height);\n break;\n }\n\n default:\n ctx.rect(-width / 2, -height / 2, width, height);\n }\n}\n"],"names":["resolveServerCrop","el","bitmap","renderImageElement","ctx","elementData","imageBitmap","scaleX","scaleY","radius","x","y","w","h","_a","hasKnockoutStroke","_b","imageConfig","canvas","offscreen","renderImageStroke","offCtx","createTempCanvas","width","height","renderShapeElement","elementOpacity","hasStroke","renderShapeWithOffscreen","renderShapeDirect","td","padding","offW","offH","offCanvas","tempData","transformData","fillOpacity","traceShapePath","stroke","shapeType","borderRadius","halfWidth","halfHeight","sides","angle","px","py","points","outerRadius","innerRadius","i","r"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { PieceGuide, SvgPath, ZoneShape, GuideLabel } from '../components/VisualGuideOverlay.js';
2
+ import { isInkDark, isInkLight, inkLuminance } from '../utils/inkLuminance.js';
2
3
  export type { PieceGuide, SvgPath, ZoneShape, GuideLabel };
3
4
  /** Minimum piece info the renderer needs. Matches the ADR-0054 backend shape. */
4
5
  export interface PieceGuideRendererPiece {
@@ -158,20 +159,5 @@ export interface PieceGuideRenderParams {
158
159
  */
159
160
  focusedPieceId?: string | null;
160
161
  }
161
- /**
162
- * Quick "is this ink dark / light" check used to decide whether to
163
- * flip an author-supplied colour for the current theme. We only
164
- * need to handle hex literals (`#rgb`, `#rrggbb`) and `rgb(...)` —
165
- * the formats Loom emits. CSS colour names / `hsl()` would fall
166
- * through to "neither" and skip the flip, which is the safe choice
167
- * (no surprising visual change for unfamiliar inputs).
168
- *
169
- * @internal — exposed for tests; not part of the package's public
170
- * API. Don't import these from outside the canvas package.
171
- */
172
- export declare function isInkDark(css: string): boolean;
173
- /** @internal */
174
- export declare function isInkLight(css: string): boolean;
175
- /** @internal */
176
- export declare function inkLuminance(css: string): number | null;
162
+ export { isInkDark, isInkLight, inkLuminance };
177
163
  export declare function renderPieceGuides(params: PieceGuideRenderParams): void;