@almadar/ui 5.61.0 → 5.63.1

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.
Files changed (61) hide show
  1. package/dist/avl/index.cjs +3599 -1810
  2. package/dist/avl/index.js +2431 -642
  3. package/dist/components/core/atoms/Box.d.ts +2 -0
  4. package/dist/components/core/molecules/CalendarGrid.d.ts +9 -1
  5. package/dist/components/core/molecules/GraphCanvas.d.ts +4 -0
  6. package/dist/components/core/molecules/PositionedCanvas.d.ts +14 -1
  7. package/dist/components/core/molecules/ReplyTree.d.ts +13 -1
  8. package/dist/components/core/templates/index.d.ts +4 -0
  9. package/dist/components/game/molecules/CardHand.d.ts +35 -0
  10. package/dist/components/game/molecules/DialogueBox.d.ts +8 -2
  11. package/dist/components/game/molecules/index.d.ts +1 -0
  12. package/dist/components/game/molecules/three/index.cjs +283 -115
  13. package/dist/components/game/molecules/three/index.js +283 -115
  14. package/dist/components/game/organisms/CardBattlerBoard.d.ts +46 -0
  15. package/dist/components/game/organisms/CityBuilderBoard.d.ts +63 -0
  16. package/dist/components/game/organisms/TopDownShooterBoard.d.ts +64 -0
  17. package/dist/components/game/organisms/TowerDefenseBoard.d.ts +10 -1
  18. package/dist/components/game/organisms/TraitSlot.d.ts +1 -3
  19. package/dist/components/game/organisms/VisualNovelBoard.d.ts +53 -0
  20. package/dist/components/game/organisms/hooks/useCamera.d.ts +16 -0
  21. package/dist/components/game/organisms/index.d.ts +4 -0
  22. package/dist/components/game/templates/CardBattlerTemplate.d.ts +35 -0
  23. package/dist/components/game/templates/CityBuilderTemplate.d.ts +40 -0
  24. package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +5 -2
  25. package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +5 -2
  26. package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +5 -2
  27. package/dist/components/game/templates/TopDownShooterTemplate.d.ts +42 -0
  28. package/dist/components/game/templates/VisualNovelTemplate.d.ts +28 -0
  29. package/dist/components/game/templates/game3dAssetManifest.d.ts +50 -0
  30. package/dist/components/game/templates/index.d.ts +4 -0
  31. package/dist/components/index.cjs +3465 -1659
  32. package/dist/components/index.js +2444 -647
  33. package/dist/components/marketing/organisms/CaseStudyOrganism.d.ts +10 -1
  34. package/dist/components/marketing/organisms/FeatureGridOrganism.d.ts +10 -1
  35. package/dist/components/marketing/organisms/HeroOrganism.d.ts +24 -1
  36. package/dist/components/marketing/organisms/PricingOrganism.d.ts +14 -1
  37. package/dist/components/marketing/organisms/ShowcaseOrganism.d.ts +14 -1
  38. package/dist/components/marketing/organisms/StatsOrganism.d.ts +6 -1
  39. package/dist/components/marketing/organisms/StepFlowOrganism.d.ts +9 -1
  40. package/dist/components/marketing/organisms/TeamOrganism.d.ts +10 -1
  41. package/dist/docs/index.cjs +169 -1
  42. package/dist/docs/index.d.cts +2 -0
  43. package/dist/docs/index.js +169 -1
  44. package/dist/hooks/index.cjs +253 -1
  45. package/dist/hooks/index.d.ts +2 -0
  46. package/dist/hooks/index.js +252 -2
  47. package/dist/hooks/useCanvasGestures.d.ts +44 -0
  48. package/dist/hooks/useTapReveal.d.ts +32 -0
  49. package/dist/locales/index.cjs +315 -3
  50. package/dist/locales/index.js +315 -3
  51. package/dist/marketing/index.cjs +59 -0
  52. package/dist/marketing/index.d.cts +2 -0
  53. package/dist/marketing/index.js +59 -0
  54. package/dist/providers/index.cjs +3408 -1619
  55. package/dist/providers/index.js +2407 -618
  56. package/dist/runtime/index.cjs +3464 -1675
  57. package/dist/runtime/index.js +2411 -622
  58. package/locales/ar.json +105 -1
  59. package/locales/en.json +105 -1
  60. package/locales/sl.json +105 -1
  61. package/package.json +2 -2
