@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.js
CHANGED
|
@@ -10301,9 +10301,10 @@ function Canvas({
|
|
|
10301
10301
|
drawables: [...drawables ?? [], ...childDrawables],
|
|
10302
10302
|
isLoading,
|
|
10303
10303
|
cameraMode: to3DCameraMode(camera?.mode),
|
|
10304
|
-
...zoom !== void 0 ? {
|
|
10304
|
+
...zoom !== void 0 ? { zoom } : {},
|
|
10305
10305
|
...camera?.fov !== void 0 ? { fov: camera.fov } : {},
|
|
10306
10306
|
...camera?.azimuth !== void 0 ? { azimuth: camera.azimuth } : {},
|
|
10307
|
+
...camera?.elevation !== void 0 ? { elevation: camera.elevation } : {},
|
|
10307
10308
|
...camera?.target !== void 0 ? { followTarget: camera.target } : {},
|
|
10308
10309
|
unitScale,
|
|
10309
10310
|
backgroundColor,
|
|
@@ -14832,23 +14833,188 @@ var init_BehaviorView = __esm({
|
|
|
14832
14833
|
BehaviorView.displayName = "BehaviorView";
|
|
14833
14834
|
}
|
|
14834
14835
|
});
|
|
14835
|
-
|
|
14836
|
+
function LearningScene3D({
|
|
14837
|
+
className,
|
|
14838
|
+
width = 600,
|
|
14839
|
+
height = 400,
|
|
14840
|
+
title,
|
|
14841
|
+
backgroundColor,
|
|
14842
|
+
drawables,
|
|
14843
|
+
camera,
|
|
14844
|
+
lighting,
|
|
14845
|
+
post,
|
|
14846
|
+
showGrid = false,
|
|
14847
|
+
shadows,
|
|
14848
|
+
interactive,
|
|
14849
|
+
isLoading,
|
|
14850
|
+
error,
|
|
14851
|
+
onItemClick
|
|
14852
|
+
}) {
|
|
14853
|
+
const instanceId = useId().replace(/[^a-zA-Z0-9]/g, "");
|
|
14854
|
+
const clickEvent = onItemClick ? `LEARNING_SCENE_3D.ITEM_CLICK.${instanceId}` : void 0;
|
|
14855
|
+
const onItemClickRef = useRef(onItemClick);
|
|
14856
|
+
onItemClickRef.current = onItemClick;
|
|
14857
|
+
useEventListener(`UI:${clickEvent ?? "LEARNING_SCENE_3D.ITEM_CLICK.__disabled"}`, (event) => {
|
|
14858
|
+
const unitId = event.payload?.unitId;
|
|
14859
|
+
if (typeof unitId === "string") onItemClickRef.current?.(unitId);
|
|
14860
|
+
});
|
|
14861
|
+
const props3d = {
|
|
14862
|
+
drawables,
|
|
14863
|
+
isLoading,
|
|
14864
|
+
error: error ? error.message : null,
|
|
14865
|
+
cameraMode: camera?.mode ?? "perspective",
|
|
14866
|
+
...camera?.zoom !== void 0 ? { zoom: camera.zoom } : {},
|
|
14867
|
+
...camera?.fov !== void 0 ? { fov: camera.fov } : {},
|
|
14868
|
+
...camera?.azimuth !== void 0 ? { azimuth: camera.azimuth } : {},
|
|
14869
|
+
...camera?.elevation !== void 0 ? { elevation: camera.elevation } : {},
|
|
14870
|
+
...camera?.target !== void 0 ? { followTarget: camera.target } : {},
|
|
14871
|
+
backgroundColor,
|
|
14872
|
+
showGrid,
|
|
14873
|
+
...shadows !== void 0 ? { shadows } : {},
|
|
14874
|
+
...interactive !== void 0 ? { controlsEnabled: interactive } : {},
|
|
14875
|
+
lighting,
|
|
14876
|
+
post,
|
|
14877
|
+
...clickEvent !== void 0 ? { unitClickEvent: clickEvent } : {}
|
|
14878
|
+
};
|
|
14879
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
14880
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
14881
|
+
/* @__PURE__ */ jsx("div", { style: { width, height, display: "flex" }, children: /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(Canvas3DHost2, { ...props3d }) }) })
|
|
14882
|
+
] }) });
|
|
14883
|
+
}
|
|
14884
|
+
function meshSphere(id, x, y, z, radius, color, opts) {
|
|
14885
|
+
return {
|
|
14886
|
+
type: "draw-mesh",
|
|
14887
|
+
...id !== void 0 ? { id } : {},
|
|
14888
|
+
shape: opts?.shape ?? "sphere",
|
|
14889
|
+
position: { x, y, z },
|
|
14890
|
+
radius,
|
|
14891
|
+
pivot: "center",
|
|
14892
|
+
segments: opts?.segments ?? 24,
|
|
14893
|
+
material: { color, ...opts?.material },
|
|
14894
|
+
...opts?.opacity !== void 0 ? { opacity: opts.opacity } : {}
|
|
14895
|
+
};
|
|
14896
|
+
}
|
|
14897
|
+
function axisRotation(from, to) {
|
|
14898
|
+
const wx = to[0] - from[0];
|
|
14899
|
+
const wy = to[2] - from[2];
|
|
14900
|
+
const wz = to[1] - from[1];
|
|
14901
|
+
const len = Math.sqrt(wx * wx + wy * wy + wz * wz);
|
|
14902
|
+
const tilt = Math.acos(Math.min(1, Math.max(-1, len > 0 ? wy / len : 1)));
|
|
14903
|
+
return [0, Math.atan2(wz, -wx), tilt];
|
|
14904
|
+
}
|
|
14905
|
+
function segmentLength(from, to) {
|
|
14906
|
+
const dx = to[0] - from[0];
|
|
14907
|
+
const dy = to[1] - from[1];
|
|
14908
|
+
const dz = to[2] - from[2];
|
|
14909
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
14910
|
+
}
|
|
14911
|
+
function cylinderBetween(from, to, radius, color) {
|
|
14912
|
+
const len = segmentLength(from, to);
|
|
14913
|
+
if (len < 1e-6) return null;
|
|
14914
|
+
return {
|
|
14915
|
+
type: "draw-mesh",
|
|
14916
|
+
shape: "cylinder",
|
|
14917
|
+
position: { x: (from[0] + to[0]) / 2, y: (from[1] + to[1]) / 2, z: (from[2] + to[2]) / 2 },
|
|
14918
|
+
radius,
|
|
14919
|
+
height: len,
|
|
14920
|
+
rotation: axisRotation(from, to),
|
|
14921
|
+
pivot: "center",
|
|
14922
|
+
segments: 12,
|
|
14923
|
+
material: { color }
|
|
14924
|
+
};
|
|
14925
|
+
}
|
|
14926
|
+
function arrowBetween(from, to, color, shaftRadius = 0.08) {
|
|
14927
|
+
const len = segmentLength(from, to);
|
|
14928
|
+
if (len < 1e-6) return null;
|
|
14929
|
+
const tipLen = Math.min(shaftRadius * 8, len * 0.35);
|
|
14930
|
+
const k = (len - tipLen) / len;
|
|
14931
|
+
const delta = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];
|
|
14932
|
+
const shaftEnd = [delta[0] * k, delta[1] * k, delta[2] * k];
|
|
14933
|
+
const tipStart = shaftEnd;
|
|
14934
|
+
const tipEnd = delta;
|
|
14935
|
+
const shaft = cylinderBetween([0, 0, 0], shaftEnd, shaftRadius, color);
|
|
14936
|
+
const tipLenActual = segmentLength(tipStart, tipEnd);
|
|
14937
|
+
const tip = {
|
|
14938
|
+
type: "draw-mesh",
|
|
14939
|
+
shape: "cone",
|
|
14940
|
+
position: {
|
|
14941
|
+
x: (tipStart[0] + tipEnd[0]) / 2,
|
|
14942
|
+
y: (tipStart[1] + tipEnd[1]) / 2,
|
|
14943
|
+
z: (tipStart[2] + tipEnd[2]) / 2
|
|
14944
|
+
},
|
|
14945
|
+
radius: shaftRadius * 3,
|
|
14946
|
+
height: tipLenActual,
|
|
14947
|
+
rotation: axisRotation(tipStart, tipEnd),
|
|
14948
|
+
pivot: "center",
|
|
14949
|
+
segments: 12,
|
|
14950
|
+
material: { color }
|
|
14951
|
+
};
|
|
14952
|
+
return {
|
|
14953
|
+
type: "draw-group",
|
|
14954
|
+
position: { x: from[0], y: from[1], z: from[2] },
|
|
14955
|
+
items: tipLenActual < 1e-6 ? shaft ? [shaft] : [] : shaft ? [shaft, tip] : [tip]
|
|
14956
|
+
};
|
|
14957
|
+
}
|
|
14958
|
+
function billboardLabel(text, x, y, z, opts) {
|
|
14959
|
+
return {
|
|
14960
|
+
type: "draw-text",
|
|
14961
|
+
text,
|
|
14962
|
+
position: { x, y, z },
|
|
14963
|
+
color: opts?.color ?? "#111827"
|
|
14964
|
+
};
|
|
14965
|
+
}
|
|
14966
|
+
function labelColorForBackground(backgroundColor) {
|
|
14967
|
+
const m = /^#(?:([0-9a-f]{3})|([0-9a-f]{6}))$/i.exec(backgroundColor ?? "");
|
|
14968
|
+
if (!m) return "#111827";
|
|
14969
|
+
const hex = m[1] !== void 0 ? m[1].split("").map((c) => c + c).join("") : m[2];
|
|
14970
|
+
const r = parseInt(hex.slice(0, 2), 16) / 255;
|
|
14971
|
+
const g = parseInt(hex.slice(2, 4), 16) / 255;
|
|
14972
|
+
const b = parseInt(hex.slice(4, 6), 16) / 255;
|
|
14973
|
+
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
14974
|
+
return luminance < 0.5 ? "#e5e7eb" : "#111827";
|
|
14975
|
+
}
|
|
14976
|
+
function get3DClickPayload(onShapeClick, idToIndex) {
|
|
14977
|
+
if (!onShapeClick) return void 0;
|
|
14978
|
+
return (id) => onShapeClick({ id, index: idToIndex.get(id) ?? -1 });
|
|
14979
|
+
}
|
|
14980
|
+
var Canvas3DHost2;
|
|
14981
|
+
var init_learningScene3D = __esm({
|
|
14982
|
+
"components/learning/molecules/learningScene3D.tsx"() {
|
|
14983
|
+
"use client";
|
|
14984
|
+
init_atoms();
|
|
14985
|
+
init_Stack();
|
|
14986
|
+
init_useEventBus();
|
|
14987
|
+
Canvas3DHost2 = lazy(
|
|
14988
|
+
() => import('@almadar/ui/components/molecules/game/three').then((m) => ({ default: m.Canvas3DHost }))
|
|
14989
|
+
);
|
|
14990
|
+
LearningScene3D.displayName = "LearningScene3D";
|
|
14991
|
+
}
|
|
14992
|
+
});
|
|
14993
|
+
var biologyLog, BiologyCanvas;
|
|
14836
14994
|
var init_BiologyCanvas = __esm({
|
|
14837
14995
|
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
14838
14996
|
"use client";
|
|
14839
14997
|
init_atoms();
|
|
14840
14998
|
init_Stack();
|
|
14841
14999
|
init_LearningCanvas();
|
|
15000
|
+
init_learningScene3D();
|
|
15001
|
+
biologyLog = createLogger("almadar:ui:biology-canvas");
|
|
14842
15002
|
BiologyCanvas = ({
|
|
14843
15003
|
className,
|
|
14844
15004
|
width = 600,
|
|
14845
15005
|
height = 400,
|
|
14846
15006
|
title,
|
|
14847
15007
|
backgroundColor,
|
|
15008
|
+
mode = "2d",
|
|
15009
|
+
camera,
|
|
15010
|
+
lighting,
|
|
15011
|
+
post,
|
|
14848
15012
|
nodes = [],
|
|
14849
15013
|
edges = [],
|
|
14850
15014
|
shapes = [],
|
|
14851
|
-
|
|
15015
|
+
showGrid,
|
|
15016
|
+
shadows,
|
|
15017
|
+
interactive,
|
|
14852
15018
|
animate = false,
|
|
14853
15019
|
onShapeClick,
|
|
14854
15020
|
isLoading,
|
|
@@ -14909,6 +15075,75 @@ var init_BiologyCanvas = __esm({
|
|
|
14909
15075
|
out.push(...shapes);
|
|
14910
15076
|
return out;
|
|
14911
15077
|
}, [nodes, edges, shapes]);
|
|
15078
|
+
const drawables3D = useMemo(() => {
|
|
15079
|
+
if (mode !== "3d") return [];
|
|
15080
|
+
if (shapes.length > 0) {
|
|
15081
|
+
biologyLog.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
15082
|
+
}
|
|
15083
|
+
const out = [];
|
|
15084
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
15085
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
15086
|
+
for (const n of nodes) {
|
|
15087
|
+
if (n.id) nodeById.set(n.id, n);
|
|
15088
|
+
}
|
|
15089
|
+
for (const e of edges) {
|
|
15090
|
+
const a = nodeById.get(e.from);
|
|
15091
|
+
const b = nodeById.get(e.to);
|
|
15092
|
+
if (!a || !b) continue;
|
|
15093
|
+
const edgeRadius = Math.max(0.04, Math.min(a.radius ?? 0.5, b.radius ?? 0.5) * 0.12);
|
|
15094
|
+
const edge = cylinderBetween([a.x, a.y, a.z ?? 0], [b.x, b.y, b.z ?? 0], edgeRadius, e.color ?? "#9ca3af");
|
|
15095
|
+
if (edge) out.push(edge);
|
|
15096
|
+
if (e.label) {
|
|
15097
|
+
out.push(
|
|
15098
|
+
billboardLabel(
|
|
15099
|
+
e.label,
|
|
15100
|
+
(a.x + b.x) / 2,
|
|
15101
|
+
(a.y + b.y) / 2,
|
|
15102
|
+
((a.z ?? 0) + (b.z ?? 0)) / 2,
|
|
15103
|
+
{ color: labelColor }
|
|
15104
|
+
)
|
|
15105
|
+
);
|
|
15106
|
+
}
|
|
15107
|
+
}
|
|
15108
|
+
for (const n of nodes) {
|
|
15109
|
+
const radius = n.radius ?? 0.5;
|
|
15110
|
+
const nz = n.z ?? 0;
|
|
15111
|
+
out.push(meshSphere(n.id, n.x, n.y, nz, radius, n.color ?? "#16a34a", { shape: n.shape, ...n.opacity !== void 0 ? { opacity: n.opacity } : {} }));
|
|
15112
|
+
if (n.label) {
|
|
15113
|
+
out.push(billboardLabel(n.label, n.x, n.y, nz + radius, { color: labelColor }));
|
|
15114
|
+
}
|
|
15115
|
+
}
|
|
15116
|
+
return out;
|
|
15117
|
+
}, [mode, nodes, edges, shapes, backgroundColor]);
|
|
15118
|
+
const nodeIndexById = useMemo(() => {
|
|
15119
|
+
const m = /* @__PURE__ */ new Map();
|
|
15120
|
+
nodes.forEach((n, i) => {
|
|
15121
|
+
if (n.id) m.set(n.id, i);
|
|
15122
|
+
});
|
|
15123
|
+
return m;
|
|
15124
|
+
}, [nodes]);
|
|
15125
|
+
if (mode === "3d") {
|
|
15126
|
+
return /* @__PURE__ */ jsx(
|
|
15127
|
+
LearningScene3D,
|
|
15128
|
+
{
|
|
15129
|
+
className,
|
|
15130
|
+
width,
|
|
15131
|
+
height,
|
|
15132
|
+
title,
|
|
15133
|
+
backgroundColor,
|
|
15134
|
+
drawables: drawables3D,
|
|
15135
|
+
camera,
|
|
15136
|
+
lighting,
|
|
15137
|
+
post,
|
|
15138
|
+
showGrid,
|
|
15139
|
+
shadows,
|
|
15140
|
+
interactive,
|
|
15141
|
+
isLoading,
|
|
15142
|
+
error,
|
|
15143
|
+
onItemClick: get3DClickPayload(onShapeClick, nodeIndexById)
|
|
15144
|
+
}
|
|
15145
|
+
);
|
|
15146
|
+
}
|
|
14912
15147
|
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
14913
15148
|
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
14914
15149
|
/* @__PURE__ */ jsx(
|
|
@@ -14918,7 +15153,7 @@ var init_BiologyCanvas = __esm({
|
|
|
14918
15153
|
height,
|
|
14919
15154
|
backgroundColor,
|
|
14920
15155
|
shapes: derivedShapes,
|
|
14921
|
-
interactive,
|
|
15156
|
+
interactive: interactive ?? false,
|
|
14922
15157
|
animate,
|
|
14923
15158
|
onShapeClick,
|
|
14924
15159
|
isLoading,
|
|
@@ -21758,24 +21993,41 @@ var init_ChatBar = __esm({
|
|
|
21758
21993
|
ChatBar.displayName = "ChatBar";
|
|
21759
21994
|
}
|
|
21760
21995
|
});
|
|
21761
|
-
|
|
21996
|
+
function bondPerpendicular(a, b) {
|
|
21997
|
+
const dx = b[0] - a[0];
|
|
21998
|
+
const dy = b[1] - a[1];
|
|
21999
|
+
const px = dy;
|
|
22000
|
+
const py = -dx;
|
|
22001
|
+
const len = Math.sqrt(px * px + py * py);
|
|
22002
|
+
if (len < 1e-6) return [1, 0, 0];
|
|
22003
|
+
return [px / len, py / len, 0];
|
|
22004
|
+
}
|
|
22005
|
+
var chemistryLog, ChemistryCanvas;
|
|
21762
22006
|
var init_ChemistryCanvas = __esm({
|
|
21763
22007
|
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
21764
22008
|
"use client";
|
|
21765
22009
|
init_atoms();
|
|
21766
22010
|
init_Stack();
|
|
21767
22011
|
init_LearningCanvas();
|
|
22012
|
+
init_learningScene3D();
|
|
22013
|
+
chemistryLog = createLogger("almadar:ui:chemistry-canvas");
|
|
21768
22014
|
ChemistryCanvas = ({
|
|
21769
22015
|
className,
|
|
21770
22016
|
width = 600,
|
|
21771
22017
|
height = 400,
|
|
21772
22018
|
title,
|
|
21773
22019
|
backgroundColor,
|
|
22020
|
+
mode = "2d",
|
|
22021
|
+
camera,
|
|
22022
|
+
lighting,
|
|
22023
|
+
post,
|
|
21774
22024
|
atoms = [],
|
|
21775
22025
|
bonds = [],
|
|
21776
22026
|
arrows = [],
|
|
21777
22027
|
shapes = [],
|
|
21778
|
-
|
|
22028
|
+
showGrid,
|
|
22029
|
+
shadows,
|
|
22030
|
+
interactive,
|
|
21779
22031
|
animate = false,
|
|
21780
22032
|
onShapeClick,
|
|
21781
22033
|
isLoading,
|
|
@@ -21854,6 +22106,88 @@ var init_ChemistryCanvas = __esm({
|
|
|
21854
22106
|
out.push(...shapes);
|
|
21855
22107
|
return out;
|
|
21856
22108
|
}, [atoms, bonds, arrows, shapes]);
|
|
22109
|
+
const drawables3D = useMemo(() => {
|
|
22110
|
+
if (mode !== "3d") return [];
|
|
22111
|
+
if (shapes.length > 0) {
|
|
22112
|
+
chemistryLog.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
22113
|
+
}
|
|
22114
|
+
const out = [];
|
|
22115
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
22116
|
+
const atomById = /* @__PURE__ */ new Map();
|
|
22117
|
+
for (const a of atoms) {
|
|
22118
|
+
if (a.id) atomById.set(a.id, a);
|
|
22119
|
+
}
|
|
22120
|
+
for (const b of bonds) {
|
|
22121
|
+
const a = atomById.get(b.from);
|
|
22122
|
+
const c = atomById.get(b.to);
|
|
22123
|
+
if (!a || !c) continue;
|
|
22124
|
+
const color = b.color ?? "#6b7280";
|
|
22125
|
+
const from = [a.x, a.y, a.z ?? 0];
|
|
22126
|
+
const to = [c.x, c.y, c.z ?? 0];
|
|
22127
|
+
const perp = bondPerpendicular(from, to);
|
|
22128
|
+
const bondRadius = Math.max(0.06, Math.min(a.radius ?? 0.45, c.radius ?? 0.45) * 0.22);
|
|
22129
|
+
const step = bondRadius * 2.2;
|
|
22130
|
+
const offsets = b.type === "double" ? [-step, step] : b.type === "triple" ? [-step, 0, step] : [0];
|
|
22131
|
+
for (const off of offsets) {
|
|
22132
|
+
const bond = cylinderBetween(
|
|
22133
|
+
[from[0] + perp[0] * off, from[1] + perp[1] * off, from[2] + perp[2] * off],
|
|
22134
|
+
[to[0] + perp[0] * off, to[1] + perp[1] * off, to[2] + perp[2] * off],
|
|
22135
|
+
bondRadius,
|
|
22136
|
+
color
|
|
22137
|
+
);
|
|
22138
|
+
if (bond) out.push(bond);
|
|
22139
|
+
}
|
|
22140
|
+
}
|
|
22141
|
+
for (const a of arrows) {
|
|
22142
|
+
const angle = (a.angle ?? 0) * (Math.PI / 180);
|
|
22143
|
+
const len = a.length ?? 60;
|
|
22144
|
+
const x2 = a.x + Math.cos(angle) * len;
|
|
22145
|
+
const y2 = a.y + Math.sin(angle) * len;
|
|
22146
|
+
const arrow = arrowBetween([a.x, a.y, 0], [x2, y2, 0], a.color ?? "#dc2626");
|
|
22147
|
+
if (arrow) out.push(arrow);
|
|
22148
|
+
if (a.label) {
|
|
22149
|
+
out.push(billboardLabel(a.label, (a.x + x2) / 2, (a.y + y2) / 2, 0, { color: labelColor }));
|
|
22150
|
+
}
|
|
22151
|
+
}
|
|
22152
|
+
for (const a of atoms) {
|
|
22153
|
+
const radius = a.radius ?? 0.45;
|
|
22154
|
+
const az = a.z ?? 0;
|
|
22155
|
+
out.push(meshSphere(a.id, a.x, a.y, az, radius, a.color ?? "#2563eb"));
|
|
22156
|
+
if (a.element) {
|
|
22157
|
+
out.push(billboardLabel(a.element, a.x, a.y, az + radius, { color: labelColor }));
|
|
22158
|
+
}
|
|
22159
|
+
}
|
|
22160
|
+
return out;
|
|
22161
|
+
}, [mode, atoms, bonds, arrows, shapes, backgroundColor]);
|
|
22162
|
+
const atomIndexById = useMemo(() => {
|
|
22163
|
+
const m = /* @__PURE__ */ new Map();
|
|
22164
|
+
atoms.forEach((a, i) => {
|
|
22165
|
+
if (a.id) m.set(a.id, i);
|
|
22166
|
+
});
|
|
22167
|
+
return m;
|
|
22168
|
+
}, [atoms]);
|
|
22169
|
+
if (mode === "3d") {
|
|
22170
|
+
return /* @__PURE__ */ jsx(
|
|
22171
|
+
LearningScene3D,
|
|
22172
|
+
{
|
|
22173
|
+
className,
|
|
22174
|
+
width,
|
|
22175
|
+
height,
|
|
22176
|
+
title,
|
|
22177
|
+
backgroundColor,
|
|
22178
|
+
drawables: drawables3D,
|
|
22179
|
+
camera,
|
|
22180
|
+
lighting,
|
|
22181
|
+
post,
|
|
22182
|
+
showGrid,
|
|
22183
|
+
shadows,
|
|
22184
|
+
interactive,
|
|
22185
|
+
isLoading,
|
|
22186
|
+
error,
|
|
22187
|
+
onItemClick: get3DClickPayload(onShapeClick, atomIndexById)
|
|
22188
|
+
}
|
|
22189
|
+
);
|
|
22190
|
+
}
|
|
21857
22191
|
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
21858
22192
|
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
21859
22193
|
/* @__PURE__ */ jsx(
|
|
@@ -21863,7 +22197,7 @@ var init_ChemistryCanvas = __esm({
|
|
|
21863
22197
|
height,
|
|
21864
22198
|
backgroundColor,
|
|
21865
22199
|
shapes: derivedShapes,
|
|
21866
|
-
interactive,
|
|
22200
|
+
interactive: interactive ?? false,
|
|
21867
22201
|
animate,
|
|
21868
22202
|
onShapeClick,
|
|
21869
22203
|
isLoading,
|
|
@@ -28168,19 +28502,25 @@ var init_MathCanvas = __esm({
|
|
|
28168
28502
|
};
|
|
28169
28503
|
}
|
|
28170
28504
|
});
|
|
28171
|
-
var PhysicsCanvas;
|
|
28505
|
+
var physicsLog2, PhysicsCanvas;
|
|
28172
28506
|
var init_PhysicsCanvas = __esm({
|
|
28173
28507
|
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
28174
28508
|
"use client";
|
|
28175
28509
|
init_atoms();
|
|
28176
28510
|
init_Stack();
|
|
28177
28511
|
init_LearningCanvas();
|
|
28512
|
+
init_learningScene3D();
|
|
28513
|
+
physicsLog2 = createLogger("almadar:ui:physics-canvas");
|
|
28178
28514
|
PhysicsCanvas = ({
|
|
28179
28515
|
className,
|
|
28180
28516
|
width = 600,
|
|
28181
28517
|
height = 400,
|
|
28182
28518
|
title,
|
|
28183
28519
|
backgroundColor,
|
|
28520
|
+
mode = "2d",
|
|
28521
|
+
camera,
|
|
28522
|
+
lighting,
|
|
28523
|
+
post,
|
|
28184
28524
|
bodies = [],
|
|
28185
28525
|
constraints = [],
|
|
28186
28526
|
showVelocity = true,
|
|
@@ -28188,7 +28528,9 @@ var init_PhysicsCanvas = __esm({
|
|
|
28188
28528
|
velocityScale = 20,
|
|
28189
28529
|
forceScale = 20,
|
|
28190
28530
|
shapes = [],
|
|
28191
|
-
|
|
28531
|
+
showGrid,
|
|
28532
|
+
shadows,
|
|
28533
|
+
interactive,
|
|
28192
28534
|
animate = false,
|
|
28193
28535
|
onShapeClick,
|
|
28194
28536
|
isLoading,
|
|
@@ -28260,6 +28602,89 @@ var init_PhysicsCanvas = __esm({
|
|
|
28260
28602
|
out.push(...shapes);
|
|
28261
28603
|
return out;
|
|
28262
28604
|
}, [bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes]);
|
|
28605
|
+
const drawables3D = useMemo(() => {
|
|
28606
|
+
if (mode !== "3d") return [];
|
|
28607
|
+
if (shapes.length > 0) {
|
|
28608
|
+
physicsLog2.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
28609
|
+
}
|
|
28610
|
+
const out = [];
|
|
28611
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
28612
|
+
const bodyById = /* @__PURE__ */ new Map();
|
|
28613
|
+
for (const b of bodies) {
|
|
28614
|
+
if (b.id) bodyById.set(b.id, b);
|
|
28615
|
+
}
|
|
28616
|
+
for (const c of constraints) {
|
|
28617
|
+
const a = bodyById.get(c.from);
|
|
28618
|
+
const b = bodyById.get(c.to);
|
|
28619
|
+
if (!a || !b) continue;
|
|
28620
|
+
const rodRadius = Math.max(0.05, Math.min(a.radius ?? 0.5, b.radius ?? 0.5) * 0.15);
|
|
28621
|
+
const rod = cylinderBetween([a.x, a.y, a.z ?? 0], [b.x, b.y, b.z ?? 0], rodRadius, c.color ?? "#9ca3af");
|
|
28622
|
+
if (rod) out.push(rod);
|
|
28623
|
+
}
|
|
28624
|
+
for (const b of bodies) {
|
|
28625
|
+
const radius = b.radius ?? 0.5;
|
|
28626
|
+
const bz = b.z ?? 0;
|
|
28627
|
+
out.push(meshSphere(b.id, b.x, b.y, bz, radius, b.color ?? "#2563eb"));
|
|
28628
|
+
if (b.label) {
|
|
28629
|
+
out.push(billboardLabel(b.label, b.x, b.y, bz + radius, { color: labelColor }));
|
|
28630
|
+
}
|
|
28631
|
+
const vx = b.vx ?? 0;
|
|
28632
|
+
const vy = b.vy ?? 0;
|
|
28633
|
+
const vz = b.vz ?? 0;
|
|
28634
|
+
const arrowRadius = Math.max(0.05, radius * 0.15);
|
|
28635
|
+
if (showVelocity && (vx !== 0 || vy !== 0 || vz !== 0)) {
|
|
28636
|
+
const arrow = arrowBetween(
|
|
28637
|
+
[b.x, b.y, bz],
|
|
28638
|
+
[b.x + vx * velocityScale, b.y + vy * velocityScale, bz + vz * velocityScale],
|
|
28639
|
+
"#16a34a",
|
|
28640
|
+
arrowRadius
|
|
28641
|
+
);
|
|
28642
|
+
if (arrow) out.push(arrow);
|
|
28643
|
+
}
|
|
28644
|
+
const fx = b.fx ?? 0;
|
|
28645
|
+
const fy = b.fy ?? 0;
|
|
28646
|
+
const fz = b.fz ?? 0;
|
|
28647
|
+
if (showForces && (fx !== 0 || fy !== 0 || fz !== 0)) {
|
|
28648
|
+
const arrow = arrowBetween(
|
|
28649
|
+
[b.x, b.y, bz],
|
|
28650
|
+
[b.x + fx * forceScale, b.y + fy * forceScale, bz + fz * forceScale],
|
|
28651
|
+
"#dc2626",
|
|
28652
|
+
arrowRadius
|
|
28653
|
+
);
|
|
28654
|
+
if (arrow) out.push(arrow);
|
|
28655
|
+
}
|
|
28656
|
+
}
|
|
28657
|
+
return out;
|
|
28658
|
+
}, [mode, bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes, backgroundColor]);
|
|
28659
|
+
const bodyIndexById = useMemo(() => {
|
|
28660
|
+
const m = /* @__PURE__ */ new Map();
|
|
28661
|
+
bodies.forEach((b, i) => {
|
|
28662
|
+
if (b.id) m.set(b.id, i);
|
|
28663
|
+
});
|
|
28664
|
+
return m;
|
|
28665
|
+
}, [bodies]);
|
|
28666
|
+
if (mode === "3d") {
|
|
28667
|
+
return /* @__PURE__ */ jsx(
|
|
28668
|
+
LearningScene3D,
|
|
28669
|
+
{
|
|
28670
|
+
className,
|
|
28671
|
+
width,
|
|
28672
|
+
height,
|
|
28673
|
+
title,
|
|
28674
|
+
backgroundColor,
|
|
28675
|
+
drawables: drawables3D,
|
|
28676
|
+
camera,
|
|
28677
|
+
lighting,
|
|
28678
|
+
post,
|
|
28679
|
+
showGrid,
|
|
28680
|
+
shadows,
|
|
28681
|
+
interactive,
|
|
28682
|
+
isLoading,
|
|
28683
|
+
error,
|
|
28684
|
+
onItemClick: get3DClickPayload(onShapeClick, bodyIndexById)
|
|
28685
|
+
}
|
|
28686
|
+
);
|
|
28687
|
+
}
|
|
28263
28688
|
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
28264
28689
|
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
28265
28690
|
/* @__PURE__ */ jsx(
|
|
@@ -28269,7 +28694,7 @@ var init_PhysicsCanvas = __esm({
|
|
|
28269
28694
|
height,
|
|
28270
28695
|
backgroundColor,
|
|
28271
28696
|
shapes: derivedShapes,
|
|
28272
|
-
interactive,
|
|
28697
|
+
interactive: interactive ?? false,
|
|
28273
28698
|
animate,
|
|
28274
28699
|
onShapeClick,
|
|
28275
28700
|
isLoading,
|
|
@@ -28887,12 +29312,12 @@ var init_MapView = __esm({
|
|
|
28887
29312
|
shadowSize: [41, 41]
|
|
28888
29313
|
});
|
|
28889
29314
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28890
|
-
const { useEffect: useEffect63, useRef:
|
|
29315
|
+
const { useEffect: useEffect63, useRef: useRef63, useCallback: useCallback96, useState: useState94 } = React87__default;
|
|
28891
29316
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28892
29317
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28893
29318
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28894
29319
|
const map = useMap();
|
|
28895
|
-
const prevRef =
|
|
29320
|
+
const prevRef = useRef63({ centerLat, centerLng, zoom });
|
|
28896
29321
|
useEffect63(() => {
|
|
28897
29322
|
const prev = prevRef.current;
|
|
28898
29323
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
@@ -39715,7 +40140,7 @@ function getEnumOptions(field) {
|
|
|
39715
40140
|
}));
|
|
39716
40141
|
}
|
|
39717
40142
|
const validation = field.validation;
|
|
39718
|
-
if (validation?.enum &&
|
|
40143
|
+
if (validation?.enum && validation.enum.length > 0) {
|
|
39719
40144
|
return validation.enum.map((v) => ({
|
|
39720
40145
|
value: v,
|
|
39721
40146
|
label: v.charAt(0).toUpperCase() + v.slice(1).replace(/_/g, " ")
|