@almadar/ui 5.148.0 → 5.149.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/{GameAudioProvider-CPGwD49P.d.cts → GameAudioProvider-B48iXwz3.d.ts} +2 -50
- package/dist/{GameAudioProvider-CPGwD49P.d.ts → GameAudioProvider-CQAdPreB.d.cts} +2 -50
- package/dist/avl/index.cjs +438 -13
- package/dist/avl/index.js +438 -13
- package/dist/{avl-schema-parser-DVmrgdwc.d.cts → avl-schema-parser-CVzkNzg7.d.cts} +18 -9
- package/dist/{avl-schema-parser-BRJ77Yze.d.ts → avl-schema-parser-Cx_4SVg9.d.ts} +18 -9
- package/dist/{cn-BAn68sNO.d.cts → cn-BnAJZcNb.d.cts} +2 -8
- package/dist/{cn-CWxxLkri.d.ts → cn-DJTUjk1M.d.ts} +2 -8
- package/dist/components/index.cjs +448 -16
- package/dist/components/index.d.cts +269 -95
- package/dist/components/index.d.ts +269 -95
- package/dist/components/index.js +444 -18
- package/dist/lib/drawable/three/index.cjs +56 -29
- package/dist/lib/drawable/three/index.d.cts +4 -3
- package/dist/lib/drawable/three/index.d.ts +4 -3
- package/dist/lib/drawable/three/index.js +56 -29
- package/dist/lib/index.d.cts +3 -2
- package/dist/lib/index.d.ts +3 -2
- package/dist/{paintDispatch-Cb_hQj4Y.d.ts → paintDispatch-BjZjUbcb.d.cts} +63 -69
- package/dist/{paintDispatch-Cb_hQj4Y.d.cts → paintDispatch-CxdLjHQq.d.ts} +63 -69
- package/dist/providers/index.cjs +438 -13
- package/dist/providers/index.d.cts +2 -1
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/index.js +438 -13
- package/dist/runtime/index.cjs +438 -13
- package/dist/runtime/index.js +438 -13
- package/dist/types-B3nHgnMG.d.cts +51 -0
- package/dist/types-B3nHgnMG.d.ts +51 -0
- package/package.json +3 -3
package/dist/providers/index.cjs
CHANGED
|
@@ -10375,9 +10375,10 @@ function Canvas({
|
|
|
10375
10375
|
drawables: [...drawables ?? [], ...childDrawables],
|
|
10376
10376
|
isLoading,
|
|
10377
10377
|
cameraMode: to3DCameraMode(camera?.mode),
|
|
10378
|
-
...zoom !== void 0 ? {
|
|
10378
|
+
...zoom !== void 0 ? { zoom } : {},
|
|
10379
10379
|
...camera?.fov !== void 0 ? { fov: camera.fov } : {},
|
|
10380
10380
|
...camera?.azimuth !== void 0 ? { azimuth: camera.azimuth } : {},
|
|
10381
|
+
...camera?.elevation !== void 0 ? { elevation: camera.elevation } : {},
|
|
10381
10382
|
...camera?.target !== void 0 ? { followTarget: camera.target } : {},
|
|
10382
10383
|
unitScale,
|
|
10383
10384
|
backgroundColor,
|
|
@@ -14906,23 +14907,188 @@ var init_BehaviorView = __esm({
|
|
|
14906
14907
|
BehaviorView.displayName = "BehaviorView";
|
|
14907
14908
|
}
|
|
14908
14909
|
});
|
|
14909
|
-
|
|
14910
|
+
function LearningScene3D({
|
|
14911
|
+
className,
|
|
14912
|
+
width = 600,
|
|
14913
|
+
height = 400,
|
|
14914
|
+
title,
|
|
14915
|
+
backgroundColor,
|
|
14916
|
+
drawables,
|
|
14917
|
+
camera,
|
|
14918
|
+
lighting,
|
|
14919
|
+
post,
|
|
14920
|
+
showGrid = false,
|
|
14921
|
+
shadows,
|
|
14922
|
+
interactive,
|
|
14923
|
+
isLoading,
|
|
14924
|
+
error,
|
|
14925
|
+
onItemClick
|
|
14926
|
+
}) {
|
|
14927
|
+
const instanceId = React87.useId().replace(/[^a-zA-Z0-9]/g, "");
|
|
14928
|
+
const clickEvent = onItemClick ? `LEARNING_SCENE_3D.ITEM_CLICK.${instanceId}` : void 0;
|
|
14929
|
+
const onItemClickRef = React87.useRef(onItemClick);
|
|
14930
|
+
onItemClickRef.current = onItemClick;
|
|
14931
|
+
useEventListener(`UI:${clickEvent ?? "LEARNING_SCENE_3D.ITEM_CLICK.__disabled"}`, (event) => {
|
|
14932
|
+
const unitId = event.payload?.unitId;
|
|
14933
|
+
if (typeof unitId === "string") onItemClickRef.current?.(unitId);
|
|
14934
|
+
});
|
|
14935
|
+
const props3d = {
|
|
14936
|
+
drawables,
|
|
14937
|
+
isLoading,
|
|
14938
|
+
error: error ? error.message : null,
|
|
14939
|
+
cameraMode: camera?.mode ?? "perspective",
|
|
14940
|
+
...camera?.zoom !== void 0 ? { zoom: camera.zoom } : {},
|
|
14941
|
+
...camera?.fov !== void 0 ? { fov: camera.fov } : {},
|
|
14942
|
+
...camera?.azimuth !== void 0 ? { azimuth: camera.azimuth } : {},
|
|
14943
|
+
...camera?.elevation !== void 0 ? { elevation: camera.elevation } : {},
|
|
14944
|
+
...camera?.target !== void 0 ? { followTarget: camera.target } : {},
|
|
14945
|
+
backgroundColor,
|
|
14946
|
+
showGrid,
|
|
14947
|
+
...shadows !== void 0 ? { shadows } : {},
|
|
14948
|
+
...interactive !== void 0 ? { controlsEnabled: interactive } : {},
|
|
14949
|
+
lighting,
|
|
14950
|
+
post,
|
|
14951
|
+
...clickEvent !== void 0 ? { unitClickEvent: clickEvent } : {}
|
|
14952
|
+
};
|
|
14953
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
14954
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
14955
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { width, height, display: "flex" }, children: /* @__PURE__ */ jsxRuntime.jsx(React87.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx(Canvas3DHost2, { ...props3d }) }) })
|
|
14956
|
+
] }) });
|
|
14957
|
+
}
|
|
14958
|
+
function meshSphere(id, x, y, z, radius, color, opts) {
|
|
14959
|
+
return {
|
|
14960
|
+
type: "draw-mesh",
|
|
14961
|
+
...id !== void 0 ? { id } : {},
|
|
14962
|
+
shape: opts?.shape ?? "sphere",
|
|
14963
|
+
position: { x, y, z },
|
|
14964
|
+
radius,
|
|
14965
|
+
pivot: "center",
|
|
14966
|
+
segments: opts?.segments ?? 24,
|
|
14967
|
+
material: { color, ...opts?.material },
|
|
14968
|
+
...opts?.opacity !== void 0 ? { opacity: opts.opacity } : {}
|
|
14969
|
+
};
|
|
14970
|
+
}
|
|
14971
|
+
function axisRotation(from, to) {
|
|
14972
|
+
const wx = to[0] - from[0];
|
|
14973
|
+
const wy = to[2] - from[2];
|
|
14974
|
+
const wz = to[1] - from[1];
|
|
14975
|
+
const len = Math.sqrt(wx * wx + wy * wy + wz * wz);
|
|
14976
|
+
const tilt = Math.acos(Math.min(1, Math.max(-1, len > 0 ? wy / len : 1)));
|
|
14977
|
+
return [0, Math.atan2(wz, -wx), tilt];
|
|
14978
|
+
}
|
|
14979
|
+
function segmentLength(from, to) {
|
|
14980
|
+
const dx = to[0] - from[0];
|
|
14981
|
+
const dy = to[1] - from[1];
|
|
14982
|
+
const dz = to[2] - from[2];
|
|
14983
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
14984
|
+
}
|
|
14985
|
+
function cylinderBetween(from, to, radius, color) {
|
|
14986
|
+
const len = segmentLength(from, to);
|
|
14987
|
+
if (len < 1e-6) return null;
|
|
14988
|
+
return {
|
|
14989
|
+
type: "draw-mesh",
|
|
14990
|
+
shape: "cylinder",
|
|
14991
|
+
position: { x: (from[0] + to[0]) / 2, y: (from[1] + to[1]) / 2, z: (from[2] + to[2]) / 2 },
|
|
14992
|
+
radius,
|
|
14993
|
+
height: len,
|
|
14994
|
+
rotation: axisRotation(from, to),
|
|
14995
|
+
pivot: "center",
|
|
14996
|
+
segments: 12,
|
|
14997
|
+
material: { color }
|
|
14998
|
+
};
|
|
14999
|
+
}
|
|
15000
|
+
function arrowBetween(from, to, color, shaftRadius = 0.08) {
|
|
15001
|
+
const len = segmentLength(from, to);
|
|
15002
|
+
if (len < 1e-6) return null;
|
|
15003
|
+
const tipLen = Math.min(shaftRadius * 8, len * 0.35);
|
|
15004
|
+
const k = (len - tipLen) / len;
|
|
15005
|
+
const delta = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];
|
|
15006
|
+
const shaftEnd = [delta[0] * k, delta[1] * k, delta[2] * k];
|
|
15007
|
+
const tipStart = shaftEnd;
|
|
15008
|
+
const tipEnd = delta;
|
|
15009
|
+
const shaft = cylinderBetween([0, 0, 0], shaftEnd, shaftRadius, color);
|
|
15010
|
+
const tipLenActual = segmentLength(tipStart, tipEnd);
|
|
15011
|
+
const tip = {
|
|
15012
|
+
type: "draw-mesh",
|
|
15013
|
+
shape: "cone",
|
|
15014
|
+
position: {
|
|
15015
|
+
x: (tipStart[0] + tipEnd[0]) / 2,
|
|
15016
|
+
y: (tipStart[1] + tipEnd[1]) / 2,
|
|
15017
|
+
z: (tipStart[2] + tipEnd[2]) / 2
|
|
15018
|
+
},
|
|
15019
|
+
radius: shaftRadius * 3,
|
|
15020
|
+
height: tipLenActual,
|
|
15021
|
+
rotation: axisRotation(tipStart, tipEnd),
|
|
15022
|
+
pivot: "center",
|
|
15023
|
+
segments: 12,
|
|
15024
|
+
material: { color }
|
|
15025
|
+
};
|
|
15026
|
+
return {
|
|
15027
|
+
type: "draw-group",
|
|
15028
|
+
position: { x: from[0], y: from[1], z: from[2] },
|
|
15029
|
+
items: tipLenActual < 1e-6 ? shaft ? [shaft] : [] : shaft ? [shaft, tip] : [tip]
|
|
15030
|
+
};
|
|
15031
|
+
}
|
|
15032
|
+
function billboardLabel(text, x, y, z, opts) {
|
|
15033
|
+
return {
|
|
15034
|
+
type: "draw-text",
|
|
15035
|
+
text,
|
|
15036
|
+
position: { x, y, z },
|
|
15037
|
+
color: opts?.color ?? "#111827"
|
|
15038
|
+
};
|
|
15039
|
+
}
|
|
15040
|
+
function labelColorForBackground(backgroundColor) {
|
|
15041
|
+
const m = /^#(?:([0-9a-f]{3})|([0-9a-f]{6}))$/i.exec(backgroundColor ?? "");
|
|
15042
|
+
if (!m) return "#111827";
|
|
15043
|
+
const hex = m[1] !== void 0 ? m[1].split("").map((c) => c + c).join("") : m[2];
|
|
15044
|
+
const r = parseInt(hex.slice(0, 2), 16) / 255;
|
|
15045
|
+
const g = parseInt(hex.slice(2, 4), 16) / 255;
|
|
15046
|
+
const b = parseInt(hex.slice(4, 6), 16) / 255;
|
|
15047
|
+
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
15048
|
+
return luminance < 0.5 ? "#e5e7eb" : "#111827";
|
|
15049
|
+
}
|
|
15050
|
+
function get3DClickPayload(onShapeClick, idToIndex) {
|
|
15051
|
+
if (!onShapeClick) return void 0;
|
|
15052
|
+
return (id) => onShapeClick({ id, index: idToIndex.get(id) ?? -1 });
|
|
15053
|
+
}
|
|
15054
|
+
var Canvas3DHost2;
|
|
15055
|
+
var init_learningScene3D = __esm({
|
|
15056
|
+
"components/learning/molecules/learningScene3D.tsx"() {
|
|
15057
|
+
"use client";
|
|
15058
|
+
init_atoms();
|
|
15059
|
+
init_Stack();
|
|
15060
|
+
init_useEventBus();
|
|
15061
|
+
Canvas3DHost2 = React87.lazy(
|
|
15062
|
+
() => import('@almadar/ui/components/molecules/game/three').then((m) => ({ default: m.Canvas3DHost }))
|
|
15063
|
+
);
|
|
15064
|
+
LearningScene3D.displayName = "LearningScene3D";
|
|
15065
|
+
}
|
|
15066
|
+
});
|
|
15067
|
+
var biologyLog, BiologyCanvas;
|
|
14910
15068
|
var init_BiologyCanvas = __esm({
|
|
14911
15069
|
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
14912
15070
|
"use client";
|
|
14913
15071
|
init_atoms();
|
|
14914
15072
|
init_Stack();
|
|
14915
15073
|
init_LearningCanvas();
|
|
15074
|
+
init_learningScene3D();
|
|
15075
|
+
biologyLog = logger.createLogger("almadar:ui:biology-canvas");
|
|
14916
15076
|
BiologyCanvas = ({
|
|
14917
15077
|
className,
|
|
14918
15078
|
width = 600,
|
|
14919
15079
|
height = 400,
|
|
14920
15080
|
title,
|
|
14921
15081
|
backgroundColor,
|
|
15082
|
+
mode = "2d",
|
|
15083
|
+
camera,
|
|
15084
|
+
lighting,
|
|
15085
|
+
post,
|
|
14922
15086
|
nodes = [],
|
|
14923
15087
|
edges = [],
|
|
14924
15088
|
shapes = [],
|
|
14925
|
-
|
|
15089
|
+
showGrid,
|
|
15090
|
+
shadows,
|
|
15091
|
+
interactive,
|
|
14926
15092
|
animate = false,
|
|
14927
15093
|
onShapeClick,
|
|
14928
15094
|
isLoading,
|
|
@@ -14983,6 +15149,75 @@ var init_BiologyCanvas = __esm({
|
|
|
14983
15149
|
out.push(...shapes);
|
|
14984
15150
|
return out;
|
|
14985
15151
|
}, [nodes, edges, shapes]);
|
|
15152
|
+
const drawables3D = React87.useMemo(() => {
|
|
15153
|
+
if (mode !== "3d") return [];
|
|
15154
|
+
if (shapes.length > 0) {
|
|
15155
|
+
biologyLog.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
15156
|
+
}
|
|
15157
|
+
const out = [];
|
|
15158
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
15159
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
15160
|
+
for (const n of nodes) {
|
|
15161
|
+
if (n.id) nodeById.set(n.id, n);
|
|
15162
|
+
}
|
|
15163
|
+
for (const e of edges) {
|
|
15164
|
+
const a = nodeById.get(e.from);
|
|
15165
|
+
const b = nodeById.get(e.to);
|
|
15166
|
+
if (!a || !b) continue;
|
|
15167
|
+
const edgeRadius = Math.max(0.04, Math.min(a.radius ?? 0.5, b.radius ?? 0.5) * 0.12);
|
|
15168
|
+
const edge = cylinderBetween([a.x, a.y, a.z ?? 0], [b.x, b.y, b.z ?? 0], edgeRadius, e.color ?? "#9ca3af");
|
|
15169
|
+
if (edge) out.push(edge);
|
|
15170
|
+
if (e.label) {
|
|
15171
|
+
out.push(
|
|
15172
|
+
billboardLabel(
|
|
15173
|
+
e.label,
|
|
15174
|
+
(a.x + b.x) / 2,
|
|
15175
|
+
(a.y + b.y) / 2,
|
|
15176
|
+
((a.z ?? 0) + (b.z ?? 0)) / 2,
|
|
15177
|
+
{ color: labelColor }
|
|
15178
|
+
)
|
|
15179
|
+
);
|
|
15180
|
+
}
|
|
15181
|
+
}
|
|
15182
|
+
for (const n of nodes) {
|
|
15183
|
+
const radius = n.radius ?? 0.5;
|
|
15184
|
+
const nz = n.z ?? 0;
|
|
15185
|
+
out.push(meshSphere(n.id, n.x, n.y, nz, radius, n.color ?? "#16a34a", { shape: n.shape, ...n.opacity !== void 0 ? { opacity: n.opacity } : {} }));
|
|
15186
|
+
if (n.label) {
|
|
15187
|
+
out.push(billboardLabel(n.label, n.x, n.y, nz + radius, { color: labelColor }));
|
|
15188
|
+
}
|
|
15189
|
+
}
|
|
15190
|
+
return out;
|
|
15191
|
+
}, [mode, nodes, edges, shapes, backgroundColor]);
|
|
15192
|
+
const nodeIndexById = React87.useMemo(() => {
|
|
15193
|
+
const m = /* @__PURE__ */ new Map();
|
|
15194
|
+
nodes.forEach((n, i) => {
|
|
15195
|
+
if (n.id) m.set(n.id, i);
|
|
15196
|
+
});
|
|
15197
|
+
return m;
|
|
15198
|
+
}, [nodes]);
|
|
15199
|
+
if (mode === "3d") {
|
|
15200
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15201
|
+
LearningScene3D,
|
|
15202
|
+
{
|
|
15203
|
+
className,
|
|
15204
|
+
width,
|
|
15205
|
+
height,
|
|
15206
|
+
title,
|
|
15207
|
+
backgroundColor,
|
|
15208
|
+
drawables: drawables3D,
|
|
15209
|
+
camera,
|
|
15210
|
+
lighting,
|
|
15211
|
+
post,
|
|
15212
|
+
showGrid,
|
|
15213
|
+
shadows,
|
|
15214
|
+
interactive,
|
|
15215
|
+
isLoading,
|
|
15216
|
+
error,
|
|
15217
|
+
onItemClick: get3DClickPayload(onShapeClick, nodeIndexById)
|
|
15218
|
+
}
|
|
15219
|
+
);
|
|
15220
|
+
}
|
|
14986
15221
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
14987
15222
|
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
14988
15223
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -14992,7 +15227,7 @@ var init_BiologyCanvas = __esm({
|
|
|
14992
15227
|
height,
|
|
14993
15228
|
backgroundColor,
|
|
14994
15229
|
shapes: derivedShapes,
|
|
14995
|
-
interactive,
|
|
15230
|
+
interactive: interactive ?? false,
|
|
14996
15231
|
animate,
|
|
14997
15232
|
onShapeClick,
|
|
14998
15233
|
isLoading,
|
|
@@ -21832,24 +22067,41 @@ var init_ChatBar = __esm({
|
|
|
21832
22067
|
ChatBar.displayName = "ChatBar";
|
|
21833
22068
|
}
|
|
21834
22069
|
});
|
|
21835
|
-
|
|
22070
|
+
function bondPerpendicular(a, b) {
|
|
22071
|
+
const dx = b[0] - a[0];
|
|
22072
|
+
const dy = b[1] - a[1];
|
|
22073
|
+
const px = dy;
|
|
22074
|
+
const py = -dx;
|
|
22075
|
+
const len = Math.sqrt(px * px + py * py);
|
|
22076
|
+
if (len < 1e-6) return [1, 0, 0];
|
|
22077
|
+
return [px / len, py / len, 0];
|
|
22078
|
+
}
|
|
22079
|
+
var chemistryLog, ChemistryCanvas;
|
|
21836
22080
|
var init_ChemistryCanvas = __esm({
|
|
21837
22081
|
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
21838
22082
|
"use client";
|
|
21839
22083
|
init_atoms();
|
|
21840
22084
|
init_Stack();
|
|
21841
22085
|
init_LearningCanvas();
|
|
22086
|
+
init_learningScene3D();
|
|
22087
|
+
chemistryLog = logger.createLogger("almadar:ui:chemistry-canvas");
|
|
21842
22088
|
ChemistryCanvas = ({
|
|
21843
22089
|
className,
|
|
21844
22090
|
width = 600,
|
|
21845
22091
|
height = 400,
|
|
21846
22092
|
title,
|
|
21847
22093
|
backgroundColor,
|
|
22094
|
+
mode = "2d",
|
|
22095
|
+
camera,
|
|
22096
|
+
lighting,
|
|
22097
|
+
post,
|
|
21848
22098
|
atoms = [],
|
|
21849
22099
|
bonds = [],
|
|
21850
22100
|
arrows = [],
|
|
21851
22101
|
shapes = [],
|
|
21852
|
-
|
|
22102
|
+
showGrid,
|
|
22103
|
+
shadows,
|
|
22104
|
+
interactive,
|
|
21853
22105
|
animate = false,
|
|
21854
22106
|
onShapeClick,
|
|
21855
22107
|
isLoading,
|
|
@@ -21928,6 +22180,88 @@ var init_ChemistryCanvas = __esm({
|
|
|
21928
22180
|
out.push(...shapes);
|
|
21929
22181
|
return out;
|
|
21930
22182
|
}, [atoms, bonds, arrows, shapes]);
|
|
22183
|
+
const drawables3D = React87.useMemo(() => {
|
|
22184
|
+
if (mode !== "3d") return [];
|
|
22185
|
+
if (shapes.length > 0) {
|
|
22186
|
+
chemistryLog.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
22187
|
+
}
|
|
22188
|
+
const out = [];
|
|
22189
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
22190
|
+
const atomById = /* @__PURE__ */ new Map();
|
|
22191
|
+
for (const a of atoms) {
|
|
22192
|
+
if (a.id) atomById.set(a.id, a);
|
|
22193
|
+
}
|
|
22194
|
+
for (const b of bonds) {
|
|
22195
|
+
const a = atomById.get(b.from);
|
|
22196
|
+
const c = atomById.get(b.to);
|
|
22197
|
+
if (!a || !c) continue;
|
|
22198
|
+
const color = b.color ?? "#6b7280";
|
|
22199
|
+
const from = [a.x, a.y, a.z ?? 0];
|
|
22200
|
+
const to = [c.x, c.y, c.z ?? 0];
|
|
22201
|
+
const perp = bondPerpendicular(from, to);
|
|
22202
|
+
const bondRadius = Math.max(0.06, Math.min(a.radius ?? 0.45, c.radius ?? 0.45) * 0.22);
|
|
22203
|
+
const step = bondRadius * 2.2;
|
|
22204
|
+
const offsets = b.type === "double" ? [-step, step] : b.type === "triple" ? [-step, 0, step] : [0];
|
|
22205
|
+
for (const off of offsets) {
|
|
22206
|
+
const bond = cylinderBetween(
|
|
22207
|
+
[from[0] + perp[0] * off, from[1] + perp[1] * off, from[2] + perp[2] * off],
|
|
22208
|
+
[to[0] + perp[0] * off, to[1] + perp[1] * off, to[2] + perp[2] * off],
|
|
22209
|
+
bondRadius,
|
|
22210
|
+
color
|
|
22211
|
+
);
|
|
22212
|
+
if (bond) out.push(bond);
|
|
22213
|
+
}
|
|
22214
|
+
}
|
|
22215
|
+
for (const a of arrows) {
|
|
22216
|
+
const angle = (a.angle ?? 0) * (Math.PI / 180);
|
|
22217
|
+
const len = a.length ?? 60;
|
|
22218
|
+
const x2 = a.x + Math.cos(angle) * len;
|
|
22219
|
+
const y2 = a.y + Math.sin(angle) * len;
|
|
22220
|
+
const arrow = arrowBetween([a.x, a.y, 0], [x2, y2, 0], a.color ?? "#dc2626");
|
|
22221
|
+
if (arrow) out.push(arrow);
|
|
22222
|
+
if (a.label) {
|
|
22223
|
+
out.push(billboardLabel(a.label, (a.x + x2) / 2, (a.y + y2) / 2, 0, { color: labelColor }));
|
|
22224
|
+
}
|
|
22225
|
+
}
|
|
22226
|
+
for (const a of atoms) {
|
|
22227
|
+
const radius = a.radius ?? 0.45;
|
|
22228
|
+
const az = a.z ?? 0;
|
|
22229
|
+
out.push(meshSphere(a.id, a.x, a.y, az, radius, a.color ?? "#2563eb"));
|
|
22230
|
+
if (a.element) {
|
|
22231
|
+
out.push(billboardLabel(a.element, a.x, a.y, az + radius, { color: labelColor }));
|
|
22232
|
+
}
|
|
22233
|
+
}
|
|
22234
|
+
return out;
|
|
22235
|
+
}, [mode, atoms, bonds, arrows, shapes, backgroundColor]);
|
|
22236
|
+
const atomIndexById = React87.useMemo(() => {
|
|
22237
|
+
const m = /* @__PURE__ */ new Map();
|
|
22238
|
+
atoms.forEach((a, i) => {
|
|
22239
|
+
if (a.id) m.set(a.id, i);
|
|
22240
|
+
});
|
|
22241
|
+
return m;
|
|
22242
|
+
}, [atoms]);
|
|
22243
|
+
if (mode === "3d") {
|
|
22244
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
22245
|
+
LearningScene3D,
|
|
22246
|
+
{
|
|
22247
|
+
className,
|
|
22248
|
+
width,
|
|
22249
|
+
height,
|
|
22250
|
+
title,
|
|
22251
|
+
backgroundColor,
|
|
22252
|
+
drawables: drawables3D,
|
|
22253
|
+
camera,
|
|
22254
|
+
lighting,
|
|
22255
|
+
post,
|
|
22256
|
+
showGrid,
|
|
22257
|
+
shadows,
|
|
22258
|
+
interactive,
|
|
22259
|
+
isLoading,
|
|
22260
|
+
error,
|
|
22261
|
+
onItemClick: get3DClickPayload(onShapeClick, atomIndexById)
|
|
22262
|
+
}
|
|
22263
|
+
);
|
|
22264
|
+
}
|
|
21931
22265
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
21932
22266
|
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
21933
22267
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -21937,7 +22271,7 @@ var init_ChemistryCanvas = __esm({
|
|
|
21937
22271
|
height,
|
|
21938
22272
|
backgroundColor,
|
|
21939
22273
|
shapes: derivedShapes,
|
|
21940
|
-
interactive,
|
|
22274
|
+
interactive: interactive ?? false,
|
|
21941
22275
|
animate,
|
|
21942
22276
|
onShapeClick,
|
|
21943
22277
|
isLoading,
|
|
@@ -28242,19 +28576,25 @@ var init_MathCanvas = __esm({
|
|
|
28242
28576
|
};
|
|
28243
28577
|
}
|
|
28244
28578
|
});
|
|
28245
|
-
var PhysicsCanvas;
|
|
28579
|
+
var physicsLog2, PhysicsCanvas;
|
|
28246
28580
|
var init_PhysicsCanvas = __esm({
|
|
28247
28581
|
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
28248
28582
|
"use client";
|
|
28249
28583
|
init_atoms();
|
|
28250
28584
|
init_Stack();
|
|
28251
28585
|
init_LearningCanvas();
|
|
28586
|
+
init_learningScene3D();
|
|
28587
|
+
physicsLog2 = logger.createLogger("almadar:ui:physics-canvas");
|
|
28252
28588
|
PhysicsCanvas = ({
|
|
28253
28589
|
className,
|
|
28254
28590
|
width = 600,
|
|
28255
28591
|
height = 400,
|
|
28256
28592
|
title,
|
|
28257
28593
|
backgroundColor,
|
|
28594
|
+
mode = "2d",
|
|
28595
|
+
camera,
|
|
28596
|
+
lighting,
|
|
28597
|
+
post,
|
|
28258
28598
|
bodies = [],
|
|
28259
28599
|
constraints = [],
|
|
28260
28600
|
showVelocity = true,
|
|
@@ -28262,7 +28602,9 @@ var init_PhysicsCanvas = __esm({
|
|
|
28262
28602
|
velocityScale = 20,
|
|
28263
28603
|
forceScale = 20,
|
|
28264
28604
|
shapes = [],
|
|
28265
|
-
|
|
28605
|
+
showGrid,
|
|
28606
|
+
shadows,
|
|
28607
|
+
interactive,
|
|
28266
28608
|
animate = false,
|
|
28267
28609
|
onShapeClick,
|
|
28268
28610
|
isLoading,
|
|
@@ -28334,6 +28676,89 @@ var init_PhysicsCanvas = __esm({
|
|
|
28334
28676
|
out.push(...shapes);
|
|
28335
28677
|
return out;
|
|
28336
28678
|
}, [bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes]);
|
|
28679
|
+
const drawables3D = React87.useMemo(() => {
|
|
28680
|
+
if (mode !== "3d") return [];
|
|
28681
|
+
if (shapes.length > 0) {
|
|
28682
|
+
physicsLog2.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
28683
|
+
}
|
|
28684
|
+
const out = [];
|
|
28685
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
28686
|
+
const bodyById = /* @__PURE__ */ new Map();
|
|
28687
|
+
for (const b of bodies) {
|
|
28688
|
+
if (b.id) bodyById.set(b.id, b);
|
|
28689
|
+
}
|
|
28690
|
+
for (const c of constraints) {
|
|
28691
|
+
const a = bodyById.get(c.from);
|
|
28692
|
+
const b = bodyById.get(c.to);
|
|
28693
|
+
if (!a || !b) continue;
|
|
28694
|
+
const rodRadius = Math.max(0.05, Math.min(a.radius ?? 0.5, b.radius ?? 0.5) * 0.15);
|
|
28695
|
+
const rod = cylinderBetween([a.x, a.y, a.z ?? 0], [b.x, b.y, b.z ?? 0], rodRadius, c.color ?? "#9ca3af");
|
|
28696
|
+
if (rod) out.push(rod);
|
|
28697
|
+
}
|
|
28698
|
+
for (const b of bodies) {
|
|
28699
|
+
const radius = b.radius ?? 0.5;
|
|
28700
|
+
const bz = b.z ?? 0;
|
|
28701
|
+
out.push(meshSphere(b.id, b.x, b.y, bz, radius, b.color ?? "#2563eb"));
|
|
28702
|
+
if (b.label) {
|
|
28703
|
+
out.push(billboardLabel(b.label, b.x, b.y, bz + radius, { color: labelColor }));
|
|
28704
|
+
}
|
|
28705
|
+
const vx = b.vx ?? 0;
|
|
28706
|
+
const vy = b.vy ?? 0;
|
|
28707
|
+
const vz = b.vz ?? 0;
|
|
28708
|
+
const arrowRadius = Math.max(0.05, radius * 0.15);
|
|
28709
|
+
if (showVelocity && (vx !== 0 || vy !== 0 || vz !== 0)) {
|
|
28710
|
+
const arrow = arrowBetween(
|
|
28711
|
+
[b.x, b.y, bz],
|
|
28712
|
+
[b.x + vx * velocityScale, b.y + vy * velocityScale, bz + vz * velocityScale],
|
|
28713
|
+
"#16a34a",
|
|
28714
|
+
arrowRadius
|
|
28715
|
+
);
|
|
28716
|
+
if (arrow) out.push(arrow);
|
|
28717
|
+
}
|
|
28718
|
+
const fx = b.fx ?? 0;
|
|
28719
|
+
const fy = b.fy ?? 0;
|
|
28720
|
+
const fz = b.fz ?? 0;
|
|
28721
|
+
if (showForces && (fx !== 0 || fy !== 0 || fz !== 0)) {
|
|
28722
|
+
const arrow = arrowBetween(
|
|
28723
|
+
[b.x, b.y, bz],
|
|
28724
|
+
[b.x + fx * forceScale, b.y + fy * forceScale, bz + fz * forceScale],
|
|
28725
|
+
"#dc2626",
|
|
28726
|
+
arrowRadius
|
|
28727
|
+
);
|
|
28728
|
+
if (arrow) out.push(arrow);
|
|
28729
|
+
}
|
|
28730
|
+
}
|
|
28731
|
+
return out;
|
|
28732
|
+
}, [mode, bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes, backgroundColor]);
|
|
28733
|
+
const bodyIndexById = React87.useMemo(() => {
|
|
28734
|
+
const m = /* @__PURE__ */ new Map();
|
|
28735
|
+
bodies.forEach((b, i) => {
|
|
28736
|
+
if (b.id) m.set(b.id, i);
|
|
28737
|
+
});
|
|
28738
|
+
return m;
|
|
28739
|
+
}, [bodies]);
|
|
28740
|
+
if (mode === "3d") {
|
|
28741
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28742
|
+
LearningScene3D,
|
|
28743
|
+
{
|
|
28744
|
+
className,
|
|
28745
|
+
width,
|
|
28746
|
+
height,
|
|
28747
|
+
title,
|
|
28748
|
+
backgroundColor,
|
|
28749
|
+
drawables: drawables3D,
|
|
28750
|
+
camera,
|
|
28751
|
+
lighting,
|
|
28752
|
+
post,
|
|
28753
|
+
showGrid,
|
|
28754
|
+
shadows,
|
|
28755
|
+
interactive,
|
|
28756
|
+
isLoading,
|
|
28757
|
+
error,
|
|
28758
|
+
onItemClick: get3DClickPayload(onShapeClick, bodyIndexById)
|
|
28759
|
+
}
|
|
28760
|
+
);
|
|
28761
|
+
}
|
|
28337
28762
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
28338
28763
|
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
28339
28764
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -28343,7 +28768,7 @@ var init_PhysicsCanvas = __esm({
|
|
|
28343
28768
|
height,
|
|
28344
28769
|
backgroundColor,
|
|
28345
28770
|
shapes: derivedShapes,
|
|
28346
|
-
interactive,
|
|
28771
|
+
interactive: interactive ?? false,
|
|
28347
28772
|
animate,
|
|
28348
28773
|
onShapeClick,
|
|
28349
28774
|
isLoading,
|
|
@@ -28961,12 +29386,12 @@ var init_MapView = __esm({
|
|
|
28961
29386
|
shadowSize: [41, 41]
|
|
28962
29387
|
});
|
|
28963
29388
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28964
|
-
const { useEffect: useEffect63, useRef:
|
|
29389
|
+
const { useEffect: useEffect63, useRef: useRef63, useCallback: useCallback96, useState: useState94 } = React87__namespace.default;
|
|
28965
29390
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28966
29391
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28967
29392
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28968
29393
|
const map = useMap();
|
|
28969
|
-
const prevRef =
|
|
29394
|
+
const prevRef = useRef63({ centerLat, centerLng, zoom });
|
|
28970
29395
|
useEffect63(() => {
|
|
28971
29396
|
const prev = prevRef.current;
|
|
28972
29397
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
@@ -39789,7 +40214,7 @@ function getEnumOptions(field) {
|
|
|
39789
40214
|
}));
|
|
39790
40215
|
}
|
|
39791
40216
|
const validation = field.validation;
|
|
39792
|
-
if (validation?.enum &&
|
|
40217
|
+
if (validation?.enum && validation.enum.length > 0) {
|
|
39793
40218
|
return validation.enum.map((v) => ({
|
|
39794
40219
|
value: v,
|
|
39795
40220
|
label: v.charAt(0).toUpperCase() + v.slice(1).replace(/_/g, " ")
|
|
@@ -7,8 +7,9 @@ export { E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaC
|
|
|
7
7
|
import { U as UseOfflineExecutorResult, a as UseOfflineExecutorOptions } from '../offline-executor-Qz4b6GpF.cjs';
|
|
8
8
|
export { N as NavigationContextValue, b as NavigationProvider, c as NavigationProviderProps, d as NavigationState, e as comparePathSpecificity, f as extractRouteParams, g as findPageByName, h as findPageByPath, i as getAllPages, j as getDefaultPage, m as matchPath, k as matchPathAmong, p as pathMatches, u as useActivePage, l as useInitPayload, n as useNavigateTo, o as useNavigation, q as useNavigationId, r as useNavigationState } from '../offline-executor-Qz4b6GpF.cjs';
|
|
9
9
|
import { E as EventBusContextType } from '../event-bus-types-Bl78kokd.cjs';
|
|
10
|
-
export { G as GameAudioContext, a as GameAudioContextValue, b as GameAudioProvider, c as GameAudioProviderProps, u as useGameAudioContext, d as useGameAudioContextOptional } from '../GameAudioProvider-
|
|
10
|
+
export { G as GameAudioContext, a as GameAudioContextValue, b as GameAudioProvider, c as GameAudioProviderProps, u as useGameAudioContext, d as useGameAudioContextOptional } from '../GameAudioProvider-CQAdPreB.cjs';
|
|
11
11
|
import '@almadar/core/patterns';
|
|
12
|
+
import '../types-B3nHgnMG.cjs';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* EventBusProvider - React context provider for the event bus
|
|
@@ -7,8 +7,9 @@ export { E as EntityBindingContext, a as EntityBindingSource, b as EntitySchemaC
|
|
|
7
7
|
import { U as UseOfflineExecutorResult, a as UseOfflineExecutorOptions } from '../offline-executor-Qz4b6GpF.js';
|
|
8
8
|
export { N as NavigationContextValue, b as NavigationProvider, c as NavigationProviderProps, d as NavigationState, e as comparePathSpecificity, f as extractRouteParams, g as findPageByName, h as findPageByPath, i as getAllPages, j as getDefaultPage, m as matchPath, k as matchPathAmong, p as pathMatches, u as useActivePage, l as useInitPayload, n as useNavigateTo, o as useNavigation, q as useNavigationId, r as useNavigationState } from '../offline-executor-Qz4b6GpF.js';
|
|
9
9
|
import { E as EventBusContextType } from '../event-bus-types-Bl78kokd.js';
|
|
10
|
-
export { G as GameAudioContext, a as GameAudioContextValue, b as GameAudioProvider, c as GameAudioProviderProps, u as useGameAudioContext, d as useGameAudioContextOptional } from '../GameAudioProvider-
|
|
10
|
+
export { G as GameAudioContext, a as GameAudioContextValue, b as GameAudioProvider, c as GameAudioProviderProps, u as useGameAudioContext, d as useGameAudioContextOptional } from '../GameAudioProvider-B48iXwz3.js';
|
|
11
11
|
import '@almadar/core/patterns';
|
|
12
|
+
import '../types-B3nHgnMG.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* EventBusProvider - React context provider for the event bus
|