@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/avl/index.cjs
CHANGED
|
@@ -14117,9 +14117,10 @@ function Canvas({
|
|
|
14117
14117
|
drawables: [...drawables ?? [], ...childDrawables],
|
|
14118
14118
|
isLoading,
|
|
14119
14119
|
cameraMode: to3DCameraMode(camera?.mode),
|
|
14120
|
-
...zoom !== void 0 ? {
|
|
14120
|
+
...zoom !== void 0 ? { zoom } : {},
|
|
14121
14121
|
...camera?.fov !== void 0 ? { fov: camera.fov } : {},
|
|
14122
14122
|
...camera?.azimuth !== void 0 ? { azimuth: camera.azimuth } : {},
|
|
14123
|
+
...camera?.elevation !== void 0 ? { elevation: camera.elevation } : {},
|
|
14123
14124
|
...camera?.target !== void 0 ? { followTarget: camera.target } : {},
|
|
14124
14125
|
unitScale,
|
|
14125
14126
|
backgroundColor,
|
|
@@ -17171,23 +17172,188 @@ var init_AuthLayout = __esm({
|
|
|
17171
17172
|
AuthLayout.displayName = "AuthLayout";
|
|
17172
17173
|
}
|
|
17173
17174
|
});
|
|
17174
|
-
|
|
17175
|
+
function LearningScene3D({
|
|
17176
|
+
className,
|
|
17177
|
+
width = 600,
|
|
17178
|
+
height = 400,
|
|
17179
|
+
title,
|
|
17180
|
+
backgroundColor,
|
|
17181
|
+
drawables,
|
|
17182
|
+
camera,
|
|
17183
|
+
lighting,
|
|
17184
|
+
post,
|
|
17185
|
+
showGrid = false,
|
|
17186
|
+
shadows,
|
|
17187
|
+
interactive,
|
|
17188
|
+
isLoading,
|
|
17189
|
+
error,
|
|
17190
|
+
onItemClick
|
|
17191
|
+
}) {
|
|
17192
|
+
const instanceId = React94.useId().replace(/[^a-zA-Z0-9]/g, "");
|
|
17193
|
+
const clickEvent = onItemClick ? `LEARNING_SCENE_3D.ITEM_CLICK.${instanceId}` : void 0;
|
|
17194
|
+
const onItemClickRef = React94.useRef(onItemClick);
|
|
17195
|
+
onItemClickRef.current = onItemClick;
|
|
17196
|
+
useEventListener(`UI:${clickEvent ?? "LEARNING_SCENE_3D.ITEM_CLICK.__disabled"}`, (event) => {
|
|
17197
|
+
const unitId = event.payload?.unitId;
|
|
17198
|
+
if (typeof unitId === "string") onItemClickRef.current?.(unitId);
|
|
17199
|
+
});
|
|
17200
|
+
const props3d = {
|
|
17201
|
+
drawables,
|
|
17202
|
+
isLoading,
|
|
17203
|
+
error: error ? error.message : null,
|
|
17204
|
+
cameraMode: camera?.mode ?? "perspective",
|
|
17205
|
+
...camera?.zoom !== void 0 ? { zoom: camera.zoom } : {},
|
|
17206
|
+
...camera?.fov !== void 0 ? { fov: camera.fov } : {},
|
|
17207
|
+
...camera?.azimuth !== void 0 ? { azimuth: camera.azimuth } : {},
|
|
17208
|
+
...camera?.elevation !== void 0 ? { elevation: camera.elevation } : {},
|
|
17209
|
+
...camera?.target !== void 0 ? { followTarget: camera.target } : {},
|
|
17210
|
+
backgroundColor,
|
|
17211
|
+
showGrid,
|
|
17212
|
+
...shadows !== void 0 ? { shadows } : {},
|
|
17213
|
+
...interactive !== void 0 ? { controlsEnabled: interactive } : {},
|
|
17214
|
+
lighting,
|
|
17215
|
+
post,
|
|
17216
|
+
...clickEvent !== void 0 ? { unitClickEvent: clickEvent } : {}
|
|
17217
|
+
};
|
|
17218
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
17219
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
17220
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { width, height, display: "flex" }, children: /* @__PURE__ */ jsxRuntime.jsx(React94.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx(Canvas3DHost2, { ...props3d }) }) })
|
|
17221
|
+
] }) });
|
|
17222
|
+
}
|
|
17223
|
+
function meshSphere(id, x, y, z, radius, color, opts) {
|
|
17224
|
+
return {
|
|
17225
|
+
type: "draw-mesh",
|
|
17226
|
+
...id !== void 0 ? { id } : {},
|
|
17227
|
+
shape: opts?.shape ?? "sphere",
|
|
17228
|
+
position: { x, y, z },
|
|
17229
|
+
radius,
|
|
17230
|
+
pivot: "center",
|
|
17231
|
+
segments: opts?.segments ?? 24,
|
|
17232
|
+
material: { color, ...opts?.material },
|
|
17233
|
+
...opts?.opacity !== void 0 ? { opacity: opts.opacity } : {}
|
|
17234
|
+
};
|
|
17235
|
+
}
|
|
17236
|
+
function axisRotation(from, to) {
|
|
17237
|
+
const wx = to[0] - from[0];
|
|
17238
|
+
const wy = to[2] - from[2];
|
|
17239
|
+
const wz = to[1] - from[1];
|
|
17240
|
+
const len = Math.sqrt(wx * wx + wy * wy + wz * wz);
|
|
17241
|
+
const tilt = Math.acos(Math.min(1, Math.max(-1, len > 0 ? wy / len : 1)));
|
|
17242
|
+
return [0, Math.atan2(wz, -wx), tilt];
|
|
17243
|
+
}
|
|
17244
|
+
function segmentLength(from, to) {
|
|
17245
|
+
const dx = to[0] - from[0];
|
|
17246
|
+
const dy = to[1] - from[1];
|
|
17247
|
+
const dz = to[2] - from[2];
|
|
17248
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
17249
|
+
}
|
|
17250
|
+
function cylinderBetween(from, to, radius, color) {
|
|
17251
|
+
const len = segmentLength(from, to);
|
|
17252
|
+
if (len < 1e-6) return null;
|
|
17253
|
+
return {
|
|
17254
|
+
type: "draw-mesh",
|
|
17255
|
+
shape: "cylinder",
|
|
17256
|
+
position: { x: (from[0] + to[0]) / 2, y: (from[1] + to[1]) / 2, z: (from[2] + to[2]) / 2 },
|
|
17257
|
+
radius,
|
|
17258
|
+
height: len,
|
|
17259
|
+
rotation: axisRotation(from, to),
|
|
17260
|
+
pivot: "center",
|
|
17261
|
+
segments: 12,
|
|
17262
|
+
material: { color }
|
|
17263
|
+
};
|
|
17264
|
+
}
|
|
17265
|
+
function arrowBetween(from, to, color, shaftRadius = 0.08) {
|
|
17266
|
+
const len = segmentLength(from, to);
|
|
17267
|
+
if (len < 1e-6) return null;
|
|
17268
|
+
const tipLen = Math.min(shaftRadius * 8, len * 0.35);
|
|
17269
|
+
const k = (len - tipLen) / len;
|
|
17270
|
+
const delta = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];
|
|
17271
|
+
const shaftEnd = [delta[0] * k, delta[1] * k, delta[2] * k];
|
|
17272
|
+
const tipStart = shaftEnd;
|
|
17273
|
+
const tipEnd = delta;
|
|
17274
|
+
const shaft = cylinderBetween([0, 0, 0], shaftEnd, shaftRadius, color);
|
|
17275
|
+
const tipLenActual = segmentLength(tipStart, tipEnd);
|
|
17276
|
+
const tip = {
|
|
17277
|
+
type: "draw-mesh",
|
|
17278
|
+
shape: "cone",
|
|
17279
|
+
position: {
|
|
17280
|
+
x: (tipStart[0] + tipEnd[0]) / 2,
|
|
17281
|
+
y: (tipStart[1] + tipEnd[1]) / 2,
|
|
17282
|
+
z: (tipStart[2] + tipEnd[2]) / 2
|
|
17283
|
+
},
|
|
17284
|
+
radius: shaftRadius * 3,
|
|
17285
|
+
height: tipLenActual,
|
|
17286
|
+
rotation: axisRotation(tipStart, tipEnd),
|
|
17287
|
+
pivot: "center",
|
|
17288
|
+
segments: 12,
|
|
17289
|
+
material: { color }
|
|
17290
|
+
};
|
|
17291
|
+
return {
|
|
17292
|
+
type: "draw-group",
|
|
17293
|
+
position: { x: from[0], y: from[1], z: from[2] },
|
|
17294
|
+
items: tipLenActual < 1e-6 ? shaft ? [shaft] : [] : shaft ? [shaft, tip] : [tip]
|
|
17295
|
+
};
|
|
17296
|
+
}
|
|
17297
|
+
function billboardLabel(text, x, y, z, opts) {
|
|
17298
|
+
return {
|
|
17299
|
+
type: "draw-text",
|
|
17300
|
+
text,
|
|
17301
|
+
position: { x, y, z },
|
|
17302
|
+
color: opts?.color ?? "#111827"
|
|
17303
|
+
};
|
|
17304
|
+
}
|
|
17305
|
+
function labelColorForBackground(backgroundColor) {
|
|
17306
|
+
const m = /^#(?:([0-9a-f]{3})|([0-9a-f]{6}))$/i.exec(backgroundColor ?? "");
|
|
17307
|
+
if (!m) return "#111827";
|
|
17308
|
+
const hex = m[1] !== void 0 ? m[1].split("").map((c) => c + c).join("") : m[2];
|
|
17309
|
+
const r2 = parseInt(hex.slice(0, 2), 16) / 255;
|
|
17310
|
+
const g = parseInt(hex.slice(2, 4), 16) / 255;
|
|
17311
|
+
const b = parseInt(hex.slice(4, 6), 16) / 255;
|
|
17312
|
+
const luminance = 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
|
|
17313
|
+
return luminance < 0.5 ? "#e5e7eb" : "#111827";
|
|
17314
|
+
}
|
|
17315
|
+
function get3DClickPayload(onShapeClick, idToIndex) {
|
|
17316
|
+
if (!onShapeClick) return void 0;
|
|
17317
|
+
return (id) => onShapeClick({ id, index: idToIndex.get(id) ?? -1 });
|
|
17318
|
+
}
|
|
17319
|
+
var Canvas3DHost2;
|
|
17320
|
+
var init_learningScene3D = __esm({
|
|
17321
|
+
"components/learning/molecules/learningScene3D.tsx"() {
|
|
17322
|
+
"use client";
|
|
17323
|
+
init_atoms();
|
|
17324
|
+
init_Stack();
|
|
17325
|
+
init_useEventBus();
|
|
17326
|
+
Canvas3DHost2 = React94.lazy(
|
|
17327
|
+
() => import('@almadar/ui/components/molecules/game/three').then((m) => ({ default: m.Canvas3DHost }))
|
|
17328
|
+
);
|
|
17329
|
+
LearningScene3D.displayName = "LearningScene3D";
|
|
17330
|
+
}
|
|
17331
|
+
});
|
|
17332
|
+
var biologyLog, BiologyCanvas;
|
|
17175
17333
|
var init_BiologyCanvas = __esm({
|
|
17176
17334
|
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
17177
17335
|
"use client";
|
|
17178
17336
|
init_atoms();
|
|
17179
17337
|
init_Stack();
|
|
17180
17338
|
init_LearningCanvas();
|
|
17339
|
+
init_learningScene3D();
|
|
17340
|
+
biologyLog = logger.createLogger("almadar:ui:biology-canvas");
|
|
17181
17341
|
BiologyCanvas = ({
|
|
17182
17342
|
className,
|
|
17183
17343
|
width = 600,
|
|
17184
17344
|
height = 400,
|
|
17185
17345
|
title,
|
|
17186
17346
|
backgroundColor,
|
|
17347
|
+
mode = "2d",
|
|
17348
|
+
camera,
|
|
17349
|
+
lighting,
|
|
17350
|
+
post,
|
|
17187
17351
|
nodes = [],
|
|
17188
17352
|
edges = [],
|
|
17189
17353
|
shapes = [],
|
|
17190
|
-
|
|
17354
|
+
showGrid,
|
|
17355
|
+
shadows,
|
|
17356
|
+
interactive,
|
|
17191
17357
|
animate = false,
|
|
17192
17358
|
onShapeClick,
|
|
17193
17359
|
isLoading,
|
|
@@ -17248,6 +17414,75 @@ var init_BiologyCanvas = __esm({
|
|
|
17248
17414
|
out.push(...shapes);
|
|
17249
17415
|
return out;
|
|
17250
17416
|
}, [nodes, edges, shapes]);
|
|
17417
|
+
const drawables3D = React94.useMemo(() => {
|
|
17418
|
+
if (mode !== "3d") return [];
|
|
17419
|
+
if (shapes.length > 0) {
|
|
17420
|
+
biologyLog.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
17421
|
+
}
|
|
17422
|
+
const out = [];
|
|
17423
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
17424
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
17425
|
+
for (const n of nodes) {
|
|
17426
|
+
if (n.id) nodeById.set(n.id, n);
|
|
17427
|
+
}
|
|
17428
|
+
for (const e of edges) {
|
|
17429
|
+
const a = nodeById.get(e.from);
|
|
17430
|
+
const b = nodeById.get(e.to);
|
|
17431
|
+
if (!a || !b) continue;
|
|
17432
|
+
const edgeRadius = Math.max(0.04, Math.min(a.radius ?? 0.5, b.radius ?? 0.5) * 0.12);
|
|
17433
|
+
const edge = cylinderBetween([a.x, a.y, a.z ?? 0], [b.x, b.y, b.z ?? 0], edgeRadius, e.color ?? "#9ca3af");
|
|
17434
|
+
if (edge) out.push(edge);
|
|
17435
|
+
if (e.label) {
|
|
17436
|
+
out.push(
|
|
17437
|
+
billboardLabel(
|
|
17438
|
+
e.label,
|
|
17439
|
+
(a.x + b.x) / 2,
|
|
17440
|
+
(a.y + b.y) / 2,
|
|
17441
|
+
((a.z ?? 0) + (b.z ?? 0)) / 2,
|
|
17442
|
+
{ color: labelColor }
|
|
17443
|
+
)
|
|
17444
|
+
);
|
|
17445
|
+
}
|
|
17446
|
+
}
|
|
17447
|
+
for (const n of nodes) {
|
|
17448
|
+
const radius = n.radius ?? 0.5;
|
|
17449
|
+
const nz = n.z ?? 0;
|
|
17450
|
+
out.push(meshSphere(n.id, n.x, n.y, nz, radius, n.color ?? "#16a34a", { shape: n.shape, ...n.opacity !== void 0 ? { opacity: n.opacity } : {} }));
|
|
17451
|
+
if (n.label) {
|
|
17452
|
+
out.push(billboardLabel(n.label, n.x, n.y, nz + radius, { color: labelColor }));
|
|
17453
|
+
}
|
|
17454
|
+
}
|
|
17455
|
+
return out;
|
|
17456
|
+
}, [mode, nodes, edges, shapes, backgroundColor]);
|
|
17457
|
+
const nodeIndexById = React94.useMemo(() => {
|
|
17458
|
+
const m = /* @__PURE__ */ new Map();
|
|
17459
|
+
nodes.forEach((n, i) => {
|
|
17460
|
+
if (n.id) m.set(n.id, i);
|
|
17461
|
+
});
|
|
17462
|
+
return m;
|
|
17463
|
+
}, [nodes]);
|
|
17464
|
+
if (mode === "3d") {
|
|
17465
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17466
|
+
LearningScene3D,
|
|
17467
|
+
{
|
|
17468
|
+
className,
|
|
17469
|
+
width,
|
|
17470
|
+
height,
|
|
17471
|
+
title,
|
|
17472
|
+
backgroundColor,
|
|
17473
|
+
drawables: drawables3D,
|
|
17474
|
+
camera,
|
|
17475
|
+
lighting,
|
|
17476
|
+
post,
|
|
17477
|
+
showGrid,
|
|
17478
|
+
shadows,
|
|
17479
|
+
interactive,
|
|
17480
|
+
isLoading,
|
|
17481
|
+
error,
|
|
17482
|
+
onItemClick: get3DClickPayload(onShapeClick, nodeIndexById)
|
|
17483
|
+
}
|
|
17484
|
+
);
|
|
17485
|
+
}
|
|
17251
17486
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
17252
17487
|
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
17253
17488
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -17257,7 +17492,7 @@ var init_BiologyCanvas = __esm({
|
|
|
17257
17492
|
height,
|
|
17258
17493
|
backgroundColor,
|
|
17259
17494
|
shapes: derivedShapes,
|
|
17260
|
-
interactive,
|
|
17495
|
+
interactive: interactive ?? false,
|
|
17261
17496
|
animate,
|
|
17262
17497
|
onShapeClick,
|
|
17263
17498
|
isLoading,
|
|
@@ -24097,24 +24332,41 @@ var init_ChatBar = __esm({
|
|
|
24097
24332
|
ChatBar.displayName = "ChatBar";
|
|
24098
24333
|
}
|
|
24099
24334
|
});
|
|
24100
|
-
|
|
24335
|
+
function bondPerpendicular(a, b) {
|
|
24336
|
+
const dx = b[0] - a[0];
|
|
24337
|
+
const dy = b[1] - a[1];
|
|
24338
|
+
const px = dy;
|
|
24339
|
+
const py = -dx;
|
|
24340
|
+
const len = Math.sqrt(px * px + py * py);
|
|
24341
|
+
if (len < 1e-6) return [1, 0, 0];
|
|
24342
|
+
return [px / len, py / len, 0];
|
|
24343
|
+
}
|
|
24344
|
+
var chemistryLog, ChemistryCanvas;
|
|
24101
24345
|
var init_ChemistryCanvas = __esm({
|
|
24102
24346
|
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
24103
24347
|
"use client";
|
|
24104
24348
|
init_atoms();
|
|
24105
24349
|
init_Stack();
|
|
24106
24350
|
init_LearningCanvas();
|
|
24351
|
+
init_learningScene3D();
|
|
24352
|
+
chemistryLog = logger.createLogger("almadar:ui:chemistry-canvas");
|
|
24107
24353
|
ChemistryCanvas = ({
|
|
24108
24354
|
className,
|
|
24109
24355
|
width = 600,
|
|
24110
24356
|
height = 400,
|
|
24111
24357
|
title,
|
|
24112
24358
|
backgroundColor,
|
|
24359
|
+
mode = "2d",
|
|
24360
|
+
camera,
|
|
24361
|
+
lighting,
|
|
24362
|
+
post,
|
|
24113
24363
|
atoms = [],
|
|
24114
24364
|
bonds = [],
|
|
24115
24365
|
arrows = [],
|
|
24116
24366
|
shapes = [],
|
|
24117
|
-
|
|
24367
|
+
showGrid,
|
|
24368
|
+
shadows,
|
|
24369
|
+
interactive,
|
|
24118
24370
|
animate = false,
|
|
24119
24371
|
onShapeClick,
|
|
24120
24372
|
isLoading,
|
|
@@ -24193,6 +24445,88 @@ var init_ChemistryCanvas = __esm({
|
|
|
24193
24445
|
out.push(...shapes);
|
|
24194
24446
|
return out;
|
|
24195
24447
|
}, [atoms, bonds, arrows, shapes]);
|
|
24448
|
+
const drawables3D = React94.useMemo(() => {
|
|
24449
|
+
if (mode !== "3d") return [];
|
|
24450
|
+
if (shapes.length > 0) {
|
|
24451
|
+
chemistryLog.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
24452
|
+
}
|
|
24453
|
+
const out = [];
|
|
24454
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
24455
|
+
const atomById = /* @__PURE__ */ new Map();
|
|
24456
|
+
for (const a of atoms) {
|
|
24457
|
+
if (a.id) atomById.set(a.id, a);
|
|
24458
|
+
}
|
|
24459
|
+
for (const b of bonds) {
|
|
24460
|
+
const a = atomById.get(b.from);
|
|
24461
|
+
const c = atomById.get(b.to);
|
|
24462
|
+
if (!a || !c) continue;
|
|
24463
|
+
const color = b.color ?? "#6b7280";
|
|
24464
|
+
const from = [a.x, a.y, a.z ?? 0];
|
|
24465
|
+
const to = [c.x, c.y, c.z ?? 0];
|
|
24466
|
+
const perp = bondPerpendicular(from, to);
|
|
24467
|
+
const bondRadius = Math.max(0.06, Math.min(a.radius ?? 0.45, c.radius ?? 0.45) * 0.22);
|
|
24468
|
+
const step = bondRadius * 2.2;
|
|
24469
|
+
const offsets = b.type === "double" ? [-step, step] : b.type === "triple" ? [-step, 0, step] : [0];
|
|
24470
|
+
for (const off of offsets) {
|
|
24471
|
+
const bond = cylinderBetween(
|
|
24472
|
+
[from[0] + perp[0] * off, from[1] + perp[1] * off, from[2] + perp[2] * off],
|
|
24473
|
+
[to[0] + perp[0] * off, to[1] + perp[1] * off, to[2] + perp[2] * off],
|
|
24474
|
+
bondRadius,
|
|
24475
|
+
color
|
|
24476
|
+
);
|
|
24477
|
+
if (bond) out.push(bond);
|
|
24478
|
+
}
|
|
24479
|
+
}
|
|
24480
|
+
for (const a of arrows) {
|
|
24481
|
+
const angle = (a.angle ?? 0) * (Math.PI / 180);
|
|
24482
|
+
const len = a.length ?? 60;
|
|
24483
|
+
const x2 = a.x + Math.cos(angle) * len;
|
|
24484
|
+
const y2 = a.y + Math.sin(angle) * len;
|
|
24485
|
+
const arrow = arrowBetween([a.x, a.y, 0], [x2, y2, 0], a.color ?? "#dc2626");
|
|
24486
|
+
if (arrow) out.push(arrow);
|
|
24487
|
+
if (a.label) {
|
|
24488
|
+
out.push(billboardLabel(a.label, (a.x + x2) / 2, (a.y + y2) / 2, 0, { color: labelColor }));
|
|
24489
|
+
}
|
|
24490
|
+
}
|
|
24491
|
+
for (const a of atoms) {
|
|
24492
|
+
const radius = a.radius ?? 0.45;
|
|
24493
|
+
const az = a.z ?? 0;
|
|
24494
|
+
out.push(meshSphere(a.id, a.x, a.y, az, radius, a.color ?? "#2563eb"));
|
|
24495
|
+
if (a.element) {
|
|
24496
|
+
out.push(billboardLabel(a.element, a.x, a.y, az + radius, { color: labelColor }));
|
|
24497
|
+
}
|
|
24498
|
+
}
|
|
24499
|
+
return out;
|
|
24500
|
+
}, [mode, atoms, bonds, arrows, shapes, backgroundColor]);
|
|
24501
|
+
const atomIndexById = React94.useMemo(() => {
|
|
24502
|
+
const m = /* @__PURE__ */ new Map();
|
|
24503
|
+
atoms.forEach((a, i) => {
|
|
24504
|
+
if (a.id) m.set(a.id, i);
|
|
24505
|
+
});
|
|
24506
|
+
return m;
|
|
24507
|
+
}, [atoms]);
|
|
24508
|
+
if (mode === "3d") {
|
|
24509
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
24510
|
+
LearningScene3D,
|
|
24511
|
+
{
|
|
24512
|
+
className,
|
|
24513
|
+
width,
|
|
24514
|
+
height,
|
|
24515
|
+
title,
|
|
24516
|
+
backgroundColor,
|
|
24517
|
+
drawables: drawables3D,
|
|
24518
|
+
camera,
|
|
24519
|
+
lighting,
|
|
24520
|
+
post,
|
|
24521
|
+
showGrid,
|
|
24522
|
+
shadows,
|
|
24523
|
+
interactive,
|
|
24524
|
+
isLoading,
|
|
24525
|
+
error,
|
|
24526
|
+
onItemClick: get3DClickPayload(onShapeClick, atomIndexById)
|
|
24527
|
+
}
|
|
24528
|
+
);
|
|
24529
|
+
}
|
|
24196
24530
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
24197
24531
|
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
24198
24532
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -24202,7 +24536,7 @@ var init_ChemistryCanvas = __esm({
|
|
|
24202
24536
|
height,
|
|
24203
24537
|
backgroundColor,
|
|
24204
24538
|
shapes: derivedShapes,
|
|
24205
|
-
interactive,
|
|
24539
|
+
interactive: interactive ?? false,
|
|
24206
24540
|
animate,
|
|
24207
24541
|
onShapeClick,
|
|
24208
24542
|
isLoading,
|
|
@@ -30507,19 +30841,25 @@ var init_MathCanvas = __esm({
|
|
|
30507
30841
|
};
|
|
30508
30842
|
}
|
|
30509
30843
|
});
|
|
30510
|
-
var PhysicsCanvas;
|
|
30844
|
+
var physicsLog2, PhysicsCanvas;
|
|
30511
30845
|
var init_PhysicsCanvas = __esm({
|
|
30512
30846
|
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
30513
30847
|
"use client";
|
|
30514
30848
|
init_atoms();
|
|
30515
30849
|
init_Stack();
|
|
30516
30850
|
init_LearningCanvas();
|
|
30851
|
+
init_learningScene3D();
|
|
30852
|
+
physicsLog2 = logger.createLogger("almadar:ui:physics-canvas");
|
|
30517
30853
|
PhysicsCanvas = ({
|
|
30518
30854
|
className,
|
|
30519
30855
|
width = 600,
|
|
30520
30856
|
height = 400,
|
|
30521
30857
|
title,
|
|
30522
30858
|
backgroundColor,
|
|
30859
|
+
mode = "2d",
|
|
30860
|
+
camera,
|
|
30861
|
+
lighting,
|
|
30862
|
+
post,
|
|
30523
30863
|
bodies = [],
|
|
30524
30864
|
constraints = [],
|
|
30525
30865
|
showVelocity = true,
|
|
@@ -30527,7 +30867,9 @@ var init_PhysicsCanvas = __esm({
|
|
|
30527
30867
|
velocityScale = 20,
|
|
30528
30868
|
forceScale = 20,
|
|
30529
30869
|
shapes = [],
|
|
30530
|
-
|
|
30870
|
+
showGrid,
|
|
30871
|
+
shadows,
|
|
30872
|
+
interactive,
|
|
30531
30873
|
animate = false,
|
|
30532
30874
|
onShapeClick,
|
|
30533
30875
|
isLoading,
|
|
@@ -30599,6 +30941,89 @@ var init_PhysicsCanvas = __esm({
|
|
|
30599
30941
|
out.push(...shapes);
|
|
30600
30942
|
return out;
|
|
30601
30943
|
}, [bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes]);
|
|
30944
|
+
const drawables3D = React94.useMemo(() => {
|
|
30945
|
+
if (mode !== "3d") return [];
|
|
30946
|
+
if (shapes.length > 0) {
|
|
30947
|
+
physicsLog2.debug("shapes ignored in 3D mode (pixel-authored 2D vocabulary)", { count: shapes.length });
|
|
30948
|
+
}
|
|
30949
|
+
const out = [];
|
|
30950
|
+
const labelColor = labelColorForBackground(backgroundColor);
|
|
30951
|
+
const bodyById = /* @__PURE__ */ new Map();
|
|
30952
|
+
for (const b of bodies) {
|
|
30953
|
+
if (b.id) bodyById.set(b.id, b);
|
|
30954
|
+
}
|
|
30955
|
+
for (const c of constraints) {
|
|
30956
|
+
const a = bodyById.get(c.from);
|
|
30957
|
+
const b = bodyById.get(c.to);
|
|
30958
|
+
if (!a || !b) continue;
|
|
30959
|
+
const rodRadius = Math.max(0.05, Math.min(a.radius ?? 0.5, b.radius ?? 0.5) * 0.15);
|
|
30960
|
+
const rod = cylinderBetween([a.x, a.y, a.z ?? 0], [b.x, b.y, b.z ?? 0], rodRadius, c.color ?? "#9ca3af");
|
|
30961
|
+
if (rod) out.push(rod);
|
|
30962
|
+
}
|
|
30963
|
+
for (const b of bodies) {
|
|
30964
|
+
const radius = b.radius ?? 0.5;
|
|
30965
|
+
const bz = b.z ?? 0;
|
|
30966
|
+
out.push(meshSphere(b.id, b.x, b.y, bz, radius, b.color ?? "#2563eb"));
|
|
30967
|
+
if (b.label) {
|
|
30968
|
+
out.push(billboardLabel(b.label, b.x, b.y, bz + radius, { color: labelColor }));
|
|
30969
|
+
}
|
|
30970
|
+
const vx = b.vx ?? 0;
|
|
30971
|
+
const vy = b.vy ?? 0;
|
|
30972
|
+
const vz = b.vz ?? 0;
|
|
30973
|
+
const arrowRadius = Math.max(0.05, radius * 0.15);
|
|
30974
|
+
if (showVelocity && (vx !== 0 || vy !== 0 || vz !== 0)) {
|
|
30975
|
+
const arrow = arrowBetween(
|
|
30976
|
+
[b.x, b.y, bz],
|
|
30977
|
+
[b.x + vx * velocityScale, b.y + vy * velocityScale, bz + vz * velocityScale],
|
|
30978
|
+
"#16a34a",
|
|
30979
|
+
arrowRadius
|
|
30980
|
+
);
|
|
30981
|
+
if (arrow) out.push(arrow);
|
|
30982
|
+
}
|
|
30983
|
+
const fx = b.fx ?? 0;
|
|
30984
|
+
const fy = b.fy ?? 0;
|
|
30985
|
+
const fz = b.fz ?? 0;
|
|
30986
|
+
if (showForces && (fx !== 0 || fy !== 0 || fz !== 0)) {
|
|
30987
|
+
const arrow = arrowBetween(
|
|
30988
|
+
[b.x, b.y, bz],
|
|
30989
|
+
[b.x + fx * forceScale, b.y + fy * forceScale, bz + fz * forceScale],
|
|
30990
|
+
"#dc2626",
|
|
30991
|
+
arrowRadius
|
|
30992
|
+
);
|
|
30993
|
+
if (arrow) out.push(arrow);
|
|
30994
|
+
}
|
|
30995
|
+
}
|
|
30996
|
+
return out;
|
|
30997
|
+
}, [mode, bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes, backgroundColor]);
|
|
30998
|
+
const bodyIndexById = React94.useMemo(() => {
|
|
30999
|
+
const m = /* @__PURE__ */ new Map();
|
|
31000
|
+
bodies.forEach((b, i) => {
|
|
31001
|
+
if (b.id) m.set(b.id, i);
|
|
31002
|
+
});
|
|
31003
|
+
return m;
|
|
31004
|
+
}, [bodies]);
|
|
31005
|
+
if (mode === "3d") {
|
|
31006
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
31007
|
+
LearningScene3D,
|
|
31008
|
+
{
|
|
31009
|
+
className,
|
|
31010
|
+
width,
|
|
31011
|
+
height,
|
|
31012
|
+
title,
|
|
31013
|
+
backgroundColor,
|
|
31014
|
+
drawables: drawables3D,
|
|
31015
|
+
camera,
|
|
31016
|
+
lighting,
|
|
31017
|
+
post,
|
|
31018
|
+
showGrid,
|
|
31019
|
+
shadows,
|
|
31020
|
+
interactive,
|
|
31021
|
+
isLoading,
|
|
31022
|
+
error,
|
|
31023
|
+
onItemClick: get3DClickPayload(onShapeClick, bodyIndexById)
|
|
31024
|
+
}
|
|
31025
|
+
);
|
|
31026
|
+
}
|
|
30602
31027
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
30603
31028
|
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
30604
31029
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -30608,7 +31033,7 @@ var init_PhysicsCanvas = __esm({
|
|
|
30608
31033
|
height,
|
|
30609
31034
|
backgroundColor,
|
|
30610
31035
|
shapes: derivedShapes,
|
|
30611
|
-
interactive,
|
|
31036
|
+
interactive: interactive ?? false,
|
|
30612
31037
|
animate,
|
|
30613
31038
|
onShapeClick,
|
|
30614
31039
|
isLoading,
|
|
@@ -31226,12 +31651,12 @@ var init_MapView = __esm({
|
|
|
31226
31651
|
shadowSize: [41, 41]
|
|
31227
31652
|
});
|
|
31228
31653
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
31229
|
-
const { useEffect: useEffect64, useRef:
|
|
31654
|
+
const { useEffect: useEffect64, useRef: useRef65, useCallback: useCallback96, useState: useState100 } = React94__namespace.default;
|
|
31230
31655
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
31231
31656
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
31232
31657
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
31233
31658
|
const map = useMap();
|
|
31234
|
-
const prevRef =
|
|
31659
|
+
const prevRef = useRef65({ centerLat, centerLng, zoom });
|
|
31235
31660
|
useEffect64(() => {
|
|
31236
31661
|
const prev = prevRef.current;
|
|
31237
31662
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
@@ -41645,7 +42070,7 @@ function getEnumOptions(field) {
|
|
|
41645
42070
|
}));
|
|
41646
42071
|
}
|
|
41647
42072
|
const validation = field.validation;
|
|
41648
|
-
if (validation?.enum &&
|
|
42073
|
+
if (validation?.enum && validation.enum.length > 0) {
|
|
41649
42074
|
return validation.enum.map((v) => ({
|
|
41650
42075
|
value: v,
|
|
41651
42076
|
label: v.charAt(0).toUpperCase() + v.slice(1).replace(/_/g, " ")
|