@@ -401,12 +401,18 @@ function ModelLoader({
401
401
  });
402
402
  return cloned;
403
403
  }, [loadedModel, castShadow, receiveShadow]);
404
+ const normFactor = React11.useMemo(() => {
405
+ if (!model) return 1;
406
+ const box = new THREE6__namespace.Box3().setFromObject(model);
407
+ const size = new THREE6__namespace.Vector3();
408
+ box.getSize(size);
409
+ const maxDim = Math.max(size.x, size.y, size.z);
410
+ return maxDim > 0 && Number.isFinite(maxDim) ? 1 / maxDim : 1;
411
+ }, [model]);
404
412
  const scaleArray = React11.useMemo(() => {
405
- if (typeof scale === "number") {
406
- return [scale, scale, scale];
407
- }
408
- return scale;
409
- }, [scale]);
413
+ const base = typeof scale === "number" ? [scale, scale, scale] : scale;
414
+ return [base[0] * normFactor, base[1] * normFactor, base[2] * normFactor];
415
+ }, [scale, normFactor]);
410
416
  const rotationRad = React11.useMemo(() => {
411
417
  return [
412
418
  rotation[0] * Math.PI / 180,
@@ -2590,6 +2596,29 @@ var GameCanvas3D = React11.forwardRef(
2590
2596
  const controlsRef = React11.useRef(null);
2591
2597
  const [hoveredTile, setHoveredTile] = React11.useState(null);
2592
2598
  const [internalError, setInternalError] = React11.useState(null);
2599
+ React11.useEffect(() => {
2600
+ const el = containerRef.current;
2601
+ if (!el) return;
2602
+ let node = el;
2603
+ let depth = 0;
2604
+ while (node && depth < 8) {
2605
+ const cs = window.getComputedStyle(node);
2606
+ const rect = node.getBoundingClientRect();
2607
+ console.log("[almadar:ui:game:3d-height]", {
2608
+ depth,
2609
+ tag: node.tagName,
2610
+ id: node.id || void 0,
2611
+ className: node.className?.slice?.(0, 60) || void 0,
2612
+ rectHeight: rect.height,
2613
+ computedHeight: cs.height,
2614
+ computedMinHeight: cs.minHeight,
2615
+ computedFlex: cs.flex,
2616
+ computedOverflow: cs.overflow
2617
+ });
2618
+ node = node.parentElement;
2619
+ depth++;
2620
+ }
2621
+ }, []);
2593
2622
  const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
2594
2623
  const preloadUrls = React11.useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
2595
2624
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
@@ -2979,7 +3008,7 @@ var GameCanvas3D = React11.forwardRef(
2979
3008
  {
2980
3009
  ref: containerRef,
2981
3010
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
2982
- style: { minHeight: "85vh" },
3011
+ style: { height: "85vh" },
2983
3012
  "data-orientation": orientation,
2984
3013
  "data-camera-mode": cameraMode,
2985
3014
  "data-overlay": overlay,
@@ -2994,7 +3023,7 @@ var GameCanvas3D = React11.forwardRef(
2994
3023
  near: 0.1,
2995
3024
  far: 1e3
2996
3025
  },
2997
- style: { background: backgroundColor, height: "85vh", width: "100%" },
3026
+ style: { background: backgroundColor, position: "absolute", inset: 0 },
2998
3027
  onClick: (e) => {
2999
3028
  if (e.target === e.currentTarget) {
3000
3029
  eventHandlers.handleCanvasClick(e);
@@ -3072,6 +3101,9 @@ var GameCanvas3D = React11.forwardRef(
3072
3101
  target: cameraTarget,
3073
3102
  enableDamping: true,
3074
3103
  dampingFactor: 0.05,
3104
+ enableZoom: true,
3105
+ enablePan: true,
3106
+ touches: { ONE: THREE6__namespace.TOUCH.ROTATE, TWO: THREE6__namespace.TOUCH.DOLLY_PAN },
3075
3107
  minDistance: 2,
3076
3108
  maxDistance: 100,
3077
3109
  maxPolarAngle: Math.PI / 2 - 0.1
@@ -4409,6 +4441,51 @@ function GameBoard3D({
4409
4441
  ] });
4410
4442
  }
4411
4443
  GameBoard3D.displayName = "GameBoard3D";
4444
+ function useTapReveal(options = {}) {
4445
+ const { onReveal, onDismiss, refs, enabled = true } = options;
4446
+ const [revealed, setRevealed] = React11.useState(false);
4447
+ const onRevealRef = React11.useRef(onReveal);
4448
+ const onDismissRef = React11.useRef(onDismiss);
4449
+ onRevealRef.current = onReveal;
4450
+ onDismissRef.current = onDismiss;
4451
+ const reveal = React11.useCallback(() => {
4452
+ setRevealed((wasRevealed) => {
4453
+ if (!wasRevealed) onRevealRef.current?.();
4454
+ return true;
4455
+ });
4456
+ }, []);
4457
+ const dismiss = React11.useCallback(() => {
4458
+ setRevealed((wasRevealed) => {
4459
+ if (wasRevealed) onDismissRef.current?.();
4460
+ return false;
4461
+ });
4462
+ }, []);
4463
+ const onPointerDown = React11.useCallback(
4464
+ (e) => {
4465
+ if (!enabled || e.pointerType === "mouse") return;
4466
+ if (revealed) dismiss();
4467
+ else reveal();
4468
+ },
4469
+ [enabled, revealed, reveal, dismiss]
4470
+ );
4471
+ React11.useEffect(() => {
4472
+ if (!revealed || typeof document === "undefined") return;
4473
+ const onDocDown = (ev) => {
4474
+ const target = ev.target;
4475
+ if (!(target instanceof Node)) return;
4476
+ const inside = (refs ?? []).some((r) => r.current?.contains(target));
4477
+ if (!inside) dismiss();
4478
+ };
4479
+ const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
4480
+ return () => {
4481
+ clearTimeout(id);
4482
+ document.removeEventListener("pointerdown", onDocDown);
4483
+ };
4484
+ }, [revealed, refs, dismiss]);
4485
+ return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
4486
+ }
4487
+
4488
+ // components/core/atoms/Box.tsx
4412
4489
  var paddingStyles = {
4413
4490
  none: "p-0",
4414
4491
  xs: "p-1",
@@ -4534,10 +4611,12 @@ var Box = React11__default.default.forwardRef(
4534
4611
  action,
4535
4612
  actionPayload,
4536
4613
  hoverEvent,
4614
+ tapReveal = true,
4537
4615
  maxWidth,
4538
4616
  onClick,
4539
4617
  onMouseEnter,
4540
4618
  onMouseLeave,
4619
+ onPointerDown,
4541
4620
  ...rest
4542
4621
  }, ref) => {
4543
4622
  const eventBus = useEventBus();
@@ -4560,6 +4639,19 @@ var Box = React11__default.default.forwardRef(
4560
4639
  }
4561
4640
  onMouseLeave?.(e);
4562
4641
  }, [hoverEvent, eventBus, onMouseLeave]);
4642
+ const { triggerProps } = useTapReveal({
4643
+ enabled: tapReveal && !!hoverEvent,
4644
+ onReveal: React11.useCallback(() => {
4645
+ if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
4646
+ }, [hoverEvent, eventBus]),
4647
+ onDismiss: React11.useCallback(() => {
4648
+ if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
4649
+ }, [hoverEvent, eventBus])
4650
+ });
4651
+ const handlePointerDown = React11.useCallback((e) => {
4652
+ if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
4653
+ onPointerDown?.(e);
4654
+ }, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
4563
4655
  const isClickable = action || onClick;
4564
4656
  return React11__default.default.createElement(
4565
4657
  Component2,
@@ -4587,6 +4679,7 @@ var Box = React11__default.default.forwardRef(
4587
4679
  onClick: isClickable ? handleClick : void 0,
4588
4680
  onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
4589
4681
  onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
4682
+ onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
4590
4683
  style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
4591
4684
  ...rest
4592
4685
  },
@@ -4595,36 +4688,113 @@ var Box = React11__default.default.forwardRef(
4595
4688
  }
4596
4689
  );
4597
4690
  Box.displayName = "Box";
4598
- var CDN = "https://almadar-kflow-assets.web.app/shared/3d/dungeon/floor";
4599
- var FLOOR_WALL = `${CDN}/template-floor-detail-a.glb`;
4600
- var FLOOR_DIRT = `${CDN}/template-floor-detail.glb`;
4601
- var FLOOR_OPEN = `${CDN}/template-floor.glb`;
4602
- var DEFAULT_3D_BATTLE_TILES = [
4603
- { id: "t00", x: 0, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4604
- { id: "t10", x: 1, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4605
- { id: "t20", x: 2, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4606
- { id: "t30", x: 3, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4607
- { id: "t40", x: 4, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4608
- { id: "t01", x: 0, y: 1, z: 1, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4609
- { id: "t11", x: 1, y: 1, z: 1, type: "dirt", passable: true, modelUrl: FLOOR_DIRT },
4610
- { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4611
- { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4612
- { id: "t41", x: 4, y: 1, z: 1, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4613
- { id: "t02", x: 0, y: 2, z: 2, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4614
- { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4615
- { id: "t22", x: 2, y: 2, z: 2, type: "dirt", passable: true, modelUrl: FLOOR_DIRT },
4616
- { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4617
- { id: "t42", x: 4, y: 2, z: 2, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4618
- { id: "t03", x: 0, y: 3, z: 3, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4619
- { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4620
- { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4621
- { id: "t33", x: 3, y: 3, z: 3, type: "dirt", passable: true, modelUrl: FLOOR_DIRT },
4622
- { id: "t43", x: 4, y: 3, z: 3, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4623
- { id: "t04", x: 0, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4624
- { id: "t14", x: 1, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4625
- { id: "t24", x: 2, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4626
- { id: "t34", x: 3, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4627
- { id: "t44", x: 4, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL }
4691
+
4692
+ // components/game/templates/game3dAssetManifest.ts
4693
+ function resolveManifestUrl(manifest, relative) {
4694
+ if (relative == null) return void 0;
4695
+ if (/^https?:\/\//.test(relative)) return relative;
4696
+ const base = manifest?.baseUrl;
4697
+ if (base == null) return relative;
4698
+ const cleanBase = base.replace(/\/$/, "");
4699
+ const cleanRel = relative.replace(/^\//, "");
4700
+ return `${cleanBase}/${cleanRel}`;
4701
+ }
4702
+ function tileKind(type, passable) {
4703
+ if (passable === false) return "wall";
4704
+ if (type === "dirt" || type === "road") return "dirt";
4705
+ return "open";
4706
+ }
4707
+ function resolveTilesWithModels(layout, manifest) {
4708
+ return layout.map((t) => {
4709
+ const kind = t.kind || tileKind(t.type, t.passable);
4710
+ return {
4711
+ id: t.id,
4712
+ x: t.x,
4713
+ y: t.y,
4714
+ z: t.z,
4715
+ type: t.type,
4716
+ passable: t.passable,
4717
+ modelUrl: resolveManifestUrl(manifest, manifest?.models?.[kind])
4718
+ };
4719
+ });
4720
+ }
4721
+ function resolvePropTiles(tiles, manifest) {
4722
+ return tiles.map((t) => {
4723
+ const kind = tileKind(t.type ?? "", t.passable);
4724
+ return {
4725
+ ...t,
4726
+ modelUrl: t.modelUrl ?? resolveManifestUrl(manifest, manifest?.models?.[kind])
4727
+ };
4728
+ });
4729
+ }
4730
+ function resolveEntityTiles(entity, manifest) {
4731
+ const row = boardEntity(entity);
4732
+ if (!row) return [];
4733
+ return rows(row.tiles).map((r) => {
4734
+ const type = str(r.type) || str(r.terrain);
4735
+ const passable = r.passable !== false;
4736
+ const kind = tileKind(type, passable);
4737
+ const explicitModel = r.modelUrl == null ? void 0 : str(r.modelUrl);
4738
+ return {
4739
+ id: r.id == null ? void 0 : str(r.id),
4740
+ x: num(r.x),
4741
+ y: num(r.y),
4742
+ z: r.z == null ? void 0 : num(r.z),
4743
+ type,
4744
+ passable,
4745
+ modelUrl: explicitModel ?? resolveManifestUrl(manifest, manifest?.models?.[kind])
4746
+ };
4747
+ });
4748
+ }
4749
+ function resolveFeaturesWithModels(features, manifest) {
4750
+ return features.map((f) => ({
4751
+ ...f,
4752
+ assetUrl: f.assetUrl ?? resolveManifestUrl(manifest, manifest?.features?.[f.type])
4753
+ }));
4754
+ }
4755
+ function resolveEntityFeatures(entity, manifest) {
4756
+ const row = boardEntity(entity);
4757
+ if (!row) return [];
4758
+ return rows(row.features).map((r) => {
4759
+ const type = str(r.type);
4760
+ const explicit = r.assetUrl == null ? void 0 : str(r.assetUrl);
4761
+ return {
4762
+ id: r.id == null ? void 0 : str(r.id),
4763
+ x: num(r.x),
4764
+ y: num(r.y),
4765
+ z: r.z == null ? void 0 : num(r.z),
4766
+ type,
4767
+ color: r.color == null ? void 0 : str(r.color),
4768
+ assetUrl: explicit ?? resolveManifestUrl(manifest, manifest?.features?.[type])
4769
+ };
4770
+ });
4771
+ }
4772
+ var DEFAULT_3D_BATTLE_LAYOUT = [
4773
+ { id: "t00", x: 0, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4774
+ { id: "t10", x: 1, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4775
+ { id: "t20", x: 2, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4776
+ { id: "t30", x: 3, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4777
+ { id: "t40", x: 4, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4778
+ { id: "t01", x: 0, y: 1, z: 1, type: "stone", passable: false, kind: "wall" },
4779
+ { id: "t11", x: 1, y: 1, z: 1, type: "dirt", passable: true, kind: "dirt" },
4780
+ { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4781
+ { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4782
+ { id: "t41", x: 4, y: 1, z: 1, type: "stone", passable: false, kind: "wall" },
4783
+ { id: "t02", x: 0, y: 2, z: 2, type: "stone", passable: false, kind: "wall" },
4784
+ { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4785
+ { id: "t22", x: 2, y: 2, z: 2, type: "dirt", passable: true, kind: "dirt" },
4786
+ { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4787
+ { id: "t42", x: 4, y: 2, z: 2, type: "stone", passable: false, kind: "wall" },
4788
+ { id: "t03", x: 0, y: 3, z: 3, type: "stone", passable: false, kind: "wall" },
4789
+ { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4790
+ { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4791
+ { id: "t33", x: 3, y: 3, z: 3, type: "dirt", passable: true, kind: "dirt" },
4792
+ { id: "t43", x: 4, y: 3, z: 3, type: "stone", passable: false, kind: "wall" },
4793
+ { id: "t04", x: 0, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4794
+ { id: "t14", x: 1, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4795
+ { id: "t24", x: 2, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4796
+ { id: "t34", x: 3, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4797
+ { id: "t44", x: 4, y: 4, z: 4, type: "stone", passable: false, kind: "wall" }
4628
4798
  ];
4629
4799
  var DEFAULT_3D_BATTLE_FEATURES = [
4630
4800
  { id: "f1", x: 2, y: 2, z: 2, type: "gold_mine", color: "#f4c542" },
@@ -4632,8 +4802,9 @@ var DEFAULT_3D_BATTLE_FEATURES = [
4632
4802
  ];
4633
4803
  function GameCanvas3DBattleTemplate({
4634
4804
  entity,
4635
- tiles: propTiles = DEFAULT_3D_BATTLE_TILES,
4805
+ tiles: propTiles,
4636
4806
  features: propFeatures = DEFAULT_3D_BATTLE_FEATURES,
4807
+ assetManifest,
4637
4808
  cameraMode = "perspective",
4638
4809
  backgroundColor = "#2a1a1a",
4639
4810
  tileClickEvent,
@@ -4647,11 +4818,12 @@ function GameCanvas3DBattleTemplate({
4647
4818
  scale,
4648
4819
  className
4649
4820
  }) {
4650
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
4651
- const tiles = resolved ? Array.isArray(resolved.tiles) ? resolved.tiles : [] : propTiles;
4652
- const features = resolved ? Array.isArray(resolved.features) ? resolved.features : [] : propFeatures;
4653
- const currentTurn = resolved?.currentTeam;
4654
- const round = resolved?.turn == null ? void 0 : Number(resolved.turn);
4821
+ const row = boardEntity(entity);
4822
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
4823
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_BATTLE_LAYOUT, assetManifest);
4824
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4825
+ const currentTurn = row?.currentTeam == null ? void 0 : String(row.currentTeam);
4826
+ const round = row?.turn == null ? void 0 : Number(row.turn);
4655
4827
  return /* @__PURE__ */ jsxRuntime.jsxs(
4656
4828
  Box,
4657
4829
  {
@@ -4697,36 +4869,32 @@ function GameCanvas3DBattleTemplate({
4697
4869
  );
4698
4870
  }
4699
4871
  GameCanvas3DBattleTemplate.displayName = "GameCanvas3DBattleTemplate";
4700
- var CDN2 = "https://almadar-kflow-assets.web.app/shared/3d/dungeon/floor";
4701
- var FLOOR_WALL2 = `${CDN2}/template-floor-detail-a.glb`;
4702
- var FLOOR_DIRT2 = `${CDN2}/template-floor-detail.glb`;
4703
- var FLOOR_OPEN2 = `${CDN2}/template-floor.glb`;
4704
- var DEFAULT_3D_CASTLE_TILES = [
4705
- { id: "t00", x: 0, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4706
- { id: "t10", x: 1, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4707
- { id: "t20", x: 2, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4708
- { id: "t30", x: 3, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4709
- { id: "t40", x: 4, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4710
- { id: "t01", x: 0, y: 1, z: 1, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4711
- { id: "t11", x: 1, y: 1, z: 1, type: "floor", passable: true, modelUrl: FLOOR_DIRT2 },
4712
- { id: "t21", x: 2, y: 1, z: 1, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4713
- { id: "t31", x: 3, y: 1, z: 1, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4714
- { id: "t41", x: 4, y: 1, z: 1, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4715
- { id: "t02", x: 0, y: 2, z: 2, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4716
- { id: "t12", x: 1, y: 2, z: 2, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4717
- { id: "t22", x: 2, y: 2, z: 2, type: "floor", passable: true, modelUrl: FLOOR_DIRT2 },
4718
- { id: "t32", x: 3, y: 2, z: 2, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4719
- { id: "t42", x: 4, y: 2, z: 2, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4720
- { id: "t03", x: 0, y: 3, z: 3, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4721
- { id: "t13", x: 1, y: 3, z: 3, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4722
- { id: "t23", x: 2, y: 3, z: 3, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4723
- { id: "t33", x: 3, y: 3, z: 3, type: "floor", passable: true, modelUrl: FLOOR_DIRT2 },
4724
- { id: "t43", x: 4, y: 3, z: 3, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4725
- { id: "t04", x: 0, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4726
- { id: "t14", x: 1, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4727
- { id: "t24", x: 2, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4728
- { id: "t34", x: 3, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4729
- { id: "t44", x: 4, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 }
4872
+ var DEFAULT_3D_CASTLE_LAYOUT = [
4873
+ { id: "t00", x: 0, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4874
+ { id: "t10", x: 1, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4875
+ { id: "t20", x: 2, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4876
+ { id: "t30", x: 3, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4877
+ { id: "t40", x: 4, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4878
+ { id: "t01", x: 0, y: 1, z: 1, type: "wall", passable: false, kind: "wall" },
4879
+ { id: "t11", x: 1, y: 1, z: 1, type: "floor", passable: true, kind: "dirt" },
4880
+ { id: "t21", x: 2, y: 1, z: 1, type: "floor", passable: true, kind: "open" },
4881
+ { id: "t31", x: 3, y: 1, z: 1, type: "floor", passable: true, kind: "open" },
4882
+ { id: "t41", x: 4, y: 1, z: 1, type: "wall", passable: false, kind: "wall" },
4883
+ { id: "t02", x: 0, y: 2, z: 2, type: "wall", passable: false, kind: "wall" },
4884
+ { id: "t12", x: 1, y: 2, z: 2, type: "floor", passable: true, kind: "open" },
4885
+ { id: "t22", x: 2, y: 2, z: 2, type: "floor", passable: true, kind: "dirt" },
4886
+ { id: "t32", x: 3, y: 2, z: 2, type: "floor", passable: true, kind: "open" },
4887
+ { id: "t42", x: 4, y: 2, z: 2, type: "wall", passable: false, kind: "wall" },
4888
+ { id: "t03", x: 0, y: 3, z: 3, type: "wall", passable: false, kind: "wall" },
4889
+ { id: "t13", x: 1, y: 3, z: 3, type: "floor", passable: true, kind: "open" },
4890
+ { id: "t23", x: 2, y: 3, z: 3, type: "floor", passable: true, kind: "open" },
4891
+ { id: "t33", x: 3, y: 3, z: 3, type: "floor", passable: true, kind: "dirt" },
4892
+ { id: "t43", x: 4, y: 3, z: 3, type: "wall", passable: false, kind: "wall" },
4893
+ { id: "t04", x: 0, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4894
+ { id: "t14", x: 1, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4895
+ { id: "t24", x: 2, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4896
+ { id: "t34", x: 3, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4897
+ { id: "t44", x: 4, y: 4, z: 4, type: "wall", passable: false, kind: "wall" }
4730
4898
  ];
4731
4899
  var DEFAULT_3D_CASTLE_FEATURES = [
4732
4900
  { id: "f1", x: 2, y: 2, z: 2, type: "chest", color: "#f4c542" },
@@ -4734,8 +4902,9 @@ var DEFAULT_3D_CASTLE_FEATURES = [
4734
4902
  ];
4735
4903
  function GameCanvas3DCastleTemplate({
4736
4904
  entity,
4737
- tiles: propTiles = DEFAULT_3D_CASTLE_TILES,
4905
+ tiles: propTiles,
4738
4906
  features: propFeatures = DEFAULT_3D_CASTLE_FEATURES,
4907
+ assetManifest,
4739
4908
  cameraMode = "isometric",
4740
4909
  backgroundColor = "#1e1e2e",
4741
4910
  buildingClickEvent,
@@ -4750,13 +4919,14 @@ function GameCanvas3DCastleTemplate({
4750
4919
  scale,
4751
4920
  className
4752
4921
  }) {
4753
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
4754
- const tiles = resolved ? Array.isArray(resolved.tiles) ? resolved.tiles : [] : propTiles;
4755
- const features = resolved ? Array.isArray(resolved.features) ? resolved.features : [] : propFeatures;
4756
- const name = resolved?.name == null ? void 0 : String(resolved.name);
4757
- const level = resolved?.level == null ? void 0 : Number(resolved.level);
4758
- const owner = resolved?.owner == null ? void 0 : String(resolved.owner);
4759
- const unitCount = resolved && Array.isArray(resolved.units) ? resolved.units.length : 0;
4922
+ const row = boardEntity(entity);
4923
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
4924
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_CASTLE_LAYOUT, assetManifest);
4925
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4926
+ const name = row?.name == null ? void 0 : str(row.name);
4927
+ const level = row?.level == null ? void 0 : num(row.level);
4928
+ const owner = row?.owner == null ? void 0 : str(row.owner);
4929
+ const unitCount = row && Array.isArray(row.units) ? row.units.length : 0;
4760
4930
  return /* @__PURE__ */ jsxRuntime.jsxs(
4761
4931
  VStack,
4762
4932
  {
@@ -4802,36 +4972,32 @@ function GameCanvas3DCastleTemplate({
4802
4972
  );
4803
4973
  }
4804
4974
  GameCanvas3DCastleTemplate.displayName = "GameCanvas3DCastleTemplate";
4805
- var CDN3 = "https://almadar-kflow-assets.web.app/shared/3d/dungeon/floor";
4806
- var FLOOR_WALL3 = `${CDN3}/template-floor-detail-a.glb`;
4807
- var FLOOR_DIRT3 = `${CDN3}/template-floor-detail.glb`;
4808
- var FLOOR_OPEN3 = `${CDN3}/template-floor.glb`;
4809
- var DEFAULT_3D_WORLDMAP_TILES = [
4810
- { id: "t00", x: 0, y: 0, z: 0, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4811
- { id: "t10", x: 1, y: 0, z: 0, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4812
- { id: "t20", x: 2, y: 0, z: 0, type: "water", passable: false, modelUrl: FLOOR_WALL3 },
4813
- { id: "t30", x: 3, y: 0, z: 0, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4814
- { id: "t40", x: 4, y: 0, z: 0, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4815
- { id: "t01", x: 0, y: 1, z: 1, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4816
- { id: "t11", x: 1, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4817
- { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4818
- { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4819
- { id: "t41", x: 4, y: 1, z: 1, type: "water", passable: false, modelUrl: FLOOR_WALL3 },
4820
- { id: "t02", x: 0, y: 2, z: 2, type: "water", passable: false, modelUrl: FLOOR_WALL3 },
4821
- { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4822
- { id: "t22", x: 2, y: 2, z: 2, type: "road", passable: true, modelUrl: FLOOR_DIRT3 },
4823
- { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4824
- { id: "t42", x: 4, y: 2, z: 2, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4825
- { id: "t03", x: 0, y: 3, z: 3, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4826
- { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4827
- { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4828
- { id: "t33", x: 3, y: 3, z: 3, type: "road", passable: true, modelUrl: FLOOR_DIRT3 },
4829
- { id: "t43", x: 4, y: 3, z: 3, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4830
- { id: "t04", x: 0, y: 4, z: 4, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4831
- { id: "t14", x: 1, y: 4, z: 4, type: "water", passable: false, modelUrl: FLOOR_WALL3 },
4832
- { id: "t24", x: 2, y: 4, z: 4, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4833
- { id: "t34", x: 3, y: 4, z: 4, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4834
- { id: "t44", x: 4, y: 4, z: 4, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 }
4975
+ var DEFAULT_3D_WORLDMAP_LAYOUT = [
4976
+ { id: "t00", x: 0, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4977
+ { id: "t10", x: 1, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4978
+ { id: "t20", x: 2, y: 0, z: 0, type: "water", passable: false, kind: "wall" },
4979
+ { id: "t30", x: 3, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4980
+ { id: "t40", x: 4, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4981
+ { id: "t01", x: 0, y: 1, z: 1, type: "mountain", passable: false, kind: "wall" },
4982
+ { id: "t11", x: 1, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4983
+ { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4984
+ { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4985
+ { id: "t41", x: 4, y: 1, z: 1, type: "water", passable: false, kind: "wall" },
4986
+ { id: "t02", x: 0, y: 2, z: 2, type: "water", passable: false, kind: "wall" },
4987
+ { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4988
+ { id: "t22", x: 2, y: 2, z: 2, type: "road", passable: true, kind: "dirt" },
4989
+ { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4990
+ { id: "t42", x: 4, y: 2, z: 2, type: "mountain", passable: false, kind: "wall" },
4991
+ { id: "t03", x: 0, y: 3, z: 3, type: "mountain", passable: false, kind: "wall" },
4992
+ { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4993
+ { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4994
+ { id: "t33", x: 3, y: 3, z: 3, type: "road", passable: true, kind: "dirt" },
4995
+ { id: "t43", x: 4, y: 3, z: 3, type: "mountain", passable: false, kind: "wall" },
4996
+ { id: "t04", x: 0, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" },
4997
+ { id: "t14", x: 1, y: 4, z: 4, type: "water", passable: false, kind: "wall" },
4998
+ { id: "t24", x: 2, y: 4, z: 4, type: "grass", passable: true, kind: "open" },
4999
+ { id: "t34", x: 3, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" },
5000
+ { id: "t44", x: 4, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" }
4835
5001
  ];
4836
5002
  var DEFAULT_3D_WORLDMAP_FEATURES = [
4837
5003
  { id: "f1", x: 2, y: 2, z: 2, type: "capital", color: "#f4c542" },
@@ -4839,8 +5005,9 @@ var DEFAULT_3D_WORLDMAP_FEATURES = [
4839
5005
  ];
4840
5006
  function GameCanvas3DWorldMapTemplate({
4841
5007
  entity,
4842
- tiles: propTiles = DEFAULT_3D_WORLDMAP_TILES,
5008
+ tiles: propTiles,
4843
5009
  features: propFeatures = DEFAULT_3D_WORLDMAP_FEATURES,
5010
+ assetManifest,
4844
5011
  cameraMode = "isometric",
4845
5012
  backgroundColor = "#1a1a2e",
4846
5013
  tileClickEvent,
@@ -4854,9 +5021,10 @@ function GameCanvas3DWorldMapTemplate({
4854
5021
  scale,
4855
5022
  className
4856
5023
  }) {
4857
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
4858
- const tiles = resolved ? Array.isArray(resolved.tiles) ? resolved.tiles : [] : propTiles;
4859
- const features = resolved ? Array.isArray(resolved.features) ? resolved.features : [] : propFeatures;
5024
+ const row = boardEntity(entity);
5025
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
5026
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_WORLDMAP_LAYOUT, assetManifest);
5027
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4860
5028
  return (
4861
5029
  /* GameBoard3D reads selectedUnitId/validMoves/attackTargets from entity */
4862
5030
  /* @__PURE__ */ jsxRuntime.jsx(