@almadar/ui 5.72.0 → 5.73.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 +402 -362
  2. package/dist/avl/index.js +402 -362
  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 +417 -363
  47. package/dist/components/index.js +417 -363
  48. package/dist/providers/index.cjs +402 -362
  49. package/dist/providers/index.js +402 -362
  50. package/dist/runtime/index.cjs +402 -362
  51. package/dist/runtime/index.js +402 -362
  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";
@@ -45859,7 +45937,6 @@ function HexStrategyBoard({
45859
45937
  units,
45860
45938
  features,
45861
45939
  assetManifest,
45862
- assetBaseUrl,
45863
45940
  scale,
45864
45941
  showMinimap,
45865
45942
  enableCamera,
@@ -45901,7 +45978,6 @@ function HolidayRunnerBoard({
45901
45978
  units,
45902
45979
  features,
45903
45980
  assetManifest,
45904
- assetBaseUrl,
45905
45981
  scale,
45906
45982
  showMinimap,
45907
45983
  enableCamera,
@@ -46696,7 +46772,6 @@ function MatchPuzzleBoard({
46696
46772
  units,
46697
46773
  features,
46698
46774
  assetManifest,
46699
- assetBaseUrl,
46700
46775
  scale,
46701
46776
  showMinimap,
46702
46777
  enableCamera,
@@ -46957,7 +47032,6 @@ function MinigolfBoard({
46957
47032
  units,
46958
47033
  features,
46959
47034
  assetManifest,
46960
- assetBaseUrl,
46961
47035
  scale,
46962
47036
  showMinimap,
46963
47037
  enableCamera,
@@ -47263,7 +47337,6 @@ function PirateBoard({
47263
47337
  units,
47264
47338
  features,
47265
47339
  assetManifest,
47266
- assetBaseUrl,
47267
47340
  scale,
47268
47341
  showMinimap,
47269
47342
  enableCamera,
@@ -47384,8 +47457,8 @@ function PlatformerBoard({
47384
47457
  canvasHeight,
47385
47458
  followCamera: true,
47386
47459
  bgColor,
47387
- playerSprite,
47388
- tileSprites,
47460
+ playerSprite: playerSprite?.url,
47461
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
47389
47462
  leftEvent,
47390
47463
  rightEvent,
47391
47464
  jumpEvent,
@@ -47450,7 +47523,7 @@ function PlatformerTemplate({
47450
47523
  worldHeight = 400,
47451
47524
  canvasWidth = 800,
47452
47525
  canvasHeight = 400,
47453
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
47526
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
47454
47527
  tileSprites = DEFAULT_TILE_SPRITES,
47455
47528
  bgColor = "#5c94fc",
47456
47529
  gameEndEvent = "GAME_END",
@@ -47503,13 +47576,14 @@ var init_PlatformerTemplate = __esm({
47503
47576
  init_PlatformerBoard();
47504
47577
  init_GameHud();
47505
47578
  init_ScoreBoard();
47579
+ init_makeAsset();
47506
47580
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
47507
- DEFAULT_TILE_SPRITES = {
47581
+ DEFAULT_TILE_SPRITES = makeAssetMap({
47508
47582
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
47509
47583
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
47510
47584
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
47511
47585
  goal: `${CDN3}/tiles/platformPack_tile007.png`
47512
- };
47586
+ }, "tile");
47513
47587
  DEFAULT_PLATFORMS = [
47514
47588
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
47515
47589
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -47665,7 +47739,6 @@ function RacingBoard({
47665
47739
  units,
47666
47740
  features,
47667
47741
  assetManifest,
47668
- assetBaseUrl,
47669
47742
  scale,
47670
47743
  showMinimap,
47671
47744
  enableCamera,
@@ -47708,7 +47781,7 @@ function ResourceCounter({
47708
47781
  assetUrl ? /* @__PURE__ */ jsx(
47709
47782
  "img",
47710
47783
  {
47711
- src: assetUrl,
47784
+ src: assetUrl.url,
47712
47785
  alt: label,
47713
47786
  width: sizes.img,
47714
47787
  height: sizes.img,
@@ -47741,7 +47814,11 @@ var init_ResourceCounter = __esm({
47741
47814
  error: "text-error",
47742
47815
  muted: "text-muted-foreground"
47743
47816
  };
47744
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
47817
+ DEFAULT_ASSET_URL11 = {
47818
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
47819
+ role: "effect",
47820
+ category: "world"
47821
+ };
47745
47822
  sizeMap16 = {
47746
47823
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
47747
47824
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -47750,27 +47827,18 @@ var init_ResourceCounter = __esm({
47750
47827
  ResourceCounter.displayName = "ResourceCounter";
47751
47828
  }
47752
47829
  });
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
47830
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
47763
47831
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
47764
47832
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
47765
47833
  const isWall = isBorder || isPillar;
47766
47834
  const terrains = manifest?.terrains;
47767
47835
  if (x === stairsX && y === stairsY) {
47768
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
47836
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
47769
47837
  }
47770
47838
  if (isWall) {
47771
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
47839
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
47772
47840
  }
47773
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
47841
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
47774
47842
  }
47775
47843
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
47776
47844
  const tiles = [];
@@ -47814,7 +47882,7 @@ function RoguelikeBoard({
47814
47882
  x: num(r.x),
47815
47883
  y: num(r.y),
47816
47884
  terrain: r.terrain == null ? void 0 : str(r.terrain),
47817
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
47885
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
47818
47886
  passable: r.passable !== false
47819
47887
  })),
47820
47888
  [board.tiles]
@@ -47894,7 +47962,7 @@ function RoguelikeBoard({
47894
47962
  health: playerHp,
47895
47963
  maxHealth: playerMaxHp,
47896
47964
  unitType: "player",
47897
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
47965
+ sprite: assetManifest?.units?.player
47898
47966
  },
47899
47967
  ...liveEnemies.map((e) => ({
47900
47968
  id: e.id,
@@ -47904,7 +47972,7 @@ function RoguelikeBoard({
47904
47972
  health: e.hp,
47905
47973
  maxHealth: 6,
47906
47974
  unitType: "enemy",
47907
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
47975
+ sprite: assetManifest?.units?.enemy
47908
47976
  }))
47909
47977
  ];
47910
47978
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -47914,7 +47982,7 @@ function RoguelikeBoard({
47914
47982
  x: it.x,
47915
47983
  y: it.y,
47916
47984
  type: it.kind,
47917
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
47985
+ sprite: assetManifest?.features?.[it.kind]
47918
47986
  })),
47919
47987
  [items, assetManifest]
47920
47988
  );
@@ -47975,7 +48043,6 @@ function RoguelikeBoard({
47975
48043
  onTileHover: (x, y) => setHoveredTile({ x, y }),
47976
48044
  onTileLeave: () => setHoveredTile(null),
47977
48045
  scale,
47978
- assetBaseUrl: assetManifest?.baseUrl,
47979
48046
  assetManifest,
47980
48047
  unitScale,
47981
48048
  spriteHeightRatio,
@@ -48035,6 +48102,7 @@ var init_RoguelikeBoard = __esm({
48035
48102
  init_Stack();
48036
48103
  init_IsometricCanvas();
48037
48104
  init_boardEntity();
48105
+ init_makeAsset();
48038
48106
  DUNGEON_GRID_W = 16;
48039
48107
  DUNGEON_GRID_H = 16;
48040
48108
  DEFAULT_ENEMIES = [
@@ -48085,55 +48153,59 @@ function RoguelikeTemplate({
48085
48153
  }
48086
48154
  );
48087
48155
  }
48088
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
48156
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
48089
48157
  var init_RoguelikeTemplate = __esm({
48090
48158
  "components/game/templates/RoguelikeTemplate.tsx"() {
48091
48159
  init_RoguelikeBoard();
48160
+ init_makeAsset();
48092
48161
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
48162
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
48163
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
48164
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
48165
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
48093
48166
  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` }
48167
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48168
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48169
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48170
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48171
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
48172
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
48173
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
48174
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
48175
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
48176
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
48177
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
48178
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
48179
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
48180
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
48181
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
48182
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
48183
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
48184
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
48185
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
48186
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
48187
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
48188
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
48189
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
48190
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
48191
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
48119
48192
  ];
48120
48193
  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
- },
48194
+ terrains: makeAssetMap({
48195
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
48196
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
48197
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
48198
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
48199
+ }, "tile"),
48128
48200
  units: {
48129
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
48130
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
48201
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
48202
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
48131
48203
  },
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
- }
48204
+ features: makeAssetMap({
48205
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
48206
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
48207
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
48208
+ }, "item")
48137
48209
  };
48138
48210
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
48139
48211
  }
@@ -50988,7 +51060,6 @@ function SokobanBoard({
50988
51060
  units,
50989
51061
  features,
50990
51062
  assetManifest,
50991
- assetBaseUrl,
50992
51063
  scale,
50993
51064
  showMinimap,
50994
51065
  enableCamera,
@@ -51030,7 +51101,6 @@ function SpaceShmupBoard({
51030
51101
  units,
51031
51102
  features,
51032
51103
  assetManifest,
51033
- assetBaseUrl,
51034
51104
  scale,
51035
51105
  showMinimap,
51036
51106
  enableCamera,
@@ -51072,7 +51142,6 @@ function SpaceStationBoard({
51072
51142
  units,
51073
51143
  features,
51074
51144
  assetManifest,
51075
- assetBaseUrl,
51076
51145
  scale,
51077
51146
  showMinimap,
51078
51147
  enableCamera,
@@ -51207,7 +51276,6 @@ function SportsBoard({
51207
51276
  units,
51208
51277
  features,
51209
51278
  assetManifest,
51210
- assetBaseUrl,
51211
51279
  scale,
51212
51280
  showMinimap,
51213
51281
  enableCamera,
@@ -51227,7 +51295,7 @@ var init_SportsBoard = __esm({
51227
51295
  }
51228
51296
  });
51229
51297
  function Sprite({
51230
- spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
51298
+ spritesheet = DEFAULT_SPRITESHEET,
51231
51299
  frameWidth = 64,
51232
51300
  frameHeight = 64,
51233
51301
  frame = 0,
@@ -51280,7 +51348,7 @@ function Sprite({
51280
51348
  position: "absolute",
51281
51349
  width: frameWidth,
51282
51350
  height: frameHeight,
51283
- backgroundImage: `url(${spritesheet})`,
51351
+ backgroundImage: `url(${spritesheet.url})`,
51284
51352
  backgroundPosition,
51285
51353
  backgroundRepeat: "no-repeat",
51286
51354
  imageRendering: "pixelated",
@@ -51328,11 +51396,17 @@ function drawSprite(ctx, image, props) {
51328
51396
  );
51329
51397
  ctx.restore();
51330
51398
  }
51399
+ var DEFAULT_SPRITESHEET;
51331
51400
  var init_Sprite = __esm({
51332
51401
  "components/game/atoms/Sprite.tsx"() {
51333
51402
  "use client";
51334
51403
  init_useEventBus();
51335
51404
  init_spriteAnimation();
51405
+ DEFAULT_SPRITESHEET = {
51406
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
51407
+ role: "tile",
51408
+ category: "tile"
51409
+ };
51336
51410
  }
51337
51411
  });
51338
51412
  var StatCard;
@@ -53160,7 +53234,6 @@ function TanksBoard({
53160
53234
  units,
53161
53235
  features,
53162
53236
  assetManifest,
53163
- assetBaseUrl,
53164
53237
  scale,
53165
53238
  showMinimap,
53166
53239
  enableCamera,
@@ -53488,15 +53561,6 @@ var init_ToastSlot = __esm({
53488
53561
  ToastSlot.displayName = "ToastSlot";
53489
53562
  }
53490
53563
  });
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
53564
  function readPlayer(v) {
53501
53565
  if (v == null || typeof v !== "object") return void 0;
53502
53566
  const o = v;
@@ -53549,10 +53613,10 @@ function TopDownShooterBoard({
53549
53613
  const wave = propWave ?? num(board.wave, 1);
53550
53614
  const lives = propLives ?? num(board.lives, 3);
53551
53615
  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);
53616
+ const playerSprite = assetManifest?.units?.player?.url;
53617
+ const enemySprite = assetManifest?.units?.enemy?.url;
53618
+ const projectileSprite = assetManifest?.features?.projectile?.url;
53619
+ const backgroundSprite = assetManifest?.background;
53556
53620
  const spriteUrls = useMemo(
53557
53621
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
53558
53622
  [playerSprite, enemySprite, projectileSprite]
@@ -53719,7 +53783,6 @@ function TopDownShooterBoard({
53719
53783
  width,
53720
53784
  height,
53721
53785
  backgroundImage: backgroundSprite,
53722
- assetBaseUrl: assetManifest?.baseUrl,
53723
53786
  onDraw
53724
53787
  }
53725
53788
  ),
@@ -53844,15 +53907,6 @@ var init_TopDownShooterTemplate = __esm({
53844
53907
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
53845
53908
  }
53846
53909
  });
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
53910
  function buildDefaultTDTiles() {
53857
53911
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
53858
53912
  const tiles = [];
@@ -53872,18 +53926,18 @@ function buildDefaultTDTiles() {
53872
53926
  function tilesToIso2(tiles, manifest) {
53873
53927
  return tiles.map((t) => {
53874
53928
  const key = t.terrain ?? "ground";
53875
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
53929
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
53876
53930
  return {
53877
53931
  x: t.x,
53878
53932
  y: t.y,
53879
53933
  terrain: t.terrain,
53880
- terrainSprite: sprite,
53934
+ terrainSprite,
53881
53935
  passable: t.passable
53882
53936
  };
53883
53937
  });
53884
53938
  }
53885
53939
  function creepsToUnits(creeps, manifest) {
53886
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
53940
+ const sprite = manifest?.units?.creep;
53887
53941
  return creeps.map((c) => ({
53888
53942
  id: c.id,
53889
53943
  position: { x: c.x, y: c.y },
@@ -53901,14 +53955,14 @@ function heroToUnit(hero, manifest) {
53901
53955
  position: { x: hero.x, y: hero.y },
53902
53956
  name: "Hero",
53903
53957
  team: "player",
53904
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
53958
+ sprite: manifest?.units?.hero,
53905
53959
  unitType: "hero",
53906
53960
  health: 1,
53907
53961
  maxHealth: 1
53908
53962
  };
53909
53963
  }
53910
53964
  function towersToFeatures(towers, manifest) {
53911
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
53965
+ const sprite = manifest?.features?.tower;
53912
53966
  return towers.map((t) => ({
53913
53967
  id: t.id,
53914
53968
  x: t.x,
@@ -54106,7 +54160,6 @@ function TowerDefenseBoard({
54106
54160
  tiles: isoTiles,
54107
54161
  units: isoUnits,
54108
54162
  features: towerFeatures,
54109
- assetBaseUrl: assetManifest?.baseUrl,
54110
54163
  assetManifest,
54111
54164
  validMoves,
54112
54165
  hoveredTile,
@@ -54150,6 +54203,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
54150
54203
  var init_TowerDefenseBoard = __esm({
54151
54204
  "components/game/organisms/TowerDefenseBoard.tsx"() {
54152
54205
  "use client";
54206
+ init_makeAsset();
54153
54207
  init_cn();
54154
54208
  init_useEventBus();
54155
54209
  init_Box();
@@ -54479,15 +54533,6 @@ var init_UncontrolledBattleBoard = __esm({
54479
54533
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
54480
54534
  }
54481
54535
  });
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
54536
  function VisualNovelBoard({
54492
54537
  entity,
54493
54538
  nodes: propNodes,
@@ -54522,11 +54567,11 @@ function VisualNovelBoard({
54522
54567
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
54523
54568
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
54524
54569
  const backgroundImage = useMemo(
54525
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
54570
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
54526
54571
  [assetManifest, currentNode?.backgroundKey]
54527
54572
  );
54528
54573
  const portraitUrl = useMemo(
54529
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
54574
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
54530
54575
  [assetManifest, currentNode?.portraitKey]
54531
54576
  );
54532
54577
  const dialogueChoices = useMemo(
@@ -54700,7 +54745,7 @@ function buildDefaultWorldTiles() {
54700
54745
  for (let x = 0; x < WORLD_GRID_W; x++) {
54701
54746
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
54702
54747
  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 });
54748
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
54704
54749
  }
54705
54750
  }
54706
54751
  return tiles;
@@ -54744,7 +54789,12 @@ function WorldMapBoard({
54744
54789
  const resolved = boardEntity(entity);
54745
54790
  const entityUnits = rows(resolved?.units);
54746
54791
  const entityTiles = rows(resolved?.tiles);
54747
- const features = propFeatures ?? rows(resolved?.features);
54792
+ const features = propFeatures ?? rows(resolved?.features).map((r) => ({
54793
+ id: r.id == null ? void 0 : str(r.id),
54794
+ x: num(r.x),
54795
+ y: num(r.y),
54796
+ type: str(r.type)
54797
+ }));
54748
54798
  const selectedHeroId = resolved?.selectedHeroId ?? null;
54749
54799
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
54750
54800
  const backgroundImage = resolved?.backgroundImage;
@@ -54754,7 +54804,7 @@ function WorldMapBoard({
54754
54804
  x: num(t.x),
54755
54805
  y: num(t.y),
54756
54806
  terrain: str(t.terrain),
54757
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
54807
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
54758
54808
  passable: t.passable !== false
54759
54809
  })),
54760
54810
  [entityTiles]
@@ -54770,7 +54820,7 @@ function WorldMapBoard({
54770
54820
  team: str(u.team) === "enemy" ? "enemy" : "player",
54771
54821
  health: num(u.health) || 100,
54772
54822
  maxHealth: num(u.maxHealth) || 100,
54773
- sprite: u.sprite == null ? void 0 : str(u.sprite)
54823
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
54774
54824
  })),
54775
54825
  [entityUnits, propUnits]
54776
54826
  );
@@ -54952,7 +55002,6 @@ function WorldMapBoard({
54952
55002
  onTileHover: (x, y) => setHoveredTile({ x, y }),
54953
55003
  onTileLeave: () => setHoveredTile(null),
54954
55004
  scale,
54955
- assetBaseUrl: assetManifest?.baseUrl,
54956
55005
  assetManifest,
54957
55006
  backgroundImage,
54958
55007
  effectSpriteUrls,
@@ -54975,6 +55024,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
54975
55024
  var init_WorldMapBoard = __esm({
54976
55025
  "components/game/organisms/WorldMapBoard.tsx"() {
54977
55026
  "use client";
55027
+ init_makeAsset();
54978
55028
  init_cn();
54979
55029
  init_useEventBus();
54980
55030
  init_Stack();
@@ -55028,62 +55078,66 @@ function WorldMapTemplate({
55028
55078
  }
55029
55079
  );
55030
55080
  }
55031
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
55081
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
55032
55082
  var init_WorldMapTemplate = __esm({
55033
55083
  "components/game/templates/WorldMapTemplate.tsx"() {
55034
55084
  init_WorldMapBoard();
55085
+ init_makeAsset();
55035
55086
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
55087
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
55088
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
55089
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
55090
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
55036
55091
  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` }
55092
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
55093
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
55094
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
55095
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
55096
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
55097
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
55098
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
55099
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
55100
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
55101
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
55102
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
55103
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
55104
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
55105
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
55106
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
55107
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
55108
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
55109
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
55110
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
55111
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
55112
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
55113
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
55114
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
55115
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
55116
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
55062
55117
  ];
55063
55118
  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` }
55119
+ { 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") },
55120
+ { 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
55121
  ];
55067
55122
  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` }
55123
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
55124
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
55070
55125
  ];
55071
55126
  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
- },
55127
+ terrains: makeAssetMap({
55128
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
55129
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
55130
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
55131
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
55132
+ }, "tile"),
55079
55133
  units: {
55080
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
55081
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
55134
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
55135
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
55082
55136
  },
55083
- features: {
55084
- capital: "/scenes/world/capital.png",
55085
- power_node: "/world-map/power_node.png"
55086
- }
55137
+ features: makeAssetMap({
55138
+ capital: `${CDN5}/scenes/world/capital.png`,
55139
+ power_node: `${CDN5}/world-map/power_node.png`
55140
+ }, "decoration")
55087
55141
  };
55088
55142
  WorldMapTemplate.displayName = "WorldMapTemplate";
55089
55143
  }