@almadar/ui 5.110.0 → 5.111.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/avl/index.cjs +29 -13
- package/dist/avl/index.js +29 -13
- package/dist/components/game/atoms/DrawShape.d.ts +6 -6
- package/dist/components/game/atoms/DrawSprite.d.ts +2 -2
- package/dist/components/index.cjs +29 -13
- package/dist/components/index.js +29 -13
- package/dist/lib/drawable/three/index.cjs +330 -178
- package/dist/lib/drawable/three/index.js +174 -22
- package/dist/lib/index.cjs +8 -0
- package/dist/lib/index.js +8 -1
- package/dist/lib/verificationRegistry.d.ts +6 -0
- package/dist/providers/index.cjs +29 -13
- package/dist/providers/index.js +29 -13
- package/dist/runtime/index.cjs +29 -13
- package/dist/runtime/index.js +29 -13
- package/package.json +7 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React3 = require('react');
|
|
4
4
|
var providers = require('@almadar/ui/providers');
|
|
5
5
|
var logger = require('@almadar/logger');
|
|
6
6
|
var fiber = require('@react-three/fiber');
|
|
@@ -37,7 +37,7 @@ function _interopNamespace(e) {
|
|
|
37
37
|
return Object.freeze(n);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
var
|
|
40
|
+
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
41
41
|
var THREE9__namespace = /*#__PURE__*/_interopNamespace(THREE9);
|
|
42
42
|
|
|
43
43
|
var __defProp = Object.defineProperty;
|
|
@@ -117,10 +117,10 @@ var fallbackEventBus = {
|
|
|
117
117
|
}
|
|
118
118
|
};
|
|
119
119
|
function useEventBus() {
|
|
120
|
-
const context =
|
|
120
|
+
const context = React3.useContext(providers.EventBusContext);
|
|
121
121
|
const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
|
|
122
122
|
const scope = providers.useTraitScope();
|
|
123
|
-
return
|
|
123
|
+
return React3.useMemo(() => {
|
|
124
124
|
if (!scope) {
|
|
125
125
|
return {
|
|
126
126
|
...baseBus,
|
|
@@ -156,7 +156,7 @@ function useEventBus() {
|
|
|
156
156
|
}
|
|
157
157
|
function useEmitEvent() {
|
|
158
158
|
const eventBus = useEventBus();
|
|
159
|
-
return
|
|
159
|
+
return React3.useCallback(
|
|
160
160
|
(type, payload, source) => {
|
|
161
161
|
eventBus.emit(type, payload, source);
|
|
162
162
|
},
|
|
@@ -208,9 +208,9 @@ function useGameCanvas3DEvents(options) {
|
|
|
208
208
|
onUnitAnimation
|
|
209
209
|
} = options;
|
|
210
210
|
const emit = useEmitEvent();
|
|
211
|
-
const optionsRef =
|
|
211
|
+
const optionsRef = React3.useRef(options);
|
|
212
212
|
optionsRef.current = options;
|
|
213
|
-
const handleTileClick =
|
|
213
|
+
const handleTileClick = React3.useCallback(
|
|
214
214
|
(tile, event) => {
|
|
215
215
|
if (tileClickEvent) {
|
|
216
216
|
emit(tileClickEvent, {
|
|
@@ -226,7 +226,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
226
226
|
},
|
|
227
227
|
[tileClickEvent, emit]
|
|
228
228
|
);
|
|
229
|
-
const handleUnitClick =
|
|
229
|
+
const handleUnitClick = React3.useCallback(
|
|
230
230
|
(unit, event) => {
|
|
231
231
|
if (unitClickEvent) {
|
|
232
232
|
emit(unitClickEvent, {
|
|
@@ -245,7 +245,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
245
245
|
},
|
|
246
246
|
[unitClickEvent, emit]
|
|
247
247
|
);
|
|
248
|
-
const handleFeatureClick =
|
|
248
|
+
const handleFeatureClick = React3.useCallback(
|
|
249
249
|
(feature, event) => {
|
|
250
250
|
if (featureClickEvent) {
|
|
251
251
|
emit(featureClickEvent, {
|
|
@@ -260,7 +260,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
260
260
|
},
|
|
261
261
|
[featureClickEvent, emit]
|
|
262
262
|
);
|
|
263
|
-
const handleCanvasClick =
|
|
263
|
+
const handleCanvasClick = React3.useCallback(
|
|
264
264
|
(event) => {
|
|
265
265
|
if (canvasClickEvent) {
|
|
266
266
|
emit(canvasClickEvent, {
|
|
@@ -273,7 +273,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
273
273
|
},
|
|
274
274
|
[canvasClickEvent, emit]
|
|
275
275
|
);
|
|
276
|
-
const handleTileHover =
|
|
276
|
+
const handleTileHover = React3.useCallback(
|
|
277
277
|
(tile, event) => {
|
|
278
278
|
if (tile) {
|
|
279
279
|
if (tileHoverEvent) {
|
|
@@ -293,7 +293,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
293
293
|
},
|
|
294
294
|
[tileHoverEvent, tileLeaveEvent, emit]
|
|
295
295
|
);
|
|
296
|
-
const handleUnitAnimation =
|
|
296
|
+
const handleUnitAnimation = React3.useCallback(
|
|
297
297
|
(unitId, state) => {
|
|
298
298
|
if (unitAnimationEvent) {
|
|
299
299
|
emit(unitAnimationEvent, {
|
|
@@ -306,7 +306,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
306
306
|
},
|
|
307
307
|
[unitAnimationEvent, emit]
|
|
308
308
|
);
|
|
309
|
-
const handleCameraChange =
|
|
309
|
+
const handleCameraChange = React3.useCallback(
|
|
310
310
|
(position) => {
|
|
311
311
|
if (cameraChangeEvent) {
|
|
312
312
|
emit(cameraChangeEvent, {
|
|
@@ -373,7 +373,7 @@ function Canvas3DLoadingState({
|
|
|
373
373
|
] });
|
|
374
374
|
}
|
|
375
375
|
var log2 = logger.createLogger("almadar:ui:game:canvas3d:error-boundary");
|
|
376
|
-
var Canvas3DErrorBoundary = class extends
|
|
376
|
+
var Canvas3DErrorBoundary = class extends React3.Component {
|
|
377
377
|
constructor(props) {
|
|
378
378
|
super(props);
|
|
379
379
|
__publicField(this, "handleReset", () => {
|
|
@@ -502,7 +502,7 @@ function CameraController3D({
|
|
|
502
502
|
onCameraChange
|
|
503
503
|
}) {
|
|
504
504
|
const { camera } = fiber.useThree();
|
|
505
|
-
|
|
505
|
+
React3.useEffect(() => {
|
|
506
506
|
if (onCameraChange) {
|
|
507
507
|
onCameraChange({
|
|
508
508
|
x: camera.position.x,
|
|
@@ -518,8 +518,8 @@ function FollowCamera3D({
|
|
|
518
518
|
offset
|
|
519
519
|
}) {
|
|
520
520
|
const { camera } = fiber.useThree();
|
|
521
|
-
const look =
|
|
522
|
-
const goal =
|
|
521
|
+
const look = React3.useRef(new THREE9__namespace.Vector3(target[0], target[1], target[2]));
|
|
522
|
+
const goal = React3.useRef(new THREE9__namespace.Vector3());
|
|
523
523
|
fiber.useFrame((_, delta) => {
|
|
524
524
|
const t = Math.min(1, delta * 5);
|
|
525
525
|
goal.current.set(target[0] + offset[0], target[1] + offset[1], target[2] + offset[2]);
|
|
@@ -529,6 +529,54 @@ function FollowCamera3D({
|
|
|
529
529
|
});
|
|
530
530
|
return null;
|
|
531
531
|
}
|
|
532
|
+
|
|
533
|
+
// lib/atlasSlice.ts
|
|
534
|
+
var atlasCache = /* @__PURE__ */ new Map();
|
|
535
|
+
function isTilesheet(a) {
|
|
536
|
+
return typeof a.tileWidth === "number";
|
|
537
|
+
}
|
|
538
|
+
function getAtlas(url, onReady) {
|
|
539
|
+
if (atlasCache.has(url)) return atlasCache.get(url) ?? void 0;
|
|
540
|
+
atlasCache.set(url, void 0);
|
|
541
|
+
fetch(url).then((r) => r.json()).then((json) => {
|
|
542
|
+
atlasCache.set(url, json);
|
|
543
|
+
onReady();
|
|
544
|
+
}).catch(() => {
|
|
545
|
+
atlasCache.set(url, null);
|
|
546
|
+
});
|
|
547
|
+
return void 0;
|
|
548
|
+
}
|
|
549
|
+
function subRectFor(atlas, sprite) {
|
|
550
|
+
if (isTilesheet(atlas)) {
|
|
551
|
+
let col;
|
|
552
|
+
let row;
|
|
553
|
+
if (sprite.includes(",")) {
|
|
554
|
+
const [c, r] = sprite.split(",").map((n) => Number(n.trim()));
|
|
555
|
+
col = c;
|
|
556
|
+
row = r;
|
|
557
|
+
} else {
|
|
558
|
+
const i = Number(sprite);
|
|
559
|
+
if (!Number.isFinite(i)) return null;
|
|
560
|
+
col = i % atlas.columns;
|
|
561
|
+
row = Math.floor(i / atlas.columns);
|
|
562
|
+
}
|
|
563
|
+
if (!Number.isFinite(col) || !Number.isFinite(row) || col < 0 || row < 0 || col >= atlas.columns || row >= atlas.rows) return null;
|
|
564
|
+
const margin = atlas.margin ?? 0;
|
|
565
|
+
const spacing = atlas.spacing ?? 0;
|
|
566
|
+
return {
|
|
567
|
+
sx: margin + col * (atlas.tileWidth + spacing),
|
|
568
|
+
sy: margin + row * (atlas.tileHeight + spacing),
|
|
569
|
+
sw: atlas.tileWidth,
|
|
570
|
+
sh: atlas.tileHeight
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
const st = atlas.subTextures[sprite];
|
|
574
|
+
if (!st) return null;
|
|
575
|
+
return { sx: st.x, sy: st.y, sw: st.width, sh: st.height };
|
|
576
|
+
}
|
|
577
|
+
function isAtlasAsset(asset) {
|
|
578
|
+
return !!asset && typeof asset.atlas === "string" && typeof asset.sprite === "string";
|
|
579
|
+
}
|
|
532
580
|
var log3 = logger.createLogger("almadar:ui:game:model-loader");
|
|
533
581
|
var gltfCache = /* @__PURE__ */ new Map();
|
|
534
582
|
function loadGltfCached(url, assetRoot) {
|
|
@@ -573,10 +621,10 @@ function stateFromEntry(entry) {
|
|
|
573
621
|
return { model: null, clips: [], isLoading: !entry.error, error: entry.error ?? null };
|
|
574
622
|
}
|
|
575
623
|
function useGLTFModel(url, resourceBasePath) {
|
|
576
|
-
const [state, setState] =
|
|
624
|
+
const [state, setState] = React3.useState(
|
|
577
625
|
() => stateFromEntry(url ? loadGltfCached(url, resourceBasePath || detectAssetRoot(url)) : null)
|
|
578
626
|
);
|
|
579
|
-
|
|
627
|
+
React3.useEffect(() => {
|
|
580
628
|
if (!url) {
|
|
581
629
|
setState({ model: null, clips: [], isLoading: false, error: null });
|
|
582
630
|
return;
|
|
@@ -611,7 +659,7 @@ function ModelLoader({
|
|
|
611
659
|
tint
|
|
612
660
|
}) {
|
|
613
661
|
const { model: loadedModel, clips, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
614
|
-
const model =
|
|
662
|
+
const model = React3.useMemo(() => {
|
|
615
663
|
if (!loadedModel) return null;
|
|
616
664
|
const cloned = SkeletonUtils.clone(loadedModel);
|
|
617
665
|
cloned.updateMatrixWorld(true);
|
|
@@ -629,8 +677,8 @@ function ModelLoader({
|
|
|
629
677
|
});
|
|
630
678
|
return cloned;
|
|
631
679
|
}, [loadedModel, castShadow, receiveShadow, tint]);
|
|
632
|
-
const mixer =
|
|
633
|
-
|
|
680
|
+
const mixer = React3.useMemo(() => model ? new THREE9__namespace.AnimationMixer(model) : null, [model]);
|
|
681
|
+
React3.useEffect(() => {
|
|
634
682
|
if (!mixer || !animation || clips.length === 0) return;
|
|
635
683
|
const wanted = animation.toLowerCase();
|
|
636
684
|
const clip = clips.find((c) => c.name === animation) ?? clips.find((c) => c.name.toLowerCase() === wanted);
|
|
@@ -644,7 +692,7 @@ function ModelLoader({
|
|
|
644
692
|
fiber.useFrame((_, delta) => {
|
|
645
693
|
mixer?.update(delta);
|
|
646
694
|
});
|
|
647
|
-
const normFactor =
|
|
695
|
+
const normFactor = React3.useMemo(() => {
|
|
648
696
|
if (!model) return 1;
|
|
649
697
|
const box = new THREE9__namespace.Box3().setFromObject(model);
|
|
650
698
|
const size = new THREE9__namespace.Vector3();
|
|
@@ -653,11 +701,11 @@ function ModelLoader({
|
|
|
653
701
|
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
654
702
|
return 1 / maxDim;
|
|
655
703
|
}, [model]);
|
|
656
|
-
const scaleArray =
|
|
704
|
+
const scaleArray = React3.useMemo(() => {
|
|
657
705
|
const base = typeof scale === "number" ? [scale, scale, scale] : scale;
|
|
658
706
|
return [base[0] * normFactor, base[1] * normFactor, base[2] * normFactor];
|
|
659
707
|
}, [scale, normFactor]);
|
|
660
|
-
const rotationRad =
|
|
708
|
+
const rotationRad = React3.useMemo(() => {
|
|
661
709
|
return [
|
|
662
710
|
rotation[0] * Math.PI / 180,
|
|
663
711
|
rotation[1] * Math.PI / 180,
|
|
@@ -730,22 +778,126 @@ function ModelLoader({
|
|
|
730
778
|
}
|
|
731
779
|
);
|
|
732
780
|
}
|
|
781
|
+
var CrossOriginTextureLoader = class extends THREE9__namespace.TextureLoader {
|
|
782
|
+
constructor() {
|
|
783
|
+
super();
|
|
784
|
+
this.crossOrigin = "anonymous";
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
function useBillboardTexture(url) {
|
|
788
|
+
const [state, setState] = React3__default.default.useState({
|
|
789
|
+
texture: null,
|
|
790
|
+
error: false
|
|
791
|
+
});
|
|
792
|
+
React3__default.default.useEffect(() => {
|
|
793
|
+
let active = true;
|
|
794
|
+
const loader = new CrossOriginTextureLoader();
|
|
795
|
+
loader.load(
|
|
796
|
+
url,
|
|
797
|
+
(texture) => {
|
|
798
|
+
if (!active) return;
|
|
799
|
+
console.log("[SpriteBillboard] texture loaded", url, texture.image?.width, texture.image?.height);
|
|
800
|
+
texture.colorSpace = THREE9__namespace.SRGBColorSpace;
|
|
801
|
+
setState({ texture, error: false });
|
|
802
|
+
},
|
|
803
|
+
void 0,
|
|
804
|
+
(err) => {
|
|
805
|
+
if (!active) return;
|
|
806
|
+
console.error("[SpriteBillboard] texture load error", url, err);
|
|
807
|
+
setState({ texture: null, error: true });
|
|
808
|
+
}
|
|
809
|
+
);
|
|
810
|
+
return () => {
|
|
811
|
+
active = false;
|
|
812
|
+
};
|
|
813
|
+
}, [url]);
|
|
814
|
+
return state;
|
|
815
|
+
}
|
|
816
|
+
function useAtlasFrame(asset) {
|
|
817
|
+
const [tick, setTick] = React3__default.default.useState(0);
|
|
818
|
+
React3__default.default.useEffect(() => {
|
|
819
|
+
if (!isAtlasAsset(asset)) return;
|
|
820
|
+
getAtlas(asset.atlas, () => setTick((t) => t + 1));
|
|
821
|
+
}, [asset, tick]);
|
|
822
|
+
return React3__default.default.useMemo(() => {
|
|
823
|
+
if (!isAtlasAsset(asset)) return { frame: null, ready: true };
|
|
824
|
+
const atlas = getAtlas(asset.atlas, () => setTick((t) => t + 1));
|
|
825
|
+
if (!atlas) {
|
|
826
|
+
console.log("[SpriteBillboard] atlas not ready", asset.atlas, asset.sprite);
|
|
827
|
+
return { frame: null, ready: false };
|
|
828
|
+
}
|
|
829
|
+
const r = subRectFor(atlas, asset.sprite);
|
|
830
|
+
console.log("[SpriteBillboard] atlas frame", asset.atlas, asset.sprite, r);
|
|
831
|
+
if (!r) return { frame: null, ready: true };
|
|
832
|
+
return { frame: { x: r.sx, y: r.sy, w: r.sw, h: r.sh }, ready: true };
|
|
833
|
+
}, [asset, tick]);
|
|
834
|
+
}
|
|
733
835
|
function SpriteBillboard({ node, world }) {
|
|
734
|
-
const texture =
|
|
735
|
-
const
|
|
736
|
-
const
|
|
737
|
-
const
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
836
|
+
const { texture, error: textureError } = useBillboardTexture(node.asset.url);
|
|
837
|
+
const { frame: atlasFrame, ready: atlasReady } = useAtlasFrame(node.asset);
|
|
838
|
+
const frame = node.frame ?? atlasFrame;
|
|
839
|
+
const anchor = node.anchor ?? "top-left";
|
|
840
|
+
console.log("[SpriteBillboard] render", node.asset.url, anchor, frame, "texture?", !!texture, "atlasReady?", atlasReady);
|
|
841
|
+
const size = React3__default.default.useMemo(() => {
|
|
842
|
+
const img = texture?.image;
|
|
843
|
+
const imgW = img?.width || 1;
|
|
844
|
+
const imgH = img?.height || 1;
|
|
845
|
+
const aspect = frame ? frame.w / frame.h : imgW / imgH;
|
|
846
|
+
if (anchor === "top-left") {
|
|
847
|
+
const width2 = node.width ?? 1;
|
|
848
|
+
const height2 = node.height ?? 1;
|
|
849
|
+
return { width: width2, height: height2, imgW, imgH };
|
|
850
|
+
}
|
|
851
|
+
const height = node.height ?? 1;
|
|
852
|
+
const width = node.width ?? height * aspect;
|
|
853
|
+
return { width, height, imgW, imgH };
|
|
854
|
+
}, [texture, frame, node.height, node.width, anchor]);
|
|
855
|
+
if (!texture || !atlasReady) {
|
|
856
|
+
if (anchor === "top-left") {
|
|
857
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: [world[0] + size.width / 2, 0.02, world[2] + size.height / 2], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], children: [
|
|
858
|
+
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
859
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE9__namespace.DoubleSide })
|
|
860
|
+
] }) });
|
|
861
|
+
}
|
|
862
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: [world[0], world[1] + size.height / 2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { children: [
|
|
863
|
+
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
864
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: textureError ? 16729156 : 8947848, transparent: true, opacity: 0.6, side: THREE9__namespace.DoubleSide })
|
|
865
|
+
] }) });
|
|
866
|
+
}
|
|
867
|
+
const groundGeometry = React3__default.default.useMemo(() => {
|
|
868
|
+
if (anchor !== "top-left" || !texture || !atlasReady) return null;
|
|
869
|
+
const g = new THREE9__namespace.PlaneGeometry(size.width, size.height);
|
|
870
|
+
g.rotateX(-Math.PI / 2);
|
|
871
|
+
if (frame) {
|
|
872
|
+
const u0 = frame.x / size.imgW;
|
|
873
|
+
const v0 = 1 - (frame.y + frame.h) / size.imgH;
|
|
874
|
+
const u1 = u0 + frame.w / size.imgW;
|
|
875
|
+
const v1 = v0 + frame.h / size.imgH;
|
|
876
|
+
const uvs = new Float32Array([u0, v1, u1, v1, u0, v0, u1, v0]);
|
|
877
|
+
g.setAttribute("uv", new THREE9__namespace.BufferAttribute(uvs, 2));
|
|
878
|
+
}
|
|
879
|
+
return g;
|
|
880
|
+
}, [anchor, texture, atlasReady, size.width, size.height, size.imgW, size.imgH, frame]);
|
|
881
|
+
texture.magFilter = texture.minFilter = THREE9__namespace.NearestFilter;
|
|
882
|
+
texture.needsUpdate = true;
|
|
883
|
+
if (anchor === "top-left") {
|
|
884
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: [world[0] + size.width / 2, 0.01, world[2] + size.height / 2], children: /* @__PURE__ */ jsxRuntime.jsx("mesh", { geometry: groundGeometry ?? void 0, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
885
|
+
"meshBasicMaterial",
|
|
886
|
+
{
|
|
887
|
+
map: texture,
|
|
888
|
+
transparent: true,
|
|
889
|
+
alphaTest: 0.1,
|
|
890
|
+
side: THREE9__namespace.DoubleSide,
|
|
891
|
+
opacity: node.opacity ?? 1
|
|
892
|
+
}
|
|
893
|
+
) }) });
|
|
894
|
+
}
|
|
895
|
+
if (frame) {
|
|
896
|
+
texture.repeat.set(frame.w / size.imgW, frame.h / size.imgH);
|
|
897
|
+
texture.offset.set(frame.x / size.imgW, 1 - (frame.y + frame.h) / size.imgH);
|
|
743
898
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
const width = node.width ?? height * aspect;
|
|
747
|
-
return /* @__PURE__ */ jsxRuntime.jsx(drei.Billboard, { position: [world[0], world[1] + height / 2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { children: [
|
|
748
|
-
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [width, height] }),
|
|
899
|
+
return /* @__PURE__ */ jsxRuntime.jsx(drei.Billboard, { position: [world[0], world[1] + size.height / 2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { children: [
|
|
900
|
+
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [size.width, size.height] }),
|
|
749
901
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
750
902
|
"meshBasicMaterial",
|
|
751
903
|
{
|
|
@@ -868,7 +1020,7 @@ var DEFAULT_GRID_CONFIG = {
|
|
|
868
1020
|
offsetX: 0,
|
|
869
1021
|
offsetZ: 0
|
|
870
1022
|
};
|
|
871
|
-
var Canvas3DHost =
|
|
1023
|
+
var Canvas3DHost = React3.forwardRef(
|
|
872
1024
|
({
|
|
873
1025
|
cameraMode = "isometric",
|
|
874
1026
|
followTarget,
|
|
@@ -894,12 +1046,12 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
894
1046
|
children,
|
|
895
1047
|
drawables
|
|
896
1048
|
}, ref) => {
|
|
897
|
-
const containerRef =
|
|
898
|
-
const controlsRef =
|
|
899
|
-
const [internalError, setInternalError] =
|
|
1049
|
+
const containerRef = React3.useRef(null);
|
|
1050
|
+
const controlsRef = React3.useRef(null);
|
|
1051
|
+
const [internalError, setInternalError] = React3.useState(null);
|
|
900
1052
|
const eventBus = useEventBus();
|
|
901
|
-
const keysRef =
|
|
902
|
-
|
|
1053
|
+
const keysRef = React3.useRef(/* @__PURE__ */ new Set());
|
|
1054
|
+
React3.useEffect(() => {
|
|
903
1055
|
if (!keyMap && !keyUpMap) return;
|
|
904
1056
|
const down = (e) => {
|
|
905
1057
|
if (keysRef.current.has(e.code)) return;
|
|
@@ -932,10 +1084,10 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
932
1084
|
unitAnimationEvent,
|
|
933
1085
|
cameraChangeEvent
|
|
934
1086
|
});
|
|
935
|
-
const drawnItems =
|
|
936
|
-
const scenePositions =
|
|
937
|
-
const hitIndex =
|
|
938
|
-
const gridBounds =
|
|
1087
|
+
const drawnItems = React3.useMemo(() => collectDrawnItems(drawables ?? []), [drawables]);
|
|
1088
|
+
const scenePositions = React3.useMemo(() => drawnItems.map((i) => i.pos), [drawnItems]);
|
|
1089
|
+
const hitIndex = React3.useMemo(() => buildHitIndex(drawnItems), [drawnItems]);
|
|
1090
|
+
const gridBounds = React3.useMemo(() => {
|
|
939
1091
|
if (scenePositions.length === 0) {
|
|
940
1092
|
return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
|
|
941
1093
|
}
|
|
@@ -951,7 +1103,7 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
951
1103
|
}
|
|
952
1104
|
return { minX, maxX, minZ, maxZ };
|
|
953
1105
|
}, [scenePositions]);
|
|
954
|
-
const cameraTarget =
|
|
1106
|
+
const cameraTarget = React3.useMemo(
|
|
955
1107
|
() => [
|
|
956
1108
|
(gridBounds.minX + gridBounds.maxX) / 2,
|
|
957
1109
|
0,
|
|
@@ -959,7 +1111,7 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
959
1111
|
],
|
|
960
1112
|
[gridBounds]
|
|
961
1113
|
);
|
|
962
|
-
const gridConfig =
|
|
1114
|
+
const gridConfig = React3.useMemo(
|
|
963
1115
|
() => ({
|
|
964
1116
|
...DEFAULT_GRID_CONFIG,
|
|
965
1117
|
offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
|
|
@@ -967,7 +1119,7 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
967
1119
|
}),
|
|
968
1120
|
[gridBounds]
|
|
969
1121
|
);
|
|
970
|
-
const drawableProjector =
|
|
1122
|
+
const drawableProjector = React3.useMemo(
|
|
971
1123
|
() => create3DProjector({
|
|
972
1124
|
cellSize: gridConfig.cellSize,
|
|
973
1125
|
offsetX: -gridBounds.minX * gridConfig.cellSize,
|
|
@@ -975,7 +1127,7 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
975
1127
|
}),
|
|
976
1128
|
[gridBounds, gridConfig]
|
|
977
1129
|
);
|
|
978
|
-
|
|
1130
|
+
React3.useImperativeHandle(ref, () => ({
|
|
979
1131
|
getCameraPosition: () => {
|
|
980
1132
|
if (controlsRef.current) {
|
|
981
1133
|
const pos = controlsRef.current.object.position;
|
|
@@ -1008,7 +1160,7 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
1008
1160
|
return null;
|
|
1009
1161
|
}
|
|
1010
1162
|
}));
|
|
1011
|
-
const cameraConfig =
|
|
1163
|
+
const cameraConfig = React3.useMemo(() => {
|
|
1012
1164
|
const size = Math.max(
|
|
1013
1165
|
gridBounds.maxX - gridBounds.minX,
|
|
1014
1166
|
gridBounds.maxZ - gridBounds.minZ,
|
|
@@ -1030,15 +1182,15 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
1030
1182
|
return { position: [cx + d, d, cz + d], fov: 45 };
|
|
1031
1183
|
}
|
|
1032
1184
|
}, [cameraMode, gridBounds]);
|
|
1033
|
-
const followWorld =
|
|
1185
|
+
const followWorld = React3.useMemo(() => {
|
|
1034
1186
|
if (followTarget) return drawableProjector.toWorld(followTarget);
|
|
1035
1187
|
return cameraTarget;
|
|
1036
1188
|
}, [followTarget, drawableProjector, cameraTarget]);
|
|
1037
|
-
const followOffset =
|
|
1189
|
+
const followOffset = React3.useMemo(
|
|
1038
1190
|
() => cameraMode === "chase" ? [0, 4, -7] : [5, 7, 5],
|
|
1039
1191
|
[cameraMode]
|
|
1040
1192
|
);
|
|
1041
|
-
const handleGroundClick =
|
|
1193
|
+
const handleGroundClick = React3.useCallback((e) => {
|
|
1042
1194
|
if (!tileClickEvent && !unitClickEvent) return;
|
|
1043
1195
|
e.stopPropagation();
|
|
1044
1196
|
const cell = {
|
|
@@ -1191,8 +1343,8 @@ var Canvas3DHost = React6.forwardRef(
|
|
|
1191
1343
|
Canvas3DHost.displayName = "Canvas3DHost";
|
|
1192
1344
|
function Scene3D({ background = "#1a1a2e", fog, children }) {
|
|
1193
1345
|
const { scene } = fiber.useThree();
|
|
1194
|
-
const initializedRef =
|
|
1195
|
-
|
|
1346
|
+
const initializedRef = React3.useRef(false);
|
|
1347
|
+
React3.useEffect(() => {
|
|
1196
1348
|
if (initializedRef.current) return;
|
|
1197
1349
|
initializedRef.current = true;
|
|
1198
1350
|
if (background.startsWith("#") || background.startsWith("rgb")) {
|
|
@@ -1213,7 +1365,7 @@ function Scene3D({ background = "#1a1a2e", fog, children }) {
|
|
|
1213
1365
|
}, [scene, background, fog]);
|
|
1214
1366
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
1215
1367
|
}
|
|
1216
|
-
var Camera3D =
|
|
1368
|
+
var Camera3D = React3.forwardRef(
|
|
1217
1369
|
({
|
|
1218
1370
|
mode = "isometric",
|
|
1219
1371
|
position = [10, 10, 10],
|
|
@@ -1226,10 +1378,10 @@ var Camera3D = React6.forwardRef(
|
|
|
1226
1378
|
onChange
|
|
1227
1379
|
}, ref) => {
|
|
1228
1380
|
const { camera, set, viewport } = fiber.useThree();
|
|
1229
|
-
const controlsRef =
|
|
1230
|
-
const initialPosition =
|
|
1231
|
-
const initialTarget =
|
|
1232
|
-
|
|
1381
|
+
const controlsRef = React3.useRef(null);
|
|
1382
|
+
const initialPosition = React3.useRef(new THREE9__namespace.Vector3(...position));
|
|
1383
|
+
const initialTarget = React3.useRef(new THREE9__namespace.Vector3(...target));
|
|
1384
|
+
React3.useEffect(() => {
|
|
1233
1385
|
let newCamera;
|
|
1234
1386
|
if (mode === "isometric") {
|
|
1235
1387
|
const aspect = viewport.aspect;
|
|
@@ -1260,7 +1412,7 @@ var Camera3D = React6.forwardRef(
|
|
|
1260
1412
|
onChange(camera);
|
|
1261
1413
|
}
|
|
1262
1414
|
});
|
|
1263
|
-
|
|
1415
|
+
React3.useImperativeHandle(ref, () => ({
|
|
1264
1416
|
getCamera: () => camera,
|
|
1265
1417
|
setPosition: (x, y, z) => {
|
|
1266
1418
|
camera.position.set(x, y, z);
|
|
@@ -1514,21 +1666,21 @@ var DEFAULT_OPTIONS = {
|
|
|
1514
1666
|
};
|
|
1515
1667
|
function useThree4(options = {}) {
|
|
1516
1668
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
1517
|
-
const containerRef =
|
|
1518
|
-
const canvasRef =
|
|
1519
|
-
const rendererRef =
|
|
1520
|
-
const sceneRef =
|
|
1521
|
-
const cameraRef =
|
|
1522
|
-
const controlsRef =
|
|
1523
|
-
const gridHelperRef =
|
|
1524
|
-
const rafRef =
|
|
1525
|
-
const [isReady, setIsReady] =
|
|
1526
|
-
const [dimensions, setDimensions] =
|
|
1527
|
-
const initialCameraPosition =
|
|
1669
|
+
const containerRef = React3.useRef(null);
|
|
1670
|
+
const canvasRef = React3.useRef(null);
|
|
1671
|
+
const rendererRef = React3.useRef(null);
|
|
1672
|
+
const sceneRef = React3.useRef(null);
|
|
1673
|
+
const cameraRef = React3.useRef(null);
|
|
1674
|
+
const controlsRef = React3.useRef(null);
|
|
1675
|
+
const gridHelperRef = React3.useRef(null);
|
|
1676
|
+
const rafRef = React3.useRef(0);
|
|
1677
|
+
const [isReady, setIsReady] = React3.useState(false);
|
|
1678
|
+
const [dimensions, setDimensions] = React3.useState({ width: 0, height: 0 });
|
|
1679
|
+
const initialCameraPosition = React3.useMemo(
|
|
1528
1680
|
() => new THREE9__namespace.Vector3(...opts.cameraPosition),
|
|
1529
1681
|
[]
|
|
1530
1682
|
);
|
|
1531
|
-
|
|
1683
|
+
React3.useEffect(() => {
|
|
1532
1684
|
if (!containerRef.current) return;
|
|
1533
1685
|
const container = containerRef.current;
|
|
1534
1686
|
const { clientWidth, clientHeight } = container;
|
|
@@ -1621,7 +1773,7 @@ function useThree4(options = {}) {
|
|
|
1621
1773
|
scene.clear();
|
|
1622
1774
|
};
|
|
1623
1775
|
}, []);
|
|
1624
|
-
|
|
1776
|
+
React3.useEffect(() => {
|
|
1625
1777
|
if (!cameraRef.current || !containerRef.current) return;
|
|
1626
1778
|
const container = containerRef.current;
|
|
1627
1779
|
const { clientWidth, clientHeight } = container;
|
|
@@ -1656,20 +1808,20 @@ function useThree4(options = {}) {
|
|
|
1656
1808
|
animate();
|
|
1657
1809
|
}
|
|
1658
1810
|
}, [opts.cameraMode]);
|
|
1659
|
-
const setCameraPosition =
|
|
1811
|
+
const setCameraPosition = React3.useCallback((x, y, z) => {
|
|
1660
1812
|
if (cameraRef.current) {
|
|
1661
1813
|
cameraRef.current.position.set(x, y, z);
|
|
1662
1814
|
controlsRef.current?.update();
|
|
1663
1815
|
}
|
|
1664
1816
|
}, []);
|
|
1665
|
-
const lookAt =
|
|
1817
|
+
const lookAt = React3.useCallback((x, y, z) => {
|
|
1666
1818
|
if (cameraRef.current) {
|
|
1667
1819
|
cameraRef.current.lookAt(x, y, z);
|
|
1668
1820
|
controlsRef.current?.target.set(x, y, z);
|
|
1669
1821
|
controlsRef.current?.update();
|
|
1670
1822
|
}
|
|
1671
1823
|
}, []);
|
|
1672
|
-
const resetCamera =
|
|
1824
|
+
const resetCamera = React3.useCallback(() => {
|
|
1673
1825
|
if (cameraRef.current) {
|
|
1674
1826
|
cameraRef.current.position.copy(initialCameraPosition);
|
|
1675
1827
|
cameraRef.current.lookAt(0, 0, 0);
|
|
@@ -1679,7 +1831,7 @@ function useThree4(options = {}) {
|
|
|
1679
1831
|
}
|
|
1680
1832
|
}
|
|
1681
1833
|
}, [initialCameraPosition]);
|
|
1682
|
-
const fitView =
|
|
1834
|
+
const fitView = React3.useCallback(
|
|
1683
1835
|
(bounds) => {
|
|
1684
1836
|
if (!cameraRef.current) return;
|
|
1685
1837
|
const centerX = (bounds.minX + bounds.maxX) / 2;
|
|
@@ -1710,20 +1862,20 @@ function useThree4(options = {}) {
|
|
|
1710
1862
|
}
|
|
1711
1863
|
function useAssetLoader(options = {}) {
|
|
1712
1864
|
const { preloadUrls = [], loader: customLoader } = options;
|
|
1713
|
-
const loaderRef =
|
|
1714
|
-
const [state, setState] =
|
|
1865
|
+
const loaderRef = React3.useRef(customLoader || new AssetLoader());
|
|
1866
|
+
const [state, setState] = React3.useState({
|
|
1715
1867
|
isLoading: false,
|
|
1716
1868
|
progress: 0,
|
|
1717
1869
|
loaded: 0,
|
|
1718
1870
|
total: 0,
|
|
1719
1871
|
errors: []
|
|
1720
1872
|
});
|
|
1721
|
-
|
|
1873
|
+
React3.useEffect(() => {
|
|
1722
1874
|
if (preloadUrls.length > 0) {
|
|
1723
1875
|
preload(preloadUrls);
|
|
1724
1876
|
}
|
|
1725
1877
|
}, []);
|
|
1726
|
-
const updateProgress =
|
|
1878
|
+
const updateProgress = React3.useCallback((loaded, total) => {
|
|
1727
1879
|
setState((prev) => ({
|
|
1728
1880
|
...prev,
|
|
1729
1881
|
loaded,
|
|
@@ -1731,7 +1883,7 @@ function useAssetLoader(options = {}) {
|
|
|
1731
1883
|
progress: total > 0 ? Math.round(loaded / total * 100) : 0
|
|
1732
1884
|
}));
|
|
1733
1885
|
}, []);
|
|
1734
|
-
const loadModel =
|
|
1886
|
+
const loadModel = React3.useCallback(
|
|
1735
1887
|
async (url) => {
|
|
1736
1888
|
setState((prev) => ({ ...prev, isLoading: true }));
|
|
1737
1889
|
try {
|
|
@@ -1754,7 +1906,7 @@ function useAssetLoader(options = {}) {
|
|
|
1754
1906
|
},
|
|
1755
1907
|
[]
|
|
1756
1908
|
);
|
|
1757
|
-
const loadOBJ =
|
|
1909
|
+
const loadOBJ = React3.useCallback(
|
|
1758
1910
|
async (url) => {
|
|
1759
1911
|
setState((prev) => ({ ...prev, isLoading: true }));
|
|
1760
1912
|
try {
|
|
@@ -1777,7 +1929,7 @@ function useAssetLoader(options = {}) {
|
|
|
1777
1929
|
},
|
|
1778
1930
|
[]
|
|
1779
1931
|
);
|
|
1780
|
-
const loadTexture =
|
|
1932
|
+
const loadTexture = React3.useCallback(
|
|
1781
1933
|
async (url) => {
|
|
1782
1934
|
setState((prev) => ({ ...prev, isLoading: true }));
|
|
1783
1935
|
try {
|
|
@@ -1800,7 +1952,7 @@ function useAssetLoader(options = {}) {
|
|
|
1800
1952
|
},
|
|
1801
1953
|
[]
|
|
1802
1954
|
);
|
|
1803
|
-
const preload =
|
|
1955
|
+
const preload = React3.useCallback(
|
|
1804
1956
|
async (urls) => {
|
|
1805
1957
|
setState((prev) => ({
|
|
1806
1958
|
...prev,
|
|
@@ -1839,27 +1991,27 @@ function useAssetLoader(options = {}) {
|
|
|
1839
1991
|
},
|
|
1840
1992
|
[updateProgress]
|
|
1841
1993
|
);
|
|
1842
|
-
const hasModel =
|
|
1994
|
+
const hasModel = React3.useCallback((url) => {
|
|
1843
1995
|
return loaderRef.current.hasModel(url);
|
|
1844
1996
|
}, []);
|
|
1845
|
-
const hasTexture =
|
|
1997
|
+
const hasTexture = React3.useCallback((url) => {
|
|
1846
1998
|
return loaderRef.current.hasTexture(url);
|
|
1847
1999
|
}, []);
|
|
1848
|
-
const getModel =
|
|
2000
|
+
const getModel = React3.useCallback((url) => {
|
|
1849
2001
|
try {
|
|
1850
2002
|
return loaderRef.current.getModel(url);
|
|
1851
2003
|
} catch {
|
|
1852
2004
|
return void 0;
|
|
1853
2005
|
}
|
|
1854
2006
|
}, []);
|
|
1855
|
-
const getTexture =
|
|
2007
|
+
const getTexture = React3.useCallback((url) => {
|
|
1856
2008
|
try {
|
|
1857
2009
|
return loaderRef.current.getTexture(url);
|
|
1858
2010
|
} catch {
|
|
1859
2011
|
return void 0;
|
|
1860
2012
|
}
|
|
1861
2013
|
}, []);
|
|
1862
|
-
const clearCache =
|
|
2014
|
+
const clearCache = React3.useCallback(() => {
|
|
1863
2015
|
loaderRef.current.clearCache();
|
|
1864
2016
|
setState({
|
|
1865
2017
|
isLoading: false,
|
|
@@ -1883,25 +2035,25 @@ function useAssetLoader(options = {}) {
|
|
|
1883
2035
|
};
|
|
1884
2036
|
}
|
|
1885
2037
|
function useSceneGraph() {
|
|
1886
|
-
const nodesRef =
|
|
1887
|
-
const addNode =
|
|
2038
|
+
const nodesRef = React3.useRef(/* @__PURE__ */ new Map());
|
|
2039
|
+
const addNode = React3.useCallback((node) => {
|
|
1888
2040
|
const existing = nodesRef.current.get(node.id);
|
|
1889
2041
|
if (existing) {
|
|
1890
2042
|
existing.mesh.removeFromParent();
|
|
1891
2043
|
}
|
|
1892
2044
|
nodesRef.current.set(node.id, node);
|
|
1893
2045
|
}, []);
|
|
1894
|
-
const removeNode =
|
|
2046
|
+
const removeNode = React3.useCallback((id) => {
|
|
1895
2047
|
const node = nodesRef.current.get(id);
|
|
1896
2048
|
if (node) {
|
|
1897
2049
|
node.mesh.removeFromParent();
|
|
1898
2050
|
nodesRef.current.delete(id);
|
|
1899
2051
|
}
|
|
1900
2052
|
}, []);
|
|
1901
|
-
const getNode =
|
|
2053
|
+
const getNode = React3.useCallback((id) => {
|
|
1902
2054
|
return nodesRef.current.get(id);
|
|
1903
2055
|
}, []);
|
|
1904
|
-
const updateNodePosition =
|
|
2056
|
+
const updateNodePosition = React3.useCallback(
|
|
1905
2057
|
(id, x, y, z) => {
|
|
1906
2058
|
const node = nodesRef.current.get(id);
|
|
1907
2059
|
if (node) {
|
|
@@ -1911,7 +2063,7 @@ function useSceneGraph() {
|
|
|
1911
2063
|
},
|
|
1912
2064
|
[]
|
|
1913
2065
|
);
|
|
1914
|
-
const updateNodeGridPosition =
|
|
2066
|
+
const updateNodeGridPosition = React3.useCallback(
|
|
1915
2067
|
(id, gridX, gridZ) => {
|
|
1916
2068
|
const node = nodesRef.current.get(id);
|
|
1917
2069
|
if (node) {
|
|
@@ -1920,7 +2072,7 @@ function useSceneGraph() {
|
|
|
1920
2072
|
},
|
|
1921
2073
|
[]
|
|
1922
2074
|
);
|
|
1923
|
-
const getNodeAtGrid =
|
|
2075
|
+
const getNodeAtGrid = React3.useCallback(
|
|
1924
2076
|
(x, z, type) => {
|
|
1925
2077
|
return Array.from(nodesRef.current.values()).find((node) => {
|
|
1926
2078
|
const matchesGrid = node.gridPosition.x === x && node.gridPosition.z === z;
|
|
@@ -1929,10 +2081,10 @@ function useSceneGraph() {
|
|
|
1929
2081
|
},
|
|
1930
2082
|
[]
|
|
1931
2083
|
);
|
|
1932
|
-
const getNodesByType =
|
|
2084
|
+
const getNodesByType = React3.useCallback((type) => {
|
|
1933
2085
|
return Array.from(nodesRef.current.values()).filter((node) => node.type === type);
|
|
1934
2086
|
}, []);
|
|
1935
|
-
const getNodesInBounds =
|
|
2087
|
+
const getNodesInBounds = React3.useCallback(
|
|
1936
2088
|
(minX, maxX, minZ, maxZ) => {
|
|
1937
2089
|
return Array.from(nodesRef.current.values()).filter((node) => {
|
|
1938
2090
|
const { x, z } = node.gridPosition;
|
|
@@ -1941,13 +2093,13 @@ function useSceneGraph() {
|
|
|
1941
2093
|
},
|
|
1942
2094
|
[]
|
|
1943
2095
|
);
|
|
1944
|
-
const clearNodes =
|
|
2096
|
+
const clearNodes = React3.useCallback(() => {
|
|
1945
2097
|
nodesRef.current.forEach((node) => {
|
|
1946
2098
|
node.mesh.removeFromParent();
|
|
1947
2099
|
});
|
|
1948
2100
|
nodesRef.current.clear();
|
|
1949
2101
|
}, []);
|
|
1950
|
-
const countNodes =
|
|
2102
|
+
const countNodes = React3.useCallback((type) => {
|
|
1951
2103
|
if (!type) {
|
|
1952
2104
|
return nodesRef.current.size;
|
|
1953
2105
|
}
|
|
@@ -1969,9 +2121,9 @@ function useSceneGraph() {
|
|
|
1969
2121
|
}
|
|
1970
2122
|
function useRaycaster(options) {
|
|
1971
2123
|
const { camera, canvas, cellSize = 1, offsetX = 0, offsetZ = 0 } = options;
|
|
1972
|
-
const raycaster =
|
|
1973
|
-
const mouse =
|
|
1974
|
-
const clientToNDC =
|
|
2124
|
+
const raycaster = React3.useRef(new THREE9__namespace.Raycaster());
|
|
2125
|
+
const mouse = React3.useRef(new THREE9__namespace.Vector2());
|
|
2126
|
+
const clientToNDC = React3.useCallback(
|
|
1975
2127
|
(clientX, clientY) => {
|
|
1976
2128
|
if (!canvas) {
|
|
1977
2129
|
return { x: 0, y: 0 };
|
|
@@ -1984,7 +2136,7 @@ function useRaycaster(options) {
|
|
|
1984
2136
|
},
|
|
1985
2137
|
[canvas]
|
|
1986
2138
|
);
|
|
1987
|
-
const isWithinCanvas =
|
|
2139
|
+
const isWithinCanvas = React3.useCallback(
|
|
1988
2140
|
(clientX, clientY) => {
|
|
1989
2141
|
if (!canvas) return false;
|
|
1990
2142
|
const rect = canvas.getBoundingClientRect();
|
|
@@ -1992,7 +2144,7 @@ function useRaycaster(options) {
|
|
|
1992
2144
|
},
|
|
1993
2145
|
[canvas]
|
|
1994
2146
|
);
|
|
1995
|
-
const getIntersection =
|
|
2147
|
+
const getIntersection = React3.useCallback(
|
|
1996
2148
|
(clientX, clientY, objects) => {
|
|
1997
2149
|
if (!camera || !canvas) return null;
|
|
1998
2150
|
const ndc = clientToNDC(clientX, clientY);
|
|
@@ -2015,7 +2167,7 @@ function useRaycaster(options) {
|
|
|
2015
2167
|
},
|
|
2016
2168
|
[camera, canvas, clientToNDC]
|
|
2017
2169
|
);
|
|
2018
|
-
const getAllIntersections =
|
|
2170
|
+
const getAllIntersections = React3.useCallback(
|
|
2019
2171
|
(clientX, clientY, objects) => {
|
|
2020
2172
|
if (!camera || !canvas) return [];
|
|
2021
2173
|
const ndc = clientToNDC(clientX, clientY);
|
|
@@ -2034,7 +2186,7 @@ function useRaycaster(options) {
|
|
|
2034
2186
|
},
|
|
2035
2187
|
[camera, canvas, clientToNDC]
|
|
2036
2188
|
);
|
|
2037
|
-
const getGridCoordinates =
|
|
2189
|
+
const getGridCoordinates = React3.useCallback(
|
|
2038
2190
|
(clientX, clientY) => {
|
|
2039
2191
|
if (!camera || !canvas) return null;
|
|
2040
2192
|
const ndc = clientToNDC(clientX, clientY);
|
|
@@ -2052,7 +2204,7 @@ function useRaycaster(options) {
|
|
|
2052
2204
|
},
|
|
2053
2205
|
[camera, canvas, cellSize, offsetX, offsetZ, clientToNDC]
|
|
2054
2206
|
);
|
|
2055
|
-
const getTileAtPosition =
|
|
2207
|
+
const getTileAtPosition = React3.useCallback(
|
|
2056
2208
|
(clientX, clientY, scene) => {
|
|
2057
2209
|
if (!camera || !canvas) return null;
|
|
2058
2210
|
const tileMeshes = [];
|
|
@@ -2387,24 +2539,24 @@ var SpatialHashGrid = class {
|
|
|
2387
2539
|
};
|
|
2388
2540
|
function useTapReveal(options = {}) {
|
|
2389
2541
|
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
2390
|
-
const [revealed, setRevealed] =
|
|
2391
|
-
const onRevealRef =
|
|
2392
|
-
const onDismissRef =
|
|
2542
|
+
const [revealed, setRevealed] = React3.useState(false);
|
|
2543
|
+
const onRevealRef = React3.useRef(onReveal);
|
|
2544
|
+
const onDismissRef = React3.useRef(onDismiss);
|
|
2393
2545
|
onRevealRef.current = onReveal;
|
|
2394
2546
|
onDismissRef.current = onDismiss;
|
|
2395
|
-
const reveal =
|
|
2547
|
+
const reveal = React3.useCallback(() => {
|
|
2396
2548
|
setRevealed((wasRevealed) => {
|
|
2397
2549
|
if (!wasRevealed) onRevealRef.current?.();
|
|
2398
2550
|
return true;
|
|
2399
2551
|
});
|
|
2400
2552
|
}, []);
|
|
2401
|
-
const dismiss =
|
|
2553
|
+
const dismiss = React3.useCallback(() => {
|
|
2402
2554
|
setRevealed((wasRevealed) => {
|
|
2403
2555
|
if (wasRevealed) onDismissRef.current?.();
|
|
2404
2556
|
return false;
|
|
2405
2557
|
});
|
|
2406
2558
|
}, []);
|
|
2407
|
-
const onPointerDown =
|
|
2559
|
+
const onPointerDown = React3.useCallback(
|
|
2408
2560
|
(e) => {
|
|
2409
2561
|
if (!enabled || e.pointerType === "mouse") return;
|
|
2410
2562
|
if (revealed) dismiss();
|
|
@@ -2412,7 +2564,7 @@ function useTapReveal(options = {}) {
|
|
|
2412
2564
|
},
|
|
2413
2565
|
[enabled, revealed, reveal, dismiss]
|
|
2414
2566
|
);
|
|
2415
|
-
|
|
2567
|
+
React3.useEffect(() => {
|
|
2416
2568
|
if (!revealed || typeof document === "undefined") return;
|
|
2417
2569
|
const onDocDown = (ev) => {
|
|
2418
2570
|
const target = ev.target;
|
|
@@ -2532,7 +2684,7 @@ var positionStyles = {
|
|
|
2532
2684
|
fixed: "fixed",
|
|
2533
2685
|
sticky: "sticky"
|
|
2534
2686
|
};
|
|
2535
|
-
var Box =
|
|
2687
|
+
var Box = React3__default.default.forwardRef(
|
|
2536
2688
|
({
|
|
2537
2689
|
padding,
|
|
2538
2690
|
paddingX,
|
|
@@ -2564,20 +2716,20 @@ var Box = React6__default.default.forwardRef(
|
|
|
2564
2716
|
...rest
|
|
2565
2717
|
}, ref) => {
|
|
2566
2718
|
const eventBus = useEventBus();
|
|
2567
|
-
const handleClick =
|
|
2719
|
+
const handleClick = React3.useCallback((e) => {
|
|
2568
2720
|
if (action) {
|
|
2569
2721
|
e.stopPropagation();
|
|
2570
2722
|
eventBus.emit(`UI:${action}`, actionPayload ?? {});
|
|
2571
2723
|
}
|
|
2572
2724
|
onClick?.(e);
|
|
2573
2725
|
}, [action, actionPayload, eventBus, onClick]);
|
|
2574
|
-
const handleMouseEnter =
|
|
2726
|
+
const handleMouseEnter = React3.useCallback((e) => {
|
|
2575
2727
|
if (hoverEvent) {
|
|
2576
2728
|
eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
2577
2729
|
}
|
|
2578
2730
|
onMouseEnter?.(e);
|
|
2579
2731
|
}, [hoverEvent, eventBus, onMouseEnter]);
|
|
2580
|
-
const handleMouseLeave =
|
|
2732
|
+
const handleMouseLeave = React3.useCallback((e) => {
|
|
2581
2733
|
if (hoverEvent) {
|
|
2582
2734
|
eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
2583
2735
|
}
|
|
@@ -2585,19 +2737,19 @@ var Box = React6__default.default.forwardRef(
|
|
|
2585
2737
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
2586
2738
|
const { triggerProps } = useTapReveal({
|
|
2587
2739
|
enabled: tapReveal && !!hoverEvent,
|
|
2588
|
-
onReveal:
|
|
2740
|
+
onReveal: React3.useCallback(() => {
|
|
2589
2741
|
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
2590
2742
|
}, [hoverEvent, eventBus]),
|
|
2591
|
-
onDismiss:
|
|
2743
|
+
onDismiss: React3.useCallback(() => {
|
|
2592
2744
|
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
2593
2745
|
}, [hoverEvent, eventBus])
|
|
2594
2746
|
});
|
|
2595
|
-
const handlePointerDown =
|
|
2747
|
+
const handlePointerDown = React3.useCallback((e) => {
|
|
2596
2748
|
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
2597
2749
|
onPointerDown?.(e);
|
|
2598
2750
|
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
2599
2751
|
const isClickable = action || onClick;
|
|
2600
|
-
return
|
|
2752
|
+
return React3__default.default.createElement(
|
|
2601
2753
|
Component2,
|
|
2602
2754
|
{
|
|
2603
2755
|
ref,
|
|
@@ -2718,7 +2870,7 @@ var Typography = ({
|
|
|
2718
2870
|
}) => {
|
|
2719
2871
|
const variant = variantProp ?? (level ? `h${level}` : "body1");
|
|
2720
2872
|
const Component2 = as || defaultElements[variant];
|
|
2721
|
-
return
|
|
2873
|
+
return React3__default.default.createElement(
|
|
2722
2874
|
Component2,
|
|
2723
2875
|
{
|
|
2724
2876
|
id,
|
|
@@ -2791,7 +2943,7 @@ var Stack = ({
|
|
|
2791
2943
|
};
|
|
2792
2944
|
const isHorizontal = direction === "horizontal";
|
|
2793
2945
|
const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
|
|
2794
|
-
return
|
|
2946
|
+
return React3__default.default.createElement(
|
|
2795
2947
|
Component2,
|
|
2796
2948
|
{
|
|
2797
2949
|
className: cn(
|
|
@@ -3538,10 +3690,10 @@ var Avl3DOrbitalNode = ({
|
|
|
3538
3690
|
position,
|
|
3539
3691
|
onClick
|
|
3540
3692
|
}) => {
|
|
3541
|
-
const groupRef =
|
|
3542
|
-
const [hovered, setHovered] =
|
|
3543
|
-
const scale =
|
|
3544
|
-
const currentScale =
|
|
3693
|
+
const groupRef = React3.useRef(null);
|
|
3694
|
+
const [hovered, setHovered] = React3.useState(false);
|
|
3695
|
+
const scale = React3.useMemo(() => 0.6 + Math.min(traitCount, 8) * 0.3, [traitCount]);
|
|
3696
|
+
const currentScale = React3.useRef(scale);
|
|
3545
3697
|
const targetScale = hovered ? scale * 1.06 : scale;
|
|
3546
3698
|
fiber.useFrame((_, delta) => {
|
|
3547
3699
|
if (!groupRef.current) return;
|
|
@@ -3683,7 +3835,7 @@ var Avl3DCrossWire = ({
|
|
|
3683
3835
|
eventName,
|
|
3684
3836
|
color = AVL_3D_COLORS.crossWire
|
|
3685
3837
|
}) => {
|
|
3686
|
-
const { tubeArgs, midpoint } =
|
|
3838
|
+
const { tubeArgs, midpoint } = React3.useMemo(() => {
|
|
3687
3839
|
const curve = arcCurve3D(from, to, 2);
|
|
3688
3840
|
const mid = curve.getPoint(0.5);
|
|
3689
3841
|
return {
|
|
@@ -3722,9 +3874,9 @@ var Avl3DApplicationScene = ({
|
|
|
3722
3874
|
data,
|
|
3723
3875
|
onOrbitalClick
|
|
3724
3876
|
}) => {
|
|
3725
|
-
const groupRef =
|
|
3726
|
-
const [, setHoverTrigger] =
|
|
3727
|
-
const orbitalPositions =
|
|
3877
|
+
const groupRef = React3.useRef(null);
|
|
3878
|
+
const [, setHoverTrigger] = React3.useState(0);
|
|
3879
|
+
const orbitalPositions = React3.useMemo(() => {
|
|
3728
3880
|
const baseRadius = Math.max(4, data.orbitals.length * 1.5);
|
|
3729
3881
|
if (data.crossLinks.length === 0) {
|
|
3730
3882
|
return goldenSpiralPositions(data.orbitals.length, baseRadius);
|
|
@@ -3737,7 +3889,7 @@ var Avl3DApplicationScene = ({
|
|
|
3737
3889
|
})).filter((e) => e.from >= 0 && e.to >= 0);
|
|
3738
3890
|
return forceDirectedPositions(data.orbitals.length, edges, baseRadius);
|
|
3739
3891
|
}, [data.orbitals, data.crossLinks]);
|
|
3740
|
-
const positionByName =
|
|
3892
|
+
const positionByName = React3.useMemo(() => {
|
|
3741
3893
|
const map = /* @__PURE__ */ new Map();
|
|
3742
3894
|
data.orbitals.forEach((orb, i) => {
|
|
3743
3895
|
const pos = orbitalPositions[i];
|
|
@@ -3820,7 +3972,7 @@ var Avl3DEntityCore = ({
|
|
|
3820
3972
|
position,
|
|
3821
3973
|
fields
|
|
3822
3974
|
}) => {
|
|
3823
|
-
const coreRef =
|
|
3975
|
+
const coreRef = React3.useRef(null);
|
|
3824
3976
|
fiber.useFrame((_, delta) => {
|
|
3825
3977
|
if (!coreRef.current) return;
|
|
3826
3978
|
coreRef.current.rotation.y += delta * 0.3;
|
|
@@ -3973,8 +4125,8 @@ function TraitOrbit({
|
|
|
3973
4125
|
onClick,
|
|
3974
4126
|
onHover
|
|
3975
4127
|
}) {
|
|
3976
|
-
const groupRef =
|
|
3977
|
-
const angleRef =
|
|
4128
|
+
const groupRef = React3.useRef(null);
|
|
4129
|
+
const angleRef = React3.useRef(Math.random() * Math.PI * 2);
|
|
3978
4130
|
fiber.useFrame((_, delta) => {
|
|
3979
4131
|
angleRef.current += delta * speed;
|
|
3980
4132
|
if (!groupRef.current) return;
|
|
@@ -4105,9 +4257,9 @@ var Avl3DOrbitalScene = ({
|
|
|
4105
4257
|
highlightedTrait,
|
|
4106
4258
|
onTraitHighlight
|
|
4107
4259
|
}) => {
|
|
4108
|
-
const [localHighlight, setLocalHighlight] =
|
|
4260
|
+
const [localHighlight, setLocalHighlight] = React3.useState(null);
|
|
4109
4261
|
const activeHighlight = highlightedTrait ?? localHighlight;
|
|
4110
|
-
const traitOrbits =
|
|
4262
|
+
const traitOrbits = React3.useMemo(() => {
|
|
4111
4263
|
return data.traits.map((trait, i) => ({
|
|
4112
4264
|
name: trait.name,
|
|
4113
4265
|
radius: 3 + i * 1.2,
|
|
@@ -4118,7 +4270,7 @@ var Avl3DOrbitalScene = ({
|
|
|
4118
4270
|
transitionCount: trait.transitionCount
|
|
4119
4271
|
}));
|
|
4120
4272
|
}, [data.traits]);
|
|
4121
|
-
const pagePositions =
|
|
4273
|
+
const pagePositions = React3.useMemo(() => {
|
|
4122
4274
|
const outerRadius = 3 + data.traits.length * 1.2 + 1.5;
|
|
4123
4275
|
return data.pages.map((_, i) => {
|
|
4124
4276
|
const angle = 2 * Math.PI * i / data.pages.length - Math.PI / 2;
|
|
@@ -4182,12 +4334,12 @@ var Avl3DStateNode = ({
|
|
|
4182
4334
|
outgoingCount = 0,
|
|
4183
4335
|
onClick
|
|
4184
4336
|
}) => {
|
|
4185
|
-
const [hovered, setHovered] =
|
|
4337
|
+
const [hovered, setHovered] = React3.useState(false);
|
|
4186
4338
|
const baseColor = active ? AVL_3D_COLORS.stateActive : AVL_3D_COLORS.stateIdle;
|
|
4187
4339
|
const emissiveColor = active ? AVL_3D_COLORS.stateActive : AVL_3D_COLORS.stateEdge;
|
|
4188
4340
|
const emissiveIntensity = active ? 2 : hovered ? 0.8 : 0.3;
|
|
4189
4341
|
const targetScale = hovered ? 1.08 : 1;
|
|
4190
|
-
const currentScale =
|
|
4342
|
+
const currentScale = React3.useRef(1);
|
|
4191
4343
|
fiber.useFrame((_, delta) => {
|
|
4192
4344
|
currentScale.current = THREE9.MathUtils.damp(currentScale.current, targetScale, 6, delta);
|
|
4193
4345
|
});
|
|
@@ -4361,8 +4513,8 @@ var Avl3DTransitionArc = ({
|
|
|
4361
4513
|
onClick,
|
|
4362
4514
|
color = AVL_3D_COLORS.transitionArc
|
|
4363
4515
|
}) => {
|
|
4364
|
-
const [hovered, setHovered] =
|
|
4365
|
-
const { tubeArgs, labelPos, guardPos, arrowPos, arrowQuat, effectPositions } =
|
|
4516
|
+
const [hovered, setHovered] = React3.useState(false);
|
|
4517
|
+
const { tubeArgs, labelPos, guardPos, arrowPos, arrowQuat, effectPositions } = React3.useMemo(() => {
|
|
4366
4518
|
const offset = 1.5 + index * 0.8;
|
|
4367
4519
|
const curve = isSelf ? selfLoopCurve3D(from, 1.2) : arcCurve3D(from, to, offset);
|
|
4368
4520
|
const mid = curve.getPoint(0.5);
|
|
@@ -4495,7 +4647,7 @@ var Avl3DTraitScene = ({
|
|
|
4495
4647
|
data,
|
|
4496
4648
|
onTransitionClick
|
|
4497
4649
|
}) => {
|
|
4498
|
-
const statePositions =
|
|
4650
|
+
const statePositions = React3.useMemo(() => {
|
|
4499
4651
|
const radius = Math.max(3, data.states.length * 0.8);
|
|
4500
4652
|
const positions = fibonacciSpherePositions(data.states.length, radius);
|
|
4501
4653
|
const posMap = /* @__PURE__ */ new Map();
|
|
@@ -4505,7 +4657,7 @@ var Avl3DTraitScene = ({
|
|
|
4505
4657
|
});
|
|
4506
4658
|
return posMap;
|
|
4507
4659
|
}, [data.states]);
|
|
4508
|
-
const transitionIndices =
|
|
4660
|
+
const transitionIndices = React3.useMemo(() => {
|
|
4509
4661
|
const pairCount = /* @__PURE__ */ new Map();
|
|
4510
4662
|
return data.transitions.map((t) => {
|
|
4511
4663
|
const key = `${t.from}->${t.to}`;
|
|
@@ -4514,7 +4666,7 @@ var Avl3DTraitScene = ({
|
|
|
4514
4666
|
return idx;
|
|
4515
4667
|
});
|
|
4516
4668
|
}, [data.transitions]);
|
|
4517
|
-
const transitionCounts =
|
|
4669
|
+
const transitionCounts = React3.useMemo(() => {
|
|
4518
4670
|
const incoming = /* @__PURE__ */ new Map();
|
|
4519
4671
|
const outgoing = /* @__PURE__ */ new Map();
|
|
4520
4672
|
for (const t of data.transitions) {
|
|
@@ -4624,11 +4776,11 @@ var Avl3DExprTree = ({
|
|
|
4624
4776
|
expression,
|
|
4625
4777
|
position
|
|
4626
4778
|
}) => {
|
|
4627
|
-
const layoutResults =
|
|
4779
|
+
const layoutResults = React3.useMemo(() => {
|
|
4628
4780
|
const origin = { x: position[0], y: position[1], z: position[2] };
|
|
4629
4781
|
return treeLayout3D(expression, origin, 2.5, 1.5);
|
|
4630
4782
|
}, [expression, position]);
|
|
4631
|
-
const edges =
|
|
4783
|
+
const edges = React3.useMemo(() => {
|
|
4632
4784
|
const result = [];
|
|
4633
4785
|
function collectEdges(node, parentPos) {
|
|
4634
4786
|
const entry = layoutResults.find((r) => r.node === node);
|
|
@@ -4908,7 +5060,7 @@ var Avl3DEffects = ({
|
|
|
4908
5060
|
const dof = DOF_CONFIG[level];
|
|
4909
5061
|
const sparkles = SPARKLE_CONFIGS[level];
|
|
4910
5062
|
const stars = STARS_CONFIG[level];
|
|
4911
|
-
const starsKey =
|
|
5063
|
+
const starsKey = React3.useMemo(() => `stars-${level}`, [level]);
|
|
4912
5064
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4913
5065
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4914
5066
|
drei.Stars,
|
|
@@ -4972,16 +5124,16 @@ var DEFAULT_CONFIG2 = {
|
|
|
4972
5124
|
modelOverrides: {},
|
|
4973
5125
|
effectsEnabled: true
|
|
4974
5126
|
};
|
|
4975
|
-
var Avl3DContext =
|
|
5127
|
+
var Avl3DContext = React3.createContext(DEFAULT_CONFIG2);
|
|
4976
5128
|
function useAvl3DConfig() {
|
|
4977
|
-
return
|
|
5129
|
+
return React3.useContext(Avl3DContext);
|
|
4978
5130
|
}
|
|
4979
5131
|
function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
4980
5132
|
const { camera } = fiber.useThree();
|
|
4981
|
-
const targetPosVec =
|
|
4982
|
-
const targetLookVec =
|
|
4983
|
-
const isAnimating =
|
|
4984
|
-
|
|
5133
|
+
const targetPosVec = React3.useRef(new THREE9__namespace.Vector3(...targetPosition));
|
|
5134
|
+
const targetLookVec = React3.useRef(new THREE9__namespace.Vector3(...targetLookAt));
|
|
5135
|
+
const isAnimating = React3.useRef(false);
|
|
5136
|
+
React3.useEffect(() => {
|
|
4985
5137
|
const newTarget = new THREE9__namespace.Vector3(...targetPosition);
|
|
4986
5138
|
const newLookAt = new THREE9__namespace.Vector3(...targetLookAt);
|
|
4987
5139
|
if (!newTarget.equals(targetPosVec.current) || !newLookAt.equals(targetLookVec.current)) {
|
|
@@ -5010,8 +5162,8 @@ function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
|
5010
5162
|
return null;
|
|
5011
5163
|
}
|
|
5012
5164
|
function SceneFade({ animating, children }) {
|
|
5013
|
-
const groupRef =
|
|
5014
|
-
const opacityRef =
|
|
5165
|
+
const groupRef = React3.useRef(null);
|
|
5166
|
+
const opacityRef = React3.useRef(1);
|
|
5015
5167
|
fiber.useFrame((_, delta) => {
|
|
5016
5168
|
if (!groupRef.current) return;
|
|
5017
5169
|
const target = animating ? 0 : 1;
|
|
@@ -5035,7 +5187,7 @@ var Avl3DViewer = ({
|
|
|
5035
5187
|
modelOverrides = {}
|
|
5036
5188
|
}) => {
|
|
5037
5189
|
const { t } = hooks.useTranslate();
|
|
5038
|
-
const schema =
|
|
5190
|
+
const schema = React3.useMemo(() => {
|
|
5039
5191
|
if (typeof schemaProp === "string") {
|
|
5040
5192
|
try {
|
|
5041
5193
|
return JSON.parse(schemaProp);
|
|
@@ -5045,12 +5197,12 @@ var Avl3DViewer = ({
|
|
|
5045
5197
|
}
|
|
5046
5198
|
return schemaProp;
|
|
5047
5199
|
}, [schemaProp]);
|
|
5048
|
-
const configValue =
|
|
5200
|
+
const configValue = React3.useMemo(() => ({
|
|
5049
5201
|
modelOverrides,
|
|
5050
5202
|
effectsEnabled: effects
|
|
5051
5203
|
}), [modelOverrides, effects]);
|
|
5052
|
-
const [state, dispatch] =
|
|
5053
|
-
|
|
5204
|
+
const [state, dispatch] = React3.useReducer(zoomReducer, initialZoomState);
|
|
5205
|
+
React3.useEffect(() => {
|
|
5054
5206
|
if (initialOrbital) {
|
|
5055
5207
|
dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: initialOrbital, targetPosition: { x: 0, y: 0 } });
|
|
5056
5208
|
setTimeout(() => dispatch({ type: "ANIMATION_COMPLETE" }), 0);
|
|
@@ -5062,35 +5214,35 @@ var Avl3DViewer = ({
|
|
|
5062
5214
|
}
|
|
5063
5215
|
}
|
|
5064
5216
|
}, [initialOrbital, initialTrait]);
|
|
5065
|
-
|
|
5217
|
+
React3.useEffect(() => {
|
|
5066
5218
|
onZoomChange?.(state.level, {
|
|
5067
5219
|
orbital: state.selectedOrbital ?? void 0,
|
|
5068
5220
|
trait: state.selectedTrait ?? void 0
|
|
5069
5221
|
});
|
|
5070
5222
|
}, [state.level, state.selectedOrbital, state.selectedTrait, onZoomChange]);
|
|
5071
|
-
|
|
5223
|
+
React3.useEffect(() => {
|
|
5072
5224
|
if (!state.animating) return;
|
|
5073
5225
|
const timer = setTimeout(() => {
|
|
5074
5226
|
dispatch({ type: "ANIMATION_COMPLETE" });
|
|
5075
5227
|
}, 800);
|
|
5076
5228
|
return () => clearTimeout(timer);
|
|
5077
5229
|
}, [state.animating]);
|
|
5078
|
-
const handleKeyDown =
|
|
5230
|
+
const handleKeyDown = React3.useCallback((e) => {
|
|
5079
5231
|
if (e.key === "Escape") {
|
|
5080
5232
|
dispatch({ type: "ZOOM_OUT" });
|
|
5081
5233
|
}
|
|
5082
5234
|
}, []);
|
|
5083
|
-
const handleOrbitalClick =
|
|
5235
|
+
const handleOrbitalClick = React3.useCallback((name) => {
|
|
5084
5236
|
dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: name, targetPosition: { x: 0, y: 0 } });
|
|
5085
5237
|
}, []);
|
|
5086
|
-
const handleTraitClick =
|
|
5238
|
+
const handleTraitClick = React3.useCallback((name) => {
|
|
5087
5239
|
dispatch({ type: "ZOOM_INTO_TRAIT", trait: name, targetPosition: { x: 0, y: 0 } });
|
|
5088
5240
|
}, []);
|
|
5089
|
-
const [highlightedTrait, setHighlightedTrait] =
|
|
5090
|
-
const handleTransitionClick =
|
|
5241
|
+
const [highlightedTrait, setHighlightedTrait] = React3__default.default.useState(null);
|
|
5242
|
+
const handleTransitionClick = React3.useCallback((index) => {
|
|
5091
5243
|
dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex: index, targetPosition: { x: 0, y: 0 } });
|
|
5092
5244
|
}, []);
|
|
5093
|
-
const handleBreadcrumbClick =
|
|
5245
|
+
const handleBreadcrumbClick = React3.useCallback((targetLevel) => {
|
|
5094
5246
|
const levelOrder = ["application", "orbital", "trait", "transition"];
|
|
5095
5247
|
const currentIdx = levelOrder.indexOf(state.level);
|
|
5096
5248
|
const targetIdx = levelOrder.indexOf(targetLevel);
|
|
@@ -5099,7 +5251,7 @@ var Avl3DViewer = ({
|
|
|
5099
5251
|
}
|
|
5100
5252
|
}, [state.level]);
|
|
5101
5253
|
const cameraConfig = CAMERA_POSITIONS[state.level];
|
|
5102
|
-
const sceneContent =
|
|
5254
|
+
const sceneContent = React3.useMemo(() => {
|
|
5103
5255
|
switch (state.level) {
|
|
5104
5256
|
case "application": {
|
|
5105
5257
|
const data = parseApplicationLevel(schema);
|
|
@@ -5173,7 +5325,7 @@ var Avl3DViewer = ({
|
|
|
5173
5325
|
gap: "xs",
|
|
5174
5326
|
align: "center",
|
|
5175
5327
|
className: "absolute top-2 left-2 z-10 bg-surface/80 backdrop-blur rounded-md px-3 py-1.5",
|
|
5176
|
-
children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5328
|
+
children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxRuntime.jsxs(React3__default.default.Fragment, { children: [
|
|
5177
5329
|
i > 0 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", className: "mx-1", children: "/" }),
|
|
5178
5330
|
i < breadcrumbs.length - 1 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5179
5331
|
Box,
|