@almadar/ui 5.61.0 → 5.62.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.
Files changed (41) hide show
  1. package/dist/avl/index.cjs +3127 -1681
  2. package/dist/avl/index.js +1948 -502
  3. package/dist/components/core/molecules/GraphCanvas.d.ts +4 -0
  4. package/dist/components/core/templates/index.d.ts +4 -0
  5. package/dist/components/game/molecules/CardHand.d.ts +35 -0
  6. package/dist/components/game/molecules/DialogueBox.d.ts +8 -2
  7. package/dist/components/game/molecules/index.d.ts +1 -0
  8. package/dist/components/game/molecules/three/index.cjs +219 -115
  9. package/dist/components/game/molecules/three/index.js +219 -115
  10. package/dist/components/game/organisms/CardBattlerBoard.d.ts +46 -0
  11. package/dist/components/game/organisms/CityBuilderBoard.d.ts +63 -0
  12. package/dist/components/game/organisms/TopDownShooterBoard.d.ts +64 -0
  13. package/dist/components/game/organisms/TowerDefenseBoard.d.ts +10 -1
  14. package/dist/components/game/organisms/TraitSlot.d.ts +1 -3
  15. package/dist/components/game/organisms/VisualNovelBoard.d.ts +53 -0
  16. package/dist/components/game/organisms/index.d.ts +4 -0
  17. package/dist/components/game/templates/CardBattlerTemplate.d.ts +35 -0
  18. package/dist/components/game/templates/CityBuilderTemplate.d.ts +40 -0
  19. package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +5 -2
  20. package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +5 -2
  21. package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +5 -2
  22. package/dist/components/game/templates/TopDownShooterTemplate.d.ts +42 -0
  23. package/dist/components/game/templates/VisualNovelTemplate.d.ts +28 -0
  24. package/dist/components/game/templates/game3dAssetManifest.d.ts +50 -0
  25. package/dist/components/game/templates/index.d.ts +4 -0
  26. package/dist/components/index.cjs +2993 -1529
  27. package/dist/components/index.js +1961 -506
  28. package/dist/docs/index.cjs +105 -1
  29. package/dist/docs/index.js +105 -1
  30. package/dist/hooks/index.cjs +105 -1
  31. package/dist/hooks/index.js +105 -1
  32. package/dist/locales/index.cjs +315 -3
  33. package/dist/locales/index.js +315 -3
  34. package/dist/providers/index.cjs +2936 -1490
  35. package/dist/providers/index.js +1924 -478
  36. package/dist/runtime/index.cjs +2992 -1546
  37. package/dist/runtime/index.js +1928 -482
  38. package/locales/ar.json +105 -1
  39. package/locales/en.json +105 -1
  40. package/locales/sl.json +105 -1
  41. package/package.json +1 -1
@@ -377,12 +377,18 @@ function ModelLoader({
377
377
  });
378
378
  return cloned;
379
379
  }, [loadedModel, castShadow, receiveShadow]);
