@almadar/ui 5.105.0 → 5.107.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 +1903 -4193
- package/dist/avl/index.js +998 -3288
- package/dist/components/core/atoms/index.d.ts +1 -1
- package/dist/components/core/molecules/index.d.ts +1 -1
- package/dist/components/core/organisms/index.d.ts +1 -1
- package/dist/components/core/templates/index.d.ts +2 -2
- package/dist/components/game/{2d/atoms → atoms}/ActionButton.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/ChoiceButton.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/ControlButton.d.ts +1 -1
- package/dist/components/game/atoms/DrawShape.d.ts +50 -0
- package/dist/components/game/atoms/DrawSprite.d.ts +47 -0
- package/dist/components/game/atoms/DrawText.d.ts +31 -0
- package/dist/components/game/{2d/atoms → atoms}/GameAudioToggle.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/GameIcon.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/ItemSlot.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/MiniMap.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/ResourceCounter.d.ts +2 -2
- package/dist/components/game/{2d/atoms → atoms}/ScoreDisplay.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/Sprite.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/StateIndicator.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/StatusEffect.d.ts +1 -1
- package/dist/components/game/{2d/atoms → atoms}/WaypointMarker.d.ts +1 -1
- package/dist/components/game/{shared/hooks → hooks}/useCamera.d.ts +1 -1
- package/dist/components/game/{shared/hooks → hooks}/useUnitSpriteAtlas.d.ts +2 -2
- package/dist/components/game/{shared → lib}/index.d.ts +1 -2
- package/dist/components/game/{shared/lib → lib}/puzzleObject.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/ActionTile.d.ts +1 -1
- package/dist/components/game/molecules/Canvas.d.ts +96 -0
- package/dist/components/game/molecules/Canvas2D.d.ts +120 -0
- package/dist/components/game/{2d/molecules → molecules}/ControlGrid.d.ts +1 -1
- package/dist/components/game/molecules/DrawShapeLayer.d.ts +19 -0
- package/dist/components/game/molecules/DrawSpriteLayer.d.ts +21 -0
- package/dist/components/game/molecules/DrawTextLayer.d.ts +22 -0
- package/dist/components/game/{2d/molecules → molecules}/GameHud.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/InventoryGrid.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/ResourceBar.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/StatBadge.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/StateNode.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/TraitSlot.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/TraitStateViewer.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/TransitionArrow.d.ts +1 -1
- package/dist/components/game/{2d/molecules → molecules}/index.d.ts +9 -16
- package/dist/components/game/patterns.d.ts +20 -0
- package/dist/components/game/{shared/providers → providers}/GameAudioProvider.d.ts +1 -1
- package/dist/components/game/{2d/templates → templates}/GameTemplate.d.ts +1 -1
- package/dist/components/game/{3d → three}/atoms/SpriteBillboard3D.d.ts +1 -1
- package/dist/components/game/{shared → three}/hooks/useGameCanvas3DEvents.d.ts +4 -3
- package/dist/components/game/{3d → three}/index.cjs +766 -3008
- package/dist/components/game/{3d → three}/index.css +3 -3
- package/dist/components/game/{3d → three}/index.d.ts +0 -1
- package/dist/components/game/{3d → three}/index.js +622 -2863
- package/dist/components/game/{shared → three}/lib/game3dAssetManifest.d.ts +1 -1
- package/dist/components/game/three/molecules/GameCanvas3D.d.ts +175 -0
- package/dist/components/game/{3d → three}/molecules/index.d.ts +9 -12
- package/dist/components/game/{3d → three}/patterns.d.ts +0 -4
- package/dist/components/index.cjs +2315 -4418
- package/dist/components/index.js +1412 -3508
- package/dist/lib/drawable/Drawable3D.d.ts +20 -0
- package/dist/lib/drawable/contract.d.ts +68 -0
- package/dist/lib/drawable/hitTest.d.ts +23 -0
- package/dist/lib/drawable/mesh3d.d.ts +28 -0
- package/dist/lib/drawable/paintDispatch.d.ts +22 -0
- package/dist/lib/drawable/projector.d.ts +14 -0
- package/dist/lib/drawable/projector3d.d.ts +20 -0
- package/dist/lib/imageCache.d.ts +9 -0
- package/dist/lib/painter2d.d.ts +81 -0
- package/dist/lib/webPainter2d.d.ts +7 -0
- package/dist/marketing/index.cjs +10 -0
- package/dist/marketing/index.js +10 -0
- package/dist/providers/index.cjs +1748 -4042
- package/dist/providers/index.js +956 -3250
- package/dist/runtime/index.cjs +1758 -4048
- package/dist/runtime/index.js +972 -3262
- package/package.json +13 -13
- package/dist/components/game/2d/molecules/Canvas2D.d.ts +0 -175
- package/dist/components/game/2d/molecules/SideCanvas2D.d.ts +0 -36
- package/dist/components/game/2d/organisms/BuilderBoard.d.ts +0 -60
- package/dist/components/game/2d/organisms/ClassifierBoard.d.ts +0 -66
- package/dist/components/game/2d/organisms/DebuggerBoard.d.ts +0 -61
- package/dist/components/game/2d/organisms/EventHandlerBoard.d.ts +0 -42
- package/dist/components/game/2d/organisms/NegotiatorBoard.d.ts +0 -56
- package/dist/components/game/2d/organisms/SequencerBoard.d.ts +0 -69
- package/dist/components/game/2d/organisms/SimulatorBoard.d.ts +0 -58
- package/dist/components/game/2d/organisms/StateArchitectBoard.d.ts +0 -61
- package/dist/components/game/3d/atoms/EventMarker3D.d.ts +0 -17
- package/dist/components/game/3d/molecules/FeatureMesh3D.d.ts +0 -21
- package/dist/components/game/3d/molecules/GameCanvas3D.d.ts +0 -259
- package/dist/components/game/3d/molecules/SideScene3D.d.ts +0 -31
- package/dist/components/game/3d/molecules/TileMesh3D.d.ts +0 -28
- package/dist/components/game/3d/molecules/UnitMesh3D.d.ts +0 -29
- package/dist/components/game/3d/organisms/GameBoard3D.d.ts +0 -66
- package/dist/components/game/3d/templates/GameCanvas3DBattleTemplate.d.ts +0 -82
- package/dist/components/game/3d/templates/GameCanvas3DCastleTemplate.d.ts +0 -87
- package/dist/components/game/3d/templates/GameCanvas3DWorldMapTemplate.d.ts +0 -95
- package/dist/components/game/shared/effects.d.ts +0 -253
- /package/dist/components/game/{2d/atoms → atoms}/ComboCounter.d.ts +0 -0
- /package/dist/components/game/{2d/atoms → atoms}/DamageNumber.d.ts +0 -0
- /package/dist/components/game/{2d/atoms → atoms}/DialogueBubble.d.ts +0 -0
- /package/dist/components/game/{2d/atoms → atoms}/GameCard.d.ts +0 -0
- /package/dist/components/game/{2d/atoms → atoms}/HealthBar.d.ts +0 -0
- /package/dist/components/game/{2d/atoms → atoms}/TimerDisplay.d.ts +0 -0
- /package/dist/components/game/{2d/atoms → atoms}/TurnIndicator.d.ts +0 -0
- /package/dist/components/game/{shared/hooks → hooks}/useGameAudio.d.ts +0 -0
- /package/dist/components/game/{shared → hooks}/useImageCache.d.ts +0 -0
- /package/dist/components/game/{shared → lib}/boardEntity.d.ts +0 -0
- /package/dist/components/game/{shared/lib → lib}/editorUtils.d.ts +0 -0
- /package/dist/components/game/{shared → lib}/game.d.ts +0 -0
- /package/dist/components/game/{shared → lib}/isometric.d.ts +0 -0
- /package/dist/components/game/{shared → lib}/isometricTypes.d.ts +0 -0
- /package/dist/components/game/{shared → lib}/makeAsset.d.ts +0 -0
- /package/dist/components/game/{shared/lib → lib}/mechanics.d.ts +0 -0
- /package/dist/components/game/{shared/lib → lib}/physicsPresets.d.ts +0 -0
- /package/dist/components/game/{shared/lib → lib}/physicsTypes.d.ts +0 -0
- /package/dist/components/game/{shared → lib}/spriteAnimation.d.ts +0 -0
- /package/dist/components/game/{shared → lib}/spriteAnimationTypes.d.ts +0 -0
- /package/dist/components/game/{shared → lib}/spriteSheetConstants.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/ActionPalette.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/EventLog.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/GameMenu.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/ObjectRulePanel.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/RuleEditor.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/SequenceBar.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/StateGraph.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/StateJsonView.d.ts +0 -0
- /package/dist/components/game/{2d/molecules → molecules}/VariablePanel.d.ts +0 -0
- /package/dist/components/game/{2d/templates → templates}/GameShell.d.ts +0 -0
- /package/dist/components/game/{shared → three}/game3dTheme.d.ts +0 -0
- /package/dist/components/game/{shared → three}/hooks/useAssetLoader.d.ts +0 -0
- /package/dist/components/game/{shared → three}/hooks/useRaycaster.d.ts +0 -0
- /package/dist/components/game/{shared → three}/hooks/useSceneGraph.d.ts +0 -0
- /package/dist/components/game/{shared → three}/hooks/useThree.d.ts +0 -0
- /package/dist/components/game/{shared → three}/lib/AssetLoader.d.ts +0 -0
- /package/dist/components/game/{shared → three}/lib/culling.d.ts +0 -0
- /package/dist/components/game/{shared → three}/lib/grid3D.d.ts +0 -0
- /package/dist/components/game/{3d → three}/molecules/Camera3D.d.ts +0 -0
- /package/dist/components/game/{3d → three}/molecules/Canvas3DErrorBoundary.d.ts +0 -0
- /package/dist/components/game/{3d → three}/molecules/Canvas3DLoadingState.d.ts +0 -0
- /package/dist/components/game/{3d → three}/molecules/GameCamera3D.d.ts +0 -0
- /package/dist/components/game/{3d → three}/molecules/Lighting3D.d.ts +0 -0
- /package/dist/components/game/{3d → three}/molecules/ModelLoader.d.ts +0 -0
- /package/dist/components/game/{3d → three}/molecules/Scene3D.d.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React7 = require('react');
|
|
4
4
|
var fiber = require('@react-three/fiber');
|
|
5
5
|
var THREE6 = require('three');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -14,10 +14,11 @@ var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
|
14
14
|
var providers = require('@almadar/ui/providers');
|
|
15
15
|
var clsx = require('clsx');
|
|
16
16
|
var tailwindMerge = require('tailwind-merge');
|
|
17
|
-
var LucideIcons = require('lucide-react');
|
|
18
17
|
var postprocessing = require('@react-three/postprocessing');
|
|
19
18
|
var hooks = require('@almadar/ui/hooks');
|
|
20
19
|
|
|
20
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
|
+
|
|
21
22
|
function _interopNamespace(e) {
|
|
22
23
|
if (e && e.__esModule) return e;
|
|
23
24
|
var n = Object.create(null);
|
|
@@ -36,17 +37,16 @@ function _interopNamespace(e) {
|
|
|
36
37
|
return Object.freeze(n);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
var
|
|
40
|
+
var React7__default = /*#__PURE__*/_interopDefault(React7);
|
|
40
41
|
var THREE6__namespace = /*#__PURE__*/_interopNamespace(THREE6);
|
|
41
|
-
var LucideIcons__namespace = /*#__PURE__*/_interopNamespace(LucideIcons);
|
|
42
42
|
|
|
43
43
|
var __defProp = Object.defineProperty;
|
|
44
44
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
45
45
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
46
46
|
function Scene3D({ background = "#1a1a2e", fog, children }) {
|
|
47
47
|
const { scene } = fiber.useThree();
|
|
48
|
-
const initializedRef =
|
|
49
|
-
|
|
48
|
+
const initializedRef = React7.useRef(false);
|
|
49
|
+
React7.useEffect(() => {
|
|
50
50
|
if (initializedRef.current) return;
|
|
51
51
|
initializedRef.current = true;
|
|
52
52
|
if (background.startsWith("#") || background.startsWith("rgb")) {
|
|
@@ -67,7 +67,7 @@ function Scene3D({ background = "#1a1a2e", fog, children }) {
|
|
|
67
67
|
}, [scene, background, fog]);
|
|
68
68
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
69
69
|
}
|
|
70
|
-
var Camera3D =
|
|
70
|
+
var Camera3D = React7.forwardRef(
|
|
71
71
|
({
|
|
72
72
|
mode = "isometric",
|
|
73
73
|
position = [10, 10, 10],
|
|
@@ -80,10 +80,10 @@ var Camera3D = React10.forwardRef(
|
|
|
80
80
|
onChange
|
|
81
81
|
}, ref) => {
|
|
82
82
|
const { camera, set, viewport } = fiber.useThree();
|
|
83
|
-
const controlsRef =
|
|
84
|
-
const initialPosition =
|
|
85
|
-
const initialTarget =
|
|
86
|
-
|
|
83
|
+
const controlsRef = React7.useRef(null);
|
|
84
|
+
const initialPosition = React7.useRef(new THREE6__namespace.Vector3(...position));
|
|
85
|
+
const initialTarget = React7.useRef(new THREE6__namespace.Vector3(...target));
|
|
86
|
+
React7.useEffect(() => {
|
|
87
87
|
let newCamera;
|
|
88
88
|
if (mode === "isometric") {
|
|
89
89
|
const aspect = viewport.aspect;
|
|
@@ -114,7 +114,7 @@ var Camera3D = React10.forwardRef(
|
|
|
114
114
|
onChange(camera);
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
|
-
|
|
117
|
+
React7.useImperativeHandle(ref, () => ({
|
|
118
118
|
getCamera: () => camera,
|
|
119
119
|
setPosition: (x, y, z) => {
|
|
120
120
|
camera.position.set(x, y, z);
|
|
@@ -261,7 +261,7 @@ function Canvas3DLoadingState({
|
|
|
261
261
|
] });
|
|
262
262
|
}
|
|
263
263
|
var log = logger.createLogger("almadar:ui:game:canvas3d:error-boundary");
|
|
264
|
-
var Canvas3DErrorBoundary = class extends
|
|
264
|
+
var Canvas3DErrorBoundary = class extends React7.Component {
|
|
265
265
|
constructor(props) {
|
|
266
266
|
super(props);
|
|
267
267
|
__publicField(this, "handleReset", () => {
|
|
@@ -376,10 +376,10 @@ function stateFromEntry(entry) {
|
|
|
376
376
|
return { model: null, clips: [], isLoading: !entry.error, error: entry.error ?? null };
|
|
377
377
|
}
|
|
378
378
|
function useGLTFModel(url, resourceBasePath) {
|
|
379
|
-
const [state, setState] =
|
|
379
|
+
const [state, setState] = React7.useState(
|
|
380
380
|
() => stateFromEntry(url ? loadGltfCached(url, resourceBasePath || detectAssetRoot(url)) : null)
|
|
381
381
|
);
|
|
382
|
-
|
|
382
|
+
React7.useEffect(() => {
|
|
383
383
|
if (!url) {
|
|
384
384
|
setState({ model: null, clips: [], isLoading: false, error: null });
|
|
385
385
|
return;
|
|
@@ -414,7 +414,7 @@ function ModelLoader({
|
|
|
414
414
|
tint
|
|
415
415
|
}) {
|
|
416
416
|
const { model: loadedModel, clips, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
417
|
-
const model =
|
|
417
|
+
const model = React7.useMemo(() => {
|
|
418
418
|
if (!loadedModel) return null;
|
|
419
419
|
const cloned = SkeletonUtils.clone(loadedModel);
|
|
420
420
|
cloned.updateMatrixWorld(true);
|
|
@@ -432,8 +432,8 @@ function ModelLoader({
|
|
|
432
432
|
});
|
|
433
433
|
return cloned;
|
|
434
434
|
}, [loadedModel, castShadow, receiveShadow, tint]);
|
|
435
|
-
const mixer =
|
|
436
|
-
|
|
435
|
+
const mixer = React7.useMemo(() => model ? new THREE6__namespace.AnimationMixer(model) : null, [model]);
|
|
436
|
+
React7.useEffect(() => {
|
|
437
437
|
if (!mixer || !animation || clips.length === 0) return;
|
|
438
438
|
const wanted = animation.toLowerCase();
|
|
439
439
|
const clip = clips.find((c) => c.name === animation) ?? clips.find((c) => c.name.toLowerCase() === wanted);
|
|
@@ -447,7 +447,7 @@ function ModelLoader({
|
|
|
447
447
|
fiber.useFrame((_, delta) => {
|
|
448
448
|
mixer?.update(delta);
|
|
449
449
|
});
|
|
450
|
-
const normFactor =
|
|
450
|
+
const normFactor = React7.useMemo(() => {
|
|
451
451
|
if (!model) return 1;
|
|
452
452
|
const box = new THREE6__namespace.Box3().setFromObject(model);
|
|
453
453
|
const size = new THREE6__namespace.Vector3();
|
|
@@ -456,11 +456,11 @@ function ModelLoader({
|
|
|
456
456
|
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
457
457
|
return 1 / maxDim;
|
|
458
458
|
}, [model]);
|
|
459
|
-
const scaleArray =
|
|
459
|
+
const scaleArray = React7.useMemo(() => {
|
|
460
460
|
const base = typeof scale === "number" ? [scale, scale, scale] : scale;
|
|
461
461
|
return [base[0] * normFactor, base[1] * normFactor, base[2] * normFactor];
|
|
462
462
|
}, [scale, normFactor]);
|
|
463
|
-
const rotationRad =
|
|
463
|
+
const rotationRad = React7.useMemo(() => {
|
|
464
464
|
return [
|
|
465
465
|
rotation[0] * Math.PI / 180,
|
|
466
466
|
rotation[1] * Math.PI / 180,
|
|
@@ -728,7 +728,7 @@ var AssetLoader = class {
|
|
|
728
728
|
};
|
|
729
729
|
var assetLoader = new AssetLoader();
|
|
730
730
|
|
|
731
|
-
// components/game/
|
|
731
|
+
// components/game/three/hooks/useThree.ts
|
|
732
732
|
var DEFAULT_OPTIONS = {
|
|
733
733
|
cameraMode: "isometric",
|
|
734
734
|
cameraPosition: [10, 10, 10],
|
|
@@ -740,21 +740,21 @@ var DEFAULT_OPTIONS = {
|
|
|
740
740
|
};
|
|
741
741
|
function useThree3(options = {}) {
|
|
742
742
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
743
|
-
const containerRef =
|
|
744
|
-
const canvasRef =
|
|
745
|
-
const rendererRef =
|
|
746
|
-
const sceneRef =
|
|
747
|
-
const cameraRef =
|
|
748
|
-
const controlsRef =
|
|
749
|
-
const gridHelperRef =
|
|
750
|
-
const rafRef =
|
|
751
|
-
const [isReady, setIsReady] =
|
|
752
|
-
const [dimensions, setDimensions] =
|
|
753
|
-
const initialCameraPosition =
|
|
743
|
+
const containerRef = React7.useRef(null);
|
|
744
|
+
const canvasRef = React7.useRef(null);
|
|
745
|
+
const rendererRef = React7.useRef(null);
|
|
746
|
+
const sceneRef = React7.useRef(null);
|
|
747
|
+
const cameraRef = React7.useRef(null);
|
|
748
|
+
const controlsRef = React7.useRef(null);
|
|
749
|
+
const gridHelperRef = React7.useRef(null);
|
|
750
|
+
const rafRef = React7.useRef(0);
|
|
751
|
+
const [isReady, setIsReady] = React7.useState(false);
|
|
752
|
+
const [dimensions, setDimensions] = React7.useState({ width: 0, height: 0 });
|
|
753
|
+
const initialCameraPosition = React7.useMemo(
|
|
754
754
|
() => new THREE6__namespace.Vector3(...opts.cameraPosition),
|
|
755
755
|
[]
|
|
756
756
|
);
|
|
757
|
-
|
|
757
|
+
React7.useEffect(() => {
|
|
758
758
|
if (!containerRef.current) return;
|
|
759
759
|
const container = containerRef.current;
|
|
760
760
|
const { clientWidth, clientHeight } = container;
|
|
@@ -847,7 +847,7 @@ function useThree3(options = {}) {
|
|
|
847
847
|
scene.clear();
|
|
848
848
|
};
|
|
849
849
|
}, []);
|
|
850
|
-
|
|
850
|
+
React7.useEffect(() => {
|
|
851
851
|
if (!cameraRef.current || !containerRef.current) return;
|
|
852
852
|
const container = containerRef.current;
|
|
853
853
|
const { clientWidth, clientHeight } = container;
|
|
@@ -882,20 +882,20 @@ function useThree3(options = {}) {
|
|
|
882
882
|
animate();
|
|
883
883
|
}
|
|
884
884
|
}, [opts.cameraMode]);
|
|
885
|
-
const setCameraPosition =
|
|
885
|
+
const setCameraPosition = React7.useCallback((x, y, z) => {
|
|
886
886
|
if (cameraRef.current) {
|
|
887
887
|
cameraRef.current.position.set(x, y, z);
|
|
888
888
|
controlsRef.current?.update();
|
|
889
889
|
}
|
|
890
890
|
}, []);
|
|
891
|
-
const lookAt =
|
|
891
|
+
const lookAt = React7.useCallback((x, y, z) => {
|
|
892
892
|
if (cameraRef.current) {
|
|
893
893
|
cameraRef.current.lookAt(x, y, z);
|
|
894
894
|
controlsRef.current?.target.set(x, y, z);
|
|
895
895
|
controlsRef.current?.update();
|
|
896
896
|
}
|
|
897
897
|
}, []);
|
|
898
|
-
const resetCamera =
|
|
898
|
+
const resetCamera = React7.useCallback(() => {
|
|
899
899
|
if (cameraRef.current) {
|
|
900
900
|
cameraRef.current.position.copy(initialCameraPosition);
|
|
901
901
|
cameraRef.current.lookAt(0, 0, 0);
|
|
@@ -905,7 +905,7 @@ function useThree3(options = {}) {
|
|
|
905
905
|
}
|
|
906
906
|
}
|
|
907
907
|
}, [initialCameraPosition]);
|
|
908
|
-
const fitView =
|
|
908
|
+
const fitView = React7.useCallback(
|
|
909
909
|
(bounds) => {
|
|
910
910
|
if (!cameraRef.current) return;
|
|
911
911
|
const centerX = (bounds.minX + bounds.maxX) / 2;
|
|
@@ -936,20 +936,20 @@ function useThree3(options = {}) {
|
|
|
936
936
|
}
|
|
937
937
|
function useAssetLoader(options = {}) {
|
|
938
938
|
const { preloadUrls = [], loader: customLoader } = options;
|
|
939
|
-
const loaderRef =
|
|
940
|
-
const [state, setState] =
|
|
939
|
+
const loaderRef = React7.useRef(customLoader || new AssetLoader());
|
|
940
|
+
const [state, setState] = React7.useState({
|
|
941
941
|
isLoading: false,
|
|
942
942
|
progress: 0,
|
|
943
943
|
loaded: 0,
|
|
944
944
|
total: 0,
|
|
945
945
|
errors: []
|
|
946
946
|
});
|
|
947
|
-
|
|
947
|
+
React7.useEffect(() => {
|
|
948
948
|
if (preloadUrls.length > 0) {
|
|
949
949
|
preload(preloadUrls);
|
|
950
950
|
}
|
|
951
951
|
}, []);
|
|
952
|
-
const updateProgress =
|
|
952
|
+
const updateProgress = React7.useCallback((loaded, total) => {
|
|
953
953
|
setState((prev) => ({
|
|
954
954
|
...prev,
|
|
955
955
|
loaded,
|
|
@@ -957,7 +957,7 @@ function useAssetLoader(options = {}) {
|
|
|
957
957
|
progress: total > 0 ? Math.round(loaded / total * 100) : 0
|
|
958
958
|
}));
|
|
959
959
|
}, []);
|
|
960
|
-
const loadModel =
|
|
960
|
+
const loadModel = React7.useCallback(
|
|
961
961
|
async (url) => {
|
|
962
962
|
setState((prev) => ({ ...prev, isLoading: true }));
|
|
963
963
|
try {
|
|
@@ -980,7 +980,7 @@ function useAssetLoader(options = {}) {
|
|
|
980
980
|
},
|
|
981
981
|
[]
|
|
982
982
|
);
|
|
983
|
-
const loadOBJ =
|
|
983
|
+
const loadOBJ = React7.useCallback(
|
|
984
984
|
async (url) => {
|
|
985
985
|
setState((prev) => ({ ...prev, isLoading: true }));
|
|
986
986
|
try {
|
|
@@ -1003,7 +1003,7 @@ function useAssetLoader(options = {}) {
|
|
|
1003
1003
|
},
|
|
1004
1004
|
[]
|
|
1005
1005
|
);
|
|
1006
|
-
const loadTexture =
|
|
1006
|
+
const loadTexture = React7.useCallback(
|
|
1007
1007
|
async (url) => {
|
|
1008
1008
|
setState((prev) => ({ ...prev, isLoading: true }));
|
|
1009
1009
|
try {
|
|
@@ -1026,7 +1026,7 @@ function useAssetLoader(options = {}) {
|
|
|
1026
1026
|
},
|
|
1027
1027
|
[]
|
|
1028
1028
|
);
|
|
1029
|
-
const preload =
|
|
1029
|
+
const preload = React7.useCallback(
|
|
1030
1030
|
async (urls) => {
|
|
1031
1031
|
setState((prev) => ({
|
|
1032
1032
|
...prev,
|
|
@@ -1065,27 +1065,27 @@ function useAssetLoader(options = {}) {
|
|
|
1065
1065
|
},
|
|
1066
1066
|
[updateProgress]
|
|
1067
1067
|
);
|
|
1068
|
-
const hasModel =
|
|
1068
|
+
const hasModel = React7.useCallback((url) => {
|
|
1069
1069
|
return loaderRef.current.hasModel(url);
|
|
1070
1070
|
}, []);
|
|
1071
|
-
const hasTexture =
|
|
1071
|
+
const hasTexture = React7.useCallback((url) => {
|
|
1072
1072
|
return loaderRef.current.hasTexture(url);
|
|
1073
1073
|
}, []);
|
|
1074
|
-
const getModel =
|
|
1074
|
+
const getModel = React7.useCallback((url) => {
|
|
1075
1075
|
try {
|
|
1076
1076
|
return loaderRef.current.getModel(url);
|
|
1077
1077
|
} catch {
|
|
1078
1078
|
return void 0;
|
|
1079
1079
|
}
|
|
1080
1080
|
}, []);
|
|
1081
|
-
const getTexture =
|
|
1081
|
+
const getTexture = React7.useCallback((url) => {
|
|
1082
1082
|
try {
|
|
1083
1083
|
return loaderRef.current.getTexture(url);
|
|
1084
1084
|
} catch {
|
|
1085
1085
|
return void 0;
|
|
1086
1086
|
}
|
|
1087
1087
|
}, []);
|
|
1088
|
-
const clearCache =
|
|
1088
|
+
const clearCache = React7.useCallback(() => {
|
|
1089
1089
|
loaderRef.current.clearCache();
|
|
1090
1090
|
setState({
|
|
1091
1091
|
isLoading: false,
|
|
@@ -1109,25 +1109,25 @@ function useAssetLoader(options = {}) {
|
|
|
1109
1109
|
};
|
|
1110
1110
|
}
|
|
1111
1111
|
function useSceneGraph() {
|
|
1112
|
-
const nodesRef =
|
|
1113
|
-
const addNode =
|
|
1112
|
+
const nodesRef = React7.useRef(/* @__PURE__ */ new Map());
|
|
1113
|
+
const addNode = React7.useCallback((node) => {
|
|
1114
1114
|
const existing = nodesRef.current.get(node.id);
|
|
1115
1115
|
if (existing) {
|
|
1116
1116
|
existing.mesh.removeFromParent();
|
|
1117
1117
|
}
|
|
1118
1118
|
nodesRef.current.set(node.id, node);
|
|
1119
1119
|
}, []);
|
|
1120
|
-
const removeNode =
|
|
1120
|
+
const removeNode = React7.useCallback((id) => {
|
|
1121
1121
|
const node = nodesRef.current.get(id);
|
|
1122
1122
|
if (node) {
|
|
1123
1123
|
node.mesh.removeFromParent();
|
|
1124
1124
|
nodesRef.current.delete(id);
|
|
1125
1125
|
}
|
|
1126
1126
|
}, []);
|
|
1127
|
-
const getNode =
|
|
1127
|
+
const getNode = React7.useCallback((id) => {
|
|
1128
1128
|
return nodesRef.current.get(id);
|
|
1129
1129
|
}, []);
|
|
1130
|
-
const updateNodePosition =
|
|
1130
|
+
const updateNodePosition = React7.useCallback(
|
|
1131
1131
|
(id, x, y, z) => {
|
|
1132
1132
|
const node = nodesRef.current.get(id);
|
|
1133
1133
|
if (node) {
|
|
@@ -1137,7 +1137,7 @@ function useSceneGraph() {
|
|
|
1137
1137
|
},
|
|
1138
1138
|
[]
|
|
1139
1139
|
);
|
|
1140
|
-
const updateNodeGridPosition =
|
|
1140
|
+
const updateNodeGridPosition = React7.useCallback(
|
|
1141
1141
|
(id, gridX, gridZ) => {
|
|
1142
1142
|
const node = nodesRef.current.get(id);
|
|
1143
1143
|
if (node) {
|
|
@@ -1146,7 +1146,7 @@ function useSceneGraph() {
|
|
|
1146
1146
|
},
|
|
1147
1147
|
[]
|
|
1148
1148
|
);
|
|
1149
|
-
const getNodeAtGrid =
|
|
1149
|
+
const getNodeAtGrid = React7.useCallback(
|
|
1150
1150
|
(x, z, type) => {
|
|
1151
1151
|
return Array.from(nodesRef.current.values()).find((node) => {
|
|
1152
1152
|
const matchesGrid = node.gridPosition.x === x && node.gridPosition.z === z;
|
|
@@ -1155,10 +1155,10 @@ function useSceneGraph() {
|
|
|
1155
1155
|
},
|
|
1156
1156
|
[]
|
|
1157
1157
|
);
|
|
1158
|
-
const getNodesByType =
|
|
1158
|
+
const getNodesByType = React7.useCallback((type) => {
|
|
1159
1159
|
return Array.from(nodesRef.current.values()).filter((node) => node.type === type);
|
|
1160
1160
|
}, []);
|
|
1161
|
-
const getNodesInBounds =
|
|
1161
|
+
const getNodesInBounds = React7.useCallback(
|
|
1162
1162
|
(minX, maxX, minZ, maxZ) => {
|
|
1163
1163
|
return Array.from(nodesRef.current.values()).filter((node) => {
|
|
1164
1164
|
const { x, z } = node.gridPosition;
|
|
@@ -1167,13 +1167,13 @@ function useSceneGraph() {
|
|
|
1167
1167
|
},
|
|
1168
1168
|
[]
|
|
1169
1169
|
);
|
|
1170
|
-
const clearNodes =
|
|
1170
|
+
const clearNodes = React7.useCallback(() => {
|
|
1171
1171
|
nodesRef.current.forEach((node) => {
|
|
1172
1172
|
node.mesh.removeFromParent();
|
|
1173
1173
|
});
|
|
1174
1174
|
nodesRef.current.clear();
|
|
1175
1175
|
}, []);
|
|
1176
|
-
const countNodes =
|
|
1176
|
+
const countNodes = React7.useCallback((type) => {
|
|
1177
1177
|
if (!type) {
|
|
1178
1178
|
return nodesRef.current.size;
|
|
1179
1179
|
}
|
|
@@ -1195,9 +1195,9 @@ function useSceneGraph() {
|
|
|
1195
1195
|
}
|
|
1196
1196
|
function useRaycaster(options) {
|
|
1197
1197
|
const { camera, canvas, cellSize = 1, offsetX = 0, offsetZ = 0 } = options;
|
|
1198
|
-
const raycaster =
|
|
1199
|
-
const mouse =
|
|
1200
|
-
const clientToNDC =
|
|
1198
|
+
const raycaster = React7.useRef(new THREE6__namespace.Raycaster());
|
|
1199
|
+
const mouse = React7.useRef(new THREE6__namespace.Vector2());
|
|
1200
|
+
const clientToNDC = React7.useCallback(
|
|
1201
1201
|
(clientX, clientY) => {
|
|
1202
1202
|
if (!canvas) {
|
|
1203
1203
|
return { x: 0, y: 0 };
|
|
@@ -1210,7 +1210,7 @@ function useRaycaster(options) {
|
|
|
1210
1210
|
},
|
|
1211
1211
|
[canvas]
|
|
1212
1212
|
);
|
|
1213
|
-
const isWithinCanvas =
|
|
1213
|
+
const isWithinCanvas = React7.useCallback(
|
|
1214
1214
|
(clientX, clientY) => {
|
|
1215
1215
|
if (!canvas) return false;
|
|
1216
1216
|
const rect = canvas.getBoundingClientRect();
|
|
@@ -1218,7 +1218,7 @@ function useRaycaster(options) {
|
|
|
1218
1218
|
},
|
|
1219
1219
|
[canvas]
|
|
1220
1220
|
);
|
|
1221
|
-
const getIntersection =
|
|
1221
|
+
const getIntersection = React7.useCallback(
|
|
1222
1222
|
(clientX, clientY, objects) => {
|
|
1223
1223
|
if (!camera || !canvas) return null;
|
|
1224
1224
|
const ndc = clientToNDC(clientX, clientY);
|
|
@@ -1241,7 +1241,7 @@ function useRaycaster(options) {
|
|
|
1241
1241
|
},
|
|
1242
1242
|
[camera, canvas, clientToNDC]
|
|
1243
1243
|
);
|
|
1244
|
-
const getAllIntersections =
|
|
1244
|
+
const getAllIntersections = React7.useCallback(
|
|
1245
1245
|
(clientX, clientY, objects) => {
|
|
1246
1246
|
if (!camera || !canvas) return [];
|
|
1247
1247
|
const ndc = clientToNDC(clientX, clientY);
|
|
@@ -1260,7 +1260,7 @@ function useRaycaster(options) {
|
|
|
1260
1260
|
},
|
|
1261
1261
|
[camera, canvas, clientToNDC]
|
|
1262
1262
|
);
|
|
1263
|
-
const getGridCoordinates =
|
|
1263
|
+
const getGridCoordinates = React7.useCallback(
|
|
1264
1264
|
(clientX, clientY) => {
|
|
1265
1265
|
if (!camera || !canvas) return null;
|
|
1266
1266
|
const ndc = clientToNDC(clientX, clientY);
|
|
@@ -1278,7 +1278,7 @@ function useRaycaster(options) {
|
|
|
1278
1278
|
},
|
|
1279
1279
|
[camera, canvas, cellSize, offsetX, offsetZ, clientToNDC]
|
|
1280
1280
|
);
|
|
1281
|
-
const getTileAtPosition =
|
|
1281
|
+
const getTileAtPosition = React7.useCallback(
|
|
1282
1282
|
(clientX, clientY, scene) => {
|
|
1283
1283
|
if (!camera || !canvas) return null;
|
|
1284
1284
|
const tileMeshes = [];
|
|
@@ -1401,10 +1401,10 @@ var fallbackEventBus = {
|
|
|
1401
1401
|
}
|
|
1402
1402
|
};
|
|
1403
1403
|
function useEventBus() {
|
|
1404
|
-
const context =
|
|
1404
|
+
const context = React7.useContext(providers.EventBusContext);
|
|
1405
1405
|
const baseBus = context ?? getGlobalEventBus() ?? fallbackEventBus;
|
|
1406
1406
|
const scope = providers.useTraitScope();
|
|
1407
|
-
return
|
|
1407
|
+
return React7.useMemo(() => {
|
|
1408
1408
|
if (!scope) {
|
|
1409
1409
|
return {
|
|
1410
1410
|
...baseBus,
|
|
@@ -1440,7 +1440,7 @@ function useEventBus() {
|
|
|
1440
1440
|
}
|
|
1441
1441
|
function useEmitEvent() {
|
|
1442
1442
|
const eventBus = useEventBus();
|
|
1443
|
-
return
|
|
1443
|
+
return React7.useCallback(
|
|
1444
1444
|
(type, payload, source) => {
|
|
1445
1445
|
eventBus.emit(type, payload, source);
|
|
1446
1446
|
},
|
|
@@ -1448,7 +1448,7 @@ function useEmitEvent() {
|
|
|
1448
1448
|
);
|
|
1449
1449
|
}
|
|
1450
1450
|
|
|
1451
|
-
// components/game/
|
|
1451
|
+
// components/game/three/hooks/useGameCanvas3DEvents.ts
|
|
1452
1452
|
function useGameCanvas3DEvents(options) {
|
|
1453
1453
|
const {
|
|
1454
1454
|
tileClickEvent,
|
|
@@ -1467,9 +1467,9 @@ function useGameCanvas3DEvents(options) {
|
|
|
1467
1467
|
onUnitAnimation
|
|
1468
1468
|
} = options;
|
|
1469
1469
|
const emit = useEmitEvent();
|
|
1470
|
-
const optionsRef =
|
|
1470
|
+
const optionsRef = React7.useRef(options);
|
|
1471
1471
|
optionsRef.current = options;
|
|
1472
|
-
const handleTileClick =
|
|
1472
|
+
const handleTileClick = React7.useCallback(
|
|
1473
1473
|
(tile, event) => {
|
|
1474
1474
|
if (tileClickEvent) {
|
|
1475
1475
|
emit(tileClickEvent, {
|
|
@@ -1485,7 +1485,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
1485
1485
|
},
|
|
1486
1486
|
[tileClickEvent, emit]
|
|
1487
1487
|
);
|
|
1488
|
-
const handleUnitClick =
|
|
1488
|
+
const handleUnitClick = React7.useCallback(
|
|
1489
1489
|
(unit, event) => {
|
|
1490
1490
|
if (unitClickEvent) {
|
|
1491
1491
|
emit(unitClickEvent, {
|
|
@@ -1504,7 +1504,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
1504
1504
|
},
|
|
1505
1505
|
[unitClickEvent, emit]
|
|
1506
1506
|
);
|
|
1507
|
-
const handleFeatureClick =
|
|
1507
|
+
const handleFeatureClick = React7.useCallback(
|
|
1508
1508
|
(feature, event) => {
|
|
1509
1509
|
if (featureClickEvent) {
|
|
1510
1510
|
emit(featureClickEvent, {
|
|
@@ -1519,7 +1519,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
1519
1519
|
},
|
|
1520
1520
|
[featureClickEvent, emit]
|
|
1521
1521
|
);
|
|
1522
|
-
const handleCanvasClick =
|
|
1522
|
+
const handleCanvasClick = React7.useCallback(
|
|
1523
1523
|
(event) => {
|
|
1524
1524
|
if (canvasClickEvent) {
|
|
1525
1525
|
emit(canvasClickEvent, {
|
|
@@ -1532,7 +1532,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
1532
1532
|
},
|
|
1533
1533
|
[canvasClickEvent, emit]
|
|
1534
1534
|
);
|
|
1535
|
-
const handleTileHover =
|
|
1535
|
+
const handleTileHover = React7.useCallback(
|
|
1536
1536
|
(tile, event) => {
|
|
1537
1537
|
if (tile) {
|
|
1538
1538
|
if (tileHoverEvent) {
|
|
@@ -1552,7 +1552,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
1552
1552
|
},
|
|
1553
1553
|
[tileHoverEvent, tileLeaveEvent, emit]
|
|
1554
1554
|
);
|
|
1555
|
-
const handleUnitAnimation =
|
|
1555
|
+
const handleUnitAnimation = React7.useCallback(
|
|
1556
1556
|
(unitId, state) => {
|
|
1557
1557
|
if (unitAnimationEvent) {
|
|
1558
1558
|
emit(unitAnimationEvent, {
|
|
@@ -1565,7 +1565,7 @@ function useGameCanvas3DEvents(options) {
|
|
|
1565
1565
|
},
|
|
1566
1566
|
[unitAnimationEvent, emit]
|
|
1567
1567
|
);
|
|
1568
|
-
const handleCameraChange =
|
|
1568
|
+
const handleCameraChange = React7.useCallback(
|
|
1569
1569
|
(position) => {
|
|
1570
1570
|
if (cameraChangeEvent) {
|
|
1571
1571
|
emit(cameraChangeEvent, {
|
|
@@ -1587,437 +1587,37 @@ function useGameCanvas3DEvents(options) {
|
|
|
1587
1587
|
};
|
|
1588
1588
|
}
|
|
1589
1589
|
|
|
1590
|
-
//
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
};
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
};
|
|
1606
|
-
var FACTION_COLORS_3D = {
|
|
1607
|
-
player: 4491519,
|
|
1608
|
-
enemy: 16729156,
|
|
1609
|
-
default: 16777028
|
|
1610
|
-
};
|
|
1611
|
-
var SELECTION_RING_COLOR_3D = "#ffff00";
|
|
1612
|
-
var HEALTHBAR_3D = {
|
|
1613
|
-
bg: 3355443,
|
|
1614
|
-
/** fill color thresholds: fraction > key → color */
|
|
1615
|
-
high: 4500036,
|
|
1616
|
-
// fraction > 0.5
|
|
1617
|
-
mid: 11184708,
|
|
1618
|
-
// fraction > 0.25
|
|
1619
|
-
low: 16729156,
|
|
1620
|
-
// else
|
|
1621
|
-
width: 0.5
|
|
1622
|
-
};
|
|
1623
|
-
function healthbarFill3D(fraction) {
|
|
1624
|
-
if (fraction > 0.5) return HEALTHBAR_3D.high;
|
|
1625
|
-
if (fraction > 0.25) return HEALTHBAR_3D.mid;
|
|
1626
|
-
return HEALTHBAR_3D.low;
|
|
1627
|
-
}
|
|
1628
|
-
var TREE_COLORS_3D = {
|
|
1629
|
-
trunk: 9127187,
|
|
1630
|
-
foliage: 2263842
|
|
1631
|
-
};
|
|
1632
|
-
var ROCK_COLOR_3D = 8421504;
|
|
1633
|
-
var EVENT_COLORS_3D = {
|
|
1634
|
-
hit: 16733508,
|
|
1635
|
-
damage: 16733508,
|
|
1636
|
-
attack: 16746564,
|
|
1637
|
-
heal: 4513126,
|
|
1638
|
-
pickup: 16763955,
|
|
1639
|
-
score: 16763955,
|
|
1640
|
-
death: 11154227,
|
|
1641
|
-
win: 6750088,
|
|
1642
|
-
lose: 16737894,
|
|
1643
|
-
default: 16777215
|
|
1644
|
-
};
|
|
1645
|
-
var SIDE_PLATFORM_COLORS_3D = {
|
|
1646
|
-
ground: 5999678,
|
|
1647
|
-
platform: 9132587,
|
|
1648
|
-
hazard: 13386820,
|
|
1649
|
-
goal: 4491468,
|
|
1650
|
-
default: 8947848
|
|
1651
|
-
};
|
|
1652
|
-
var SIDE_PLAYER_COLOR_3D = "#4488ff";
|
|
1653
|
-
var GRID_COLORS_3D = {
|
|
1654
|
-
cell: "#444444",
|
|
1655
|
-
section: "#666666"
|
|
1656
|
-
};
|
|
1657
|
-
var DEFAULT_BACKGROUND_3D = "#1a1a2e";
|
|
1658
|
-
function TileMesh3D({
|
|
1659
|
-
tile,
|
|
1660
|
-
position,
|
|
1661
|
-
model,
|
|
1662
|
-
isSelected,
|
|
1663
|
-
isHovered,
|
|
1664
|
-
isValidMove,
|
|
1665
|
-
isAttackTarget,
|
|
1666
|
-
onTileClick,
|
|
1667
|
-
onTileHover
|
|
1668
|
-
}) {
|
|
1669
|
-
const color = tile.color ?? TERRAIN_COLORS_3D[tile.type ?? ""] ?? TERRAIN_COLORS_3D.base;
|
|
1670
|
-
let emissive = HIGHLIGHT_EMISSIVE_3D.none;
|
|
1671
|
-
if (isSelected) emissive = HIGHLIGHT_EMISSIVE_3D.selected;
|
|
1672
|
-
else if (isAttackTarget) emissive = HIGHLIGHT_EMISSIVE_3D.attackTarget;
|
|
1673
|
-
else if (isValidMove) emissive = HIGHLIGHT_EMISSIVE_3D.validMove;
|
|
1674
|
-
else if (isHovered) emissive = HIGHLIGHT_EMISSIVE_3D.hovered;
|
|
1675
|
-
if (model?.url) {
|
|
1676
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1677
|
-
"group",
|
|
1678
|
-
{
|
|
1679
|
-
position,
|
|
1680
|
-
onClick: (e) => onTileClick(tile, e),
|
|
1681
|
-
onPointerEnter: (e) => onTileHover(tile, e),
|
|
1682
|
-
onPointerLeave: (e) => onTileHover(null, e),
|
|
1683
|
-
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
1684
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1685
|
-
ModelLoader,
|
|
1686
|
-
{
|
|
1687
|
-
url: model.url,
|
|
1688
|
-
scale: 0.95,
|
|
1689
|
-
rotation: [0, tile.rotation ?? 0, 0],
|
|
1690
|
-
fallbackGeometry: "box",
|
|
1691
|
-
castShadow: true,
|
|
1692
|
-
receiveShadow: true
|
|
1693
|
-
}
|
|
1694
|
-
)
|
|
1695
|
-
}
|
|
1696
|
-
);
|
|
1697
|
-
}
|
|
1698
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1699
|
-
"mesh",
|
|
1700
|
-
{
|
|
1701
|
-
position,
|
|
1702
|
-
onClick: (e) => onTileClick(tile, e),
|
|
1703
|
-
onPointerEnter: (e) => onTileHover(tile, e),
|
|
1704
|
-
onPointerLeave: (e) => onTileHover(null, e),
|
|
1705
|
-
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
1706
|
-
children: [
|
|
1707
|
-
/* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
|
|
1708
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, emissive })
|
|
1709
|
-
]
|
|
1590
|
+
// lib/drawable/hitTest.ts
|
|
1591
|
+
function collectDrawnItems(nodes) {
|
|
1592
|
+
const out = [];
|
|
1593
|
+
for (const n of nodes) {
|
|
1594
|
+
switch (n.type) {
|
|
1595
|
+
case "draw-sprite":
|
|
1596
|
+
case "draw-shape":
|
|
1597
|
+
case "draw-text":
|
|
1598
|
+
out.push({ pos: n.position, id: n.id });
|
|
1599
|
+
break;
|
|
1600
|
+
case "draw-sprite-layer":
|
|
1601
|
+
case "draw-shape-layer":
|
|
1602
|
+
case "draw-text-layer":
|
|
1603
|
+
for (const it of n.items) out.push({ pos: it.position, id: it.id });
|
|
1604
|
+
break;
|
|
1710
1605
|
}
|
|
1711
|
-
);
|
|
1712
|
-
}
|
|
1713
|
-
function SpriteBillboard3D({
|
|
1714
|
-
sheetUrl,
|
|
1715
|
-
resolveFrame,
|
|
1716
|
-
height = 1.2
|
|
1717
|
-
}) {
|
|
1718
|
-
const texture = fiber.useLoader(THREE6__namespace.TextureLoader, sheetUrl);
|
|
1719
|
-
const meshRef = React10.useRef(null);
|
|
1720
|
-
const matRef = React10.useRef(null);
|
|
1721
|
-
const [aspect, setAspect] = React10.useState(1);
|
|
1722
|
-
fiber.useFrame(() => {
|
|
1723
|
-
const frame = resolveFrame();
|
|
1724
|
-
if (!frame || !texture.image) return;
|
|
1725
|
-
const imgW = texture.image.width;
|
|
1726
|
-
const imgH = texture.image.height;
|
|
1727
|
-
if (!imgW || !imgH) return;
|
|
1728
|
-
texture.repeat.set((frame.flipX ? -1 : 1) * (frame.sw / imgW), frame.sh / imgH);
|
|
1729
|
-
texture.offset.set(
|
|
1730
|
-
frame.flipX ? (frame.sx + frame.sw) / imgW : frame.sx / imgW,
|
|
1731
|
-
1 - (frame.sy + frame.sh) / imgH
|
|
1732
|
-
);
|
|
1733
|
-
texture.magFilter = THREE6__namespace.NearestFilter;
|
|
1734
|
-
texture.minFilter = THREE6__namespace.NearestFilter;
|
|
1735
|
-
texture.needsUpdate = true;
|
|
1736
|
-
const nextAspect = frame.sw / frame.sh;
|
|
1737
|
-
if (Math.abs(nextAspect - aspect) > 1e-3) setAspect(nextAspect);
|
|
1738
|
-
if (matRef.current) matRef.current.needsUpdate = true;
|
|
1739
|
-
});
|
|
1740
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ref: meshRef, position: [0, height / 2, 0], children: [
|
|
1741
|
-
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [height * aspect, height] }),
|
|
1742
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1743
|
-
"meshBasicMaterial",
|
|
1744
|
-
{
|
|
1745
|
-
ref: matRef,
|
|
1746
|
-
map: texture,
|
|
1747
|
-
transparent: true,
|
|
1748
|
-
alphaTest: 0.1,
|
|
1749
|
-
side: THREE6__namespace.DoubleSide
|
|
1750
|
-
}
|
|
1751
|
-
)
|
|
1752
|
-
] });
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
// components/game/shared/spriteAnimation.ts
|
|
1756
|
-
function resolveSheetDirection(facing) {
|
|
1757
|
-
switch (facing) {
|
|
1758
|
-
case "se":
|
|
1759
|
-
return { sheetDir: "se", flipX: false };
|
|
1760
|
-
case "sw":
|
|
1761
|
-
return { sheetDir: "sw", flipX: false };
|
|
1762
|
-
case "ne":
|
|
1763
|
-
return { sheetDir: "sw", flipX: true };
|
|
1764
|
-
case "nw":
|
|
1765
|
-
return { sheetDir: "se", flipX: true };
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
function frameRect(frame, row, columns, frameWidth, frameHeight) {
|
|
1769
|
-
return {
|
|
1770
|
-
sx: frame % columns * frameWidth,
|
|
1771
|
-
sy: row * frameHeight,
|
|
1772
|
-
sw: frameWidth,
|
|
1773
|
-
sh: frameHeight
|
|
1774
|
-
};
|
|
1775
|
-
}
|
|
1776
|
-
|
|
1777
|
-
// components/game/shared/hooks/useUnitSpriteAtlas.ts
|
|
1778
|
-
function unitAtlasUrl(unit) {
|
|
1779
|
-
return unit.spriteSheet?.url ?? null;
|
|
1780
|
-
}
|
|
1781
|
-
function resolveSheetUrl(atlasUrl, relativeSheetPath) {
|
|
1782
|
-
try {
|
|
1783
|
-
return new URL(relativeSheetPath, atlasUrl).toString();
|
|
1784
|
-
} catch {
|
|
1785
|
-
const base = atlasUrl.slice(0, atlasUrl.lastIndexOf("/") + 1);
|
|
1786
|
-
return `${base}${relativeSheetPath.replace(/^\.\//, "")}`;
|
|
1787
1606
|
}
|
|
1607
|
+
return out;
|
|
1788
1608
|
}
|
|
1789
|
-
function
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
const [, forceTick] = React10.useState(0);
|
|
1794
|
-
const atlasUrls = React10.useMemo(() => {
|
|
1795
|
-
const set = /* @__PURE__ */ new Set();
|
|
1796
|
-
for (const unit of units) {
|
|
1797
|
-
const url = unitAtlasUrl(unit);
|
|
1798
|
-
if (url) set.add(url);
|
|
1799
|
-
}
|
|
1800
|
-
return [...set];
|
|
1801
|
-
}, [units]);
|
|
1802
|
-
React10.useEffect(() => {
|
|
1803
|
-
const cache = atlasCacheRef.current;
|
|
1804
|
-
const loading = loadingRef.current;
|
|
1805
|
-
const toLoad = atlasUrls.filter((url) => !cache.has(url) && !loading.has(url));
|
|
1806
|
-
if (toLoad.length === 0) return;
|
|
1807
|
-
let cancelled = false;
|
|
1808
|
-
setPendingCount((prev) => prev + toLoad.length);
|
|
1809
|
-
for (const url of toLoad) {
|
|
1810
|
-
loading.add(url);
|
|
1811
|
-
fetch(url).then((res) => res.ok ? res.json() : Promise.reject(new Error(String(res.status)))).then((atlas) => {
|
|
1812
|
-
if (cancelled) return;
|
|
1813
|
-
cache.set(url, atlas);
|
|
1814
|
-
}).catch(() => {
|
|
1815
|
-
}).finally(() => {
|
|
1816
|
-
if (cancelled) return;
|
|
1817
|
-
loading.delete(url);
|
|
1818
|
-
setPendingCount((prev) => Math.max(0, prev - 1));
|
|
1819
|
-
forceTick((n) => n + 1);
|
|
1820
|
-
});
|
|
1821
|
-
}
|
|
1822
|
-
return () => {
|
|
1823
|
-
cancelled = true;
|
|
1824
|
-
};
|
|
1825
|
-
}, [atlasUrls]);
|
|
1826
|
-
const sheetUrls = React10.useMemo(() => {
|
|
1827
|
-
const urls = /* @__PURE__ */ new Set();
|
|
1828
|
-
for (const unit of units) {
|
|
1829
|
-
const atlasUrl = unitAtlasUrl(unit);
|
|
1830
|
-
if (!atlasUrl) continue;
|
|
1831
|
-
const atlas = atlasCacheRef.current.get(atlasUrl);
|
|
1832
|
-
if (!atlas) continue;
|
|
1833
|
-
for (const rel of Object.values(atlas.sheets)) {
|
|
1834
|
-
if (rel) urls.add(resolveSheetUrl(atlasUrl, rel));
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
return [...urls];
|
|
1838
|
-
}, [units, pendingCount]);
|
|
1839
|
-
const resolveUnitFrame = React10.useCallback((unitId) => {
|
|
1840
|
-
const unit = units.find((u) => u.id === unitId);
|
|
1841
|
-
if (!unit) return null;
|
|
1842
|
-
const atlasUrl = unitAtlasUrl(unit);
|
|
1843
|
-
if (!atlasUrl) return null;
|
|
1844
|
-
const atlas = atlasCacheRef.current.get(atlasUrl);
|
|
1845
|
-
if (!atlas) return null;
|
|
1846
|
-
const animation = unit.animation ?? "idle";
|
|
1847
|
-
const frame = unit.frame ?? 0;
|
|
1848
|
-
const def = atlas.animations[animation] ?? atlas.animations.idle;
|
|
1849
|
-
if (!def) return null;
|
|
1850
|
-
const { sheetDir, flipX } = resolveSheetDirection("se");
|
|
1851
|
-
const rel = atlas.sheets[sheetDir] ?? atlas.sheets.se ?? atlas.sheets.sw;
|
|
1852
|
-
if (!rel) return null;
|
|
1853
|
-
const sheetUrl = resolveSheetUrl(atlasUrl, rel);
|
|
1854
|
-
const rect = frameRect(frame, def.row, atlas.columns, atlas.frameWidth, atlas.frameHeight);
|
|
1855
|
-
return {
|
|
1856
|
-
sheetUrl,
|
|
1857
|
-
sx: rect.sx,
|
|
1858
|
-
sy: rect.sy,
|
|
1859
|
-
sw: rect.sw,
|
|
1860
|
-
sh: rect.sh,
|
|
1861
|
-
flipX,
|
|
1862
|
-
applyBreathing: animation === "idle"
|
|
1863
|
-
};
|
|
1864
|
-
}, [units]);
|
|
1865
|
-
return { sheetUrls, resolveUnitFrame, pendingCount };
|
|
1866
|
-
}
|
|
1867
|
-
var UNIT_BASE_MODEL_SCALE = 0.5;
|
|
1868
|
-
var UNIT_BASE_BILLBOARD_HEIGHT = 1.2;
|
|
1869
|
-
var UNIT_BASE_PRIMITIVE_RADIUS = 0.3;
|
|
1870
|
-
var HEALTHBAR_HEIGHT = 0.05;
|
|
1871
|
-
function UnitMesh3D({
|
|
1872
|
-
unit,
|
|
1873
|
-
position,
|
|
1874
|
-
model,
|
|
1875
|
-
isSelected,
|
|
1876
|
-
unitScale,
|
|
1877
|
-
cellSize,
|
|
1878
|
-
resolveUnitFrame,
|
|
1879
|
-
onUnitClick
|
|
1880
|
-
}) {
|
|
1881
|
-
const color = unit.tint ?? FACTION_COLORS_3D[unit.faction ?? ""] ?? FACTION_COLORS_3D.default;
|
|
1882
|
-
const hasAtlas = unitAtlasUrl(unit) !== null;
|
|
1883
|
-
const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
|
|
1884
|
-
const modelScale = UNIT_BASE_MODEL_SCALE * unitScale * cellSize;
|
|
1885
|
-
const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale * cellSize;
|
|
1886
|
-
const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale * cellSize;
|
|
1887
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1888
|
-
"group",
|
|
1889
|
-
{
|
|
1890
|
-
position,
|
|
1891
|
-
onClick: (e) => onUnitClick(unit, e),
|
|
1892
|
-
userData: { type: "unit", unitId: unit.id },
|
|
1893
|
-
children: [
|
|
1894
|
-
isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
1895
|
-
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
|
|
1896
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: SELECTION_RING_COLOR_3D, transparent: true, opacity: 0.8 })
|
|
1897
|
-
] }),
|
|
1898
|
-
hasAtlas && initialFrame ? (
|
|
1899
|
-
/* Animated sprite-sheet billboard — single cropped frame, by state */
|
|
1900
|
-
/* @__PURE__ */ jsxRuntime.jsx(drei.Billboard, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1901
|
-
SpriteBillboard3D,
|
|
1902
|
-
{
|
|
1903
|
-
sheetUrl: initialFrame.sheetUrl,
|
|
1904
|
-
resolveFrame: () => resolveUnitFrame(unit.id),
|
|
1905
|
-
height: billboardHeight
|
|
1906
|
-
}
|
|
1907
|
-
) })
|
|
1908
|
-
) : model?.url ? (
|
|
1909
|
-
/* GLB unit model — LOLO's `animation` field drives the named clip;
|
|
1910
|
-
`heading` (radians) faces the model along its travel direction (driving). */
|
|
1911
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1912
|
-
ModelLoader,
|
|
1913
|
-
{
|
|
1914
|
-
url: model.url,
|
|
1915
|
-
scale: modelScale,
|
|
1916
|
-
rotation: [0, unit.heading ?? 0, 0],
|
|
1917
|
-
animation: unit.animation ?? "idle",
|
|
1918
|
-
fallbackGeometry: "box",
|
|
1919
|
-
castShadow: true
|
|
1920
|
-
}
|
|
1921
|
-
)
|
|
1922
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1923
|
-
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius, 0], children: [
|
|
1924
|
-
/* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [primitiveRadius, primitiveRadius, primitiveRadius * 0.33, 8] }),
|
|
1925
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
1926
|
-
] }),
|
|
1927
|
-
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius * 2, 0], children: [
|
|
1928
|
-
/* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [primitiveRadius * 0.67, primitiveRadius * 1.33, 4, 8] }),
|
|
1929
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
1930
|
-
] }),
|
|
1931
|
-
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius * 3, 0], children: [
|
|
1932
|
-
/* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [primitiveRadius * 0.4, 8, 8] }),
|
|
1933
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
1934
|
-
] })
|
|
1935
|
-
] }),
|
|
1936
|
-
unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, billboardHeight, 0], children: [
|
|
1937
|
-
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.5 / 2, 0, 0], children: [
|
|
1938
|
-
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [HEALTHBAR_3D.width, HEALTHBAR_HEIGHT] }),
|
|
1939
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: HEALTHBAR_3D.bg })
|
|
1940
|
-
] }),
|
|
1941
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1942
|
-
"mesh",
|
|
1943
|
-
{
|
|
1944
|
-
position: [
|
|
1945
|
-
-0.5 / 2 + HEALTHBAR_3D.width * (unit.health / unit.maxHealth) / 2,
|
|
1946
|
-
0,
|
|
1947
|
-
0.01
|
|
1948
|
-
],
|
|
1949
|
-
children: [
|
|
1950
|
-
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [HEALTHBAR_3D.width * (unit.health / unit.maxHealth), HEALTHBAR_HEIGHT] }),
|
|
1951
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: healthbarFill3D(unit.health / unit.maxHealth) })
|
|
1952
|
-
]
|
|
1953
|
-
}
|
|
1954
|
-
)
|
|
1955
|
-
] })
|
|
1956
|
-
]
|
|
1957
|
-
}
|
|
1958
|
-
);
|
|
1959
|
-
}
|
|
1960
|
-
function FeatureMesh3D({
|
|
1961
|
-
feature,
|
|
1962
|
-
position,
|
|
1963
|
-
model,
|
|
1964
|
-
onFeatureClick
|
|
1965
|
-
}) {
|
|
1966
|
-
if (model?.url) {
|
|
1967
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1968
|
-
ModelLoader,
|
|
1969
|
-
{
|
|
1970
|
-
url: model.url,
|
|
1971
|
-
position,
|
|
1972
|
-
scale: 0.5,
|
|
1973
|
-
rotation: [0, feature.rotation ?? 0, 0],
|
|
1974
|
-
tint: feature.color,
|
|
1975
|
-
onClick: () => onFeatureClick(feature, null),
|
|
1976
|
-
fallbackGeometry: "box"
|
|
1977
|
-
}
|
|
1978
|
-
);
|
|
1979
|
-
}
|
|
1980
|
-
if (feature.type === "tree") {
|
|
1981
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1982
|
-
"group",
|
|
1983
|
-
{
|
|
1984
|
-
position,
|
|
1985
|
-
onClick: (e) => onFeatureClick(feature, e),
|
|
1986
|
-
userData: { type: "feature", featureId: feature.id },
|
|
1987
|
-
children: [
|
|
1988
|
-
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.4, 0], children: [
|
|
1989
|
-
/* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
|
|
1990
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: TREE_COLORS_3D.trunk })
|
|
1991
|
-
] }),
|
|
1992
|
-
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
1993
|
-
/* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
|
|
1994
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: TREE_COLORS_3D.foliage })
|
|
1995
|
-
] })
|
|
1996
|
-
]
|
|
1997
|
-
}
|
|
1998
|
-
);
|
|
1999
|
-
}
|
|
2000
|
-
if (feature.type === "rock") {
|
|
2001
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2002
|
-
"mesh",
|
|
2003
|
-
{
|
|
2004
|
-
position: [position[0], position[1] + 0.3, position[2]],
|
|
2005
|
-
onClick: (e) => onFeatureClick(feature, e),
|
|
2006
|
-
userData: { type: "feature", featureId: feature.id },
|
|
2007
|
-
children: [
|
|
2008
|
-
/* @__PURE__ */ jsxRuntime.jsx("dodecahedronGeometry", { args: [0.3, 0] }),
|
|
2009
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: ROCK_COLOR_3D })
|
|
2010
|
-
]
|
|
2011
|
-
}
|
|
2012
|
-
);
|
|
1609
|
+
function buildHitIndex(items) {
|
|
1610
|
+
const m = /* @__PURE__ */ new Map();
|
|
1611
|
+
for (const it of items) {
|
|
1612
|
+
if (it.id !== void 0) m.set(`${it.pos.x},${it.pos.y}`, it.id);
|
|
2013
1613
|
}
|
|
2014
|
-
return
|
|
1614
|
+
return m;
|
|
2015
1615
|
}
|
|
2016
1616
|
function CameraController3D({
|
|
2017
1617
|
onCameraChange
|
|
2018
1618
|
}) {
|
|
2019
1619
|
const { camera } = fiber.useThree();
|
|
2020
|
-
|
|
1620
|
+
React7.useEffect(() => {
|
|
2021
1621
|
if (onCameraChange) {
|
|
2022
1622
|
onCameraChange({
|
|
2023
1623
|
x: camera.position.x,
|
|
@@ -2033,8 +1633,8 @@ function FollowCamera3D({
|
|
|
2033
1633
|
offset
|
|
2034
1634
|
}) {
|
|
2035
1635
|
const { camera } = fiber.useThree();
|
|
2036
|
-
const look =
|
|
2037
|
-
const goal =
|
|
1636
|
+
const look = React7.useRef(new THREE6__namespace.Vector3(target[0], target[1], target[2]));
|
|
1637
|
+
const goal = React7.useRef(new THREE6__namespace.Vector3());
|
|
2038
1638
|
fiber.useFrame((_, delta) => {
|
|
2039
1639
|
const t = Math.min(1, delta * 5);
|
|
2040
1640
|
goal.current.set(target[0] + offset[0], target[1] + offset[1], target[2] + offset[2]);
|
|
@@ -2044,109 +1644,136 @@ function FollowCamera3D({
|
|
|
2044
1644
|
});
|
|
2045
1645
|
return null;
|
|
2046
1646
|
}
|
|
2047
|
-
function
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1647
|
+
function SpriteBillboard({ node, world }) {
|
|
1648
|
+
const texture = fiber.useLoader(THREE6__namespace.TextureLoader, node.asset.url);
|
|
1649
|
+
const img = texture.image;
|
|
1650
|
+
const imgW = img?.width || 1;
|
|
1651
|
+
const imgH = img?.height || 1;
|
|
1652
|
+
if (node.frame) {
|
|
1653
|
+
texture.repeat.set(node.frame.w / imgW, node.frame.h / imgH);
|
|
1654
|
+
texture.offset.set(node.frame.x / imgW, 1 - (node.frame.y + node.frame.h) / imgH);
|
|
1655
|
+
texture.magFilter = texture.minFilter = THREE6__namespace.NearestFilter;
|
|
1656
|
+
texture.needsUpdate = true;
|
|
1657
|
+
}
|
|
1658
|
+
const aspect = node.frame ? node.frame.w / node.frame.h : imgW / imgH;
|
|
1659
|
+
const height = node.height ?? 1;
|
|
1660
|
+
const width = node.width ?? height * aspect;
|
|
1661
|
+
return /* @__PURE__ */ jsxRuntime.jsx(drei.Billboard, { position: [world[0], world[1] + height / 2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { children: [
|
|
1662
|
+
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [width, height] }),
|
|
1663
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1664
|
+
"meshBasicMaterial",
|
|
1665
|
+
{
|
|
1666
|
+
map: texture,
|
|
1667
|
+
transparent: true,
|
|
1668
|
+
alphaTest: 0.1,
|
|
1669
|
+
side: THREE6__namespace.DoubleSide,
|
|
1670
|
+
opacity: node.opacity ?? 1
|
|
1671
|
+
}
|
|
1672
|
+
)
|
|
1673
|
+
] }) });
|
|
1674
|
+
}
|
|
1675
|
+
function Sprite3D({ node, projector }) {
|
|
1676
|
+
if (node.asset.dimension === "3d" && node.asset.url) {
|
|
1677
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: projector.toWorld(node.position), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1678
|
+
ModelLoader,
|
|
1679
|
+
{
|
|
1680
|
+
url: node.asset.url,
|
|
1681
|
+
scale: node.width ?? projector.cellSize,
|
|
1682
|
+
rotation: [0, node.rotation ?? 0, 0],
|
|
1683
|
+
fallbackGeometry: "box",
|
|
1684
|
+
castShadow: true,
|
|
1685
|
+
receiveShadow: true
|
|
1686
|
+
}
|
|
1687
|
+
) });
|
|
1688
|
+
}
|
|
1689
|
+
if (!node.asset.url) return null;
|
|
1690
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SpriteBillboard, { node, world: projector.toWorld(node.position) });
|
|
1691
|
+
}
|
|
1692
|
+
function Shape3D({ node, projector }) {
|
|
1693
|
+
const world = projector.toWorld(node.position);
|
|
1694
|
+
const color = node.fill ?? node.stroke ?? "#ffffff";
|
|
1695
|
+
let geometry;
|
|
1696
|
+
switch (node.shape) {
|
|
1697
|
+
case "cell":
|
|
1698
|
+
case "rect": {
|
|
1699
|
+
const w = node.shape === "cell" ? projector.cellSize * 0.95 : node.width ?? projector.cellSize;
|
|
1700
|
+
const h = node.shape === "cell" ? projector.cellSize * 0.95 : node.height ?? projector.cellSize;
|
|
1701
|
+
geometry = /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [w, h] });
|
|
1702
|
+
break;
|
|
1703
|
+
}
|
|
1704
|
+
case "ellipse": {
|
|
1705
|
+
const radiusX = node.radiusX ?? 0.4;
|
|
1706
|
+
geometry = node.stroke && !node.fill ? /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [Math.max(0, radiusX - 0.08), radiusX, 32] }) : /* @__PURE__ */ jsxRuntime.jsx("circleGeometry", { args: [radiusX, 32] });
|
|
1707
|
+
break;
|
|
1708
|
+
}
|
|
1709
|
+
case "poly": {
|
|
1710
|
+
if (!node.points || node.points.length === 0) return null;
|
|
1711
|
+
const s = new THREE6__namespace.Shape();
|
|
1712
|
+
node.points.forEach((p, i) => {
|
|
1713
|
+
if (i === 0) s.moveTo(p.x, p.y);
|
|
1714
|
+
else s.lineTo(p.x, p.y);
|
|
1715
|
+
});
|
|
1716
|
+
s.closePath();
|
|
1717
|
+
geometry = /* @__PURE__ */ jsxRuntime.jsx("shapeGeometry", { args: [s] });
|
|
1718
|
+
break;
|
|
1719
|
+
}
|
|
1720
|
+
default:
|
|
1721
|
+
return null;
|
|
1722
|
+
}
|
|
1723
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], position: [world[0], world[1] + 0.02, world[2]], children: [
|
|
1724
|
+
geometry,
|
|
1725
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color, transparent: true, opacity: node.opacity ?? 1, side: THREE6__namespace.DoubleSide })
|
|
1726
|
+
] });
|
|
2062
1727
|
}
|
|
2063
|
-
function
|
|
2064
|
-
|
|
1728
|
+
function Text3D({ node, projector }) {
|
|
1729
|
+
const world = projector.toWorld(node.position);
|
|
1730
|
+
return /* @__PURE__ */ jsxRuntime.jsx(drei.Billboard, { position: [world[0], world[1] + 1.2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2065
1731
|
drei.Text,
|
|
2066
1732
|
{
|
|
2067
1733
|
fontSize: 0.32,
|
|
2068
|
-
color:
|
|
2069
|
-
outlineWidth: 0.02,
|
|
2070
|
-
outlineColor: "#000000",
|
|
1734
|
+
color: node.color,
|
|
2071
1735
|
anchorX: "center",
|
|
2072
1736
|
anchorY: "middle",
|
|
2073
|
-
|
|
1737
|
+
outlineWidth: 0.02,
|
|
1738
|
+
outlineColor: "#000000",
|
|
1739
|
+
children: node.text
|
|
2074
1740
|
}
|
|
2075
1741
|
) });
|
|
2076
1742
|
}
|
|
2077
|
-
function
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
})
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
const
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
const cells = Math.max(1, Math.round(p.width / ppu));
|
|
2104
|
-
const x0 = p.x / ppu;
|
|
2105
|
-
return /* @__PURE__ */ jsxRuntime.jsx("group", { children: Array.from({ length: cells }, (_, c) => /* @__PURE__ */ jsxRuntime.jsx("group", { position: [x0 + c + 0.5, topY - 0.475, 0], children: /* @__PURE__ */ jsxRuntime.jsx(ModelLoader, { url: model, scale: 0.95, fallbackGeometry: "box", castShadow: true, receiveShadow: true }) }, c)) }, `plat-${i}`);
|
|
2106
|
-
}
|
|
2107
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2108
|
-
"mesh",
|
|
2109
|
-
{
|
|
2110
|
-
position: [(p.x + p.width / 2) / ppu, topY - p.height / 2 / ppu, 0],
|
|
2111
|
-
children: [
|
|
2112
|
-
/* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [p.width / ppu, p.height / ppu, 1] }),
|
|
2113
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: SIDE_PLATFORM_COLORS_3D[platformType] ?? SIDE_PLATFORM_COLORS_3D.default })
|
|
2114
|
-
]
|
|
2115
|
-
},
|
|
2116
|
-
`plat-${i}`
|
|
2117
|
-
);
|
|
2118
|
-
}),
|
|
2119
|
-
features.map((feature, i) => {
|
|
2120
|
-
const model = feature.assetUrl ?? assetManifest?.features?.[feature.type];
|
|
2121
|
-
const fx = feature.x / ppu;
|
|
2122
|
-
const fy = (worldHeight - feature.y) / ppu;
|
|
2123
|
-
if (!model?.url) return null;
|
|
2124
|
-
return /* @__PURE__ */ jsxRuntime.jsx("group", { position: [fx, fy, 0], children: /* @__PURE__ */ jsxRuntime.jsx(ModelLoader, { url: model.url, scale: 0.6, tint: feature.color, fallbackGeometry: "sphere", castShadow: true }) }, feature.id ?? `sfeat-${i}`);
|
|
2125
|
-
}),
|
|
2126
|
-
events.map((ev, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2127
|
-
EventMarker3D,
|
|
2128
|
-
{
|
|
2129
|
-
event: ev,
|
|
2130
|
-
position: [ev.x / ppu, (worldHeight - (ev.y ?? 0)) / ppu + 0.8, 0.2]
|
|
2131
|
-
},
|
|
2132
|
-
ev.id ?? `sev-${i}`
|
|
2133
|
-
)),
|
|
2134
|
-
/* @__PURE__ */ jsxRuntime.jsx(LerpedGroup3D, { target: playerPos, enabled: interpolate, children: playerSprite?.url ? /* @__PURE__ */ jsxRuntime.jsx("group", { position: [0, playerH / 2, 0], children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2135
|
-
ModelLoader,
|
|
2136
|
-
{
|
|
2137
|
-
url: playerSprite.url,
|
|
2138
|
-
scale: playerH,
|
|
2139
|
-
rotation: [0, player.facingRight ? 90 : -90, 0],
|
|
2140
|
-
animation: player.animation ?? "idle",
|
|
2141
|
-
fallbackGeometry: "box",
|
|
2142
|
-
castShadow: true
|
|
2143
|
-
}
|
|
2144
|
-
) }) : /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, playerH / 2, 0], children: [
|
|
2145
|
-
/* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [playerH * 0.25, playerH * 0.5, 4, 8] }),
|
|
2146
|
-
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: SIDE_PLAYER_COLOR_3D })
|
|
2147
|
-
] }) })
|
|
2148
|
-
] });
|
|
1743
|
+
function Drawable3D({ node, projector }) {
|
|
1744
|
+
switch (node.type) {
|
|
1745
|
+
case "draw-sprite":
|
|
1746
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Sprite3D, { node, projector });
|
|
1747
|
+
case "draw-shape":
|
|
1748
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Shape3D, { node, projector });
|
|
1749
|
+
case "draw-text":
|
|
1750
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node, projector });
|
|
1751
|
+
case "draw-sprite-layer":
|
|
1752
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Sprite3D, { node: item, projector }, i)) });
|
|
1753
|
+
case "draw-shape-layer":
|
|
1754
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Shape3D, { node: item, projector }, i)) });
|
|
1755
|
+
case "draw-text-layer":
|
|
1756
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node: item, projector }, i)) });
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// lib/drawable/projector3d.ts
|
|
1761
|
+
function create3DProjector(opts = {}) {
|
|
1762
|
+
const cellSize = opts.cellSize ?? 1;
|
|
1763
|
+
const offsetX = opts.offsetX ?? 0;
|
|
1764
|
+
const offsetZ = opts.offsetZ ?? 0;
|
|
1765
|
+
return {
|
|
1766
|
+
cellSize,
|
|
1767
|
+
toWorld: (pos) => [pos.x * cellSize + offsetX, pos.z ?? 0, pos.y * cellSize + offsetZ]
|
|
1768
|
+
};
|
|
2149
1769
|
}
|
|
1770
|
+
|
|
1771
|
+
// components/game/three/game3dTheme.ts
|
|
1772
|
+
var GRID_COLORS_3D = {
|
|
1773
|
+
cell: "#444444",
|
|
1774
|
+
section: "#666666"
|
|
1775
|
+
};
|
|
1776
|
+
var DEFAULT_BACKGROUND_3D = "#1a1a2e";
|
|
2150
1777
|
function cn(...inputs) {
|
|
2151
1778
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
2152
1779
|
}
|
|
@@ -2155,35 +1782,18 @@ var DEFAULT_GRID_CONFIG = {
|
|
|
2155
1782
|
offsetX: 0,
|
|
2156
1783
|
offsetZ: 0
|
|
2157
1784
|
};
|
|
2158
|
-
var
|
|
2159
|
-
var GameCanvas3D = React10.forwardRef(
|
|
1785
|
+
var GameCanvas3D = React7.forwardRef(
|
|
2160
1786
|
({
|
|
2161
|
-
tiles = [],
|
|
2162
|
-
units = [],
|
|
2163
|
-
features = [],
|
|
2164
|
-
events = [],
|
|
2165
|
-
orientation = "standard",
|
|
2166
1787
|
cameraMode = "isometric",
|
|
1788
|
+
followTarget,
|
|
2167
1789
|
showGrid = true,
|
|
2168
|
-
|
|
2169
|
-
showTileInfo = false,
|
|
1790
|
+
orientation = "standard",
|
|
2170
1791
|
overlay = "default",
|
|
2171
1792
|
shadows = true,
|
|
2172
1793
|
backgroundColor = DEFAULT_BACKGROUND_3D,
|
|
2173
|
-
onTileClick,
|
|
2174
|
-
onUnitClick,
|
|
2175
|
-
onFeatureClick,
|
|
2176
|
-
onCanvasClick,
|
|
2177
|
-
onTileHover,
|
|
2178
|
-
onUnitAnimation,
|
|
2179
|
-
assetLoader: customAssetLoader,
|
|
2180
|
-
tileRenderer: CustomTileRenderer,
|
|
2181
|
-
unitRenderer: CustomUnitRenderer,
|
|
2182
|
-
featureRenderer: CustomFeatureRenderer,
|
|
2183
1794
|
className,
|
|
2184
1795
|
isLoading: externalLoading,
|
|
2185
1796
|
error: externalError,
|
|
2186
|
-
preloadAssets = [],
|
|
2187
1797
|
tileClickEvent,
|
|
2188
1798
|
unitClickEvent,
|
|
2189
1799
|
featureClickEvent,
|
|
@@ -2193,31 +1803,17 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2193
1803
|
unitAnimationEvent,
|
|
2194
1804
|
cameraChangeEvent,
|
|
2195
1805
|
loadingMessage = "Loading 3D Scene...",
|
|
2196
|
-
useInstancing = true,
|
|
2197
|
-
validMoves = [],
|
|
2198
|
-
attackTargets = [],
|
|
2199
|
-
selectedTileIds = [],
|
|
2200
|
-
selectedUnitId = null,
|
|
2201
|
-
unitScale = 1,
|
|
2202
1806
|
keyMap,
|
|
2203
1807
|
keyUpMap,
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
worldHeight = 400,
|
|
2207
|
-
pixelsPerUnit = 32,
|
|
2208
|
-
playerSprite,
|
|
2209
|
-
tileSprites,
|
|
2210
|
-
assetManifest,
|
|
2211
|
-
interpolateUnits = false,
|
|
2212
|
-
children
|
|
1808
|
+
children,
|
|
1809
|
+
drawables
|
|
2213
1810
|
}, ref) => {
|
|
2214
|
-
const containerRef =
|
|
2215
|
-
const controlsRef =
|
|
2216
|
-
const [
|
|
2217
|
-
const [internalError, setInternalError] = React10.useState(null);
|
|
1811
|
+
const containerRef = React7.useRef(null);
|
|
1812
|
+
const controlsRef = React7.useRef(null);
|
|
1813
|
+
const [internalError, setInternalError] = React7.useState(null);
|
|
2218
1814
|
const eventBus = useEventBus();
|
|
2219
|
-
const keysRef =
|
|
2220
|
-
|
|
1815
|
+
const keysRef = React7.useRef(/* @__PURE__ */ new Set());
|
|
1816
|
+
React7.useEffect(() => {
|
|
2221
1817
|
if (!keyMap && !keyUpMap) return;
|
|
2222
1818
|
const down = (e) => {
|
|
2223
1819
|
if (keysRef.current.has(e.code)) return;
|
|
@@ -2240,35 +1836,6 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2240
1836
|
window.removeEventListener("keyup", up);
|
|
2241
1837
|
};
|
|
2242
1838
|
}, [keyMap, keyUpMap, eventBus]);
|
|
2243
|
-
React10.useEffect(() => {
|
|
2244
|
-
const el = containerRef.current;
|
|
2245
|
-
if (!el) return;
|
|
2246
|
-
let node = el;
|
|
2247
|
-
let depth = 0;
|
|
2248
|
-
while (node && depth < 8) {
|
|
2249
|
-
const cs = window.getComputedStyle(node);
|
|
2250
|
-
const rect = node.getBoundingClientRect();
|
|
2251
|
-
console.log("[almadar:ui:game:3d-height]", {
|
|
2252
|
-
depth,
|
|
2253
|
-
tag: node.tagName,
|
|
2254
|
-
id: node.id || void 0,
|
|
2255
|
-
className: node.className?.slice?.(0, 60) || void 0,
|
|
2256
|
-
rectHeight: rect.height,
|
|
2257
|
-
computedHeight: cs.height,
|
|
2258
|
-
computedMinHeight: cs.minHeight,
|
|
2259
|
-
computedFlex: cs.flex,
|
|
2260
|
-
computedOverflow: cs.overflow
|
|
2261
|
-
});
|
|
2262
|
-
node = node.parentElement;
|
|
2263
|
-
depth++;
|
|
2264
|
-
}
|
|
2265
|
-
}, []);
|
|
2266
|
-
const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
|
|
2267
|
-
const preloadUrls = React10.useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
|
|
2268
|
-
const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
|
|
2269
|
-
preloadUrls,
|
|
2270
|
-
loader: customAssetLoader
|
|
2271
|
-
});
|
|
2272
1839
|
const eventHandlers = useGameCanvas3DEvents({
|
|
2273
1840
|
tileClickEvent,
|
|
2274
1841
|
unitClickEvent,
|
|
@@ -2277,35 +1844,36 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2277
1844
|
tileHoverEvent,
|
|
2278
1845
|
tileLeaveEvent,
|
|
2279
1846
|
unitAnimationEvent,
|
|
2280
|
-
cameraChangeEvent
|
|
2281
|
-
onTileClick,
|
|
2282
|
-
onUnitClick,
|
|
2283
|
-
onFeatureClick,
|
|
2284
|
-
onCanvasClick,
|
|
2285
|
-
onTileHover,
|
|
2286
|
-
onUnitAnimation
|
|
1847
|
+
cameraChangeEvent
|
|
2287
1848
|
});
|
|
2288
|
-
const
|
|
2289
|
-
|
|
1849
|
+
const drawnItems = React7.useMemo(() => collectDrawnItems(drawables ?? []), [drawables]);
|
|
1850
|
+
const scenePositions = React7.useMemo(() => drawnItems.map((i) => i.pos), [drawnItems]);
|
|
1851
|
+
const hitIndex = React7.useMemo(() => buildHitIndex(drawnItems), [drawnItems]);
|
|
1852
|
+
const gridBounds = React7.useMemo(() => {
|
|
1853
|
+
if (scenePositions.length === 0) {
|
|
2290
1854
|
return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
|
|
2291
1855
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
return
|
|
1856
|
+
let minX = Infinity;
|
|
1857
|
+
let maxX = -Infinity;
|
|
1858
|
+
let minZ = Infinity;
|
|
1859
|
+
let maxZ = -Infinity;
|
|
1860
|
+
for (const p of scenePositions) {
|
|
1861
|
+
if (p.x < minX) minX = p.x;
|
|
1862
|
+
if (p.x > maxX) maxX = p.x;
|
|
1863
|
+
if (p.y < minZ) minZ = p.y;
|
|
1864
|
+
if (p.y > maxZ) maxZ = p.y;
|
|
1865
|
+
}
|
|
1866
|
+
return { minX, maxX, minZ, maxZ };
|
|
1867
|
+
}, [scenePositions]);
|
|
1868
|
+
const cameraTarget = React7.useMemo(
|
|
1869
|
+
() => [
|
|
2303
1870
|
(gridBounds.minX + gridBounds.maxX) / 2,
|
|
2304
1871
|
0,
|
|
2305
1872
|
(gridBounds.minZ + gridBounds.maxZ) / 2
|
|
2306
|
-
]
|
|
2307
|
-
|
|
2308
|
-
|
|
1873
|
+
],
|
|
1874
|
+
[gridBounds]
|
|
1875
|
+
);
|
|
1876
|
+
const gridConfig = React7.useMemo(
|
|
2309
1877
|
() => ({
|
|
2310
1878
|
...DEFAULT_GRID_CONFIG,
|
|
2311
1879
|
offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
|
|
@@ -2313,15 +1881,15 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2313
1881
|
}),
|
|
2314
1882
|
[gridBounds]
|
|
2315
1883
|
);
|
|
2316
|
-
const
|
|
2317
|
-
(
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
},
|
|
1884
|
+
const drawableProjector = React7.useMemo(
|
|
1885
|
+
() => create3DProjector({
|
|
1886
|
+
cellSize: gridConfig.cellSize,
|
|
1887
|
+
offsetX: -gridBounds.minX * gridConfig.cellSize,
|
|
1888
|
+
offsetZ: -gridBounds.minZ * gridConfig.cellSize
|
|
1889
|
+
}),
|
|
2322
1890
|
[gridBounds, gridConfig]
|
|
2323
1891
|
);
|
|
2324
|
-
|
|
1892
|
+
React7.useImperativeHandle(ref, () => ({
|
|
2325
1893
|
getCameraPosition: () => {
|
|
2326
1894
|
if (controlsRef.current) {
|
|
2327
1895
|
const pos = controlsRef.current.object.position;
|
|
@@ -2352,43 +1920,9 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2352
1920
|
return canvas.toDataURL("image/png");
|
|
2353
1921
|
}
|
|
2354
1922
|
return null;
|
|
2355
|
-
}
|
|
2356
|
-
export: () => ({
|
|
2357
|
-
tiles,
|
|
2358
|
-
units,
|
|
2359
|
-
features
|
|
2360
|
-
})
|
|
1923
|
+
}
|
|
2361
1924
|
}));
|
|
2362
|
-
const
|
|
2363
|
-
(tile, event) => {
|
|
2364
|
-
eventHandlers.handleTileClick(tile, event);
|
|
2365
|
-
},
|
|
2366
|
-
[eventHandlers]
|
|
2367
|
-
);
|
|
2368
|
-
const handleUnitClick = React10.useCallback(
|
|
2369
|
-
(unit, event) => {
|
|
2370
|
-
eventHandlers.handleUnitClick(unit, event);
|
|
2371
|
-
},
|
|
2372
|
-
[eventHandlers]
|
|
2373
|
-
);
|
|
2374
|
-
const handleFeatureClick = React10.useCallback(
|
|
2375
|
-
(feature, event) => {
|
|
2376
|
-
if (event) {
|
|
2377
|
-
eventHandlers.handleFeatureClick(feature, event);
|
|
2378
|
-
}
|
|
2379
|
-
},
|
|
2380
|
-
[eventHandlers]
|
|
2381
|
-
);
|
|
2382
|
-
const handleTileHover = React10.useCallback(
|
|
2383
|
-
(tile, event) => {
|
|
2384
|
-
setHoveredTile(tile);
|
|
2385
|
-
if (event) {
|
|
2386
|
-
eventHandlers.handleTileHover(tile, event);
|
|
2387
|
-
}
|
|
2388
|
-
},
|
|
2389
|
-
[eventHandlers]
|
|
2390
|
-
);
|
|
2391
|
-
const cameraConfig = React10.useMemo(() => {
|
|
1925
|
+
const cameraConfig = React7.useMemo(() => {
|
|
2392
1926
|
const size = Math.max(
|
|
2393
1927
|
gridBounds.maxX - gridBounds.minX,
|
|
2394
1928
|
gridBounds.maxZ - gridBounds.minZ,
|
|
@@ -2400,65 +1934,45 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2400
1934
|
const d = size * 1;
|
|
2401
1935
|
switch (cameraMode) {
|
|
2402
1936
|
case "isometric":
|
|
2403
|
-
return {
|
|
2404
|
-
position: [cx + d, d * 0.8, cz + d],
|
|
2405
|
-
fov: 45
|
|
2406
|
-
};
|
|
1937
|
+
return { position: [cx + d, d * 0.8, cz + d], fov: 45 };
|
|
2407
1938
|
case "top-down":
|
|
2408
|
-
return {
|
|
2409
|
-
position: [cx, d * 2, cz + d * 0.35],
|
|
2410
|
-
fov: 45
|
|
2411
|
-
};
|
|
1939
|
+
return { position: [cx, d * 2, cz + d * 0.35], fov: 45 };
|
|
2412
1940
|
case "follow":
|
|
2413
|
-
return {
|
|
2414
|
-
position: [cx, d * 0.5, cz + d],
|
|
2415
|
-
fov: 45
|
|
2416
|
-
};
|
|
1941
|
+
return { position: [cx, d * 0.5, cz + d], fov: 45 };
|
|
2417
1942
|
case "perspective":
|
|
2418
1943
|
default:
|
|
2419
|
-
return {
|
|
2420
|
-
position: [cx + d, d, cz + d],
|
|
2421
|
-
fov: 45
|
|
2422
|
-
};
|
|
1944
|
+
return { position: [cx + d, d, cz + d], fov: 45 };
|
|
2423
1945
|
}
|
|
2424
1946
|
}, [cameraMode, gridBounds]);
|
|
2425
|
-
const
|
|
2426
|
-
if (
|
|
2427
|
-
return [
|
|
2428
|
-
(player.x + (player.width ?? 32) / 2) / pixelsPerUnit,
|
|
2429
|
-
(worldHeight - player.y - (player.height ?? 48) / 2) / pixelsPerUnit,
|
|
2430
|
-
0
|
|
2431
|
-
];
|
|
2432
|
-
}
|
|
2433
|
-
const selected = units.find((u) => u.id === selectedUnitId);
|
|
2434
|
-
if (selected) {
|
|
2435
|
-
const sx = selected.x ?? selected.position?.x ?? 0;
|
|
2436
|
-
const sz = selected.z ?? selected.y ?? selected.position?.y ?? 0;
|
|
2437
|
-
return [
|
|
2438
|
-
(sx - gridBounds.minX) * gridConfig.cellSize,
|
|
2439
|
-
0,
|
|
2440
|
-
(sz - gridBounds.minZ) * gridConfig.cellSize
|
|
2441
|
-
];
|
|
2442
|
-
}
|
|
1947
|
+
const followWorld = React7.useMemo(() => {
|
|
1948
|
+
if (followTarget) return drawableProjector.toWorld(followTarget);
|
|
2443
1949
|
return cameraTarget;
|
|
2444
|
-
}, [
|
|
2445
|
-
const followOffset =
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
1950
|
+
}, [followTarget, drawableProjector, cameraTarget]);
|
|
1951
|
+
const followOffset = React7.useMemo(
|
|
1952
|
+
() => cameraMode === "chase" ? [0, 4, -7] : [5, 7, 5],
|
|
1953
|
+
[cameraMode]
|
|
1954
|
+
);
|
|
1955
|
+
const handleGroundClick = React7.useCallback((e) => {
|
|
1956
|
+
if (!tileClickEvent && !unitClickEvent) return;
|
|
1957
|
+
e.stopPropagation();
|
|
1958
|
+
const cell = {
|
|
1959
|
+
x: Math.round(e.point.x / gridConfig.cellSize + gridBounds.minX),
|
|
1960
|
+
y: Math.round(e.point.z / gridConfig.cellSize + gridBounds.minZ)
|
|
1961
|
+
};
|
|
1962
|
+
const hitId = hitIndex.get(`${cell.x},${cell.y}`);
|
|
1963
|
+
if (hitId !== void 0 && unitClickEvent) {
|
|
1964
|
+
eventBus.emit(`UI:${unitClickEvent}`, { unitId: hitId, x: cell.x, z: cell.y });
|
|
1965
|
+
} else if (tileClickEvent) {
|
|
1966
|
+
eventBus.emit(`UI:${tileClickEvent}`, { x: cell.x, z: cell.y });
|
|
2452
1967
|
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
if (externalLoading || assetsLoading && preloadAssets.length > 0) {
|
|
1968
|
+
}, [tileClickEvent, unitClickEvent, gridConfig, gridBounds, hitIndex, eventBus]);
|
|
1969
|
+
if (externalLoading) {
|
|
2456
1970
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2457
1971
|
Canvas3DLoadingState,
|
|
2458
1972
|
{
|
|
2459
|
-
progress,
|
|
2460
|
-
loaded,
|
|
2461
|
-
total,
|
|
1973
|
+
progress: 1,
|
|
1974
|
+
loaded: 1,
|
|
1975
|
+
total: 1,
|
|
2462
1976
|
message: loadingMessage,
|
|
2463
1977
|
className
|
|
2464
1978
|
}
|
|
@@ -2476,7 +1990,7 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2476
1990
|
{
|
|
2477
1991
|
onError: (err) => setInternalError(err.message),
|
|
2478
1992
|
onReset: () => setInternalError(null),
|
|
2479
|
-
children: /* @__PURE__ */ jsxRuntime.
|
|
1993
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2480
1994
|
"div",
|
|
2481
1995
|
{
|
|
2482
1996
|
ref: containerRef,
|
|
@@ -2485,193 +1999,103 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2485
1999
|
"data-orientation": orientation,
|
|
2486
2000
|
"data-camera-mode": cameraMode,
|
|
2487
2001
|
"data-overlay": overlay,
|
|
2488
|
-
children:
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2002
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2003
|
+
fiber.Canvas,
|
|
2004
|
+
{
|
|
2005
|
+
shadows,
|
|
2006
|
+
camera: {
|
|
2007
|
+
position: cameraConfig.position,
|
|
2008
|
+
fov: cameraConfig.fov,
|
|
2009
|
+
near: 0.1,
|
|
2010
|
+
far: 1e3
|
|
2011
|
+
},
|
|
2012
|
+
style: { background: backgroundColor, position: "absolute", inset: 0 },
|
|
2013
|
+
onClick: (e) => {
|
|
2014
|
+
if (e.target === e.currentTarget) {
|
|
2015
|
+
eventHandlers.handleCanvasClick(e);
|
|
2016
|
+
}
|
|
2017
|
+
},
|
|
2018
|
+
children: [
|
|
2019
|
+
/* @__PURE__ */ jsxRuntime.jsx(CameraController3D, { onCameraChange: eventHandlers.handleCameraChange }),
|
|
2020
|
+
(cameraMode === "follow" || cameraMode === "chase") && /* @__PURE__ */ jsxRuntime.jsx(FollowCamera3D, { target: followWorld, offset: followOffset }),
|
|
2021
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2022
|
+
Lighting3D,
|
|
2023
|
+
{
|
|
2024
|
+
shadows,
|
|
2025
|
+
shadowBias: -4e-4,
|
|
2026
|
+
shadowNormalBias: 0.04,
|
|
2027
|
+
shadowCameraSize: 5,
|
|
2028
|
+
shadowCameraNear: 0.5,
|
|
2029
|
+
shadowCameraFar: 500
|
|
2503
2030
|
}
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
sectionThickness: 1.5,
|
|
2542
|
-
sectionColor: GRID_COLORS_3D.section,
|
|
2543
|
-
fadeDistance: 50,
|
|
2544
|
-
fadeStrength: 1
|
|
2545
|
-
}
|
|
2546
|
-
),
|
|
2547
|
-
player ? (
|
|
2548
|
-
/* Side-scroller mode — LOLO-owned pixel space mapped to world units */
|
|
2549
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2550
|
-
SideScene3D,
|
|
2551
|
-
{
|
|
2552
|
-
player,
|
|
2553
|
-
platforms,
|
|
2554
|
-
worldHeight,
|
|
2555
|
-
ppu: pixelsPerUnit,
|
|
2556
|
-
playerSprite,
|
|
2557
|
-
tileSprites,
|
|
2558
|
-
interpolate: interpolateUnits,
|
|
2559
|
-
features,
|
|
2560
|
-
events,
|
|
2561
|
-
assetManifest
|
|
2562
|
-
}
|
|
2563
|
-
)
|
|
2564
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs("group", { children: [
|
|
2565
|
-
tiles.map((tile, index) => {
|
|
2566
|
-
const position = gridToWorld2(
|
|
2567
|
-
tile.x,
|
|
2568
|
-
tile.z ?? tile.y ?? 0,
|
|
2569
|
-
tile.elevation ?? 0
|
|
2570
|
-
);
|
|
2571
|
-
const key = tile.id ?? `tile-${index}`;
|
|
2572
|
-
if (CustomTileRenderer) {
|
|
2573
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CustomTileRenderer, { tile, position }, key);
|
|
2574
|
-
}
|
|
2575
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2576
|
-
TileMesh3D,
|
|
2577
|
-
{
|
|
2578
|
-
tile,
|
|
2579
|
-
position,
|
|
2580
|
-
model: tile.modelUrl ?? assetManifest?.terrains?.[tile.terrain ?? tile.type ?? ""],
|
|
2581
|
-
isSelected: tile.id ? selectedTileIds.includes(tile.id) : false,
|
|
2582
|
-
isHovered: hoveredTile?.id === tile.id,
|
|
2583
|
-
isValidMove: validMoves.some((m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)),
|
|
2584
|
-
isAttackTarget: attackTargets.some((m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)),
|
|
2585
|
-
onTileClick: handleTileClick,
|
|
2586
|
-
onTileHover: handleTileHover
|
|
2587
|
-
},
|
|
2588
|
-
key
|
|
2589
|
-
);
|
|
2590
|
-
}),
|
|
2591
|
-
features.map((feature, index) => {
|
|
2592
|
-
const position = gridToWorld2(
|
|
2593
|
-
feature.x,
|
|
2594
|
-
feature.z ?? feature.y ?? 0,
|
|
2595
|
-
(feature.elevation ?? 0) + TILE_TOP_OFFSET
|
|
2596
|
-
);
|
|
2597
|
-
const key = feature.id ?? `feature-${index}`;
|
|
2598
|
-
if (CustomFeatureRenderer) {
|
|
2599
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CustomFeatureRenderer, { feature, position }, key);
|
|
2600
|
-
}
|
|
2601
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2602
|
-
FeatureMesh3D,
|
|
2603
|
-
{
|
|
2604
|
-
feature,
|
|
2605
|
-
position,
|
|
2606
|
-
model: feature.assetUrl ?? assetManifest?.features?.[feature.type],
|
|
2607
|
-
onFeatureClick: handleFeatureClick
|
|
2608
|
-
},
|
|
2609
|
-
key
|
|
2610
|
-
);
|
|
2611
|
-
}),
|
|
2612
|
-
units.map((unit) => {
|
|
2613
|
-
const position = gridToWorld2(
|
|
2614
|
-
unit.x ?? unit.position?.x ?? 0,
|
|
2615
|
-
unit.z ?? unit.y ?? unit.position?.y ?? 0,
|
|
2616
|
-
(unit.elevation ?? 0) + TILE_TOP_OFFSET
|
|
2617
|
-
);
|
|
2618
|
-
return /* @__PURE__ */ jsxRuntime.jsx(LerpedGroup3D, { target: position, enabled: interpolateUnits, children: CustomUnitRenderer ? /* @__PURE__ */ jsxRuntime.jsx(CustomUnitRenderer, { unit, position: [0, 0, 0] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2619
|
-
UnitMesh3D,
|
|
2031
|
+
),
|
|
2032
|
+
showGrid && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2033
|
+
drei.Grid,
|
|
2034
|
+
{
|
|
2035
|
+
args: [
|
|
2036
|
+
Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
|
|
2037
|
+
Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
|
|
2038
|
+
],
|
|
2039
|
+
position: [
|
|
2040
|
+
(gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
|
|
2041
|
+
0,
|
|
2042
|
+
(gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
|
|
2043
|
+
],
|
|
2044
|
+
cellSize: 1,
|
|
2045
|
+
cellThickness: 1,
|
|
2046
|
+
cellColor: GRID_COLORS_3D.cell,
|
|
2047
|
+
sectionSize: 5,
|
|
2048
|
+
sectionThickness: 1.5,
|
|
2049
|
+
sectionColor: GRID_COLORS_3D.section,
|
|
2050
|
+
fadeDistance: 50,
|
|
2051
|
+
fadeStrength: 1
|
|
2052
|
+
}
|
|
2053
|
+
),
|
|
2054
|
+
drawables && drawables.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("group", { children: drawables.map((node, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node, projector: drawableProjector }, i)) }),
|
|
2055
|
+
(tileClickEvent || unitClickEvent) && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2056
|
+
"mesh",
|
|
2057
|
+
{
|
|
2058
|
+
rotation: [-Math.PI / 2, 0, 0],
|
|
2059
|
+
position: [
|
|
2060
|
+
(gridBounds.maxX - gridBounds.minX) / 2 * gridConfig.cellSize,
|
|
2061
|
+
0,
|
|
2062
|
+
(gridBounds.maxZ - gridBounds.minZ) / 2 * gridConfig.cellSize
|
|
2063
|
+
],
|
|
2064
|
+
onClick: handleGroundClick,
|
|
2065
|
+
children: [
|
|
2066
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2067
|
+
"planeGeometry",
|
|
2620
2068
|
{
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
unitScale,
|
|
2626
|
-
cellSize: gridConfig.cellSize,
|
|
2627
|
-
resolveUnitFrame,
|
|
2628
|
-
onUnitClick: handleUnitClick
|
|
2069
|
+
args: [
|
|
2070
|
+
(gridBounds.maxX - gridBounds.minX + 4) * gridConfig.cellSize,
|
|
2071
|
+
(gridBounds.maxZ - gridBounds.minZ + 4) * gridConfig.cellSize
|
|
2072
|
+
]
|
|
2629
2073
|
}
|
|
2630
|
-
)
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
touches: { ONE: THREE6__namespace.TOUCH.ROTATE, TWO: THREE6__namespace.TOUCH.DOLLY_PAN },
|
|
2656
|
-
minDistance: 2,
|
|
2657
|
-
maxDistance: 100,
|
|
2658
|
-
maxPolarAngle: Math.PI / 2 - 0.1
|
|
2659
|
-
}
|
|
2660
|
-
)
|
|
2661
|
-
]
|
|
2662
|
-
}
|
|
2663
|
-
),
|
|
2664
|
-
showCoordinates && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__coordinates", children: [
|
|
2665
|
-
"X: ",
|
|
2666
|
-
hoveredTile.x,
|
|
2667
|
-
", Z: ",
|
|
2668
|
-
hoveredTile.z ?? hoveredTile.y ?? 0
|
|
2669
|
-
] }),
|
|
2670
|
-
showTileInfo && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__tile-info", children: [
|
|
2671
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
|
|
2672
|
-
hoveredTile.terrain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
|
|
2673
|
-
] })
|
|
2674
|
-
]
|
|
2074
|
+
),
|
|
2075
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { transparent: true, opacity: 0, depthWrite: false })
|
|
2076
|
+
]
|
|
2077
|
+
}
|
|
2078
|
+
),
|
|
2079
|
+
children,
|
|
2080
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2081
|
+
drei.OrbitControls,
|
|
2082
|
+
{
|
|
2083
|
+
ref: controlsRef,
|
|
2084
|
+
enabled: cameraMode !== "follow" && cameraMode !== "chase",
|
|
2085
|
+
target: cameraTarget,
|
|
2086
|
+
enableDamping: true,
|
|
2087
|
+
dampingFactor: 0.05,
|
|
2088
|
+
enableZoom: true,
|
|
2089
|
+
enablePan: true,
|
|
2090
|
+
touches: { ONE: THREE6__namespace.TOUCH.ROTATE, TWO: THREE6__namespace.TOUCH.DOLLY_PAN },
|
|
2091
|
+
minDistance: 2,
|
|
2092
|
+
maxDistance: 100,
|
|
2093
|
+
maxPolarAngle: Math.PI / 2 - 0.1
|
|
2094
|
+
}
|
|
2095
|
+
)
|
|
2096
|
+
]
|
|
2097
|
+
}
|
|
2098
|
+
)
|
|
2675
2099
|
}
|
|
2676
2100
|
)
|
|
2677
2101
|
}
|
|
@@ -2679,1086 +2103,357 @@ var GameCanvas3D = React10.forwardRef(
|
|
|
2679
2103
|
}
|
|
2680
2104
|
);
|
|
2681
2105
|
GameCanvas3D.displayName = "GameCanvas3D";
|
|
2682
|
-
var
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
"phosphor-duotone",
|
|
2688
|
-
"tabler",
|
|
2689
|
-
"fa-solid"
|
|
2690
|
-
];
|
|
2691
|
-
function getCurrentIconFamily() {
|
|
2692
|
-
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
2693
|
-
return DEFAULT_FAMILY;
|
|
2694
|
-
}
|
|
2695
|
-
const raw = getComputedStyle(document.documentElement).getPropertyValue("--icon-family").trim().replace(/^["']|["']$/g, "");
|
|
2696
|
-
return VALID_FAMILIES.includes(raw) ? raw : DEFAULT_FAMILY;
|
|
2697
|
-
}
|
|
2698
|
-
var cachedFamily = null;
|
|
2699
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
2700
|
-
var observer = null;
|
|
2701
|
-
function ensureObserver() {
|
|
2702
|
-
if (typeof window === "undefined" || observer) return;
|
|
2703
|
-
observer = new MutationObserver(() => {
|
|
2704
|
-
const next = getCurrentIconFamily();
|
|
2705
|
-
if (next !== cachedFamily) {
|
|
2706
|
-
cachedFamily = next;
|
|
2707
|
-
listeners.forEach((fn) => fn());
|
|
2708
|
-
}
|
|
2709
|
-
});
|
|
2710
|
-
observer.observe(document.documentElement, {
|
|
2711
|
-
attributes: true,
|
|
2712
|
-
attributeFilter: ["data-theme", "style"]
|
|
2713
|
-
});
|
|
2714
|
-
cachedFamily = getCurrentIconFamily();
|
|
2715
|
-
}
|
|
2716
|
-
function subscribeIconFamily(notify) {
|
|
2717
|
-
ensureObserver();
|
|
2718
|
-
listeners.add(notify);
|
|
2719
|
-
return () => {
|
|
2720
|
-
listeners.delete(notify);
|
|
2721
|
-
};
|
|
2722
|
-
}
|
|
2723
|
-
function getIconFamilySnapshot() {
|
|
2724
|
-
if (cachedFamily !== null) return cachedFamily;
|
|
2725
|
-
cachedFamily = getCurrentIconFamily();
|
|
2726
|
-
return cachedFamily;
|
|
2727
|
-
}
|
|
2728
|
-
function getIconFamilyServerSnapshot() {
|
|
2729
|
-
return DEFAULT_FAMILY;
|
|
2730
|
-
}
|
|
2731
|
-
function useIconFamily() {
|
|
2732
|
-
return React10.useSyncExternalStore(
|
|
2733
|
-
subscribeIconFamily,
|
|
2734
|
-
getIconFamilySnapshot,
|
|
2735
|
-
getIconFamilyServerSnapshot
|
|
2736
|
-
);
|
|
2737
|
-
}
|
|
2738
|
-
function kebabToPascal(name) {
|
|
2739
|
-
return name.split("-").map((part) => {
|
|
2740
|
-
if (/^\d+$/.test(part)) return part;
|
|
2741
|
-
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
2742
|
-
}).join("");
|
|
2743
|
-
}
|
|
2744
|
-
var libPromises = /* @__PURE__ */ new Map();
|
|
2745
|
-
function loadLib(key, importer) {
|
|
2746
|
-
let p = libPromises.get(key);
|
|
2747
|
-
if (!p) {
|
|
2748
|
-
p = importer();
|
|
2749
|
-
libPromises.set(key, p);
|
|
2750
|
-
}
|
|
2751
|
-
return p;
|
|
2752
|
-
}
|
|
2753
|
-
function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
|
|
2754
|
-
const Lazy = React10__namespace.default.lazy(async () => {
|
|
2755
|
-
const lib = await loadLib(libKey, importer);
|
|
2756
|
-
const Comp = pick(lib);
|
|
2757
|
-
if (!Comp) {
|
|
2758
|
-
warnFallback(fallbackName, family);
|
|
2759
|
-
return { default: makeLucideAdapter(fallbackName, true) };
|
|
2760
|
-
}
|
|
2761
|
-
return { default: Comp };
|
|
2762
|
-
});
|
|
2763
|
-
const Wrapped = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2764
|
-
React10__namespace.default.Suspense,
|
|
2765
|
-
{
|
|
2766
|
-
fallback: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2767
|
-
"span",
|
|
2768
|
-
{
|
|
2769
|
-
"aria-hidden": true,
|
|
2770
|
-
className: props.className,
|
|
2771
|
-
style: { display: "inline-block", ...props.style }
|
|
2772
|
-
}
|
|
2773
|
-
),
|
|
2774
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Lazy, { ...props })
|
|
2775
|
-
}
|
|
2776
|
-
);
|
|
2777
|
-
Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
|
|
2778
|
-
return Wrapped;
|
|
2779
|
-
}
|
|
2780
|
-
var lucideAliases = {
|
|
2781
|
-
close: LucideIcons__namespace.X,
|
|
2782
|
-
trash: LucideIcons__namespace.Trash2,
|
|
2783
|
-
loader: LucideIcons__namespace.Loader2,
|
|
2784
|
-
stop: LucideIcons__namespace.Square,
|
|
2785
|
-
volume: LucideIcons__namespace.Volume2,
|
|
2786
|
-
"volume-off": LucideIcons__namespace.VolumeX,
|
|
2787
|
-
refresh: LucideIcons__namespace.RefreshCw,
|
|
2788
|
-
share: LucideIcons__namespace.Share2,
|
|
2789
|
-
"sort-asc": LucideIcons__namespace.ArrowUpNarrowWide,
|
|
2790
|
-
"sort-desc": LucideIcons__namespace.ArrowDownNarrowWide
|
|
2791
|
-
};
|
|
2792
|
-
function isComponentLike(v) {
|
|
2793
|
-
return v != null && (typeof v === "function" || typeof v === "object");
|
|
2794
|
-
}
|
|
2795
|
-
function resolveLucide(name) {
|
|
2796
|
-
if (lucideAliases[name]) return lucideAliases[name];
|
|
2797
|
-
const pascal = kebabToPascal(name);
|
|
2798
|
-
const lucideMap = LucideIcons__namespace;
|
|
2799
|
-
const direct = lucideMap[pascal];
|
|
2800
|
-
if (isComponentLike(direct)) return direct;
|
|
2801
|
-
const asIs = lucideMap[name];
|
|
2802
|
-
if (isComponentLike(asIs)) return asIs;
|
|
2803
|
-
return LucideIcons__namespace.HelpCircle;
|
|
2804
|
-
}
|
|
2805
|
-
var phosphorAliases = {
|
|
2806
|
-
// lucide name → phosphor PascalCase name
|
|
2807
|
-
// Actions
|
|
2808
|
-
plus: "Plus",
|
|
2809
|
-
minus: "Minus",
|
|
2810
|
-
x: "X",
|
|
2811
|
-
check: "Check",
|
|
2812
|
-
close: "X",
|
|
2813
|
-
edit: "PencilSimple",
|
|
2814
|
-
pencil: "PencilSimple",
|
|
2815
|
-
trash: "Trash",
|
|
2816
|
-
save: "FloppyDisk",
|
|
2817
|
-
copy: "Copy",
|
|
2818
|
-
share: "Share",
|
|
2819
|
-
send: "PaperPlaneRight",
|
|
2820
|
-
download: "DownloadSimple",
|
|
2821
|
-
upload: "UploadSimple",
|
|
2822
|
-
archive: "Archive",
|
|
2823
|
-
refresh: "ArrowsClockwise",
|
|
2824
|
-
loader: "CircleNotch",
|
|
2825
|
-
link: "Link",
|
|
2826
|
-
paperclip: "Paperclip",
|
|
2827
|
-
// Navigation
|
|
2828
|
-
"chevron-down": "CaretDown",
|
|
2829
|
-
"chevron-up": "CaretUp",
|
|
2830
|
-
"chevron-left": "CaretLeft",
|
|
2831
|
-
"chevron-right": "CaretRight",
|
|
2832
|
-
"arrow-up": "ArrowUp",
|
|
2833
|
-
"arrow-down": "ArrowDown",
|
|
2834
|
-
"arrow-left": "ArrowLeft",
|
|
2835
|
-
"arrow-right": "ArrowRight",
|
|
2836
|
-
menu: "List",
|
|
2837
|
-
more: "DotsThree",
|
|
2838
|
-
"more-vertical": "DotsThreeVertical",
|
|
2839
|
-
"more-horizontal": "DotsThree",
|
|
2840
|
-
external: "ArrowSquareOut",
|
|
2841
|
-
"external-link": "ArrowSquareOut",
|
|
2842
|
-
// Files
|
|
2843
|
-
file: "File",
|
|
2844
|
-
"file-text": "FileText",
|
|
2845
|
-
"file-plus": "FilePlus",
|
|
2846
|
-
"file-minus": "FileMinus",
|
|
2847
|
-
folder: "Folder",
|
|
2848
|
-
"folder-open": "FolderOpen",
|
|
2849
|
-
document: "FileText",
|
|
2850
|
-
// Charts
|
|
2851
|
-
"bar-chart": "ChartBar",
|
|
2852
|
-
"bar-chart-2": "ChartBar",
|
|
2853
|
-
"bar-chart-3": "ChartBar",
|
|
2854
|
-
"line-chart": "ChartLine",
|
|
2855
|
-
"pie-chart": "ChartPie",
|
|
2856
|
-
activity: "Pulse",
|
|
2857
|
-
"trending-up": "TrendUp",
|
|
2858
|
-
"trending-down": "TrendDown",
|
|
2859
|
-
// Messages
|
|
2860
|
-
message: "ChatCircle",
|
|
2861
|
-
"message-circle": "ChatCircle",
|
|
2862
|
-
"message-square": "ChatText",
|
|
2863
|
-
"messages-square": "ChatsCircle",
|
|
2864
|
-
comment: "ChatCircle",
|
|
2865
|
-
comments: "ChatsCircle",
|
|
2866
|
-
inbox: "Tray",
|
|
2867
|
-
mail: "Envelope",
|
|
2868
|
-
envelope: "Envelope",
|
|
2869
|
-
// Status
|
|
2870
|
-
"alert-circle": "WarningCircle",
|
|
2871
|
-
"alert-triangle": "Warning",
|
|
2872
|
-
"check-circle": "CheckCircle",
|
|
2873
|
-
"x-circle": "XCircle",
|
|
2874
|
-
info: "Info",
|
|
2875
|
-
"help-circle": "Question",
|
|
2876
|
-
"life-buoy": "Lifebuoy",
|
|
2877
|
-
lifebuoy: "Lifebuoy",
|
|
2878
|
-
warning: "Warning",
|
|
2879
|
-
error: "WarningCircle",
|
|
2880
|
-
// Media
|
|
2881
|
-
image: "Image",
|
|
2882
|
-
video: "VideoCamera",
|
|
2883
|
-
film: "FilmStrip",
|
|
2884
|
-
camera: "Camera",
|
|
2885
|
-
music: "MusicNote",
|
|
2886
|
-
play: "Play",
|
|
2887
|
-
pause: "Pause",
|
|
2888
|
-
stop: "Stop",
|
|
2889
|
-
"skip-forward": "SkipForward",
|
|
2890
|
-
"skip-back": "SkipBack",
|
|
2891
|
-
volume: "SpeakerHigh",
|
|
2892
|
-
"volume-2": "SpeakerHigh",
|
|
2893
|
-
"volume-x": "SpeakerX",
|
|
2894
|
-
mic: "Microphone",
|
|
2895
|
-
"mic-off": "MicrophoneSlash",
|
|
2896
|
-
// People
|
|
2897
|
-
user: "User",
|
|
2898
|
-
users: "Users",
|
|
2899
|
-
"user-plus": "UserPlus",
|
|
2900
|
-
"user-check": "UserCheck",
|
|
2901
|
-
// Time
|
|
2902
|
-
calendar: "Calendar",
|
|
2903
|
-
clock: "Clock",
|
|
2904
|
-
timer: "Timer",
|
|
2905
|
-
// Location
|
|
2906
|
-
map: "MapTrifold",
|
|
2907
|
-
"map-pin": "MapPin",
|
|
2908
|
-
navigation: "NavigationArrow",
|
|
2909
|
-
compass: "Compass",
|
|
2910
|
-
globe: "Globe",
|
|
2911
|
-
target: "Target",
|
|
2912
|
-
// Project / layout
|
|
2913
|
-
kanban: "Kanban",
|
|
2914
|
-
list: "List",
|
|
2915
|
-
table: "Table",
|
|
2916
|
-
grid: "GridFour",
|
|
2917
|
-
layout: "Layout",
|
|
2918
|
-
columns: "Columns",
|
|
2919
|
-
rows: "Rows",
|
|
2920
|
-
// Misc
|
|
2921
|
-
bell: "Bell",
|
|
2922
|
-
bookmark: "Bookmark",
|
|
2923
|
-
briefcase: "Briefcase",
|
|
2924
|
-
flag: "Flag",
|
|
2925
|
-
tag: "Tag",
|
|
2926
|
-
tags: "Tag",
|
|
2927
|
-
star: "Star",
|
|
2928
|
-
heart: "Heart",
|
|
2929
|
-
home: "House",
|
|
2930
|
-
settings: "Gear",
|
|
2931
|
-
eye: "Eye",
|
|
2932
|
-
"eye-off": "EyeSlash",
|
|
2933
|
-
lock: "Lock",
|
|
2934
|
-
unlock: "LockOpen",
|
|
2935
|
-
key: "Key",
|
|
2936
|
-
shield: "Shield",
|
|
2937
|
-
search: "MagnifyingGlass",
|
|
2938
|
-
filter: "Funnel",
|
|
2939
|
-
"sort-asc": "SortAscending",
|
|
2940
|
-
"sort-desc": "SortDescending",
|
|
2941
|
-
zap: "Lightning",
|
|
2942
|
-
sparkles: "Sparkle",
|
|
2943
|
-
// Code
|
|
2944
|
-
code: "Code",
|
|
2945
|
-
terminal: "Terminal",
|
|
2946
|
-
database: "Database",
|
|
2947
|
-
server: "HardDrives",
|
|
2948
|
-
cloud: "Cloud",
|
|
2949
|
-
wifi: "WifiHigh",
|
|
2950
|
-
package: "Package",
|
|
2951
|
-
box: "Package",
|
|
2952
|
-
// Theme
|
|
2953
|
-
sun: "Sun",
|
|
2954
|
-
moon: "Moon",
|
|
2955
|
-
// Phone
|
|
2956
|
-
phone: "Phone",
|
|
2957
|
-
printer: "Printer",
|
|
2958
|
-
// Hierarchy
|
|
2959
|
-
tree: "Tree",
|
|
2960
|
-
network: "Network"
|
|
2106
|
+
var DEFAULT_CONFIG = {
|
|
2107
|
+
cellSize: 1,
|
|
2108
|
+
offsetX: 0,
|
|
2109
|
+
offsetZ: 0,
|
|
2110
|
+
elevation: 0
|
|
2961
2111
|
};
|
|
2962
|
-
function
|
|
2963
|
-
const
|
|
2964
|
-
return
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
const PhosphorComp = lib[target];
|
|
2969
|
-
if (!PhosphorComp) return null;
|
|
2970
|
-
const Component2 = PhosphorComp;
|
|
2971
|
-
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2972
|
-
Component2,
|
|
2973
|
-
{
|
|
2974
|
-
weight,
|
|
2975
|
-
className: props.className,
|
|
2976
|
-
style: props.style,
|
|
2977
|
-
size: props.size ?? "1em"
|
|
2978
|
-
}
|
|
2979
|
-
);
|
|
2980
|
-
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
2981
|
-
return Adapter;
|
|
2982
|
-
},
|
|
2983
|
-
name,
|
|
2984
|
-
family
|
|
2112
|
+
function gridToWorld(gridX, gridZ, config = DEFAULT_CONFIG) {
|
|
2113
|
+
const opts = { ...DEFAULT_CONFIG, ...config };
|
|
2114
|
+
return new THREE6__namespace.Vector3(
|
|
2115
|
+
gridX * opts.cellSize + opts.offsetX,
|
|
2116
|
+
opts.elevation,
|
|
2117
|
+
gridZ * opts.cellSize + opts.offsetZ
|
|
2985
2118
|
);
|
|
2986
2119
|
}
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
check: "Check",
|
|
2994
|
-
close: "X",
|
|
2995
|
-
edit: "Pencil",
|
|
2996
|
-
pencil: "Pencil",
|
|
2997
|
-
trash: "Trash",
|
|
2998
|
-
save: "DeviceFloppy",
|
|
2999
|
-
copy: "Copy",
|
|
3000
|
-
share: "Share",
|
|
3001
|
-
send: "Send",
|
|
3002
|
-
download: "Download",
|
|
3003
|
-
upload: "Upload",
|
|
3004
|
-
archive: "Archive",
|
|
3005
|
-
refresh: "Refresh",
|
|
3006
|
-
loader: "Loader2",
|
|
3007
|
-
link: "Link",
|
|
3008
|
-
paperclip: "Paperclip",
|
|
3009
|
-
external: "ExternalLink",
|
|
3010
|
-
"external-link": "ExternalLink",
|
|
3011
|
-
// Navigation
|
|
3012
|
-
"chevron-down": "ChevronDown",
|
|
3013
|
-
"chevron-up": "ChevronUp",
|
|
3014
|
-
"chevron-left": "ChevronLeft",
|
|
3015
|
-
"chevron-right": "ChevronRight",
|
|
3016
|
-
"arrow-down": "ArrowDown",
|
|
3017
|
-
"arrow-up": "ArrowUp",
|
|
3018
|
-
"arrow-left": "ArrowLeft",
|
|
3019
|
-
"arrow-right": "ArrowRight",
|
|
3020
|
-
menu: "Menu2",
|
|
3021
|
-
more: "Dots",
|
|
3022
|
-
"more-vertical": "DotsVertical",
|
|
3023
|
-
// Files
|
|
3024
|
-
file: "File",
|
|
3025
|
-
"file-text": "FileText",
|
|
3026
|
-
"file-plus": "FilePlus",
|
|
3027
|
-
"file-check": "FileCheck",
|
|
3028
|
-
"file-minus": "FileMinus",
|
|
3029
|
-
folder: "Folder",
|
|
3030
|
-
"folder-open": "FolderOpen",
|
|
3031
|
-
document: "FileText",
|
|
3032
|
-
// Charts
|
|
3033
|
-
"bar-chart": "ChartBar",
|
|
3034
|
-
"bar-chart-2": "ChartBar",
|
|
3035
|
-
"bar-chart-3": "ChartBar",
|
|
3036
|
-
"line-chart": "ChartLine",
|
|
3037
|
-
"pie-chart": "ChartPie",
|
|
3038
|
-
activity: "Activity",
|
|
3039
|
-
"trending-up": "TrendingUp",
|
|
3040
|
-
"trending-down": "TrendingDown",
|
|
3041
|
-
// Messages
|
|
3042
|
-
message: "Message",
|
|
3043
|
-
"message-circle": "MessageCircle",
|
|
3044
|
-
"message-square": "Message2",
|
|
3045
|
-
"messages-square": "Messages",
|
|
3046
|
-
comment: "Message",
|
|
3047
|
-
comments: "Messages",
|
|
3048
|
-
inbox: "Inbox",
|
|
3049
|
-
mail: "Mail",
|
|
3050
|
-
envelope: "Mail",
|
|
3051
|
-
// Status
|
|
3052
|
-
"alert-circle": "AlertCircle",
|
|
3053
|
-
"alert-triangle": "AlertTriangle",
|
|
3054
|
-
"check-circle": "CircleCheck",
|
|
3055
|
-
"x-circle": "CircleX",
|
|
3056
|
-
info: "InfoCircle",
|
|
3057
|
-
"help-circle": "HelpCircle",
|
|
3058
|
-
"life-buoy": "Lifebuoy",
|
|
3059
|
-
warning: "AlertTriangle",
|
|
3060
|
-
error: "AlertOctagon",
|
|
3061
|
-
// Media
|
|
3062
|
-
image: "Photo",
|
|
3063
|
-
video: "Video",
|
|
3064
|
-
camera: "Camera",
|
|
3065
|
-
music: "Music",
|
|
3066
|
-
play: "PlayerPlay",
|
|
3067
|
-
pause: "PlayerPause",
|
|
3068
|
-
stop: "PlayerStop",
|
|
3069
|
-
"skip-forward": "PlayerSkipForward",
|
|
3070
|
-
"skip-back": "PlayerSkipBack",
|
|
3071
|
-
volume: "Volume",
|
|
3072
|
-
"volume-2": "Volume",
|
|
3073
|
-
"volume-x": "VolumeOff",
|
|
3074
|
-
mic: "Microphone",
|
|
3075
|
-
"mic-off": "MicrophoneOff",
|
|
3076
|
-
// People
|
|
3077
|
-
user: "User",
|
|
3078
|
-
users: "Users",
|
|
3079
|
-
"user-plus": "UserPlus",
|
|
3080
|
-
"user-check": "UserCheck",
|
|
3081
|
-
// Time
|
|
3082
|
-
calendar: "Calendar",
|
|
3083
|
-
clock: "Clock",
|
|
3084
|
-
timer: "Hourglass",
|
|
3085
|
-
// Location
|
|
3086
|
-
map: "Map",
|
|
3087
|
-
"map-pin": "MapPin",
|
|
3088
|
-
navigation: "Navigation",
|
|
3089
|
-
compass: "Compass",
|
|
3090
|
-
globe: "World",
|
|
3091
|
-
target: "Target",
|
|
3092
|
-
// Project / layout
|
|
3093
|
-
kanban: "LayoutKanban",
|
|
3094
|
-
list: "List",
|
|
3095
|
-
table: "Table",
|
|
3096
|
-
grid: "LayoutGrid",
|
|
3097
|
-
layout: "Layout",
|
|
3098
|
-
columns: "LayoutColumns",
|
|
3099
|
-
rows: "LayoutRows",
|
|
3100
|
-
// Misc
|
|
3101
|
-
bell: "Bell",
|
|
3102
|
-
bookmark: "Bookmark",
|
|
3103
|
-
briefcase: "Briefcase",
|
|
3104
|
-
flag: "Flag",
|
|
3105
|
-
tag: "Tag",
|
|
3106
|
-
tags: "Tags",
|
|
3107
|
-
star: "Star",
|
|
3108
|
-
heart: "Heart",
|
|
3109
|
-
home: "Home",
|
|
3110
|
-
settings: "Settings",
|
|
3111
|
-
eye: "Eye",
|
|
3112
|
-
"eye-off": "EyeOff",
|
|
3113
|
-
lock: "Lock",
|
|
3114
|
-
unlock: "LockOpen",
|
|
3115
|
-
key: "Key",
|
|
3116
|
-
shield: "Shield",
|
|
3117
|
-
search: "Search",
|
|
3118
|
-
filter: "Filter",
|
|
3119
|
-
"sort-asc": "SortAscending",
|
|
3120
|
-
"sort-desc": "SortDescending",
|
|
3121
|
-
zap: "Bolt",
|
|
3122
|
-
sparkles: "Sparkles",
|
|
3123
|
-
// Code / data
|
|
3124
|
-
code: "Code",
|
|
3125
|
-
terminal: "Terminal",
|
|
3126
|
-
database: "Database",
|
|
3127
|
-
server: "Server",
|
|
3128
|
-
cloud: "Cloud",
|
|
3129
|
-
wifi: "Wifi",
|
|
3130
|
-
package: "Package",
|
|
3131
|
-
box: "Box",
|
|
3132
|
-
// Theme
|
|
3133
|
-
sun: "Sun",
|
|
3134
|
-
moon: "Moon",
|
|
3135
|
-
// Phone
|
|
3136
|
-
phone: "Phone",
|
|
3137
|
-
printer: "Printer",
|
|
3138
|
-
// Hierarchy
|
|
3139
|
-
tree: "Hierarchy",
|
|
3140
|
-
network: "Network"
|
|
3141
|
-
};
|
|
3142
|
-
function resolveTabler(name, family) {
|
|
3143
|
-
const suffix = tablerAliases[name] ?? kebabToPascal(name);
|
|
3144
|
-
const target = `Icon${suffix}`;
|
|
3145
|
-
return lazyFamilyIcon(
|
|
3146
|
-
"tabler",
|
|
3147
|
-
() => import('@tabler/icons-react'),
|
|
3148
|
-
(lib) => {
|
|
3149
|
-
const TablerComp = lib[target];
|
|
3150
|
-
if (!TablerComp) return null;
|
|
3151
|
-
const Component2 = TablerComp;
|
|
3152
|
-
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3153
|
-
Component2,
|
|
3154
|
-
{
|
|
3155
|
-
stroke: props.strokeWidth ?? 1.5,
|
|
3156
|
-
className: props.className,
|
|
3157
|
-
style: props.style,
|
|
3158
|
-
size: props.size ?? 24
|
|
3159
|
-
}
|
|
3160
|
-
);
|
|
3161
|
-
Adapter.displayName = `Tabler.${target}`;
|
|
3162
|
-
return Adapter;
|
|
3163
|
-
},
|
|
3164
|
-
name,
|
|
3165
|
-
family
|
|
3166
|
-
);
|
|
2120
|
+
function worldToGrid(worldX, worldZ, config = DEFAULT_CONFIG) {
|
|
2121
|
+
const opts = { ...DEFAULT_CONFIG, ...config };
|
|
2122
|
+
return {
|
|
2123
|
+
x: Math.round((worldX - opts.offsetX) / opts.cellSize),
|
|
2124
|
+
z: Math.round((worldZ - opts.offsetZ) / opts.cellSize)
|
|
2125
|
+
};
|
|
3167
2126
|
}
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
x: "Times",
|
|
3177
|
-
loader: "Spinner",
|
|
3178
|
-
refresh: "Sync",
|
|
3179
|
-
"sort-asc": "SortAmountUp",
|
|
3180
|
-
"sort-desc": "SortAmountDown",
|
|
3181
|
-
"chevron-down": "ChevronDown",
|
|
3182
|
-
"chevron-up": "ChevronUp",
|
|
3183
|
-
"chevron-left": "ChevronLeft",
|
|
3184
|
-
"chevron-right": "ChevronRight",
|
|
3185
|
-
"help-circle": "QuestionCircle",
|
|
3186
|
-
"alert-triangle": "ExclamationTriangle",
|
|
3187
|
-
"alert-circle": "ExclamationCircle",
|
|
3188
|
-
"check-circle": "CheckCircle",
|
|
3189
|
-
"x-circle": "TimesCircle",
|
|
3190
|
-
edit: "Edit",
|
|
3191
|
-
pencil: "PencilAlt",
|
|
3192
|
-
trash: "Trash",
|
|
3193
|
-
send: "PaperPlane",
|
|
3194
|
-
share: "ShareAlt",
|
|
3195
|
-
external: "ExternalLinkAlt",
|
|
3196
|
-
plus: "Plus",
|
|
3197
|
-
minus: "Minus",
|
|
3198
|
-
check: "Check",
|
|
3199
|
-
star: "Star",
|
|
3200
|
-
heart: "Heart",
|
|
3201
|
-
home: "Home",
|
|
3202
|
-
user: "User",
|
|
3203
|
-
users: "Users",
|
|
3204
|
-
"user-plus": "UserPlus",
|
|
3205
|
-
"user-check": "UserCheck",
|
|
3206
|
-
settings: "Cog",
|
|
3207
|
-
menu: "Bars",
|
|
3208
|
-
"arrow-up": "ArrowUp",
|
|
3209
|
-
"arrow-down": "ArrowDown",
|
|
3210
|
-
"arrow-left": "ArrowLeft",
|
|
3211
|
-
"arrow-right": "ArrowRight",
|
|
3212
|
-
copy: "Copy",
|
|
3213
|
-
download: "Download",
|
|
3214
|
-
upload: "Upload",
|
|
3215
|
-
filter: "Filter",
|
|
3216
|
-
calendar: "Calendar",
|
|
3217
|
-
clock: "Clock",
|
|
3218
|
-
bell: "Bell",
|
|
3219
|
-
mail: "Envelope",
|
|
3220
|
-
envelope: "Envelope",
|
|
3221
|
-
lock: "Lock",
|
|
3222
|
-
unlock: "LockOpen",
|
|
3223
|
-
eye: "Eye",
|
|
3224
|
-
"eye-off": "EyeSlash",
|
|
3225
|
-
more: "EllipsisH",
|
|
3226
|
-
"more-vertical": "EllipsisV",
|
|
3227
|
-
info: "InfoCircle",
|
|
3228
|
-
warning: "ExclamationTriangle",
|
|
3229
|
-
error: "ExclamationCircle",
|
|
3230
|
-
// Time
|
|
3231
|
-
timer: "Hourglass",
|
|
3232
|
-
// Files (FA renamed FileText → FileAlt)
|
|
3233
|
-
file: "File",
|
|
3234
|
-
"file-text": "FileAlt",
|
|
3235
|
-
"file-plus": "FileMedical",
|
|
3236
|
-
"file-minus": "FileExcel",
|
|
3237
|
-
"file-check": "FileSignature",
|
|
3238
|
-
document: "FileAlt",
|
|
3239
|
-
// Charts (lucide BarChart2 / BarChart3 → FA ChartBar)
|
|
3240
|
-
"bar-chart": "ChartBar",
|
|
3241
|
-
"bar-chart-2": "ChartBar",
|
|
3242
|
-
"bar-chart-3": "ChartBar",
|
|
3243
|
-
"line-chart": "ChartLine",
|
|
3244
|
-
"pie-chart": "ChartPie",
|
|
3245
|
-
activity: "ChartLine",
|
|
3246
|
-
"trending-up": "ChartLine",
|
|
3247
|
-
"trending-down": "ChartLine",
|
|
3248
|
-
// Messages (lucide MessageCircle/MessageSquare → FA CommentDots/CommentAlt)
|
|
3249
|
-
message: "Comment",
|
|
3250
|
-
"message-circle": "CommentDots",
|
|
3251
|
-
"message-square": "CommentAlt",
|
|
3252
|
-
"messages-square": "Comments",
|
|
3253
|
-
comment: "Comment",
|
|
3254
|
-
comments: "Comments",
|
|
3255
|
-
inbox: "Inbox",
|
|
3256
|
-
// Support / help
|
|
3257
|
-
"life-buoy": "LifeRing",
|
|
3258
|
-
lifebuoy: "LifeRing",
|
|
3259
|
-
// Project / kanban (FA has no kanban; closest semantic is Tasks/Columns)
|
|
3260
|
-
kanban: "Tasks",
|
|
3261
|
-
columns: "Columns",
|
|
3262
|
-
rows: "Bars",
|
|
3263
|
-
layout: "ThLarge",
|
|
3264
|
-
grid: "Th",
|
|
3265
|
-
list: "List",
|
|
3266
|
-
table: "Table",
|
|
3267
|
-
// Storage / folders
|
|
3268
|
-
folder: "Folder",
|
|
3269
|
-
"folder-open": "FolderOpen",
|
|
3270
|
-
archive: "Archive",
|
|
3271
|
-
bookmark: "Bookmark",
|
|
3272
|
-
briefcase: "Briefcase",
|
|
3273
|
-
package: "Box",
|
|
3274
|
-
box: "Box",
|
|
3275
|
-
// Map / location
|
|
3276
|
-
map: "Map",
|
|
3277
|
-
"map-pin": "MapMarkerAlt",
|
|
3278
|
-
navigation: "LocationArrow",
|
|
3279
|
-
compass: "Compass",
|
|
3280
|
-
globe: "Globe",
|
|
3281
|
-
target: "Bullseye",
|
|
3282
|
-
// Media
|
|
3283
|
-
image: "Image",
|
|
3284
|
-
video: "Video",
|
|
3285
|
-
film: "Film",
|
|
3286
|
-
camera: "Camera",
|
|
3287
|
-
music: "Music",
|
|
3288
|
-
play: "Play",
|
|
3289
|
-
pause: "Pause",
|
|
3290
|
-
stop: "Stop",
|
|
3291
|
-
"skip-forward": "Forward",
|
|
3292
|
-
"skip-back": "Backward",
|
|
3293
|
-
volume: "VolumeUp",
|
|
3294
|
-
"volume-2": "VolumeUp",
|
|
3295
|
-
"volume-x": "VolumeMute",
|
|
3296
|
-
mic: "Microphone",
|
|
3297
|
-
"mic-off": "MicrophoneSlash",
|
|
3298
|
-
phone: "Phone",
|
|
3299
|
-
// Code / data
|
|
3300
|
-
code: "Code",
|
|
3301
|
-
terminal: "Terminal",
|
|
3302
|
-
database: "Database",
|
|
3303
|
-
server: "Server",
|
|
3304
|
-
cloud: "Cloud",
|
|
3305
|
-
wifi: "Wifi",
|
|
3306
|
-
// Security
|
|
3307
|
-
shield: "ShieldAlt",
|
|
3308
|
-
key: "Key",
|
|
3309
|
-
// Misc actions
|
|
3310
|
-
printer: "Print",
|
|
3311
|
-
save: "Save",
|
|
3312
|
-
link: "Link",
|
|
3313
|
-
unlink: "Unlink",
|
|
3314
|
-
paperclip: "Paperclip",
|
|
3315
|
-
flag: "Flag",
|
|
3316
|
-
tag: "Tag",
|
|
3317
|
-
tags: "Tags",
|
|
3318
|
-
zap: "Bolt",
|
|
3319
|
-
sparkles: "Magic",
|
|
3320
|
-
// Theme
|
|
3321
|
-
sun: "Sun",
|
|
3322
|
-
moon: "Moon",
|
|
3323
|
-
// Hierarchy (FA has no Tree icon for hierarchies; Sitemap is the org-chart icon)
|
|
3324
|
-
tree: "Sitemap",
|
|
3325
|
-
network: "NetworkWired"
|
|
3326
|
-
};
|
|
3327
|
-
function resolveFa(name, family) {
|
|
3328
|
-
const suffix = faAliases[name] ?? kebabToPascal(name);
|
|
3329
|
-
const target = `Fa${suffix}`;
|
|
3330
|
-
return lazyFamilyIcon(
|
|
3331
|
-
"fa",
|
|
3332
|
-
() => import('react-icons/fa'),
|
|
3333
|
-
(lib) => {
|
|
3334
|
-
const FaComp = lib[target];
|
|
3335
|
-
if (!FaComp) return null;
|
|
3336
|
-
const Component2 = FaComp;
|
|
3337
|
-
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3338
|
-
Component2,
|
|
3339
|
-
{
|
|
3340
|
-
className: props.className,
|
|
3341
|
-
style: props.style,
|
|
3342
|
-
size: props.size ?? "1em"
|
|
3343
|
-
}
|
|
3344
|
-
);
|
|
3345
|
-
Adapter.displayName = `Fa.${target}`;
|
|
3346
|
-
return Adapter;
|
|
3347
|
-
},
|
|
3348
|
-
name,
|
|
3349
|
-
family
|
|
3350
|
-
);
|
|
2127
|
+
function raycastToPlane(camera, mouseX, mouseY, planeY = 0) {
|
|
2128
|
+
const raycaster = new THREE6__namespace.Raycaster();
|
|
2129
|
+
const mouse = new THREE6__namespace.Vector2(mouseX, mouseY);
|
|
2130
|
+
raycaster.setFromCamera(mouse, camera);
|
|
2131
|
+
const plane = new THREE6__namespace.Plane(new THREE6__namespace.Vector3(0, 1, 0), -planeY);
|
|
2132
|
+
const target = new THREE6__namespace.Vector3();
|
|
2133
|
+
const intersection = raycaster.ray.intersectPlane(plane, target);
|
|
2134
|
+
return intersection ? target : null;
|
|
3351
2135
|
}
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
const
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
console.warn(
|
|
3359
|
-
`[iconFamily] No '${name}' mapping in family '${family}'; falling back to lucide. Add an alias in lib/iconFamily.ts.`
|
|
3360
|
-
);
|
|
3361
|
-
}
|
|
2136
|
+
function raycastToObjects(camera, mouseX, mouseY, objects) {
|
|
2137
|
+
const raycaster = new THREE6__namespace.Raycaster();
|
|
2138
|
+
const mouse = new THREE6__namespace.Vector2(mouseX, mouseY);
|
|
2139
|
+
raycaster.setFromCamera(mouse, camera);
|
|
2140
|
+
const intersects = raycaster.intersectObjects(objects, true);
|
|
2141
|
+
return intersects.length > 0 ? intersects[0] : null;
|
|
3362
2142
|
}
|
|
3363
|
-
function
|
|
3364
|
-
const
|
|
3365
|
-
const
|
|
3366
|
-
|
|
3367
|
-
const style = isFallback ? { ...props.style ?? {}, strokeWidth: stroke ?? 2 } : props.style;
|
|
3368
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3369
|
-
LucideComp,
|
|
3370
|
-
{
|
|
3371
|
-
className: props.className,
|
|
3372
|
-
strokeWidth: stroke,
|
|
3373
|
-
style,
|
|
3374
|
-
size: props.size
|
|
3375
|
-
}
|
|
3376
|
-
);
|
|
3377
|
-
};
|
|
3378
|
-
Adapter.displayName = `Lucide.${name}${isFallback ? ".fallback" : ""}`;
|
|
3379
|
-
return Adapter;
|
|
2143
|
+
function gridDistance(a, b) {
|
|
2144
|
+
const dx = b.x - a.x;
|
|
2145
|
+
const dz = b.z - a.z;
|
|
2146
|
+
return Math.sqrt(dx * dx + dz * dz);
|
|
3380
2147
|
}
|
|
3381
|
-
function
|
|
3382
|
-
|
|
3383
|
-
case "lucide":
|
|
3384
|
-
return makeLucideAdapter(name, false);
|
|
3385
|
-
// Non-lucide families resolve to a lazy, Suspense-wrapped component that
|
|
3386
|
-
// dynamic-imports the library on first render and falls back to lucide
|
|
3387
|
-
// internally when the family lacks the icon (see lazyFamilyIcon).
|
|
3388
|
-
case "phosphor-outline":
|
|
3389
|
-
return resolvePhosphor(name, "regular", family);
|
|
3390
|
-
case "phosphor-fill":
|
|
3391
|
-
return resolvePhosphor(name, "fill", family);
|
|
3392
|
-
case "phosphor-duotone":
|
|
3393
|
-
return resolvePhosphor(name, "duotone", family);
|
|
3394
|
-
case "tabler":
|
|
3395
|
-
return resolveTabler(name, family);
|
|
3396
|
-
case "fa-solid":
|
|
3397
|
-
return resolveFa(name, family);
|
|
3398
|
-
}
|
|
2148
|
+
function gridManhattanDistance(a, b) {
|
|
2149
|
+
return Math.abs(b.x - a.x) + Math.abs(b.z - a.z);
|
|
3399
2150
|
}
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
xl: "w-8 h-8"
|
|
3414
|
-
};
|
|
3415
|
-
var animationClasses = {
|
|
3416
|
-
none: "",
|
|
3417
|
-
spin: "animate-spin",
|
|
3418
|
-
pulse: "animate-pulse"
|
|
3419
|
-
};
|
|
3420
|
-
var Icon = ({
|
|
3421
|
-
icon,
|
|
3422
|
-
name,
|
|
3423
|
-
size = "md",
|
|
3424
|
-
color,
|
|
3425
|
-
animation = "none",
|
|
3426
|
-
className,
|
|
3427
|
-
strokeWidth,
|
|
3428
|
-
style
|
|
3429
|
-
}) => {
|
|
3430
|
-
const directIcon = typeof icon === "string" ? void 0 : icon;
|
|
3431
|
-
const effectiveName = typeof icon === "string" ? icon : name;
|
|
3432
|
-
const family = useIconFamily();
|
|
3433
|
-
const RenderedComponent = React10__namespace.default.useMemo(() => {
|
|
3434
|
-
if (directIcon) return null;
|
|
3435
|
-
return effectiveName ? resolveIconForFamily(effectiveName, family) : null;
|
|
3436
|
-
}, [directIcon, effectiveName, family]);
|
|
3437
|
-
const effectiveStrokeWidth = strokeWidth ?? void 0;
|
|
3438
|
-
const inlineStyle = {
|
|
3439
|
-
...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
|
|
3440
|
-
...style
|
|
3441
|
-
};
|
|
3442
|
-
const resolvedColor = color ? color in colorTokenClasses ? colorTokenClasses[color] : color : "text-current";
|
|
3443
|
-
const composedClassName = cn(
|
|
3444
|
-
sizeClasses[size],
|
|
3445
|
-
animationClasses[animation],
|
|
3446
|
-
resolvedColor,
|
|
3447
|
-
className
|
|
3448
|
-
);
|
|
3449
|
-
if (directIcon) {
|
|
3450
|
-
const Direct = directIcon;
|
|
3451
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3452
|
-
Direct,
|
|
3453
|
-
{
|
|
3454
|
-
className: composedClassName,
|
|
3455
|
-
strokeWidth: effectiveStrokeWidth,
|
|
3456
|
-
style: inlineStyle
|
|
3457
|
-
}
|
|
3458
|
-
);
|
|
3459
|
-
}
|
|
3460
|
-
if (RenderedComponent) {
|
|
3461
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3462
|
-
RenderedComponent,
|
|
3463
|
-
{
|
|
3464
|
-
className: composedClassName,
|
|
3465
|
-
strokeWidth: effectiveStrokeWidth,
|
|
3466
|
-
style: inlineStyle
|
|
3467
|
-
}
|
|
2151
|
+
function getNeighbors(x, z, includeDiagonal = false) {
|
|
2152
|
+
const neighbors = [
|
|
2153
|
+
{ x: x + 1, z },
|
|
2154
|
+
{ x: x - 1, z },
|
|
2155
|
+
{ x, z: z + 1 },
|
|
2156
|
+
{ x, z: z - 1 }
|
|
2157
|
+
];
|
|
2158
|
+
if (includeDiagonal) {
|
|
2159
|
+
neighbors.push(
|
|
2160
|
+
{ x: x + 1, z: z + 1 },
|
|
2161
|
+
{ x: x - 1, z: z - 1 },
|
|
2162
|
+
{ x: x + 1, z: z - 1 },
|
|
2163
|
+
{ x: x - 1, z: z + 1 }
|
|
3468
2164
|
);
|
|
3469
2165
|
}
|
|
3470
|
-
|
|
3471
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3472
|
-
Fallback,
|
|
3473
|
-
{
|
|
3474
|
-
className: composedClassName,
|
|
3475
|
-
strokeWidth: effectiveStrokeWidth,
|
|
3476
|
-
style: inlineStyle
|
|
3477
|
-
}
|
|
3478
|
-
);
|
|
3479
|
-
};
|
|
3480
|
-
Icon.displayName = "Icon";
|
|
3481
|
-
|
|
3482
|
-
// lib/atlasSlice.ts
|
|
3483
|
-
var atlasCache = /* @__PURE__ */ new Map();
|
|
3484
|
-
function isTilesheet(a) {
|
|
3485
|
-
return typeof a.tileWidth === "number";
|
|
2166
|
+
return neighbors;
|
|
3486
2167
|
}
|
|
3487
|
-
function
|
|
3488
|
-
|
|
3489
|
-
atlasCache.set(url, void 0);
|
|
3490
|
-
fetch(url).then((r) => r.json()).then((json) => {
|
|
3491
|
-
atlasCache.set(url, json);
|
|
3492
|
-
onReady();
|
|
3493
|
-
}).catch(() => {
|
|
3494
|
-
atlasCache.set(url, null);
|
|
3495
|
-
});
|
|
3496
|
-
return void 0;
|
|
2168
|
+
function isInBounds(x, z, bounds) {
|
|
2169
|
+
return x >= bounds.minX && x <= bounds.maxX && z >= bounds.minZ && z <= bounds.maxZ;
|
|
3497
2170
|
}
|
|
3498
|
-
function
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
const
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
2171
|
+
function getCellsInRadius(centerX, centerZ, radius) {
|
|
2172
|
+
const cells = [];
|
|
2173
|
+
const radiusSquared = radius * radius;
|
|
2174
|
+
const minX = Math.floor(centerX - radius);
|
|
2175
|
+
const maxX = Math.ceil(centerX + radius);
|
|
2176
|
+
const minZ = Math.floor(centerZ - radius);
|
|
2177
|
+
const maxZ = Math.ceil(centerZ + radius);
|
|
2178
|
+
for (let x = minX; x <= maxX; x++) {
|
|
2179
|
+
for (let z = minZ; z <= maxZ; z++) {
|
|
2180
|
+
const dx = x - centerX;
|
|
2181
|
+
const dz = z - centerZ;
|
|
2182
|
+
if (dx * dx + dz * dz <= radiusSquared) {
|
|
2183
|
+
cells.push({ x, z });
|
|
2184
|
+
}
|
|
3511
2185
|
}
|
|
3512
|
-
if (!Number.isFinite(col) || !Number.isFinite(row) || col < 0 || row < 0 || col >= atlas.columns || row >= atlas.rows) return null;
|
|
3513
|
-
const margin = atlas.margin ?? 0;
|
|
3514
|
-
const spacing = atlas.spacing ?? 0;
|
|
3515
|
-
return {
|
|
3516
|
-
sx: margin + col * (atlas.tileWidth + spacing),
|
|
3517
|
-
sy: margin + row * (atlas.tileHeight + spacing),
|
|
3518
|
-
sw: atlas.tileWidth,
|
|
3519
|
-
sh: atlas.tileHeight
|
|
3520
|
-
};
|
|
3521
2186
|
}
|
|
3522
|
-
|
|
3523
|
-
if (!st) return null;
|
|
3524
|
-
return { sx: st.x, sy: st.y, sw: st.width, sh: st.height };
|
|
3525
|
-
}
|
|
3526
|
-
function isAtlasAsset(asset) {
|
|
3527
|
-
return !!asset && typeof asset.atlas === "string" && typeof asset.sprite === "string";
|
|
2187
|
+
return cells;
|
|
3528
2188
|
}
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
imageWaiters.get(url)?.forEach((fn) => fn());
|
|
3542
|
-
imageWaiters.delete(url);
|
|
3543
|
-
};
|
|
3544
|
-
img.src = url;
|
|
3545
|
-
}
|
|
3546
|
-
return null;
|
|
2189
|
+
function createGridHighlight(color = 16776960, opacity = 0.3) {
|
|
2190
|
+
const geometry = new THREE6__namespace.PlaneGeometry(0.95, 0.95);
|
|
2191
|
+
const material = new THREE6__namespace.MeshBasicMaterial({
|
|
2192
|
+
color,
|
|
2193
|
+
transparent: true,
|
|
2194
|
+
opacity,
|
|
2195
|
+
side: THREE6__namespace.DoubleSide
|
|
2196
|
+
});
|
|
2197
|
+
const mesh = new THREE6__namespace.Mesh(geometry, material);
|
|
2198
|
+
mesh.rotation.x = -Math.PI / 2;
|
|
2199
|
+
mesh.position.y = 0.01;
|
|
2200
|
+
return mesh;
|
|
3547
2201
|
}
|
|
3548
|
-
function
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
fill = false,
|
|
3554
|
-
fit = "contain",
|
|
3555
|
-
alt,
|
|
3556
|
-
className,
|
|
3557
|
-
style,
|
|
3558
|
-
"aria-hidden": ariaHidden
|
|
3559
|
-
}) {
|
|
3560
|
-
const [, bump] = React10__namespace.useReducer((x) => x + 1, 0);
|
|
3561
|
-
const canvasRef = React10__namespace.useRef(null);
|
|
3562
|
-
const sliced = isAtlasAsset(asset);
|
|
3563
|
-
const atlas = sliced ? getAtlas(asset.atlas, bump) : void 0;
|
|
3564
|
-
const img = sliced && asset?.url ? getSheetImage(asset.url, bump) : null;
|
|
3565
|
-
const rect = sliced && atlas ? subRectFor(atlas, asset.sprite) : null;
|
|
3566
|
-
React10__namespace.useEffect(() => {
|
|
3567
|
-
const canvas = canvasRef.current;
|
|
3568
|
-
if (!canvas || !img || !rect) return;
|
|
3569
|
-
canvas.width = rect.sw;
|
|
3570
|
-
canvas.height = rect.sh;
|
|
3571
|
-
const ctx = canvas.getContext("2d");
|
|
3572
|
-
if (!ctx) return;
|
|
3573
|
-
ctx.imageSmoothingEnabled = false;
|
|
3574
|
-
ctx.clearRect(0, 0, rect.sw, rect.sh);
|
|
3575
|
-
ctx.drawImage(img, rect.sx, rect.sy, rect.sw, rect.sh, 0, 0, rect.sw, rect.sh);
|
|
3576
|
-
}, [img, rect?.sx, rect?.sy, rect?.sw, rect?.sh]);
|
|
3577
|
-
const w = fill ? "100%" : width ?? size;
|
|
3578
|
-
const h = fill ? "100%" : height ?? size;
|
|
3579
|
-
const boxStyle = {
|
|
3580
|
-
...fill ? { position: "absolute", inset: 0 } : {},
|
|
3581
|
-
width: w,
|
|
3582
|
-
height: h,
|
|
3583
|
-
objectFit: fit,
|
|
3584
|
-
imageRendering: "pixelated",
|
|
3585
|
-
...style
|
|
2202
|
+
function normalizeMouseCoordinates(clientX, clientY, element) {
|
|
2203
|
+
const rect = element.getBoundingClientRect();
|
|
2204
|
+
return {
|
|
2205
|
+
x: (clientX - rect.left) / rect.width * 2 - 1,
|
|
2206
|
+
y: -((clientY - rect.top) / rect.height) * 2 + 1
|
|
3586
2207
|
};
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
)
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
"
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
}
|
|
2208
|
+
}
|
|
2209
|
+
function useTapReveal(options = {}) {
|
|
2210
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
2211
|
+
const [revealed, setRevealed] = React7.useState(false);
|
|
2212
|
+
const onRevealRef = React7.useRef(onReveal);
|
|
2213
|
+
const onDismissRef = React7.useRef(onDismiss);
|
|
2214
|
+
onRevealRef.current = onReveal;
|
|
2215
|
+
onDismissRef.current = onDismiss;
|
|
2216
|
+
const reveal = React7.useCallback(() => {
|
|
2217
|
+
setRevealed((wasRevealed) => {
|
|
2218
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
2219
|
+
return true;
|
|
2220
|
+
});
|
|
2221
|
+
}, []);
|
|
2222
|
+
const dismiss = React7.useCallback(() => {
|
|
2223
|
+
setRevealed((wasRevealed) => {
|
|
2224
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
2225
|
+
return false;
|
|
2226
|
+
});
|
|
2227
|
+
}, []);
|
|
2228
|
+
const onPointerDown = React7.useCallback(
|
|
2229
|
+
(e) => {
|
|
2230
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
2231
|
+
if (revealed) dismiss();
|
|
2232
|
+
else reveal();
|
|
2233
|
+
},
|
|
2234
|
+
[enabled, revealed, reveal, dismiss]
|
|
3615
2235
|
);
|
|
2236
|
+
React7.useEffect(() => {
|
|
2237
|
+
if (!revealed || typeof document === "undefined") return;
|
|
2238
|
+
const onDocDown = (ev) => {
|
|
2239
|
+
const target = ev.target;
|
|
2240
|
+
if (!(target instanceof Node)) return;
|
|
2241
|
+
const inside = (refs ?? []).some((r) => r.current?.contains(target));
|
|
2242
|
+
if (!inside) dismiss();
|
|
2243
|
+
};
|
|
2244
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
2245
|
+
return () => {
|
|
2246
|
+
clearTimeout(id);
|
|
2247
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
2248
|
+
};
|
|
2249
|
+
}, [revealed, refs, dismiss]);
|
|
2250
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
3616
2251
|
}
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
"bg-transparent text-accent",
|
|
3628
|
-
"border border-accent",
|
|
3629
|
-
"hover:bg-accent hover:text-white hover:border-accent",
|
|
3630
|
-
"active:scale-[var(--active-scale)]"
|
|
3631
|
-
].join(" "),
|
|
3632
|
-
ghost: [
|
|
3633
|
-
"bg-transparent text-muted-foreground",
|
|
3634
|
-
"border border-transparent",
|
|
3635
|
-
"hover:text-primary-foreground hover:bg-primary hover:border-primary",
|
|
3636
|
-
"active:scale-[var(--active-scale)]"
|
|
3637
|
-
].join(" "),
|
|
3638
|
-
danger: [
|
|
3639
|
-
"bg-surface text-error",
|
|
3640
|
-
"border-[length:var(--border-width)] border-error",
|
|
3641
|
-
"shadow-sm",
|
|
3642
|
-
"hover:bg-error hover:text-error-foreground hover:shadow-lg",
|
|
3643
|
-
"active:scale-[var(--active-scale)] active:shadow-sm"
|
|
3644
|
-
].join(" "),
|
|
3645
|
-
success: [
|
|
3646
|
-
"bg-surface text-success",
|
|
3647
|
-
"border-[length:var(--border-width)] border-success",
|
|
3648
|
-
"shadow-sm",
|
|
3649
|
-
"hover:bg-success hover:text-success-foreground hover:shadow-lg",
|
|
3650
|
-
"active:scale-[var(--active-scale)] active:shadow-sm"
|
|
3651
|
-
].join(" "),
|
|
3652
|
-
warning: [
|
|
3653
|
-
"bg-surface text-warning",
|
|
3654
|
-
"border-[length:var(--border-width)] border-warning",
|
|
3655
|
-
"shadow-sm",
|
|
3656
|
-
"hover:bg-warning hover:text-warning-foreground hover:shadow-lg",
|
|
3657
|
-
"active:scale-[var(--active-scale)] active:shadow-sm"
|
|
3658
|
-
].join(" "),
|
|
3659
|
-
// "default" is an alias for secondary
|
|
3660
|
-
default: [
|
|
3661
|
-
"bg-secondary text-secondary-foreground",
|
|
3662
|
-
"border-[length:var(--border-width-thin)] border-border",
|
|
3663
|
-
"hover:bg-secondary-hover",
|
|
3664
|
-
"active:scale-[var(--active-scale)]"
|
|
3665
|
-
].join(" ")
|
|
2252
|
+
|
|
2253
|
+
// components/core/atoms/Box.tsx
|
|
2254
|
+
var paddingStyles = {
|
|
2255
|
+
none: "p-0",
|
|
2256
|
+
xs: "p-1",
|
|
2257
|
+
sm: "p-2",
|
|
2258
|
+
md: "p-4",
|
|
2259
|
+
lg: "p-6",
|
|
2260
|
+
xl: "p-8",
|
|
2261
|
+
"2xl": "p-12"
|
|
3666
2262
|
};
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
2263
|
+
var paddingXStyles = {
|
|
2264
|
+
none: "px-0",
|
|
2265
|
+
xs: "px-1",
|
|
2266
|
+
sm: "px-2",
|
|
2267
|
+
md: "px-4",
|
|
2268
|
+
lg: "px-6",
|
|
2269
|
+
xl: "px-8",
|
|
2270
|
+
"2xl": "px-12"
|
|
3672
2271
|
};
|
|
3673
|
-
var
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
2272
|
+
var paddingYStyles = {
|
|
2273
|
+
none: "py-0",
|
|
2274
|
+
xs: "py-1",
|
|
2275
|
+
sm: "py-2",
|
|
2276
|
+
md: "py-4",
|
|
2277
|
+
lg: "py-6",
|
|
2278
|
+
xl: "py-8",
|
|
2279
|
+
"2xl": "py-12"
|
|
3677
2280
|
};
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
2281
|
+
var marginStyles = {
|
|
2282
|
+
none: "m-0",
|
|
2283
|
+
xs: "m-1",
|
|
2284
|
+
sm: "m-2",
|
|
2285
|
+
md: "m-4",
|
|
2286
|
+
lg: "m-6",
|
|
2287
|
+
xl: "m-8",
|
|
2288
|
+
"2xl": "m-12",
|
|
2289
|
+
auto: "m-auto"
|
|
2290
|
+
};
|
|
2291
|
+
var marginXStyles = {
|
|
2292
|
+
none: "mx-0",
|
|
2293
|
+
xs: "mx-1",
|
|
2294
|
+
sm: "mx-2",
|
|
2295
|
+
md: "mx-4",
|
|
2296
|
+
lg: "mx-6",
|
|
2297
|
+
xl: "mx-8",
|
|
2298
|
+
"2xl": "mx-12",
|
|
2299
|
+
auto: "mx-auto"
|
|
2300
|
+
};
|
|
2301
|
+
var marginYStyles = {
|
|
2302
|
+
none: "my-0",
|
|
2303
|
+
xs: "my-1",
|
|
2304
|
+
sm: "my-2",
|
|
2305
|
+
md: "my-4",
|
|
2306
|
+
lg: "my-6",
|
|
2307
|
+
xl: "my-8",
|
|
2308
|
+
"2xl": "my-12",
|
|
2309
|
+
auto: "my-auto"
|
|
2310
|
+
};
|
|
2311
|
+
var bgStyles = {
|
|
2312
|
+
transparent: "bg-transparent",
|
|
2313
|
+
primary: "bg-primary text-primary-foreground",
|
|
2314
|
+
secondary: "bg-secondary text-secondary-foreground",
|
|
2315
|
+
muted: "bg-muted text-foreground",
|
|
2316
|
+
accent: "bg-accent text-accent-foreground",
|
|
2317
|
+
surface: "bg-card",
|
|
2318
|
+
overlay: "bg-card/80 backdrop-blur-sm"
|
|
2319
|
+
};
|
|
2320
|
+
var roundedStyles = {
|
|
2321
|
+
none: "rounded-none",
|
|
2322
|
+
sm: "rounded-sm",
|
|
2323
|
+
md: "rounded-md",
|
|
2324
|
+
lg: "rounded-lg",
|
|
2325
|
+
xl: "rounded-xl",
|
|
2326
|
+
"2xl": "rounded-xl",
|
|
2327
|
+
full: "rounded-full"
|
|
2328
|
+
};
|
|
2329
|
+
var shadowStyles = {
|
|
2330
|
+
none: "shadow-none",
|
|
2331
|
+
sm: "shadow-sm",
|
|
2332
|
+
md: "shadow",
|
|
2333
|
+
lg: "shadow-lg",
|
|
2334
|
+
xl: "shadow-lg"
|
|
2335
|
+
};
|
|
2336
|
+
var displayStyles = {
|
|
2337
|
+
block: "block",
|
|
2338
|
+
inline: "inline",
|
|
2339
|
+
"inline-block": "inline-block",
|
|
2340
|
+
flex: "flex",
|
|
2341
|
+
"inline-flex": "inline-flex",
|
|
2342
|
+
grid: "grid"
|
|
2343
|
+
};
|
|
2344
|
+
var overflowStyles = {
|
|
2345
|
+
auto: "overflow-auto",
|
|
2346
|
+
hidden: "overflow-hidden",
|
|
2347
|
+
visible: "overflow-visible",
|
|
2348
|
+
scroll: "overflow-scroll"
|
|
2349
|
+
};
|
|
2350
|
+
var positionStyles = {
|
|
2351
|
+
relative: "relative",
|
|
2352
|
+
absolute: "absolute",
|
|
2353
|
+
fixed: "fixed",
|
|
2354
|
+
sticky: "sticky"
|
|
2355
|
+
};
|
|
2356
|
+
var Box = React7__default.default.forwardRef(
|
|
2357
|
+
({
|
|
2358
|
+
padding,
|
|
2359
|
+
paddingX,
|
|
2360
|
+
paddingY,
|
|
2361
|
+
margin,
|
|
2362
|
+
marginX,
|
|
2363
|
+
marginY,
|
|
2364
|
+
bg = "transparent",
|
|
2365
|
+
border = false,
|
|
2366
|
+
rounded = "none",
|
|
2367
|
+
shadow = "none",
|
|
2368
|
+
display,
|
|
2369
|
+
fullWidth = false,
|
|
2370
|
+
fullHeight = false,
|
|
2371
|
+
overflow,
|
|
2372
|
+
position,
|
|
2373
|
+
className,
|
|
2374
|
+
children,
|
|
2375
|
+
as: Component2 = "div",
|
|
2376
|
+
action,
|
|
2377
|
+
actionPayload,
|
|
2378
|
+
hoverEvent,
|
|
2379
|
+
tapReveal = true,
|
|
2380
|
+
maxWidth,
|
|
2381
|
+
onClick,
|
|
2382
|
+
onMouseEnter,
|
|
2383
|
+
onMouseLeave,
|
|
2384
|
+
onPointerDown,
|
|
2385
|
+
...rest
|
|
2386
|
+
}, ref) => {
|
|
2387
|
+
const eventBus = useEventBus();
|
|
2388
|
+
const handleClick = React7.useCallback((e) => {
|
|
3726
2389
|
if (action) {
|
|
2390
|
+
e.stopPropagation();
|
|
3727
2391
|
eventBus.emit(`UI:${action}`, actionPayload ?? {});
|
|
3728
2392
|
}
|
|
3729
2393
|
onClick?.(e);
|
|
3730
|
-
};
|
|
3731
|
-
|
|
3732
|
-
|
|
2394
|
+
}, [action, actionPayload, eventBus, onClick]);
|
|
2395
|
+
const handleMouseEnter = React7.useCallback((e) => {
|
|
2396
|
+
if (hoverEvent) {
|
|
2397
|
+
eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
2398
|
+
}
|
|
2399
|
+
onMouseEnter?.(e);
|
|
2400
|
+
}, [hoverEvent, eventBus, onMouseEnter]);
|
|
2401
|
+
const handleMouseLeave = React7.useCallback((e) => {
|
|
2402
|
+
if (hoverEvent) {
|
|
2403
|
+
eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
2404
|
+
}
|
|
2405
|
+
onMouseLeave?.(e);
|
|
2406
|
+
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
2407
|
+
const { triggerProps } = useTapReveal({
|
|
2408
|
+
enabled: tapReveal && !!hoverEvent,
|
|
2409
|
+
onReveal: React7.useCallback(() => {
|
|
2410
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
2411
|
+
}, [hoverEvent, eventBus]),
|
|
2412
|
+
onDismiss: React7.useCallback(() => {
|
|
2413
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
2414
|
+
}, [hoverEvent, eventBus])
|
|
2415
|
+
});
|
|
2416
|
+
const handlePointerDown = React7.useCallback((e) => {
|
|
2417
|
+
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
2418
|
+
onPointerDown?.(e);
|
|
2419
|
+
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
2420
|
+
const isClickable = action || onClick;
|
|
2421
|
+
return React7__default.default.createElement(
|
|
2422
|
+
Component2,
|
|
3733
2423
|
{
|
|
3734
2424
|
ref,
|
|
3735
|
-
disabled: disabled || isLoading,
|
|
3736
2425
|
className: cn(
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
2426
|
+
padding && paddingStyles[padding],
|
|
2427
|
+
paddingX && paddingXStyles[paddingX],
|
|
2428
|
+
paddingY && paddingYStyles[paddingY],
|
|
2429
|
+
margin && marginStyles[margin],
|
|
2430
|
+
marginX && marginXStyles[marginX],
|
|
2431
|
+
marginY && marginYStyles[marginY],
|
|
2432
|
+
bgStyles[bg],
|
|
2433
|
+
border && "border-[length:var(--border-width)] border-border",
|
|
2434
|
+
roundedStyles[rounded],
|
|
2435
|
+
shadowStyles[shadow],
|
|
2436
|
+
display && displayStyles[display],
|
|
2437
|
+
fullWidth && "w-full",
|
|
2438
|
+
fullHeight && "h-full",
|
|
2439
|
+
overflow && overflowStyles[overflow],
|
|
2440
|
+
position && positionStyles[position],
|
|
2441
|
+
isClickable && "cursor-pointer",
|
|
3746
2442
|
className
|
|
3747
2443
|
),
|
|
3748
|
-
onClick: handleClick,
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
}
|
|
2444
|
+
onClick: isClickable ? handleClick : void 0,
|
|
2445
|
+
onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
|
|
2446
|
+
onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
|
|
2447
|
+
onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
|
|
2448
|
+
style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
|
|
2449
|
+
...rest
|
|
2450
|
+
},
|
|
2451
|
+
children
|
|
3757
2452
|
);
|
|
3758
2453
|
}
|
|
3759
2454
|
);
|
|
3760
|
-
|
|
3761
|
-
var
|
|
2455
|
+
Box.displayName = "Box";
|
|
2456
|
+
var variantStyles = {
|
|
3762
2457
|
h1: "text-4xl font-bold tracking-tight text-foreground",
|
|
3763
2458
|
h2: "text-3xl font-bold tracking-tight text-foreground",
|
|
3764
2459
|
h3: "text-2xl font-bold text-foreground",
|
|
@@ -3819,7 +2514,7 @@ var typographySizeStyles = {
|
|
|
3819
2514
|
"2xl": "text-2xl",
|
|
3820
2515
|
"3xl": "text-3xl"
|
|
3821
2516
|
};
|
|
3822
|
-
var
|
|
2517
|
+
var overflowStyles2 = {
|
|
3823
2518
|
visible: "overflow-visible",
|
|
3824
2519
|
hidden: "overflow-hidden",
|
|
3825
2520
|
wrap: "break-words overflow-hidden",
|
|
@@ -3844,18 +2539,18 @@ var Typography = ({
|
|
|
3844
2539
|
}) => {
|
|
3845
2540
|
const variant = variantProp ?? (level ? `h${level}` : "body1");
|
|
3846
2541
|
const Component2 = as || defaultElements[variant];
|
|
3847
|
-
return
|
|
2542
|
+
return React7__default.default.createElement(
|
|
3848
2543
|
Component2,
|
|
3849
2544
|
{
|
|
3850
2545
|
id,
|
|
3851
2546
|
className: cn(
|
|
3852
|
-
|
|
2547
|
+
variantStyles[variant],
|
|
3853
2548
|
colorStyles[color],
|
|
3854
2549
|
weight && weightStyles[weight],
|
|
3855
2550
|
size && typographySizeStyles[size],
|
|
3856
2551
|
align && `text-${align}`,
|
|
3857
2552
|
truncate && "truncate overflow-hidden text-ellipsis",
|
|
3858
|
-
overflow &&
|
|
2553
|
+
overflow && overflowStyles2[overflow],
|
|
3859
2554
|
className
|
|
3860
2555
|
),
|
|
3861
2556
|
style
|
|
@@ -3917,7 +2612,7 @@ var Stack = ({
|
|
|
3917
2612
|
};
|
|
3918
2613
|
const isHorizontal = direction === "horizontal";
|
|
3919
2614
|
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";
|
|
3920
|
-
return
|
|
2615
|
+
return React7__default.default.createElement(
|
|
3921
2616
|
Component2,
|
|
3922
2617
|
{
|
|
3923
2618
|
className: cn(
|
|
@@ -3942,939 +2637,6 @@ var Stack = ({
|
|
|
3942
2637
|
var VStack = (props) => /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "vertical", ...props });
|
|
3943
2638
|
var HStack = (props) => /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "horizontal", ...props });
|
|
3944
2639
|
|
|
3945
|
-
// components/game/shared/boardEntity.ts
|
|
3946
|
-
function boardEntity(entity) {
|
|
3947
|
-
if (!entity) return void 0;
|
|
3948
|
-
return Array.isArray(entity) ? entity[0] : entity;
|
|
3949
|
-
}
|
|
3950
|
-
function str(v) {
|
|
3951
|
-
return v == null ? "" : String(v);
|
|
3952
|
-
}
|
|
3953
|
-
function num(v, fallback = 0) {
|
|
3954
|
-
const n = Number(v);
|
|
3955
|
-
return Number.isFinite(n) ? n : fallback;
|
|
3956
|
-
}
|
|
3957
|
-
function rows(v) {
|
|
3958
|
-
return Array.isArray(v) ? v : [];
|
|
3959
|
-
}
|
|
3960
|
-
function vec2(v) {
|
|
3961
|
-
const o = v ?? {};
|
|
3962
|
-
return { x: num(o.x), y: num(o.y) };
|
|
3963
|
-
}
|
|
3964
|
-
function unitPosition(u) {
|
|
3965
|
-
return vec2(u.position);
|
|
3966
|
-
}
|
|
3967
|
-
function unitTeam(u) {
|
|
3968
|
-
return str(u.team);
|
|
3969
|
-
}
|
|
3970
|
-
function unitHealth(u) {
|
|
3971
|
-
return num(u.health);
|
|
3972
|
-
}
|
|
3973
|
-
function GameBoard3D({
|
|
3974
|
-
entity,
|
|
3975
|
-
tiles = [],
|
|
3976
|
-
features = [],
|
|
3977
|
-
cameraMode = "perspective",
|
|
3978
|
-
backgroundColor = "#2a1a1a",
|
|
3979
|
-
unitScale = 1,
|
|
3980
|
-
scale = 0.45,
|
|
3981
|
-
tileClickEvent,
|
|
3982
|
-
unitClickEvent,
|
|
3983
|
-
attackEvent,
|
|
3984
|
-
endTurnEvent,
|
|
3985
|
-
cancelEvent,
|
|
3986
|
-
playAgainEvent,
|
|
3987
|
-
gameEndEvent,
|
|
3988
|
-
className
|
|
3989
|
-
}) {
|
|
3990
|
-
const row = boardEntity(entity);
|
|
3991
|
-
const eventBus = useEventBus();
|
|
3992
|
-
const entityUnits = row ? rows(row.units) : [];
|
|
3993
|
-
const units = entityUnits.map((r) => ({
|
|
3994
|
-
id: str(r.id),
|
|
3995
|
-
x: num(r.x),
|
|
3996
|
-
y: num(r.y),
|
|
3997
|
-
z: num(r.z),
|
|
3998
|
-
faction: str(r.faction) || "neutral",
|
|
3999
|
-
team: str(r.team) || str(r.faction) || "neutral",
|
|
4000
|
-
unitType: r.unitType == null ? void 0 : str(r.unitType),
|
|
4001
|
-
name: r.name == null ? void 0 : str(r.name),
|
|
4002
|
-
health: r.health == null ? void 0 : num(r.health),
|
|
4003
|
-
maxHealth: r.maxHealth == null ? void 0 : num(r.maxHealth)
|
|
4004
|
-
}));
|
|
4005
|
-
const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
|
|
4006
|
-
const phase = row ? str(row.phase) : "observation";
|
|
4007
|
-
const result = row ? str(row.result) : "none";
|
|
4008
|
-
const validMoves = row && Array.isArray(row.validMoves) ? row.validMoves : [];
|
|
4009
|
-
const attackTargets = row && Array.isArray(row.attackTargets) ? row.attackTargets : [];
|
|
4010
|
-
const turn = row ? num(row.turn) : 0;
|
|
4011
|
-
const currentTeam = row ? str(row.currentTeam) : "player";
|
|
4012
|
-
const isGameOver = result !== "none";
|
|
4013
|
-
const gameEndEmittedRef = React10.useRef(false);
|
|
4014
|
-
React10.useEffect(() => {
|
|
4015
|
-
if ((result === "victory" || result === "defeat") && gameEndEvent) {
|
|
4016
|
-
if (!gameEndEmittedRef.current) {
|
|
4017
|
-
gameEndEmittedRef.current = true;
|
|
4018
|
-
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
4019
|
-
}
|
|
4020
|
-
} else {
|
|
4021
|
-
gameEndEmittedRef.current = false;
|
|
4022
|
-
}
|
|
4023
|
-
}, [result, gameEndEvent, eventBus]);
|
|
4024
|
-
const checkGameEnd = React10.useCallback(() => {
|
|
4025
|
-
const alivePlayer = entityUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
4026
|
-
const aliveEnemy = entityUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
4027
|
-
if (alivePlayer.length === 0 && gameEndEvent) {
|
|
4028
|
-
eventBus.emit(`UI:${gameEndEvent}`, { result: "defeat" });
|
|
4029
|
-
} else if (aliveEnemy.length === 0 && gameEndEvent) {
|
|
4030
|
-
eventBus.emit(`UI:${gameEndEvent}`, { result: "victory" });
|
|
4031
|
-
}
|
|
4032
|
-
}, [entityUnits, gameEndEvent, eventBus]);
|
|
4033
|
-
const handleUnitClickCallback = React10.useCallback((isoUnit) => {
|
|
4034
|
-
if (phase !== "action" || !selectedUnitId || !attackEvent) return;
|
|
4035
|
-
const attackerRow = entityUnits.find((u) => str(u.id) === selectedUnitId);
|
|
4036
|
-
const targetRow = entityUnits.find((u) => str(u.id) === isoUnit.id);
|
|
4037
|
-
if (!attackerRow || !targetRow) return;
|
|
4038
|
-
if (unitTeam(targetRow) !== "enemy" || unitHealth(targetRow) <= 0) return;
|
|
4039
|
-
const ap = unitPosition(attackerRow);
|
|
4040
|
-
const tp = unitPosition(targetRow);
|
|
4041
|
-
const dx = Math.abs(ap.x - tp.x);
|
|
4042
|
-
const dy = Math.abs(ap.y - tp.y);
|
|
4043
|
-
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
4044
|
-
const damage = Math.max(1, num(attackerRow.attack) - num(targetRow.defense));
|
|
4045
|
-
eventBus.emit(`UI:${attackEvent}`, {
|
|
4046
|
-
attackerId: str(attackerRow.id),
|
|
4047
|
-
targetId: str(targetRow.id),
|
|
4048
|
-
damage
|
|
4049
|
-
});
|
|
4050
|
-
setTimeout(checkGameEnd, 100);
|
|
4051
|
-
}
|
|
4052
|
-
}, [phase, selectedUnitId, entityUnits, attackEvent, eventBus, checkGameEnd]);
|
|
4053
|
-
const handleEndTurn = React10.useCallback(() => {
|
|
4054
|
-
if (endTurnEvent) eventBus.emit(`UI:${endTurnEvent}`, {});
|
|
4055
|
-
}, [endTurnEvent, eventBus]);
|
|
4056
|
-
const handleCancel = React10.useCallback(() => {
|
|
4057
|
-
if (cancelEvent) eventBus.emit(`UI:${cancelEvent}`, {});
|
|
4058
|
-
}, [cancelEvent, eventBus]);
|
|
4059
|
-
const handlePlayAgain = React10.useCallback(() => {
|
|
4060
|
-
if (playAgainEvent) eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
4061
|
-
}, [playAgainEvent, eventBus]);
|
|
4062
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("game-board-3d block w-full min-h-[85vh] relative", className), children: [
|
|
4063
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-board-3d__status absolute top-3 left-3 z-10 flex gap-2 items-center", children: [
|
|
4064
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "status__phase capitalize", children: phase.replace("_", " ") }),
|
|
4065
|
-
currentTeam && !isGameOver && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", color: "muted", className: "status__team", children: [
|
|
4066
|
-
"\u2014 ",
|
|
4067
|
-
currentTeam === "player" ? "Your Turn" : "Enemy's Turn"
|
|
4068
|
-
] }),
|
|
4069
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", color: "muted", className: "status__turn", children: [
|
|
4070
|
-
"Turn ",
|
|
4071
|
-
turn
|
|
4072
|
-
] })
|
|
4073
|
-
] }),
|
|
4074
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4075
|
-
GameCanvas3D,
|
|
4076
|
-
{
|
|
4077
|
-
tiles,
|
|
4078
|
-
units,
|
|
4079
|
-
features,
|
|
4080
|
-
cameraMode,
|
|
4081
|
-
showGrid: true,
|
|
4082
|
-
showCoordinates: false,
|
|
4083
|
-
showTileInfo: false,
|
|
4084
|
-
shadows: true,
|
|
4085
|
-
backgroundColor,
|
|
4086
|
-
tileClickEvent,
|
|
4087
|
-
unitClickEvent,
|
|
4088
|
-
onUnitClick: handleUnitClickCallback,
|
|
4089
|
-
selectedUnitId,
|
|
4090
|
-
validMoves,
|
|
4091
|
-
attackTargets,
|
|
4092
|
-
unitScale,
|
|
4093
|
-
scale,
|
|
4094
|
-
className: "game-board-3d__canvas w-full min-h-[85vh]"
|
|
4095
|
-
}
|
|
4096
|
-
),
|
|
4097
|
-
!isGameOver && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "fixed bottom-6 right-6 z-50", gap: "sm", children: [
|
|
4098
|
-
(phase === "selection" || phase === "movement" || phase === "action") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4099
|
-
Button,
|
|
4100
|
-
{
|
|
4101
|
-
variant: "secondary",
|
|
4102
|
-
className: "shadow-xl",
|
|
4103
|
-
onClick: handleCancel,
|
|
4104
|
-
children: "Cancel"
|
|
4105
|
-
}
|
|
4106
|
-
),
|
|
4107
|
-
phase !== "enemy_turn" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4108
|
-
Button,
|
|
4109
|
-
{
|
|
4110
|
-
variant: "primary",
|
|
4111
|
-
className: "shadow-xl",
|
|
4112
|
-
onClick: handleEndTurn,
|
|
4113
|
-
children: "End Turn"
|
|
4114
|
-
}
|
|
4115
|
-
)
|
|
4116
|
-
] }),
|
|
4117
|
-
isGameOver && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "game-board-3d__overlay absolute inset-0 z-20 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { align: "center", gap: "md", className: "overlay__card p-8 rounded-xl bg-gray-900/90 shadow-2xl", children: [
|
|
4118
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4119
|
-
Typography,
|
|
4120
|
-
{
|
|
4121
|
-
variant: "h2",
|
|
4122
|
-
className: cn(
|
|
4123
|
-
"overlay__result",
|
|
4124
|
-
result === "victory" ? "text-yellow-400" : "text-red-500"
|
|
4125
|
-
),
|
|
4126
|
-
children: result === "victory" ? "Victory!" : "Defeat"
|
|
4127
|
-
}
|
|
4128
|
-
),
|
|
4129
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "body", color: "muted", className: "overlay__turn-count", children: [
|
|
4130
|
-
"Completed in ",
|
|
4131
|
-
turn,
|
|
4132
|
-
" turn",
|
|
4133
|
-
turn !== 1 ? "s" : ""
|
|
4134
|
-
] }),
|
|
4135
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4136
|
-
Button,
|
|
4137
|
-
{
|
|
4138
|
-
variant: "primary",
|
|
4139
|
-
className: "px-8 py-3 font-semibold",
|
|
4140
|
-
onClick: handlePlayAgain,
|
|
4141
|
-
children: "Play Again"
|
|
4142
|
-
}
|
|
4143
|
-
)
|
|
4144
|
-
] }) })
|
|
4145
|
-
] });
|
|
4146
|
-
}
|
|
4147
|
-
GameBoard3D.displayName = "GameBoard3D";
|
|
4148
|
-
function useTapReveal(options = {}) {
|
|
4149
|
-
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
4150
|
-
const [revealed, setRevealed] = React10.useState(false);
|
|
4151
|
-
const onRevealRef = React10.useRef(onReveal);
|
|
4152
|
-
const onDismissRef = React10.useRef(onDismiss);
|
|
4153
|
-
onRevealRef.current = onReveal;
|
|
4154
|
-
onDismissRef.current = onDismiss;
|
|
4155
|
-
const reveal = React10.useCallback(() => {
|
|
4156
|
-
setRevealed((wasRevealed) => {
|
|
4157
|
-
if (!wasRevealed) onRevealRef.current?.();
|
|
4158
|
-
return true;
|
|
4159
|
-
});
|
|
4160
|
-
}, []);
|
|
4161
|
-
const dismiss = React10.useCallback(() => {
|
|
4162
|
-
setRevealed((wasRevealed) => {
|
|
4163
|
-
if (wasRevealed) onDismissRef.current?.();
|
|
4164
|
-
return false;
|
|
4165
|
-
});
|
|
4166
|
-
}, []);
|
|
4167
|
-
const onPointerDown = React10.useCallback(
|
|
4168
|
-
(e) => {
|
|
4169
|
-
if (!enabled || e.pointerType === "mouse") return;
|
|
4170
|
-
if (revealed) dismiss();
|
|
4171
|
-
else reveal();
|
|
4172
|
-
},
|
|
4173
|
-
[enabled, revealed, reveal, dismiss]
|
|
4174
|
-
);
|
|
4175
|
-
React10.useEffect(() => {
|
|
4176
|
-
if (!revealed || typeof document === "undefined") return;
|
|
4177
|
-
const onDocDown = (ev) => {
|
|
4178
|
-
const target = ev.target;
|
|
4179
|
-
if (!(target instanceof Node)) return;
|
|
4180
|
-
const inside = (refs ?? []).some((r) => r.current?.contains(target));
|
|
4181
|
-
if (!inside) dismiss();
|
|
4182
|
-
};
|
|
4183
|
-
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
4184
|
-
return () => {
|
|
4185
|
-
clearTimeout(id);
|
|
4186
|
-
document.removeEventListener("pointerdown", onDocDown);
|
|
4187
|
-
};
|
|
4188
|
-
}, [revealed, refs, dismiss]);
|
|
4189
|
-
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
4190
|
-
}
|
|
4191
|
-
|
|
4192
|
-
// components/core/atoms/Box.tsx
|
|
4193
|
-
var paddingStyles = {
|
|
4194
|
-
none: "p-0",
|
|
4195
|
-
xs: "p-1",
|
|
4196
|
-
sm: "p-2",
|
|
4197
|
-
md: "p-4",
|
|
4198
|
-
lg: "p-6",
|
|
4199
|
-
xl: "p-8",
|
|
4200
|
-
"2xl": "p-12"
|
|
4201
|
-
};
|
|
4202
|
-
var paddingXStyles = {
|
|
4203
|
-
none: "px-0",
|
|
4204
|
-
xs: "px-1",
|
|
4205
|
-
sm: "px-2",
|
|
4206
|
-
md: "px-4",
|
|
4207
|
-
lg: "px-6",
|
|
4208
|
-
xl: "px-8",
|
|
4209
|
-
"2xl": "px-12"
|
|
4210
|
-
};
|
|
4211
|
-
var paddingYStyles = {
|
|
4212
|
-
none: "py-0",
|
|
4213
|
-
xs: "py-1",
|
|
4214
|
-
sm: "py-2",
|
|
4215
|
-
md: "py-4",
|
|
4216
|
-
lg: "py-6",
|
|
4217
|
-
xl: "py-8",
|
|
4218
|
-
"2xl": "py-12"
|
|
4219
|
-
};
|
|
4220
|
-
var marginStyles = {
|
|
4221
|
-
none: "m-0",
|
|
4222
|
-
xs: "m-1",
|
|
4223
|
-
sm: "m-2",
|
|
4224
|
-
md: "m-4",
|
|
4225
|
-
lg: "m-6",
|
|
4226
|
-
xl: "m-8",
|
|
4227
|
-
"2xl": "m-12",
|
|
4228
|
-
auto: "m-auto"
|
|
4229
|
-
};
|
|
4230
|
-
var marginXStyles = {
|
|
4231
|
-
none: "mx-0",
|
|
4232
|
-
xs: "mx-1",
|
|
4233
|
-
sm: "mx-2",
|
|
4234
|
-
md: "mx-4",
|
|
4235
|
-
lg: "mx-6",
|
|
4236
|
-
xl: "mx-8",
|
|
4237
|
-
"2xl": "mx-12",
|
|
4238
|
-
auto: "mx-auto"
|
|
4239
|
-
};
|
|
4240
|
-
var marginYStyles = {
|
|
4241
|
-
none: "my-0",
|
|
4242
|
-
xs: "my-1",
|
|
4243
|
-
sm: "my-2",
|
|
4244
|
-
md: "my-4",
|
|
4245
|
-
lg: "my-6",
|
|
4246
|
-
xl: "my-8",
|
|
4247
|
-
"2xl": "my-12",
|
|
4248
|
-
auto: "my-auto"
|
|
4249
|
-
};
|
|
4250
|
-
var bgStyles = {
|
|
4251
|
-
transparent: "bg-transparent",
|
|
4252
|
-
primary: "bg-primary text-primary-foreground",
|
|
4253
|
-
secondary: "bg-secondary text-secondary-foreground",
|
|
4254
|
-
muted: "bg-muted text-foreground",
|
|
4255
|
-
accent: "bg-accent text-accent-foreground",
|
|
4256
|
-
surface: "bg-card",
|
|
4257
|
-
overlay: "bg-card/80 backdrop-blur-sm"
|
|
4258
|
-
};
|
|
4259
|
-
var roundedStyles = {
|
|
4260
|
-
none: "rounded-none",
|
|
4261
|
-
sm: "rounded-sm",
|
|
4262
|
-
md: "rounded-md",
|
|
4263
|
-
lg: "rounded-lg",
|
|
4264
|
-
xl: "rounded-xl",
|
|
4265
|
-
"2xl": "rounded-xl",
|
|
4266
|
-
full: "rounded-full"
|
|
4267
|
-
};
|
|
4268
|
-
var shadowStyles = {
|
|
4269
|
-
none: "shadow-none",
|
|
4270
|
-
sm: "shadow-sm",
|
|
4271
|
-
md: "shadow",
|
|
4272
|
-
lg: "shadow-lg",
|
|
4273
|
-
xl: "shadow-lg"
|
|
4274
|
-
};
|
|
4275
|
-
var displayStyles = {
|
|
4276
|
-
block: "block",
|
|
4277
|
-
inline: "inline",
|
|
4278
|
-
"inline-block": "inline-block",
|
|
4279
|
-
flex: "flex",
|
|
4280
|
-
"inline-flex": "inline-flex",
|
|
4281
|
-
grid: "grid"
|
|
4282
|
-
};
|
|
4283
|
-
var overflowStyles2 = {
|
|
4284
|
-
auto: "overflow-auto",
|
|
4285
|
-
hidden: "overflow-hidden",
|
|
4286
|
-
visible: "overflow-visible",
|
|
4287
|
-
scroll: "overflow-scroll"
|
|
4288
|
-
};
|
|
4289
|
-
var positionStyles = {
|
|
4290
|
-
relative: "relative",
|
|
4291
|
-
absolute: "absolute",
|
|
4292
|
-
fixed: "fixed",
|
|
4293
|
-
sticky: "sticky"
|
|
4294
|
-
};
|
|
4295
|
-
var Box = React10__namespace.default.forwardRef(
|
|
4296
|
-
({
|
|
4297
|
-
padding,
|
|
4298
|
-
paddingX,
|
|
4299
|
-
paddingY,
|
|
4300
|
-
margin,
|
|
4301
|
-
marginX,
|
|
4302
|
-
marginY,
|
|
4303
|
-
bg = "transparent",
|
|
4304
|
-
border = false,
|
|
4305
|
-
rounded = "none",
|
|
4306
|
-
shadow = "none",
|
|
4307
|
-
display,
|
|
4308
|
-
fullWidth = false,
|
|
4309
|
-
fullHeight = false,
|
|
4310
|
-
overflow,
|
|
4311
|
-
position,
|
|
4312
|
-
className,
|
|
4313
|
-
children,
|
|
4314
|
-
as: Component2 = "div",
|
|
4315
|
-
action,
|
|
4316
|
-
actionPayload,
|
|
4317
|
-
hoverEvent,
|
|
4318
|
-
tapReveal = true,
|
|
4319
|
-
maxWidth,
|
|
4320
|
-
onClick,
|
|
4321
|
-
onMouseEnter,
|
|
4322
|
-
onMouseLeave,
|
|
4323
|
-
onPointerDown,
|
|
4324
|
-
...rest
|
|
4325
|
-
}, ref) => {
|
|
4326
|
-
const eventBus = useEventBus();
|
|
4327
|
-
const handleClick = React10.useCallback((e) => {
|
|
4328
|
-
if (action) {
|
|
4329
|
-
e.stopPropagation();
|
|
4330
|
-
eventBus.emit(`UI:${action}`, actionPayload ?? {});
|
|
4331
|
-
}
|
|
4332
|
-
onClick?.(e);
|
|
4333
|
-
}, [action, actionPayload, eventBus, onClick]);
|
|
4334
|
-
const handleMouseEnter = React10.useCallback((e) => {
|
|
4335
|
-
if (hoverEvent) {
|
|
4336
|
-
eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
4337
|
-
}
|
|
4338
|
-
onMouseEnter?.(e);
|
|
4339
|
-
}, [hoverEvent, eventBus, onMouseEnter]);
|
|
4340
|
-
const handleMouseLeave = React10.useCallback((e) => {
|
|
4341
|
-
if (hoverEvent) {
|
|
4342
|
-
eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
4343
|
-
}
|
|
4344
|
-
onMouseLeave?.(e);
|
|
4345
|
-
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
4346
|
-
const { triggerProps } = useTapReveal({
|
|
4347
|
-
enabled: tapReveal && !!hoverEvent,
|
|
4348
|
-
onReveal: React10.useCallback(() => {
|
|
4349
|
-
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
4350
|
-
}, [hoverEvent, eventBus]),
|
|
4351
|
-
onDismiss: React10.useCallback(() => {
|
|
4352
|
-
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
4353
|
-
}, [hoverEvent, eventBus])
|
|
4354
|
-
});
|
|
4355
|
-
const handlePointerDown = React10.useCallback((e) => {
|
|
4356
|
-
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
4357
|
-
onPointerDown?.(e);
|
|
4358
|
-
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
4359
|
-
const isClickable = action || onClick;
|
|
4360
|
-
return React10__namespace.default.createElement(
|
|
4361
|
-
Component2,
|
|
4362
|
-
{
|
|
4363
|
-
ref,
|
|
4364
|
-
className: cn(
|
|
4365
|
-
padding && paddingStyles[padding],
|
|
4366
|
-
paddingX && paddingXStyles[paddingX],
|
|
4367
|
-
paddingY && paddingYStyles[paddingY],
|
|
4368
|
-
margin && marginStyles[margin],
|
|
4369
|
-
marginX && marginXStyles[marginX],
|
|
4370
|
-
marginY && marginYStyles[marginY],
|
|
4371
|
-
bgStyles[bg],
|
|
4372
|
-
border && "border-[length:var(--border-width)] border-border",
|
|
4373
|
-
roundedStyles[rounded],
|
|
4374
|
-
shadowStyles[shadow],
|
|
4375
|
-
display && displayStyles[display],
|
|
4376
|
-
fullWidth && "w-full",
|
|
4377
|
-
fullHeight && "h-full",
|
|
4378
|
-
overflow && overflowStyles2[overflow],
|
|
4379
|
-
position && positionStyles[position],
|
|
4380
|
-
isClickable && "cursor-pointer",
|
|
4381
|
-
className
|
|
4382
|
-
),
|
|
4383
|
-
onClick: isClickable ? handleClick : void 0,
|
|
4384
|
-
onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
|
|
4385
|
-
onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
|
|
4386
|
-
onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
|
|
4387
|
-
style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
|
|
4388
|
-
...rest
|
|
4389
|
-
},
|
|
4390
|
-
children
|
|
4391
|
-
);
|
|
4392
|
-
}
|
|
4393
|
-
);
|
|
4394
|
-
Box.displayName = "Box";
|
|
4395
|
-
|
|
4396
|
-
// components/game/shared/makeAsset.ts
|
|
4397
|
-
var ROLE_DEFAULTS = {
|
|
4398
|
-
tile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
|
|
4399
|
-
decoration: { dimension: "2d", animations: ["static"], aspect: "1:1" },
|
|
4400
|
-
effect: { dimension: "2d", animations: ["static"], aspect: "1:1" },
|
|
4401
|
-
item: { dimension: "2d", animations: ["static"], aspect: "5:7" },
|
|
4402
|
-
player: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
|
|
4403
|
-
enemy: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
|
|
4404
|
-
npc: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
|
|
4405
|
-
projectile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
|
|
4406
|
-
vehicle: { dimension: "2d", animations: ["idle", "walk"], aspect: "1:1" },
|
|
4407
|
-
ui: { dimension: "2d", animations: ["static"], aspect: "1:1" }
|
|
4408
|
-
};
|
|
4409
|
-
function makeAsset(url, role, overrides = {}) {
|
|
4410
|
-
const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
|
|
4411
|
-
return {
|
|
4412
|
-
url,
|
|
4413
|
-
role,
|
|
4414
|
-
category: url.split("/").pop()?.replace(/\.[^.]+$/, "") ?? role,
|
|
4415
|
-
...defaults,
|
|
4416
|
-
...overrides
|
|
4417
|
-
};
|
|
4418
|
-
}
|
|
4419
|
-
|
|
4420
|
-
// components/game/shared/lib/game3dAssetManifest.ts
|
|
4421
|
-
function tileKind(type, passable) {
|
|
4422
|
-
if (passable === false) return "wall";
|
|
4423
|
-
if (type === "dirt" || type === "road") return "dirt";
|
|
4424
|
-
return "open";
|
|
4425
|
-
}
|
|
4426
|
-
function resolveTilesWithModels(layout, manifest) {
|
|
4427
|
-
return layout.map((t) => {
|
|
4428
|
-
const kind = t.kind || tileKind(t.type, t.passable);
|
|
4429
|
-
return {
|
|
4430
|
-
id: t.id,
|
|
4431
|
-
x: t.x,
|
|
4432
|
-
y: t.y,
|
|
4433
|
-
z: t.z,
|
|
4434
|
-
type: t.type,
|
|
4435
|
-
passable: t.passable,
|
|
4436
|
-
modelUrl: manifest?.models?.[kind]
|
|
4437
|
-
};
|
|
4438
|
-
});
|
|
4439
|
-
}
|
|
4440
|
-
function resolvePropTiles(tiles, manifest) {
|
|
4441
|
-
return tiles.map((t) => {
|
|
4442
|
-
const kind = tileKind(t.type ?? "", t.passable);
|
|
4443
|
-
return {
|
|
4444
|
-
...t,
|
|
4445
|
-
modelUrl: t.modelUrl ?? manifest?.models?.[kind]
|
|
4446
|
-
};
|
|
4447
|
-
});
|
|
4448
|
-
}
|
|
4449
|
-
function resolveEntityTiles(entity, manifest) {
|
|
4450
|
-
const row = boardEntity(entity);
|
|
4451
|
-
if (!row) return [];
|
|
4452
|
-
return rows(row.tiles).map((r) => {
|
|
4453
|
-
const type = str(r.type) || str(r.terrain);
|
|
4454
|
-
const passable = r.passable !== false;
|
|
4455
|
-
const kind = tileKind(type, passable);
|
|
4456
|
-
const explicitModelUrl = r.modelUrl == null ? void 0 : str(r.modelUrl);
|
|
4457
|
-
const explicitModel = explicitModelUrl ? makeAsset(explicitModelUrl, "decoration", { dimension: "3d" }) : void 0;
|
|
4458
|
-
return {
|
|
4459
|
-
id: r.id == null ? void 0 : str(r.id),
|
|
4460
|
-
x: num(r.x),
|
|
4461
|
-
y: num(r.y),
|
|
4462
|
-
z: r.z == null ? void 0 : num(r.z),
|
|
4463
|
-
type,
|
|
4464
|
-
passable,
|
|
4465
|
-
modelUrl: explicitModel ?? manifest?.models?.[kind]
|
|
4466
|
-
};
|
|
4467
|
-
});
|
|
4468
|
-
}
|
|
4469
|
-
function resolveFeaturesWithModels(features, manifest) {
|
|
4470
|
-
return features.map((f) => ({
|
|
4471
|
-
...f,
|
|
4472
|
-
assetUrl: f.assetUrl ?? manifest?.features?.[f.type]
|
|
4473
|
-
}));
|
|
4474
|
-
}
|
|
4475
|
-
function resolveEntityFeatures(entity, manifest) {
|
|
4476
|
-
const row = boardEntity(entity);
|
|
4477
|
-
if (!row) return [];
|
|
4478
|
-
return rows(row.features).map((r) => {
|
|
4479
|
-
const type = str(r.type);
|
|
4480
|
-
const explicitUrl = r.assetUrl == null ? void 0 : str(r.assetUrl);
|
|
4481
|
-
const explicit = explicitUrl ? makeAsset(explicitUrl, "decoration", { dimension: "3d" }) : void 0;
|
|
4482
|
-
return {
|
|
4483
|
-
id: r.id == null ? void 0 : str(r.id),
|
|
4484
|
-
x: num(r.x),
|
|
4485
|
-
y: num(r.y),
|
|
4486
|
-
z: r.z == null ? void 0 : num(r.z),
|
|
4487
|
-
type,
|
|
4488
|
-
color: r.color == null ? void 0 : str(r.color),
|
|
4489
|
-
assetUrl: explicit ?? manifest?.features?.[type]
|
|
4490
|
-
};
|
|
4491
|
-
});
|
|
4492
|
-
}
|
|
4493
|
-
var DEFAULT_3D_BATTLE_LAYOUT = [
|
|
4494
|
-
{ id: "t00", x: 0, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
|
|
4495
|
-
{ id: "t10", x: 1, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
|
|
4496
|
-
{ id: "t20", x: 2, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
|
|
4497
|
-
{ id: "t30", x: 3, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
|
|
4498
|
-
{ id: "t40", x: 4, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
|
|
4499
|
-
{ id: "t01", x: 0, y: 1, z: 1, type: "stone", passable: false, kind: "wall" },
|
|
4500
|
-
{ id: "t11", x: 1, y: 1, z: 1, type: "dirt", passable: true, kind: "dirt" },
|
|
4501
|
-
{ id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
|
|
4502
|
-
{ id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
|
|
4503
|
-
{ id: "t41", x: 4, y: 1, z: 1, type: "stone", passable: false, kind: "wall" },
|
|
4504
|
-
{ id: "t02", x: 0, y: 2, z: 2, type: "stone", passable: false, kind: "wall" },
|
|
4505
|
-
{ id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
|
|
4506
|
-
{ id: "t22", x: 2, y: 2, z: 2, type: "dirt", passable: true, kind: "dirt" },
|
|
4507
|
-
{ id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
|
|
4508
|
-
{ id: "t42", x: 4, y: 2, z: 2, type: "stone", passable: false, kind: "wall" },
|
|
4509
|
-
{ id: "t03", x: 0, y: 3, z: 3, type: "stone", passable: false, kind: "wall" },
|
|
4510
|
-
{ id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
|
|
4511
|
-
{ id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
|
|
4512
|
-
{ id: "t33", x: 3, y: 3, z: 3, type: "dirt", passable: true, kind: "dirt" },
|
|
4513
|
-
{ id: "t43", x: 4, y: 3, z: 3, type: "stone", passable: false, kind: "wall" },
|
|
4514
|
-
{ id: "t04", x: 0, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
|
|
4515
|
-
{ id: "t14", x: 1, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
|
|
4516
|
-
{ id: "t24", x: 2, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
|
|
4517
|
-
{ id: "t34", x: 3, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
|
|
4518
|
-
{ id: "t44", x: 4, y: 4, z: 4, type: "stone", passable: false, kind: "wall" }
|
|
4519
|
-
];
|
|
4520
|
-
var DEFAULT_3D_BATTLE_FEATURES = [
|
|
4521
|
-
{ id: "f1", x: 2, y: 2, z: 2, type: "gold_mine", color: "#f4c542" },
|
|
4522
|
-
{ id: "f2", x: 3, y: 1, z: 1, type: "portal", color: "#8b5cf6" }
|
|
4523
|
-
];
|
|
4524
|
-
function GameCanvas3DBattleTemplate({
|
|
4525
|
-
entity,
|
|
4526
|
-
tiles: propTiles,
|
|
4527
|
-
features: propFeatures = DEFAULT_3D_BATTLE_FEATURES,
|
|
4528
|
-
assetManifest,
|
|
4529
|
-
cameraMode = "perspective",
|
|
4530
|
-
backgroundColor = "#2a1a1a",
|
|
4531
|
-
tileClickEvent,
|
|
4532
|
-
unitClickEvent,
|
|
4533
|
-
endTurnEvent,
|
|
4534
|
-
cancelEvent,
|
|
4535
|
-
attackEvent,
|
|
4536
|
-
playAgainEvent,
|
|
4537
|
-
gameEndEvent,
|
|
4538
|
-
unitScale,
|
|
4539
|
-
scale,
|
|
4540
|
-
className
|
|
4541
|
-
}) {
|
|
4542
|
-
const row = boardEntity(entity);
|
|
4543
|
-
const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
|
|
4544
|
-
const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_BATTLE_LAYOUT, assetManifest);
|
|
4545
|
-
const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
|
|
4546
|
-
const currentTurn = row?.currentTeam == null ? void 0 : String(row.currentTeam);
|
|
4547
|
-
const round = row?.turn == null ? void 0 : Number(row.turn);
|
|
4548
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4549
|
-
Box,
|
|
4550
|
-
{
|
|
4551
|
-
className: cn("game-canvas-3d-battle-template block relative w-full min-h-[85vh]", className),
|
|
4552
|
-
children: [
|
|
4553
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4554
|
-
GameBoard3D,
|
|
4555
|
-
{
|
|
4556
|
-
entity,
|
|
4557
|
-
tiles,
|
|
4558
|
-
features,
|
|
4559
|
-
cameraMode,
|
|
4560
|
-
backgroundColor,
|
|
4561
|
-
unitScale,
|
|
4562
|
-
scale,
|
|
4563
|
-
tileClickEvent,
|
|
4564
|
-
unitClickEvent,
|
|
4565
|
-
endTurnEvent,
|
|
4566
|
-
cancelEvent,
|
|
4567
|
-
attackEvent,
|
|
4568
|
-
playAgainEvent,
|
|
4569
|
-
gameEndEvent,
|
|
4570
|
-
className: "game-canvas-3d-battle-template__board"
|
|
4571
|
-
}
|
|
4572
|
-
),
|
|
4573
|
-
currentTurn && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4574
|
-
HStack,
|
|
4575
|
-
{
|
|
4576
|
-
gap: "sm",
|
|
4577
|
-
align: "center",
|
|
4578
|
-
className: cn("battle-template__turn-indicator absolute top-3 right-3 z-10", `battle-template__turn-indicator--${currentTurn}`),
|
|
4579
|
-
children: [
|
|
4580
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "turn-indicator__label", children: currentTurn === "player" ? "Your Turn" : "Enemy's Turn" }),
|
|
4581
|
-
round != null && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "turn-indicator__round", children: [
|
|
4582
|
-
"Round ",
|
|
4583
|
-
round
|
|
4584
|
-
] })
|
|
4585
|
-
]
|
|
4586
|
-
}
|
|
4587
|
-
)
|
|
4588
|
-
]
|
|
4589
|
-
}
|
|
4590
|
-
);
|
|
4591
|
-
}
|
|
4592
|
-
GameCanvas3DBattleTemplate.displayName = "GameCanvas3DBattleTemplate";
|
|
4593
|
-
var DEFAULT_3D_CASTLE_LAYOUT = [
|
|
4594
|
-
{ id: "t00", x: 0, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
|
|
4595
|
-
{ id: "t10", x: 1, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
|
|
4596
|
-
{ id: "t20", x: 2, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
|
|
4597
|
-
{ id: "t30", x: 3, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
|
|
4598
|
-
{ id: "t40", x: 4, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
|
|
4599
|
-
{ id: "t01", x: 0, y: 1, z: 1, type: "wall", passable: false, kind: "wall" },
|
|
4600
|
-
{ id: "t11", x: 1, y: 1, z: 1, type: "floor", passable: true, kind: "dirt" },
|
|
4601
|
-
{ id: "t21", x: 2, y: 1, z: 1, type: "floor", passable: true, kind: "open" },
|
|
4602
|
-
{ id: "t31", x: 3, y: 1, z: 1, type: "floor", passable: true, kind: "open" },
|
|
4603
|
-
{ id: "t41", x: 4, y: 1, z: 1, type: "wall", passable: false, kind: "wall" },
|
|
4604
|
-
{ id: "t02", x: 0, y: 2, z: 2, type: "wall", passable: false, kind: "wall" },
|
|
4605
|
-
{ id: "t12", x: 1, y: 2, z: 2, type: "floor", passable: true, kind: "open" },
|
|
4606
|
-
{ id: "t22", x: 2, y: 2, z: 2, type: "floor", passable: true, kind: "dirt" },
|
|
4607
|
-
{ id: "t32", x: 3, y: 2, z: 2, type: "floor", passable: true, kind: "open" },
|
|
4608
|
-
{ id: "t42", x: 4, y: 2, z: 2, type: "wall", passable: false, kind: "wall" },
|
|
4609
|
-
{ id: "t03", x: 0, y: 3, z: 3, type: "wall", passable: false, kind: "wall" },
|
|
4610
|
-
{ id: "t13", x: 1, y: 3, z: 3, type: "floor", passable: true, kind: "open" },
|
|
4611
|
-
{ id: "t23", x: 2, y: 3, z: 3, type: "floor", passable: true, kind: "open" },
|
|
4612
|
-
{ id: "t33", x: 3, y: 3, z: 3, type: "floor", passable: true, kind: "dirt" },
|
|
4613
|
-
{ id: "t43", x: 4, y: 3, z: 3, type: "wall", passable: false, kind: "wall" },
|
|
4614
|
-
{ id: "t04", x: 0, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
|
|
4615
|
-
{ id: "t14", x: 1, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
|
|
4616
|
-
{ id: "t24", x: 2, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
|
|
4617
|
-
{ id: "t34", x: 3, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
|
|
4618
|
-
{ id: "t44", x: 4, y: 4, z: 4, type: "wall", passable: false, kind: "wall" }
|
|
4619
|
-
];
|
|
4620
|
-
var DEFAULT_3D_CASTLE_FEATURES = [
|
|
4621
|
-
{ id: "f1", x: 2, y: 2, z: 2, type: "chest", color: "#f4c542" },
|
|
4622
|
-
{ id: "f2", x: 3, y: 1, z: 1, type: "crystal", color: "#8b5cf6" }
|
|
4623
|
-
];
|
|
4624
|
-
function GameCanvas3DCastleTemplate({
|
|
4625
|
-
entity,
|
|
4626
|
-
tiles: propTiles,
|
|
4627
|
-
features: propFeatures = DEFAULT_3D_CASTLE_FEATURES,
|
|
4628
|
-
assetManifest,
|
|
4629
|
-
cameraMode = "isometric",
|
|
4630
|
-
backgroundColor = "#1e1e2e",
|
|
4631
|
-
buildingClickEvent,
|
|
4632
|
-
unitClickEvent,
|
|
4633
|
-
endTurnEvent,
|
|
4634
|
-
cancelEvent,
|
|
4635
|
-
attackEvent,
|
|
4636
|
-
playAgainEvent,
|
|
4637
|
-
gameEndEvent,
|
|
4638
|
-
showHeader = true,
|
|
4639
|
-
unitScale,
|
|
4640
|
-
scale,
|
|
4641
|
-
className
|
|
4642
|
-
}) {
|
|
4643
|
-
const row = boardEntity(entity);
|
|
4644
|
-
const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
|
|
4645
|
-
const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_CASTLE_LAYOUT, assetManifest);
|
|
4646
|
-
const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
|
|
4647
|
-
const name = row?.name == null ? void 0 : str(row.name);
|
|
4648
|
-
const level = row?.level == null ? void 0 : num(row.level);
|
|
4649
|
-
const owner = row?.owner == null ? void 0 : str(row.owner);
|
|
4650
|
-
const unitCount = row && Array.isArray(row.units) ? row.units.length : 0;
|
|
4651
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4652
|
-
VStack,
|
|
4653
|
-
{
|
|
4654
|
-
className: cn("game-canvas-3d-castle-template block w-full min-h-[85vh]", className),
|
|
4655
|
-
children: [
|
|
4656
|
-
showHeader && name && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "center", className: "castle-template__header", children: [
|
|
4657
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", className: "header__name", children: name }),
|
|
4658
|
-
level != null && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "header__level", children: [
|
|
4659
|
-
"Level ",
|
|
4660
|
-
level
|
|
4661
|
-
] }),
|
|
4662
|
-
owner && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", className: "header__owner", children: owner })
|
|
4663
|
-
] }),
|
|
4664
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4665
|
-
GameBoard3D,
|
|
4666
|
-
{
|
|
4667
|
-
entity,
|
|
4668
|
-
tiles,
|
|
4669
|
-
features,
|
|
4670
|
-
cameraMode,
|
|
4671
|
-
backgroundColor,
|
|
4672
|
-
unitScale,
|
|
4673
|
-
scale,
|
|
4674
|
-
tileClickEvent: buildingClickEvent,
|
|
4675
|
-
unitClickEvent,
|
|
4676
|
-
endTurnEvent,
|
|
4677
|
-
cancelEvent,
|
|
4678
|
-
attackEvent,
|
|
4679
|
-
playAgainEvent,
|
|
4680
|
-
gameEndEvent,
|
|
4681
|
-
className: "game-canvas-3d-castle-template__board"
|
|
4682
|
-
}
|
|
4683
|
-
),
|
|
4684
|
-
unitCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "center", className: "castle-template__garrison-info", children: [
|
|
4685
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "garrison-info__label", children: "Garrison:" }),
|
|
4686
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", weight: "bold", className: "garrison-info__count", children: [
|
|
4687
|
-
unitCount,
|
|
4688
|
-
" units"
|
|
4689
|
-
] })
|
|
4690
|
-
] })
|
|
4691
|
-
]
|
|
4692
|
-
}
|
|
4693
|
-
);
|
|
4694
|
-
}
|
|
4695
|
-
GameCanvas3DCastleTemplate.displayName = "GameCanvas3DCastleTemplate";
|
|
4696
|
-
var DEFAULT_3D_WORLDMAP_LAYOUT = [
|
|
4697
|
-
{ id: "t00", x: 0, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
|
|
4698
|
-
{ id: "t10", x: 1, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
|
|
4699
|
-
{ id: "t20", x: 2, y: 0, z: 0, type: "water", passable: false, kind: "wall" },
|
|
4700
|
-
{ id: "t30", x: 3, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
|
|
4701
|
-
{ id: "t40", x: 4, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
|
|
4702
|
-
{ id: "t01", x: 0, y: 1, z: 1, type: "mountain", passable: false, kind: "wall" },
|
|
4703
|
-
{ id: "t11", x: 1, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
|
|
4704
|
-
{ id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
|
|
4705
|
-
{ id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
|
|
4706
|
-
{ id: "t41", x: 4, y: 1, z: 1, type: "water", passable: false, kind: "wall" },
|
|
4707
|
-
{ id: "t02", x: 0, y: 2, z: 2, type: "water", passable: false, kind: "wall" },
|
|
4708
|
-
{ id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
|
|
4709
|
-
{ id: "t22", x: 2, y: 2, z: 2, type: "road", passable: true, kind: "dirt" },
|
|
4710
|
-
{ id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
|
|
4711
|
-
{ id: "t42", x: 4, y: 2, z: 2, type: "mountain", passable: false, kind: "wall" },
|
|
4712
|
-
{ id: "t03", x: 0, y: 3, z: 3, type: "mountain", passable: false, kind: "wall" },
|
|
4713
|
-
{ id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
|
|
4714
|
-
{ id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
|
|
4715
|
-
{ id: "t33", x: 3, y: 3, z: 3, type: "road", passable: true, kind: "dirt" },
|
|
4716
|
-
{ id: "t43", x: 4, y: 3, z: 3, type: "mountain", passable: false, kind: "wall" },
|
|
4717
|
-
{ id: "t04", x: 0, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" },
|
|
4718
|
-
{ id: "t14", x: 1, y: 4, z: 4, type: "water", passable: false, kind: "wall" },
|
|
4719
|
-
{ id: "t24", x: 2, y: 4, z: 4, type: "grass", passable: true, kind: "open" },
|
|
4720
|
-
{ id: "t34", x: 3, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" },
|
|
4721
|
-
{ id: "t44", x: 4, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" }
|
|
4722
|
-
];
|
|
4723
|
-
var DEFAULT_3D_WORLDMAP_FEATURES = [
|
|
4724
|
-
{ id: "f1", x: 2, y: 2, z: 2, type: "capital", color: "#f4c542" },
|
|
4725
|
-
{ id: "f2", x: 4, y: 2, z: 2, type: "power_node", color: "#8b5cf6" }
|
|
4726
|
-
];
|
|
4727
|
-
function GameCanvas3DWorldMapTemplate({
|
|
4728
|
-
entity,
|
|
4729
|
-
tiles: propTiles,
|
|
4730
|
-
features: propFeatures = DEFAULT_3D_WORLDMAP_FEATURES,
|
|
4731
|
-
assetManifest,
|
|
4732
|
-
cameraMode = "isometric",
|
|
4733
|
-
backgroundColor = "#1a1a2e",
|
|
4734
|
-
tileClickEvent,
|
|
4735
|
-
unitClickEvent,
|
|
4736
|
-
endTurnEvent,
|
|
4737
|
-
cancelEvent,
|
|
4738
|
-
attackEvent,
|
|
4739
|
-
playAgainEvent,
|
|
4740
|
-
gameEndEvent,
|
|
4741
|
-
unitScale,
|
|
4742
|
-
scale,
|
|
4743
|
-
className
|
|
4744
|
-
}) {
|
|
4745
|
-
const row = boardEntity(entity);
|
|
4746
|
-
const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
|
|
4747
|
-
const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_WORLDMAP_LAYOUT, assetManifest);
|
|
4748
|
-
const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
|
|
4749
|
-
return (
|
|
4750
|
-
/* GameBoard3D reads selectedUnitId/validMoves/attackTargets from entity */
|
|
4751
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4752
|
-
GameBoard3D,
|
|
4753
|
-
{
|
|
4754
|
-
entity,
|
|
4755
|
-
tiles,
|
|
4756
|
-
features,
|
|
4757
|
-
cameraMode,
|
|
4758
|
-
backgroundColor,
|
|
4759
|
-
unitScale,
|
|
4760
|
-
scale,
|
|
4761
|
-
tileClickEvent,
|
|
4762
|
-
unitClickEvent,
|
|
4763
|
-
endTurnEvent,
|
|
4764
|
-
cancelEvent,
|
|
4765
|
-
attackEvent,
|
|
4766
|
-
playAgainEvent,
|
|
4767
|
-
gameEndEvent,
|
|
4768
|
-
className
|
|
4769
|
-
}
|
|
4770
|
-
)
|
|
4771
|
-
);
|
|
4772
|
-
}
|
|
4773
|
-
GameCanvas3DWorldMapTemplate.displayName = "GameCanvas3DWorldMapTemplate";
|
|
4774
|
-
var DEFAULT_CONFIG = {
|
|
4775
|
-
cellSize: 1,
|
|
4776
|
-
offsetX: 0,
|
|
4777
|
-
offsetZ: 0,
|
|
4778
|
-
elevation: 0
|
|
4779
|
-
};
|
|
4780
|
-
function gridToWorld(gridX, gridZ, config = DEFAULT_CONFIG) {
|
|
4781
|
-
const opts = { ...DEFAULT_CONFIG, ...config };
|
|
4782
|
-
return new THREE6__namespace.Vector3(
|
|
4783
|
-
gridX * opts.cellSize + opts.offsetX,
|
|
4784
|
-
opts.elevation,
|
|
4785
|
-
gridZ * opts.cellSize + opts.offsetZ
|
|
4786
|
-
);
|
|
4787
|
-
}
|
|
4788
|
-
function worldToGrid(worldX, worldZ, config = DEFAULT_CONFIG) {
|
|
4789
|
-
const opts = { ...DEFAULT_CONFIG, ...config };
|
|
4790
|
-
return {
|
|
4791
|
-
x: Math.round((worldX - opts.offsetX) / opts.cellSize),
|
|
4792
|
-
z: Math.round((worldZ - opts.offsetZ) / opts.cellSize)
|
|
4793
|
-
};
|
|
4794
|
-
}
|
|
4795
|
-
function raycastToPlane(camera, mouseX, mouseY, planeY = 0) {
|
|
4796
|
-
const raycaster = new THREE6__namespace.Raycaster();
|
|
4797
|
-
const mouse = new THREE6__namespace.Vector2(mouseX, mouseY);
|
|
4798
|
-
raycaster.setFromCamera(mouse, camera);
|
|
4799
|
-
const plane = new THREE6__namespace.Plane(new THREE6__namespace.Vector3(0, 1, 0), -planeY);
|
|
4800
|
-
const target = new THREE6__namespace.Vector3();
|
|
4801
|
-
const intersection = raycaster.ray.intersectPlane(plane, target);
|
|
4802
|
-
return intersection ? target : null;
|
|
4803
|
-
}
|
|
4804
|
-
function raycastToObjects(camera, mouseX, mouseY, objects) {
|
|
4805
|
-
const raycaster = new THREE6__namespace.Raycaster();
|
|
4806
|
-
const mouse = new THREE6__namespace.Vector2(mouseX, mouseY);
|
|
4807
|
-
raycaster.setFromCamera(mouse, camera);
|
|
4808
|
-
const intersects = raycaster.intersectObjects(objects, true);
|
|
4809
|
-
return intersects.length > 0 ? intersects[0] : null;
|
|
4810
|
-
}
|
|
4811
|
-
function gridDistance(a, b) {
|
|
4812
|
-
const dx = b.x - a.x;
|
|
4813
|
-
const dz = b.z - a.z;
|
|
4814
|
-
return Math.sqrt(dx * dx + dz * dz);
|
|
4815
|
-
}
|
|
4816
|
-
function gridManhattanDistance(a, b) {
|
|
4817
|
-
return Math.abs(b.x - a.x) + Math.abs(b.z - a.z);
|
|
4818
|
-
}
|
|
4819
|
-
function getNeighbors(x, z, includeDiagonal = false) {
|
|
4820
|
-
const neighbors = [
|
|
4821
|
-
{ x: x + 1, z },
|
|
4822
|
-
{ x: x - 1, z },
|
|
4823
|
-
{ x, z: z + 1 },
|
|
4824
|
-
{ x, z: z - 1 }
|
|
4825
|
-
];
|
|
4826
|
-
if (includeDiagonal) {
|
|
4827
|
-
neighbors.push(
|
|
4828
|
-
{ x: x + 1, z: z + 1 },
|
|
4829
|
-
{ x: x - 1, z: z - 1 },
|
|
4830
|
-
{ x: x + 1, z: z - 1 },
|
|
4831
|
-
{ x: x - 1, z: z + 1 }
|
|
4832
|
-
);
|
|
4833
|
-
}
|
|
4834
|
-
return neighbors;
|
|
4835
|
-
}
|
|
4836
|
-
function isInBounds(x, z, bounds) {
|
|
4837
|
-
return x >= bounds.minX && x <= bounds.maxX && z >= bounds.minZ && z <= bounds.maxZ;
|
|
4838
|
-
}
|
|
4839
|
-
function getCellsInRadius(centerX, centerZ, radius) {
|
|
4840
|
-
const cells = [];
|
|
4841
|
-
const radiusSquared = radius * radius;
|
|
4842
|
-
const minX = Math.floor(centerX - radius);
|
|
4843
|
-
const maxX = Math.ceil(centerX + radius);
|
|
4844
|
-
const minZ = Math.floor(centerZ - radius);
|
|
4845
|
-
const maxZ = Math.ceil(centerZ + radius);
|
|
4846
|
-
for (let x = minX; x <= maxX; x++) {
|
|
4847
|
-
for (let z = minZ; z <= maxZ; z++) {
|
|
4848
|
-
const dx = x - centerX;
|
|
4849
|
-
const dz = z - centerZ;
|
|
4850
|
-
if (dx * dx + dz * dz <= radiusSquared) {
|
|
4851
|
-
cells.push({ x, z });
|
|
4852
|
-
}
|
|
4853
|
-
}
|
|
4854
|
-
}
|
|
4855
|
-
return cells;
|
|
4856
|
-
}
|
|
4857
|
-
function createGridHighlight(color = 16776960, opacity = 0.3) {
|
|
4858
|
-
const geometry = new THREE6__namespace.PlaneGeometry(0.95, 0.95);
|
|
4859
|
-
const material = new THREE6__namespace.MeshBasicMaterial({
|
|
4860
|
-
color,
|
|
4861
|
-
transparent: true,
|
|
4862
|
-
opacity,
|
|
4863
|
-
side: THREE6__namespace.DoubleSide
|
|
4864
|
-
});
|
|
4865
|
-
const mesh = new THREE6__namespace.Mesh(geometry, material);
|
|
4866
|
-
mesh.rotation.x = -Math.PI / 2;
|
|
4867
|
-
mesh.position.y = 0.01;
|
|
4868
|
-
return mesh;
|
|
4869
|
-
}
|
|
4870
|
-
function normalizeMouseCoordinates(clientX, clientY, element) {
|
|
4871
|
-
const rect = element.getBoundingClientRect();
|
|
4872
|
-
return {
|
|
4873
|
-
x: (clientX - rect.left) / rect.width * 2 - 1,
|
|
4874
|
-
y: -((clientY - rect.top) / rect.height) * 2 + 1
|
|
4875
|
-
};
|
|
4876
|
-
}
|
|
4877
|
-
|
|
4878
2640
|
// components/avl/lib/avl-schema-parser.ts
|
|
4879
2641
|
function getEntity(orbital) {
|
|
4880
2642
|
const entity = orbital.entity;
|
|
@@ -4969,10 +2731,10 @@ function parseApplicationLevel(schema) {
|
|
|
4969
2731
|
}
|
|
4970
2732
|
const count = schema.orbitals.length;
|
|
4971
2733
|
const cols = Math.ceil(Math.sqrt(count));
|
|
4972
|
-
const
|
|
2734
|
+
const rows = Math.ceil(count / cols);
|
|
4973
2735
|
const spacing = 200;
|
|
4974
2736
|
const gridW = cols * spacing;
|
|
4975
|
-
const gridH =
|
|
2737
|
+
const gridH = rows * spacing;
|
|
4976
2738
|
const originX = (600 - gridW) / 2 + spacing / 2;
|
|
4977
2739
|
const originY = (400 - gridH) / 2 + spacing / 2;
|
|
4978
2740
|
schema.orbitals.forEach((orbital, i) => {
|
|
@@ -5505,7 +3267,7 @@ Avl3DLabel.displayName = "Avl3DLabel";
|
|
|
5505
3267
|
var Avl3DTooltip = ({
|
|
5506
3268
|
position,
|
|
5507
3269
|
title,
|
|
5508
|
-
rows
|
|
3270
|
+
rows,
|
|
5509
3271
|
accentColor = "#5b9bd5"
|
|
5510
3272
|
}) => {
|
|
5511
3273
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -5543,7 +3305,7 @@ var Avl3DTooltip = ({
|
|
|
5543
3305
|
children: title
|
|
5544
3306
|
}
|
|
5545
3307
|
),
|
|
5546
|
-
|
|
3308
|
+
rows.map((row) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5547
3309
|
Box,
|
|
5548
3310
|
{
|
|
5549
3311
|
style: {
|
|
@@ -5597,10 +3359,10 @@ var Avl3DOrbitalNode = ({
|
|
|
5597
3359
|
position,
|
|
5598
3360
|
onClick
|
|
5599
3361
|
}) => {
|
|
5600
|
-
const groupRef =
|
|
5601
|
-
const [hovered, setHovered] =
|
|
5602
|
-
const scale =
|
|
5603
|
-
const currentScale =
|
|
3362
|
+
const groupRef = React7.useRef(null);
|
|
3363
|
+
const [hovered, setHovered] = React7.useState(false);
|
|
3364
|
+
const scale = React7.useMemo(() => 0.6 + Math.min(traitCount, 8) * 0.3, [traitCount]);
|
|
3365
|
+
const currentScale = React7.useRef(scale);
|
|
5604
3366
|
const targetScale = hovered ? scale * 1.06 : scale;
|
|
5605
3367
|
fiber.useFrame((_, delta) => {
|
|
5606
3368
|
if (!groupRef.current) return;
|
|
@@ -5742,7 +3504,7 @@ var Avl3DCrossWire = ({
|
|
|
5742
3504
|
eventName,
|
|
5743
3505
|
color = AVL_3D_COLORS.crossWire
|
|
5744
3506
|
}) => {
|
|
5745
|
-
const { tubeArgs, midpoint } =
|
|
3507
|
+
const { tubeArgs, midpoint } = React7.useMemo(() => {
|
|
5746
3508
|
const curve = arcCurve3D(from, to, 2);
|
|
5747
3509
|
const mid = curve.getPoint(0.5);
|
|
5748
3510
|
return {
|
|
@@ -5781,9 +3543,9 @@ var Avl3DApplicationScene = ({
|
|
|
5781
3543
|
data,
|
|
5782
3544
|
onOrbitalClick
|
|
5783
3545
|
}) => {
|
|
5784
|
-
const groupRef =
|
|
5785
|
-
const [, setHoverTrigger] =
|
|
5786
|
-
const orbitalPositions =
|
|
3546
|
+
const groupRef = React7.useRef(null);
|
|
3547
|
+
const [, setHoverTrigger] = React7.useState(0);
|
|
3548
|
+
const orbitalPositions = React7.useMemo(() => {
|
|
5787
3549
|
const baseRadius = Math.max(4, data.orbitals.length * 1.5);
|
|
5788
3550
|
if (data.crossLinks.length === 0) {
|
|
5789
3551
|
return goldenSpiralPositions(data.orbitals.length, baseRadius);
|
|
@@ -5796,7 +3558,7 @@ var Avl3DApplicationScene = ({
|
|
|
5796
3558
|
})).filter((e) => e.from >= 0 && e.to >= 0);
|
|
5797
3559
|
return forceDirectedPositions(data.orbitals.length, edges, baseRadius);
|
|
5798
3560
|
}, [data.orbitals, data.crossLinks]);
|
|
5799
|
-
const positionByName =
|
|
3561
|
+
const positionByName = React7.useMemo(() => {
|
|
5800
3562
|
const map = /* @__PURE__ */ new Map();
|
|
5801
3563
|
data.orbitals.forEach((orb, i) => {
|
|
5802
3564
|
const pos = orbitalPositions[i];
|
|
@@ -5879,7 +3641,7 @@ var Avl3DEntityCore = ({
|
|
|
5879
3641
|
position,
|
|
5880
3642
|
fields
|
|
5881
3643
|
}) => {
|
|
5882
|
-
const coreRef =
|
|
3644
|
+
const coreRef = React7.useRef(null);
|
|
5883
3645
|
fiber.useFrame((_, delta) => {
|
|
5884
3646
|
if (!coreRef.current) return;
|
|
5885
3647
|
coreRef.current.rotation.y += delta * 0.3;
|
|
@@ -6032,8 +3794,8 @@ function TraitOrbit({
|
|
|
6032
3794
|
onClick,
|
|
6033
3795
|
onHover
|
|
6034
3796
|
}) {
|
|
6035
|
-
const groupRef =
|
|
6036
|
-
const angleRef =
|
|
3797
|
+
const groupRef = React7.useRef(null);
|
|
3798
|
+
const angleRef = React7.useRef(Math.random() * Math.PI * 2);
|
|
6037
3799
|
fiber.useFrame((_, delta) => {
|
|
6038
3800
|
angleRef.current += delta * speed;
|
|
6039
3801
|
if (!groupRef.current) return;
|
|
@@ -6164,9 +3926,9 @@ var Avl3DOrbitalScene = ({
|
|
|
6164
3926
|
highlightedTrait,
|
|
6165
3927
|
onTraitHighlight
|
|
6166
3928
|
}) => {
|
|
6167
|
-
const [localHighlight, setLocalHighlight] =
|
|
3929
|
+
const [localHighlight, setLocalHighlight] = React7.useState(null);
|
|
6168
3930
|
const activeHighlight = highlightedTrait ?? localHighlight;
|
|
6169
|
-
const traitOrbits =
|
|
3931
|
+
const traitOrbits = React7.useMemo(() => {
|
|
6170
3932
|
return data.traits.map((trait, i) => ({
|
|
6171
3933
|
name: trait.name,
|
|
6172
3934
|
radius: 3 + i * 1.2,
|
|
@@ -6177,7 +3939,7 @@ var Avl3DOrbitalScene = ({
|
|
|
6177
3939
|
transitionCount: trait.transitionCount
|
|
6178
3940
|
}));
|
|
6179
3941
|
}, [data.traits]);
|
|
6180
|
-
const pagePositions =
|
|
3942
|
+
const pagePositions = React7.useMemo(() => {
|
|
6181
3943
|
const outerRadius = 3 + data.traits.length * 1.2 + 1.5;
|
|
6182
3944
|
return data.pages.map((_, i) => {
|
|
6183
3945
|
const angle = 2 * Math.PI * i / data.pages.length - Math.PI / 2;
|
|
@@ -6241,12 +4003,12 @@ var Avl3DStateNode = ({
|
|
|
6241
4003
|
outgoingCount = 0,
|
|
6242
4004
|
onClick
|
|
6243
4005
|
}) => {
|
|
6244
|
-
const [hovered, setHovered] =
|
|
4006
|
+
const [hovered, setHovered] = React7.useState(false);
|
|
6245
4007
|
const baseColor = active ? AVL_3D_COLORS.stateActive : AVL_3D_COLORS.stateIdle;
|
|
6246
4008
|
const emissiveColor = active ? AVL_3D_COLORS.stateActive : AVL_3D_COLORS.stateEdge;
|
|
6247
4009
|
const emissiveIntensity = active ? 2 : hovered ? 0.8 : 0.3;
|
|
6248
4010
|
const targetScale = hovered ? 1.08 : 1;
|
|
6249
|
-
const currentScale =
|
|
4011
|
+
const currentScale = React7.useRef(1);
|
|
6250
4012
|
fiber.useFrame((_, delta) => {
|
|
6251
4013
|
currentScale.current = THREE6.MathUtils.damp(currentScale.current, targetScale, 6, delta);
|
|
6252
4014
|
});
|
|
@@ -6420,8 +4182,8 @@ var Avl3DTransitionArc = ({
|
|
|
6420
4182
|
onClick,
|
|
6421
4183
|
color = AVL_3D_COLORS.transitionArc
|
|
6422
4184
|
}) => {
|
|
6423
|
-
const [hovered, setHovered] =
|
|
6424
|
-
const { tubeArgs, labelPos, guardPos, arrowPos, arrowQuat, effectPositions } =
|
|
4185
|
+
const [hovered, setHovered] = React7.useState(false);
|
|
4186
|
+
const { tubeArgs, labelPos, guardPos, arrowPos, arrowQuat, effectPositions } = React7.useMemo(() => {
|
|
6425
4187
|
const offset = 1.5 + index * 0.8;
|
|
6426
4188
|
const curve = isSelf ? selfLoopCurve3D(from, 1.2) : arcCurve3D(from, to, offset);
|
|
6427
4189
|
const mid = curve.getPoint(0.5);
|
|
@@ -6554,7 +4316,7 @@ var Avl3DTraitScene = ({
|
|
|
6554
4316
|
data,
|
|
6555
4317
|
onTransitionClick
|
|
6556
4318
|
}) => {
|
|
6557
|
-
const statePositions =
|
|
4319
|
+
const statePositions = React7.useMemo(() => {
|
|
6558
4320
|
const radius = Math.max(3, data.states.length * 0.8);
|
|
6559
4321
|
const positions = fibonacciSpherePositions(data.states.length, radius);
|
|
6560
4322
|
const posMap = /* @__PURE__ */ new Map();
|
|
@@ -6564,7 +4326,7 @@ var Avl3DTraitScene = ({
|
|
|
6564
4326
|
});
|
|
6565
4327
|
return posMap;
|
|
6566
4328
|
}, [data.states]);
|
|
6567
|
-
const transitionIndices =
|
|
4329
|
+
const transitionIndices = React7.useMemo(() => {
|
|
6568
4330
|
const pairCount = /* @__PURE__ */ new Map();
|
|
6569
4331
|
return data.transitions.map((t) => {
|
|
6570
4332
|
const key = `${t.from}->${t.to}`;
|
|
@@ -6573,7 +4335,7 @@ var Avl3DTraitScene = ({
|
|
|
6573
4335
|
return idx;
|
|
6574
4336
|
});
|
|
6575
4337
|
}, [data.transitions]);
|
|
6576
|
-
const transitionCounts =
|
|
4338
|
+
const transitionCounts = React7.useMemo(() => {
|
|
6577
4339
|
const incoming = /* @__PURE__ */ new Map();
|
|
6578
4340
|
const outgoing = /* @__PURE__ */ new Map();
|
|
6579
4341
|
for (const t of data.transitions) {
|
|
@@ -6683,11 +4445,11 @@ var Avl3DExprTree = ({
|
|
|
6683
4445
|
expression,
|
|
6684
4446
|
position
|
|
6685
4447
|
}) => {
|
|
6686
|
-
const layoutResults =
|
|
4448
|
+
const layoutResults = React7.useMemo(() => {
|
|
6687
4449
|
const origin = { x: position[0], y: position[1], z: position[2] };
|
|
6688
4450
|
return treeLayout3D(expression, origin, 2.5, 1.5);
|
|
6689
4451
|
}, [expression, position]);
|
|
6690
|
-
const edges =
|
|
4452
|
+
const edges = React7.useMemo(() => {
|
|
6691
4453
|
const result = [];
|
|
6692
4454
|
function collectEdges(node, parentPos) {
|
|
6693
4455
|
const entry = layoutResults.find((r) => r.node === node);
|
|
@@ -6967,7 +4729,7 @@ var Avl3DEffects = ({
|
|
|
6967
4729
|
const dof = DOF_CONFIG[level];
|
|
6968
4730
|
const sparkles = SPARKLE_CONFIGS[level];
|
|
6969
4731
|
const stars = STARS_CONFIG[level];
|
|
6970
|
-
const starsKey =
|
|
4732
|
+
const starsKey = React7.useMemo(() => `stars-${level}`, [level]);
|
|
6971
4733
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6972
4734
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6973
4735
|
drei.Stars,
|
|
@@ -7031,16 +4793,16 @@ var DEFAULT_CONFIG2 = {
|
|
|
7031
4793
|
modelOverrides: {},
|
|
7032
4794
|
effectsEnabled: true
|
|
7033
4795
|
};
|
|
7034
|
-
var Avl3DContext =
|
|
4796
|
+
var Avl3DContext = React7.createContext(DEFAULT_CONFIG2);
|
|
7035
4797
|
function useAvl3DConfig() {
|
|
7036
|
-
return
|
|
4798
|
+
return React7.useContext(Avl3DContext);
|
|
7037
4799
|
}
|
|
7038
4800
|
function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
7039
4801
|
const { camera } = fiber.useThree();
|
|
7040
|
-
const targetPosVec =
|
|
7041
|
-
const targetLookVec =
|
|
7042
|
-
const isAnimating =
|
|
7043
|
-
|
|
4802
|
+
const targetPosVec = React7.useRef(new THREE6__namespace.Vector3(...targetPosition));
|
|
4803
|
+
const targetLookVec = React7.useRef(new THREE6__namespace.Vector3(...targetLookAt));
|
|
4804
|
+
const isAnimating = React7.useRef(false);
|
|
4805
|
+
React7.useEffect(() => {
|
|
7044
4806
|
const newTarget = new THREE6__namespace.Vector3(...targetPosition);
|
|
7045
4807
|
const newLookAt = new THREE6__namespace.Vector3(...targetLookAt);
|
|
7046
4808
|
if (!newTarget.equals(targetPosVec.current) || !newLookAt.equals(targetLookVec.current)) {
|
|
@@ -7069,8 +4831,8 @@ function CameraController({ targetPosition, targetLookAt, animated }) {
|
|
|
7069
4831
|
return null;
|
|
7070
4832
|
}
|
|
7071
4833
|
function SceneFade({ animating, children }) {
|
|
7072
|
-
const groupRef =
|
|
7073
|
-
const opacityRef =
|
|
4834
|
+
const groupRef = React7.useRef(null);
|
|
4835
|
+
const opacityRef = React7.useRef(1);
|
|
7074
4836
|
fiber.useFrame((_, delta) => {
|
|
7075
4837
|
if (!groupRef.current) return;
|
|
7076
4838
|
const target = animating ? 0 : 1;
|
|
@@ -7094,7 +4856,7 @@ var Avl3DViewer = ({
|
|
|
7094
4856
|
modelOverrides = {}
|
|
7095
4857
|
}) => {
|
|
7096
4858
|
const { t } = hooks.useTranslate();
|
|
7097
|
-
const schema =
|
|
4859
|
+
const schema = React7.useMemo(() => {
|
|
7098
4860
|
if (typeof schemaProp === "string") {
|
|
7099
4861
|
try {
|
|
7100
4862
|
return JSON.parse(schemaProp);
|
|
@@ -7104,12 +4866,12 @@ var Avl3DViewer = ({
|
|
|
7104
4866
|
}
|
|
7105
4867
|
return schemaProp;
|
|
7106
4868
|
}, [schemaProp]);
|
|
7107
|
-
const configValue =
|
|
4869
|
+
const configValue = React7.useMemo(() => ({
|
|
7108
4870
|
modelOverrides,
|
|
7109
4871
|
effectsEnabled: effects
|
|
7110
4872
|
}), [modelOverrides, effects]);
|
|
7111
|
-
const [state, dispatch] =
|
|
7112
|
-
|
|
4873
|
+
const [state, dispatch] = React7.useReducer(zoomReducer, initialZoomState);
|
|
4874
|
+
React7.useEffect(() => {
|
|
7113
4875
|
if (initialOrbital) {
|
|
7114
4876
|
dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: initialOrbital, targetPosition: { x: 0, y: 0 } });
|
|
7115
4877
|
setTimeout(() => dispatch({ type: "ANIMATION_COMPLETE" }), 0);
|
|
@@ -7121,35 +4883,35 @@ var Avl3DViewer = ({
|
|
|
7121
4883
|
}
|
|
7122
4884
|
}
|
|
7123
4885
|
}, [initialOrbital, initialTrait]);
|
|
7124
|
-
|
|
4886
|
+
React7.useEffect(() => {
|
|
7125
4887
|
onZoomChange?.(state.level, {
|
|
7126
4888
|
orbital: state.selectedOrbital ?? void 0,
|
|
7127
4889
|
trait: state.selectedTrait ?? void 0
|
|
7128
4890
|
});
|
|
7129
4891
|
}, [state.level, state.selectedOrbital, state.selectedTrait, onZoomChange]);
|
|
7130
|
-
|
|
4892
|
+
React7.useEffect(() => {
|
|
7131
4893
|
if (!state.animating) return;
|
|
7132
4894
|
const timer = setTimeout(() => {
|
|
7133
4895
|
dispatch({ type: "ANIMATION_COMPLETE" });
|
|
7134
4896
|
}, 800);
|
|
7135
4897
|
return () => clearTimeout(timer);
|
|
7136
4898
|
}, [state.animating]);
|
|
7137
|
-
const handleKeyDown =
|
|
4899
|
+
const handleKeyDown = React7.useCallback((e) => {
|
|
7138
4900
|
if (e.key === "Escape") {
|
|
7139
4901
|
dispatch({ type: "ZOOM_OUT" });
|
|
7140
4902
|
}
|
|
7141
4903
|
}, []);
|
|
7142
|
-
const handleOrbitalClick =
|
|
4904
|
+
const handleOrbitalClick = React7.useCallback((name) => {
|
|
7143
4905
|
dispatch({ type: "ZOOM_INTO_ORBITAL", orbital: name, targetPosition: { x: 0, y: 0 } });
|
|
7144
4906
|
}, []);
|
|
7145
|
-
const handleTraitClick =
|
|
4907
|
+
const handleTraitClick = React7.useCallback((name) => {
|
|
7146
4908
|
dispatch({ type: "ZOOM_INTO_TRAIT", trait: name, targetPosition: { x: 0, y: 0 } });
|
|
7147
4909
|
}, []);
|
|
7148
|
-
const [highlightedTrait, setHighlightedTrait] =
|
|
7149
|
-
const handleTransitionClick =
|
|
4910
|
+
const [highlightedTrait, setHighlightedTrait] = React7__default.default.useState(null);
|
|
4911
|
+
const handleTransitionClick = React7.useCallback((index) => {
|
|
7150
4912
|
dispatch({ type: "ZOOM_INTO_TRANSITION", transitionIndex: index, targetPosition: { x: 0, y: 0 } });
|
|
7151
4913
|
}, []);
|
|
7152
|
-
const handleBreadcrumbClick =
|
|
4914
|
+
const handleBreadcrumbClick = React7.useCallback((targetLevel) => {
|
|
7153
4915
|
const levelOrder = ["application", "orbital", "trait", "transition"];
|
|
7154
4916
|
const currentIdx = levelOrder.indexOf(state.level);
|
|
7155
4917
|
const targetIdx = levelOrder.indexOf(targetLevel);
|
|
@@ -7158,7 +4920,7 @@ var Avl3DViewer = ({
|
|
|
7158
4920
|
}
|
|
7159
4921
|
}, [state.level]);
|
|
7160
4922
|
const cameraConfig = CAMERA_POSITIONS[state.level];
|
|
7161
|
-
const sceneContent =
|
|
4923
|
+
const sceneContent = React7.useMemo(() => {
|
|
7162
4924
|
switch (state.level) {
|
|
7163
4925
|
case "application": {
|
|
7164
4926
|
const data = parseApplicationLevel(schema);
|
|
@@ -7232,7 +4994,7 @@ var Avl3DViewer = ({
|
|
|
7232
4994
|
gap: "xs",
|
|
7233
4995
|
align: "center",
|
|
7234
4996
|
className: "absolute top-2 left-2 z-10 bg-surface/80 backdrop-blur rounded-md px-3 py-1.5",
|
|
7235
|
-
children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4997
|
+
children: breadcrumbs.map((crumb, i) => /* @__PURE__ */ jsxRuntime.jsxs(React7__default.default.Fragment, { children: [
|
|
7236
4998
|
i > 0 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", className: "mx-1", children: "/" }),
|
|
7237
4999
|
i < breadcrumbs.length - 1 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7238
5000
|
Box,
|
|
@@ -7521,11 +5283,7 @@ exports.CAMERA_POSITIONS = CAMERA_POSITIONS;
|
|
|
7521
5283
|
exports.Camera3D = Camera3D;
|
|
7522
5284
|
exports.Canvas3DErrorBoundary = Canvas3DErrorBoundary;
|
|
7523
5285
|
exports.Canvas3DLoadingState = Canvas3DLoadingState;
|
|
7524
|
-
exports.GameBoard3D = GameBoard3D;
|
|
7525
5286
|
exports.GameCanvas3D = GameCanvas3D;
|
|
7526
|
-
exports.GameCanvas3DBattleTemplate = GameCanvas3DBattleTemplate;
|
|
7527
|
-
exports.GameCanvas3DCastleTemplate = GameCanvas3DCastleTemplate;
|
|
7528
|
-
exports.GameCanvas3DWorldMapTemplate = GameCanvas3DWorldMapTemplate;
|
|
7529
5287
|
exports.Lighting3D = Lighting3D;
|
|
7530
5288
|
exports.ModelLoader = ModelLoader;
|
|
7531
5289
|
exports.Scene3D = Scene3D;
|