@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/runtime/index.cjs
CHANGED
|
@@ -45,6 +45,7 @@ var THREE3 = require('three');
|
|
|
45
45
|
var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
|
|
46
46
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
47
47
|
var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
|
|
48
|
+
var SkeletonUtils = require('three/examples/jsm/utils/SkeletonUtils');
|
|
48
49
|
var fiber = require('@react-three/fiber');
|
|
49
50
|
var drei = require('@react-three/drei');
|
|
50
51
|
var patterns = require('@almadar/patterns');
|
|
@@ -10983,16 +10984,26 @@ var init_useUnitSpriteAtlas = __esm({
|
|
|
10983
10984
|
});
|
|
10984
10985
|
|
|
10985
10986
|
// components/game/organisms/utils/isometric.ts
|
|
10986
|
-
function isoToScreen(tileX, tileY, scale, baseOffsetX) {
|
|
10987
|
+
function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
|
|
10987
10988
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
10988
10989
|
const scaledFloorHeight = FLOOR_HEIGHT * scale;
|
|
10990
|
+
if (layout === "hex") {
|
|
10991
|
+
const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
|
|
10992
|
+
const screenY2 = tileY * (scaledFloorHeight * 0.75);
|
|
10993
|
+
return { x: screenX2, y: screenY2 };
|
|
10994
|
+
}
|
|
10989
10995
|
const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
|
|
10990
10996
|
const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
|
|
10991
10997
|
return { x: screenX, y: screenY };
|
|
10992
10998
|
}
|
|
10993
|
-
function screenToIso(screenX, screenY, scale, baseOffsetX) {
|
|
10999
|
+
function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
|
|
10994
11000
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
10995
11001
|
const scaledFloorHeight = FLOOR_HEIGHT * scale;
|
|
11002
|
+
if (layout === "hex") {
|
|
11003
|
+
const row = Math.round(screenY / (scaledFloorHeight * 0.75));
|
|
11004
|
+
const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
|
|
11005
|
+
return { x: col, y: row };
|
|
11006
|
+
}
|
|
10996
11007
|
const adjustedX = screenX - baseOffsetX;
|
|
10997
11008
|
const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
|
|
10998
11009
|
const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
|
|
@@ -11042,6 +11053,7 @@ function IsometricCanvas({
|
|
|
11042
11053
|
tileHoverEvent,
|
|
11043
11054
|
tileLeaveEvent,
|
|
11044
11055
|
// Rendering options
|
|
11056
|
+
tileLayout = "isometric",
|
|
11045
11057
|
scale = 0.4,
|
|
11046
11058
|
debug: debug2 = false,
|
|
11047
11059
|
backgroundImage = "",
|
|
@@ -11111,13 +11123,17 @@ function IsometricCanvas({
|
|
|
11111
11123
|
);
|
|
11112
11124
|
const sortedTiles = React84.useMemo(() => {
|
|
11113
11125
|
const tiles = [...tilesProp];
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11126
|
+
if (tileLayout === "hex") {
|
|
11127
|
+
tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
|
|
11128
|
+
} else {
|
|
11129
|
+
tiles.sort((a, b) => {
|
|
11130
|
+
const depthA = a.x + a.y;
|
|
11131
|
+
const depthB = b.x + b.y;
|
|
11132
|
+
return depthA !== depthB ? depthA - depthB : a.y - b.y;
|
|
11133
|
+
});
|
|
11134
|
+
}
|
|
11119
11135
|
return tiles;
|
|
11120
|
-
}, [tilesProp]);
|
|
11136
|
+
}, [tilesProp, tileLayout]);
|
|
11121
11137
|
const gridWidth = React84.useMemo(() => {
|
|
11122
11138
|
if (sortedTiles.length === 0) return 0;
|
|
11123
11139
|
return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
|
|
@@ -11231,7 +11247,7 @@ function IsometricCanvas({
|
|
|
11231
11247
|
miniCanvas.width = mW;
|
|
11232
11248
|
miniCanvas.height = mH;
|
|
11233
11249
|
mCtx.clearRect(0, 0, mW, mH);
|
|
11234
|
-
const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
|
|
11250
|
+
const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
|
|
11235
11251
|
const minX = Math.min(...allScreenPos.map((p2) => p2.x));
|
|
11236
11252
|
const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
|
|
11237
11253
|
const minY = Math.min(...allScreenPos.map((p2) => p2.y));
|
|
@@ -11242,7 +11258,7 @@ function IsometricCanvas({
|
|
|
11242
11258
|
const offsetMx = (mW - worldW * scaleM) / 2;
|
|
11243
11259
|
const offsetMy = (mH - worldH * scaleM) / 2;
|
|
11244
11260
|
for (const tile of sortedTiles) {
|
|
11245
|
-
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
|
|
11261
|
+
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
|
|
11246
11262
|
const mx = (pos.x - minX) * scaleM + offsetMx;
|
|
11247
11263
|
const my = (pos.y - minY) * scaleM + offsetMy;
|
|
11248
11264
|
const mTileW = scaledTileWidth * scaleM;
|
|
@@ -11258,7 +11274,7 @@ function IsometricCanvas({
|
|
|
11258
11274
|
}
|
|
11259
11275
|
for (const unit of units) {
|
|
11260
11276
|
if (!unit.position) continue;
|
|
11261
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
11277
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
11262
11278
|
const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
|
|
11263
11279
|
const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
|
|
11264
11280
|
mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
|
|
@@ -11274,7 +11290,7 @@ function IsometricCanvas({
|
|
|
11274
11290
|
mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
|
|
11275
11291
|
mCtx.lineWidth = 1;
|
|
11276
11292
|
mCtx.strokeRect(vLeft, vTop, vW, vH);
|
|
11277
|
-
}, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
|
|
11293
|
+
}, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
|
|
11278
11294
|
const draw = React84.useCallback((animTime) => {
|
|
11279
11295
|
const canvas = canvasRef.current;
|
|
11280
11296
|
if (!canvas) return;
|
|
@@ -11314,7 +11330,7 @@ function IsometricCanvas({
|
|
|
11314
11330
|
const visTop = cam.y - viewportSize.height / cam.zoom;
|
|
11315
11331
|
const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
|
|
11316
11332
|
for (const tile of sortedTiles) {
|
|
11317
|
-
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
|
|
11333
|
+
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
|
|
11318
11334
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
11319
11335
|
continue;
|
|
11320
11336
|
}
|
|
@@ -11394,12 +11410,13 @@ function IsometricCanvas({
|
|
|
11394
11410
|
}
|
|
11395
11411
|
}
|
|
11396
11412
|
const sortedFeatures = [...features].sort((a, b) => {
|
|
11413
|
+
if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
|
|
11397
11414
|
const depthA = a.x + a.y;
|
|
11398
11415
|
const depthB = b.x + b.y;
|
|
11399
11416
|
return depthA !== depthB ? depthA - depthB : a.y - b.y;
|
|
11400
11417
|
});
|
|
11401
11418
|
for (const feature of sortedFeatures) {
|
|
11402
|
-
const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
|
|
11419
|
+
const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
|
|
11403
11420
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
11404
11421
|
continue;
|
|
11405
11422
|
}
|
|
@@ -11434,12 +11451,13 @@ function IsometricCanvas({
|
|
|
11434
11451
|
}
|
|
11435
11452
|
const unitsWithPosition = units.filter((u) => !!u.position);
|
|
11436
11453
|
const sortedUnits = [...unitsWithPosition].sort((a, b) => {
|
|
11454
|
+
if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
|
|
11437
11455
|
const depthA = a.position.x + a.position.y;
|
|
11438
11456
|
const depthB = b.position.x + b.position.y;
|
|
11439
11457
|
return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
|
|
11440
11458
|
});
|
|
11441
11459
|
for (const unit of sortedUnits) {
|
|
11442
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
11460
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
11443
11461
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
11444
11462
|
continue;
|
|
11445
11463
|
}
|
|
@@ -11459,7 +11477,7 @@ function IsometricCanvas({
|
|
|
11459
11477
|
drawH = maxUnitW / ar;
|
|
11460
11478
|
}
|
|
11461
11479
|
if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
|
|
11462
|
-
const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
|
|
11480
|
+
const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
|
|
11463
11481
|
const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
|
|
11464
11482
|
const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
|
|
11465
11483
|
ctx.save();
|
|
@@ -11588,6 +11606,7 @@ function IsometricCanvas({
|
|
|
11588
11606
|
units,
|
|
11589
11607
|
features,
|
|
11590
11608
|
selectedUnitId,
|
|
11609
|
+
tileLayout,
|
|
11591
11610
|
scale,
|
|
11592
11611
|
debug2,
|
|
11593
11612
|
resolveTerrainSpriteUrl,
|
|
@@ -11616,14 +11635,14 @@ function IsometricCanvas({
|
|
|
11616
11635
|
if (!selectedUnitId) return;
|
|
11617
11636
|
const unit = units.find((u) => u.id === selectedUnitId);
|
|
11618
11637
|
if (!unit?.position) return;
|
|
11619
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
11638
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
11620
11639
|
const centerX = pos.x + scaledTileWidth / 2;
|
|
11621
11640
|
const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
|
|
11622
11641
|
targetCameraRef.current = {
|
|
11623
11642
|
x: centerX - viewportSize.width / 2,
|
|
11624
11643
|
y: centerY - viewportSize.height / 2
|
|
11625
11644
|
};
|
|
11626
|
-
}, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
11645
|
+
}, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
11627
11646
|
React84.useEffect(() => {
|
|
11628
11647
|
const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
|
|
11629
11648
|
draw(animTimeRef.current);
|
|
@@ -11656,13 +11675,13 @@ function IsometricCanvas({
|
|
|
11656
11675
|
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
11657
11676
|
const adjustedX = world.x - scaledTileWidth / 2;
|
|
11658
11677
|
const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
11659
|
-
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
|
|
11678
|
+
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
|
|
11660
11679
|
const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
|
|
11661
11680
|
if (tileExists) {
|
|
11662
11681
|
if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
|
|
11663
11682
|
onTileHover?.(isoPos.x, isoPos.y);
|
|
11664
11683
|
}
|
|
11665
|
-
}, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
|
|
11684
|
+
}, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
|
|
11666
11685
|
const handleCanvasPointerUp = React84.useCallback((e) => {
|
|
11667
11686
|
singlePointerActiveRef.current = false;
|
|
11668
11687
|
if (enableCamera) handlePointerUp();
|
|
@@ -11671,7 +11690,7 @@ function IsometricCanvas({
|
|
|
11671
11690
|
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
11672
11691
|
const adjustedX = world.x - scaledTileWidth / 2;
|
|
11673
11692
|
const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
11674
|
-
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
|
|
11693
|
+
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
|
|
11675
11694
|
const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
|
|
11676
11695
|
if (clickedUnit && (onUnitClick || unitClickEvent)) {
|
|
11677
11696
|
if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
|
|
@@ -11683,7 +11702,7 @@ function IsometricCanvas({
|
|
|
11683
11702
|
onTileClick?.(isoPos.x, isoPos.y);
|
|
11684
11703
|
}
|
|
11685
11704
|
}
|
|
11686
|
-
}, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
|
|
11705
|
+
}, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
|
|
11687
11706
|
const handleCanvasPointerLeave = React84.useCallback(() => {
|
|
11688
11707
|
handleMouseLeave();
|
|
11689
11708
|
if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
|
|
@@ -42959,7 +42978,8 @@ function ModelLoader({
|
|
|
42959
42978
|
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
42960
42979
|
const model = React84.useMemo(() => {
|
|
42961
42980
|
if (!loadedModel) return null;
|
|
42962
|
-
const cloned =
|
|
42981
|
+
const cloned = SkeletonUtils.clone(loadedModel);
|
|
42982
|
+
cloned.updateMatrixWorld(true);
|
|
42963
42983
|
cloned.traverse((child) => {
|
|
42964
42984
|
if (child instanceof THREE3__namespace.Mesh) {
|
|
42965
42985
|
child.castShadow = castShadow;
|
|
@@ -42974,7 +42994,8 @@ function ModelLoader({
|
|
|
42974
42994
|
const size = new THREE3__namespace.Vector3();
|
|
42975
42995
|
box.getSize(size);
|
|
42976
42996
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
42977
|
-
|
|
42997
|
+
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
42998
|
+
return 1 / maxDim;
|
|
42978
42999
|
}, [model]);
|
|
42979
43000
|
const scaleArray = React84.useMemo(() => {
|
|
42980
43001
|
const base = typeof scale === "number" ? [scale, scale, scale] : scale;
|
|
@@ -44256,6 +44277,48 @@ var init_HeroOrganism = __esm({
|
|
|
44256
44277
|
_HeroClickInterceptor.displayName = "_HeroClickInterceptor";
|
|
44257
44278
|
}
|
|
44258
44279
|
});
|
|
44280
|
+
function HexStrategyBoard({
|
|
44281
|
+
tiles,
|
|
44282
|
+
units,
|
|
44283
|
+
features,
|
|
44284
|
+
assetManifest,
|
|
44285
|
+
assetBaseUrl,
|
|
44286
|
+
scale = 0.45,
|
|
44287
|
+
showMinimap = true,
|
|
44288
|
+
enableCamera = true,
|
|
44289
|
+
tileClickEvent,
|
|
44290
|
+
unitClickEvent,
|
|
44291
|
+
isLoading,
|
|
44292
|
+
error,
|
|
44293
|
+
className
|
|
44294
|
+
}) {
|
|
44295
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
44296
|
+
IsometricCanvas_default,
|
|
44297
|
+
{
|
|
44298
|
+
tileLayout: "hex",
|
|
44299
|
+
tiles,
|
|
44300
|
+
units,
|
|
44301
|
+
features,
|
|
44302
|
+
assetManifest,
|
|
44303
|
+
assetBaseUrl,
|
|
44304
|
+
scale,
|
|
44305
|
+
showMinimap,
|
|
44306
|
+
enableCamera,
|
|
44307
|
+
tileClickEvent,
|
|
44308
|
+
unitClickEvent,
|
|
44309
|
+
isLoading,
|
|
44310
|
+
error
|
|
44311
|
+
}
|
|
44312
|
+
) });
|
|
44313
|
+
}
|
|
44314
|
+
var init_HexStrategyBoard = __esm({
|
|
44315
|
+
"components/game/organisms/HexStrategyBoard.tsx"() {
|
|
44316
|
+
"use client";
|
|
44317
|
+
init_cn();
|
|
44318
|
+
init_IsometricCanvas();
|
|
44319
|
+
HexStrategyBoard.displayName = "HexStrategyBoard";
|
|
44320
|
+
}
|
|
44321
|
+
});
|
|
44259
44322
|
var LandingPageTemplate;
|
|
44260
44323
|
var init_LandingPageTemplate = __esm({
|
|
44261
44324
|
"components/marketing/templates/LandingPageTemplate.tsx"() {
|
|
@@ -52084,6 +52147,7 @@ var init_component_registry_generated = __esm({
|
|
|
52084
52147
|
init_HealthPanel();
|
|
52085
52148
|
init_HeroOrganism();
|
|
52086
52149
|
init_HeroSection();
|
|
52150
|
+
init_HexStrategyBoard();
|
|
52087
52151
|
init_Icon();
|
|
52088
52152
|
init_InfiniteScrollSentinel();
|
|
52089
52153
|
init_Input();
|
|
@@ -52420,6 +52484,7 @@ var init_component_registry_generated = __esm({
|
|
|
52420
52484
|
"HealthPanel": HealthPanel,
|
|
52421
52485
|
"HeroOrganism": HeroOrganism,
|
|
52422
52486
|
"HeroSection": HeroSection,
|
|
52487
|
+
"HexStrategyBoard": HexStrategyBoard,
|
|
52423
52488
|
"Icon": Icon,
|
|
52424
52489
|
"InfiniteScrollSentinel": InfiniteScrollSentinel,
|
|
52425
52490
|
"Input": Input,
|
package/dist/runtime/index.js
CHANGED
|
@@ -45,6 +45,7 @@ import * as THREE3 from 'three';
|
|
|
45
45
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
46
46
|
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
47
47
|
import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
48
|
+
import { clone } from 'three/examples/jsm/utils/SkeletonUtils';
|
|
48
49
|
import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
|
|
49
50
|
import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
|
|
50
51
|
import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
|
|
@@ -10936,16 +10937,26 @@ var init_useUnitSpriteAtlas = __esm({
|
|
|
10936
10937
|
});
|
|
10937
10938
|
|
|
10938
10939
|
// components/game/organisms/utils/isometric.ts
|
|
10939
|
-
function isoToScreen(tileX, tileY, scale, baseOffsetX) {
|
|
10940
|
+
function isoToScreen(tileX, tileY, scale, baseOffsetX, layout = "isometric") {
|
|
10940
10941
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
10941
10942
|
const scaledFloorHeight = FLOOR_HEIGHT * scale;
|
|
10943
|
+
if (layout === "hex") {
|
|
10944
|
+
const screenX2 = tileX * scaledTileWidth + (tileY & 1) * (scaledTileWidth / 2) + baseOffsetX;
|
|
10945
|
+
const screenY2 = tileY * (scaledFloorHeight * 0.75);
|
|
10946
|
+
return { x: screenX2, y: screenY2 };
|
|
10947
|
+
}
|
|
10942
10948
|
const screenX = (tileX - tileY) * (scaledTileWidth / 2) + baseOffsetX;
|
|
10943
10949
|
const screenY = (tileX + tileY) * (scaledFloorHeight / 2);
|
|
10944
10950
|
return { x: screenX, y: screenY };
|
|
10945
10951
|
}
|
|
10946
|
-
function screenToIso(screenX, screenY, scale, baseOffsetX) {
|
|
10952
|
+
function screenToIso(screenX, screenY, scale, baseOffsetX, layout = "isometric") {
|
|
10947
10953
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
10948
10954
|
const scaledFloorHeight = FLOOR_HEIGHT * scale;
|
|
10955
|
+
if (layout === "hex") {
|
|
10956
|
+
const row = Math.round(screenY / (scaledFloorHeight * 0.75));
|
|
10957
|
+
const col = Math.round((screenX - (row & 1) * (scaledTileWidth / 2) - baseOffsetX) / scaledTileWidth);
|
|
10958
|
+
return { x: col, y: row };
|
|
10959
|
+
}
|
|
10949
10960
|
const adjustedX = screenX - baseOffsetX;
|
|
10950
10961
|
const tileX = (adjustedX / (scaledTileWidth / 2) + screenY / (scaledFloorHeight / 2)) / 2;
|
|
10951
10962
|
const tileY = (screenY / (scaledFloorHeight / 2) - adjustedX / (scaledTileWidth / 2)) / 2;
|
|
@@ -10995,6 +11006,7 @@ function IsometricCanvas({
|
|
|
10995
11006
|
tileHoverEvent,
|
|
10996
11007
|
tileLeaveEvent,
|
|
10997
11008
|
// Rendering options
|
|
11009
|
+
tileLayout = "isometric",
|
|
10998
11010
|
scale = 0.4,
|
|
10999
11011
|
debug: debug2 = false,
|
|
11000
11012
|
backgroundImage = "",
|
|
@@ -11064,13 +11076,17 @@ function IsometricCanvas({
|
|
|
11064
11076
|
);
|
|
11065
11077
|
const sortedTiles = useMemo(() => {
|
|
11066
11078
|
const tiles = [...tilesProp];
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11079
|
+
if (tileLayout === "hex") {
|
|
11080
|
+
tiles.sort((a, b) => a.y !== b.y ? a.y - b.y : a.x - b.x);
|
|
11081
|
+
} else {
|
|
11082
|
+
tiles.sort((a, b) => {
|
|
11083
|
+
const depthA = a.x + a.y;
|
|
11084
|
+
const depthB = b.x + b.y;
|
|
11085
|
+
return depthA !== depthB ? depthA - depthB : a.y - b.y;
|
|
11086
|
+
});
|
|
11087
|
+
}
|
|
11072
11088
|
return tiles;
|
|
11073
|
-
}, [tilesProp]);
|
|
11089
|
+
}, [tilesProp, tileLayout]);
|
|
11074
11090
|
const gridWidth = useMemo(() => {
|
|
11075
11091
|
if (sortedTiles.length === 0) return 0;
|
|
11076
11092
|
return Math.max(...sortedTiles.map((t2) => t2.x)) + 1;
|
|
@@ -11184,7 +11200,7 @@ function IsometricCanvas({
|
|
|
11184
11200
|
miniCanvas.width = mW;
|
|
11185
11201
|
miniCanvas.height = mH;
|
|
11186
11202
|
mCtx.clearRect(0, 0, mW, mH);
|
|
11187
|
-
const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX));
|
|
11203
|
+
const allScreenPos = sortedTiles.map((t2) => isoToScreen(t2.x, t2.y, scale, baseOffsetX, tileLayout));
|
|
11188
11204
|
const minX = Math.min(...allScreenPos.map((p2) => p2.x));
|
|
11189
11205
|
const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
|
|
11190
11206
|
const minY = Math.min(...allScreenPos.map((p2) => p2.y));
|
|
@@ -11195,7 +11211,7 @@ function IsometricCanvas({
|
|
|
11195
11211
|
const offsetMx = (mW - worldW * scaleM) / 2;
|
|
11196
11212
|
const offsetMy = (mH - worldH * scaleM) / 2;
|
|
11197
11213
|
for (const tile of sortedTiles) {
|
|
11198
|
-
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
|
|
11214
|
+
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
|
|
11199
11215
|
const mx = (pos.x - minX) * scaleM + offsetMx;
|
|
11200
11216
|
const my = (pos.y - minY) * scaleM + offsetMy;
|
|
11201
11217
|
const mTileW = scaledTileWidth * scaleM;
|
|
@@ -11211,7 +11227,7 @@ function IsometricCanvas({
|
|
|
11211
11227
|
}
|
|
11212
11228
|
for (const unit of units) {
|
|
11213
11229
|
if (!unit.position) continue;
|
|
11214
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
11230
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
11215
11231
|
const mx = (pos.x + scaledTileWidth / 2 - minX) * scaleM + offsetMx;
|
|
11216
11232
|
const my = (pos.y + scaledTileHeight / 2 - minY) * scaleM + offsetMy;
|
|
11217
11233
|
mCtx.fillStyle = unit.team === "player" ? "#60a5fa" : unit.team === "enemy" ? "#f87171" : "#9ca3af";
|
|
@@ -11227,7 +11243,7 @@ function IsometricCanvas({
|
|
|
11227
11243
|
mCtx.strokeStyle = "rgba(255, 255, 255, 0.8)";
|
|
11228
11244
|
mCtx.lineWidth = 1;
|
|
11229
11245
|
mCtx.strokeRect(vLeft, vTop, vW, vH);
|
|
11230
|
-
}, [showMinimap, sortedTiles, units, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
|
|
11246
|
+
}, [showMinimap, sortedTiles, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledTileHeight, scaledFloorHeight, viewportSize, cameraRef]);
|
|
11231
11247
|
const draw = useCallback((animTime) => {
|
|
11232
11248
|
const canvas = canvasRef.current;
|
|
11233
11249
|
if (!canvas) return;
|
|
@@ -11267,7 +11283,7 @@ function IsometricCanvas({
|
|
|
11267
11283
|
const visTop = cam.y - viewportSize.height / cam.zoom;
|
|
11268
11284
|
const visBottom = cam.y + viewportSize.height * 2 / cam.zoom;
|
|
11269
11285
|
for (const tile of sortedTiles) {
|
|
11270
|
-
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX);
|
|
11286
|
+
const pos = isoToScreen(tile.x, tile.y, scale, baseOffsetX, tileLayout);
|
|
11271
11287
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
11272
11288
|
continue;
|
|
11273
11289
|
}
|
|
@@ -11347,12 +11363,13 @@ function IsometricCanvas({
|
|
|
11347
11363
|
}
|
|
11348
11364
|
}
|
|
11349
11365
|
const sortedFeatures = [...features].sort((a, b) => {
|
|
11366
|
+
if (tileLayout === "hex") return a.y !== b.y ? a.y - b.y : a.x - b.x;
|
|
11350
11367
|
const depthA = a.x + a.y;
|
|
11351
11368
|
const depthB = b.x + b.y;
|
|
11352
11369
|
return depthA !== depthB ? depthA - depthB : a.y - b.y;
|
|
11353
11370
|
});
|
|
11354
11371
|
for (const feature of sortedFeatures) {
|
|
11355
|
-
const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX);
|
|
11372
|
+
const pos = isoToScreen(feature.x, feature.y, scale, baseOffsetX, tileLayout);
|
|
11356
11373
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
11357
11374
|
continue;
|
|
11358
11375
|
}
|
|
@@ -11387,12 +11404,13 @@ function IsometricCanvas({
|
|
|
11387
11404
|
}
|
|
11388
11405
|
const unitsWithPosition = units.filter((u) => !!u.position);
|
|
11389
11406
|
const sortedUnits = [...unitsWithPosition].sort((a, b) => {
|
|
11407
|
+
if (tileLayout === "hex") return a.position.y !== b.position.y ? a.position.y - b.position.y : a.position.x - b.position.x;
|
|
11390
11408
|
const depthA = a.position.x + a.position.y;
|
|
11391
11409
|
const depthB = b.position.x + b.position.y;
|
|
11392
11410
|
return depthA !== depthB ? depthA - depthB : a.position.y - b.position.y;
|
|
11393
11411
|
});
|
|
11394
11412
|
for (const unit of sortedUnits) {
|
|
11395
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
11413
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
11396
11414
|
if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
|
|
11397
11415
|
continue;
|
|
11398
11416
|
}
|
|
@@ -11412,7 +11430,7 @@ function IsometricCanvas({
|
|
|
11412
11430
|
drawH = maxUnitW / ar;
|
|
11413
11431
|
}
|
|
11414
11432
|
if (unit.previousPosition && (unit.previousPosition.x !== unit.position.x || unit.previousPosition.y !== unit.position.y)) {
|
|
11415
|
-
const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX);
|
|
11433
|
+
const ghostPos = isoToScreen(unit.previousPosition.x, unit.previousPosition.y, scale, baseOffsetX, tileLayout);
|
|
11416
11434
|
const ghostCenterX = ghostPos.x + scaledTileWidth / 2;
|
|
11417
11435
|
const ghostGroundY = ghostPos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
|
|
11418
11436
|
ctx.save();
|
|
@@ -11541,6 +11559,7 @@ function IsometricCanvas({
|
|
|
11541
11559
|
units,
|
|
11542
11560
|
features,
|
|
11543
11561
|
selectedUnitId,
|
|
11562
|
+
tileLayout,
|
|
11544
11563
|
scale,
|
|
11545
11564
|
debug2,
|
|
11546
11565
|
resolveTerrainSpriteUrl,
|
|
@@ -11569,14 +11588,14 @@ function IsometricCanvas({
|
|
|
11569
11588
|
if (!selectedUnitId) return;
|
|
11570
11589
|
const unit = units.find((u) => u.id === selectedUnitId);
|
|
11571
11590
|
if (!unit?.position) return;
|
|
11572
|
-
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX);
|
|
11591
|
+
const pos = isoToScreen(unit.position.x, unit.position.y, scale, baseOffsetX, tileLayout);
|
|
11573
11592
|
const centerX = pos.x + scaledTileWidth / 2;
|
|
11574
11593
|
const centerY = pos.y + scaledDiamondTopY + scaledFloorHeight / 2;
|
|
11575
11594
|
targetCameraRef.current = {
|
|
11576
11595
|
x: centerX - viewportSize.width / 2,
|
|
11577
11596
|
y: centerY - viewportSize.height / 2
|
|
11578
11597
|
};
|
|
11579
|
-
}, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
11598
|
+
}, [selectedUnitId, units, tileLayout, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
11580
11599
|
useEffect(() => {
|
|
11581
11600
|
const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
|
|
11582
11601
|
draw(animTimeRef.current);
|
|
@@ -11609,13 +11628,13 @@ function IsometricCanvas({
|
|
|
11609
11628
|
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
11610
11629
|
const adjustedX = world.x - scaledTileWidth / 2;
|
|
11611
11630
|
const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
11612
|
-
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
|
|
11631
|
+
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
|
|
11613
11632
|
const tileExists = tilesProp.some((t2) => t2.x === isoPos.x && t2.y === isoPos.y);
|
|
11614
11633
|
if (tileExists) {
|
|
11615
11634
|
if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
|
|
11616
11635
|
onTileHover?.(isoPos.x, isoPos.y);
|
|
11617
11636
|
}
|
|
11618
|
-
}, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
|
|
11637
|
+
}, [onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
|
|
11619
11638
|
const handleCanvasPointerUp = useCallback((e) => {
|
|
11620
11639
|
singlePointerActiveRef.current = false;
|
|
11621
11640
|
if (enableCamera) handlePointerUp();
|
|
@@ -11624,7 +11643,7 @@ function IsometricCanvas({
|
|
|
11624
11643
|
const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
|
|
11625
11644
|
const adjustedX = world.x - scaledTileWidth / 2;
|
|
11626
11645
|
const adjustedY = world.y - scaledDiamondTopY - scaledFloorHeight / 2;
|
|
11627
|
-
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
|
|
11646
|
+
const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX, tileLayout);
|
|
11628
11647
|
const clickedUnit = units.find((u) => u.position?.x === isoPos.x && u.position?.y === isoPos.y);
|
|
11629
11648
|
if (clickedUnit && (onUnitClick || unitClickEvent)) {
|
|
11630
11649
|
if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
|
|
@@ -11636,7 +11655,7 @@ function IsometricCanvas({
|
|
|
11636
11655
|
onTileClick?.(isoPos.x, isoPos.y);
|
|
11637
11656
|
}
|
|
11638
11657
|
}
|
|
11639
|
-
}, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
|
|
11658
|
+
}, [enableCamera, handlePointerUp, dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, tileLayout, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
|
|
11640
11659
|
const handleCanvasPointerLeave = useCallback(() => {
|
|
11641
11660
|
handleMouseLeave();
|
|
11642
11661
|
if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
|
|
@@ -42912,7 +42931,8 @@ function ModelLoader({
|
|
|
42912
42931
|
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
42913
42932
|
const model = useMemo(() => {
|
|
42914
42933
|
if (!loadedModel) return null;
|
|
42915
|
-
const cloned =
|
|
42934
|
+
const cloned = clone(loadedModel);
|
|
42935
|
+
cloned.updateMatrixWorld(true);
|
|
42916
42936
|
cloned.traverse((child) => {
|
|
42917
42937
|
if (child instanceof THREE3.Mesh) {
|
|
42918
42938
|
child.castShadow = castShadow;
|
|
@@ -42927,7 +42947,8 @@ function ModelLoader({
|
|
|
42927
42947
|
const size = new THREE3.Vector3();
|
|
42928
42948
|
box.getSize(size);
|
|
42929
42949
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
42930
|
-
|
|
42950
|
+
if (!Number.isFinite(maxDim) || maxDim < 0.05) return 1;
|
|
42951
|
+
return 1 / maxDim;
|
|
42931
42952
|
}, [model]);
|
|
42932
42953
|
const scaleArray = useMemo(() => {
|
|
42933
42954
|
const base = typeof scale === "number" ? [scale, scale, scale] : scale;
|
|
@@ -44209,6 +44230,48 @@ var init_HeroOrganism = __esm({
|
|
|
44209
44230
|
_HeroClickInterceptor.displayName = "_HeroClickInterceptor";
|
|
44210
44231
|
}
|
|
44211
44232
|
});
|
|
44233
|
+
function HexStrategyBoard({
|
|
44234
|
+
tiles,
|
|
44235
|
+
units,
|
|
44236
|
+
features,
|
|
44237
|
+
assetManifest,
|
|
44238
|
+
assetBaseUrl,
|
|
44239
|
+
scale = 0.45,
|
|
44240
|
+
showMinimap = true,
|
|
44241
|
+
enableCamera = true,
|
|
44242
|
+
tileClickEvent,
|
|
44243
|
+
unitClickEvent,
|
|
44244
|
+
isLoading,
|
|
44245
|
+
error,
|
|
44246
|
+
className
|
|
44247
|
+
}) {
|
|
44248
|
+
return /* @__PURE__ */ jsx("div", { className: cn("hex-strategy-board relative w-full h-full", className), children: /* @__PURE__ */ jsx(
|
|
44249
|
+
IsometricCanvas_default,
|
|
44250
|
+
{
|
|
44251
|
+
tileLayout: "hex",
|
|
44252
|
+
tiles,
|
|
44253
|
+
units,
|
|
44254
|
+
features,
|
|
44255
|
+
assetManifest,
|
|
44256
|
+
assetBaseUrl,
|
|
44257
|
+
scale,
|
|
44258
|
+
showMinimap,
|
|
44259
|
+
enableCamera,
|
|
44260
|
+
tileClickEvent,
|
|
44261
|
+
unitClickEvent,
|
|
44262
|
+
isLoading,
|
|
44263
|
+
error
|
|
44264
|
+
}
|
|
44265
|
+
) });
|
|
44266
|
+
}
|
|
44267
|
+
var init_HexStrategyBoard = __esm({
|
|
44268
|
+
"components/game/organisms/HexStrategyBoard.tsx"() {
|
|
44269
|
+
"use client";
|
|
44270
|
+
init_cn();
|
|
44271
|
+
init_IsometricCanvas();
|
|
44272
|
+
HexStrategyBoard.displayName = "HexStrategyBoard";
|
|
44273
|
+
}
|
|
44274
|
+
});
|
|
44212
44275
|
var LandingPageTemplate;
|
|
44213
44276
|
var init_LandingPageTemplate = __esm({
|
|
44214
44277
|
"components/marketing/templates/LandingPageTemplate.tsx"() {
|
|
@@ -52037,6 +52100,7 @@ var init_component_registry_generated = __esm({
|
|
|
52037
52100
|
init_HealthPanel();
|
|
52038
52101
|
init_HeroOrganism();
|
|
52039
52102
|
init_HeroSection();
|
|
52103
|
+
init_HexStrategyBoard();
|
|
52040
52104
|
init_Icon();
|
|
52041
52105
|
init_InfiniteScrollSentinel();
|
|
52042
52106
|
init_Input();
|
|
@@ -52373,6 +52437,7 @@ var init_component_registry_generated = __esm({
|
|
|
52373
52437
|
"HealthPanel": HealthPanel,
|
|
52374
52438
|
"HeroOrganism": HeroOrganism,
|
|
52375
52439
|
"HeroSection": HeroSection,
|
|
52440
|
+
"HexStrategyBoard": HexStrategyBoard,
|
|
52376
52441
|
"Icon": Icon,
|
|
52377
52442
|
"InfiniteScrollSentinel": InfiniteScrollSentinel,
|
|
52378
52443
|
"Input": Input,
|