@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
@@ -67,6 +67,10 @@ export interface GraphCanvasProps {
67
67
  repulsion?: number;
68
68
  /** Force-sim target edge length (larger ⇒ more spread out) */
69
69
  linkDistance?: number;
70
+ /** Minimum empty gap (px) enforced between node edges so nodes never overlap. */
71
+ nodeSpacing?: number;
72
+ /** Base opacity for links when nothing is hovered (kept faint so dense graphs stay readable; incident links brighten on hover). */
73
+ linkOpacity?: number;
70
74
  /** Layout algorithm */
71
75
  layout?: "force" | "circular" | "grid";
72
76
  /** Entity name for schema-driven auto-fetch */
@@ -11,6 +11,10 @@ export { WorldMapTemplate, type WorldMapTemplateProps, type WorldMapSlotContext,
11
11
  export { PlatformerTemplate, type PlatformerTemplateProps, } from '../../game/templates/PlatformerTemplate';
12
12
  export { TowerDefenseTemplate, type TowerDefenseTemplateProps, } from '../../game/templates/TowerDefenseTemplate';
13
13
  export { RoguelikeTemplate, type RoguelikeTemplateProps, } from '../../game/templates/RoguelikeTemplate';
14
+ export { TopDownShooterTemplate, type TopDownShooterTemplateProps, } from '../../game/templates/TopDownShooterTemplate';
15
+ export { CityBuilderTemplate, type CityBuilderTemplateProps, } from '../../game/templates/CityBuilderTemplate';
16
+ export { VisualNovelTemplate, type VisualNovelTemplateProps, } from '../../game/templates/VisualNovelTemplate';
17
+ export { CardBattlerTemplate, type CardBattlerTemplateProps, } from '../../game/templates/CardBattlerTemplate';
14
18
  export { LandingPageTemplate, type LandingPageTemplateProps, type LandingPageEntity, } from '../../marketing/templates/LandingPageTemplate';
15
19
  export { PricingPageTemplate, type PricingPageTemplateProps, type PricingPageEntity, } from '../../marketing/templates/PricingPageTemplate';
16
20
  export { FeatureDetailPageTemplate, type FeatureDetailPageTemplateProps, type FeatureDetailPageEntity, type FeatureDetailSection, } from '../../marketing/templates/FeatureDetailPageTemplate';
@@ -0,0 +1,35 @@
1
+ import * as React from 'react';
2
+ import type { AssetUrl, EventEmit } from '@almadar/core';
3
+ /** One playable card (icon + title + a few stat numbers). UI value DTO. */
4
+ export interface CardHandCard {
5
+ id: string;
6
+ iconUrl?: AssetUrl;
7
+ title?: string;
8
+ cost?: number;
9
+ attack?: number;
10
+ defense?: number;
11
+ disabled?: boolean;
12
+ }
13
+ export interface CardHandProps {
14
+ /** Cards to lay out as a horizontal hand (or grid when wrapped). */
15
+ cards: CardHandCard[];
16
+ /** Currently selected card id. */
17
+ selectedId?: string;
18
+ /** Card-art size variant. */
19
+ size?: 'sm' | 'md' | 'lg';
20
+ /** Direct callback when a (non-disabled) card is clicked. */
21
+ onCardClick?: (id: string) => void;
22
+ /** Event-bus event emitted with `{ cardId }` on click. */
23
+ cardClickEvent?: EventEmit<{
24
+ cardId: string;
25
+ }>;
26
+ /** Empty-state label when there are no cards. */
27
+ emptyLabel?: string;
28
+ className?: string;
29
+ }
30
+ /** Pure card-hand molecule: renders a row/grid of cards from props alone. */
31
+ export declare function CardHand({ cards, selectedId, size, onCardClick, cardClickEvent, emptyLabel, className, }: CardHandProps): React.JSX.Element;
32
+ export declare namespace CardHand {
33
+ var displayName: string;
34
+ }
35
+ export default CardHand;
@@ -12,7 +12,7 @@
12
12
  * concern analogous to Form's `formData`.
13
13
  */
14
14
  import React from 'react';
15
- import type { EventEmit, EventPayload } from '@almadar/core';
15
+ import type { AssetUrl, EventEmit, EventPayload } from '@almadar/core';
16
16
  export type DialogueChoice = EventPayload & {
17
17
  text: string;
18
18
  action?: string;
@@ -53,8 +53,14 @@ export interface DialogueBoxProps {
53
53
  }>;
54
54
  /** Declarative event: emits UI:{advanceEvent} when dialogue is advanced */
55
55
  advanceEvent?: EventEmit<Record<string, never>>;
56
+ /** Optional full-frame scene image rendered behind the dialogue (visual-novel mode). */
57
+ backgroundImage?: AssetUrl;
58
+ /** Optional larger character portrait rendered standing over the scene (visual-novel mode). */
59
+ portraitUrl?: AssetUrl;
60
+ /** Multiplier for the large `portraitUrl` height relative to its default (default 1). */
61
+ portraitScale?: number;
56
62
  /** Optional className */
57
63
  className?: string;
58
64
  }
59
- export declare function DialogueBox({ dialogue, typewriterSpeed, position, onComplete, onChoice, onAdvance, completeEvent, choiceEvent, advanceEvent, className, }: DialogueBoxProps): React.JSX.Element;
65
+ export declare function DialogueBox({ dialogue, typewriterSpeed, position, onComplete, onChoice, onAdvance, completeEvent, choiceEvent, advanceEvent, backgroundImage, portraitUrl, portraitScale, className, }: DialogueBoxProps): React.JSX.Element;
60
66
  export default DialogueBox;
@@ -9,6 +9,7 @@ export { DPad, type DPadProps, type DPadDirection } from './DPad';
9
9
  export { ActionButtons, type ActionButtonsProps, type ActionButtonConfig } from './ActionButtons';
10
10
  export { StatBadge, type StatBadgeProps } from './StatBadge';
11
11
  export { InventoryGrid, type InventoryGridProps, type InventoryGridItem } from './InventoryGrid';
12
+ export { CardHand, type CardHandProps, type CardHandCard } from './CardHand';
12
13
  export { QuestTracker, type QuestTrackerProps, type Quest } from './QuestTracker';
13
14
  export { CraftingRecipe, type CraftingRecipeProps, type CraftingIngredient } from './CraftingRecipe';
14
15
  export { PowerupSlots, type PowerupSlotsProps, type ActivePowerup } from './PowerupSlots';
@@ -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);
@@ -4595,36 +4624,113 @@ var Box = React11__default.default.forwardRef(
4595
4624
  }
4596
4625
  );
