@almadar/ui 5.28.2 → 5.28.4

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.
@@ -20,6 +20,7 @@
20
20
  import React from 'react';
21
21
  import type { AssetUrl, EventEmit, EntityRow } from '@almadar/core';
22
22
  import type { DisplayStateProps } from '../../core/organisms/types';
23
+ import type { IsometricTile, IsometricUnit, IsometricFeature } from './types/isometric';
23
24
  import type { ResolvedFrame } from './types/spriteAnimation';
24
25
  /** Battle phases an encounter walks through (UI value enum — not entity data). */
25
26
  export type BattlePhase = 'observation' | 'selection' | 'movement' | 'action' | 'enemy_turn' | 'game_over';
@@ -45,9 +46,25 @@ export type BattleSlotContext = {
45
46
  y: number;
46
47
  };
47
48
  };
49
+ /** Asset manifest shape for BattleBoard. */
50
+ type BattleAssetManifest = {
51
+ baseUrl?: AssetUrl;
52
+ terrains?: Record<string, AssetUrl>;
53
+ units?: Record<string, AssetUrl>;
54
+ features?: Record<string, AssetUrl>;
55
+ effects?: Record<string, AssetUrl>;
56
+ };
48
57
  export interface BattleBoardProps extends DisplayStateProps {
49
58
  /** Entity (single board state) containing all board data */
50
59
  entity?: EntityRow | readonly EntityRow[];
60
+ /** Direct tile data — takes priority over entity-derived tiles. */
61
+ tiles?: IsometricTile[];
62
+ /** Direct unit data — takes priority over entity-derived units. */
63
+ units?: IsometricUnit[];
64
+ /** Direct feature data — takes priority over entity-derived features. */
65
+ features?: IsometricFeature[];
66
+ /** Direct asset manifest — takes priority over entity-derived manifest. */
67
+ assetManifest?: BattleAssetManifest;
51
68
  /** Canvas render scale */
52
69
  scale?: number;
53
70
  /** Unit draw-size multiplier */
@@ -104,7 +121,7 @@ export interface BattleBoardProps extends DisplayStateProps {
104
121
  }>;
105
122
  className?: string;
106
123
  }
107
- export declare function BattleBoard({ entity, scale, unitScale, header, sidebar, actions, overlay, gameOverOverlay, onAttack, onGameEnd, onUnitMove, calculateDamage, onDrawEffects, hasActiveEffects, effectSpriteUrls, resolveUnitFrame, tileClickEvent, unitClickEvent, endTurnEvent, cancelEvent, gameEndEvent, playAgainEvent, attackEvent, className, }: BattleBoardProps): React.JSX.Element;
124
+ export declare function BattleBoard({ entity, tiles: propTiles, units: propUnits, features: propFeatures, assetManifest: propAssetManifest, scale, unitScale, header, sidebar, actions, overlay, gameOverOverlay, onAttack, onGameEnd, onUnitMove, calculateDamage, onDrawEffects, hasActiveEffects, effectSpriteUrls, resolveUnitFrame, tileClickEvent, unitClickEvent, endTurnEvent, cancelEvent, gameEndEvent, playAgainEvent, attackEvent, className, }: BattleBoardProps): React.JSX.Element;
108
125
  export declare namespace BattleBoard {
109
126
  var displayName: string;
110
127
  }
@@ -63,7 +63,7 @@ export interface CanvasEffectProps {
63
63
  /** Canvas height (default 300) */
64
64
  height?: number;
65
65
  }
66
- export declare function CanvasEffect(props: CanvasEffectProps): React.JSX.Element | null;
66
+ export declare function CanvasEffect({ effectSpriteUrl, assetBaseUrl, ...props }: CanvasEffectProps): React.JSX.Element | null;
67
67
  export declare namespace CanvasEffect {
68
68
  var displayName: string;
69
69
  }
@@ -13,8 +13,15 @@
13
13
  * @packageDocumentation
14
14
  */
15
15
  import React from 'react';
