@almadar/ui 5.63.2 → 5.65.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 +89 -24
- package/dist/avl/index.js +89 -24
- package/dist/components/game/molecules/IsometricCanvas.d.ts +4 -1
- package/dist/components/game/molecules/index.d.ts +1 -0
- package/dist/components/game/molecules/three/index.cjs +5 -2
- package/dist/components/game/molecules/three/index.js +5 -2
- package/dist/components/game/organisms/HexStrategyBoard.d.ts +37 -0
- package/dist/components/game/organisms/index.d.ts +2 -0
- package/dist/components/game/organisms/utils/isometric.d.ts +20 -7
- package/dist/components/index.cjs +91 -24
- package/dist/components/index.js +91 -25
- package/dist/components/marketing/organisms/HeroOrganism.d.ts +2 -2
- package/dist/components/marketing/organisms/ShowcaseOrganism.d.ts +2 -2
- package/dist/components/marketing/organisms/TeamOrganism.d.ts +2 -2
- package/dist/providers/index.cjs +89 -24
- package/dist/providers/index.js +89 -24
- package/dist/runtime/index.cjs +89 -24
- package/dist/runtime/index.js +89 -24
- package/package.json +1 -1
package/dist/avl/index.cjs
CHANGED
|
@@ -43,6 +43,7 @@ var THREE3 = require('three');
|
|
|
43
43
|
var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
|
|
44
44
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
45
45
|
var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
|
|
46
|
+
var SkeletonUtils = require('three/examples/jsm/utils/SkeletonUtils');
|
|
46
47
|
var fiber = require('@react-three/fiber');
|
|
47
48
|
var drei = require('@react-three/drei');
|
|
48
49
|
var patterns = require('@almadar/patterns');
|
|
@@ -14722,16 +14723,26 @@ var init_useUnitSpriteAtlas = __esm({
|
|
|
14722
14723
|
});
|
|
14723
14724
|
|
|
14724
14725
|
// components/game/organisms/utils/isometric.ts
|
|
14725
|
-
function isoToScreen(tileX, tileY, scale, baseOffsetX) {
|
|
14726
|
+
function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
|
|
14726
14727
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
14727
14728
|
const scaledFloorHeight = FLOOR_HEIGHT * scale;
|
|
14729
|
+
if (layout === "hex") {
|
|
14730
|
+
const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
|
|
14731
|
+
const screenY2 = tileY * (scaledFloorHeight * 0.75);
|
|
14732
|
+
return { x: screenX2, y: screenY2 };
|
|
14733
|
+
}
|
|
14728
14734
|
const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
|
|
14729
14735
|
const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
|
|
14730
14736
|
return { x: screenX, y: screenY };
|
|
14731
14737
|
}
|
|
14732
|
-
function screenToIso(screenX, screenY, scale, baseOffsetX) {
|
|
14738
|
+
function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
|
|
14733
14739
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
14734
14740
|
const scaledFloorHeight = FLOOR_HEIGHT * scale;
|
|
14741
|
+
if (layout === "hex") {
|
|
14742
|
+
const row = Math.round(screenY / (scaledFloorHeight * 0.75));
|
|
14743
|
+
const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
|
|
14744
|
+
return { x: col, y: row };
|
|
14745
|
+
}
|
|
14735
14746
|
const adjustedX = screenX - baseOffsetX;
|
|
14736
14747
|
const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
|
|
14737
14748
|
const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
|
|
@@ -14781,6 +14792,7 @@ function IsometricCanvas({
|
|
|
14781
14792
|
tileHoverEvent,
|
|
14782
14793
|
tileLeaveEvent,
|
|
14783
14794
|
// Rendering options
|
|
14795
|
+
tileLayout = "isometric",
|
|
14784
14796
|
scale = 0.4,
|
|
14785
14797
|
debug: debug2 = false,
|
|
14786
14798
|
backgroundImage = "",
|
|
@@ -14850,13 +14862,17 @@ function IsometricCanvas({
|
|
|
14850
14862
|
);
|
|
14851
14863
|
const sortedTiles = React93.useMemo(() => {
|
|
14852
14864
|
const tiles = [...tilesProp];
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14865
|
+
if (tileLayout === "hex") {
|
|
14866
|
+
tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
|
|
14867
|
+
} else {
|
|
14868
|
+
tiles.sort((a, b) => {
|
|
14869
|
+
const depthA = a.x + a.y;
|
|
14870
|
+
const depthB = b.x + b.y;
|
|
14871
|
+
return depthA !== depthB ? depthA - depthB : a.y - b.y;
|
|
14872
|
+
});
|
|
14873
|
+
}
|
|
14858
14874
|
return tiles;
|
|
14859
|
-
}, [tilesProp]);
|
|
14875
|
+
}, [tilesProp, tileLayout]);
|
|
14860
14876
|
const gridWidth = React93.useMemo(() => {
|
|
14861
14877
|
if (sortedTiles.length === 0) return 0;
|
|
14862
14878
|
return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
|
|
@@ -14970,7 +14986,7 @@ function IsometricCanvas({
|
|
|
14970
14986
|
miniCanvas.width = mW;
|
|
14971
14987
|
miniCanvas.height = mH;
|
|
14972
14988
|
mCtx.clearRect(0, 0, mW, mH);
|
|
14973
|
-
const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
|
|
14989
|
+
const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
|
|
14974
14990
|
const minX = Math.min(...allScreenPos.map((p2) => p2.x));
|
|
14975
14991
|
const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
|
|
14976
14992
|
const minY = Math.min(...allScreenPos.map((p2) => p2.y));
|
|
@@ -14981,7 +14997,7 @@ function IsometricCanvas({
|
|
|
14981
14997
|
const offsetMx = (mW - worldW * scaleM) / 2;
|
|
14982
14998
|
const offsetMy = (mH - worldH * scaleM) / 2;
|
|
14983
14999
|
for (const tile of sortedTiles) {
|
|
14984
|
-
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
|
|
15000
|
+
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
|
|
14985
15001
|
const mx = (pos.x - minX) * scaleM + offsetMx;
|
|
14986
15002
|
const my = (pos.y - minY) * scaleM + offsetMy;
|
|
14987
15003
|
const mTileW = scaledTileWidth * scaleM;
|
|
@@ -14997,7 +15013,7 @@ function IsometricCanvas({
|
|
|
14997
15013
|
}
|
|
14998
15014
|
for (const unit of units) {
|
|
14999
15015
|
if (!unit.position) continue;
|
|
15000
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
15016
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
15001
15017
|
const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
|
|
15002
15018
|
const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
|
|
15003
15019
|
mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
|
|
@@ -15013,7 +15029,7 @@ function IsometricCanvas({
|
|
|
15013
15029
|
mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
|
|
15014
15030
|
mCtx.lineWidth = 1;
|
|
15015
15031
|
mCtx.strokeRect(vLeft, vTop, vW, vH);
|
|
15016
|
-
}, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
|
|
15032
|
+
}, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
|
|
15017
15033
|
const draw = React93.useCallback((animTime) => {
|
|
15018
15034
|
const canvas = canvasRef.current;
|
|
15019
15035
|
if (!canvas) return;
|
|
@@ -15053,7 +15069,7 @@ function IsometricCanvas({
|
|
|
15053
15069
|
const visTop = cam.y - viewportSize.height / cam.zoom;
|
|
15054
15070
|
const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
|
|
15055
15071
|
for (const tile of sortedTiles) {
|
|
15056
|
-
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
|
|
15072
|
+
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
|
|
15057
15073
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
15058
15074
|
continue;
|
|
15059
15075
|
}
|
|
@@ -15133,12 +15149,13 @@ function IsometricCanvas({
|
|
|
15133
15149
|
}
|
|
15134
15150
|
}
|
|
15135
15151
|
const sortedFeatures = [...features].sort((a, b) => {
|
|
15152
|
+
if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
|
|
15136
15153
|
const depthA = a.x + a.y;
|
|
15137
15154
|
const depthB = b.x + b.y;
|
|
15138
15155
|
return depthA !== depthB ? depthA - depthB : a.y - b.y;
|
|
15139
15156
|
});
|
|
15140
15157
|
for (const feature of sortedFeatures) {
|
|
15141
|
-
const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
|
|
15158
|
+
const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
|
|
15142
15159
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
15143
15160
|
continue;
|
|
15144
15161
|
}
|
|
@@ -15173,12 +15190,13 @@ function IsometricCanvas({
|
|
|
15173
15190
|
}
|
|
15174
15191
|
const unitsWithPosition = units.filter((u) => !!u.position);
|
|
15175
15192
|
const sortedUnits = [...unitsWithPosition].sort((a, b) => {
|
|
15193
|
+
if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
|
|
15176
15194
|
const depthA = a.position.x + a.position.y;
|
|
15177
15195
|
const depthB = b.position.x + b.position.y;
|
|
15178
15196
|
return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
|
|
15179
15197
|
});
|
|
15180
15198
|
for (const unit of sortedUnits) {
|
|
15181
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
15199
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
15182
15200
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
15183
15201
|
continue;
|
|
15184
15202
|
}
|
|
@@ -15198,7 +15216,7 @@ function IsometricCanvas({
|
|
|
15198
15216
|
drawH = maxUnitW / ar;
|
|
15199
15217
|
}
|
|
15200
15218
|
if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
|
|
15201
|
-
const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
|
|
15219
|
+
const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
|
|
15202
15220
|
const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
|
|
15203
15221
|
const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
|
|
15204
15222
|
ctx.save();
|
|
@@ -15327,6 +15345,7 @@ function IsometricCanvas({
|
|
|
15327
15345
|
units,
|
|
15328
15346
|
features,
|
|
15329
15347
|
selectedUnitId,
|
|
15348
|
+
tileLayout,
|
|
15330
15349
|
scale,
|
|
15331
15350
|
debug2,
|
|
15332
15351
|
resolveTerrainSpriteUrl,
|
|
@@ -15355,14 +15374,14 @@ function IsometricCanvas({
|
|
|
15355
15374
|
if (!selectedUnitId) return;
|
|
15356
15375
|
const unit = units.find((u) => u.id === selectedUnitId);
|
|
15357
15376
|
if (!unit?.position) return;
|
|
15358
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
15377
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
15359
15378
|
const centerX = pos.x + scaledTileWidth / 2;
|
|
15360
15379
|
const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
|
|
15361
15380
|
targetCameraRef.current = {
|
|
15362
15381
|
x: centerX - viewportSize.width / 2,
|
|
15363
15382
|
y: centerY - viewportSize.height / 2
|
|
15364
15383
|
};
|
|
15365
|
-
}, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
15384
|
+
}, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
15366
15385
|
React93.useEffect(() => {
|
|
15367
15386
|
const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
|
|
15368
15387
|
draw(animTimeRef.current);
|
|
@@ -15395,13 +15414,13 @@ function IsometricCanvas({
|
|
|
15395
15414
|
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
15396
15415
|
const adjustedX = world.x - scaledTileWidth / 2;
|
|
15397
15416
|
const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
15398
|
-
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
|
|
15417
|
+
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
|
|
15399
15418
|
const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
|
|
15400
15419
|
if (tileExists) {
|
|
15401
15420
|
if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
|
|
15402
15421
|
onTileHover?.(isoPos.x, isoPos.y);
|
|
15403
15422
|
}
|
|
15404
|
-
}, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
|
|
15423
|
+
}, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
|
|
15405
15424
|
const handleCanvasPointerUp = React93.useCallback((e) => {
|
|
15406
15425
|
singlePointerActiveRef.current = false;
|
|
15407
15426
|
if (enableCamera) handlePointerUp();
|
|
@@ -15410,7 +15429,7 @@ function IsometricCanvas({
|
|
|
15410
15429
|
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
15411
15430
|
const adjustedX = world.x - scaledTileWidth / 2;
|
|
15412
15431
|
const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
15413
|
-
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
|
|
15432
|
+
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
|
|
15414
15433
|
const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
|
|
15415
15434
|
if (clickedUnit && (onUnitClick || unitClickEvent)) {
|
|
15416
15435
|
if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
|
|
@@ -15422,7 +15441,7 @@ function IsometricCanvas({
|
|
|
15422
15441
|
onTileClick?.(isoPos.x, isoPos.y);
|
|
15423
15442
|
}
|
|
15424
15443
|
}
|
|
15425
|
-
}, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
|
|
15444
|
+
}, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
|
|
15426
15445
|
const handleCanvasPointerLeave = React93.useCallback(() => {
|
|
15427
15446
|
handleMouseLeave();
|
|
15428
15447
|
if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
|
|
@@ -45460,7 +45479,8 @@ function ModelLoader({
|
|
|
45460
45479
|
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
45461
45480
|
const model = React93.useMemo(() => {
|
|
45462
45481
|
if (!loadedModel) return null;
|
|
45463
|
-
const cloned =
|
|
45482
|
+
const cloned = SkeletonUtils.clone(loadedModel);
|
|
45483
|
+
cloned.updateMatrixWorld(true);
|
|
45464
45484
|
cloned.traverse((child) => {
|
|
45465
45485
|
if (child instanceof THREE3__namespace.Mesh) {
|
|
45466
45486
|
child.castShadow = castShadow;
|
|
@@ -45475,7 +45495,8 @@ function ModelLoader({
|
|
|
45475
45495
|
const size = new THREE3__namespace.Vector3();
|
|
45476
45496
|
box.getSize(size);
|
|
45477
45497
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
45478
|
-
|
|
45498
|
+
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
45499
|
+
return 1 / maxDim;
|
|
45479
45500
|
}, [model]);
|
|
45480
45501
|
const scaleArray = React93.useMemo(() => {
|
|
45481
45502
|
const base = typeof scale === "number" ? [scale, scale, scale] : scale;
|
|
@@ -46757,6 +46778,48 @@ var init_HeroOrganism = __esm({
|
|
|
46757
46778
|
_HeroClickInterceptor.displayName = "_HeroClickInterceptor";
|
|
46758
46779
|
}
|
|
46759
46780
|
});
|
|
46781
|
+
function HexStrategyBoard({
|
|
46782
|
+
tiles,
|
|
46783
|
+
units,
|
|
46784
|
+
features,
|
|
46785
|
+
assetManifest,
|
|
46786
|
+
assetBaseUrl,
|
|
46787
|
+
scale = 0.45,
|
|
46788
|
+
showMinimap = true,
|
|
46789
|
+
enableCamera = true,
|
|
46790
|
+
tileClickEvent,
|
|
46791
|
+
unitClickEvent,
|
|
46792
|
+
isLoading,
|
|
46793
|
+
error,
|
|
46794
|
+
className
|
|
46795
|
+
}) {
|
|
46796
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
46797
|
+
IsometricCanvas_default,
|
|
46798
|
+
{
|
|
46799
|
+
tileLayout: "hex",
|
|
46800
|
+
tiles,
|
|
46801
|
+
units,
|
|
46802
|
+
features,
|
|
46803
|
+
assetManifest,
|
|
46804
|
+
assetBaseUrl,
|
|
46805
|
+
scale,
|
|
46806
|
+
showMinimap,
|
|
46807
|
+
enableCamera,
|
|
46808
|
+
tileClickEvent,
|
|
46809
|
+
unitClickEvent,
|
|
46810
|
+
isLoading,
|
|
46811
|
+
error
|
|
46812
|
+
}
|
|
46813
|
+
) });
|
|
46814
|
+
}
|
|
46815
|
+
var init_HexStrategyBoard = __esm({
|
|
46816
|
+
"components/game/organisms/HexStrategyBoard.tsx"() {
|
|
46817
|
+
"use client";
|
|
46818
|
+
init_cn();
|
|
46819
|
+
init_IsometricCanvas();
|
|
46820
|
+
HexStrategyBoard.displayName = "HexStrategyBoard";
|
|
46821
|
+
}
|
|
46822
|
+
});
|
|
46760
46823
|
var LandingPageTemplate;
|
|
46761
46824
|
var init_LandingPageTemplate = __esm({
|
|
46762
46825
|
"components/marketing/templates/LandingPageTemplate.tsx"() {
|
|
@@ -54585,6 +54648,7 @@ var init_component_registry_generated = __esm({
|
|
|
54585
54648
|
init_HealthPanel();
|
|
54586
54649
|
init_HeroOrganism();
|
|
54587
54650
|
init_HeroSection();
|
|
54651
|
+
init_HexStrategyBoard();
|
|
54588
54652
|
init_Icon();
|
|
54589
54653
|
init_InfiniteScrollSentinel();
|
|
54590
54654
|
init_Input();
|
|
@@ -54921,6 +54985,7 @@ var init_component_registry_generated = __esm({
|
|
|
54921
54985
|
"HealthPanel": HealthPanel,
|
|
54922
54986
|
"HeroOrganism": HeroOrganism,
|
|
54923
54987
|
"HeroSection": HeroSection,
|
|
54988
|
+
"HexStrategyBoard": HexStrategyBoard,
|
|
54924
54989
|
"Icon": Icon,
|
|
54925
54990
|
"InfiniteScrollSentinel": InfiniteScrollSentinel,
|
|
54926
54991
|
"Input": Input,
|
package/dist/avl/index.js
CHANGED
|
@@ -43,6 +43,7 @@ import * as THREE3 from 'three';
|
|
|
43
43
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
44
44
|
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
45
45
|
import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
46
|
+
import { clone } from 'three/examples/jsm/utils/SkeletonUtils';
|
|
46
47
|
import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
|
|
47
48
|
import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
|
|
48
49
|
import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1, isEntityAwarePattern } from '@almadar/patterns';
|
|
@@ -14675,16 +14676,26 @@ var init_useUnitSpriteAtlas = __esm({
|
|
|
14675
14676
|
});
|
|
14676
14677
|
|
|
14677
14678
|
// components/game/organisms/utils/isometric.ts
|
|
14678
|
-
function isoToScreen(tileX, tileY, scale, baseOffsetX) {
|
|
14679
|
+
function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
|
|
14679
14680
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
14680
14681
|
const scaledFloorHeight = FLOOR_HEIGHT * scale;
|
|
14682
|
+
if (layout === "hex") {
|
|
14683
|
+
const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
|
|
14684
|
+
const screenY2 = tileY * (scaledFloorHeight * 0.75);
|
|
14685
|
+
return { x: screenX2, y: screenY2 };
|
|
14686
|
+
}
|
|
14681
14687
|
const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
|
|
14682
14688
|
const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
|
|
14683
14689
|
return { x: screenX, y: screenY };
|
|
14684
14690
|
}
|
|
14685
|
-
function screenToIso(screenX, screenY, scale, baseOffsetX) {
|
|
14691
|
+
function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
|
|
14686
14692
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
14687
14693
|
const scaledFloorHeight = FLOOR_HEIGHT * scale;
|
|
14694
|
+
if (layout === "hex") {
|
|
14695
|
+
const row = Math.round(screenY / (scaledFloorHeight * 0.75));
|
|
14696
|
+
const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
|
|
14697
|
+
return { x: col, y: row };
|
|
14698
|
+
}
|
|
14688
14699
|
const adjustedX = screenX - baseOffsetX;
|
|
14689
14700
|
const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
|
|
14690
14701
|
const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
|
|
@@ -14734,6 +14745,7 @@ function IsometricCanvas({
|
|
|
14734
14745
|
tileHoverEvent,
|
|
14735
14746
|
tileLeaveEvent,
|
|
14736
14747
|
// Rendering options
|
|
14748
|
+
tileLayout = "isometric",
|
|
14737
14749
|
scale = 0.4,
|
|
14738
14750
|
debug: debug2 = false,
|
|
14739
14751
|
backgroundImage = "",
|
|
@@ -14803,13 +14815,17 @@ function IsometricCanvas({
|
|
|
14803
14815
|
);
|
|
14804
14816
|
const sortedTiles = useMemo(() => {
|
|
14805
14817
|
const tiles = [...tilesProp];
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
|
|
14810
|
-
|
|
14818
|
+
if (tileLayout === "hex") {
|
|
14819
|
+
tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
|
|
14820
|
+
} else {
|
|
14821
|
+
tiles.sort((a, b) => {
|
|
14822
|
+
const depthA = a.x + a.y;
|
|
14823
|
+
const depthB = b.x + b.y;
|
|
14824
|
+
return depthA !== depthB ? depthA - depthB : a.y - b.y;
|
|
14825
|
+
});
|
|
14826
|
+
}
|
|
14811
14827
|
return tiles;
|
|
14812
|
-
}, [tilesProp]);
|
|
14828
|
+
}, [tilesProp, tileLayout]);
|
|
14813
14829
|
const gridWidth = useMemo(() => {
|
|
14814
14830
|
if (sortedTiles.length === 0) return 0;
|
|
14815
14831
|
return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
|
|
@@ -14923,7 +14939,7 @@ function IsometricCanvas({
|
|
|
14923
14939
|
miniCanvas.width = mW;
|
|
14924
14940
|
miniCanvas.height = mH;
|
|
14925
14941
|
mCtx.clearRect(0, 0, mW, mH);
|
|
14926
|
-
const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
|
|
14942
|
+
const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
|
|
14927
14943
|
const minX = Math.min(...allScreenPos.map((p2) => p2.x));
|
|
14928
14944
|
const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
|
|
14929
14945
|
const minY = Math.min(...allScreenPos.map((p2) => p2.y));
|
|
@@ -14934,7 +14950,7 @@ function IsometricCanvas({
|
|
|
14934
14950
|
const offsetMx = (mW - worldW * scaleM) / 2;
|
|
14935
14951
|
const offsetMy = (mH - worldH * scaleM) / 2;
|
|
14936
14952
|
for (const tile of sortedTiles) {
|
|
14937
|
-
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
|
|
14953
|
+
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
|
|
14938
14954
|
const mx = (pos.x - minX) * scaleM + offsetMx;
|
|
14939
14955
|
const my = (pos.y - minY) * scaleM + offsetMy;
|
|
14940
14956
|
const mTileW = scaledTileWidth * scaleM;
|
|
@@ -14950,7 +14966,7 @@ function IsometricCanvas({
|
|
|
14950
14966
|
}
|
|
14951
14967
|
for (const unit of units) {
|
|
14952
14968
|
if (!unit.position) continue;
|
|
14953
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
14969
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
14954
14970
|
const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
|
|
14955
14971
|
const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
|
|
14956
14972
|
mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
|
|
@@ -14966,7 +14982,7 @@ function IsometricCanvas({
|
|
|
14966
14982
|
mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
|
|
14967
14983
|
mCtx.lineWidth = 1;
|
|
14968
14984
|
mCtx.strokeRect(vLeft, vTop, vW, vH);
|
|
14969
|
-
}, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
|
|
14985
|
+
}, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
|
|
14970
14986
|
const draw = useCallback((animTime) => {
|
|
14971
14987
|
const canvas = canvasRef.current;
|
|
14972
14988
|
if (!canvas) return;
|
|
@@ -15006,7 +15022,7 @@ function IsometricCanvas({
|
|
|
15006
15022
|
const visTop = cam.y - viewportSize.height / cam.zoom;
|
|
15007
15023
|
const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
|
|
15008
15024
|
for (const tile of sortedTiles) {
|
|
15009
|
-
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
|
|
15025
|
+
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
|
|
15010
15026
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
15011
15027
|
continue;
|
|
15012
15028
|
}
|
|
@@ -15086,12 +15102,13 @@ function IsometricCanvas({
|
|
|
15086
15102
|
}
|
|
15087
15103
|
}
|
|
15088
15104
|
const sortedFeatures = [...features].sort((a, b) => {
|
|
15105
|
+
if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
|
|
15089
15106
|
const depthA = a.x + a.y;
|
|
15090
15107
|
const depthB = b.x + b.y;
|
|
15091
15108
|
return depthA !== depthB ? depthA - depthB : a.y - b.y;
|
|
15092
15109
|
});
|
|
15093
15110
|
for (const feature of sortedFeatures) {
|
|
15094
|
-
const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
|
|
15111
|
+
const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
|
|
15095
15112
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
15096
15113
|
continue;
|
|
15097
15114
|
}
|
|
@@ -15126,12 +15143,13 @@ function IsometricCanvas({
|
|
|
15126
15143
|
}
|
|
15127
15144
|
const unitsWithPosition = units.filter((u) => !!u.position);
|
|
15128
15145
|
const sortedUnits = [...unitsWithPosition].sort((a, b) => {
|
|
15146
|
+
if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
|
|
15129
15147
|
const depthA = a.position.x + a.position.y;
|
|
15130
15148
|
const depthB = b.position.x + b.position.y;
|
|
15131
15149
|
return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
|
|
15132
15150
|
});
|
|
15133
15151
|
for (const unit of sortedUnits) {
|
|
15134
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
15152
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
15135
15153
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
15136
15154
|
continue;
|
|
15137
15155
|
}
|
|
@@ -15151,7 +15169,7 @@ function IsometricCanvas({
|
|
|
15151
15169
|
drawH = maxUnitW / ar;
|
|
15152
15170
|
}
|
|
15153
15171
|
if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
|
|
15154
|
-
const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
|
|
15172
|
+
const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
|
|
15155
15173
|
const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
|
|
15156
15174
|
const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
|
|
15157
15175
|
ctx.save();
|
|
@@ -15280,6 +15298,7 @@ function IsometricCanvas({
|
|
|
15280
15298
|
units,
|
|
15281
15299
|
features,
|
|
15282
15300
|
selectedUnitId,
|
|
15301
|
+
tileLayout,
|
|
15283
15302
|
scale,
|
|
15284
15303
|
debug2,
|
|
15285
15304
|
resolveTerrainSpriteUrl,
|
|
@@ -15308,14 +15327,14 @@ function IsometricCanvas({
|
|
|
15308
15327
|
if (!selectedUnitId) return;
|
|
15309
15328
|
const unit = units.find((u) => u.id === selectedUnitId);
|
|
15310
15329
|
if (!unit?.position) return;
|
|
15311
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
15330
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
15312
15331
|
const centerX = pos.x + scaledTileWidth / 2;
|
|
15313
15332
|
const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
|
|
15314
15333
|
targetCameraRef.current = {
|
|
15315
15334
|
x: centerX - viewportSize.width / 2,
|
|
15316
15335
|
y: centerY - viewportSize.height / 2
|
|
15317
15336
|
};
|
|
15318
|
-
}, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
15337
|
+
}, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
15319
15338
|
useEffect(() => {
|
|
15320
15339
|
const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
|
|
15321
15340
|
draw(animTimeRef.current);
|
|
@@ -15348,13 +15367,13 @@ function IsometricCanvas({
|
|
|
15348
15367
|
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
15349
15368
|
const adjustedX = world.x - scaledTileWidth / 2;
|
|
15350
15369
|
const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
15351
|
-
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
|
|
15370
|
+
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
|
|
15352
15371
|
const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
|
|
15353
15372
|
if (tileExists) {
|
|
15354
15373
|
if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
|
|
15355
15374
|
onTileHover?.(isoPos.x, isoPos.y);
|
|
15356
15375
|
}
|
|
15357
|
-
}, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
|
|
15376
|
+
}, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
|
|
15358
15377
|
const handleCanvasPointerUp = useCallback((e) => {
|
|
15359
15378
|
singlePointerActiveRef.current = false;
|
|
15360
15379
|
if (enableCamera) handlePointerUp();
|
|
@@ -15363,7 +15382,7 @@ function IsometricCanvas({
|
|
|
15363
15382
|
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
15364
15383
|
const adjustedX = world.x - scaledTileWidth / 2;
|
|
15365
15384
|
const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
15366
|
-
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
|
|
15385
|
+
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
|
|
15367
15386
|
const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
|
|
15368
15387
|
if (clickedUnit && (onUnitClick || unitClickEvent)) {
|
|
15369
15388
|
if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
|
|
@@ -15375,7 +15394,7 @@ function IsometricCanvas({
|
|
|
15375
15394
|
onTileClick?.(isoPos.x, isoPos.y);
|
|
15376
15395
|
}
|
|
15377
15396
|
}
|
|
15378
|
-
}, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
|
|
15397
|
+
}, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
|
|
15379
15398
|
const handleCanvasPointerLeave = useCallback(() => {
|
|
15380
15399
|
handleMouseLeave();
|
|
15381
15400
|
if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
|
|
@@ -45413,7 +45432,8 @@ function ModelLoader({
|
|
|
45413
45432
|
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
45414
45433
|
const model = useMemo(() => {
|
|
45415
45434
|
if (!loadedModel) return null;
|
|
45416
|
-
const cloned =
|
|
45435
|
+
const cloned = clone(loadedModel);
|
|
45436
|
+
cloned.updateMatrixWorld(true);
|
|
45417
45437
|
cloned.traverse((child) => {
|
|
45418
45438
|
if (child instanceof THREE3.Mesh) {
|
|
45419
45439
|
child.castShadow = castShadow;
|
|
@@ -45428,7 +45448,8 @@ function ModelLoader({
|
|
|
45428
45448
|
const size = new THREE3.Vector3();
|
|
45429
45449
|
box.getSize(size);
|
|
45430
45450
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
45431
|
-
|
|
45451
|
+
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
45452
|
+
return 1 / maxDim;
|
|
45432
45453
|
}, [model]);
|
|
45433
45454
|
const scaleArray = useMemo(() => {
|
|
45434
45455
|
const base = typeof scale === "number" ? [scale, scale, scale] : scale;
|
|
@@ -46710,6 +46731,48 @@ var init_HeroOrganism = __esm({
|
|
|
46710
46731
|
_HeroClickInterceptor.displayName = "_HeroClickInterceptor";
|
|
46711
46732
|
}
|
|
46712
46733
|
});
|
|
46734
|
+
function HexStrategyBoard({
|
|
46735
|
+
tiles,
|
|
46736
|
+
units,
|
|
46737
|
+
features,
|
|
46738
|
+
assetManifest,
|
|
46739
|
+
assetBaseUrl,
|
|
46740
|
+
scale = 0.45,
|
|
46741
|
+
showMinimap = true,
|
|
46742
|
+
enableCamera = true,
|
|
46743
|
+
tileClickEvent,
|
|
46744
|
+
unitClickEvent,
|
|
46745
|
+
isLoading,
|
|
46746
|
+
error,
|
|
46747
|
+
className
|
|
46748
|
+
}) {
|
|
46749
|
+
return /* @__PURE__ */ jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsx(
|
|
46750
|
+
IsometricCanvas_default,
|
|
46751
|
+
{
|
|
46752
|
+
tileLayout: "hex",
|
|
46753
|
+
tiles,
|
|
46754
|
+
units,
|
|
46755
|
+
features,
|
|
46756
|
+
assetManifest,
|
|
46757
|
+
assetBaseUrl,
|
|
46758
|
+
scale,
|
|
46759
|
+
showMinimap,
|
|
46760
|
+
enableCamera,
|
|
46761
|
+
tileClickEvent,
|
|
46762
|
+
unitClickEvent,
|
|
46763
|
+
isLoading,
|
|
46764
|
+
error
|
|
46765
|
+
}
|
|
46766
|
+
) });
|
|
46767
|
+
}
|
|
46768
|
+
var init_HexStrategyBoard = __esm({
|
|
46769
|
+
"components/game/organisms/HexStrategyBoard.tsx"() {
|
|
46770
|
+
"use client";
|
|
46771
|
+
init_cn();
|
|
46772
|
+
init_IsometricCanvas();
|
|
46773
|
+
HexStrategyBoard.displayName = "HexStrategyBoard";
|
|
46774
|
+
}
|
|
46775
|
+
});
|
|
46713
46776
|
var LandingPageTemplate;
|
|
46714
46777
|
var init_LandingPageTemplate = __esm({
|
|
46715
46778
|
"components/marketing/templates/LandingPageTemplate.tsx"() {
|
|
@@ -54538,6 +54601,7 @@ var init_component_registry_generated = __esm({
|
|
|
54538
54601
|
init_HealthPanel();
|
|
54539
54602
|
init_HeroOrganism();
|
|
54540
54603
|
init_HeroSection();
|
|
54604
|
+
init_HexStrategyBoard();
|
|
54541
54605
|
init_Icon();
|
|
54542
54606
|
init_InfiniteScrollSentinel();
|
|
54543
54607
|
init_Input();
|
|
@@ -54874,6 +54938,7 @@ var init_component_registry_generated = __esm({
|
|
|
54874
54938
|
"HealthPanel": HealthPanel,
|
|
54875
54939
|
"HeroOrganism": HeroOrganism,
|
|
54876
54940
|
"HeroSection": HeroSection,
|
|
54941
|
+
"HexStrategyBoard": HexStrategyBoard,
|
|
54877
54942
|
"Icon": Icon,
|
|
54878
54943
|
"InfiniteScrollSentinel": InfiniteScrollSentinel,
|
|
54879
54944
|
"Input": Input,
|
|
@@ -27,6 +27,7 @@ import * as React from 'react';
|
|
|
27
27
|
import type { AssetUrl, EventEmit } from '@almadar/core';
|
|
28
28
|
import type { IsometricTile, IsometricUnit, IsometricFeature } from '../organisms/types/isometric';
|
|
29
29
|
import type { ResolvedFrame } from '../organisms/types/spriteAnimation';
|
|
30
|
+
import type { TileLayout } from '../organisms/utils/isometric';
|
|
30
31
|
import type { UiError } from '../../core/atoms/types';
|
|
31
32
|
/** Event Contract:
|
|
32
33
|
* Emits: UI:TILE_CLICK
|
|
@@ -79,6 +80,8 @@ export interface IsometricCanvasProps {
|
|
|
79
80
|
}>;
|
|
80
81
|
/** Declarative event: emits UI:{tileLeaveEvent} with {} on tile leave */
|
|
81
82
|
tileLeaveEvent?: EventEmit<Record<string, never>>;
|
|
83
|
+
/** Tile layout projection: 'isometric' (default 2:1 diamond) or 'hex' (pointy-top offset rows) */
|
|
84
|
+
tileLayout?: TileLayout;
|
|
82
85
|
/** Render scale (0.4 = 40% zoom) */
|
|
83
86
|
scale?: number;
|
|
84
87
|
/** Show debug grid lines and coordinates */
|
|
@@ -129,7 +132,7 @@ export interface IsometricCanvasProps {
|
|
|
129
132
|
effects?: Record<string, string>;
|
|
130
133
|
};
|
|
131
134
|
}
|
|
132
|
-
export declare function IsometricCanvas({ className, isLoading, error, tiles: _tilesPropRaw, units: _unitsPropRaw, features: _featuresPropRaw, selectedUnitId, validMoves, attackTargets, hoveredTile, onTileClick, onUnitClick, onTileHover, onTileLeave, tileClickEvent, unitClickEvent, tileHoverEvent, tileLeaveEvent, scale, debug, backgroundImage, showMinimap, enableCamera, unitScale, spriteHeightRatio, spriteMaxWidthRatio, getTerrainSprite, getFeatureSprite, getUnitSprite, resolveUnitFrame, effectSpriteUrls, onDrawEffects, hasActiveEffects, diamondTopY: diamondTopYProp, assetBaseUrl, assetManifest, }: IsometricCanvasProps): React.JSX.Element;
|
|
135
|
+
export declare function IsometricCanvas({ className, isLoading, error, tiles: _tilesPropRaw, units: _unitsPropRaw, features: _featuresPropRaw, selectedUnitId, validMoves, attackTargets, hoveredTile, onTileClick, onUnitClick, onTileHover, onTileLeave, tileClickEvent, unitClickEvent, tileHoverEvent, tileLeaveEvent, tileLayout, scale, debug, backgroundImage, showMinimap, enableCamera, unitScale, spriteHeightRatio, spriteMaxWidthRatio, getTerrainSprite, getFeatureSprite, getUnitSprite, resolveUnitFrame, effectSpriteUrls, onDrawEffects, hasActiveEffects, diamondTopY: diamondTopYProp, assetBaseUrl, assetManifest, }: IsometricCanvasProps): React.JSX.Element;
|
|
133
136
|
export declare namespace IsometricCanvas {
|
|
134
137
|
var displayName: string;
|
|
135
138
|
}
|
|
@@ -28,4 +28,5 @@ export { GameMenu, type GameMenuProps, type MenuOption } from './GameMenu';
|
|
|
28
28
|
export { GameOverScreen, type GameOverScreenProps, type GameOverStat, type GameOverAction } from './GameOverScreen';
|
|
29
29
|
export { PlatformerCanvas, type PlatformerCanvasProps, type PlatformerPlatform, type PlatformerPlayer } from './PlatformerCanvas';
|
|
30
30
|
export { IsometricCanvas, type IsometricCanvasProps } from './IsometricCanvas';
|
|
31
|
+
export type { TileLayout } from '../organisms/utils/isometric';
|
|
31
32
|
export type { IsometricTile, IsometricUnit, IsometricFeature } from '../organisms/types/isometric';
|
|
@@ -7,6 +7,7 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
7
7
|
var drei = require('@react-three/drei');
|
|
8
8
|
var logger = require('@almadar/logger');
|
|
9
9
|
var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
|
|
10
|
+
var SkeletonUtils = require('three/examples/jsm/utils/SkeletonUtils');
|
|
10
11
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
11
12
|
var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
|
|
12
13
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
@@ -392,7 +393,8 @@ function ModelLoader({
|
|
|
392
393
|
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
393
394
|
const model = React11.useMemo(() => {
|
|
394
395
|
if (!loadedModel) return null;
|
|
395
|
-
const cloned =
|
|
396
|
+
const cloned = SkeletonUtils.clone(loadedModel);
|
|
397
|
+
cloned.updateMatrixWorld(true);
|
|
396
398
|
cloned.traverse((child) => {
|
|
397
399
|
if (child instanceof THREE6__namespace.Mesh) {
|
|
398
400
|
child.castShadow = castShadow;
|
|
@@ -407,7 +409,8 @@ function ModelLoader({
|
|
|
407
409
|
const size = new THREE6__namespace.Vector3();
|
|
408
410
|
box.getSize(size);
|
|
409
411
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
410
|
-
|
|
412
|
+
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
413
|
+
return 1 / maxDim;
|
|
411
414
|
}, [model]);
|
|
412
415
|
const scaleArray = React11.useMemo(() => {
|
|
413
416
|
const base = typeof scale === "number" ? [scale, scale, scale] : scale;
|