@almadar/ui 5.72.0 → 5.74.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 (52) hide show
  1. package/dist/avl/index.cjs +410 -365
  2. package/dist/avl/index.js +410 -365
  3. package/dist/components/game/atoms/ActionButton.d.ts +3 -3
  4. package/dist/components/game/atoms/ChoiceButton.d.ts +3 -3
  5. package/dist/components/game/atoms/ComboCounter.d.ts +3 -3
  6. package/dist/components/game/atoms/ControlButton.d.ts +3 -3
  7. package/dist/components/game/atoms/DamageNumber.d.ts +3 -3
  8. package/dist/components/game/atoms/DialogueBubble.d.ts +3 -3
  9. package/dist/components/game/atoms/ItemSlot.d.ts +3 -3
  10. package/dist/components/game/atoms/ResourceCounter.d.ts +3 -3
  11. package/dist/components/game/atoms/ScoreDisplay.d.ts +3 -3
  12. package/dist/components/game/atoms/Sprite.d.ts +3 -20
  13. package/dist/components/game/atoms/StateIndicator.d.ts +2 -2
  14. package/dist/components/game/atoms/StatusEffect.d.ts +3 -3
  15. package/dist/components/game/atoms/TurnIndicator.d.ts +3 -3
  16. package/dist/components/game/atoms/WaypointMarker.d.ts +3 -3
  17. package/dist/components/game/molecules/CardHand.d.ts +2 -2
  18. package/dist/components/game/molecules/DialogueBox.d.ts +3 -3
  19. package/dist/components/game/molecules/EnemyPlate.d.ts +3 -3
  20. package/dist/components/game/molecules/GameCanvas2D.d.ts +3 -3
  21. package/dist/components/game/molecules/HealthPanel.d.ts +3 -3
  22. package/dist/components/game/molecules/IsometricCanvas.d.ts +8 -12
  23. package/dist/components/game/molecules/PowerupSlots.d.ts +3 -3
  24. package/dist/components/game/molecules/StatBadge.d.ts +5 -5
  25. package/dist/components/game/molecules/TurnPanel.d.ts +3 -3
  26. package/dist/components/game/molecules/three/index.cjs +51 -28
  27. package/dist/components/game/molecules/three/index.js +51 -28
  28. package/dist/components/game/molecules/useUnitSpriteAtlas.d.ts +3 -10
  29. package/dist/components/game/organisms/BattleBoard.d.ts +5 -6
  30. package/dist/components/game/organisms/CardBattlerBoard.d.ts +3 -4
  31. package/dist/components/game/organisms/CastleBoard.d.ts +5 -6
  32. package/dist/components/game/organisms/CityBuilderBoard.d.ts +6 -7
  33. package/dist/components/game/organisms/FishingBoard.d.ts +4 -6
  34. package/dist/components/game/organisms/PlatformerBoard.d.ts +5 -5
  35. package/dist/components/game/organisms/RoguelikeBoard.d.ts +4 -5
  36. package/dist/components/game/organisms/TopDownShooterBoard.d.ts +5 -6
  37. package/dist/components/game/organisms/TowerDefenseBoard.d.ts +5 -6
  38. package/dist/components/game/organisms/VisualNovelBoard.d.ts +4 -5
  39. package/dist/components/game/organisms/WorldMapBoard.d.ts +5 -6
  40. package/dist/components/game/organisms/types/effects.d.ts +7 -8
  41. package/dist/components/game/organisms/types/isometric.d.ts +8 -8
  42. package/dist/components/game/organisms/types/spriteAnimation.d.ts +3 -4
  43. package/dist/components/game/organisms/utils/makeAsset.d.ts +5 -0
  44. package/dist/components/game/templates/PlatformerTemplate.d.ts +5 -4
  45. package/dist/components/game/templates/game3dAssetManifest.d.ts +6 -8
  46. package/dist/components/index.cjs +425 -366
  47. package/dist/components/index.js +425 -366
  48. package/dist/providers/index.cjs +410 -365
  49. package/dist/providers/index.js +410 -365
  50. package/dist/runtime/index.cjs +410 -365
  51. package/dist/runtime/index.js +410 -365
  52. package/package.json +2 -2