4597
4626
  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 }
4627
+
4628
+ // components/game/templates/game3dAssetManifest.ts
4629
+ function resolveManifestUrl(manifest, relative) {
4630
+ if (relative == null) return void 0;
4631
+ if (/^https?:\/\//.test(relative)) return relative;
4632
+ const base = manifest?.baseUrl;
4633
+ if (base == null) return relative;
4634
+ const cleanBase = base.replace(/\/$/, "");
4635
+ const cleanRel = relative.replace(/^\//, "");
4636
+ return `${cleanBase}/${cleanRel}`;
4637
+ }
4638
+ function tileKind(type, passable) {
4639
+ if (passable === false) return "wall";
4640
+ if (type === "dirt" || type === "road") return "dirt";
4641
+ return "open";
4642
+ }
4643
+ function resolveTilesWithModels(layout, manifest) {
4644
+ return layout.map((t) => {
4645
+ const kind = t.kind || tileKind(t.type, t.passable);
4646
+ return {
4647
+ id: t.id,
4648
+ x: t.x,
4649
+ y: t.y,
4650
+ z: t.z,
4651
+ type: t.type,
4652
+ passable: t.passable,
4653
+ modelUrl: resolveManifestUrl(manifest, manifest?.models?.[kind])
4654
+ };
4655
+ });
4656
+ }
4657
+ function resolvePropTiles(tiles, manifest) {
4658
+ return tiles.map((t) => {
4659
+ const kind = tileKind(t.type ?? "", t.passable);
4660
+ return {
4661
+ ...t,
4662
+ modelUrl: t.modelUrl ?? resolveManifestUrl(manifest, manifest?.models?.[kind])
4663
+ };
4664
+ });
4665
+ }
4666
+ function resolveEntityTiles(entity, manifest) {
4667
+ const row = boardEntity(entity);
4668
+ if (!row) return [];
4669
+ return rows(row.tiles).map((r) => {
4670
+ const type = str(r.type) || str(r.terrain);
4671
+ const passable = r.passable !== false;
4672
+ const kind = tileKind(type, passable);
4673
+ const explicitModel = r.modelUrl == null ? void 0 : str(r.modelUrl);
4674
+ return {
4675
+ id: r.id == null ? void 0 : str(r.id),
4676
+ x: num(r.x),
4677
+ y: num(r.y),
4678
+ z: r.z == null ? void 0 : num(r.z),
4679
+ type,
4680
+ passable,
4681
+ modelUrl: explicitModel ?? resolveManifestUrl(manifest, manifest?.models?.[kind])
4682
+ };
4683
+ });
4684
+ }
4685
+ function resolveFeaturesWithModels(features, manifest) {
4686
+ return features.map((f) => ({
4687
+ ...f,
4688
+ assetUrl: f.assetUrl ?? resolveManifestUrl(manifest, manifest?.features?.[f.type])
4689
+ }));
4690
+ }
4691
+ function resolveEntityFeatures(entity, manifest) {
4692
+ const row = boardEntity(entity);
4693
+ if (!row) return [];
4694
+ return rows(row.features).map((r) => {
4695
+ const type = str(r.type);
4696
+ const explicit = r.assetUrl == null ? void 0 : str(r.assetUrl);
4697
+ return {
4698
+ id: r.id == null ? void 0 : str(r.id),
4699
+ x: num(r.x),
4700
+ y: num(r.y),
4701
+ z: r.z == null ? void 0 : num(r.z),
4702
+ type,
4703
+ color: r.color == null ? void 0 : str(r.color),
4704
+ assetUrl: explicit ?? resolveManifestUrl(manifest, manifest?.features?.[type])
4705
+ };
4706
+ });
4707
+ }
4708
+ var DEFAULT_3D_BATTLE_LAYOUT = [
4709
+ { id: "t00", x: 0, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4710
+ { id: "t10", x: 1, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4711
+ { id: "t20", x: 2, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4712
+ { id: "t30", x: 3, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4713
+ { id: "t40", x: 4, y: 0, z: 0, type: "stone", passable: false, kind: "wall" },
4714
+ { id: "t01", x: 0, y: 1, z: 1, type: "stone", passable: false, kind: "wall" },
4715
+ { id: "t11", x: 1, y: 1, z: 1, type: "dirt", passable: true, kind: "dirt" },
4716
+ { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4717
+ { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4718
+ { id: "t41", x: 4, y: 1, z: 1, type: "stone", passable: false, kind: "wall" },
4719
+ { id: "t02", x: 0, y: 2, z: 2, type: "stone", passable: false, kind: "wall" },
4720
+ { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4721
+ { id: "t22", x: 2, y: 2, z: 2, type: "dirt", passable: true, kind: "dirt" },
4722
+ { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4723
+ { id: "t42", x: 4, y: 2, z: 2, type: "stone", passable: false, kind: "wall" },
4724
+ { id: "t03", x: 0, y: 3, z: 3, type: "stone", passable: false, kind: "wall" },
4725
+ { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4726
+ { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4727
+ { id: "t33", x: 3, y: 3, z: 3, type: "dirt", passable: true, kind: "dirt" },
4728
+ { id: "t43", x: 4, y: 3, z: 3, type: "stone", passable: false, kind: "wall" },
4729
+ { id: "t04", x: 0, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4730
+ { id: "t14", x: 1, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4731
+ { id: "t24", x: 2, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4732
+ { id: "t34", x: 3, y: 4, z: 4, type: "stone", passable: false, kind: "wall" },
4733
+ { id: "t44", x: 4, y: 4, z: 4, type: "stone", passable: false, kind: "wall" }
4628
4734
  ];
4629
4735
  var DEFAULT_3D_BATTLE_FEATURES = [
4630
4736
  { id: "f1", x: 2, y: 2, z: 2, type: "gold_mine", color: "#f4c542" },
@@ -4632,8 +4738,9 @@ var DEFAULT_3D_BATTLE_FEATURES = [
4632
4738
  ];
4633
4739
  function GameCanvas3DBattleTemplate({
4634
4740
  entity,
4635
- tiles: propTiles = DEFAULT_3D_BATTLE_TILES,
4741
+ tiles: propTiles,
4636
4742
  features: propFeatures = DEFAULT_3D_BATTLE_FEATURES,
4743
+ assetManifest,
4637
4744
  cameraMode = "perspective",
4638
4745
  backgroundColor = "#2a1a1a",
4639
4746
  tileClickEvent,
@@ -4647,11 +4754,12 @@ function GameCanvas3DBattleTemplate({
4647
4754
  scale,
4648
4755
  className
4649
4756
  }) {
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);
4757
+ const row = boardEntity(entity);
4758
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
4759
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_BATTLE_LAYOUT, assetManifest);
4760
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4761
+ const currentTurn = row?.currentTeam == null ? void 0 : String(row.currentTeam);
4762
+ const round = row?.turn == null ? void 0 : Number(row.turn);
4655
4763
  return /* @__PURE__ */ jsxRuntime.jsxs(
4656
4764
  Box,
4657
4765
  {
@@ -4697,36 +4805,32 @@ function GameCanvas3DBattleTemplate({
4697
4805
  );
4698
4806
  }
4699
4807
  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 }
4808
+ var DEFAULT_3D_CASTLE_LAYOUT = [
4809
+ { id: "t00", x: 0, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4810
+ { id: "t10", x: 1, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4811
+ { id: "t20", x: 2, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4812
+ { id: "t30", x: 3, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4813
+ { id: "t40", x: 4, y: 0, z: 0, type: "wall", passable: false, kind: "wall" },
4814
+ { id: "t01", x: 0, y: 1, z: 1, type: "wall", passable: false, kind: "wall" },
4815
+ { id: "t11", x: 1, y: 1, z: 1, type: "floor", passable: true, kind: "dirt" },
4816
+ { id: "t21", x: 2, y: 1, z: 1, type: "floor", passable: true, kind: "open" },
4817
+ { id: "t31", x: 3, y: 1, z: 1, type: "floor", passable: true, kind: "open" },
4818
+ { id: "t41", x: 4, y: 1, z: 1, type: "wall", passable: false, kind: "wall" },
4819
+ { id: "t02", x: 0, y: 2, z: 2, type: "wall", passable: false, kind: "wall" },
4820
+ { id: "t12", x: 1, y: 2, z: 2, type: "floor", passable: true, kind: "open" },
4821
+ { id: "t22", x: 2, y: 2, z: 2, type: "floor", passable: true, kind: "dirt" },
4822
+ { id: "t32", x: 3, y: 2, z: 2, type: "floor", passable: true, kind: "open" },
4823
+ { id: "t42", x: 4, y: 2, z: 2, type: "wall", passable: false, kind: "wall" },
4824
+ { id: "t03", x: 0, y: 3, z: 3, type: "wall", passable: false, kind: "wall" },
4825
+ { id: "t13", x: 1, y: 3, z: 3, type: "floor", passable: true, kind: "open" },
4826
+ { id: "t23", x: 2, y: 3, z: 3, type: "floor", passable: true, kind: "open" },
4827
+ { id: "t33", x: 3, y: 3, z: 3, type: "floor", passable: true, kind: "dirt" },
4828
+ { id: "t43", x: 4, y: 3, z: 3, type: "wall", passable: false, kind: "wall" },
4829
+ { id: "t04", x: 0, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4830
+ { id: "t14", x: 1, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4831
+ { id: "t24", x: 2, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4832
+ { id: "t34", x: 3, y: 4, z: 4, type: "wall", passable: false, kind: "wall" },
4833
+ { id: "t44", x: 4, y: 4, z: 4, type: "wall", passable: false, kind: "wall" }
4730
4834
  ];
4731
4835
  var DEFAULT_3D_CASTLE_FEATURES = [
4732
4836
  { id: "f1", x: 2, y: 2, z: 2, type: "chest", color: "#f4c542" },
@@ -4734,8 +4838,9 @@ var DEFAULT_3D_CASTLE_FEATURES = [
4734
4838
  ];
4735
4839
  function GameCanvas3DCastleTemplate({
4736
4840
  entity,
4737
- tiles: propTiles = DEFAULT_3D_CASTLE_TILES,
4841
+ tiles: propTiles,
4738
4842
  features: propFeatures = DEFAULT_3D_CASTLE_FEATURES,
4843
+ assetManifest,
4739
4844
  cameraMode = "isometric",
4740
4845
  backgroundColor = "#1e1e2e",
4741
4846
  buildingClickEvent,
@@ -4750,13 +4855,14 @@ function GameCanvas3DCastleTemplate({
4750
4855
  scale,
4751
4856
  className
4752
4857
  }) {
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;
4858
+ const row = boardEntity(entity);
4859
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
4860
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_CASTLE_LAYOUT, assetManifest);
4861
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4862
+ const name = row?.name == null ? void 0 : str(row.name);
4863
+ const level = row?.level == null ? void 0 : num(row.level);
4864
+ const owner = row?.owner == null ? void 0 : str(row.owner);
4865
+ const unitCount = row && Array.isArray(row.units) ? row.units.length : 0;
4760
4866
  return /* @__PURE__ */ jsxRuntime.jsxs(
4761
4867
  VStack,
4762
4868
  {
@@ -4802,36 +4908,32 @@ function GameCanvas3DCastleTemplate({
4802
4908
  );
4803
4909
  }
4804
4910
  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 }
4911
+ var DEFAULT_3D_WORLDMAP_LAYOUT = [
4912
+ { id: "t00", x: 0, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4913
+ { id: "t10", x: 1, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4914
+ { id: "t20", x: 2, y: 0, z: 0, type: "water", passable: false, kind: "wall" },
4915
+ { id: "t30", x: 3, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4916
+ { id: "t40", x: 4, y: 0, z: 0, type: "mountain", passable: false, kind: "wall" },
4917
+ { id: "t01", x: 0, y: 1, z: 1, type: "mountain", passable: false, kind: "wall" },
4918
+ { id: "t11", x: 1, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4919
+ { id: "t21", x: 2, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4920
+ { id: "t31", x: 3, y: 1, z: 1, type: "grass", passable: true, kind: "open" },
4921
+ { id: "t41", x: 4, y: 1, z: 1, type: "water", passable: false, kind: "wall" },
4922
+ { id: "t02", x: 0, y: 2, z: 2, type: "water", passable: false, kind: "wall" },
4923
+ { id: "t12", x: 1, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4924
+ { id: "t22", x: 2, y: 2, z: 2, type: "road", passable: true, kind: "dirt" },
4925
+ { id: "t32", x: 3, y: 2, z: 2, type: "grass", passable: true, kind: "open" },
4926
+ { id: "t42", x: 4, y: 2, z: 2, type: "mountain", passable: false, kind: "wall" },
4927
+ { id: "t03", x: 0, y: 3, z: 3, type: "mountain", passable: false, kind: "wall" },
4928
+ { id: "t13", x: 1, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4929
+ { id: "t23", x: 2, y: 3, z: 3, type: "grass", passable: true, kind: "open" },
4930
+ { id: "t33", x: 3, y: 3, z: 3, type: "road", passable: true, kind: "dirt" },
4931
+ { id: "t43", x: 4, y: 3, z: 3, type: "mountain", passable: false, kind: "wall" },
4932
+ { id: "t04", x: 0, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" },
4933
+ { id: "t14", x: 1, y: 4, z: 4, type: "water", passable: false, kind: "wall" },
4934
+ { id: "t24", x: 2, y: 4, z: 4, type: "grass", passable: true, kind: "open" },
4935
+ { id: "t34", x: 3, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" },
4936
+ { id: "t44", x: 4, y: 4, z: 4, type: "mountain", passable: false, kind: "wall" }
4835
4937
  ];
4836
4938
  var DEFAULT_3D_WORLDMAP_FEATURES = [
4837
4939
  { id: "f1", x: 2, y: 2, z: 2, type: "capital", color: "#f4c542" },
@@ -4839,8 +4941,9 @@ var DEFAULT_3D_WORLDMAP_FEATURES = [
4839
4941
  ];
4840
4942
  function GameCanvas3DWorldMapTemplate({
4841
4943
  entity,
4842
- tiles: propTiles = DEFAULT_3D_WORLDMAP_TILES,
4944
+ tiles: propTiles,
4843
4945
  features: propFeatures = DEFAULT_3D_WORLDMAP_FEATURES,
4946
+ assetManifest,
4844
4947
  cameraMode = "isometric",
4845
4948
  backgroundColor = "#1a1a2e",
4846
4949
  tileClickEvent,
@@ -4854,9 +4957,10 @@ function GameCanvas3DWorldMapTemplate({
4854
4957
  scale,
4855
4958
  className
4856
4959
  }) {
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;
4960
+ const row = boardEntity(entity);
4961
+ const hasEntityTiles = !!row && Array.isArray(row.tiles) && row.tiles.length > 0;
4962
+ const tiles = hasEntityTiles ? resolveEntityTiles(entity, assetManifest) : propTiles ? resolvePropTiles(propTiles, assetManifest) : resolveTilesWithModels(DEFAULT_3D_WORLDMAP_LAYOUT, assetManifest);
4963
+ const features = row && Array.isArray(row.features) && row.features.length > 0 ? resolveEntityFeatures(entity, assetManifest) : resolveFeaturesWithModels(propFeatures, assetManifest);
4860
4964
  return (
4861
4965
  /* GameBoard3D reads selectedUnitId/validMoves/attackTargets from entity */
4862
4966
  /* @__PURE__ */ jsxRuntime.jsx(