@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.
- package/dist/{ArbitraryClassCompiler-Mzabq-UB.d.ts → ArbitraryClassCompiler-CO_iASBn.d.ts} +99 -4
- package/dist/AvlGlyph-PIXU6QH5.js +5 -0
- package/dist/AvlStateMachine-CKGMECMG.js +8 -0
- package/dist/AvlTransitionDetail-QZX6G5KJ.js +10 -0
- package/dist/AvlTransitionExplainer-26WLEIC6.js +11 -0
- package/dist/BehaviorView-JLZ4PKWY.js +10 -0
- package/dist/{EventBusProvider-CVwjkV_2.d.ts → EventBusProvider-BFFHfN4O.d.ts} +12 -0
- package/dist/{FileTree-BCFnBEuQ.d.ts → FileTree-B3GDAjaQ.d.ts} +131 -4
- package/dist/FlowCanvas-RPII4V24.js +23 -0
- package/dist/{BehaviorValueFrame-SSEMEBTG.css → FlowCanvas-VWUPMBKB.css} +189 -191
- package/dist/{GameAudioProvider-Cm9BnvmP.d.ts → GameAudioProvider-D7wo5ryN.d.ts} +5 -8
- package/dist/KernelEngineContext-CPeWQMAz.d.ts +46 -0
- package/dist/LayersPanel-M2LHWUFF.js +6 -0
- package/dist/ModuleCard-NJD6JQGD.js +6 -0
- package/dist/OrbInspector-OWWKPOBF.js +23 -0
- package/dist/{TraitValueFrame-4G3KOUBR.css → OrbInspector-VMTMZHNQ.css} +189 -191
- package/dist/{Select-mDZIwNqN.d.ts → Select-C2Uq6t86.d.ts} +17 -31
- package/dist/ServerBridge-Bqsj-lOU.d.ts +124 -0
- package/dist/{FlowCanvas-3JRMNJLV.css → UISlotRenderer-BIS6KT7T.css} +189 -191
- package/dist/UISlotRenderer-PY7FIJXN.js +23 -0
- package/dist/auth/browser/index.js +1 -0
- package/dist/auth/react/index.d.ts +8 -1
- package/dist/auth/react/index.js +40 -2
- package/dist/avl/index.css +189 -191
- package/dist/avl/index.d.ts +107 -85
- package/dist/avl/index.js +170 -39
- package/dist/{chunk-P4LNHAFI.js → chunk-2WGR4TDJ.js} +465 -36
- package/dist/{chunk-GKIFONTE.js → chunk-3S54FWRC.js} +2 -2
- package/dist/{chunk-KVQS4GXU.js → chunk-4YJ53G7S.js} +18 -8
- package/dist/{chunk-MBQAMMSE.js → chunk-4YXBKHHM.js} +269 -658
- package/dist/{chunk-YDNJLLG6.js → chunk-57DC34LY.js} +19 -10
- package/dist/{chunk-FP3WIKTC.js → chunk-7N6ZPHQ5.js} +9 -1
- package/dist/{chunk-AILY3XPS.js → chunk-AE7VCQB6.js} +5 -6
- package/dist/{chunk-L677XGY3.js → chunk-AGVSO4WY.js} +4 -5
- package/dist/{chunk-FAJDTHWC.js → chunk-AGXD77SL.js} +2 -2
- package/dist/chunk-AU7O65OX.js +66 -0
- package/dist/{chunk-DFNZUYX4.js → chunk-FAKU5F62.js} +273 -29
- package/dist/{chunk-U6QRZASX.js → chunk-ILQXJ2AR.js} +1 -1
- package/dist/chunk-M74BCDBQ.js +490 -0
- package/dist/{chunk-GYTPOFVC.js → chunk-MS4K3K2R.js} +12095 -13329
- package/dist/{chunk-SGM3FASH.js → chunk-OWNG4JZI.js} +13 -12
- package/dist/{chunk-VFF5OO47.js → chunk-PCR37T3U.js} +15 -38
- package/dist/{chunk-SJGJJKBY.js → chunk-PRLHKBXG.js} +5 -3
- package/dist/{chunk-R5O5AUPI.js → chunk-PRXQGGCO.js} +93 -86
- package/dist/{chunk-42FY4RYA.js → chunk-REXYVBUO.js} +2 -2
- package/dist/{chunk-EQAMU2ZC.js → chunk-UTDC2NEA.js} +1 -1
- package/dist/{chunk-73SRAB4P.js → chunk-UU57VNS2.js} +2 -2
- package/dist/{chunk-TESBIVUA.js → chunk-VHC2M26B.js} +2 -2
- package/dist/{chunk-L2DEKY4J.js → chunk-VO2TTLS5.js} +3 -6
- package/dist/{chunk-2PY54Z44.js → chunk-VUIACGDU.js} +4 -5
- package/dist/{chunk-DLZF4PVE.js → chunk-YYIHRIDH.js} +3 -3
- package/dist/{chunk-DYEKAA4L.js → chunk-ZDRDJKYB.js} +243 -252
- package/dist/components/index.css +189 -191
- package/dist/components/index.d.ts +739 -289
- package/dist/components/index.js +25 -28
- package/dist/context/index.d.ts +2 -3
- package/dist/context/index.js +4 -3
- package/dist/core.d.ts +95 -19
- package/dist/core.js +2 -1
- package/dist/design-classes/index.cjs +3 -1
- package/dist/design-classes/index.js +3 -1
- package/dist/{fx-CmQjnHmT.d.ts → fx-Br8zjvu9.d.ts} +6 -6
- package/dist/hooks/index.d.ts +40 -5
- package/dist/hooks/index.js +5 -4
- package/dist/index.d.ts +40 -114
- package/dist/index.js +174 -34
- package/dist/kernel-client-JW6OH5FX.js +537 -0
- package/dist/kernel-wire-DGAySGhX.d.ts +95 -0
- package/dist/lib/index.d.ts +3 -4
- package/dist/lib/index.js +4 -4
- package/dist/{prism-AIWGN2X5.js → prism-X5YWKXO5.js} +5 -3
- package/dist/providers/index.css +189 -191
- package/dist/providers/index.d.ts +41 -28
- package/dist/providers/index.js +19 -24
- package/dist/renderer/index.d.ts +0 -2
- package/dist/renderer/index.js +1 -0
- package/dist/runtime/index.css +189 -191
- package/dist/runtime/index.d.ts +57 -253
- package/dist/runtime/index.js +18 -24
- package/dist/ssr/index.cjs +2643 -535
- package/dist/ssr/index.d.cts +0 -23
- package/dist/ssr/index.d.ts +0 -23
- package/dist/ssr/index.js +2639 -535
- package/dist/storage/browser/index.js +1 -0
- package/dist/test-support.d.ts +15 -8
- package/dist/test-support.js +91 -24
- package/dist/{paintDispatch-ChW5mVuK.d.ts → verificationRegistry-oopV1J1n.d.ts} +132 -30
- package/package.json +14 -38
- package/src/core/lib/band-shapes.json +7 -0
- package/src/core/locales/ar.json +18 -5
- package/src/core/locales/en.json +18 -5
- package/src/core/locales/sl.json +18 -5
- package/tailwind-preset.cjs +30 -1
- package/dist/AvlGlyph-JKJOAH23.js +0 -6
- package/dist/AvlStateMachine-PI4YGREK.js +0 -8
- package/dist/AvlTransitionDetail-ZH7V24UG.js +0 -12
- package/dist/AvlTransitionExplainer-ZSRT7L6Y.js +0 -13
- package/dist/BehaviorValueFrame-6RUJXT4A.js +0 -29
- package/dist/BehaviorView-RFEE5J6E.js +0 -10
- package/dist/Canvas3DHost-_Y-5uLM_.d.ts +0 -552
- package/dist/FlowCanvas-STDC4OWK.js +0 -27
- package/dist/KernelEngineContext-BOCQoFwk.d.ts +0 -43
- package/dist/LayersPanel-BBQ54IVG.js +0 -7
- package/dist/ModuleCard-3TT2X7IW.js +0 -7
- package/dist/OrbInspector-K6T6O7GI.js +0 -27
- package/dist/OrbInspector-MHLJ6OEE.css +0 -1756
- package/dist/ServerBridge-Cm1On51b.d.ts +0 -233
- package/dist/TraitValueFrame-2PJGLLVI.js +0 -28
- package/dist/UISlotRenderer-JKFSX24W.js +0 -27
- package/dist/UISlotRenderer-KVFO6J7R.css +0 -1756
- package/dist/UserContext-DqWeZkUZ.d.ts +0 -100
- package/dist/avl-3d-context-BIRKWpaL.d.ts +0 -204
- package/dist/avl-schema-parser-CtJxJ9KU.d.ts +0 -132
- package/dist/avl-zoom-state-CKMVuBFg.d.ts +0 -17
- package/dist/chunk-2QOH2HWM.js +0 -95
- package/dist/chunk-6P3MWXYE.js +0 -440
- package/dist/chunk-B4BU77LT.js +0 -432
- package/dist/chunk-DJ433ET5.js +0 -1327
- package/dist/chunk-DZ42OJQC.js +0 -176
- package/dist/chunk-EOWMARUB.js +0 -16
- package/dist/chunk-FIW6WN23.js +0 -508
- package/dist/chunk-GAR5TQ5B.js +0 -199
- package/dist/chunk-PC7K4SK7.js +0 -1384
- package/dist/chunk-ZO6MXAS3.js +0 -69
- package/dist/kernel-client-ZH4PSMCN.js +0 -367
- package/dist/kernel-wire-B4S8pnP3.d.ts +0 -65
- package/dist/three/index.css +0 -503
- package/dist/three/index.d.ts +0 -1185
- package/dist/three/index.js +0 -3896
- package/dist/useKeyboardRouter-Dsq553Ur.d.ts +0 -42
- package/dist/verificationRegistry-CabxhfTv.d.ts +0 -122
package/dist/chunk-PC7K4SK7.js
DELETED
|
@@ -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 };
|