@almadar/shell-web 0.1.0 → 1.1.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 (131) hide show
  1. package/dist/{ArbitraryClassCompiler-Mzabq-UB.d.ts → ArbitraryClassCompiler-CO_iASBn.d.ts} +99 -4
  2. package/dist/AvlGlyph-PIXU6QH5.js +5 -0
  3. package/dist/AvlStateMachine-CKGMECMG.js +8 -0
  4. package/dist/AvlTransitionDetail-QZX6G5KJ.js +10 -0
  5. package/dist/AvlTransitionExplainer-26WLEIC6.js +11 -0
  6. package/dist/BehaviorView-JLZ4PKWY.js +10 -0
  7. package/dist/{EventBusProvider-CVwjkV_2.d.ts → EventBusProvider-BFFHfN4O.d.ts} +12 -0
  8. package/dist/{FileTree-BCFnBEuQ.d.ts → FileTree-B3GDAjaQ.d.ts} +131 -4
  9. package/dist/FlowCanvas-RPII4V24.js +23 -0
  10. package/dist/{BehaviorValueFrame-SSEMEBTG.css → FlowCanvas-VWUPMBKB.css} +189 -191
  11. package/dist/{GameAudioProvider-Cm9BnvmP.d.ts → GameAudioProvider-D7wo5ryN.d.ts} +5 -8
  12. package/dist/KernelEngineContext-CPeWQMAz.d.ts +46 -0
  13. package/dist/LayersPanel-M2LHWUFF.js +6 -0
  14. package/dist/ModuleCard-NJD6JQGD.js +6 -0
  15. package/dist/OrbInspector-OWWKPOBF.js +23 -0
  16. package/dist/{TraitValueFrame-4G3KOUBR.css → OrbInspector-VMTMZHNQ.css} +189 -191
  17. package/dist/{Select-mDZIwNqN.d.ts → Select-C2Uq6t86.d.ts} +17 -31
  18. package/dist/ServerBridge-Bqsj-lOU.d.ts +124 -0
  19. package/dist/{FlowCanvas-3JRMNJLV.css → UISlotRenderer-BIS6KT7T.css} +189 -191
  20. package/dist/UISlotRenderer-PY7FIJXN.js +23 -0
  21. package/dist/auth/browser/index.js +1 -0
  22. package/dist/auth/react/index.d.ts +8 -1
  23. package/dist/auth/react/index.js +40 -2
  24. package/dist/avl/index.css +189 -191
  25. package/dist/avl/index.d.ts +107 -85
  26. package/dist/avl/index.js +170 -39
  27. package/dist/{chunk-P4LNHAFI.js → chunk-2WGR4TDJ.js} +465 -36
  28. package/dist/{chunk-GKIFONTE.js → chunk-3S54FWRC.js} +2 -2
  29. package/dist/{chunk-KVQS4GXU.js → chunk-4YJ53G7S.js} +18 -8
  30. package/dist/{chunk-MBQAMMSE.js → chunk-4YXBKHHM.js} +269 -658
  31. package/dist/{chunk-YDNJLLG6.js → chunk-57DC34LY.js} +19 -10
  32. package/dist/{chunk-FP3WIKTC.js → chunk-7N6ZPHQ5.js} +9 -1
  33. package/dist/{chunk-AILY3XPS.js → chunk-AE7VCQB6.js} +5 -6
  34. package/dist/{chunk-L677XGY3.js → chunk-AGVSO4WY.js} +4 -5
  35. package/dist/{chunk-FAJDTHWC.js → chunk-AGXD77SL.js} +2 -2
  36. package/dist/chunk-AU7O65OX.js +66 -0
  37. package/dist/{chunk-DFNZUYX4.js → chunk-FAKU5F62.js} +273 -29
  38. package/dist/{chunk-U6QRZASX.js → chunk-ILQXJ2AR.js} +1 -1
  39. package/dist/chunk-M74BCDBQ.js +490 -0
  40. package/dist/{chunk-GYTPOFVC.js → chunk-MS4K3K2R.js} +12095 -13329
  41. package/dist/{chunk-SGM3FASH.js → chunk-OWNG4JZI.js} +13 -12
  42. package/dist/{chunk-VFF5OO47.js → chunk-PCR37T3U.js} +15 -38
  43. package/dist/{chunk-SJGJJKBY.js → chunk-PRLHKBXG.js} +5 -3
  44. package/dist/{chunk-R5O5AUPI.js → chunk-PRXQGGCO.js} +93 -86
  45. package/dist/{chunk-42FY4RYA.js → chunk-REXYVBUO.js} +2 -2
  46. package/dist/{chunk-EQAMU2ZC.js → chunk-UTDC2NEA.js} +1 -1
  47. package/dist/{chunk-73SRAB4P.js → chunk-UU57VNS2.js} +2 -2
  48. package/dist/{chunk-TESBIVUA.js → chunk-VHC2M26B.js} +2 -2
  49. package/dist/{chunk-L2DEKY4J.js → chunk-VO2TTLS5.js} +3 -6
  50. package/dist/{chunk-2PY54Z44.js → chunk-VUIACGDU.js} +4 -5
  51. package/dist/{chunk-DLZF4PVE.js → chunk-YYIHRIDH.js} +3 -3
  52. package/dist/{chunk-DYEKAA4L.js → chunk-ZDRDJKYB.js} +243 -252
  53. package/dist/components/index.css +189 -191
  54. package/dist/components/index.d.ts +739 -289
  55. package/dist/components/index.js +25 -28
  56. package/dist/context/index.d.ts +2 -3
  57. package/dist/context/index.js +4 -3
  58. package/dist/core.d.ts +95 -19
  59. package/dist/core.js +2 -1
  60. package/dist/design-classes/index.cjs +3 -1
  61. package/dist/design-classes/index.js +3 -1
  62. package/dist/{fx-CmQjnHmT.d.ts → fx-Br8zjvu9.d.ts} +6 -6
  63. package/dist/hooks/index.d.ts +40 -5
  64. package/dist/hooks/index.js +5 -4
  65. package/dist/index.d.ts +40 -114
  66. package/dist/index.js +174 -34
  67. package/dist/kernel-client-JW6OH5FX.js +537 -0
  68. package/dist/kernel-wire-DGAySGhX.d.ts +95 -0
  69. package/dist/lib/index.d.ts +3 -4
  70. package/dist/lib/index.js +4 -4
  71. package/dist/{prism-AIWGN2X5.js → prism-X5YWKXO5.js} +5 -3
  72. package/dist/providers/index.css +189 -191
  73. package/dist/providers/index.d.ts +41 -28
  74. package/dist/providers/index.js +19 -24
  75. package/dist/renderer/index.d.ts +0 -2
  76. package/dist/renderer/index.js +1 -0
  77. package/dist/runtime/index.css +189 -191
  78. package/dist/runtime/index.d.ts +57 -253
  79. package/dist/runtime/index.js +18 -24
  80. package/dist/ssr/index.cjs +2643 -535
  81. package/dist/ssr/index.d.cts +0 -23
  82. package/dist/ssr/index.d.ts +0 -23
  83. package/dist/ssr/index.js +2639 -535
  84. package/dist/storage/browser/index.js +1 -0
  85. package/dist/test-support.d.ts +15 -8
  86. package/dist/test-support.js +91 -24
  87. package/dist/{paintDispatch-ChW5mVuK.d.ts → verificationRegistry-oopV1J1n.d.ts} +132 -30
  88. package/package.json +14 -38
  89. package/src/core/lib/band-shapes.json +7 -0
  90. package/src/core/locales/ar.json +18 -5
  91. package/src/core/locales/en.json +18 -5
  92. package/src/core/locales/sl.json +18 -5
  93. package/tailwind-preset.cjs +30 -1
  94. package/dist/AvlGlyph-JKJOAH23.js +0 -6
  95. package/dist/AvlStateMachine-PI4YGREK.js +0 -8
  96. package/dist/AvlTransitionDetail-ZH7V24UG.js +0 -12
  97. package/dist/AvlTransitionExplainer-ZSRT7L6Y.js +0 -13
  98. package/dist/BehaviorValueFrame-6RUJXT4A.js +0 -29
  99. package/dist/BehaviorView-RFEE5J6E.js +0 -10
  100. package/dist/Canvas3DHost-_Y-5uLM_.d.ts +0 -552
  101. package/dist/FlowCanvas-STDC4OWK.js +0 -27
  102. package/dist/KernelEngineContext-BOCQoFwk.d.ts +0 -43
  103. package/dist/LayersPanel-BBQ54IVG.js +0 -7
  104. package/dist/ModuleCard-3TT2X7IW.js +0 -7
  105. package/dist/OrbInspector-K6T6O7GI.js +0 -27
  106. package/dist/OrbInspector-MHLJ6OEE.css +0 -1756
  107. package/dist/ServerBridge-Cm1On51b.d.ts +0 -233
  108. package/dist/TraitValueFrame-2PJGLLVI.js +0 -28
  109. package/dist/UISlotRenderer-JKFSX24W.js +0 -27
  110. package/dist/UISlotRenderer-KVFO6J7R.css +0 -1756
  111. package/dist/UserContext-DqWeZkUZ.d.ts +0 -100
  112. package/dist/avl-3d-context-BIRKWpaL.d.ts +0 -204
  113. package/dist/avl-schema-parser-CtJxJ9KU.d.ts +0 -132
  114. package/dist/avl-zoom-state-CKMVuBFg.d.ts +0 -17
  115. package/dist/chunk-2QOH2HWM.js +0 -95
  116. package/dist/chunk-6P3MWXYE.js +0 -440
  117. package/dist/chunk-B4BU77LT.js +0 -432
  118. package/dist/chunk-DJ433ET5.js +0 -1327
  119. package/dist/chunk-DZ42OJQC.js +0 -176
  120. package/dist/chunk-EOWMARUB.js +0 -16
  121. package/dist/chunk-FIW6WN23.js +0 -508
  122. package/dist/chunk-GAR5TQ5B.js +0 -199
  123. package/dist/chunk-PC7K4SK7.js +0 -1384
  124. package/dist/chunk-ZO6MXAS3.js +0 -69
  125. package/dist/kernel-client-ZH4PSMCN.js +0 -367
  126. package/dist/kernel-wire-B4S8pnP3.d.ts +0 -65
  127. package/dist/three/index.css +0 -503
  128. package/dist/three/index.d.ts +0 -1185
  129. package/dist/three/index.js +0 -3896
  130. package/dist/useKeyboardRouter-Dsq553Ur.d.ts +0 -42
  131. package/dist/verificationRegistry-CabxhfTv.d.ts +0 -122