380
+ const normFactor = useMemo(() => {
381
+ if (!model) return 1;
382
+ const box = new THREE6.Box3().setFromObject(model);
383
+ const size = new THREE6.Vector3();
384
+ box.getSize(size);
385
+ const maxDim = Math.max(size.x, size.y, size.z);
386
+ return maxDim > 0 && Number.isFinite(maxDim) ? 1 / maxDim : 1;
387
+ }, [model]);
380
388
  const scaleArray = useMemo(() => {
381
- if (typeof scale === "number") {
382
- return [scale, scale, scale];
383
- }
384
- return scale;
385
- }, [scale]);
389
+ const base = typeof scale === "number" ? [scale, scale, scale] : scale;
390
+ return [base[0] * normFactor, base[1] * normFactor, base[2] * normFactor];
391
+ }, [scale, normFactor]);
386
392
  const rotationRad = useMemo(() => {
387
393
  return [
388
394
  rotation[0] * Math.PI / 180,
@@ -2566,6 +2572,29 @@ var GameCanvas3D = forwardRef(
2566
2572
  const controlsRef = useRef(null);
2567
2573
  const [hoveredTile, setHoveredTile] = useState(null);
2568
2574
  const [internalError, setInternalError] = useState(null);
2575
+ useEffect(() => {
2576
+ const el = containerRef.current;
2577
+ if (!el) return;
2578
+ let node = el;
2579
+ let depth = 0;
2580
+ while (node && depth < 8) {
2581
+ const cs = window.getComputedStyle(node);
2582
+ const rect = node.getBoundingClientRect();
2583
+ console.log("[almadar:ui:game:3d-height]", {
2584
+ depth,
2585
+ tag: node.tagName,
2586
+ id: node.id || void 0,
2587
+ className: node.className?.slice?.(0, 60) || void 0,
2588
+ rectHeight: rect.height,
2589
+ computedHeight: cs.height,
2590
+ computedMinHeight: cs.minHeight,
2591
+ computedFlex: cs.flex,
2592
+ computedOverflow: cs.overflow
2593
+ });
2594
+ node = node.parentElement;
2595
+ depth++;
2596
+ }
2597
+ }, []);
2569
2598
  const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
2570
2599
  const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
2571
2600
  const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
@@ -2955,7 +2984,7 @@ var GameCanvas3D = forwardRef(
2955
2984
  {
2956
2985
  ref: containerRef,
2957
2986
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
2958
- style: { minHeight: "85vh" },
2987
+ style: { height: "85vh" },
2959
2988
  "data-orientation": orientation,
2960
2989
  "data-camera-mode": cameraMode,
2961
2990
  "data-overlay": overlay,
@@ -2970,7 +2999,7 @@ var GameCanvas3D = forwardRef(
2970
2999
  near: 0.1,
2971
3000
  far: 1e3
2972
3001
  },
2973
- style: { background: backgroundColor, height: "85vh", width: "100%" },
3002
+ style: { background: backgroundColor, position: "absolute", inset: 0 },
2974
3003
  onClick: (e) => {
2975
3004
  if (e.target === e.currentTarget) {
2976
3005
  eventHandlers.handleCanvasClick(e);
@@ -4571,36 +4600,113 @@ var Box = React11.forwardRef(
4571
4600
  }
4572
4601
  );
4573
4602
  Box.displayName = "Box";
4574
- var CDN = "https://almadar-kflow-assets.web.app/shared/3d/dungeon/floor";
4575
- var FLOOR_WALL = `${CDN}/template-floor-detail-a.glb`;
4576
- var FLOOR_DIRT = `${CDN}/template-floor-detail.glb`;
4577
- var FLOOR_OPEN = `${CDN}/template-floor.glb`;
4578
- var DEFAULT_3D_BATTLE_TILES = [
4579
- { id: "t00", x: 0, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4580
- { id: "t10", x: 1, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4581
- { id: "t20", x: 2, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4582
- { id: "t30", x: 3, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4583
- { id: "t40", x: 4, y: 0, z: 0, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4584
- { id: "t01", x: 0, y: 1, z: 1, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4585
- { id: "t11", x: 1, y: 1, z: 1, type: "dirt", passable: true, modelUrl: FLOOR_DIRT },
4586
- { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4587
- { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4588
- { id: "t41", x: 4, y: 1, z: 1, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4589
- { id: "t02", x: 0, y: 2, z: 2, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4590
- { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4591
- { id: "t22", x: 2, y: 2, z: 2, type: "dirt", passable: true, modelUrl: FLOOR_DIRT },
4592
- { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4593
- { id: "t42", x: 4, y: 2, z: 2, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4594
- { id: "t03", x: 0, y: 3, z: 3, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4595
- { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4596
- { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, modelUrl: FLOOR_OPEN },
4597
- { id: "t33", x: 3, y: 3, z: 3, type: "dirt", passable: true, modelUrl: FLOOR_DIRT },
4598
- { id: "t43", x: 4, y: 3, z: 3, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4599
- { id: "t04", x: 0, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4600
- { id: "t14", x: 1, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4601
- { id: "t24", x: 2, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4602
- { id: "t34", x: 3, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL },
4603
- { id: "t44", x: 4, y: 4, z: 4, type: "stone", passable: false, modelUrl: FLOOR_WALL }
4603
+
4604
+ // components/game/templates/game3dAssetManifest.ts
4605
+ function resolveManifestUrl(manifest, relative) {
4606
+ if (relative == null) return void 0;
4607
+ if (/^https?:\/\//.test(relative)) return relative;
4608
+ const base = manifest?.baseUrl;
4609
+ if (base == null) return relative;
4610
+ const cleanBase = base.replace(/\/$/, "");
4611
+ const cleanRel = relative.replace(/^\//, "");
4612
+ return `${cleanBase}/${cleanRel}`;
4613
+ }
4614
+ function tileKind(type, passable) {
4615
+ if (passable === false) return "wall";
4616
+ if (type === "dirt" || type === "road") return "dirt";
4617
+ return "open";
4618
+ }
4619
+ function resolveTilesWithModels(layout, manifest) {
4620
+ return layout.map((t) => {
4621
+ const kind = t.kind || tileKind(t.type, t.passable);
4622
+ return {
4623
+ id: t.id,
4624
+ x: t.x,
4625
+ y: t.y,
4626
+ z: t.z,
4627
+ type: t.type,
4628
+ passable: t.passable,
4629
+ modelUrl: resolveManifestUrl(manifest, manifest?.models?.[kind])
4630
+ };
4631
+ });
4632
+ }
4633
+ function resolvePropTiles(tiles, manifest) {
4634
+ return tiles.map((t) => {
4635
+ const kind = tileKind(t.type ?? "", t.passable);
4636
+ return {
4637
+ ...t,
4638
+ modelUrl: t.modelUrl ?? resolveManifestUrl(manifest, manifest?.models?.[kind])
4639
+ };
4640
+ });
4641
+ }
4642
+ function resolveEntityTiles(entity, manifest) {
4643
+ const row = boardEntity(entity);
4644
+ if (!row) return [];
4645
+ return rows(row.tiles).map((r) => {
4646
+ const type = str(r.type) || str(r.terrain);
4647
+ const passable = r.passable !== false;
4648
+ const kind = tileKind(type, passable);
4649
+ const explicitModel = r.modelUrl == null ? void 0 : str(r.modelUrl);
4650
+ return {
4651
+ id: r.id == null ? void 0 : str(r.id),
4652
+ x: num(r.x),
4653
+ y: num(r.y),
4654
+ z: r.z == null ? void 0 : num(r.z),
4655
+ type,
4656
+ passable,
4657
+ modelUrl: explicitModel ?? resolveManifestUrl(manifest, manifest?.models?.[kind])
4658
+ };
4659
+ });
4660
+ }
4661
+ function resolveFeaturesWithModels(features, manifest) {
4662
+ return features.map((f) => ({
4663
+ ...f,
4664
+ assetUrl: f.assetUrl ?? resolveManifestUrl(manifest, manifest?.features?.[f.type])
4665
+ }));
4666
+ }
4667
+ function resolveEntityFeatures(entity, manifest) {
4668
+ const row = boardEntity(entity);
4669
+ if (!row) return [];
4670
+ return rows(row.features).map((r) => {
4671
+ const type = str(r.type);
4672
+ const explicit = r.assetUrl == null ? void 0 : str(r.assetUrl);
4673
+ return {
4674
+ id: r.id == null ? void 0 : str(r.id),
4675
+ x: num(r.x),
4676
+ y: num(r.y),
4677
+ z: r.z == null ? void 0 : num(r.z),
4678
+ type,
4679
+ color: r.color == null ? void 0 : str(r.color),
4680
+ assetUrl: explicit ?? resolveManifestUrl(manifest, manifest?.features?.[type])
4681
+ };
4682
+ });
4683
+ }
4684
+ var DEFAULT_3D_BATTLE_LAYOUT = [
4685
+ { id: "t00", x: 0, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4686
+ { id: "t10", x: 1, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4687
+ { id: "t20", x: 2, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4688
+ { id: "t30", x: 3, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4689
+ { id: "t40", x: 4, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4690
+ { id: "t01", x: 0, y: 1, z: 1, type: "stone", passable: false, kind: "wall" },
4691
+ { id: "t11", x: 1, y: 1, z: 1, type: "dirt", passable: true, kind: "dirt" },
4692
+ { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4693
+ { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4694
+ { id: "t41", x: 4, y: 1, z: 1, type: "stone", passable: false, kind: "wall" },
4695
+ { id: "t02", x: 0, y: 2, z: 2, type: "stone", passable: false, kind: "wall" },
4696
+ { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4697
+ { id: "t22", x: 2, y: 2, z: 2, type: "dirt", passable: true, kind: "dirt" },
4698
+ { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4699
+ { id: "t42", x: 4, y: 2, z: 2, type: "stone", passable: false, kind: "wall" },
4700
+ { id: "t03", x: 0, y: 3, z: 3, type: "stone", passable: false, kind: "wall" },
4701
+ { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4702
+ { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4703
+ { id: "t33", x: 3, y: 3, z: 3, type: "dirt", passable: true, kind: "dirt" },
4704
+ { id: "t43", x: 4, y: 3, z: 3, type: "stone", passable: false, kind: "wall" },
4705
+ { id: "t04", x: 0, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4706
+ { id: "t14", x: 1, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4707
+ { id: "t24", x: 2, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4708
+ { id: "t34", x: 3, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4709
+ { id: "t44", x: 4, y: 4, z: 4, type: "stone", passable: false, kind: "wall" }
4604
4710
  ];
4605
4711
  var DEFAULT_3D_BATTLE_FEATURES = [
4606
4712
  { id: "f1", x: 2, y: 2, z: 2, type: "gold_mine", color: "#f4c542" },
@@ -4608,8 +4714,9 @@ var DEFAULT_3D_BATTLE_FEATURES = [
4608
4714
  ];
4609
4715
  function GameCanvas3DBattleTemplate({
4610
4716
  entity,
4611
- tiles: propTiles = DEFAULT_3D_BATTLE_TILES,
4717
+ tiles: propTiles,
4612
4718
  features: propFeatures = DEFAULT_3D_BATTLE_FEATURES,
4719
+ assetManifest,
4613
4720
  cameraMode = "perspective",
4614
4721
  backgroundColor = "#2a1a1a",
4615
4722
  tileClickEvent,
@@ -4623,11 +4730,12 @@ function GameCanvas3DBattleTemplate({
4623
4730
  scale,
4624
4731
  className
4625
4732
  }) {
4626
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
4627
- const tiles = resolved ? Array.isArray(resolved.tiles) ? resolved.tiles : [] : propTiles;
4628
- const features = resolved ? Array.isArray(resolved.features) ? resolved.features : [] : propFeatures;
4629
- const currentTurn = resolved?.currentTeam;
4630
- const round = resolved?.turn == null ? void 0 : Number(resolved.turn);
4733
+ const row = boardEntity(entity);
4734
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
4735
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_BATTLE_LAYOUT, assetManifest);
4736
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4737
+ const currentTurn = row?.currentTeam == null ? void 0 : String(row.currentTeam);
4738
+ const round = row?.turn == null ? void 0 : Number(row.turn);
4631
4739
  return /* @__PURE__ */ jsxs(
4632
4740
  Box,
4633
4741
  {
@@ -4673,36 +4781,32 @@ function GameCanvas3DBattleTemplate({
4673
4781
  );
4674
4782
  }
4675
4783
  GameCanvas3DBattleTemplate.displayName = "GameCanvas3DBattleTemplate";
4676
- var CDN2 = "https://almadar-kflow-assets.web.app/shared/3d/dungeon/floor";
4677
- var FLOOR_WALL2 = `${CDN2}/template-floor-detail-a.glb`;
4678
- var FLOOR_DIRT2 = `${CDN2}/template-floor-detail.glb`;
4679
- var FLOOR_OPEN2 = `${CDN2}/template-floor.glb`;
4680
- var DEFAULT_3D_CASTLE_TILES = [
4681
- { id: "t00", x: 0, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4682
- { id: "t10", x: 1, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4683
- { id: "t20", x: 2, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4684
- { id: "t30", x: 3, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4685
- { id: "t40", x: 4, y: 0, z: 0, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4686
- { id: "t01", x: 0, y: 1, z: 1, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4687
- { id: "t11", x: 1, y: 1, z: 1, type: "floor", passable: true, modelUrl: FLOOR_DIRT2 },
4688
- { id: "t21", x: 2, y: 1, z: 1, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4689
- { id: "t31", x: 3, y: 1, z: 1, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4690
- { id: "t41", x: 4, y: 1, z: 1, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4691
- { id: "t02", x: 0, y: 2, z: 2, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4692
- { id: "t12", x: 1, y: 2, z: 2, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4693
- { id: "t22", x: 2, y: 2, z: 2, type: "floor", passable: true, modelUrl: FLOOR_DIRT2 },
4694
- { id: "t32", x: 3, y: 2, z: 2, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4695
- { id: "t42", x: 4, y: 2, z: 2, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4696
- { id: "t03", x: 0, y: 3, z: 3, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4697
- { id: "t13", x: 1, y: 3, z: 3, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4698
- { id: "t23", x: 2, y: 3, z: 3, type: "floor", passable: true, modelUrl: FLOOR_OPEN2 },
4699
- { id: "t33", x: 3, y: 3, z: 3, type: "floor", passable: true, modelUrl: FLOOR_DIRT2 },
4700
- { id: "t43", x: 4, y: 3, z: 3, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4701
- { id: "t04", x: 0, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4702
- { id: "t14", x: 1, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4703
- { id: "t24", x: 2, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4704
- { id: "t34", x: 3, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 },
4705
- { id: "t44", x: 4, y: 4, z: 4, type: "wall", passable: false, modelUrl: FLOOR_WALL2 }
4784
+ var DEFAULT_3D_CASTLE_LAYOUT = [
4785
+ { id: "t00", x: 0, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4786
+ { id: "t10", x: 1, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4787
+ { id: "t20", x: 2, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4788
+ { id: "t30", x: 3, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4789
+ { id: "t40", x: 4, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4790
+ { id: "t01", x: 0, y: 1, z: 1, type: "wall", passable: false, kind: "wall" },
4791
+ { id: "t11", x: 1, y: 1, z: 1, type: "floor", passable: true, kind: "dirt" },
4792
+ { id: "t21", x: 2, y: 1, z: 1, type: "floor", passable: true, kind: "open" },
4793
+ { id: "t31", x: 3, y: 1, z: 1, type: "floor", passable: true, kind: "open" },
4794
+ { id: "t41", x: 4, y: 1, z: 1, type: "wall", passable: false, kind: "wall" },
4795
+ { id: "t02", x: 0, y: 2, z: 2, type: "wall", passable: false, kind: "wall" },
4796
+ { id: "t12", x: 1, y: 2, z: 2, type: "floor", passable: true, kind: "open" },
4797
+ { id: "t22", x: 2, y: 2, z: 2, type: "floor", passable: true, kind: "dirt" },
4798
+ { id: "t32", x: 3, y: 2, z: 2, type: "floor", passable: true, kind: "open" },
4799
+ { id: "t42", x: 4, y: 2, z: 2, type: "wall", passable: false, kind: "wall" },
4800
+ { id: "t03", x: 0, y: 3, z: 3, type: "wall", passable: false, kind: "wall" },
4801
+ { id: "t13", x: 1, y: 3, z: 3, type: "floor", passable: true, kind: "open" },
4802
+ { id: "t23", x: 2, y: 3, z: 3, type: "floor", passable: true, kind: "open" },
4803
+ { id: "t33", x: 3, y: 3, z: 3, type: "floor", passable: true, kind: "dirt" },
4804
+ { id: "t43", x: 4, y: 3, z: 3, type: "wall", passable: false, kind: "wall" },
4805
+ { id: "t04", x: 0, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4806
+ { id: "t14", x: 1, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4807
+ { id: "t24", x: 2, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4808
+ { id: "t34", x: 3, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4809
+ { id: "t44", x: 4, y: 4, z: 4, type: "wall", passable: false, kind: "wall" }
4706
4810
  ];
4707
4811
  var DEFAULT_3D_CASTLE_FEATURES = [
4708
4812
  { id: "f1", x: 2, y: 2, z: 2, type: "chest", color: "#f4c542" },
@@ -4710,8 +4814,9 @@ var DEFAULT_3D_CASTLE_FEATURES = [
4710
4814
  ];
4711
4815
  function GameCanvas3DCastleTemplate({
4712
4816
  entity,
4713
- tiles: propTiles = DEFAULT_3D_CASTLE_TILES,
4817
+ tiles: propTiles,
4714
4818
  features: propFeatures = DEFAULT_3D_CASTLE_FEATURES,
4819
+ assetManifest,
4715
4820
  cameraMode = "isometric",
4716
4821
  backgroundColor = "#1e1e2e",
4717
4822
  buildingClickEvent,
@@ -4726,13 +4831,14 @@ function GameCanvas3DCastleTemplate({
4726
4831
  scale,
4727
4832
  className
4728
4833
  }) {
4729
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
4730
- const tiles = resolved ? Array.isArray(resolved.tiles) ? resolved.tiles : [] : propTiles;
4731
- const features = resolved ? Array.isArray(resolved.features) ? resolved.features : [] : propFeatures;
4732
- const name = resolved?.name == null ? void 0 : String(resolved.name);
4733
- const level = resolved?.level == null ? void 0 : Number(resolved.level);
4734
- const owner = resolved?.owner == null ? void 0 : String(resolved.owner);
4735
- const unitCount = resolved && Array.isArray(resolved.units) ? resolved.units.length : 0;
4834
+ const row = boardEntity(entity);
4835
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
4836
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_CASTLE_LAYOUT, assetManifest);
4837
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4838
+ const name = row?.name == null ? void 0 : str(row.name);
4839
+ const level = row?.level == null ? void 0 : num(row.level);
4840
+ const owner = row?.owner == null ? void 0 : str(row.owner);
4841
+ const unitCount = row && Array.isArray(row.units) ? row.units.length : 0;
4736
4842
  return /* @__PURE__ */ jsxs(
4737
4843
  VStack,
4738
4844
  {
@@ -4778,36 +4884,32 @@ function GameCanvas3DCastleTemplate({
4778
4884
  );
4779
4885
  }
4780
4886
  GameCanvas3DCastleTemplate.displayName = "GameCanvas3DCastleTemplate";
4781
- var CDN3 = "https://almadar-kflow-assets.web.app/shared/3d/dungeon/floor";
4782
- var FLOOR_WALL3 = `${CDN3}/template-floor-detail-a.glb`;
4783
- var FLOOR_DIRT3 = `${CDN3}/template-floor-detail.glb`;
4784
- var FLOOR_OPEN3 = `${CDN3}/template-floor.glb`;
4785
- var DEFAULT_3D_WORLDMAP_TILES = [
4786
- { id: "t00", x: 0, y: 0, z: 0, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4787
- { id: "t10", x: 1, y: 0, z: 0, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4788
- { id: "t20", x: 2, y: 0, z: 0, type: "water", passable: false, modelUrl: FLOOR_WALL3 },
4789
- { id: "t30", x: 3, y: 0, z: 0, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4790
- { id: "t40", x: 4, y: 0, z: 0, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4791
- { id: "t01", x: 0, y: 1, z: 1, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4792
- { id: "t11", x: 1, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4793
- { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4794
- { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4795
- { id: "t41", x: 4, y: 1, z: 1, type: "water", passable: false, modelUrl: FLOOR_WALL3 },
4796
- { id: "t02", x: 0, y: 2, z: 2, type: "water", passable: false, modelUrl: FLOOR_WALL3 },
4797
- { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4798
- { id: "t22", x: 2, y: 2, z: 2, type: "road", passable: true, modelUrl: FLOOR_DIRT3 },
4799
- { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4800
- { id: "t42", x: 4, y: 2, z: 2, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4801
- { id: "t03", x: 0, y: 3, z: 3, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4802
- { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4803
- { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4804
- { id: "t33", x: 3, y: 3, z: 3, type: "road", passable: true, modelUrl: FLOOR_DIRT3 },
4805
- { id: "t43", x: 4, y: 3, z: 3, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4806
- { id: "t04", x: 0, y: 4, z: 4, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4807
- { id: "t14", x: 1, y: 4, z: 4, type: "water", passable: false, modelUrl: FLOOR_WALL3 },
4808
- { id: "t24", x: 2, y: 4, z: 4, type: "grass", passable: true, modelUrl: FLOOR_OPEN3 },
4809
- { id: "t34", x: 3, y: 4, z: 4, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 },
4810
- { id: "t44", x: 4, y: 4, z: 4, type: "mountain", passable: false, modelUrl: FLOOR_WALL3 }
4887
+ var DEFAULT_3D_WORLDMAP_LAYOUT = [
4888
+ { id: "t00", x: 0, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4889
+ { id: "t10", x: 1, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4890
+ { id: "t20", x: 2, y: 0, z: 0, type: "water", passable: false, kind: "wall" },
4891
+ { id: "t30", x: 3, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4892
+ { id: "t40", x: 4, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4893
+ { id: "t01", x: 0, y: 1, z: 1, type: "mountain", passable: false, kind: "wall" },
4894
+ { id: "t11", x: 1, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4895
+ { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4896
+ { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4897
+ { id: "t41", x: 4, y: 1, z: 1, type: "water", passable: false, kind: "wall" },
4898
+ { id: "t02", x: 0, y: 2, z: 2, type: "water", passable: false, kind: "wall" },
4899
+ { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4900
+ { id: "t22", x: 2, y: 2, z: 2, type: "road", passable: true, kind: "dirt" },
4901
+ { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4902
+ { id: "t42", x: 4, y: 2, z: 2, type: "mountain", passable: false, kind: "wall" },
4903
+ { id: "t03", x: 0, y: 3, z: 3, type: "mountain", passable: false, kind: "wall" },
4904
+ { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4905
+ { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4906
+ { id: "t33", x: 3, y: 3, z: 3, type: "road", passable: true, kind: "dirt" },
4907
+ { id: "t43", x: 4, y: 3, z: 3, type: "mountain", passable: false, kind: "wall" },
4908
+ { id: "t04", x: 0, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" },
4909
+ { id: "t14", x: 1, y: 4, z: 4, type: "water", passable: false, kind: "wall" },
4910
+ { id: "t24", x: 2, y: 4, z: 4, type: "grass", passable: true, kind: "open" },
4911
+ { id: "t34", x: 3, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" },
4912
+ { id: "t44", x: 4, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" }
4811
4913
  ];
4812
4914
  var DEFAULT_3D_WORLDMAP_FEATURES = [
4813
4915
  { id: "f1", x: 2, y: 2, z: 2, type: "capital", color: "#f4c542" },
@@ -4815,8 +4917,9 @@ var DEFAULT_3D_WORLDMAP_FEATURES = [
4815
4917
  ];
4816
4918
  function GameCanvas3DWorldMapTemplate({
4817
4919
  entity,
4818
- tiles: propTiles = DEFAULT_3D_WORLDMAP_TILES,
4920
+ tiles: propTiles,
4819
4921
  features: propFeatures = DEFAULT_3D_WORLDMAP_FEATURES,
4922
+ assetManifest,
4820
4923
  cameraMode = "isometric",
4821
4924
  backgroundColor = "#1a1a2e",
4822
4925
  tileClickEvent,
@@ -4830,9 +4933,10 @@ function GameCanvas3DWorldMapTemplate({
4830
4933
  scale,
4831
4934
  className
4832
4935
  }) {
4833
- const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
4834
- const tiles = resolved ? Array.isArray(resolved.tiles) ? resolved.tiles : [] : propTiles;
4835
- const features = resolved ? Array.isArray(resolved.features) ? resolved.features : [] : propFeatures;
4936
+ const row = boardEntity(entity);
4937
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
4938
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_WORLDMAP_LAYOUT, assetManifest);
4939
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4836
4940
  return (
4837
4941
  /* GameBoard3D reads selectedUnitId/validMoves/attackTargets from entity */
4838
4942
  /* @__PURE__ */ jsx(
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import type { AssetUrl, EventEmit, EntityRow } from '@almadar/core';
3
+ import type { DisplayStateProps } from '../../core/organisms/types';
4
+ /** Manifest of asset base-url + per-card sprite map (UI value DTO). */
5
+ type CardBattlerAssetManifest = {
6
+ baseUrl?: AssetUrl;
7
+ cards?: Record<string, AssetUrl>;
8
+ };
9
+ /** One card as carried on the entity / passed as a prop. */
10
+ export interface CardBattlerCard {
11
+ id: string;
12
+ iconKey?: string;
13
+ title?: string;
14
+ cost?: number;
15
+ attack?: number;
16
+ defense?: number;
17
+ }
18
+ export interface CardBattlerBoardProps extends DisplayStateProps {
19
+ entity?: EntityRow | readonly EntityRow[];
20
+ /** Cards remaining in the draw deck (count-only view). */
21
+ deck?: CardBattlerCard[];
22
+ /** Cards currently in the player's hand. */
23
+ hand?: CardBattlerCard[];
24
+ /** Cards played onto the board this match. */
25
+ board?: CardBattlerCard[];
26
+ mana?: number;
27
+ maxMana?: number;
28
+ turn?: number;
29
+ result?: 'none' | 'won' | 'lost';
30
+ /** Base-url + per-iconKey card sprite map (organism owns asset choice). */
31
+ assetManifest?: CardBattlerAssetManifest;
32
+ playCardEvent?: EventEmit<{
33
+ cardId: string;
34
+ }>;
35
+ endTurnEvent?: EventEmit<Record<string, never>>;
36
+ playAgainEvent?: EventEmit<Record<string, never>>;
37
+ gameEndEvent?: EventEmit<{
38
+ result: 'won' | 'lost';
39
+ }>;
40
+ className?: string;
41
+ }
42
+ export declare function CardBattlerBoard({ entity, deck: propDeck, hand: propHand, board: propBoard, mana: propMana, maxMana: propMaxMana, turn: propTurn, result: propResult, assetManifest: propAssetManifest, playCardEvent, endTurnEvent, playAgainEvent, gameEndEvent, className, }: CardBattlerBoardProps): React.JSX.Element;
43
+ export declare namespace CardBattlerBoard {
44
+ var displayName: string;
45
+ }
46
+ export default CardBattlerBoard;
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import type { AssetUrl, EventEmit, EntityRow } from '@almadar/core';
3
+ import type { DisplayStateProps } from '../../core/organisms/types';
4
+ /** Manifest of asset base-url + per-kind sprite maps (UI value DTO). */
5
+ type CityBuilderAssetManifest = {
6
+ baseUrl?: AssetUrl;
7
+ terrains?: Record<string, AssetUrl>;
8
+ units?: Record<string, AssetUrl>;
9
+ features?: Record<string, AssetUrl>;
10
+ };
11
+ export interface CityBuilderTile {
12
+ x: number;
13
+ y: number;
14
+ terrain?: string;
15
+ terrainSprite?: AssetUrl;
16
+ passable?: boolean;
17
+ }
18
+ export interface CityBuilderBuilding {
19
+ id: string;
20
+ x: number;
21
+ y: number;
22
+ type: string;
23
+ }
24
+ /** A placeable building type shown in the build palette (UI value DTO). */
25
+ export interface CityBuilderBuildType {
26
+ type: string;
27
+ label: string;
28
+ cost: number;
29
+ }
30
+ export interface CityBuilderBoardProps extends DisplayStateProps {
31
+ entity?: EntityRow | readonly EntityRow[];
32
+ tiles?: CityBuilderTile[];
33
+ buildings?: CityBuilderBuilding[];
34
+ /** Asset base-url + terrain/unit/feature sprite maps (organism owns asset choice). */
35
+ assetManifest?: CityBuilderAssetManifest;
36
+ buildTypes?: CityBuilderBuildType[];
37
+ pendingBuildType?: string;
38
+ gold?: number;
39
+ wood?: number;
40
+ population?: number;
41
+ tick?: number;
42
+ result?: 'none' | 'won' | 'lost';
43
+ scale?: number;
44
+ unitScale?: number;
45
+ spriteHeightRatio?: number;
46
+ spriteMaxWidthRatio?: number;
47
+ selectBuildTypeEvent?: EventEmit<{
48
+ buildType: string;
49
+ }>;
50
+ placeBuildingEvent?: EventEmit<{
51
+ x: number;
52
+ y: number;
53
+ }>;
54
+ gameEndEvent?: EventEmit<{
55
+ result: 'won' | 'lost';
56
+ }>;
57
+ className?: string;
58
+ }
59
+ export declare function CityBuilderBoard({ entity, tiles: propTiles, buildings: propBuildings, assetManifest: propAssetManifest, buildTypes: propBuildTypes, pendingBuildType: propPendingBuildType, gold: propGold, wood: propWood, population: propPopulation, result: propResult, scale, unitScale, spriteHeightRatio, spriteMaxWidthRatio, selectBuildTypeEvent, placeBuildingEvent, gameEndEvent, className, }: CityBuilderBoardProps): React.JSX.Element;
60
+ export declare namespace CityBuilderBoard {
61
+ var displayName: string;
62
+ }
63
+ export default CityBuilderBoard;
@@ -0,0 +1,64 @@
1
+ import * as React from 'react';
2
+ import type { AssetUrl, EventEmit, EntityRow } from '@almadar/core';
3
+ /** Asset base-url + per-kind sprite maps (organism owns asset choice; UI value DTO). */
4
+ type ShooterAssetManifest = {
5
+ baseUrl?: AssetUrl;
6
+ units?: Record<string, AssetUrl>;
7
+ features?: Record<string, AssetUrl>;
8
+ background?: AssetUrl;
9
+ };
10
+ export interface ShooterPlayer {
11
+ x: number;
12
+ y: number;
13
+ }
14
+ export interface ShooterEnemy {
15
+ id: string;
16
+ x: number;
17
+ y: number;
18
+ hp: number;
19
+ }
20
+ export interface ShooterProjectile {
21
+ id: string;
22
+ x: number;
23
+ y: number;
24
+ vx: number;
25
+ vy: number;
26
+ }
27
+ export interface TopDownShooterBoardProps {
28
+ /** Entity carrying all board state (player, enemies, projectiles, score, wave, lives, result). */
29
+ entity?: EntityRow | readonly EntityRow[];
30
+ /** Direct state — each takes priority over its entity-derived value. */
31
+ player?: ShooterPlayer;
32
+ enemies?: ShooterEnemy[];
33
+ projectiles?: ShooterProjectile[];
34
+ score?: number;
35
+ wave?: number;
36
+ lives?: number;
37
+ result?: 'none' | 'won' | 'lost';
38
+ /** Asset base-url + unit/feature sprite maps + background. */
39
+ assetManifest?: ShooterAssetManifest;
40
+ /** Canvas / arena dimensions in pixels. */
41
+ width?: number;
42
+ height?: number;
43
+ /** Pixel draw-size of sprites. */
44
+ spriteSize?: number;
45
+ /** Closed-circuit event emits (UI:{event}). */
46
+ moveEvent?: EventEmit<{
47
+ dx: number;
48
+ dy: number;
49
+ }>;
50
+ fireEvent?: EventEmit<{
51
+ tx: number;
52
+ ty: number;
53
+ }>;
54
+ playAgainEvent?: EventEmit<Record<string, never>>;
55
+ gameEndEvent?: EventEmit<{
56
+ result: 'won' | 'lost';
57
+ }>;
58
+ className?: string;
59
+ }
60
+ export declare function TopDownShooterBoard({ entity, player: propPlayer, enemies: propEnemies, projectiles: propProjectiles, score: propScore, wave: propWave, lives: propLives, result: propResult, assetManifest: propAssetManifest, width, height, spriteSize, moveEvent, fireEvent, playAgainEvent, gameEndEvent, className, }: TopDownShooterBoardProps): React.JSX.Element;
61
+ export declare namespace TopDownShooterBoard {
62
+ var displayName: string;
63
+ }
64
+ export default TopDownShooterBoard;