@almadar/ui 5.147.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 +535 -15
- package/dist/avl/index.js +535 -15
- 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 +545 -18
- package/dist/components/index.d.cts +278 -98
- package/dist/components/index.d.ts +278 -98
- package/dist/components/index.js +541 -20
- 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 +535 -15
- package/dist/providers/index.d.cts +2 -1
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/index.js +535 -15
- package/dist/runtime/index.cjs +535 -15
- package/dist/runtime/index.js +535 -15
- package/dist/types-B3nHgnMG.d.cts +51 -0
- package/dist/types-B3nHgnMG.d.ts +51 -0
- package/package.json +4 -4
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,
|
|
@@ -11779,7 +11780,10 @@ var init_LearningCanvas = __esm({
|
|
|
11779
11780
|
ctx.fillRect(0, 0, width, height);
|
|
11780
11781
|
}
|
|
11781
11782
|
for (const shape of shapes) {
|
|
11782
|
-
drawShape(ctx, shape, width, height);
|
|
11783
|
+
if (shape.type !== "text") drawShape(ctx, shape, width, height);
|
|
11784
|
+
}
|
|
11785
|
+
for (const shape of shapes) {
|
|
11786
|
+
if (shape.type === "text") drawShape(ctx, shape, width, height);
|
|
11783
11787
|
}
|
|
11784
11788
|
}, [width, height, backgroundColor, shapes]);
|
|
11785
11789
|
useEffect(() => {
|
|
@@ -13725,7 +13729,7 @@ var init_AlgorithmCanvas = __esm({
|
|
|
13725
13729
|
DEFAULT_CELL_COLOR = "#e5e7eb";
|
|
13726
13730
|
DEFAULT_POINTER_COLOR = "#dc2626";
|
|
13727
13731
|
POINTER_BAND = 34;
|
|
13728
|
-
TOP_PAD =
|
|
13732
|
+
TOP_PAD = 26;
|
|
13729
13733
|
AlgorithmCanvas = ({
|
|
13730
13734
|
className,
|
|
13731
13735
|
width = 600,
|
|
@@ -14829,23 +14833,188 @@ var init_BehaviorView = __esm({
|
|
|
14829
14833
|
BehaviorView.displayName = "BehaviorView";
|
|
14830
14834
|
}
|
|
14831
14835
|
});
|
|
14832
|
-
|
|
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;
|
|
14833
14994
|
var init_BiologyCanvas = __esm({
|
|
14834
14995
|
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
14835
14996
|
"use client";
|
|
14836
14997
|
init_atoms();
|
|
14837
14998
|
init_Stack();
|
|
14838
14999
|
init_LearningCanvas();
|
|
15000
|
+
init_learningScene3D();
|
|
15001
|
+
biologyLog = createLogger("almadar:ui:biology-canvas");
|
|
14839
15002
|
BiologyCanvas = ({
|
|
14840
15003
|
className,
|
|
14841
15004
|
width = 600,
|
|
14842
15005
|
height = 400,
|
|
14843
15006
|
title,
|
|
14844
15007
|
backgroundColor,
|
|
15008
|
+
mode = "2d",
|
|
15009
|
+
camera,
|
|
15010
|
+
lighting,
|
|
15011
|
+
post,
|
|
14845
15012
|
nodes = [],
|
|
14846
15013
|
edges = [],
|
|
14847
15014
|
shapes = [],
|
|
14848
|
-
|
|
15015
|
+
showGrid,
|
|
15016
|
+
shadows,
|
|
15017
|
+
interactive,
|
|
14849
15018
|
animate = false,
|
|
14850
15019
|
onShapeClick,
|
|
14851
15020
|
isLoading,
|
|
@@ -14906,6 +15075,75 @@ var init_BiologyCanvas = __esm({
|
|
|
14906
15075
|
out.push(...shapes);
|
|
14907
15076
|
return out;
|
|
14908
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
|
+
}
|
|
14909
15147
|
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
14910
15148
|
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
14911
15149
|
/* @__PURE__ */ jsx(
|
|
@@ -14915,7 +15153,7 @@ var init_BiologyCanvas = __esm({
|
|
|
14915
15153
|
height,
|
|
14916
15154
|
backgroundColor,
|
|
14917
15155
|
shapes: derivedShapes,
|
|
14918
|
-
interactive,
|
|
15156
|
+
interactive: interactive ?? false,
|
|
14919
15157
|
animate,
|
|
14920
15158
|
onShapeClick,
|
|
14921
15159
|
isLoading,
|
|
@@ -21755,24 +21993,41 @@ var init_ChatBar = __esm({
|
|
|
21755
21993
|
ChatBar.displayName = "ChatBar";
|
|
21756
21994
|
}
|
|
21757
21995
|
});
|
|
21758
|
-
|
|
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;
|
|
21759
22006
|
var init_ChemistryCanvas = __esm({
|
|
21760
22007
|
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
21761
22008
|
"use client";
|
|
21762
22009
|
init_atoms();
|
|
21763
22010
|
init_Stack();
|
|
21764
22011
|
init_LearningCanvas();
|
|
22012
|
+
init_learningScene3D();
|
|
22013
|
+
chemistryLog = createLogger("almadar:ui:chemistry-canvas");
|
|
21765
22014
|
ChemistryCanvas = ({
|
|
21766
22015
|
className,
|
|
21767
22016
|
width = 600,
|
|
21768
22017
|
height = 400,
|
|
21769
22018
|
title,
|
|
21770
22019
|
backgroundColor,
|
|
22020
|
+
mode = "2d",
|
|
22021
|
+
camera,
|
|
22022
|
+
lighting,
|
|
22023
|
+
post,
|
|
21771
22024
|
atoms = [],
|
|
21772
22025
|
bonds = [],
|
|
21773
22026
|
arrows = [],
|
|
21774
22027
|
shapes = [],
|
|
21775
|
-
|
|
22028
|
+
showGrid,
|
|
22029
|
+
shadows,
|
|
22030
|
+
interactive,
|
|
21776
22031
|
animate = false,
|
|
21777
22032
|
onShapeClick,
|
|
21778
22033
|
isLoading,
|
|
@@ -21851,6 +22106,88 @@ var init_ChemistryCanvas = __esm({
|
|
|
21851
22106
|
out.push(...shapes);
|
|
21852
22107
|
return out;
|
|
21853
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
|
+
}
|
|
21854
22191
|
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
21855
22192
|
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
21856
22193
|
/* @__PURE__ */ jsx(
|
|
@@ -21860,7 +22197,7 @@ var init_ChemistryCanvas = __esm({
|
|
|
21860
22197
|
height,
|
|
21861
22198
|
backgroundColor,
|
|
21862
22199
|
shapes: derivedShapes,
|
|
21863
|
-
interactive,
|
|
22200
|
+
interactive: interactive ?? false,
|
|
21864
22201
|
animate,
|
|
21865
22202
|
onShapeClick,
|
|
21866
22203
|
isLoading,
|
|
@@ -25331,6 +25668,7 @@ var init_FilterGroup = __esm({
|
|
|
25331
25668
|
init_Badge();
|
|
25332
25669
|
init_Stack();
|
|
25333
25670
|
init_Icon();
|
|
25671
|
+
init_RangeSlider();
|
|
25334
25672
|
init_useEventBus();
|
|
25335
25673
|
init_useQuerySingleton();
|
|
25336
25674
|
resolveFilterType = (filter) => filter.filterType ?? filter.type;
|
|
@@ -25525,6 +25863,35 @@ var init_FilterGroup = __esm({
|
|
|
25525
25863
|
onClear: () => handleFilterSelect(`${filter.field}_to`, null)
|
|
25526
25864
|
}
|
|
25527
25865
|
)
|
|
25866
|
+
] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
25867
|
+
/* @__PURE__ */ jsx(
|
|
25868
|
+
RangeSlider,
|
|
25869
|
+
{
|
|
25870
|
+
min: filter.min ?? 0,
|
|
25871
|
+
max: filter.max ?? 100,
|
|
25872
|
+
step: filter.step ?? 1,
|
|
25873
|
+
value: Number(
|
|
25874
|
+
selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
|
|
25875
|
+
),
|
|
25876
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
|
|
25877
|
+
showTooltip: true,
|
|
25878
|
+
"aria-label": t("filterGroup.from")
|
|
25879
|
+
}
|
|
25880
|
+
),
|
|
25881
|
+
/* @__PURE__ */ jsx(
|
|
25882
|
+
RangeSlider,
|
|
25883
|
+
{
|
|
25884
|
+
min: filter.min ?? 0,
|
|
25885
|
+
max: filter.max ?? 100,
|
|
25886
|
+
step: filter.step ?? 1,
|
|
25887
|
+
value: Number(
|
|
25888
|
+
selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
|
|
25889
|
+
),
|
|
25890
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
|
|
25891
|
+
showTooltip: true,
|
|
25892
|
+
"aria-label": t("filterGroup.to")
|
|
25893
|
+
}
|
|
25894
|
+
)
|
|
25528
25895
|
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
25529
25896
|
Input,
|
|
25530
25897
|
{
|
|
@@ -25607,6 +25974,36 @@ var init_FilterGroup = __esm({
|
|
|
25607
25974
|
className: "text-sm min-w-[100px]"
|
|
25608
25975
|
}
|
|
25609
25976
|
)
|
|
25977
|
+
] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
25978
|
+
/* @__PURE__ */ jsx(
|
|
25979
|
+
RangeSlider,
|
|
25980
|
+
{
|
|
25981
|
+
min: filter.min ?? 0,
|
|
25982
|
+
max: filter.max ?? 100,
|
|
25983
|
+
step: filter.step ?? 1,
|
|
25984
|
+
value: Number(
|
|
25985
|
+
selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
|
|
25986
|
+
),
|
|
25987
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
|
|
25988
|
+
className: "min-w-[100px]",
|
|
25989
|
+
"aria-label": t("filterGroup.from")
|
|
25990
|
+
}
|
|
25991
|
+
),
|
|
25992
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "-" }),
|
|
25993
|
+
/* @__PURE__ */ jsx(
|
|
25994
|
+
RangeSlider,
|
|
25995
|
+
{
|
|
25996
|
+
min: filter.min ?? 0,
|
|
25997
|
+
max: filter.max ?? 100,
|
|
25998
|
+
step: filter.step ?? 1,
|
|
25999
|
+
value: Number(
|
|
26000
|
+
selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
|
|
26001
|
+
),
|
|
26002
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
|
|
26003
|
+
className: "min-w-[100px]",
|
|
26004
|
+
"aria-label": t("filterGroup.to")
|
|
26005
|
+
}
|
|
26006
|
+
)
|
|
25610
26007
|
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
25611
26008
|
Input,
|
|
25612
26009
|
{
|
|
@@ -25725,6 +26122,38 @@ var init_FilterGroup = __esm({
|
|
|
25725
26122
|
className: "min-w-[130px]"
|
|
25726
26123
|
}
|
|
25727
26124
|
)
|
|
26125
|
+
] }) : resolveFilterType(filter) === "numberrange" || resolveFilterType(filter) === "number-range" ? /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
26126
|
+
/* @__PURE__ */ jsx(
|
|
26127
|
+
RangeSlider,
|
|
26128
|
+
{
|
|
26129
|
+
min: filter.min ?? 0,
|
|
26130
|
+
max: filter.max ?? 100,
|
|
26131
|
+
step: filter.step ?? 1,
|
|
26132
|
+
value: Number(
|
|
26133
|
+
selectedValues[`${filter.field}_min`] ?? filter.min ?? 0
|
|
26134
|
+
),
|
|
26135
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_min`, String(v)),
|
|
26136
|
+
showTooltip: true,
|
|
26137
|
+
className: "min-w-[130px]",
|
|
26138
|
+
"aria-label": t("filterGroup.from")
|
|
26139
|
+
}
|
|
26140
|
+
),
|
|
26141
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "-" }),
|
|
26142
|
+
/* @__PURE__ */ jsx(
|
|
26143
|
+
RangeSlider,
|
|
26144
|
+
{
|
|
26145
|
+
min: filter.min ?? 0,
|
|
26146
|
+
max: filter.max ?? 100,
|
|
26147
|
+
step: filter.step ?? 1,
|
|
26148
|
+
value: Number(
|
|
26149
|
+
selectedValues[`${filter.field}_max`] ?? filter.max ?? 100
|
|
26150
|
+
),
|
|
26151
|
+
onChange: (v) => handleFilterSelect(`${filter.field}_max`, String(v)),
|
|
26152
|
+
showTooltip: true,
|
|
26153
|
+
className: "min-w-[130px]",
|
|
26154
|
+
"aria-label": t("filterGroup.to")
|
|
26155
|
+
}
|
|
26156
|
+
)
|
|
25728
26157
|
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
25729
26158
|
Input,
|
|
25730
26159
|
{
|
|
@@ -28073,19 +28502,25 @@ var init_MathCanvas = __esm({
|
|
|
28073
28502
|
};
|
|
28074
28503
|
}
|
|
28075
28504
|
});
|
|
28076
|
-
var PhysicsCanvas;
|
|
28505
|
+
var physicsLog2, PhysicsCanvas;
|
|
28077
28506
|
var init_PhysicsCanvas = __esm({
|
|
28078
28507
|
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
28079
28508
|
"use client";
|
|
28080
28509
|
init_atoms();
|
|
28081
28510
|
init_Stack();
|
|
28082
28511
|
init_LearningCanvas();
|
|
28512
|
+
init_learningScene3D();
|
|
28513
|
+
physicsLog2 = createLogger("almadar:ui:physics-canvas");
|
|
28083
28514
|
PhysicsCanvas = ({
|
|
28084
28515
|
className,
|
|
28085
28516
|
width = 600,
|
|
28086
28517
|
height = 400,
|
|
28087
28518
|
title,
|
|
28088
28519
|
backgroundColor,
|
|
28520
|
+
mode = "2d",
|
|
28521
|
+
camera,
|
|
28522
|
+
lighting,
|
|
28523
|
+
post,
|
|
28089
28524
|
bodies = [],
|
|
28090
28525
|
constraints = [],
|
|
28091
28526
|
showVelocity = true,
|
|
@@ -28093,7 +28528,9 @@ var init_PhysicsCanvas = __esm({
|
|
|
28093
28528
|
velocityScale = 20,
|
|
28094
28529
|
forceScale = 20,
|
|
28095
28530
|
shapes = [],
|
|
28096
|
-
|
|
28531
|
+
showGrid,
|
|
28532
|
+
shadows,
|
|
28533
|
+
interactive,
|
|
28097
28534
|
animate = false,
|
|
28098
28535
|
onShapeClick,
|
|
28099
28536
|
isLoading,
|
|
@@ -28165,6 +28602,89 @@ var init_PhysicsCanvas = __esm({
|
|
|
28165
28602
|
out.push(...shapes);
|
|
28166
28603
|
return out;
|
|
28167
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
|
+
}
|
|
28168
28688
|
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
28169
28689
|
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
28170
28690
|
/* @__PURE__ */ jsx(
|
|
@@ -28174,7 +28694,7 @@ var init_PhysicsCanvas = __esm({
|
|
|
28174
28694
|
height,
|
|
28175
28695
|
backgroundColor,
|
|
28176
28696
|
shapes: derivedShapes,
|
|
28177
|
-
interactive,
|
|
28697
|
+
interactive: interactive ?? false,
|
|
28178
28698
|
animate,
|
|
28179
28699
|
onShapeClick,
|
|
28180
28700
|
isLoading,
|
|
@@ -28792,12 +29312,12 @@ var init_MapView = __esm({
|
|
|
28792
29312
|
shadowSize: [41, 41]
|
|
28793
29313
|
});
|
|
28794
29314
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28795
|
-
const { useEffect: useEffect63, useRef:
|
|
29315
|
+
const { useEffect: useEffect63, useRef: useRef63, useCallback: useCallback96, useState: useState94 } = React87__default;
|
|
28796
29316
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28797
29317
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28798
29318
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28799
29319
|
const map = useMap();
|
|
28800
|
-
const prevRef =
|
|
29320
|
+
const prevRef = useRef63({ centerLat, centerLng, zoom });
|
|
28801
29321
|
useEffect63(() => {
|
|
28802
29322
|
const prev = prevRef.current;
|
|
28803
29323
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
@@ -39620,7 +40140,7 @@ function getEnumOptions(field) {
|
|
|
39620
40140
|
}));
|
|
39621
40141
|
}
|
|
39622
40142
|
const validation = field.validation;
|
|
39623
|
-
if (validation?.enum &&
|
|
40143
|
+
if (validation?.enum && validation.enum.length > 0) {
|
|
39624
40144
|
return validation.enum.map((v) => ({
|
|
39625
40145
|
value: v,
|
|
39626
40146
|
label: v.charAt(0).toUpperCase() + v.slice(1).replace(/_/g, " ")
|