@@ -1,1384 +0,0 @@
1
- import { resolveThemeColor, parseComputedColor } from './chunk-DFNZUYX4.js';
2
- import { updateAssetStatus } from './chunk-B4BU77LT.js';
3
- import { resolveFxView, useTheme, useThemeScope, fxLifecycle, fxHash01 } from './chunk-MBQAMMSE.js';
4
- import { createContext, useContext, useState, useLayoutEffect, useEffect } from 'react';
5
- import { createLogger } from '@almadar/logger';
6
- import { DIAGRAM_TONES, DIAGRAM_TONE_COLOR_KEYS, DIAGRAM_TEXT_SIZES } from '@almadar/core';
7
-
8
- // src/lib/drawable/contract.ts
9
- function isValidScenePos(pos) {
10
- return Number.isFinite(pos?.x) && Number.isFinite(pos?.y);
11
- }
12
- function spriteAssetState(node) {
13
- if (!isValidScenePos(node.position)) return "invalid-position";
14
- return typeof node.asset?.url === "string" && node.asset.url.length > 0 ? "ready" : "asset-unset";
15
- }
16
- var SPRITE_FALLBACK_FILL = "#9b8f7f";
17
- var SPRITE_FALLBACK_STROKE = "#5e564b";
18
- function spriteRect(projector, node, natural) {
19
- const tw = projector.tileWidth;
20
- const fallbackW = projector.worldPixelDirect ? natural?.w ?? 0 : tw;
21
- const fallbackH = projector.worldPixelDirect ? natural?.h ?? 0 : tw;
22
- const w = node.width !== void 0 ? node.width * tw : fallbackW;
23
- const h = node.height !== void 0 ? node.height * tw : fallbackH;
24
- const anchor = node.anchor ?? "top-left";
25
- const p = projector.anchorPoint(node.position, anchor);
26
- return {
27
- x: anchor === "top-left" ? p.x : p.x - w / 2,
28
- y: anchor === "ground" ? p.y - h : anchor === "center" ? p.y - h / 2 : p.y,
29
- w,
30
- h
31
- };
32
- }
33
- var DrawableRegistryContext = createContext(null);
34
- var NUMERIC_TRACKS = [
35
- "offsetX",
36
- "offsetY",
37
- "rotate",
38
- "opacity",
39
- "radiusX",
40
- "radiusY",
41
- "width",
42
- "height",
43
- "strokeWidth",
44
- "strokeDashOffset",
45
- "blur"
46
- ];
47
- function isAnimatedShape(node) {
48
- return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
49
- }
50
- var lerp = (a, b, k) => a + (b - a) * k;
51
- function applyShapeAnimation(node, timeMs) {
52
- const anim = node.animation;
53
- if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return node;
54
- const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
55
- const cycle = timeMs / anim.durationMs;
56
- const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
57
- const out = { ...node };
58
- const trackValue = (key) => {
59
- const defined = frames.filter((f) => f[key] !== void 0);
60
- if (defined.length === 0) return void 0;
61
- let prev;
62
- let next;
63
- for (const f of defined) {
64
- if (f.at <= t) prev = f;
65
- else if (!next) next = f;
66
- }
67
- if (!prev) return defined[0][key];
68
- if (!next) return prev[key];
69
- const span = next.at - prev.at;
70
- const k = span > 0 ? (t - prev.at) / span : 1;
71
- const a = prev[key];
72
- const b = next[key];
73
- if (typeof a === "number" && typeof b === "number") return lerp(a, b, k);
74
- return a;
75
- };
76
- for (const key of NUMERIC_TRACKS) {
77
- const v = trackValue(key);
78
- if (v !== void 0) out[key] = v;
79
- }
80
- const fill = trackValue("fill");
81
- if (fill !== void 0) out.fill = fill;
82
- const stroke = trackValue("stroke");
83
- if (stroke !== void 0) out.stroke = stroke;
84
- const shadowFrames = frames.filter((f) => f.shadow !== void 0);
85
- if (shadowFrames.length > 0) {
86
- const sh = trackValue("shadow");
87
- if (sh !== void 0) {
88
- let prevSh;
89
- let nextSh;
90
- for (const f of shadowFrames) {
91
- if (f.at <= t) prevSh = f;
92
- else if (!nextSh) nextSh = f;
93
- }
94
- if (prevSh?.shadow && nextSh?.shadow) {
95
- const span = nextSh.at - prevSh.at;
96
- const k = span > 0 ? (t - prevSh.at) / span : 1;
97
- out.shadow = { color: prevSh.shadow.color, blur: lerp(prevSh.shadow.blur, nextSh.shadow.blur, k) };
98
- } else {
99
- out.shadow = sh;
100
- }
101
- }
102
- }
103
- return out;
104
- }
105
- function gradientStyle(g, ox, oy, scale) {
106
- if (g.kind === "linear") {
107
- if (!g.from || !g.to) return void 0;
108
- return {
109
- kind: "linear",
110
- x1: ox + g.from.x * scale,
111
- y1: oy + g.from.y * scale,
112
- x2: ox + g.to.x * scale,
113
- y2: oy + g.to.y * scale,
114
- stops: g.stops
115
- };
116
- }
117
- if (g.kind === "conic") {
118
- if (!g.center) return void 0;
119
- return {
120
- kind: "conic",
121
- cx: ox + g.center.x * scale,
122
- cy: oy + g.center.y * scale,
123
- angle: g.angle ?? 0,
124
- stops: g.stops
125
- };
126
- }
127
- if (!g.center || g.radius === void 0) return void 0;
128
- return {
129
- kind: "radial",
130
- cx: ox + g.center.x * scale,
131
- cy: oy + g.center.y * scale,
132
- r: g.radius * scale,
133
- stops: g.stops
134
- };
135
- }
136
- function patternStyle(p, unit) {
137
- if (p.kind === "image") {
138
- if (!p.url) return void 0;
139
- return { kind: "image", url: p.url, scale: (p.scale ?? 1) / unit };
140
- }
141
- return { kind: "noise", scale: (p.scale ?? 2) / unit, alpha: p.alpha, color: p.color };
142
- }
143
- var paintShape = (painter, rawNode, dctx) => {
144
- const node = dctx.time > 0 ? applyShapeAnimation(rawNode, dctx.time) : rawNode;
145
- if (!isValidScenePos(node.position)) return;
146
- painter.save();
147
- if (node.opacity !== void 0 && node.opacity !== 1) painter.setAlpha(node.opacity);
148
- const origin = dctx.projector.project(node.position);
149
- const tileWidth = dctx.projector.tileWidth;
150
- const groupScale = dctx.groupScale ?? 1;
151
- const strokePx = (node.strokeWidth ?? 1) / groupScale;
152
- if (node.blendMode) painter.setBlend(node.blendMode);
153
- if (node.strokeDash && node.strokeDash.length > 0) {
154
- painter.setLineDash(
155
- node.strokeDash.map((v) => v / groupScale),
156
- (node.strokeDashOffset ?? 0) / groupScale
157
- );
158
- }
159
- if (node.blur !== void 0 && node.blur > 0) painter.setBlur(node.blur / groupScale);
160
- if (node.rotate) {
161
- const pivot = node.pivot ?? { x: 0.5, y: 0.5 };
162
- const px = origin.x + pivot.x * tileWidth;
163
- const py = origin.y + pivot.y * tileWidth;
164
- painter.translate(px, py);
165
- painter.rotate(node.rotate);
166
- painter.translate(-px, -py);
167
- }
168
- if (node.shadow) painter.setShadow({ color: node.shadow.color, blur: node.shadow.blur * tileWidth * groupScale });
169
- const fill = node.fill === "none" ? void 0 : node.fill;
170
- const stroke = node.stroke === "none" ? void 0 : node.stroke;
171
- const pxFill = node.gradient ? gradientStyle(node.gradient, origin.x, origin.y, tileWidth) ?? fill : fill;
172
- const pxStroke = node.strokeGradient ? gradientStyle(node.strokeGradient, origin.x, origin.y, tileWidth) ?? stroke : stroke;
173
- const patFill = node.fillPattern ? patternStyle(node.fillPattern, groupScale) : void 0;
174
- switch (node.shape) {
175
- case "cell": {
176
- const pts = dctx.projector.cellPath(node.position);
177
- if (pxFill) painter.fillPoly(pts, pxFill);
178
- if (patFill) painter.fillPoly(pts, patFill);
179
- if (pxStroke) painter.strokePoly(pts, pxStroke, strokePx, true);
180
- break;
181
- }
182
- case "rect": {
183
- const p = dctx.projector.anchorPoint(node.position, node.anchor ?? "top-left");
184
- const tw = dctx.projector.tileWidth;
185
- const x = p.x + (node.offsetX ?? 0) * tw;
186
- const y = p.y + (node.offsetY ?? 0) * tw;
187
- const w = (node.width ?? 0) * tw;
188
- const h = (node.height ?? 0) * tw;
189
- if (pxFill) painter.fillRect(x, y, w, h, pxFill);
190
- if (patFill) painter.fillRect(x, y, w, h, patFill);
191
- if (pxStroke) painter.strokeRect(x, y, w, h, pxStroke, strokePx);
192
- break;
193
- }
194
- case "ellipse": {
195
- const p = dctx.projector.anchorPoint(node.position, node.anchor ?? "ground");
196
- const tw = dctx.projector.tileWidth;
197
- const cx = p.x + (node.offsetX ?? 0) * tw;
198
- const cy = p.y + (node.offsetY ?? 0) * tw;
199
- const rx = (node.radiusX ?? 0) * tw;
200
- const ry = (node.radiusY ?? node.radiusX ?? 0) * tw;
201
- if (pxFill) painter.fillEllipse(cx, cy, rx, ry, pxFill);
202
- if (patFill) painter.fillEllipse(cx, cy, rx, ry, patFill);
203
- if (pxStroke) painter.strokeEllipse(cx, cy, rx, ry, pxStroke, strokePx);
204
- break;
205
- }
206
- case "poly": {
207
- const pts = (node.points ?? []).map((pt) => ({
208
- x: origin.x + ((node.offsetX ?? 0) + pt.x) * tileWidth,
209
- y: origin.y + ((node.offsetY ?? 0) + pt.y) * tileWidth
210
- }));
211
- if (pxFill) painter.fillPoly(pts, pxFill);
212
- if (patFill) painter.fillPoly(pts, patFill);
213
- if (pxStroke) painter.strokePoly(pts, pxStroke, strokePx, true);
214
- break;
215
- }
216
- case "path": {
217
- if (!node.d) break;
218
- painter.translate(origin.x + (node.offsetX ?? 0) * tileWidth, origin.y + (node.offsetY ?? 0) * tileWidth);
219
- painter.scale(tileWidth, tileWidth);
220
- if (node.strokeDash && node.strokeDash.length > 0) {
221
- painter.setLineDash(
222
- node.strokeDash.map((v) => v / (groupScale * tileWidth)),
223
- (node.strokeDashOffset ?? 0) / (groupScale * tileWidth)
224
- );
225
- }
226
- if (node.blur !== void 0 && node.blur > 0) painter.setBlur(node.blur / (groupScale * tileWidth));
227
- const localFill = node.gradient ? gradientStyle(node.gradient, 0, 0, 1) ?? fill : fill;
228
- const localStroke = node.strokeGradient ? gradientStyle(node.strokeGradient, 0, 0, 1) ?? stroke : stroke;
229
- const localPat = node.fillPattern ? patternStyle(node.fillPattern, groupScale * tileWidth) : void 0;
230
- if (localFill) painter.fillPath(node.d, localFill);
231
- if (localPat) painter.fillPath(node.d, localPat);
232
- if (localStroke) painter.strokePath(node.d, localStroke, strokePx / tileWidth);
233
- break;
234
- }
235
- }
236
- painter.restore();
237
- };
238
- function DrawShape(props) {
239
- const register = useContext(DrawableRegistryContext);
240
- if (register) {
241
- const { opacity, ...rest } = props;
242
- const node = {
243
- ...rest,
244
- type: "draw-shape",
245
- ...opacity !== void 0 && opacity > 0 ? { opacity } : {}
246
- };
247
- register(node);
248
- }
249
- return null;
250
- }
251
- function isAnimatedGroup(node) {
252
- return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
253
- }
254
- function DrawGroup(props) {
255
- const register = useContext(DrawableRegistryContext);
256
- if (register) register({ ...props, type: "draw-group" });
257
- return null;
258
- }
259
-
260
- // src/lib/imageCache.ts
261
- var RETRY_AFTER_MS = 5e3;
262
- var cache = /* @__PURE__ */ new Map();
263
- function startLoad(url, onReady, existing) {
264
- const img = new Image();
265
- img.crossOrigin = "anonymous";
266
- const entry = existing ?? { img, status: "pending" };
267
- entry.img = img;
268
- if (onReady) entry.onReady = onReady;
269
- img.onload = () => {
270
- entry.status = "loaded";
271
- updateAssetStatus(url, "loaded");
272
- entry.onReady?.();
273
- };
274
- img.onerror = () => {
275
- entry.status = "failed";
276
- entry.failedAt = Date.now();
277
- updateAssetStatus(url, "failed");
278
- entry.onReady?.();
279
- };
280
- img.src = url;
281
- return entry;
282
- }
283
- function getOrLoadImage(url, onReady) {
284
- if (!url || typeof window === "undefined") return null;
285
- const existing = cache.get(url);
286
- if (existing) {
287
- if (existing.status === "loaded") return existing.img;
288
- if (existing.status === "pending" && onReady) existing.onReady = onReady;
289
- if (existing.status === "failed" && Date.now() - (existing.failedAt ?? 0) >= RETRY_AFTER_MS) {
290
- existing.failedAt = Date.now();
291
- startLoad(url, onReady, existing);
292
- }
293
- return null;
294
- }
295
- const entry = startLoad(url, onReady);
296
- cache.set(url, entry);
297
- updateAssetStatus(url, "pending");
298
- return null;
299
- }
300
- function getImageStatus(url) {
301
- return cache.get(url)?.status;
302
- }
303
-
304
- // src/lib/skinning.ts
305
- var IDENTITY = [1, 0, 0, 1, 0, 0];
306
- function composeAffine(a, b) {
307
- return [
308
- a[0] * b[0] + a[2] * b[1],
309
- a[1] * b[0] + a[3] * b[1],
310
- a[0] * b[2] + a[2] * b[3],
311
- a[1] * b[2] + a[3] * b[3],
312
- a[0] * b[4] + a[2] * b[5] + a[4],
313
- a[1] * b[4] + a[3] * b[5] + a[5]
314
- ];
315
- }
316
- function invertAffine(m) {
317
- const det = m[0] * m[3] - m[1] * m[2];
318
- if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return IDENTITY;
319
- const inv = 1 / det;
320
- return [
321
- m[3] * inv,
322
- -m[1] * inv,
323
- -m[2] * inv,
324
- m[0] * inv,
325
- (m[2] * m[5] - m[3] * m[4]) * inv,
326
- (m[1] * m[4] - m[0] * m[5]) * inv
327
- ];
328
- }
329
- function applyAffine(m, x, y) {
330
- return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
331
- }
332
- function rotationAbout(pivot, degrees) {
333
- const r = degrees * Math.PI / 180;
334
- const cos = Math.cos(r);
335
- const sin = Math.sin(r);
336
- const [px, py] = pivot;
337
- return [cos, sin, -sin, cos, px - cos * px + sin * py, py - sin * px - cos * py];
338
- }
339
- function computeWorldMatrices(bones, pose) {
340
- const indexByName = /* @__PURE__ */ new Map();
341
- bones.forEach((b, i) => indexByName.set(b.name, i));
342
- const world = new Array(bones.length);
343
- const visiting = /* @__PURE__ */ new Set();
344
- const resolve = (i) => {
345
- const cached = world[i];
346
- if (cached) return cached;
347
- if (visiting.has(i)) return IDENTITY;
348
- visiting.add(i);
349
- const b = bones[i];
350
- const parentIndex = b.parent === null ? void 0 : indexByName.get(b.parent);
351
- const parentWorld = parentIndex === void 0 ? IDENTITY : resolve(parentIndex);
352
- const local = rotationAbout(b.pivot, pose[b.name] ?? 0);
353
- const m = composeAffine(parentWorld, local);
354
- visiting.delete(i);
355
- world[i] = m;
356
- return m;
357
- };
358
- return bones.map((_, i) => resolve(i));
359
- }
360
- function skinVertices(mesh, bindWorld, curWorld) {
361
- const skinMats = /* @__PURE__ */ new Map();
362
- const skinMat = (bone) => {
363
- let m = skinMats.get(bone);
364
- if (!m) {
365
- m = composeAffine(curWorld[bone] ?? IDENTITY, invertAffine(bindWorld[bone] ?? IDENTITY));
366
- skinMats.set(bone, m);
367
- }
368
- return m;
369
- };
370
- return mesh.vertices.map((v) => {
371
- if (v.weights.length === 0) return [v.x, v.y];
372
- let x = 0;
373
- let y = 0;
374
- for (const { bone, w } of v.weights) {
375
- const [bx, by] = applyAffine(skinMat(bone), v.x, v.y);
376
- x += w * bx;
377
- y += w * by;
378
- }
379
- return [x, y];
380
- });
381
- }
382
- function triangleAffine(src, dst) {
383
- const [s0, s1, s2] = src;
384
- const det = s0[0] * (s1[1] - s2[1]) + s1[0] * (s2[1] - s0[1]) + s2[0] * (s0[1] - s1[1]);
385
- if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return null;
386
- const [d0, d1, d2] = dst;
387
- const a = (d0[0] * (s1[1] - s2[1]) + d1[0] * (s2[1] - s0[1]) + d2[0] * (s0[1] - s1[1])) / det;
388
- const c = (d0[0] * (s2[0] - s1[0]) + d1[0] * (s0[0] - s2[0]) + d2[0] * (s1[0] - s0[0])) / det;
389
- const e = (d0[0] * (s1[0] * s2[1] - s2[0] * s1[1]) + d1[0] * (s2[0] * s0[1] - s0[0] * s2[1]) + d2[0] * (s0[0] * s1[1] - s1[0] * s0[1])) / det;
390
- const b = (d0[1] * (s1[1] - s2[1]) + d1[1] * (s2[1] - s0[1]) + d2[1] * (s0[1] - s1[1])) / det;
391
- const d = (d0[1] * (s2[0] - s1[0]) + d1[1] * (s0[0] - s2[0]) + d2[1] * (s1[0] - s0[0])) / det;
392
- const f = (d0[1] * (s1[0] * s2[1] - s2[0] * s1[1]) + d1[1] * (s2[0] * s0[1] - s0[0] * s2[1]) + d2[1] * (s0[0] * s1[1] - s1[0] * s0[1])) / det;
393
- return [a, b, c, d, e, f];
394
- }
395
- var meshCache = /* @__PURE__ */ new Map();
396
- function isRigBundle(json) {
397
- return json.mesh !== void 0 || json.bones !== void 0;
398
- }
399
- function getRigBundle(url, onReady) {
400
- if (meshCache.has(url)) return meshCache.get(url) ?? void 0;
401
- meshCache.set(url, void 0);
402
- fetch(url).then((r) => {
403
- if (!r.ok) throw new Error(`rigbundle fetch failed: HTTP ${r.status}`);
404
- return r.json();
405
- }).then((json) => {
406
- const ok = isRigBundle(json) || Array.isArray(json.vertices);
407
- if (!ok) throw new Error("rigbundle payload is neither a SkinMesh nor a rigbundle");
408
- meshCache.set(url, json);
409
- onReady();
410
- }).catch(() => {
411
- meshCache.set(url, null);
412
- onReady();
413
- });
414
- return void 0;
415
- }
416
- function skinMeshFailed(url) {
417
- return meshCache.get(url) === null;
418
- }
419
- function vertexBounds(points) {
420
- if (points.length === 0) return null;
421
- let minX = Infinity;
422
- let minY = Infinity;
423
- let maxX = -Infinity;
424
- let maxY = -Infinity;
425
- for (const [x, y] of points) {
426
- if (x < minX) minX = x;
427
- if (y < minY) minY = y;
428
- if (x > maxX) maxX = x;
429
- if (y > maxY) maxY = y;
430
- }
431
- return { minX, minY, maxX, maxY };
432
- }
433
-
434
- // src/components/game/atoms/DrawSkinnedMesh.tsx
435
- var skinnedLog = createLogger("almadar:ui:draw-skinned-mesh");
436
- var loggedMissing = /* @__PURE__ */ new Set();
437
- function warnMissingOnce(reason, node) {
438
- const key = `${reason}:${node.asset.url}:${String(node.meshUrl)}`;
439
- if (loggedMissing.has(key)) return;
440
- loggedMissing.add(key);
441
- skinnedLog.warn("draw-skinned-mesh unresolvable \u2014 painting fallback", { reason, url: node.asset.url, meshUrl: node.meshUrl });
442
- }
443
- var WEIGHT_PALETTE = Array.from({ length: 10 }, (_, i) => `hsl(${i * 36 % 360}, 70%, 55%)`);
444
- function dominantBone(v) {
445
- let best = -1;
446
- let bestW = 0;
447
- for (const { bone, w } of v.weights) {
448
- if (w > bestW) {
449
- bestW = w;
450
- best = bone;
451
- }
452
- }
453
- return best;
454
- }
455
- function resolveSkinPose(node, clip) {
456
- const effectiveClip = clip ?? node.clip;
457
- if (effectiveClip && node.frame !== void 0 && effectiveClip.frames.length > 0) {
458
- return effectiveClip.frames[node.frame % effectiveClip.frames.length];
459
- }
460
- return node.pose ?? {};
461
- }
462
- function resolveRig(node, dctx) {
463
- const fetched = node.meshUrl ? getRigBundle(node.meshUrl, dctx.invalidate) : void 0;
464
- if (node.meshUrl && fetched === void 0) return void 0;
465
- const rb = fetched && isRigBundle(fetched) ? fetched : void 0;
466
- const mesh = node.mesh ?? rb?.mesh ?? (!rb ? fetched : void 0);
467
- if (!mesh) return void 0;
468
- const bones = node.bones.length > 0 ? node.bones : rb?.bones ?? [];
469
- if (bones.length === 0) return void 0;
470
- const clip = node.clip ?? (node.clipName ? rb?.clips?.[node.clipName] : void 0);
471
- return { mesh, bones, clip };
472
- }
473
- var pixelUVByMesh = /* @__PURE__ */ new WeakMap();
474
- function meshHasPixelUVs(mesh) {
475
- const cached = pixelUVByMesh.get(mesh);
476
- if (cached !== void 0) return cached;
477
- let pixel = false;
478
- for (const v of mesh.vertices) {
479
- if (v.u < 0 || v.u > 1 || v.v < 0 || v.v > 1) {
480
- pixel = true;
481
- break;
482
- }
483
- }
484
- pixelUVByMesh.set(mesh, pixel);
485
- return pixel;
486
- }
487
- function paintMeshPass(painter, node, bones, mesh, tex, dctx, pose, opacity) {
488
- const bindWorld = computeWorldMatrices(bones, {});
489
- const curWorld = computeWorldMatrices(bones, pose);
490
- const skinned = skinVertices(mesh, bindWorld, curWorld);
491
- const origin = dctx.projector.project(node.position);
492
- const tw = dctx.projector.tileWidth;
493
- painter.save();
494
- if (opacity !== 1) painter.setAlpha(opacity);
495
- for (const [i0, i1, i2] of mesh.triangles) {
496
- const v0 = mesh.vertices[i0];
497
- const v1 = mesh.vertices[i1];
498
- const v2 = mesh.vertices[i2];
499
- const p0 = skinned[i0];
500
- const p1 = skinned[i1];
501
- const p2 = skinned[i2];
502
- if (!v0 || !v1 || !v2 || !p0 || !p1 || !p2) continue;
503
- const dst = [
504
- [origin.x + p0[0] * tw, origin.y + p0[1] * tw],
505
- [origin.x + p1[0] * tw, origin.y + p1[1] * tw],
506
- [origin.x + p2[0] * tw, origin.y + p2[1] * tw]
507
- ];
508
- if (node.weightsOverlay || !tex) {
509
- if (!node.weightsOverlay) continue;
510
- const bone = dominantBone(v0);
511
- painter.fillPoly(
512
- dst.map(([x, y]) => ({ x, y })),
513
- WEIGHT_PALETTE[(bone % WEIGHT_PALETTE.length + WEIGHT_PALETTE.length) % WEIGHT_PALETTE.length]
514
- );
515
- continue;
516
- }
517
- const pixelUV = meshHasPixelUVs(mesh);
518
- const uv = pixelUV ? [[v0.u, v0.v], [v1.u, v1.v], [v2.u, v2.v]] : [
519
- [v0.u * tex.width, v0.v * tex.height],
520
- [v1.u * tex.width, v1.v * tex.height],
521
- [v2.u * tex.width, v2.v * tex.height]
522
- ];
523
- const affine = triangleAffine(uv, dst);
524
- if (!affine) continue;
525
- painter.save();
526
- painter.clipPath(`M ${dst[0][0]} ${dst[0][1]} L ${dst[1][0]} ${dst[1][1]} L ${dst[2][0]} ${dst[2][1]} Z`);
527
- painter.blitTransformed(tex, { x: 0, y: 0, w: tex.width, h: tex.height }, affine);
528
- painter.restore();
529
- }
530
- painter.restore();
531
- }
532
- var paintSkinnedMesh = (painter, node, dctx) => {
533
- if (!isValidScenePos(node.position)) return;
534
- const rig = resolveRig(node, dctx);
535
- if (!rig) {
536
- if (node.meshUrl && skinMeshFailed(node.meshUrl)) warnMissingOnce("mesh-failed", node);
537
- else if (!node.mesh && !node.meshUrl) warnMissingOnce("mesh-missing", node);
538
- return;
539
- }
540
- const tex = node.weightsOverlay ? null : painter.resolveTexture(node.asset.url);
541
- if (!node.weightsOverlay && !tex) {
542
- if (getImageStatus(node.asset.url) === "failed") warnMissingOnce("texture-failed", node);
543
- return;
544
- }
545
- if (node.ghost && rig.clip && rig.clip.frames.length > 0) {
546
- paintMeshPass(painter, node, rig.bones, rig.mesh, tex, dctx, rig.clip.frames[node.ghost.frame % rig.clip.frames.length], node.ghost.opacity);
547
- }
548
- paintMeshPass(painter, node, rig.bones, rig.mesh, tex, dctx, resolveSkinPose(node, rig.clip), node.opacity ?? 1);
549
- };
550
- function DrawSkinnedMesh(props) {
551
- const register = useContext(DrawableRegistryContext);
552
- if (register) register({ ...props, type: "draw-skinned-mesh" });
553
- return null;
554
- }
555
- var MESH_SEGMENTS_DEFAULT = 24;
556
- function polyhedronBounds(vertices) {
557
- if (!vertices || vertices.length < 3) return null;
558
- const min = [Infinity, Infinity, Infinity];
559
- const max = [-Infinity, -Infinity, -Infinity];
560
- for (const v of vertices) {
561
- if (v.length < 3 || !v.every((c) => Number.isFinite(c))) return null;
562
- for (let axis = 0; axis < 3; axis++) {
563
- min[axis] = Math.min(min[axis], v[axis]);
564
- max[axis] = Math.max(max[axis], v[axis]);
565
- }
566
- }
567
- return { min, max };
568
- }
569
- function clampSegments(segments) {
570
- const s = segments ?? MESH_SEGMENTS_DEFAULT;
571
- return Math.min(64, Math.max(3, Math.round(s)));
572
- }
573
- function isAnimatedMesh(node) {
574
- return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
575
- }
576
- var lerp2 = (a, b, k) => a + (b - a) * k;
577
- var NUMERIC_TRACKS2 = [
578
- "offsetX",
579
- "offsetY",
580
- "offsetZ",
581
- "rotateX",
582
- "rotateY",
583
- "rotateZ",
584
- "scale",
585
- "opacity",
586
- "emissiveIntensity"
587
- ];
588
- function applyMeshAnimation(node, timeMs) {
589
- const anim = node.animation;
590
- if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return null;
591
- const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
592
- const cycle = timeMs / anim.durationMs;
593
- const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
594
- const trackValue = (key) => {
595
- const defined = frames.filter((f) => f[key] !== void 0);
596
- if (defined.length === 0) return void 0;
597
- let prev;
598
- let next;
599
- for (const f of defined) {
600
- if (f.at <= t) prev = f;
601
- else if (!next) next = f;
602
- }
603
- if (!prev) return defined[0][key];
604
- if (!next) return prev[key];
605
- const span = next.at - prev.at;
606
- const k = span > 0 ? (t - prev.at) / span : 1;
607
- const a = prev[key];
608
- const b = next[key];
609
- if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
610
- return a;
611
- };
612
- const num = {};
613
- for (const key of NUMERIC_TRACKS2) {
614
- const v = trackValue(key);
615
- if (v !== void 0) num[key] = v;
616
- }
617
- return {
618
- offset: [num.offsetX ?? 0, num.offsetY ?? 0, num.offsetZ ?? 0],
619
- rotate: [num.rotateX ?? 0, num.rotateY ?? 0, num.rotateZ ?? 0],
620
- scale: num.scale ?? 1,
621
- opacity: num.opacity,
622
- emissiveIntensity: num.emissiveIntensity,
623
- color: trackValue("color"),
624
- emissive: trackValue("emissive")
625
- };
626
- }
627
- function DrawMesh(props) {
628
- const register = useContext(DrawableRegistryContext);
629
- if (register) register({ ...props, type: "draw-mesh" });
630
- return null;
631
- }
632
-
633
- // src/components/game/molecules/DrawFxLayer.tsx
634
- var DEFAULT_TICK_MS = 500;
635
- var DEFAULT_TEXT_COLOR = "#ffe066";
636
- var DEFAULT_SPARK_COLOR = "#ffffff";
637
- var easeOut = (t) => 1 - (1 - t) * (1 - t);
638
- function fxPosition(view, dim, ageSec) {
639
- const g = view.gravity ?? 0;
640
- const fall = 0.5 * g * ageSec * ageSec;
641
- if (dim === "2d") {
642
- const base2 = view.position ?? { x: view.x, y: view.z ?? view.y ?? 0 };
643
- if (!Number.isFinite(base2.x) || !Number.isFinite(base2.y)) return void 0;
644
- return {
645
- x: base2.x + (view.vx ?? 0) * ageSec,
646
- y: base2.y + (view.vz ?? 0) * ageSec + fall
647
- };
648
- }
649
- const base = view.position ?? { x: view.x, y: view.z ?? 0, z: view.y };
650
- if (!Number.isFinite(base.x) || !Number.isFinite(base.y)) return void 0;
651
- return {
652
- x: base.x + (view.vx ?? 0) * ageSec,
653
- y: base.y + (view.vz ?? 0) * ageSec,
654
- ...base.z !== void 0 || view.vy !== void 0 || g !== 0 ? { z: (base.z ?? 0) + (view.vy ?? 0) * ageSec - fall } : {}
655
- };
656
- }
657
- function sparkShape(view, pos, i, fade, progress) {
658
- const size = view.size ?? 0.5;
659
- const angle = fxHash01(view.id, i * 3) * Math.PI * 2;
660
- const dist = size * (0.4 + 0.6 * fxHash01(view.id, i * 3 + 1)) * easeOut(progress);
661
- const r = size * (0.06 + 0.06 * fxHash01(view.id, i * 3 + 2));
662
- const color = view.color ?? DEFAULT_SPARK_COLOR;
663
- return {
664
- type: "draw-shape",
665
- shape: "ellipse",
666
- position: { ...pos, x: pos.x + Math.cos(angle) * dist, y: pos.y + Math.sin(angle) * dist },
667
- anchor: "center",
668
- radiusX: r,
669
- fill: color,
670
- blendMode: "lighter",
671
- opacity: fade,
672
- ...view.glow ? { shadow: { color, blur: view.glow } } : {}
673
- };
674
- }
675
- function proceduralShapes(view, pos, fade, progress) {
676
- const size = view.size ?? 0.5;
677
- const color = view.color ?? DEFAULT_SPARK_COLOR;
678
- switch (view.shape ?? "spark") {
679
- case "ring": {
680
- return [
681
- {
682
- type: "draw-shape",
683
- shape: "ellipse",
684
- position: pos,
685
- anchor: "center",
686
- radiusX: size * easeOut(progress),
687
- stroke: view.color2 ?? color,
688
- strokeWidth: 2,
689
- blendMode: "lighter",
690
- opacity: fade,
691
- ...view.glow ? { shadow: { color, blur: view.glow } } : {}
692
- }
693
- ];
694
- }
695
- case "puff": {
696
- const count = view.count ?? 3;
697
- return Array.from({ length: count }, (_, i) => {
698
- const angle = fxHash01(view.id, i * 5) * Math.PI * 2;
699
- const drift = size * 0.3 * fxHash01(view.id, i * 5 + 1) * easeOut(progress);
700
- return {
701
- type: "draw-shape",
702
- shape: "ellipse",
703
- position: { ...pos, x: pos.x + Math.cos(angle) * drift, y: pos.y + Math.sin(angle) * drift },
704
- anchor: "center",
705
- radiusX: size * (0.15 + 0.35 * progress) * (0.7 + 0.6 * fxHash01(view.id, i * 5 + 2)),
706
- fill: i === 0 && view.color2 ? view.color2 : color,
707
- opacity: fade * 0.6,
708
- ...view.glow ? { shadow: { color, blur: view.glow } } : {}
709
- };
710
- });
711
- }
712
- case "streak": {
713
- const count = view.count ?? 5;
714
- return Array.from({ length: count }, (_, i) => {
715
- const angle = fxHash01(view.id, i * 3) * Math.PI * 2;
716
- const inner = size * (0.2 + 0.8 * easeOut(progress)) * (0.6 + 0.4 * fxHash01(view.id, i * 3 + 1));
717
- const len = size * 0.35;
718
- return {
719
- type: "draw-shape",
720
- shape: "ellipse",
721
- position: pos,
722
- anchor: "center",
723
- offsetX: inner + len / 2,
724
- offsetY: 0,
725
- radiusX: len / 2,
726
- radiusY: size * 0.04,
727
- rotate: angle,
728
- fill: color,
729
- blendMode: "lighter",
730
- opacity: fade,
731
- ...view.glow ? { shadow: { color, blur: view.glow } } : {}
732
- };
733
- });
734
- }
735
- default: {
736
- const count = view.count ?? 6;
737
- return Array.from({ length: count }, (_, i) => sparkShape(view, pos, i, fade, progress));
738
- }
739
- }
740
- }
741
- function expandFxItem(view, node, epochNowMs, dim, projector, fontFamily) {
742
- if (view.space === "screen") return [];
743
- const tickMs = node.tickMs ?? DEFAULT_TICK_MS;
744
- const { ageMs, progress, fade } = fxLifecycle(view, epochNowMs, tickMs);
745
- if (progress >= 1) return [];
746
- const pos = fxPosition(view, dim, ageMs / 1e3);
747
- if (!pos) return [];
748
- const out = [];
749
- const artItems = node.art?.[view.type]?.["idle"];
750
- const sprite = node.sprites?.[view.type];
751
- if (Array.isArray(artItems)) {
752
- out.push({
753
- type: "draw-group",
754
- position: pos,
755
- opacity: fade,
756
- ...view.size !== void 0 ? { scale: view.size } : {},
757
- items: artItems
758
- });
759
- } else if (sprite?.url) {
760
- const spriteSize = view.size ?? 0.6;
761
- out.push({
762
- type: "draw-sprite",
763
- position: pos,
764
- asset: sprite,
765
- anchor: "center",
766
- width: spriteSize,
767
- height: spriteSize,
768
- opacity: fade,
769
- animation: view.animation ?? sprite.animations?.[0],
770
- // One-shot fx rows (burst) play from the item's birth, not wall-time.
771
- clockMs: ageMs
772
- });
773
- } else {
774
- out.push(...proceduralShapes(view, pos, fade, progress));
775
- }
776
- if (view.message) {
777
- const pxSize = projector && view.size !== void 0 ? Math.max(10, Math.round(view.size * projector.tileWidth)) : void 0;
778
- const family = fontFamily ?? "system-ui, sans-serif";
779
- const text = {
780
- type: "draw-text",
781
- text: view.message,
782
- position: pos,
783
- offsetY: -(0.15 + 0.55 * progress),
784
- color: view.color ?? node.textColor ?? DEFAULT_TEXT_COLOR,
785
- opacity: fade,
786
- font: `bold ${pxSize ?? 14}px ${family}`
787
- };
788
- out.push(text);
789
- }
790
- return out;
791
- }
792
- function expandFxLayer(node, epochNowMs, dim, projector, fontFamily) {
793
- if (!Array.isArray(node.items)) return [];
794
- const out = [];
795
- for (const item of node.items) {
796
- if (!item || typeof item.id !== "string") continue;
797
- out.push(...expandFxItem(resolveFxView(item, node.presets), node, epochNowMs, dim, projector, fontFamily));
798
- }
799
- return out;
800
- }
801
- function DrawFxLayer(_props) {
802
- return null;
803
- }
804
- var log = createLogger("almadar:ui:canvas-theme");
805
- var toneVar = (tone) => `--color-${DIAGRAM_TONE_COLOR_KEYS[tone]}`;
806
- var SERIES_TONES = ["series-1", "series-2", "series-3", "series-4", "series-5", "series-6", "series-7", "series-8"];
807
- var TONE_SET = new Set(DIAGRAM_TONES);
808
- function isDiagramTone(value) {
809
- return TONE_SET.has(value);
810
- }
811
- function colorCss(c) {
812
- return c.a >= 1 ? c.css : `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a})`;
813
- }
814
- function oneOf(value, allowed, fallback, name) {
815
- const hit = allowed.find((a) => a === value);
816
- if (hit !== void 0) return hit;
817
- if (value !== "") log.warn("invalid-theme-keyword", { var: name, value, allowed });
818
- return fallback;
819
- }
820
- var PLAIN_LENGTH = /^(-?[\d.]+)(px)?$/;
821
- var ScopeReader = class {
822
- constructor(scope) {
823
- this.scope = scope;
824
- this.style = getComputedStyle(scope);
825
- const doc = scope.ownerDocument;
826
- this.probe = doc.createElement("span");
827
- this.probe.style.position = "absolute";
828
- this.probe.style.visibility = "hidden";
829
- this.probe.style.pointerEvents = "none";
830
- scope.appendChild(this.probe);
831
- }
832
- scope;
833
- style;
834
- probe;
835
- dispose() {
836
- this.probe.remove();
837
- }
838
- raw(name) {
839
- return this.style.getPropertyValue(name).trim();
840
- }
841
- /** A length var in px: a plain value parses directly, a derived one (`calc`, `var`) through the probe. */
842
- length(name, fallback) {
843
- const raw = this.raw(name);
844
- const plain = PLAIN_LENGTH.exec(raw);
845
- if (plain) return Number(plain[1]);
846
- if (raw === "") return fallback;
847
- this.probe.style.width = `var(${name})`;
848
- const computed = PLAIN_LENGTH.exec(getComputedStyle(this.probe).width.trim());
849
- this.probe.style.width = "";
850
- if (computed) return Number(computed[1]);
851
- log.warn("unresolvable-theme-length", { var: name, raw });
852
- return fallback;
853
- }
854
- number(name, fallback) {
855
- const raw = this.raw(name);
856
- if (raw === "") return fallback;
857
- const n = Number(raw);
858
- if (Number.isFinite(n)) return n;
859
- log.warn("unresolvable-theme-number", { var: name, raw });
860
- return fallback;
861
- }
862
- /** A duration var in ms (`250ms`, `0.25s`, or a `var()` alias resolved through the probe). */
863
- durationMs(name, fallback) {
864
- const parse = (v) => {
865
- const m = /^([\d.]+)(ms|s)$/.exec(v.trim());
866
- return m ? Number(m[1]) * (m[2] === "s" ? 1e3 : 1) : null;
867
- };
868
- const raw = this.raw(name);
869
- const direct = parse(raw);
870
- if (direct !== null) return direct;
871
- if (raw === "") return fallback;
872
- this.probe.style.transitionDuration = `var(${name})`;
873
- const computed = parse(getComputedStyle(this.probe).transitionDuration.split(",")[0] ?? "");
874
- this.probe.style.transitionDuration = "";
875
- return computed ?? fallback;
876
- }
877
- color(name) {
878
- const raw = this.raw(name);
879
- return parseComputedColor(raw) ?? resolveThemeColor(`var(${name})`, this.scope);
880
- }
881
- shadow(name) {
882
- const raw = this.raw(name);
883
- if (raw === "" || raw === "none") return null;
884
- this.probe.style.boxShadow = `var(${name})`;
885
- const computed = getComputedStyle(this.probe).boxShadow.trim() || raw;
886
- this.probe.style.boxShadow = "";
887
- const colorMatch = /(rgba?\([^)]*\)|#[0-9a-f]{3,8}|oklch\([^)]*\))/i.exec(computed);
888
- const lengths = computed.replace(colorMatch?.[0] ?? "", "").trim().split(/\s+/).map((t) => PLAIN_LENGTH.exec(t)).filter((m) => m !== null).map((m) => Number(m[1]));
889
- if (lengths.length < 2) return null;
890
- const color = colorMatch ? parseComputedColor(colorMatch[0]) : null;
891
- return { offsetX: lengths[0], offsetY: lengths[1], blur: lengths[2] ?? 0, color: color ? colorCss(color) : "rgba(0, 0, 0, 0.25)" };
892
- }
893
- family(name, fallback) {
894
- return this.raw(name) || fallback;
895
- }
896
- };
897
- function dashList(raw, fallback) {
898
- if (raw === "") return fallback;
899
- const parts = raw.split(/[\s,]+/).map(Number);
900
- return parts.every((n) => Number.isFinite(n) && n >= 0) ? parts : fallback;
901
- }
902
- function prefersReducedMotion(scope) {
903
- const view = scope.ownerDocument.defaultView;
904
- return typeof view?.matchMedia === "function" && view.matchMedia("(prefers-reduced-motion: reduce)").matches;
905
- }
906
- function resolveCanvasTheme(scope) {
907
- const r = new ScopeReader(scope);
908
- try {
909
- const tones = {};
910
- for (const tone of DIAGRAM_TONES) {
911
- const c = r.color(toneVar(tone));
912
- tones[tone] = c ? colorCss(c) : "currentColor";
913
- }
914
- const surface = (name) => {
915
- const c = r.color(name);
916
- return c ? colorCss(c) : "transparent";
917
- };
918
- const ground = r.color("--surface-diagram");
919
- const text = {};
920
- const TEXT_FALLBACK = { xs: 12, sm: 14, base: 16, lg: 18, xl: 20, "2xl": 24 };
921
- for (const size of DIAGRAM_TEXT_SIZES) text[size] = r.length(`--text-${size}`, TEXT_FALLBACK[size]);
922
- const body = r.family("--font-family-body", r.family("--font-family", "system-ui, sans-serif"));
923
- return {
924
- ground: ground ? colorCss(ground) : "transparent",
925
- surfaces: {
926
- muted: surface("--color-muted"),
927
- card: surface("--color-card"),
928
- onPrimary: surface("--color-primary-foreground")
929
- },
930
- tones,
931
- series: SERIES_TONES.map((t) => tones[t]),
932
- strokes: {
933
- thin: r.length("--diagram-stroke-thin", 1),
934
- normal: r.length("--diagram-stroke-normal", 1.5),
935
- bold: r.length("--diagram-stroke-bold", 3)
936
- },
937
- lineCap: oneOf(r.raw("--diagram-line-cap"), ["butt", "round", "square"], "round", "--diagram-line-cap"),
938
- lineJoin: oneOf(r.raw("--diagram-line-join"), ["miter", "round", "bevel"], "round", "--diagram-line-join"),
939
- dash: dashList(r.raw("--diagram-dash"), [6, 4]),
940
- dot: dashList(r.raw("--diagram-dot"), [1, 4]),
941
- fillStyle: oneOf(r.raw("--diagram-fill-style"), ["solid", "tint", "outline", "hatch"], "tint", "--diagram-fill-style"),
942
- fillOpacity: r.number("--diagram-fill-opacity", 0.18),
943
- roughness: r.number("--diagram-roughness", 0),
944
- glow: r.number("--diagram-glow", 0),
945
- shadow: r.shadow("--diagram-shadow"),
946
- marker: oneOf(r.raw("--diagram-marker"), ["triangle", "open", "line", "dot"], "triangle", "--diagram-marker"),
947
- faces: {
948
- body,
949
- display: r.family("--font-family-display", body),
950
- mono: r.family("--font-family-mono", "ui-monospace, monospace")
951
- },
952
- label: {
953
- font: oneOf(r.raw("--diagram-label-font"), ["body", "display", "mono"], "body", "--diagram-label-font"),
954
- size: oneOf(r.raw("--diagram-label-size"), DIAGRAM_TEXT_SIZES, "sm", "--diagram-label-size"),
955
- weight: r.raw("--diagram-label-weight") || "500",
956
- uppercase: oneOf(r.raw("--diagram-label-case"), ["none", "uppercase"], "none", "--diagram-label-case") === "uppercase"
957
- },
958
- text,
959
- corner: r.length("--diagram-corner", 4),
960
- motion: {
961
- enabled: r.raw("--motion-enable") !== "off" && !prefersReducedMotion(scope),
962
- fastMs: r.durationMs("--duration-fast", 150),
963
- normalMs: r.durationMs("--duration-normal", 250),
964
- slowMs: r.durationMs("--duration-slow", 400),
965
- easing: r.raw("--easing-standard") || "ease"
966
- },
967
- scene: {
968
- roughness: r.number("--material-roughness", 0.6),
969
- metalness: r.number("--material-metalness", 0),
970
- flat: r.number("--material-flat", 0) >= 1,
971
- outline: r.number("--material-outline", 0),
972
- ambient: r.number("--light-ambient", 0.55),
973
- key: r.number("--light-key", 1),
974
- keyColor: (() => {
975
- const c = r.color("--light-key-color");
976
- return c ? colorCss(c) : "#ffffff";
977
- })(),
978
- fog: r.number("--scene-fog", 0)
979
- }
980
- };
981
- } finally {
982
- r.dispose();
983
- }
984
- }
985
- function withSeries(theme, series, scope) {
986
- if (!theme || !series || series.length === 0 || !scope) return theme;
987
- const colors = series.map((c, i) => markColor(theme, c, scope, SERIES_TONES[i % SERIES_TONES.length]));
988
- const tones = { ...theme.tones };
989
- SERIES_TONES.forEach((tone, i) => {
990
- tones[tone] = colors[i % colors.length];
991
- });
992
- return { ...theme, tones, series: SERIES_TONES.map((t) => tones[t]) };
993
- }
994
- function markColor(theme, value, scope, fallback) {
995
- if (value === void 0 || value === "") return theme.tones[fallback];
996
- if (isDiagramTone(value)) return theme.tones[value];
997
- if (value.startsWith("var(") || value.startsWith("color-mix(")) {
998
- const resolved = resolveThemeColor(value, scope);
999
- return resolved ? colorCss(resolved) : theme.tones[fallback];
1000
- }
1001
- return value;
1002
- }
1003
- function markStrokeWidth(theme, literal, role, fallback = "normal") {
1004
- return literal ?? theme.strokes[role ?? fallback];
1005
- }
1006
- function labelFont(theme, roles, literalPx, literalFamily) {
1007
- const px = literalPx ?? theme.text[roles.textSize ?? theme.label.size];
1008
- const family = literalFamily ?? theme.faces[roles.font ?? theme.label.font];
1009
- return { font: `${theme.label.weight} ${px}px ${family}`, px };
1010
- }
1011
- function labelText(theme, text, textCase = "theme") {
1012
- return theme.label.uppercase && textCase === "theme" ? text.toUpperCase() : text;
1013
- }
1014
- function fillLabel(ctx, theme, text, x, y) {
1015
- if (!text) return;
1016
- ctx.save();
1017
- ctx.strokeStyle = theme.ground;
1018
- ctx.lineWidth = Math.max(2, theme.text.xs * 0.3);
1019
- ctx.lineJoin = "round";
1020
- ctx.strokeText(text, x, y);
1021
- ctx.restore();
1022
- ctx.fillText(text, x, y);
1023
- }
1024
- function outlineStroke(stroke, fill, style, fillTone) {
1025
- return outlineCarriesFill(fill, style, fillTone) && fill !== void 0 ? fill : stroke;
1026
- }
1027
- function outlineCarriesFill(fill, style, fillTone) {
1028
- return style === "outline" && fill !== void 0 && fillTone !== "fill";
1029
- }
1030
- function applyLineCharacter(ctx, theme, strokeColor) {
1031
- ctx.lineCap = theme.lineCap;
1032
- ctx.lineJoin = theme.lineJoin;
1033
- if (theme.glow > 0) {
1034
- ctx.shadowColor = strokeColor;
1035
- ctx.shadowBlur = theme.glow;
1036
- ctx.shadowOffsetX = 0;
1037
- ctx.shadowOffsetY = 0;
1038
- }
1039
- }
1040
- function markDash(theme, dash) {
1041
- if (dash === "dashed") return theme.dash;
1042
- if (dash === "dotted") return theme.dot;
1043
- return [];
1044
- }
1045
- function wobble(x, y, k) {
1046
- const s = Math.sin(x * 12.9898 + y * 78.233 + k * 37.719) * 43758.5453;
1047
- return (s - Math.floor(s)) * 2 - 1;
1048
- }
1049
- function tracePolyline(ctx, theme, points, closed) {
1050
- ctx.beginPath();
1051
- if (points.length === 0) return;
1052
- const amp = theme.roughness;
1053
- const pts = closed ? [...points, points[0]] : [...points];
1054
- ctx.moveTo(pts[0].x + amp * wobble(pts[0].x, pts[0].y, 0), pts[0].y + amp * wobble(pts[0].y, pts[0].x, 1));
1055
- for (let i = 1; i < pts.length; i++) {
1056
- const a = pts[i - 1];
1057
- const b = pts[i];
1058
- if (amp === 0) {
1059
- ctx.lineTo(b.x, b.y);
1060
- continue;
1061
- }
1062
- const steps = Math.max(1, Math.round(Math.hypot(b.x - a.x, b.y - a.y) / 24));
1063
- for (let s = 1; s <= steps; s++) {
1064
- const t = s / steps;
1065
- const x = a.x + (b.x - a.x) * t;
1066
- const y = a.y + (b.y - a.y) * t;
1067
- ctx.lineTo(x + amp * wobble(x, y, 2), y + amp * wobble(y, x, 3));
1068
- }
1069
- }
1070
- if (closed) ctx.closePath();
1071
- }
1072
- function arcPoints(cx, cy, rx, ry, startRad = 0, endRad = Math.PI * 2) {
1073
- const steps = Math.max(12, Math.round(Math.abs(endRad - startRad) * Math.max(rx, ry) / 8));
1074
- const out = [];
1075
- for (let i = 0; i <= steps; i++) {
1076
- const t = startRad + (endRad - startRad) * i / steps;
1077
- out.push({ x: cx + rx * Math.cos(t), y: cy + ry * Math.sin(t) });
1078
- }
1079
- return out;
1080
- }
1081
- function fillMark(ctx, theme, color, style = theme.fillStyle) {
1082
- if (style === "outline") return;
1083
- ctx.save();
1084
- ctx.shadowBlur = 0;
1085
- ctx.shadowColor = "transparent";
1086
- if (theme.shadow) {
1087
- ctx.shadowColor = theme.shadow.color;
1088
- ctx.shadowOffsetX = theme.shadow.offsetX;
1089
- ctx.shadowOffsetY = theme.shadow.offsetY;
1090
- ctx.shadowBlur = theme.shadow.blur;
1091
- }
1092
- if (style === "hatch") {
1093
- ctx.clip();
1094
- const span = ctx.canvas.width + ctx.canvas.height;
1095
- ctx.strokeStyle = color;
1096
- ctx.lineWidth = theme.strokes.thin;
1097
- ctx.setLineDash([]);
1098
- ctx.beginPath();
1099
- for (let d = -span; d < span; d += 6) {
1100
- ctx.moveTo(d, 0);
1101
- ctx.lineTo(d + span, span);
1102
- }
1103
- ctx.stroke();
1104
- } else {
1105
- ctx.globalAlpha *= style === "tint" ? theme.fillOpacity : 1;
1106
- ctx.fillStyle = color;
1107
- ctx.fill();
1108
- }
1109
- ctx.restore();
1110
- }
1111
- function drawMarker(ctx, theme, x1, y1, x2, y2, color, width) {
1112
- const size = Math.max(8, width * 4);
1113
- const angle = Math.atan2(y2 - y1, x2 - x1);
1114
- const left = { x: x2 - size * Math.cos(angle - Math.PI / 6), y: y2 - size * Math.sin(angle - Math.PI / 6) };
1115
- const right = { x: x2 - size * Math.cos(angle + Math.PI / 6), y: y2 - size * Math.sin(angle + Math.PI / 6) };
1116
- ctx.save();
1117
- ctx.strokeStyle = color;
1118
- ctx.fillStyle = color;
1119
- ctx.lineWidth = width;
1120
- ctx.setLineDash([]);
1121
- switch (theme.marker) {
1122
- case "triangle": {
1123
- ctx.beginPath();
1124
- ctx.moveTo(x2, y2);
1125
- ctx.lineTo(left.x, left.y);
1126
- ctx.lineTo(right.x, right.y);
1127
- ctx.closePath();
1128
- ctx.fill();
1129
- break;
1130
- }
1131
- case "open":
1132
- case "line": {
1133
- ctx.beginPath();
1134
- ctx.moveTo(left.x, left.y);
1135
- ctx.lineTo(x2, y2);
1136
- ctx.lineTo(right.x, right.y);
1137
- if (theme.marker === "open") ctx.stroke();
1138
- else {
1139
- ctx.moveTo(x2 - size * 0.5 * Math.cos(angle + Math.PI / 2), y2 - size * 0.5 * Math.sin(angle + Math.PI / 2));
1140
- ctx.lineTo(x2 + size * 0.5 * Math.cos(angle + Math.PI / 2), y2 + size * 0.5 * Math.sin(angle + Math.PI / 2));
1141
- ctx.stroke();
1142
- }
1143
- break;
1144
- }
1145
- case "dot": {
1146
- ctx.beginPath();
1147
- ctx.arc(x2, y2, Math.max(2.5, width * 1.5), 0, Math.PI * 2);
1148
- ctx.fill();
1149
- break;
1150
- }
1151
- }
1152
- ctx.restore();
1153
- }
1154
- function useCanvasTheme(scopeRef) {
1155
- const { appliedTheme } = useTheme();
1156
- const scopeKey = JSON.stringify(useThemeScope());
1157
- const [state, setState] = useState({ theme: null, version: 0 });
1158
- useLayoutEffect(() => {
1159
- const scope = scopeRef.current;
1160
- if (!scope) return;
1161
- const theme = resolveCanvasTheme(scope);
1162
- setState((prev) => ({ theme, version: prev.version + 1 }));
1163
- }, [appliedTheme, scopeKey, scopeRef]);
1164
- return state;
1165
- }
1166
-
1167
- // src/lib/drawable/themeDrawables.ts
1168
- function opt(value, resolve) {
1169
- return value === void 0 ? void 0 : resolve(value);
1170
- }
1171
- function themeShape(node, resolve) {
1172
- return {
1173
- ...node,
1174
- ...node.fill !== void 0 ? { fill: resolve(node.fill) } : {},
1175
- ...node.stroke !== void 0 ? { stroke: resolve(node.stroke) } : {},
1176
- ...node.gradient ? { gradient: { ...node.gradient, stops: node.gradient.stops.map((s) => ({ ...s, color: resolve(s.color) })) } } : {},
1177
- ...node.fillPattern?.color !== void 0 ? { fillPattern: { ...node.fillPattern, color: resolve(node.fillPattern.color) } } : {},
1178
- ...node.shadow ? { shadow: { ...node.shadow, color: resolve(node.shadow.color) } } : {},
1179
- ...node.animation ? {
1180
- animation: {
1181
- ...node.animation,
1182
- keyframes: node.animation.keyframes.map((k) => ({
1183
- ...k,
1184
- ...k.fill !== void 0 ? { fill: resolve(k.fill) } : {},
1185
- ...k.stroke !== void 0 ? { stroke: resolve(k.stroke) } : {}
1186
- }))
1187
- }
1188
- } : {}
1189
- };
1190
- }
1191
- function themeText(node, resolve) {
1192
- return { ...node, color: resolve(node.color) };
1193
- }
1194
- function themeMaterial(material, resolve) {
1195
- if (!material) return material;
1196
- return {
1197
- ...material,
1198
- ...material.color !== void 0 ? { color: resolve(material.color) } : {},
1199
- ...material.emissive !== void 0 ? { emissive: resolve(material.emissive) } : {}
1200
- };
1201
- }
1202
- function resolveDrawableColors(nodes, resolve) {
1203
- return nodes.map((node) => {
1204
- switch (node.type) {
1205
- case "draw-shape":
1206
- return themeShape(node, resolve);
1207
- case "draw-text":
1208
- return themeText(node, resolve);
1209
- case "draw-group":
1210
- return { ...node, items: resolveDrawableColors(node.items, resolve) };
1211
- case "draw-shape-layer":
1212
- return { ...node, items: node.items.map((item) => themeShape(item, resolve)) };
1213
- case "draw-text-layer":
1214
- return { ...node, items: node.items.map((item) => themeText(item, resolve)) };
1215
- case "draw-fx-layer":
1216
- return {
1217
- ...node,
1218
- ...node.textColor !== void 0 ? { textColor: resolve(node.textColor) } : {},
1219
- ...node.presets ? {
1220
- presets: node.presets.map((p) => ({
1221
- ...p,
1222
- ...p.color !== void 0 ? { color: resolve(p.color) } : {},
1223
- ...p.color2 !== void 0 ? { color2: resolve(p.color2) } : {}
1224
- }))
1225
- } : {}
1226
- };
1227
- case "draw-mesh":
1228
- return {
1229
- ...node,
1230
- material: themeMaterial(node.material, resolve),
1231
- ...node.outline ? { outline: { ...node.outline, ...node.outline.color !== void 0 ? { color: resolve(node.outline.color) } : {} } } : {},
1232
- ...node.animation ? {
1233
- animation: {
1234
- ...node.animation,
1235
- keyframes: node.animation.keyframes.map((k) => ({
1236
- ...k,
1237
- ...k.color !== void 0 ? { color: resolve(k.color) } : {},
1238
- ...k.emissive !== void 0 ? { emissive: opt(k.emissive, resolve) } : {}
1239
- }))
1240
- }
1241
- } : {}
1242
- };
1243
- default:
1244
- return node;
1245
- }
1246
- });
1247
- }
1248
- function applySceneMaterials(nodes, theme) {
1249
- return nodes.map((node) => {
1250
- if (node.type === "draw-group") return { ...node, items: applySceneMaterials(node.items, theme) };
1251
- if (node.type !== "draw-mesh") return node;
1252
- const m = node.material ?? {};
1253
- const pbr = (m.kind ?? "standard") === "standard" || m.kind === "physical";
1254
- return {
1255
- ...node,
1256
- material: {
1257
- ...m,
1258
- ...pbr && m.roughness === void 0 ? { roughness: theme.scene.roughness } : {},
1259
- ...pbr && m.metalness === void 0 ? { metalness: theme.scene.metalness } : {},
1260
- ...m.flatShading === void 0 && theme.scene.flat ? { flatShading: true } : {}
1261
- },
1262
- ...node.outline === void 0 && theme.scene.outline > 0 ? { outline: { color: theme.tones.ink, width: theme.scene.outline * 0.02 } } : {}
1263
- };
1264
- });
1265
- }
1266
-
1267
- // src/lib/drawable/hitTest.ts
1268
- function shapeDrawnItem(n) {
1269
- if (n.shape !== "rect") return { pos: n.position, id: n.id };
1270
- return { pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotate };
1271
- }
1272
- function skinnedMeshDrawnItem(n) {
1273
- const mesh = n.mesh;
1274
- if (!mesh || n.bones.length === 0) return { pos: n.position, id: n.id };
1275
- const bindWorld = computeWorldMatrices(n.bones, {});
1276
- const curWorld = computeWorldMatrices(n.bones, resolveSkinPose(n));
1277
- const bounds = vertexBounds(skinVertices(mesh, bindWorld, curWorld));
1278
- if (!bounds) return { pos: n.position, id: n.id };
1279
- return {
1280
- pos: { ...n.position, x: n.position.x + bounds.minX, y: n.position.y + bounds.minY },
1281
- id: n.id,
1282
- anchor: "top-left",
1283
- width: bounds.maxX - bounds.minX,
1284
- height: bounds.maxY - bounds.minY
1285
- };
1286
- }
1287
- function collectDrawnItems(nodes) {
1288
- const out = [];
1289
- for (const n of nodes) {
1290
- switch (n.type) {
1291
- case "draw-sprite":
1292
- if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotation });
1293
- break;
1294
- case "draw-shape":
1295
- if (isValidScenePos(n.position)) out.push(shapeDrawnItem(n));
1296
- break;
1297
- case "draw-skinned-mesh":
1298
- if (isValidScenePos(n.position)) out.push(skinnedMeshDrawnItem(n));
1299
- break;
1300
- case "draw-text":
1301
- case "draw-group":
1302
- case "draw-mesh":
1303
- if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id });
1304
- break;
1305
- case "draw-sprite-layer":
1306
- for (const it of n.items) {
1307
- if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height, rotation: it.rotation });
1308
- }
1309
- break;
1310
- case "draw-shape-layer":
1311
- for (const it of n.items) {
1312
- if (isValidScenePos(it.position)) out.push(shapeDrawnItem(it));
1313
- }
1314
- break;
1315
- case "draw-text-layer":
1316
- for (const it of n.items) {
1317
- if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id });
1318
- }
1319
- break;
1320
- }
1321
- }
1322
- return out;
1323
- }
1324
- function buildHitIndex(items) {
1325
- const m = /* @__PURE__ */ new Map();
1326
- for (const it of items) {
1327
- if (it.id !== void 0) m.set(`${it.pos.x},${it.pos.y}`, it.id);
1328
- }
1329
- return m;
1330
- }
1331
- function withPreviewPosition(nodes, id, pos) {
1332
- return nodes.map((n) => {
1333
- if (n.type === "draw-sprite-layer" || n.type === "draw-shape-layer" || n.type === "draw-text-layer") {
1334
- if (!n.items.some((it) => it.id === id)) return n;
1335
- return { ...n, items: n.items.map((it) => it.id === id ? { ...it, position: pos } : it) };
1336
- }
1337
- if (n.type === "draw-group") {
1338
- if (!Array.isArray(n.items)) return n;
1339
- return { ...n, items: withPreviewPosition(n.items, id, pos) };
1340
- }
1341
- if (n.id === id && "position" in n) {
1342
- return { ...n, position: pos };
1343
- }
1344
- return n;
1345
- });
1346
- }
1347
- function hitTestSprites(items, projector, point) {
1348
- for (let i = items.length - 1; i >= 0; i--) {
1349
- const it = items[i];
1350
- if (it.id === void 0) continue;
1351
- const r = spriteRect(projector, { position: it.pos, anchor: it.anchor, width: it.width, height: it.height });
1352
- const test = it.rotation ? rotatePoint(point, { x: r.x + r.w / 2, y: r.y + r.h / 2 }, -it.rotation) : point;
1353
- if (test.x >= r.x && test.x <= r.x + r.w && test.y >= r.y && test.y <= r.y + r.h) return it.id;
1354
- }
1355
- return void 0;
1356
- }
1357
- function rotatePoint(p, center, radians) {
1358
- const cos = Math.cos(radians);
1359
- const sin = Math.sin(radians);
1360
- const dx = p.x - center.x;
1361
- const dy = p.y - center.y;
1362
- return { x: center.x + dx * cos - dy * sin, y: center.y + dx * sin + dy * cos };
1363
- }
1364
- function useOnScreen(ref, margin = "200px") {
1365
- const [intersecting, setIntersecting] = useState(true);
1366
- const [pageVisible, setPageVisible] = useState(true);
1367
- useEffect(() => {
1368
- const el = ref.current;
1369
- if (!el || typeof IntersectionObserver === "undefined") return;
1370
- const observer = new IntersectionObserver(([entry]) => setIntersecting(entry.isIntersecting), { rootMargin: margin });
1371
- observer.observe(el);
1372
- return () => observer.disconnect();
1373
- }, [ref, margin]);
1374
- useEffect(() => {
1375
- if (typeof document === "undefined") return;
1376
- const update = () => setPageVisible(document.visibilityState !== "hidden");
1377
- update();
1378
- document.addEventListener("visibilitychange", update);
1379
- return () => document.removeEventListener("visibilitychange", update);
1380
- }, []);
1381
- return intersecting && pageVisible;
1382
- }
1383
-
1384
- export { DrawFxLayer, DrawGroup, DrawMesh, DrawShape, DrawSkinnedMesh, DrawableRegistryContext, SPRITE_FALLBACK_FILL, SPRITE_FALLBACK_STROKE, applyLineCharacter, applyMeshAnimation, applySceneMaterials, applyShapeAnimation, arcPoints, buildHitIndex, clampSegments, collectDrawnItems, drawMarker, expandFxLayer, fillLabel, fillMark, getImageStatus, getOrLoadImage, hitTestSprites, isAnimatedGroup, isAnimatedMesh, isAnimatedShape, isValidScenePos, labelFont, labelText, markColor, markDash, markStrokeWidth, outlineCarriesFill, outlineStroke, paintShape, paintSkinnedMesh, polyhedronBounds, resolveDrawableColors, spriteAssetState, spriteRect, tracePolyline, useCanvasTheme, useOnScreen, withPreviewPosition, withSeries };