16
- import type { EventEmit, EntityRow } from '@almadar/core';
17
- import type { IsometricUnit, IsometricFeature } from './types/isometric';
16
+ import type { AssetUrl, EventEmit, EntityRow } from '@almadar/core';
17
+ import type { IsometricTile, IsometricUnit, IsometricFeature } from './types/isometric';
18
+ /** Manifest of asset base-url + per-kind sprite maps (UI value DTO). */
19
+ type CastleAssetManifest = {
20
+ baseUrl?: AssetUrl;
21
+ terrains?: Record<string, AssetUrl>;
22
+ units?: Record<string, AssetUrl>;
23
+ features?: Record<string, AssetUrl>;
24
+ };
18
25
  /** Context exposed to render-prop slots */
19
26
  export type CastleSlotContext = {
20
27
  /** Currently hovered tile coordinates (null when not hovering) */
@@ -42,6 +49,14 @@ export interface CastleBoardProps {
42
49
  /** Castle board-state entity (single row or array). The board reads
43
50
  * `tiles` / `features` / `units` arrays plus an `assetManifest` off it. */
44
51
  entity?: EntityRow | readonly EntityRow[];
52
+ /** Direct tile data — takes priority over entity-derived tiles. */
53
+ tiles?: IsometricTile[];
54
+ /** Direct unit data — takes priority over entity-derived units. */
55
+ units?: IsometricUnit[];
56
+ /** Direct feature data — takes priority over entity-derived features. */
57
+ features?: IsometricFeature[];
58
+ /** Direct asset manifest — takes priority over entity-derived manifest. */
59
+ assetManifest?: CastleAssetManifest;
45
60
  /** Canvas render scale */
46
61
  scale?: number;
47
62
  /** Top bar / header */
@@ -76,7 +91,7 @@ export interface CastleBoardProps {
76
91
  }>;
77
92
  className?: string;
78
93
  }
79
- export declare function CastleBoard({ entity, scale, header, sidePanel, overlay, footer, onFeatureClick, onUnitClick, onTileClick, featureClickEvent, unitClickEvent, tileClickEvent, className, }: CastleBoardProps): React.JSX.Element;
94
+ export declare function CastleBoard({ entity, tiles: propTiles, units: propUnits, features: propFeatures, assetManifest: propAssetManifest, scale, header, sidePanel, overlay, footer, onFeatureClick, onUnitClick, onTileClick, featureClickEvent, unitClickEvent, tileClickEvent, className, }: CastleBoardProps): React.JSX.Element;
80
95
  export declare namespace CastleBoard {
81
96
  var displayName: string;
82
97
  }
@@ -16,10 +16,19 @@
16
16
  import * as React from 'react';
17
17
  import type { EntityRow } from '@almadar/core';
18
18
  import { type BattleBoardProps } from './BattleBoard';
19
+ import type { IsometricTile, IsometricUnit, IsometricFeature } from './types/isometric';
19
20
  export interface UncontrolledBattleBoardProps extends Omit<BattleBoardProps, 'entity'> {
20
21
  entity?: EntityRow | readonly EntityRow[];
22
+ /** Direct tile data — takes priority over entity-derived tiles. */
23
+ tiles?: IsometricTile[];
24
+ /** Direct unit data — takes priority over entity-derived units. */
25
+ units?: IsometricUnit[];
26
+ /** Direct feature data — takes priority over entity-derived features. */
27
+ features?: IsometricFeature[];
28
+ /** Direct asset manifest — takes priority over entity-derived manifest. */
29
+ assetManifest?: BattleBoardProps['assetManifest'];
21
30
  }
22
- export declare function UncontrolledBattleBoard({ entity, ...rest }: UncontrolledBattleBoardProps): React.JSX.Element | null;
31
+ export declare function UncontrolledBattleBoard({ entity, tiles, units, features, assetManifest, ...rest }: UncontrolledBattleBoardProps): React.JSX.Element | null;
23
32
  export declare namespace UncontrolledBattleBoard {
24
33
  var displayName: string;
25
34
  }
@@ -20,8 +20,16 @@
20
20
  */
21
21
  import React from 'react';
22
22
  import type { AssetUrl, EventEmit, EntityRow } from '@almadar/core';
23
+ import type { IsometricTile, IsometricUnit, IsometricFeature } from './types/isometric';
23
24
  import type { ResolvedFrame } from './types/spriteAnimation';
24
25
  import type { UiError } from '../../core/atoms/types';
26
+ /** Manifest of asset base-url + per-kind sprite maps (UI value DTO). */
27
+ type WorldMapAssetManifest = {
28
+ baseUrl?: AssetUrl;
29
+ terrains?: Record<string, AssetUrl>;
30
+ units?: Record<string, AssetUrl>;
31
+ features?: Record<string, AssetUrl>;
32
+ };
25
33
  /** Context exposed to render-prop slots. Hex / hero rows are `EntityRow`. */
26
34
  export type WorldMapSlotContext = {
27
35
  /** Currently hovered tile */
@@ -67,6 +75,14 @@ export interface WorldMapBoardProps {
67
75
  /** World-map board-state entity (single row or array). The board reads
68
76
  * `hexes` / `heroes` / `features` arrays + `selectedHeroId` off it. */
69
77
  entity?: EntityRow | readonly EntityRow[];
78
+ /** Direct tile data — takes priority over entity-derived tiles. */
79
+ tiles?: IsometricTile[];
80
+ /** Direct unit data — takes priority over entity-derived units. */
81
+ units?: IsometricUnit[];
82
+ /** Direct feature data — takes priority over entity-derived features. */
83
+ features?: IsometricFeature[];
84
+ /** Direct asset manifest — takes priority over entity-derived manifest. */
85
+ assetManifest?: WorldMapAssetManifest;
70
86
  /** Canvas render scale */
71
87
  scale?: number;
72
88
  /** Unit draw-size multiplier */
@@ -128,7 +144,7 @@ export interface WorldMapBoardProps {
128
144
  effectSpriteUrls?: AssetUrl[];
129
145
  resolveUnitFrame?: (unitId: string) => ResolvedFrame | null;
130
146
  }
131
- export declare function WorldMapBoard({ entity, isLoading, scale, unitScale, allowMoveAllHeroes, isInRange, heroSelectEvent, heroMoveEvent, battleEncounterEvent, featureEnterEvent, tileClickEvent, header, sidePanel, overlay, footer, onHeroSelect, onHeroMove, onBattleEncounter, onFeatureEnter, diamondTopY, enableCamera, effectSpriteUrls, resolveUnitFrame, className, }: WorldMapBoardProps): React.JSX.Element;
147
+ export declare function WorldMapBoard({ entity, tiles: propTiles, units: propUnits, features: propFeatures, assetManifest: propAssetManifest, isLoading, scale, unitScale, allowMoveAllHeroes, isInRange, heroSelectEvent, heroMoveEvent, battleEncounterEvent, featureEnterEvent, tileClickEvent, header, sidePanel, overlay, footer, onHeroSelect, onHeroMove, onBattleEncounter, onFeatureEnter, diamondTopY, enableCamera, effectSpriteUrls, resolveUnitFrame, className, }: WorldMapBoardProps): React.JSX.Element;
132
148
  export declare namespace WorldMapBoard {
133
149
  var displayName: string;
134
150
  }
@@ -10,14 +10,24 @@
10
10
  */
11
11
  import React from 'react';
12
12
  import type { TemplateProps } from '../../core/templates/types';
13
+ import type { BattleBoardProps } from '../organisms/BattleBoard';
14
+ import type { IsometricTile, IsometricUnit, IsometricFeature } from '../organisms/types/isometric';
13
15
  export type { BattlePhase, BattleSlotContext, } from '../organisms/BattleBoard';
14
16
  export interface BattleTemplateProps extends TemplateProps {
15
17
  /** Canvas render scale */
16
18
  scale?: number;
17
19
  /** Unit draw-size multiplier */
18
20
  unitScale?: number;
21
+ /** Direct tile data — forwarded to BattleBoard; takes priority over entity. */
22
+ tiles?: IsometricTile[];
23
+ /** Direct unit data — forwarded to BattleBoard; takes priority over entity. */
24
+ units?: IsometricUnit[];
25
+ /** Direct feature data — forwarded to BattleBoard; takes priority over entity. */
26
+ features?: IsometricFeature[];
27
+ /** Direct asset manifest — forwarded to BattleBoard; takes priority over entity. */
28
+ assetManifest?: BattleBoardProps['assetManifest'];
19
29
  }
20
- export declare function BattleTemplate({ entity, scale, unitScale, className, }: BattleTemplateProps): React.JSX.Element | null;
30
+ export declare function BattleTemplate({ entity, scale, unitScale, tiles, units, features, assetManifest, className, }: BattleTemplateProps): React.JSX.Element | null;
21
31
  export declare namespace BattleTemplate {
22
32
  var displayName: string;
23
33
  }
@@ -10,12 +10,22 @@
10
10
  */
11
11
  import React from 'react';
12
12
  import type { TemplateProps } from '../../core/templates/types';
13
+ import type { CastleBoardProps } from '../organisms/CastleBoard';
14
+ import type { IsometricTile, IsometricUnit, IsometricFeature } from '../organisms/types/isometric';
13
15
  export type { CastleSlotContext } from '../organisms/CastleBoard';
14
16
  export interface CastleTemplateProps extends TemplateProps {
15
17
  /** Canvas render scale */
16
18
  scale?: number;
19
+ /** Direct tile data — forwarded to CastleBoard; takes priority over entity. */
20
+ tiles?: IsometricTile[];
21
+ /** Direct unit data — forwarded to CastleBoard; takes priority over entity. */
22
+ units?: IsometricUnit[];
23
+ /** Direct feature data — forwarded to CastleBoard; takes priority over entity. */
24
+ features?: IsometricFeature[];
25
+ /** Direct asset manifest — forwarded to CastleBoard; takes priority over entity. */
26
+ assetManifest?: CastleBoardProps['assetManifest'];
17
27
  }
18
- export declare function CastleTemplate({ entity, scale, className, }: CastleTemplateProps): React.JSX.Element | null;
28
+ export declare function CastleTemplate({ entity, scale, tiles, units, features, assetManifest, className, }: CastleTemplateProps): React.JSX.Element | null;
19
29
  export declare namespace CastleTemplate {
20
30
  var displayName: string;
21
31
  }
@@ -9,7 +9,9 @@
9
9
  * @packageDocumentation
10
10
  */
11
11
  import React from 'react';
12
+ import type { WorldMapBoardProps } from '../organisms/WorldMapBoard';
12
13
  import type { TemplateProps } from '../../core/templates/types';
14
+ import type { IsometricTile, IsometricUnit, IsometricFeature } from '../organisms/types/isometric';
13
15
  export type { WorldMapSlotContext } from '../organisms/WorldMapBoard';
14
16
  export interface WorldMapTemplateProps extends TemplateProps {
15
17
  /** Canvas render scale */
@@ -20,8 +22,16 @@ export interface WorldMapTemplateProps extends TemplateProps {
20
22
  diamondTopY?: number;
21
23
  /** Allow selecting / moving ALL heroes (including enemy). For testing. */
22
24
  allowMoveAllHeroes?: boolean;
25
+ /** Direct tile data — forwarded to WorldMapBoard; takes priority over entity. */
26
+ tiles?: IsometricTile[];
27
+ /** Direct unit data — forwarded to WorldMapBoard; takes priority over entity. */
28
+ units?: IsometricUnit[];
29
+ /** Direct feature data — forwarded to WorldMapBoard; takes priority over entity. */
30
+ features?: IsometricFeature[];
31
+ /** Direct asset manifest — forwarded to WorldMapBoard; takes priority over entity. */
32
+ assetManifest?: WorldMapBoardProps['assetManifest'];
23
33
  }
24
- export declare function WorldMapTemplate({ entity, scale, unitScale, diamondTopY, allowMoveAllHeroes, className, }: WorldMapTemplateProps): React.JSX.Element;
34
+ export declare function WorldMapTemplate({ entity, scale, unitScale, diamondTopY, allowMoveAllHeroes, tiles, units, features, assetManifest, className, }: WorldMapTemplateProps): React.JSX.Element;
25
35
  export declare namespace WorldMapTemplate {
26
36
  var displayName: string;
27
37
  }
@@ -9302,7 +9302,7 @@ function IsometricCanvas({
9302
9302
  // Rendering options
9303
9303
  scale = 0.4,
9304
9304
  debug: debug2 = false,
9305
- backgroundImage,
9305
+ backgroundImage = "https://almadar-kflow-assets.web.app/shared/scenes/court.png",
9306
9306
  showMinimap = true,
9307
9307
  enableCamera = true,
9308
9308
  unitScale = 1,
@@ -9317,7 +9317,7 @@ function IsometricCanvas({
9317
9317
  // Tuning
9318
9318
  diamondTopY: diamondTopYProp,
9319
9319
  // Remote asset loading
9320
- assetBaseUrl,
9320
+ assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
9321
9321
  assetManifest
9322
9322
  }) {
9323
9323
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -10077,6 +10077,10 @@ var init_boardEntity = __esm({
10077
10077
  });
10078
10078
  function BattleBoard({
10079
10079
  entity,
10080
+ tiles: propTiles,
10081
+ units: propUnits,
10082
+ features: propFeatures,
10083
+ assetManifest: propAssetManifest,
10080
10084
  scale = 0.45,
10081
10085
  unitScale = 1,
10082
10086
  header,
@@ -10102,11 +10106,11 @@ function BattleBoard({
10102
10106
  className
10103
10107
  }) {
10104
10108
  const board = boardEntity(entity) ?? {};
10105
- const tiles = Array.isArray(board.tiles) ? board.tiles : [];
10106
- const features = Array.isArray(board.features) ? board.features : [];
10109
+ const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
10110
+ const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
10107
10111
  const boardWidth = num(board.boardWidth, 8);
10108
10112
  const boardHeight = num(board.boardHeight, 6);
10109
- const assetManifest = board.assetManifest;
10113
+ const assetManifest = propAssetManifest ?? board.assetManifest;
10110
10114
  const backgroundImage = board.backgroundImage;
10111
10115
  const units = rows(board.units);
10112
10116
  const selectedUnitId = board.selectedUnitId ?? null;
@@ -10198,7 +10202,7 @@ function BattleBoard({
10198
10202
  }, 16);
10199
10203
  return () => clearInterval(interval);
10200
10204
  }, []);
10201
- const isoUnits = React74.useMemo(() => {
10205
+ const derivedIsoUnits = React74.useMemo(() => {
10202
10206
  return units.filter((u) => unitHealth(u) > 0).map((unit) => {
10203
10207
  const id = str(unit.id);
10204
10208
  const pos = movingPositions.get(id) ?? unitPosition(unit);
@@ -10222,6 +10226,7 @@ function BattleBoard({
10222
10226
  };
10223
10227
  });
10224
10228
  }, [units, movingPositions]);
10229
+ const isoUnits = propUnits ?? derivedIsoUnits;
10225
10230
  const maxY = Math.max(...tiles.map((t2) => t2.y), 0);
10226
10231
  const baseOffsetX = (maxY + 1) * (exports.TILE_WIDTH * scale / 2);
10227
10232
  const tileToScreen = React74.useCallback(
@@ -10443,14 +10448,22 @@ function BattleTemplate({
10443
10448
  entity,
10444
10449
  scale = 0.45,
10445
10450
  unitScale = 1,
10451
+ tiles,
10452
+ units,
10453
+ features,
10454
+ assetManifest,
10446
10455
  className
10447
10456
  }) {
10448
10457
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
10449
- if (!resolved) return null;
10458
+ if (!resolved && !tiles && !units && !features && !assetManifest) return null;
10450
10459
  return /* @__PURE__ */ jsxRuntime.jsx(
10451
10460
  BattleBoard,
10452
10461
  {
10453
10462
  entity: resolved,
10463
+ tiles,
10464
+ units,
10465
+ features,
10466
+ assetManifest,
10454
10467
  scale,
10455
10468
  unitScale,
10456
10469
  tileClickEvent: "TILE_CLICK",
@@ -17425,16 +17438,21 @@ function EmojiEffect({
17425
17438
  }
17426
17439
  );
17427
17440
  }
17428
- function CanvasEffect(props) {
17441
+ function CanvasEffect({
17442
+ effectSpriteUrl = "https://almadar-kflow-assets.web.app/shared/effects/gas/gas00.png",
17443
+ assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/effects/",
17444
+ ...props
17445
+ }) {
17429
17446
  const eventBus = useEventBus();
17430
- const { completeEvent, onComplete, ...rest } = props;
17447
+ const mergedProps = { effectSpriteUrl, assetBaseUrl, ...props };
17448
+ const { completeEvent, onComplete, ...rest } = mergedProps;
17431
17449
  const handleComplete = React74.useCallback(() => {
17432
17450
  if (completeEvent) eventBus.emit(`UI:${completeEvent}`, {});
17433
17451
  onComplete?.();
17434
17452
  }, [completeEvent, eventBus, onComplete]);
17435
17453
  const enhancedProps = { ...rest, onComplete: handleComplete };
17436
- if (props.assetManifest) {
17437
- return /* @__PURE__ */ jsxRuntime.jsx(CanvasEffectEngine, { ...enhancedProps, assetManifest: props.assetManifest });
17454
+ if (rest.assetManifest) {
17455
+ return /* @__PURE__ */ jsxRuntime.jsx(CanvasEffectEngine, { ...enhancedProps, assetManifest: rest.assetManifest });
17438
17456
  }
17439
17457
  return /* @__PURE__ */ jsxRuntime.jsx(EmojiEffect, { ...enhancedProps });
17440
17458
  }
@@ -18219,6 +18237,10 @@ var init_CaseStudyOrganism = __esm({
18219
18237
  });
18220
18238
  function CastleBoard({
18221
18239
  entity,
18240
+ tiles: propTiles,
18241
+ units: propUnits,
18242
+ features: propFeatures,
18243
+ assetManifest: propAssetManifest,
18222
18244
  scale = 0.45,
18223
18245
  header,
18224
18246
  sidePanel,
@@ -18234,10 +18256,10 @@ function CastleBoard({
18234
18256
  }) {
18235
18257
  const eventBus = useEventBus();
18236
18258
  const resolved = boardEntity(entity);
18237
- const tiles = Array.isArray(resolved?.tiles) ? resolved.tiles : [];
18238
- const features = Array.isArray(resolved?.features) ? resolved.features : [];
18239
- const units = Array.isArray(resolved?.units) ? resolved.units : [];
18240
- const assetManifest = resolved?.assetManifest;
18259
+ const tiles = propTiles ?? (Array.isArray(resolved?.tiles) ? resolved.tiles : []);
18260
+ const features = propFeatures ?? (Array.isArray(resolved?.features) ? resolved.features : []);
18261
+ const units = propUnits ?? (Array.isArray(resolved?.units) ? resolved.units : []);
18262
+ const assetManifest = propAssetManifest ?? resolved?.assetManifest;
18241
18263
  const backgroundImage = resolved?.backgroundImage;
18242
18264
  const [hoveredTile, setHoveredTile] = React74.useState(null);
18243
18265
  const [selectedFeature, setSelectedFeature] = React74.useState(null);
@@ -18340,14 +18362,22 @@ var init_CastleBoard = __esm({
18340
18362
  function CastleTemplate({
18341
18363
  entity,
18342
18364
  scale = 0.45,
18365
+ tiles,
18366
+ units,
18367
+ features,
18368
+ assetManifest,
18343
18369
  className
18344
18370
  }) {
18345
18371
  const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
18346
- if (!resolved) return null;
18372
+ if (!resolved && !tiles && !units && !features && !assetManifest) return null;
18347
18373
  return /* @__PURE__ */ jsxRuntime.jsx(
18348
18374
  CastleBoard,
18349
18375
  {
18350
18376
  entity: resolved,
18377
+ tiles,
18378
+ units,
18379
+ features,
18380
+ assetManifest,
18351
18381
  scale,
18352
18382
  featureClickEvent: "FEATURE_CLICK",
18353
18383
  unitClickEvent: "UNIT_CLICK",
@@ -26234,8 +26264,8 @@ function GameCanvas2D({
26234
26264
  tickEvent,
26235
26265
  drawEvent,
26236
26266
  fps = 60,
26237
- backgroundImage,
26238
- assetBaseUrl = "",
26267
+ backgroundImage = "https://almadar-kflow-assets.web.app/shared/scenes/resonators.jpeg",
26268
+ assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/",
26239
26269
  className
26240
26270
  }) {
26241
26271
  const canvasRef = React74__namespace.useRef(null);
@@ -26299,6 +26329,9 @@ function GameCanvas2D({
26299
26329
  const bgImg = loadImage(backgroundImageRef.current);
26300
26330
  if (bgImg) {
26301
26331
  ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
26332
+ } else {
26333
+ ctx.fillStyle = "#0f1420";
26334
+ ctx.fillRect(0, 0, widthRef.current, heightRef.current);
26302
26335
  }
26303
26336
  }
26304
26337
  onDrawRef.current?.(ctx, frame);
@@ -27495,10 +27528,10 @@ function PlatformerCanvas({
27495
27528
  canvasHeight = 400,
27496
27529
  followCamera = true,
27497
27530
  bgColor,
27498
- playerSprite,
27531
+ playerSprite = "https://almadar-kflow-assets.web.app/shared/platformer/characters/platformChar_idle.png",
27499
27532
  tileSprites,
27500
- backgroundImage,
27501
- assetBaseUrl = "",
27533
+ backgroundImage = "https://almadar-kflow-assets.web.app/shared/scenes/court.png",
27534
+ assetBaseUrl = "https://almadar-kflow-assets.web.app/shared/platformer/",
27502
27535
  leftEvent = "MOVE_LEFT",
27503
27536
  rightEvent = "MOVE_RIGHT",
27504
27537
  jumpEvent = "JUMP",
@@ -38381,7 +38414,7 @@ var init_DetailPanel = __esm({
38381
38414
  function DialogueBubble({
38382
38415
  speaker,
38383
38416
  text,
38384
- portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/00_base_model.png",
38417
+ portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
38385
38418
  position = "bottom",
38386
38419
  className
38387
38420
  }) {
@@ -46611,7 +46644,14 @@ var init_useBattleState = __esm({
46611
46644
  init_boardEntity();
46612
46645
  }
46613
46646
  });
46614
- function UncontrolledBattleBoard({ entity, ...rest }) {
46647
+ function UncontrolledBattleBoard({
46648
+ entity,
46649
+ tiles,
46650
+ units,
46651
+ features,
46652
+ assetManifest,
46653
+ ...rest
46654
+ }) {
46615
46655
  const resolved = boardEntity(entity);
46616
46656
  const battleState = useBattleState(
46617
46657
  rows(resolved?.initialUnits),
@@ -46631,19 +46671,23 @@ function UncontrolledBattleBoard({ entity, ...rest }) {
46631
46671
  calculateDamage: rest.calculateDamage
46632
46672
  }
46633
46673
  );
46634
- if (!resolved) return null;
46674
+ if (!resolved && !tiles && !units && !features && !assetManifest) return null;
46635
46675
  return /* @__PURE__ */ jsxRuntime.jsx(
46636
46676
  BattleBoard,
46637
46677
  {
46638
46678
  ...rest,
46639
- entity: {
46679
+ tiles,
46680
+ units,
46681
+ features,
46682
+ assetManifest,
46683
+ entity: resolved ? {
46640
46684
  ...resolved,
46641
46685
  units: battleState.units,
46642
46686
  phase: battleState.phase,
46643
46687
  turn: battleState.turn,
46644
46688
  gameResult: battleState.gameResult,
46645
46689
  selectedUnitId: battleState.selectedUnitId
46646
- }
46690
+ } : void 0
46647
46691
  }
46648
46692
  );
46649
46693
  }
@@ -46672,6 +46716,10 @@ function defaultIsInRange(from, to, range) {
46672
46716
  }
46673
46717
  function WorldMapBoard({
46674
46718
  entity,
46719
+ tiles: propTiles,
46720
+ units: propUnits,
46721
+ features: propFeatures,
46722
+ assetManifest: propAssetManifest,
46675
46723
  isLoading,
46676
46724
  scale = 0.4,
46677
46725
  unitScale = 2.5,
@@ -46700,16 +46748,16 @@ function WorldMapBoard({
46700
46748
  const resolved = boardEntity(entity);
46701
46749
  const hexes = rows(resolved?.hexes);
46702
46750
  const heroes = rows(resolved?.heroes);
46703
- const features = Array.isArray(resolved?.features) ? resolved.features : [];
46751
+ const features = propFeatures ?? (Array.isArray(resolved?.features) ? resolved.features : []);
46704
46752
  const selectedHeroId = resolved?.selectedHeroId ?? null;
46705
- const assetManifest = resolved?.assetManifest;
46753
+ const assetManifest = propAssetManifest ?? resolved?.assetManifest;
46706
46754
  const backgroundImage = resolved?.backgroundImage;
46707
46755
  const [hoveredTile, setHoveredTile] = React74.useState(null);
46708
46756
  const selectedHero = React74.useMemo(
46709
46757
  () => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
46710
46758
  [heroes, selectedHeroId]
46711
46759
  );
46712
- const tiles = React74.useMemo(
46760
+ const derivedTiles = React74.useMemo(
46713
46761
  () => hexes.map((hex) => ({
46714
46762
  x: num(hex.x),
46715
46763
  y: num(hex.y),
@@ -46718,8 +46766,9 @@ function WorldMapBoard({
46718
46766
  })),
46719
46767
  [hexes]
46720
46768
  );
46769
+ const tiles = propTiles ?? derivedTiles;
46721
46770
  const baseUnits = React74.useMemo(
46722
- () => heroes.map((hero) => ({
46771
+ () => propUnits ?? heroes.map((hero) => ({
46723
46772
  id: str(hero.id),
46724
46773
  position: heroPosition(hero),
46725
46774
  name: str(hero.name),
@@ -46728,7 +46777,7 @@ function WorldMapBoard({
46728
46777
  maxHealth: 100,
46729
46778
  sprite: hero.sprite == null ? void 0 : str(hero.sprite)
46730
46779
  })),
46731
- [heroes]
46780
+ [heroes, propUnits]
46732
46781
  );
46733
46782
  const MOVE_SPEED_MS_PER_TILE = 300;
46734
46783
  const movementAnimRef = React74.useRef(null);
@@ -46938,12 +46987,20 @@ function WorldMapTemplate({
46938
46987
  unitScale = 2.5,
46939
46988
  diamondTopY,
46940
46989
  allowMoveAllHeroes = false,
46990
+ tiles,
46991
+ units,
46992
+ features,
46993
+ assetManifest,
46941
46994
  className
46942
46995
  }) {
46943
46996
  return /* @__PURE__ */ jsxRuntime.jsx(
46944
46997
  WorldMapBoard,
46945
46998
  {
46946
46999
  entity,
47000
+ tiles,
47001
+ units,
47002
+ features,
47003
+ assetManifest,
46947
47004
  scale,
46948
47005
  unitScale,
46949
47006
  diamondTopY,
@@ -48245,6 +48302,24 @@ function renderPatternProps(props, onDismiss) {
48245
48302
  priority: 0
48246
48303
  };
48247
48304
  rendered[key] = /* @__PURE__ */ jsxRuntime.jsx(SlotContentRenderer, { content: childContent, onDismiss });
48305
+ } else if (Array.isArray(value)) {
48306
+ rendered[key] = value.map((item, i) => {
48307
+ const el = item;
48308
+ if (isPatternConfig(el)) {
48309
+ const nestedProps = {};
48310
+ for (const [k, v] of Object.entries(el)) {
48311
+ if (k !== "type") nestedProps[k] = v;
48312
+ }
48313
+ const childContent = {
48314
+ id: `prop-${key}-${i}`,
48315
+ pattern: el.type,
48316
+ props: nestedProps,
48317
+ priority: 0
48318
+ };
48319
+ return /* @__PURE__ */ jsxRuntime.jsx(SlotContentRenderer, { content: childContent, onDismiss }, i);
48320
+ }
48321
+ return substituteTraitRefsDeep(el, `prop:${key}[${i}]`);
48322
+ });
48248
48323
  } else {
48249
48324
  rendered[key] = substituteTraitRefsDeep(value, `prop:${key}`);
48250
48325
  }