@@ -8125,7 +8125,7 @@ function ActionButton({
8125
8125
  assetUrl ? /* @__PURE__ */ jsx(
8126
8126
  "img",
8127
8127
  {
8128
- src: assetUrl,
8128
+ src: assetUrl.url,
8129
8129
  alt: "",
8130
8130
  width: 16,
8131
8131
  height: 16,
@@ -8169,7 +8169,11 @@ var init_ActionButton = __esm({
8169
8169
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
8170
8170
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
8171
8171
  };
8172
- DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
8172
+ DEFAULT_ASSET_URL = {
8173
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
8174
+ role: "effect",
8175
+ category: "effect"
8176
+ };
8173
8177
  ActionButton.displayName = "ActionButton";
8174
8178
  }
8175
8179
  });
@@ -8245,7 +8249,7 @@ function ControlButton({
8245
8249
  children: assetUrl ? /* @__PURE__ */ jsx(
8246
8250
  "img",
8247
8251
  {
8248
- src: assetUrl,
8252
+ src: assetUrl.url,
8249
8253
  alt: "",
8250
8254
  width: 24,
8251
8255
  height: 24,
@@ -8285,7 +8289,11 @@ var init_ControlButton = __esm({
8285
8289
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
8286
8290
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
8287
8291
  };
8288
- DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
8292
+ DEFAULT_ASSET_URL2 = {
8293
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
8294
+ role: "effect",
8295
+ category: "effect"
8296
+ };
8289
8297
  ControlButton.displayName = "ControlButton";
8290
8298
  }
8291
8299
  });
@@ -9854,12 +9862,7 @@ var init_spriteAnimation = __esm({
9854
9862
  }
9855
9863
  });
9856
9864
  function unitAtlasUrl(unit) {
9857
- if (unit.spriteSheet) return unit.spriteSheet;
9858
- const sprite = unit.sprite;
9859
- if (!sprite) return null;
9860
- const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
9861
- if (!match) return null;
9862
- return `${match[1]}.json`;
9865
+ return unit.spriteSheet?.url ?? null;
9863
9866
  }
9864
9867
  function resolveSheetUrl(atlasUrl, relativeSheetPath) {
9865
9868
  try {
@@ -10055,7 +10058,6 @@ function IsometricCanvas({
10055
10058
  // Tuning
10056
10059
  diamondTopY: diamondTopYProp,
10057
10060
  // Remote asset loading
10058
- assetBaseUrl,
10059
10061
  assetManifest
10060
10062
  }) {
10061
10063
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -10137,54 +10139,48 @@ function IsometricCanvas({
10137
10139
  const attackTargetSet = useMemo(() => {
10138
10140
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
10139
10141
  }, [attackTargets]);
10140
- const resolveManifestUrl7 = useCallback((relativePath) => {
10141
- if (!relativePath) return void 0;
10142
- if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
10143
- return relativePath;
10144
- }, [assetBaseUrl]);
10145
10142
  const spriteUrls = useMemo(() => {
10146
10143
  const urls = [];
10147
10144
  for (const tile of sortedTiles) {
10148
- if (tile.terrainSprite) urls.push(tile.terrainSprite);
10145
+ if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
10149
10146
  else if (getTerrainSprite) {
10150
10147
  const url = getTerrainSprite(tile.terrain ?? "");
10151
10148
  if (url) urls.push(url);
10152
10149
  } else {
10153
- const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
10150
+ const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
10154
10151
  if (url) urls.push(url);
10155
10152
  }
10156
10153
  }
10157
10154
  for (const feature of features) {
10158
- if (feature.sprite) urls.push(feature.sprite);
10155
+ if (feature.sprite) urls.push(feature.sprite.url);
10159
10156
  else if (getFeatureSprite) {
10160
10157
  const url = getFeatureSprite(feature.type);
10161
10158
  if (url) urls.push(url);
10162
10159
  } else {
10163
- const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
10160
+ const url = assetManifest?.features?.[feature.type]?.url;
10164
10161
  if (url) urls.push(url);
10165
10162
  }
10166
10163
  }
10167
10164
  for (const unit of units) {
10168
- if (unit.sprite) urls.push(unit.sprite);
10165
+ if (unit.sprite) urls.push(unit.sprite.url);
10169
10166
  else if (getUnitSprite) {
10170
10167
  const url = getUnitSprite(unit);
10171
10168
  if (url) urls.push(url);
10172
10169
  } else if (unit.unitType) {
10173
- const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
10170
+ const url = assetManifest?.units?.[unit.unitType]?.url;
10174
10171
  if (url) urls.push(url);
10175
10172
  }
10176
10173
  }
10177
10174
  if (assetManifest?.effects) {
10178
- for (const path of Object.values(assetManifest.effects)) {
10179
- const url = resolveManifestUrl7(path);
10180
- if (url) urls.push(url);
10175
+ for (const asset of Object.values(assetManifest.effects)) {
10176
+ if (asset.url) urls.push(asset.url);
10181
10177
  }
10182
10178
  }
10183
10179
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
10184
10180
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
10185
10181
  if (backgroundImage) urls.push(backgroundImage);
10186
10182
  return [...new Set(urls.filter(Boolean))];
10187
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
10183
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest]);
10188
10184
  const { getImage, pendingCount: _imagePendingCount } = useImageCache(spriteUrls);
10189
10185
  useEffect(() => {
10190
10186
  if (typeof window === "undefined") return;
@@ -10209,14 +10205,14 @@ function IsometricCanvas({
10209
10205
  lerpToTarget
10210
10206
  } = useCamera();
10211
10207
  const resolveTerrainSpriteUrl = useCallback((tile) => {
10212
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
10213
- }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
10208
+ return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
10209
+ }, [getTerrainSprite, assetManifest]);
10214
10210
  const resolveFeatureSpriteUrl = useCallback((featureType) => {
10215
- return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
10216
- }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
10211
+ return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
10212
+ }, [getFeatureSprite, assetManifest]);
10217
10213
  const resolveUnitSpriteUrl = useCallback((unit) => {
10218
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
10219
- }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
10214
+ return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
10215
+ }, [getUnitSprite, assetManifest]);
10220
10216
  const miniMapTiles = useMemo(() => {
10221
10217
  if (!showMinimap) return [];
10222
10218
  return sortedTiles.map((t2) => ({
@@ -10363,7 +10359,7 @@ function IsometricCanvas({
10363
10359
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
10364
10360
  continue;
10365
10361
  }
10366
- const spriteUrl = feature.sprite || resolveFeatureSpriteUrl(feature.type);
10362
+ const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
10367
10363
  const img = spriteUrl ? getImage(spriteUrl) : null;
10368
10364
  const centerX = pos.x + scaledTileWidth / 2;
10369
10365
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
@@ -10412,12 +10408,12 @@ function IsometricCanvas({
10412
10408
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
10413
10409
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
10414
10410
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
10411
+ const unitIsSheet = unit.sprite?.dimension === "2d" && (unit.sprite?.animations?.length ?? 0) > 0;
10415
10412
  const SHEET_ROWS = 5;
10416
10413
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
10417
10414
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
10418
- const imgIsSheet = img ? img.naturalWidth % SHEET_COLUMNS === 0 && img.naturalHeight % SHEET_ROWS === 0 && Math.abs(sheetFrameW - sheetFrameH) < 2 : false;
10419
- const frameW = imgIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
10420
- const frameH = imgIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
10415
+ const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
10416
+ const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
10421
10417
  const ar = frameW / (frameH || 1);
10422
10418
  let drawH = unitDrawH;
10423
10419
  let drawW = unitDrawH * ar;
@@ -10432,7 +10428,7 @@ function IsometricCanvas({
10432
10428
  ctx.save();
10433
10429
  ctx.globalAlpha = 0.25;
10434
10430
  if (img) {
10435
- if (imgIsSheet) {
10431
+ if (unitIsSheet) {
10436
10432
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
10437
10433
  } else {
10438
10434
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
@@ -10480,7 +10476,7 @@ function IsometricCanvas({
10480
10476
  } else if (img) {
10481
10477
  const spriteY = groundY - drawH - breatheOffset;
10482
10478
  const drawUnit = (x) => {
10483
- if (imgIsSheet) {
10479
+ if (unitIsSheet) {
10484
10480
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
10485
10481
  } else {
10486
10482
  ctx.drawImage(img, x, spriteY, drawW, drawH);
@@ -10507,7 +10503,7 @@ function IsometricCanvas({
10507
10503
  }
10508
10504
  }
10509
10505
  for (const fx of effects) {
10510
- const spriteUrl = resolveManifestUrl7(assetManifest?.effects?.[fx.key]);
10506
+ const spriteUrl = assetManifest?.effects?.[fx.key]?.url;
10511
10507
  if (!spriteUrl) continue;
10512
10508
  const img = getImage(spriteUrl);
10513
10509
  if (!img) continue;
@@ -10551,7 +10547,6 @@ function IsometricCanvas({
10551
10547
  backgroundImage,
10552
10548
  cameraRef,
10553
10549
  unitScale,
10554
- resolveManifestUrl7,
10555
10550
  assetManifest
10556
10551
  ]);
10557
10552
  useEffect(() => {
@@ -10829,6 +10824,42 @@ var init_boardEntity = __esm({
10829
10824
  "components/game/organisms/boardEntity.ts"() {
10830
10825
  }
10831
10826
  });
10827
+
10828
+ // components/game/organisms/utils/makeAsset.ts
10829
+ function makeAsset(url, role, overrides = {}) {
10830
+ const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
10831
+ return {
10832
+ url,
10833
+ role,
10834
+ category: url.split("/").pop()?.replace(/\.[^.]+$/, "") ?? role,
10835
+ ...defaults,
10836
+ ...overrides
10837
+ };
10838
+ }
10839
+ function makeAssetMap(record, role, overrides = {}) {
10840
+ const result = {};
10841
+ for (const [key, url] of Object.entries(record)) {
10842
+ result[key] = makeAsset(url, role, overrides);
10843
+ }
10844
+ return result;
10845
+ }
10846
+ var ROLE_DEFAULTS;
10847
+ var init_makeAsset = __esm({
10848
+ "components/game/organisms/utils/makeAsset.ts"() {
10849
+ ROLE_DEFAULTS = {
10850
+ tile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
10851
+ decoration: { dimension: "2d", animations: ["static"], aspect: "1:1" },
10852
+ effect: { dimension: "2d", animations: ["static"], aspect: "1:1" },
10853
+ item: { dimension: "2d", animations: ["static"], aspect: "5:7" },
10854
+ player: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
10855
+ enemy: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
10856
+ npc: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
10857
+ projectile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
10858
+ vehicle: { dimension: "2d", animations: ["idle", "walk"], aspect: "1:1" },
10859
+ ui: { dimension: "2d", animations: ["static"], aspect: "1:1" }
10860
+ };
10861
+ }
10862
+ });
10832
10863
  function buildDefaultBattleTiles() {
10833
10864
  const tiles = [];
10834
10865
  for (let y = 0; y < BATTLE_GRID_H; y++) {
@@ -10887,14 +10918,14 @@ function BattleBoard({
10887
10918
  if (o === null || typeof o.x !== "number" || typeof o.y !== "number") return [];
10888
10919
  const tile = { x: o.x, y: o.y };
10889
10920
  if (typeof o.terrain === "string") tile.terrain = o.terrain;
10890
- if (typeof o.terrainSprite === "string") tile.terrainSprite = o.terrainSprite;
10921
+ if (typeof o.terrainSprite === "string") tile.terrainSprite = makeAsset(o.terrainSprite, "tile");
10891
10922
  if (typeof o.passable === "boolean") tile.passable = o.passable;
10892
10923
  if (typeof o.movementCost === "number") tile.movementCost = o.movementCost;
10893
10924
  if (typeof o.elevation === "number") tile.elevation = o.elevation;
10894
10925
  if (typeof o.type === "string") tile.type = o.type;
10895
10926
  if (typeof o.tileType === "string") tile.tileType = o.tileType;
10896
10927
  if (typeof o.id === "string") tile.id = o.id;
10897
- if (typeof o.modelUrl === "string") tile.modelUrl = o.modelUrl;
10928
+ if (typeof o.modelUrl === "string") tile.modelUrl = makeAsset(o.modelUrl, "decoration", { dimension: "3d" });
10898
10929
  return [tile];
10899
10930
  }) : []);
10900
10931
  const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
@@ -10903,10 +10934,10 @@ function BattleBoard({
10903
10934
  if (o === null || typeof o.type !== "string" || typeof o.x !== "number" || typeof o.y !== "number") return [];
10904
10935
  const feat = { type: o.type, x: o.x, y: o.y };
10905
10936
  if (typeof o.id === "string") feat.id = o.id;
10906
- if (typeof o.sprite === "string") feat.sprite = o.sprite;
10937
+ if (typeof o.sprite === "string") feat.sprite = makeAsset(o.sprite, "decoration");
10907
10938
  if (typeof o.color === "string") feat.color = o.color;
10908
10939
  if (typeof o.elevation === "number") feat.elevation = o.elevation;
10909
- if (typeof o.assetUrl === "string") feat.assetUrl = o.assetUrl;
10940
+ if (typeof o.assetUrl === "string") feat.assetUrl = makeAsset(o.assetUrl, "decoration", { dimension: "3d" });
10910
10941
  return [feat];
10911
10942
  }) : []);
10912
10943
  const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
@@ -11022,7 +11053,7 @@ function BattleBoard({
11022
11053
  maxHealth: num(unit.maxHealth),
11023
11054
  unitType: unit.unitType == null ? void 0 : str(unit.unitType),
11024
11055
  heroId: unit.heroId == null ? void 0 : str(unit.heroId),
11025
- sprite: unit.sprite == null ? void 0 : str(unit.sprite),
11056
+ sprite: unit.sprite == null ? void 0 : makeAsset(str(unit.sprite), "npc"),
11026
11057
  traits: unitTraits?.map((tr) => ({
11027
11058
  name: tr.name,
11028
11059
  currentState: tr.currentState,
@@ -11172,7 +11203,6 @@ function BattleBoard({
11172
11203
  onTileHover: (x, y) => setHoveredTile({ x, y }),
11173
11204
  onTileLeave: () => setHoveredTile(null),
11174
11205
  scale,
11175
- assetBaseUrl: assetManifest?.baseUrl,
11176
11206
  assetManifest,
11177
11207
  backgroundImage,
11178
11208
  onDrawEffects,
@@ -11250,15 +11280,16 @@ var init_BattleBoard = __esm({
11250
11280
  init_IsometricCanvas();
11251
11281
  init_boardEntity();
11252
11282
  init_isometric();
11283
+ init_makeAsset();
11253
11284
  BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
11254
11285
  BATTLE_GRID_W = 16;
11255
11286
  BATTLE_GRID_H = 16;
11256
11287
  BATTLE_TERRAIN_SPRITES = [
11257
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
11258
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
11259
- `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
11260
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
11261
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
11288
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`, "tile"),
11289
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile"),
11290
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`, "tile"),
11291
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, "tile"),
11292
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile")
11262
11293
  ];
11263
11294
  DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
11264
11295
  BattleBoard.displayName = "BattleBoard";
@@ -11297,61 +11328,64 @@ function BattleTemplate({
11297
11328
  }
11298
11329
  );
11299
11330
  }
11300
- var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
11331
+ var CDN, STONE, DIRT, GRASS, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
11301
11332
  var init_BattleTemplate = __esm({
11302
11333
  "components/game/templates/BattleTemplate.tsx"() {
11303
11334
  init_BattleBoard();
11335
+ init_makeAsset();
11304
11336
  CDN = "https://almadar-kflow-assets.web.app/shared";
11337
+ STONE = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`, "tile");
11338
+ DIRT = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`, "tile");
11339
+ GRASS = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`, "tile");
11305
11340
  DEFAULT_BATTLE_TILES2 = [
11306
- { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11307
- { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11308
- { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11309
- { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11310
- { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11311
- { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11312
- { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
11313
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
11314
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
11315
- { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11316
- { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11317
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
11318
- { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
11319
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
11320
- { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11321
- { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11322
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
11323
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
11324
- { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
11325
- { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11326
- { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11327
- { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11328
- { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11329
- { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11330
- { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` }
11341
+ { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
11342
+ { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
11343
+ { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
11344
+ { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
11345
+ { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
11346
+ { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
11347
+ { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: DIRT },
11348
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
11349
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
11350
+ { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
11351
+ { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
11352
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
11353
+ { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: DIRT },
11354
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
11355
+ { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
11356
+ { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
11357
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
11358
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
11359
+ { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: DIRT },
11360
+ { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
11361
+ { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
11362
+ { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
11363
+ { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
11364
+ { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
11365
+ { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: STONE }
11331
11366
  ];
11332
11367
  DEFAULT_BATTLE_UNITS = [
11333
- { id: "u1", position: { x: 1, y: 1 }, unitType: "worker", name: "Worker", team: "player", health: 10, maxHealth: 10, sprite: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png` },
11334
- { id: "u2", position: { x: 3, y: 3 }, unitType: "guardian", name: "Guardian", team: "enemy", health: 8, maxHealth: 10, sprite: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png` }
11368
+ { id: "u1", position: { x: 1, y: 1 }, unitType: "worker", name: "Worker", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN}/sprite-sheets/amir-sprite-sheet-se.png`, "player") },
11369
+ { id: "u2", position: { x: 3, y: 3 }, unitType: "guardian", name: "Guardian", team: "enemy", health: 8, maxHealth: 10, sprite: makeAsset(`${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`, "enemy") }
11335
11370
  ];
11336
11371
  DEFAULT_BATTLE_FEATURES = [
11337
- { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: `${CDN}/world-map/gold_mine.png` },
11338
- { id: "f2", x: 3, y: 1, type: "portal", sprite: `${CDN}/world-map/portal_open.png` }
11372
+ { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: makeAsset(`${CDN}/world-map/gold_mine.png`, "decoration") },
11373
+ { id: "f2", x: 3, y: 1, type: "portal", sprite: makeAsset(`${CDN}/world-map/portal_open.png`, "decoration") }
11339
11374
  ];
11340
11375
  DEFAULT_BATTLE_MANIFEST = {
11341
- baseUrl: CDN,
11342
- terrains: {
11343
- stone: "/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png",
11344
- dirt: "/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png",
11345
- grass: "/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png"
11346
- },
11347
- units: {
11348
- worker: "/sprite-sheets/amir-sprite-sheet-se.png",
11349
- guardian: "/sprite-sheets/destroyer-sprite-sheet-sw.png"
11350
- },
11351
- features: {
11352
- gold_mine: "/world-map/gold_mine.png",
11353
- portal: "/world-map/portal_open.png"
11354
- }
11376
+ terrains: makeAssetMap({
11377
+ stone: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`,
11378
+ dirt: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`,
11379
+ grass: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`
11380
+ }, "tile"),
11381
+ units: makeAssetMap({
11382
+ worker: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png`,
11383
+ guardian: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`
11384
+ }, "npc"),
11385
+ features: makeAssetMap({
11386
+ gold_mine: `${CDN}/world-map/gold_mine.png`,
11387
+ portal: `${CDN}/world-map/portal_open.png`
11388
+ }, "decoration")
11355
11389
  };
11356
11390
  BattleTemplate.displayName = "BattleTemplate";
11357
11391
  }
@@ -13566,7 +13600,6 @@ function BoardgameBoard({
13566
13600
  units,
13567
13601
  features,
13568
13602
  assetManifest,
13569
- assetBaseUrl,
13570
13603
  scale,
13571
13604
  showMinimap,
13572
13605
  enableCamera,
@@ -18636,7 +18669,7 @@ function CardHand({
18636
18669
  /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsx(
18637
18670
  "img",
18638
18671
  {
18639
- src: card.iconUrl,
18672
+ src: card.iconUrl.url,
18640
18673
  alt: card.title ?? card.id,
18641
18674
  width: art,
18642
18675
  height: art,
@@ -18694,15 +18727,6 @@ var init_CardHand = __esm({
18694
18727
  CardHand.displayName = "CardHand";
18695
18728
  }
18696
18729
  });
18697
- function resolveManifestUrl(manifest, relative) {
18698
- if (relative == null) return void 0;
18699
- if (/^https?:\/\//.test(relative)) return relative;
18700
- const base = manifest?.baseUrl;
18701
- if (base == null) return relative;
18702
- const cleanBase = base.replace(/\/$/, "");
18703
- const cleanRel = relative.replace(/^\//, "");
18704
- return `${cleanBase}/${cleanRel}`;
18705
- }
18706
18730
  function rowToCard(r) {
18707
18731
  return {
18708
18732
  id: str(r.id),
@@ -18716,7 +18740,7 @@ function rowToCard(r) {
18716
18740
  function toHandCards(cards, manifest, mana) {
18717
18741
  return cards.map((c) => {
18718
18742
  const key = c.iconKey ?? c.id;
18719
- const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
18743
+ const iconUrl = manifest?.cards?.[key];
18720
18744
  return {
18721
18745
  id: c.id,
18722
18746
  iconUrl,
@@ -19830,7 +19854,6 @@ function CastleBoard({
19830
19854
  onTileHover: (x, y) => setHoveredTile({ x, y }),
19831
19855
  onTileLeave: () => setHoveredTile(null),
19832
19856
  scale,
19833
- assetBaseUrl: assetManifest?.baseUrl,
19834
19857
  assetManifest,
19835
19858
  backgroundImage
19836
19859
  }
@@ -19906,60 +19929,63 @@ function CastleTemplate({
19906
19929
  }
19907
19930
  );
19908
19931
  }
19909
- var CDN2, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
19932
+ var CDN2, WALL, FLOOR, FLOOR_CENTER, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
19910
19933
  var init_CastleTemplate = __esm({
19911
19934
  "components/game/templates/CastleTemplate.tsx"() {
19912
19935
  init_CastleBoard();
19936
+ init_makeAsset();
19913
19937
  CDN2 = "https://almadar-kflow-assets.web.app/shared";
19938
+ WALL = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`, "tile");
19939
+ FLOOR = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
19940
+ FLOOR_CENTER = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`, "tile");
19914
19941
  DEFAULT_CASTLE_TILES = [
19915
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19916
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19917
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19918
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19919
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19920
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19921
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
19922
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
19923
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
19924
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19925
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19926
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
19927
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png` },
19928
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
19929
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19930
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19931
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
19932
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
19933
- { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
19934
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19935
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19936
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19937
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19938
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
19939
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` }
19942
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
19943
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
19944
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
19945
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
19946
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
19947
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
19948
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
19949
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
19950
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
19951
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
19952
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
19953
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
19954
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR_CENTER },
19955
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
19956
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
19957
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
19958
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
19959
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
19960
+ { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
19961
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
19962
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
19963
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
19964
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
19965
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
19966
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: WALL }
19940
19967
  ];
19941
19968
  DEFAULT_CASTLE_UNITS = [
19942
- { id: "u1", position: { x: 1, y: 1 }, unitType: "worker", name: "Worker", team: "player", health: 10, maxHealth: 10, sprite: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png` },
19943
- { id: "u2", position: { x: 3, y: 3 }, unitType: "guardian", name: "Guardian", team: "player", health: 10, maxHealth: 10, sprite: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png` }
19969
+ { id: "u1", position: { x: 1, y: 1 }, unitType: "worker", name: "Worker", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`, "player") },
19970
+ { id: "u2", position: { x: 3, y: 3 }, unitType: "guardian", name: "Guardian", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`, "player") }
19944
19971
  ];
19945
19972
  DEFAULT_CASTLE_FEATURES = [
19946
- { id: "f1", x: 2, y: 2, type: "chest", sprite: `${CDN2}/world-map/treasure_chest_closed.png` },
19947
- { id: "f2", x: 3, y: 1, type: "crystal", sprite: `${CDN2}/world-map/resonance_crystal.png` }
19973
+ { id: "f1", x: 2, y: 2, type: "chest", sprite: makeAsset(`${CDN2}/world-map/treasure_chest_closed.png`, "decoration") },
19974
+ { id: "f2", x: 3, y: 1, type: "crystal", sprite: makeAsset(`${CDN2}/world-map/resonance_crystal.png`, "decoration") }
19948
19975
  ];
19949
19976
  DEFAULT_CASTLE_MANIFEST = {
19950
- baseUrl: CDN2,
19951
- terrains: {
19952
- wall: "/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png",
19953
- floor: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png"
19954
- },
19955
- units: {
19956
- worker: "/sprite-sheets/coordinator-sprite-sheet-se.png",
19957
- guardian: "/sprite-sheets/forger-sprite-sheet-se.png"
19958
- },
19959
- features: {
19960
- chest: "/world-map/treasure_chest_closed.png",
19961
- crystal: "/world-map/resonance_crystal.png"
19962
- }
19977
+ terrains: makeAssetMap({
19978
+ wall: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
19979
+ floor: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`
19980
+ }, "tile"),
19981
+ units: makeAssetMap({
19982
+ worker: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`,
19983
+ guardian: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`
19984
+ }, "player"),
19985
+ features: makeAssetMap({
19986
+ chest: `${CDN2}/world-map/treasure_chest_closed.png`,
19987
+ crystal: `${CDN2}/world-map/resonance_crystal.png`
19988
+ }, "decoration")
19963
19989
  };
19964
19990
  CastleTemplate.displayName = "CastleTemplate";
19965
19991
  }
@@ -20987,7 +21013,7 @@ function ChoiceButton({
20987
21013
  assetUrl ? /* @__PURE__ */ jsx(
20988
21014
  "img",
20989
21015
  {
20990
- src: assetUrl,
21016
+ src: assetUrl.url,
20991
21017
  alt: "",
20992
21018
  width: 16,
20993
21019
  height: 16,
@@ -21013,15 +21039,6 @@ var init_ChoiceButton = __esm({
21013
21039
  ChoiceButton.displayName = "ChoiceButton";
21014
21040
  }
21015
21041
  });
21016
- function resolveManifestUrl2(manifest, relative) {
21017
- if (relative == null) return void 0;
21018
- if (/^https?:\/\//.test(relative)) return relative;
21019
- const base = manifest?.baseUrl;
21020
- if (base == null) return relative;
21021
- const cleanBase = base.replace(/\/$/, "");
21022
- const cleanRel = relative.replace(/^\//, "");
21023
- return `${cleanBase}/${cleanRel}`;
21024
- }
21025
21042
  function buildDefaultCBTiles() {
21026
21043
  const tiles = [];
21027
21044
  for (let y = 0; y < CB_GRID_H; y++) {
@@ -21036,12 +21053,12 @@ function buildDefaultCBTiles() {
21036
21053
  function tilesToIso(tiles, manifest) {
21037
21054
  return tiles.map((t) => {
21038
21055
  const key = t.terrain ?? "grass";
21039
- const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
21056
+ const terrainSprite = t.terrainSprite ?? manifest?.terrains?.[key] ?? manifest?.terrains?.grass;
21040
21057
  return {
21041
21058
  x: t.x,
21042
21059
  y: t.y,
21043
21060
  terrain: t.terrain,
21044
- terrainSprite: sprite,
21061
+ terrainSprite,
21045
21062
  passable: t.passable
21046
21063
  };
21047
21064
  });
@@ -21052,7 +21069,7 @@ function buildingsToFeatures(buildings, manifest) {
21052
21069
  x: b.x,
21053
21070
  y: b.y,
21054
21071
  type: b.type,
21055
- sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
21072
+ sprite: manifest?.features?.[b.type]
21056
21073
  }));
21057
21074
  }
21058
21075
  function CityBuilderBoard({
@@ -21084,7 +21101,7 @@ function CityBuilderBoard({
21084
21101
  x: num(r.x),
21085
21102
  y: num(r.y),
21086
21103
  terrain: r.terrain == null ? void 0 : str(r.terrain),
21087
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
21104
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
21088
21105
  passable: r.passable !== false
21089
21106
  })),
21090
21107
  [board.tiles]
@@ -21193,7 +21210,6 @@ function CityBuilderBoard({
21193
21210
  {
21194
21211
  tiles: isoTiles,
21195
21212
  features: buildingFeatures,
21196
- assetBaseUrl: assetManifest?.baseUrl,
21197
21213
  assetManifest,
21198
21214
  validMoves,
21199
21215
  hoveredTile,
@@ -21228,6 +21244,7 @@ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
21228
21244
  var init_CityBuilderBoard = __esm({
21229
21245
  "components/game/organisms/CityBuilderBoard.tsx"() {
21230
21246
  "use client";
21247
+ init_makeAsset();
21231
21248
  init_cn();
21232
21249
  init_useEventBus();
21233
21250
  init_Box();
@@ -21759,7 +21776,7 @@ function ComboCounter({
21759
21776
  assetUrl && /* @__PURE__ */ jsx(
21760
21777
  "img",
21761
21778
  {
21762
- src: assetUrl,
21779
+ src: assetUrl.url,
21763
21780
  alt: "combo",
21764
21781
  width: 24,
21765
21782
  height: 24,
@@ -21785,7 +21802,11 @@ var DEFAULT_ASSET_URL3, sizeMap5;
21785
21802
  var init_ComboCounter = __esm({
21786
21803
  "components/game/atoms/ComboCounter.tsx"() {
21787
21804
  init_cn();
21788
- DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
21805
+ DEFAULT_ASSET_URL3 = {
21806
+ url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
21807
+ role: "effect",
21808
+ category: "effect"
21809
+ };
21789
21810
  sizeMap5 = {
21790
21811
  sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
21791
21812
  md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
@@ -22230,7 +22251,7 @@ function ItemSlot({
22230
22251
  assetUrl ? /* @__PURE__ */ jsx(
22231
22252
  "img",
22232
22253
  {
22233
- src: assetUrl,
22254
+ src: assetUrl?.url,
22234
22255
  alt: label,
22235
22256
  width: px,
22236
22257
  height: px,
@@ -22278,7 +22299,11 @@ var init_ItemSlot = __esm({
22278
22299
  epic: "shadow-lg",
22279
22300
  legendary: "shadow-lg"
22280
22301
  };
22281
- DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
22302
+ DEFAULT_ASSET_URL4 = {
22303
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
22304
+ role: "effect",
22305
+ category: "item"
22306
+ };
22282
22307
  assetSizeMap = {
22283
22308
  sm: 28,
22284
22309
  md: 40,
@@ -22480,7 +22505,7 @@ function DamageNumber({
22480
22505
  assetUrl && /* @__PURE__ */ jsx(
22481
22506
  "img",
22482
22507
  {
22483
- src: assetUrl,
22508
+ src: assetUrl.url,
22484
22509
  alt: "",
22485
22510
  width: 14,
22486
22511
  height: 14,
@@ -22516,7 +22541,11 @@ var init_DamageNumber = __esm({
22516
22541
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
22517
22542
  }
22518
22543
  `;
22519
- DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
22544
+ DEFAULT_ASSET_URL5 = {
22545
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
22546
+ role: "effect",
22547
+ category: "effect"
22548
+ };
22520
22549
  DamageNumber.displayName = "DamageNumber";
22521
22550
  }
22522
22551
  });
@@ -25459,6 +25488,9 @@ function TextLikeControl({
25459
25488
  function isTraitConfigObject(v) {
25460
25489
  return v !== null && v !== void 0 && typeof v === "object" && !Array.isArray(v);
25461
25490
  }
25491
+ function isAssetObject(v) {
25492
+ return isTraitConfigObject(v) && typeof v.url === "string";
25493
+ }
25462
25494
  function FieldControl({
25463
25495
  name,
25464
25496
  decl,
@@ -25480,6 +25512,17 @@ function FieldControl({
25480
25512
  onChange: (url) => onChange(name, url)
25481
25513
  }
25482
25514
  );
25515
+ } else if (decl.type === "Asset") {
25516
+ const assetUrl = isAssetObject(effectiveValue) ? effectiveValue.url : "";
25517
+ const baseAsset = isAssetObject(effectiveValue) ? effectiveValue : {};
25518
+ control = /* @__PURE__ */ jsx(
25519
+ AssetPicker,
25520
+ {
25521
+ assets: assets ?? [],
25522
+ value: assetUrl,
25523
+ onChange: (url) => onChange(name, { ...baseAsset, url })
25524
+ }
25525
+ );
25483
25526
  } else if (decl.type === "boolean") {
25484
25527
  control = /* @__PURE__ */ jsx(Switch, { checked: value === true, onChange: (c) => onChange(name, c) });
25485
25528
  } else if (decl.type === "string" && decl.values !== void 0 && decl.values.length > 0) {
@@ -25532,7 +25575,7 @@ var init_PropertyInspector = __esm({
25532
25575
  init_JsonTreeEditor();
25533
25576
  init_NodeSlotEditor();
25534
25577
  TIER_ORDER = ["presentation", "domain", "policy", "infra", "internal"];
25535
- SCALAR_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "icon", "asset"]);
25578
+ SCALAR_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "icon", "asset", "Asset"]);
25536
25579
  PropertyInspector = ({
25537
25580
  config,
25538
25581
  values,
@@ -28636,7 +28679,7 @@ function ScoreDisplay({
28636
28679
  assetUrl ? /* @__PURE__ */ jsx(
28637
28680
  "img",
28638
28681
  {
28639
- src: assetUrl,
28682
+ src: assetUrl.url,
28640
28683
  alt: "",
28641
28684
  width: 20,
28642
28685
  height: 20,
@@ -28661,7 +28704,11 @@ var init_ScoreDisplay = __esm({
28661
28704
  lg: "text-2xl",
28662
28705
  xl: "text-4xl"
28663
28706
  };
28664
- DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
28707
+ DEFAULT_ASSET_URL6 = {
28708
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png",
28709
+ role: "effect",
28710
+ category: "effect"
28711
+ };
28665
28712
  ScoreDisplay.displayName = "ScoreDisplay";
28666
28713
  }
28667
28714
  });
@@ -28695,7 +28742,7 @@ function StatBadge({
28695
28742
  resolvedAsset ? /* @__PURE__ */ jsx(
28696
28743
  "img",
28697
28744
  {
28698
- src: resolvedAsset,
28745
+ src: resolvedAsset.url,
28699
28746
  alt: "",
28700
28747
  width: 16,
28701
28748
  height: 16,
@@ -28878,7 +28925,7 @@ function WaypointMarker({
28878
28925
  children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsx(
28879
28926
  "img",
28880
28927
  {
28881
- src: assetUrl,
28928
+ src: assetUrl.url,
28882
28929
  alt: label,
28883
28930
  width: sizes.img,
28884
28931
  height: sizes.img,
@@ -28907,7 +28954,11 @@ var init_WaypointMarker = __esm({
28907
28954
  "components/game/atoms/WaypointMarker.tsx"() {
28908
28955
  init_cn();
28909
28956
  init_Icon();
28910
- DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
28957
+ DEFAULT_ASSET_URL7 = {
28958
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
28959
+ role: "effect",
28960
+ category: "world"
28961
+ };
28911
28962
  sizeMap12 = {
28912
28963
  sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
28913
28964
  md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
@@ -29084,7 +29135,7 @@ function GameCanvas2D({
29084
29135
  tickEvent,
29085
29136
  drawEvent,
29086
29137
  fps = 60,
29087
- backgroundImage = "",
29138
+ backgroundImage,
29088
29139
  assetBaseUrl,
29089
29140
  className
29090
29141
  }) {
@@ -29148,7 +29199,7 @@ function GameCanvas2D({
29148
29199
  emitRef.current(tickEventRef.current, { dt, frame });
29149
29200
  }
29150
29201
  if (backgroundImageRef.current) {
29151
- const bgImg = loadImage(backgroundImageRef.current);
29202
+ const bgImg = loadImage(backgroundImageRef.current.url);
29152
29203
  if (bgImg) {
29153
29204
  ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
29154
29205
  } else {
@@ -29220,7 +29271,7 @@ function StatusEffect({
29220
29271
  /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsx(
29221
29272
  "img",
29222
29273
  {
29223
- src: assetUrl,
29274
+ src: assetUrl.url,
29224
29275
  alt: label,
29225
29276
  width: sizes.img,
29226
29277
  height: sizes.img,
@@ -29259,7 +29310,11 @@ var init_StatusEffect = __esm({
29259
29310
  "components/game/atoms/StatusEffect.tsx"() {
29260
29311
  init_cn();
29261
29312
  init_Icon();
29262
- DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
29313
+ DEFAULT_ASSET_URL8 = {
29314
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
29315
+ role: "effect",
29316
+ category: "effect"
29317
+ };
29263
29318
  sizeMap13 = {
29264
29319
  sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]", img: 20 },
29265
29320
  md: { container: "w-10 h-10", icon: "text-base", badge: "text-xs -top-1 -right-1 w-5 h-5", timer: "text-xs", img: 28 },
@@ -29550,7 +29605,7 @@ function TurnIndicator({
29550
29605
  assetUrl ? /* @__PURE__ */ jsx(
29551
29606
  "img",
29552
29607
  {
29553
- src: assetUrl,
29608
+ src: assetUrl.url,
29554
29609
  alt: "",
29555
29610
  width: 12,
29556
29611
  height: 12,
@@ -29573,7 +29628,11 @@ var init_TurnIndicator = __esm({
29573
29628
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
29574
29629
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
29575
29630
  };
29576
- DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
29631
+ DEFAULT_ASSET_URL9 = {
29632
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
29633
+ role: "effect",
29634
+ category: "effect"
29635
+ };
29577
29636
  TurnIndicator.displayName = "TurnIndicator";
29578
29637
  }
29579
29638
  });
@@ -29667,7 +29726,7 @@ function EnemyPlate({
29667
29726
  assetUrl && /* @__PURE__ */ jsx(
29668
29727
  "img",
29669
29728
  {
29670
- src: assetUrl,
29729
+ src: assetUrl.url,
29671
29730
  alt: name,
29672
29731
  width: 24,
29673
29732
  height: 24,
@@ -30009,7 +30068,7 @@ function DialogueBox({
30009
30068
  "div",
30010
30069
  {
30011
30070
  className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
30012
- style: { backgroundImage: `url(${backgroundImage})` },
30071
+ style: { backgroundImage: `url(${backgroundImage?.url})` },
30013
30072
  "aria-hidden": "true"
30014
30073
  }
30015
30074
  ),
@@ -30024,7 +30083,7 @@ function DialogueBox({
30024
30083
  children: /* @__PURE__ */ jsx(
30025
30084
  "img",
30026
30085
  {
30027
- src: portraitUrl,
30086
+ src: portraitUrl?.url,
30028
30087
  alt: dialogue.speaker,
30029
30088
  className: "h-full w-auto object-contain drop-shadow-2xl"
30030
30089
  }
@@ -41741,7 +41800,7 @@ var init_DetailPanel = __esm({
41741
41800
  function DialogueBubble({
41742
41801
  speaker = "Hero",
41743
41802
  text = "The dungeon awaits. Choose your path wisely.",
41744
- portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
41803
+ portrait = DEFAULT_PORTRAIT,
41745
41804
  position = "bottom",
41746
41805
  className
41747
41806
  }) {
@@ -41757,7 +41816,7 @@ function DialogueBubble({
41757
41816
  portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsx(
41758
41817
  "img",
41759
41818
  {
41760
- src: portrait,
41819
+ src: portrait?.url,
41761
41820
  alt: speaker ?? "speaker",
41762
41821
  className: "w-full h-full object-cover"
41763
41822
  }
@@ -41770,9 +41829,15 @@ function DialogueBubble({
41770
41829
  }
41771
41830
  );
41772
41831
  }
41832
+ var DEFAULT_PORTRAIT;
41773
41833
  var init_DialogueBubble = __esm({
41774
41834
  "components/game/atoms/DialogueBubble.tsx"() {
41775
41835
  init_cn();
41836
+ DEFAULT_PORTRAIT = {
41837
+ url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
41838
+ role: "effect",
41839
+ category: "character"
41840
+ };
41776
41841
  DialogueBubble.displayName = "DialogueBubble";
41777
41842
  }
41778
41843
  });
@@ -41848,7 +41913,7 @@ function StateIndicator({
41848
41913
  /* @__PURE__ */ jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsx(
41849
41914
  "img",
41850
41915
  {
41851
- src: assetUrl,
41916
+ src: assetUrl.url,
41852
41917
  alt: displayLabel,
41853
41918
  width: 16,
41854
41919
  height: 16,
@@ -41867,7 +41932,11 @@ var init_StateIndicator = __esm({
41867
41932
  init_Box();
41868
41933
  init_Icon();
41869
41934
  init_cn();
41870
- DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
41935
+ DEFAULT_ASSET_URL10 = {
41936
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
41937
+ role: "effect",
41938
+ category: "item"
41939
+ };
41871
41940
  DEFAULT_STATE_STYLES = {
41872
41941
  idle: { icon: "\u23F8", bgClass: "bg-muted" },
41873
41942
  active: { icon: "\u25B6", bgClass: "bg-success" },
@@ -42673,7 +42742,6 @@ var init_FeatureGridOrganism = __esm({
42673
42742
  });
42674
42743
  function FishingBoard({
42675
42744
  backgroundImage,
42676
- assetBaseUrl,
42677
42745
  scale = 1,
42678
42746
  showMinimap = false,
42679
42747
  enableCamera = true,
@@ -42691,8 +42759,7 @@ function FishingBoard({
42691
42759
  {
42692
42760
  width,
42693
42761
  height,
42694
- backgroundImage: backgroundImage ?? "",
42695
- assetBaseUrl,
42762
+ backgroundImage,
42696
42763
  fps: 60,
42697
42764
  className: "w-full h-full"
42698
42765
  }
@@ -44918,7 +44985,7 @@ var init_GameCanvas3D2 = __esm({
44918
44985
  children: /* @__PURE__ */ jsx(
44919
44986
  ModelLoader,
44920
44987
  {
44921
- url: tile.modelUrl,
44988
+ url: tile.modelUrl.url,
44922
44989
  scale: 0.95,
44923
44990
  fallbackGeometry: "box",
44924
44991
  castShadow: true,
@@ -44983,7 +45050,7 @@ var init_GameCanvas3D2 = __esm({
44983
45050
  /* @__PURE__ */ jsx(
44984
45051
  ModelLoader,
44985
45052
  {
44986
- url: unit.modelUrl,
45053
+ url: unit.modelUrl.url,
44987
45054
  scale: modelScale,
44988
45055
  fallbackGeometry: "box",
44989
45056
  castShadow: true
@@ -45043,7 +45110,7 @@ var init_GameCanvas3D2 = __esm({
45043
45110
  return /* @__PURE__ */ jsx(
45044
45111
  ModelLoader,
45045
45112
  {
45046
- url: feature.assetUrl,
45113
+ url: feature.assetUrl.url,
45047
45114
  position,
45048
45115
  scale: 0.5,
45049
45116
  rotation: [0, feature.rotation ?? 0, 0],
@@ -45264,7 +45331,18 @@ function GameBoard3D({
45264
45331
  const row = boardEntity(entity);
45265
45332
  const eventBus = useEventBus();
45266
45333
  const entityUnits = row ? rows(row.units) : [];
45267
- const units = entityUnits;
45334
+ const units = entityUnits.map((r) => ({
45335
+ id: str(r.id),
45336
+ x: num(r.x),
45337
+ y: num(r.y),
45338
+ z: num(r.z),
45339
+ faction: str(r.faction) || "neutral",
45340
+ team: str(r.team) || str(r.faction) || "neutral",
45341
+ unitType: r.unitType == null ? void 0 : str(r.unitType),
45342
+ name: r.name == null ? void 0 : str(r.name),
45343
+ health: r.health == null ? void 0 : num(r.health),
45344
+ maxHealth: r.maxHealth == null ? void 0 : num(r.maxHealth)
45345
+ }));
45268
45346
  const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
45269
45347
  const phase = row ? str(row.phase) : "observation";
45270
45348
  const result = row ? str(row.result) : "none";
@@ -45443,22 +45521,27 @@ function resolveDescriptor(value, idPrefix) {
45443
45521
  }
45444
45522
  if (typeof value === "object" && value !== null) {
45445
45523
  const desc = asDescriptor(value);
45446
- if (desc !== null && getComponentForPattern(desc.type) !== null) {
45524
+ const hasComp = desc !== null && getComponentForPattern(desc.type) !== null;
45525
+ shellLog.debug("resolve", { idPrefix, type: desc?.type ?? null, hasDesc: desc !== null, render: hasComp });
45526
+ if (hasComp) {
45447
45527
  const resolvedProps = desc.props ?? {};
45448
45528
  const content = { id: desc._id ?? idPrefix, pattern: desc.type, props: resolvedProps, priority: 0 };
45449
45529
  const SCR = getSlotContentRenderer();
45450
- return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 });
45530
+ return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 }, content.id);
45451
45531
  }
45532
+ } else {
45533
+ shellLog.debug("resolve", { idPrefix, type: null, hasDesc: false, render: false, branch: typeof value });
45452
45534
  }
45453
45535
  return null;
45454
45536
  }
45455
- var _scr, GameShell;
45537
+ var shellLog, _scr, GameShell;
45456
45538
  var init_GameShell = __esm({
45457
45539
  "components/game/templates/GameShell.tsx"() {
45458
45540
  init_cn();
45459
45541
  init_Box();
45460
45542
  init_Stack();
45461
45543
  init_Typography();
45544
+ shellLog = createLogger("almadar:ui:game:game-shell");
45462
45545
  _scr = null;
45463
45546
  GameShell = ({
45464
45547
  appName = "Game",
@@ -45859,7 +45942,6 @@ function HexStrategyBoard({
45859
45942
  units,
45860
45943
  features,
45861
45944
  assetManifest,
45862
- assetBaseUrl,
45863
45945
  scale,
45864
45946
  showMinimap,
45865
45947
  enableCamera,
@@ -45901,7 +45983,6 @@ function HolidayRunnerBoard({
45901
45983
  units,
45902
45984
  features,
45903
45985
  assetManifest,
45904
- assetBaseUrl,
45905
45986
  scale,
45906
45987
  showMinimap,
45907
45988
  enableCamera,
@@ -46696,7 +46777,6 @@ function MatchPuzzleBoard({
46696
46777
  units,
46697
46778
  features,
46698
46779
  assetManifest,
46699
- assetBaseUrl,
46700
46780
  scale,
46701
46781
  showMinimap,
46702
46782
  enableCamera,
@@ -46957,7 +47037,6 @@ function MinigolfBoard({
46957
47037
  units,
46958
47038
  features,
46959
47039
  assetManifest,
46960
- assetBaseUrl,
46961
47040
  scale,
46962
47041
  showMinimap,
46963
47042
  enableCamera,
@@ -47263,7 +47342,6 @@ function PirateBoard({
47263
47342
  units,
47264
47343
  features,
47265
47344
  assetManifest,
47266
- assetBaseUrl,
47267
47345
  scale,
47268
47346
  showMinimap,
47269
47347
  enableCamera,
@@ -47384,8 +47462,8 @@ function PlatformerBoard({
47384
47462
  canvasHeight,
47385
47463
  followCamera: true,
47386
47464
  bgColor,
47387
- playerSprite,
47388
- tileSprites,
47465
+ playerSprite: playerSprite?.url,
47466
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
47389
47467
  leftEvent,
47390
47468
  rightEvent,
47391
47469
  jumpEvent,
@@ -47450,7 +47528,7 @@ function PlatformerTemplate({
47450
47528
  worldHeight = 400,
47451
47529
  canvasWidth = 800,
47452
47530
  canvasHeight = 400,
47453
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
47531
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
47454
47532
  tileSprites = DEFAULT_TILE_SPRITES,
47455
47533
  bgColor = "#5c94fc",
47456
47534
  gameEndEvent = "GAME_END",
@@ -47503,13 +47581,14 @@ var init_PlatformerTemplate = __esm({
47503
47581
  init_PlatformerBoard();
47504
47582
  init_GameHud();
47505
47583
  init_ScoreBoard();
47584
+ init_makeAsset();
47506
47585
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
47507
- DEFAULT_TILE_SPRITES = {
47586
+ DEFAULT_TILE_SPRITES = makeAssetMap({
47508
47587
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
47509
47588
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
47510
47589
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
47511
47590
  goal: `${CDN3}/tiles/platformPack_tile007.png`
47512
- };
47591
+ }, "tile");
47513
47592
  DEFAULT_PLATFORMS = [
47514
47593
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
47515
47594
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -47665,7 +47744,6 @@ function RacingBoard({
47665
47744
  units,
47666
47745
  features,
47667
47746
  assetManifest,
47668
- assetBaseUrl,
47669
47747
  scale,
47670
47748
  showMinimap,
47671
47749
  enableCamera,
@@ -47708,7 +47786,7 @@ function ResourceCounter({
47708
47786
  assetUrl ? /* @__PURE__ */ jsx(
47709
47787
  "img",
47710
47788
  {
47711
- src: assetUrl,
47789
+ src: assetUrl.url,
47712
47790
  alt: label,
47713
47791
  width: sizes.img,
47714
47792
  height: sizes.img,
@@ -47741,7 +47819,11 @@ var init_ResourceCounter = __esm({
47741
47819
  error: "text-error",
47742
47820
  muted: "text-muted-foreground"
47743
47821
  };
47744
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
47822
+ DEFAULT_ASSET_URL11 = {
47823
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
47824
+ role: "effect",
47825
+ category: "world"
47826
+ };
47745
47827
  sizeMap16 = {
47746
47828
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
47747
47829
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -47750,27 +47832,18 @@ var init_ResourceCounter = __esm({
47750
47832
  ResourceCounter.displayName = "ResourceCounter";
47751
47833
  }
47752
47834
  });
47753
- function resolveManifestUrl3(manifest, relative) {
47754
- if (relative == null) return void 0;
47755
- if (/^https?:\/\//.test(relative)) return relative;
47756
- const base = manifest?.baseUrl;
47757
- if (base == null) return relative;
47758
- const cleanBase = base.replace(/\/$/, "");
47759
- const cleanRel = relative.replace(/^\//, "");
47760
- return `${cleanBase}/${cleanRel}`;
47761
- }
47762
47835
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
47763
47836
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
47764
47837
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
47765
47838
  const isWall = isBorder || isPillar;
47766
47839
  const terrains = manifest?.terrains;
47767
47840
  if (x === stairsX && y === stairsY) {
47768
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
47841
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
47769
47842
  }
47770
47843
  if (isWall) {
47771
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
47844
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
47772
47845
  }
47773
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
47846
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
47774
47847
  }
47775
47848
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
47776
47849
  const tiles = [];
@@ -47814,7 +47887,7 @@ function RoguelikeBoard({
47814
47887
  x: num(r.x),
47815
47888
  y: num(r.y),
47816
47889
  terrain: r.terrain == null ? void 0 : str(r.terrain),
47817
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
47890
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
47818
47891
  passable: r.passable !== false
47819
47892
  })),
47820
47893
  [board.tiles]
@@ -47894,7 +47967,7 @@ function RoguelikeBoard({
47894
47967
  health: playerHp,
47895
47968
  maxHealth: playerMaxHp,
47896
47969
  unitType: "player",
47897
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
47970
+ sprite: assetManifest?.units?.player
47898
47971
  },
47899
47972
  ...liveEnemies.map((e) => ({
47900
47973
  id: e.id,
@@ -47904,7 +47977,7 @@ function RoguelikeBoard({
47904
47977
  health: e.hp,
47905
47978
  maxHealth: 6,
47906
47979
  unitType: "enemy",
47907
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
47980
+ sprite: assetManifest?.units?.enemy
47908
47981
  }))
47909
47982
  ];
47910
47983
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -47914,7 +47987,7 @@ function RoguelikeBoard({
47914
47987
  x: it.x,
47915
47988
  y: it.y,
47916
47989
  type: it.kind,
47917
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
47990
+ sprite: assetManifest?.features?.[it.kind]
47918
47991
  })),
47919
47992
  [items, assetManifest]
47920
47993
  );
@@ -47975,7 +48048,6 @@ function RoguelikeBoard({
47975
48048
  onTileHover: (x, y) => setHoveredTile({ x, y }),
47976
48049
  onTileLeave: () => setHoveredTile(null),
47977
48050
  scale,
47978
- assetBaseUrl: assetManifest?.baseUrl,
47979
48051
  assetManifest,
47980
48052
  unitScale,
47981
48053
  spriteHeightRatio,
@@ -48035,6 +48107,7 @@ var init_RoguelikeBoard = __esm({
48035
48107
  init_Stack();
48036
48108
  init_IsometricCanvas();
48037
48109
  init_boardEntity();
48110
+ init_makeAsset();
48038
48111
  DUNGEON_GRID_W = 16;
48039
48112
  DUNGEON_GRID_H = 16;
48040
48113
  DEFAULT_ENEMIES = [
@@ -48085,55 +48158,59 @@ function RoguelikeTemplate({
48085
48158
  }
48086
48159
  );
48087
48160
  }
48088
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
48161
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
48089
48162
  var init_RoguelikeTemplate = __esm({
48090
48163
  "components/game/templates/RoguelikeTemplate.tsx"() {
48091
48164
  init_RoguelikeBoard();
48165
+ init_makeAsset();
48092
48166
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
48167
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
48168
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
48169
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
48170
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
48093
48171
  DEFAULT_ROGUELIKE_TILES = [
48094
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48095
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48096
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48097
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48098
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48099
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48100
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48101
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48102
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48103
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48104
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48105
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48106
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48107
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48108
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48109
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48110
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
48111
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
48112
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
48113
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48114
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48115
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48116
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48117
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
48118
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
48172
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48173
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48174
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48175
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48176
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48177
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
48178
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
48179
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
48180
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
48181
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
48182
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
48183
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
48184
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
48185
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
48186
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
48187
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
48188
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
48189
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
48190
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
48191
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
48192
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
48193
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
48194
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
48195
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
48196
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
48119
48197
  ];
48120
48198
  DEFAULT_ROGUELIKE_MANIFEST = {
48121
- baseUrl: CDN4,
48122
- terrains: {
48123
- floor: "/isometric-dungeon/Isometric/dirt_E.png",
48124
- wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
48125
- stairs: "/isometric-dungeon/Isometric/stairs_E.png",
48126
- planks: "/isometric-dungeon/Isometric/planks_E.png"
48127
- },
48199
+ terrains: makeAssetMap({
48200
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
48201
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
48202
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
48203
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
48204
+ }, "tile"),
48128
48205
  units: {
48129
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
48130
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
48206
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
48207
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
48131
48208
  },
48132
- features: {
48133
- health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
48134
- sword: "/isometric-dungeon/Isometric/barrel_E.png",
48135
- shield: "/isometric-dungeon/Isometric/barrel_E.png"
48136
- }
48209
+ features: makeAssetMap({
48210
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
48211
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
48212
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
48213
+ }, "item")
48137
48214
  };
48138
48215
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
48139
48216
  }
@@ -50988,7 +51065,6 @@ function SokobanBoard({
50988
51065
  units,
50989
51066
  features,
50990
51067
  assetManifest,
50991
- assetBaseUrl,
50992
51068
  scale,
50993
51069
  showMinimap,
50994
51070
  enableCamera,
@@ -51030,7 +51106,6 @@ function SpaceShmupBoard({
51030
51106
  units,
51031
51107
  features,
51032
51108
  assetManifest,
51033
- assetBaseUrl,
51034
51109
  scale,
51035
51110
  showMinimap,
51036
51111
  enableCamera,
@@ -51072,7 +51147,6 @@ function SpaceStationBoard({
51072
51147
  units,
51073
51148
  features,
51074
51149
  assetManifest,
51075
- assetBaseUrl,
51076
51150
  scale,
51077
51151
  showMinimap,
51078
51152
  enableCamera,
@@ -51207,7 +51281,6 @@ function SportsBoard({
51207
51281
  units,
51208
51282
  features,
51209
51283
  assetManifest,
51210
- assetBaseUrl,
51211
51284
  scale,
51212
51285
  showMinimap,
51213
51286
  enableCamera,
@@ -51227,7 +51300,7 @@ var init_SportsBoard = __esm({
51227
51300
  }
51228
51301
  });
51229
51302
  function Sprite({
51230
- spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
51303
+ spritesheet = DEFAULT_SPRITESHEET,
51231
51304
  frameWidth = 64,
51232
51305
  frameHeight = 64,
51233
51306
  frame = 0,
@@ -51280,7 +51353,7 @@ function Sprite({
51280
51353
  position: "absolute",
51281
51354
  width: frameWidth,
51282
51355
  height: frameHeight,
51283
- backgroundImage: `url(${spritesheet})`,
51356
+ backgroundImage: `url(${spritesheet.url})`,
51284
51357
  backgroundPosition,
51285
51358
  backgroundRepeat: "no-repeat",
51286
51359
  imageRendering: "pixelated",
@@ -51328,11 +51401,17 @@ function drawSprite(ctx, image, props) {
51328
51401
  );
51329
51402
  ctx.restore();
51330
51403
  }
51404
+ var DEFAULT_SPRITESHEET;
51331
51405
  var init_Sprite = __esm({
51332
51406
  "components/game/atoms/Sprite.tsx"() {
51333
51407
  "use client";
51334
51408
  init_useEventBus();
51335
51409
  init_spriteAnimation();
51410
+ DEFAULT_SPRITESHEET = {
51411
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
51412
+ role: "tile",
51413
+ category: "tile"
51414
+ };
51336
51415
  }
51337
51416
  });
51338
51417
  var StatCard;
@@ -53160,7 +53239,6 @@ function TanksBoard({
53160
53239
  units,
53161
53240
  features,
53162
53241
  assetManifest,
53163
- assetBaseUrl,
53164
53242
  scale,
53165
53243
  showMinimap,
53166
53244
  enableCamera,
@@ -53488,15 +53566,6 @@ var init_ToastSlot = __esm({
53488
53566
  ToastSlot.displayName = "ToastSlot";
53489
53567
  }
53490
53568
  });
53491
- function resolveManifestUrl4(manifest, relative) {
53492
- if (relative == null || relative === "") return void 0;
53493
- if (/^https?:\/\//.test(relative)) return relative;
53494
- const base = manifest?.baseUrl;
53495
- if (base == null) return relative;
53496
- const cleanBase = base.replace(/\/$/, "");
53497
- const cleanRel = relative.replace(/^\//, "");
53498
- return `${cleanBase}/${cleanRel}`;
53499
- }
53500
53569
  function readPlayer(v) {
53501
53570
  if (v == null || typeof v !== "object") return void 0;
53502
53571
  const o = v;
@@ -53549,10 +53618,10 @@ function TopDownShooterBoard({
53549
53618
  const wave = propWave ?? num(board.wave, 1);
53550
53619
  const lives = propLives ?? num(board.lives, 3);
53551
53620
  const result = propResult ?? (str(board.result) || "none");
53552
- const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
53553
- const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
53554
- const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
53555
- const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
53621
+ const playerSprite = assetManifest?.units?.player?.url;
53622
+ const enemySprite = assetManifest?.units?.enemy?.url;
53623
+ const projectileSprite = assetManifest?.features?.projectile?.url;
53624
+ const backgroundSprite = assetManifest?.background;
53556
53625
  const spriteUrls = useMemo(
53557
53626
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
53558
53627
  [playerSprite, enemySprite, projectileSprite]
@@ -53719,7 +53788,6 @@ function TopDownShooterBoard({
53719
53788
  width,
53720
53789
  height,
53721
53790
  backgroundImage: backgroundSprite,
53722
- assetBaseUrl: assetManifest?.baseUrl,
53723
53791
  onDraw
53724
53792
  }
53725
53793
  ),
@@ -53844,15 +53912,6 @@ var init_TopDownShooterTemplate = __esm({
53844
53912
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
53845
53913
  }
53846
53914
  });
53847
- function resolveManifestUrl5(manifest, relative) {
53848
- if (relative == null) return void 0;
53849
- if (/^https?:\/\//.test(relative)) return relative;
53850
- const base = manifest?.baseUrl;
53851
- if (base == null) return relative;
53852
- const cleanBase = base.replace(/\/$/, "");
53853
- const cleanRel = relative.replace(/^\//, "");
53854
- return `${cleanBase}/${cleanRel}`;
53855
- }
53856
53915
  function buildDefaultTDTiles() {
53857
53916
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
53858
53917
  const tiles = [];
@@ -53872,18 +53931,18 @@ function buildDefaultTDTiles() {
53872
53931
  function tilesToIso2(tiles, manifest) {
53873
53932
  return tiles.map((t) => {
53874
53933
  const key = t.terrain ?? "ground";
53875
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
53934
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
53876
53935
  return {
53877
53936
  x: t.x,
53878
53937
  y: t.y,
53879
53938
  terrain: t.terrain,
53880
- terrainSprite: sprite,
53939
+ terrainSprite,
53881
53940
  passable: t.passable
53882
53941
  };
53883
53942
  });
53884
53943
  }
53885
53944
  function creepsToUnits(creeps, manifest) {
53886
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
53945
+ const sprite = manifest?.units?.creep;
53887
53946
  return creeps.map((c) => ({
53888
53947
  id: c.id,
53889
53948
  position: { x: c.x, y: c.y },
@@ -53901,14 +53960,14 @@ function heroToUnit(hero, manifest) {
53901
53960
  position: { x: hero.x, y: hero.y },
53902
53961
  name: "Hero",
53903
53962
  team: "player",
53904
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
53963
+ sprite: manifest?.units?.hero,
53905
53964
  unitType: "hero",
53906
53965
  health: 1,
53907
53966
  maxHealth: 1
53908
53967
  };
53909
53968
  }
53910
53969
  function towersToFeatures(towers, manifest) {
53911
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
53970
+ const sprite = manifest?.features?.tower;
53912
53971
  return towers.map((t) => ({
53913
53972
  id: t.id,
53914
53973
  x: t.x,
@@ -54106,7 +54165,6 @@ function TowerDefenseBoard({
54106
54165
  tiles: isoTiles,
54107
54166
  units: isoUnits,
54108
54167
  features: towerFeatures,
54109
- assetBaseUrl: assetManifest?.baseUrl,
54110
54168
  assetManifest,
54111
54169
  validMoves,
54112
54170
  hoveredTile,
@@ -54150,6 +54208,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
54150
54208
  var init_TowerDefenseBoard = __esm({
54151
54209
  "components/game/organisms/TowerDefenseBoard.tsx"() {
54152
54210
  "use client";
54211
+ init_makeAsset();
54153
54212
  init_cn();
54154
54213
  init_useEventBus();
54155
54214
  init_Box();
@@ -54479,15 +54538,6 @@ var init_UncontrolledBattleBoard = __esm({
54479
54538
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
54480
54539
  }
54481
54540
  });
54482
- function resolveManifestUrl6(manifest, relative) {
54483
- if (relative == null) return void 0;
54484
- if (/^https?:\/\//.test(relative)) return relative;
54485
- const base = manifest?.baseUrl;
54486
- if (base == null) return relative;
54487
- const cleanBase = base.replace(/\/$/, "");
54488
- const cleanRel = relative.replace(/^\//, "");
54489
- return `${cleanBase}/${cleanRel}`;
54490
- }
54491
54541
  function VisualNovelBoard({
54492
54542
  entity,
54493
54543
  nodes: propNodes,
@@ -54522,11 +54572,11 @@ function VisualNovelBoard({
54522
54572
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
54523
54573
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
54524
54574
  const backgroundImage = useMemo(
54525
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
54575
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
54526
54576
  [assetManifest, currentNode?.backgroundKey]
54527
54577
  );
54528
54578
  const portraitUrl = useMemo(
54529
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
54579
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
54530
54580
  [assetManifest, currentNode?.portraitKey]
54531
54581
  );
54532
54582
  const dialogueChoices = useMemo(
@@ -54700,7 +54750,7 @@ function buildDefaultWorldTiles() {
54700
54750
  for (let x = 0; x < WORLD_GRID_W; x++) {
54701
54751
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
54702
54752
  const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
54703
- tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
54753
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
54704
54754
  }
54705
54755
  }
54706
54756
  return tiles;
@@ -54744,7 +54794,12 @@ function WorldMapBoard({
54744
54794
  const resolved = boardEntity(entity);
54745
54795
  const entityUnits = rows(resolved?.units);
54746
54796
  const entityTiles = rows(resolved?.tiles);
54747
- const features = propFeatures ?? rows(resolved?.features);
54797
+ const features = propFeatures ?? rows(resolved?.features).map((r) => ({
54798
+ id: r.id == null ? void 0 : str(r.id),
54799
+ x: num(r.x),
54800
+ y: num(r.y),
54801
+ type: str(r.type)
54802
+ }));
54748
54803
  const selectedHeroId = resolved?.selectedHeroId ?? null;
54749
54804
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
54750
54805
  const backgroundImage = resolved?.backgroundImage;
@@ -54754,7 +54809,7 @@ function WorldMapBoard({
54754
54809
  x: num(t.x),
54755
54810
  y: num(t.y),
54756
54811
  terrain: str(t.terrain),
54757
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
54812
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
54758
54813
  passable: t.passable !== false
54759
54814
  })),
54760
54815
  [entityTiles]
@@ -54770,7 +54825,7 @@ function WorldMapBoard({
54770
54825
  team: str(u.team) === "enemy" ? "enemy" : "player",
54771
54826
  health: num(u.health) || 100,
54772
54827
  maxHealth: num(u.maxHealth) || 100,
54773
- sprite: u.sprite == null ? void 0 : str(u.sprite)
54828
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
54774
54829
  })),
54775
54830
  [entityUnits, propUnits]
54776
54831
  );
@@ -54952,7 +55007,6 @@ function WorldMapBoard({
54952
55007
  onTileHover: (x, y) => setHoveredTile({ x, y }),
54953
55008
  onTileLeave: () => setHoveredTile(null),
54954
55009
  scale,
54955
- assetBaseUrl: assetManifest?.baseUrl,
54956
55010
  assetManifest,
54957
55011
  backgroundImage,
54958
55012
  effectSpriteUrls,
@@ -54975,6 +55029,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
54975
55029
  var init_WorldMapBoard = __esm({
54976
55030
  "components/game/organisms/WorldMapBoard.tsx"() {
54977
55031
  "use client";
55032
+ init_makeAsset();
54978
55033
  init_cn();
54979
55034
  init_useEventBus();
54980
55035
  init_Stack();
@@ -55028,62 +55083,66 @@ function WorldMapTemplate({
55028
55083
  }
55029
55084
  );
55030
55085
  }
55031
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
55086
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
55032
55087
  var init_WorldMapTemplate = __esm({
55033
55088
  "components/game/templates/WorldMapTemplate.tsx"() {
55034
55089
  init_WorldMapBoard();
55090
+ init_makeAsset();
55035
55091
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
55092
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
55093
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
55094
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
55095
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
55036
55096
  DEFAULT_WORLDMAP_TILES = [
55037
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55038
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55039
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
55040
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55041
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55042
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55043
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
55044
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
55045
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
55046
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
55047
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
55048
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
55049
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
55050
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
55051
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55052
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55053
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
55054
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
55055
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
55056
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55057
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55058
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
55059
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
55060
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
55061
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
55097
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
55098
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
55099
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
55100
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
55101
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
55102
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
55103
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
55104
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
55105
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
55106
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
55107
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
55108
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
55109
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
55110
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
55111
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
55112
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
55113
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
55114
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
55115
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
55116
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
55117
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
55118
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
55119
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
55120
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
55121
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
55062
55122
  ];
55063
55123
  DEFAULT_WORLDMAP_UNITS = [
55064
- { id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${CDN5}/sprite-sheets/amir-sprite-sheet-se.png` },
55065
- { id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png` }
55124
+ { id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player") },
55125
+ { id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc") }
55066
55126
  ];
55067
55127
  DEFAULT_WORLDMAP_FEATURES = [
55068
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
55069
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
55128
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
55129
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
55070
55130
  ];
55071
55131
  DEFAULT_WORLDMAP_MANIFEST = {
55072
- baseUrl: CDN5,
55073
- terrains: {
55074
- grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
55075
- water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
55076
- mountain: "/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png",
55077
- road: "/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png"
55078
- },
55132
+ terrains: makeAssetMap({
55133
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
55134
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
55135
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
55136
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
55137
+ }, "tile"),
55079
55138
  units: {
55080
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
55081
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
55139
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
55140
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
55082
55141
  },
55083
- features: {
55084
- capital: "/scenes/world/capital.png",
55085
- power_node: "/world-map/power_node.png"
55086
- }
55142
+ features: makeAssetMap({
55143
+ capital: `${CDN5}/scenes/world/capital.png`,
55144
+ power_node: `${CDN5}/world-map/power_node.png`
55145
+ }, "decoration")
55087
55146
  };
55088
55147
  WorldMapTemplate.displayName = "WorldMapTemplate";
55089
55148
  }