@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
package/dist/avl/index.js CHANGED
@@ -10692,7 +10692,7 @@ function ScoreDisplay({
10692
10692
  assetUrl ? /* @__PURE__ */ jsx(
10693
10693
  "img",
10694
10694
  {
10695
- src: assetUrl,
10695
+ src: assetUrl.url,
10696
10696
  alt: "",
10697
10697
  width: 20,
10698
10698
  height: 20,
@@ -10717,7 +10717,11 @@ var init_ScoreDisplay = __esm({
10717
10717
  lg: "text-2xl",
10718
10718
  xl: "text-4xl"
10719
10719
  };
10720
- DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
10720
+ DEFAULT_ASSET_URL = {
10721
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png",
10722
+ role: "effect",
10723
+ category: "effect"
10724
+ };
10721
10725
  ScoreDisplay.displayName = "ScoreDisplay";
10722
10726
  }
10723
10727
  });
@@ -10793,7 +10797,7 @@ function ControlButton({
10793
10797
  children: assetUrl ? /* @__PURE__ */ jsx(
10794
10798
  "img",
10795
10799
  {
10796
- src: assetUrl,
10800
+ src: assetUrl.url,
10797
10801
  alt: "",
10798
10802
  width: 24,
10799
10803
  height: 24,
@@ -10833,7 +10837,11 @@ var init_ControlButton = __esm({
10833
10837
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
10834
10838
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
10835
10839
  };
10836
- DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
10840
+ DEFAULT_ASSET_URL2 = {
10841
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
10842
+ role: "effect",
10843
+ category: "effect"
10844
+ };
10837
10845
  ControlButton.displayName = "ControlButton";
10838
10846
  }
10839
10847
  });
@@ -10872,7 +10880,7 @@ var init_spriteAnimation = __esm({
10872
10880
  }
10873
10881
  });
10874
10882
  function Sprite({
10875
- spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
10883
+ spritesheet = DEFAULT_SPRITESHEET,
10876
10884
  frameWidth = 64,
10877
10885
  frameHeight = 64,
10878
10886
  frame = 0,
@@ -10925,7 +10933,7 @@ function Sprite({
10925
10933
  position: "absolute",
10926
10934
  width: frameWidth,
10927
10935
  height: frameHeight,
10928
- backgroundImage: `url(${spritesheet})`,
10936
+ backgroundImage: `url(${spritesheet.url})`,
10929
10937
  backgroundPosition,
10930
10938
  backgroundRepeat: "no-repeat",
10931
10939
  imageRendering: "pixelated",
@@ -10938,11 +10946,17 @@ function Sprite({
10938
10946
  }
10939
10947
  );
10940
10948
  }
10949
+ var DEFAULT_SPRITESHEET;
10941
10950
  var init_Sprite = __esm({
10942
10951
  "components/game/atoms/Sprite.tsx"() {
10943
10952
  "use client";
10944
10953
  init_useEventBus();
10945
10954
  init_spriteAnimation();
10955
+ DEFAULT_SPRITESHEET = {
10956
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
10957
+ role: "tile",
10958
+ category: "tile"
10959
+ };
10946
10960
  }
10947
10961
  });
10948
10962
  function StateIndicator({
@@ -10972,7 +10986,7 @@ function StateIndicator({
10972
10986
  /* @__PURE__ */ jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsx(
10973
10987
  "img",
10974
10988
  {
10975
- src: assetUrl,
10989
+ src: assetUrl.url,
10976
10990
  alt: displayLabel,
10977
10991
  width: 16,
10978
10992
  height: 16,
@@ -10991,7 +11005,11 @@ var init_StateIndicator = __esm({
10991
11005
  init_Box();
10992
11006
  init_Icon();
10993
11007
  init_cn();
10994
- DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
11008
+ DEFAULT_ASSET_URL3 = {
11009
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
11010
+ role: "effect",
11011
+ category: "item"
11012
+ };
10995
11013
  DEFAULT_STATE_STYLES = {
10996
11014
  idle: { icon: "\u23F8", bgClass: "bg-muted" },
10997
11015
  active: { icon: "\u25B6", bgClass: "bg-success" },
@@ -11089,7 +11107,7 @@ function ResourceCounter({
11089
11107
  assetUrl ? /* @__PURE__ */ jsx(
11090
11108
  "img",
11091
11109
  {
11092
- src: assetUrl,
11110
+ src: assetUrl.url,
11093
11111
  alt: label,
11094
11112
  width: sizes.img,
11095
11113
  height: sizes.img,
@@ -11122,7 +11140,11 @@ var init_ResourceCounter = __esm({
11122
11140
  error: "text-error",
11123
11141
  muted: "text-muted-foreground"
11124
11142
  };
11125
- DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
11143
+ DEFAULT_ASSET_URL4 = {
11144
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
11145
+ role: "effect",
11146
+ category: "world"
11147
+ };
11126
11148
  sizeMap5 = {
11127
11149
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
11128
11150
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -11168,7 +11190,7 @@ function ItemSlot({
11168
11190
  assetUrl ? /* @__PURE__ */ jsx(
11169
11191
  "img",
11170
11192
  {
11171
- src: assetUrl,
11193
+ src: assetUrl?.url,
11172
11194
  alt: label,
11173
11195
  width: px,
11174
11196
  height: px,
@@ -11216,7 +11238,11 @@ var init_ItemSlot = __esm({
11216
11238
  epic: "shadow-lg",
11217
11239
  legendary: "shadow-lg"
11218
11240
  };
11219
- DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
11241
+ DEFAULT_ASSET_URL5 = {
11242
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
11243
+ role: "effect",
11244
+ category: "item"
11245
+ };
11220
11246
  assetSizeMap = {
11221
11247
  sm: 28,
11222
11248
  md: 40,
@@ -11262,7 +11288,7 @@ function TurnIndicator({
11262
11288
  assetUrl ? /* @__PURE__ */ jsx(
11263
11289
  "img",
11264
11290
  {
11265
- src: assetUrl,
11291
+ src: assetUrl.url,
11266
11292
  alt: "",
11267
11293
  width: 12,
11268
11294
  height: 12,
@@ -11285,7 +11311,11 @@ var init_TurnIndicator = __esm({
11285
11311
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
11286
11312
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
11287
11313
  };
11288
- DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
11314
+ DEFAULT_ASSET_URL6 = {
11315
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
11316
+ role: "effect",
11317
+ category: "effect"
11318
+ };
11289
11319
  TurnIndicator.displayName = "TurnIndicator";
11290
11320
  }
11291
11321
  });
@@ -11324,7 +11354,7 @@ function ComboCounter({
11324
11354
  assetUrl && /* @__PURE__ */ jsx(
11325
11355
  "img",
11326
11356
  {
11327
- src: assetUrl,
11357
+ src: assetUrl.url,
11328
11358
  alt: "combo",
11329
11359
  width: 24,
11330
11360
  height: 24,
@@ -11350,7 +11380,11 @@ var DEFAULT_ASSET_URL7, sizeMap8;
11350
11380
  var init_ComboCounter = __esm({
11351
11381
  "components/game/atoms/ComboCounter.tsx"() {
11352
11382
  init_cn();
11353
- DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
11383
+ DEFAULT_ASSET_URL7 = {
11384
+ url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
11385
+ role: "effect",
11386
+ category: "effect"
11387
+ };
11354
11388
  sizeMap8 = {
11355
11389
  sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
11356
11390
  md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
@@ -11470,7 +11504,7 @@ function WaypointMarker({
11470
11504
  children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsx(
11471
11505
  "img",
11472
11506
  {
11473
- src: assetUrl,
11507
+ src: assetUrl.url,
11474
11508
  alt: label,
11475
11509
  width: sizes.img,
11476
11510
  height: sizes.img,
@@ -11499,7 +11533,11 @@ var init_WaypointMarker = __esm({
11499
11533
  "components/game/atoms/WaypointMarker.tsx"() {
11500
11534
  init_cn();
11501
11535
  init_Icon();
11502
- DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
11536
+ DEFAULT_ASSET_URL8 = {
11537
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
11538
+ role: "effect",
11539
+ category: "world"
11540
+ };
11503
11541
  sizeMap10 = {
11504
11542
  sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
11505
11543
  md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
@@ -11540,7 +11578,7 @@ function StatusEffect({
11540
11578
  /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsx(
11541
11579
  "img",
11542
11580
  {
11543
- src: assetUrl,
11581
+ src: assetUrl.url,
11544
11582
  alt: label,
11545
11583
  width: sizes.img,
11546
11584
  height: sizes.img,
@@ -11579,7 +11617,11 @@ var init_StatusEffect = __esm({
11579
11617
  "components/game/atoms/StatusEffect.tsx"() {
11580
11618
  init_cn();
11581
11619
  init_Icon();
11582
- DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
11620
+ DEFAULT_ASSET_URL9 = {
11621
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
11622
+ role: "effect",
11623
+ category: "effect"
11624
+ };
11583
11625
  sizeMap11 = {
11584
11626
  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 },
11585
11627
  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 },
@@ -11617,7 +11659,7 @@ function DamageNumber({
11617
11659
  assetUrl && /* @__PURE__ */ jsx(
11618
11660
  "img",
11619
11661
  {
11620
- src: assetUrl,
11662
+ src: assetUrl.url,
11621
11663
  alt: "",
11622
11664
  width: 14,
11623
11665
  height: 14,
@@ -11653,14 +11695,18 @@ var init_DamageNumber = __esm({
11653
11695
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
11654
11696
  }
11655
11697
  `;
11656
- DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
11698
+ DEFAULT_ASSET_URL10 = {
11699
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
11700
+ role: "effect",
11701
+ category: "effect"
11702
+ };
11657
11703
  DamageNumber.displayName = "DamageNumber";
11658
11704
  }
11659
11705
  });
11660
11706
  function DialogueBubble({
11661
11707
  speaker = "Hero",
11662
11708
  text = "The dungeon awaits. Choose your path wisely.",
11663
- portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
11709
+ portrait = DEFAULT_PORTRAIT,
11664
11710
  position = "bottom",
11665
11711
  className
11666
11712
  }) {
@@ -11676,7 +11722,7 @@ function DialogueBubble({
11676
11722
  portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsx(
11677
11723
  "img",
11678
11724
  {
11679
- src: portrait,
11725
+ src: portrait?.url,
11680
11726
  alt: speaker ?? "speaker",
11681
11727
  className: "w-full h-full object-cover"
11682
11728
  }
@@ -11689,9 +11735,15 @@ function DialogueBubble({
11689
11735
  }
11690
11736
  );
11691
11737
  }
11738
+ var DEFAULT_PORTRAIT;
11692
11739
  var init_DialogueBubble = __esm({
11693
11740
  "components/game/atoms/DialogueBubble.tsx"() {
11694
11741
  init_cn();
11742
+ DEFAULT_PORTRAIT = {
11743
+ url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
11744
+ role: "effect",
11745
+ category: "character"
11746
+ };
11695
11747
  DialogueBubble.displayName = "DialogueBubble";
11696
11748
  }
11697
11749
  });
@@ -11735,7 +11787,7 @@ function ChoiceButton({
11735
11787
  assetUrl ? /* @__PURE__ */ jsx(
11736
11788
  "img",
11737
11789
  {
11738
- src: assetUrl,
11790
+ src: assetUrl.url,
11739
11791
  alt: "",
11740
11792
  width: 16,
11741
11793
  height: 16,
@@ -11805,7 +11857,7 @@ function ActionButton({
11805
11857
  assetUrl ? /* @__PURE__ */ jsx(
11806
11858
  "img",
11807
11859
  {
11808
- src: assetUrl,
11860
+ src: assetUrl.url,
11809
11861
  alt: "",
11810
11862
  width: 16,
11811
11863
  height: 16,
@@ -11849,7 +11901,11 @@ var init_ActionButton = __esm({
11849
11901
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
11850
11902
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
11851
11903
  };
11852
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
11904
+ DEFAULT_ASSET_URL11 = {
11905
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
11906
+ role: "effect",
11907
+ category: "effect"
11908
+ };
11853
11909
  ActionButton.displayName = "ActionButton";
11854
11910
  }
11855
11911
  });
@@ -14436,12 +14492,7 @@ var init_useCanvasGestures = __esm({
14436
14492
  }
14437
14493
  });
14438
14494
  function unitAtlasUrl(unit) {
14439
- if (unit.spriteSheet) return unit.spriteSheet;
14440
- const sprite = unit.sprite;
14441
- if (!sprite) return null;
14442
- const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
14443
- if (!match) return null;
14444
- return `${match[1]}.json`;
14495
+ return unit.spriteSheet?.url ?? null;
14445
14496
  }
14446
14497
  function resolveSheetUrl(atlasUrl, relativeSheetPath) {
14447
14498
  try {
@@ -14637,7 +14688,6 @@ function IsometricCanvas({
14637
14688
  // Tuning
14638
14689
  diamondTopY: diamondTopYProp,
14639
14690
  // Remote asset loading
14640
- assetBaseUrl,
14641
14691
  assetManifest
14642
14692
  }) {
14643
14693
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -14719,54 +14769,48 @@ function IsometricCanvas({
14719
14769
  const attackTargetSet = useMemo(() => {
14720
14770
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
14721
14771
  }, [attackTargets]);
14722
- const resolveManifestUrl7 = useCallback((relativePath) => {
14723
- if (!relativePath) return void 0;
14724
- if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
14725
- return relativePath;
14726
- }, [assetBaseUrl]);
14727
14772
  const spriteUrls = useMemo(() => {
14728
14773
  const urls = [];
14729
14774
  for (const tile of sortedTiles) {
14730
- if (tile.terrainSprite) urls.push(tile.terrainSprite);
14775
+ if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
14731
14776
  else if (getTerrainSprite) {
14732
14777
  const url = getTerrainSprite(tile.terrain ?? "");
14733
14778
  if (url) urls.push(url);
14734
14779
  } else {
14735
- const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14780
+ const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
14736
14781
  if (url) urls.push(url);
14737
14782
  }
14738
14783
  }
14739
14784
  for (const feature of features) {
14740
- if (feature.sprite) urls.push(feature.sprite);
14785
+ if (feature.sprite) urls.push(feature.sprite.url);
14741
14786
  else if (getFeatureSprite) {
14742
14787
  const url = getFeatureSprite(feature.type);
14743
14788
  if (url) urls.push(url);
14744
14789
  } else {
14745
- const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
14790
+ const url = assetManifest?.features?.[feature.type]?.url;
14746
14791
  if (url) urls.push(url);
14747
14792
  }
14748
14793
  }
14749
14794
  for (const unit of units) {
14750
- if (unit.sprite) urls.push(unit.sprite);
14795
+ if (unit.sprite) urls.push(unit.sprite.url);
14751
14796
  else if (getUnitSprite) {
14752
14797
  const url = getUnitSprite(unit);
14753
14798
  if (url) urls.push(url);
14754
14799
  } else if (unit.unitType) {
14755
- const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
14800
+ const url = assetManifest?.units?.[unit.unitType]?.url;
14756
14801
  if (url) urls.push(url);
14757
14802
  }
14758
14803
  }
14759
14804
  if (assetManifest?.effects) {
14760
- for (const path of Object.values(assetManifest.effects)) {
14761
- const url = resolveManifestUrl7(path);
14762
- if (url) urls.push(url);
14805
+ for (const asset of Object.values(assetManifest.effects)) {
14806
+ if (asset.url) urls.push(asset.url);
14763
14807
  }
14764
14808
  }
14765
14809
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
14766
14810
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
14767
14811
  if (backgroundImage) urls.push(backgroundImage);
14768
14812
  return [...new Set(urls.filter(Boolean))];
14769
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
14813
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest]);
14770
14814
  const { getImage, pendingCount: _imagePendingCount } = useImageCache(spriteUrls);
14771
14815
  useEffect(() => {
14772
14816
  if (typeof window === "undefined") return;
@@ -14791,14 +14835,14 @@ function IsometricCanvas({
14791
14835
  lerpToTarget
14792
14836
  } = useCamera();
14793
14837
  const resolveTerrainSpriteUrl = useCallback((tile) => {
14794
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14795
- }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
14838
+ return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
14839
+ }, [getTerrainSprite, assetManifest]);
14796
14840
  const resolveFeatureSpriteUrl = useCallback((featureType) => {
14797
- return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
14798
- }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
14841
+ return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
14842
+ }, [getFeatureSprite, assetManifest]);
14799
14843
  const resolveUnitSpriteUrl = useCallback((unit) => {
14800
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
14801
- }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
14844
+ return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
14845
+ }, [getUnitSprite, assetManifest]);
14802
14846
  const miniMapTiles = useMemo(() => {
14803
14847
  if (!showMinimap) return [];
14804
14848
  return sortedTiles.map((t2) => ({
@@ -14945,7 +14989,7 @@ function IsometricCanvas({
14945
14989
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
14946
14990
  continue;
14947
14991
  }
14948
- const spriteUrl = feature.sprite || resolveFeatureSpriteUrl(feature.type);
14992
+ const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
14949
14993
  const img = spriteUrl ? getImage(spriteUrl) : null;
14950
14994
  const centerX = pos.x + scaledTileWidth / 2;
14951
14995
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
@@ -14994,12 +15038,12 @@ function IsometricCanvas({
14994
15038
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
14995
15039
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
14996
15040
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
15041
+ const unitIsSheet = unit.sprite?.dimension === "2d" && (unit.sprite?.animations?.length ?? 0) > 0;
14997
15042
  const SHEET_ROWS = 5;
14998
15043
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
14999
15044
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
15000
- const imgIsSheet = img ? img.naturalWidth % SHEET_COLUMNS === 0 && img.naturalHeight % SHEET_ROWS === 0 && Math.abs(sheetFrameW - sheetFrameH) < 2 : false;
15001
- const frameW = imgIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
15002
- const frameH = imgIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
15045
+ const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
15046
+ const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
15003
15047
  const ar = frameW / (frameH || 1);
15004
15048
  let drawH = unitDrawH;
15005
15049
  let drawW = unitDrawH * ar;
@@ -15014,7 +15058,7 @@ function IsometricCanvas({
15014
15058
  ctx.save();
15015
15059
  ctx.globalAlpha = 0.25;
15016
15060
  if (img) {
15017
- if (imgIsSheet) {
15061
+ if (unitIsSheet) {
15018
15062
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
15019
15063
  } else {
15020
15064
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
@@ -15062,7 +15106,7 @@ function IsometricCanvas({
15062
15106
  } else if (img) {
15063
15107
  const spriteY = groundY - drawH - breatheOffset;
15064
15108
  const drawUnit = (x) => {
15065
- if (imgIsSheet) {
15109
+ if (unitIsSheet) {
15066
15110
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
15067
15111
  } else {
15068
15112
  ctx.drawImage(img, x, spriteY, drawW, drawH);
@@ -15089,7 +15133,7 @@ function IsometricCanvas({
15089
15133
  }
15090
15134
  }
15091
15135
  for (const fx of effects) {
15092
- const spriteUrl = resolveManifestUrl7(assetManifest?.effects?.[fx.key]);
15136
+ const spriteUrl = assetManifest?.effects?.[fx.key]?.url;
15093
15137
  if (!spriteUrl) continue;
15094
15138
  const img = getImage(spriteUrl);
15095
15139
  if (!img) continue;
@@ -15133,7 +15177,6 @@ function IsometricCanvas({
15133
15177
  backgroundImage,
15134
15178
  cameraRef,
15135
15179
  unitScale,
15136
- resolveManifestUrl7,
15137
15180
  assetManifest
15138
15181
  ]);
15139
15182
  useEffect(() => {
@@ -15411,6 +15454,42 @@ var init_boardEntity = __esm({
15411
15454
  "components/game/organisms/boardEntity.ts"() {
15412
15455
  }
15413
15456
  });
15457
+
15458
+ // components/game/organisms/utils/makeAsset.ts
15459
+ function makeAsset(url, role, overrides = {}) {
15460
+ const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
15461
+ return {
15462
+ url,
15463
+ role,
15464
+ category: url.split("/").pop()?.replace(/\.[^.]+$/, "") ?? role,
15465
+ ...defaults,
15466
+ ...overrides
15467
+ };
15468
+ }
15469
+ function makeAssetMap(record, role, overrides = {}) {
15470
+ const result = {};
15471
+ for (const [key, url] of Object.entries(record)) {
15472
+ result[key] = makeAsset(url, role, overrides);
15473
+ }
15474
+ return result;
15475
+ }
15476
+ var ROLE_DEFAULTS;
15477
+ var init_makeAsset = __esm({
15478
+ "components/game/organisms/utils/makeAsset.ts"() {
15479
+ ROLE_DEFAULTS = {
15480
+ tile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15481
+ decoration: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15482
+ effect: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15483
+ item: { dimension: "2d", animations: ["static"], aspect: "5:7" },
15484
+ player: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15485
+ enemy: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15486
+ npc: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15487
+ projectile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15488
+ vehicle: { dimension: "2d", animations: ["idle", "walk"], aspect: "1:1" },
15489
+ ui: { dimension: "2d", animations: ["static"], aspect: "1:1" }
15490
+ };
15491
+ }
15492
+ });
15414
15493
  function buildDefaultBattleTiles() {
15415
15494
  const tiles = [];
15416
15495
  for (let y = 0; y < BATTLE_GRID_H; y++) {
@@ -15469,14 +15548,14 @@ function BattleBoard({
15469
15548
  if (o === null || typeof o.x !== "number" || typeof o.y !== "number") return [];
15470
15549
  const tile = { x: o.x, y: o.y };
15471
15550
  if (typeof o.terrain === "string") tile.terrain = o.terrain;
15472
- if (typeof o.terrainSprite === "string") tile.terrainSprite = o.terrainSprite;
15551
+ if (typeof o.terrainSprite === "string") tile.terrainSprite = makeAsset(o.terrainSprite, "tile");
15473
15552
  if (typeof o.passable === "boolean") tile.passable = o.passable;
15474
15553
  if (typeof o.movementCost === "number") tile.movementCost = o.movementCost;
15475
15554
  if (typeof o.elevation === "number") tile.elevation = o.elevation;
15476
15555
  if (typeof o.type === "string") tile.type = o.type;
15477
15556
  if (typeof o.tileType === "string") tile.tileType = o.tileType;
15478
15557
  if (typeof o.id === "string") tile.id = o.id;
15479
- if (typeof o.modelUrl === "string") tile.modelUrl = o.modelUrl;
15558
+ if (typeof o.modelUrl === "string") tile.modelUrl = makeAsset(o.modelUrl, "decoration", { dimension: "3d" });
15480
15559
  return [tile];
15481
15560
  }) : []);
15482
15561
  const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
@@ -15485,10 +15564,10 @@ function BattleBoard({
15485
15564
  if (o === null || typeof o.type !== "string" || typeof o.x !== "number" || typeof o.y !== "number") return [];
15486
15565
  const feat = { type: o.type, x: o.x, y: o.y };
15487
15566
  if (typeof o.id === "string") feat.id = o.id;
15488
- if (typeof o.sprite === "string") feat.sprite = o.sprite;
15567
+ if (typeof o.sprite === "string") feat.sprite = makeAsset(o.sprite, "decoration");
15489
15568
  if (typeof o.color === "string") feat.color = o.color;
15490
15569
  if (typeof o.elevation === "number") feat.elevation = o.elevation;
15491
- if (typeof o.assetUrl === "string") feat.assetUrl = o.assetUrl;
15570
+ if (typeof o.assetUrl === "string") feat.assetUrl = makeAsset(o.assetUrl, "decoration", { dimension: "3d" });
15492
15571
  return [feat];
15493
15572
  }) : []);
15494
15573
  const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
@@ -15604,7 +15683,7 @@ function BattleBoard({
15604
15683
  maxHealth: num(unit.maxHealth),
15605
15684
  unitType: unit.unitType == null ? void 0 : str(unit.unitType),
15606
15685
  heroId: unit.heroId == null ? void 0 : str(unit.heroId),
15607
- sprite: unit.sprite == null ? void 0 : str(unit.sprite),
15686
+ sprite: unit.sprite == null ? void 0 : makeAsset(str(unit.sprite), "npc"),
15608
15687
  traits: unitTraits?.map((tr) => ({
15609
15688
  name: tr.name,
15610
15689
  currentState: tr.currentState,
@@ -15754,7 +15833,6 @@ function BattleBoard({
15754
15833
  onTileHover: (x, y) => setHoveredTile({ x, y }),
15755
15834
  onTileLeave: () => setHoveredTile(null),
15756
15835
  scale,
15757
- assetBaseUrl: assetManifest?.baseUrl,
15758
15836
  assetManifest,
15759
15837
  backgroundImage,
15760
15838
  onDrawEffects,
@@ -15832,15 +15910,16 @@ var init_BattleBoard = __esm({
15832
15910
  init_IsometricCanvas();
15833
15911
  init_boardEntity();
15834
15912
  init_isometric();
15913
+ init_makeAsset();
15835
15914
  BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
15836
15915
  BATTLE_GRID_W = 16;
15837
15916
  BATTLE_GRID_H = 16;
15838
15917
  BATTLE_TERRAIN_SPRITES = [
15839
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
15840
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
15841
- `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
15842
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
15843
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
15918
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`, "tile"),
15919
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile"),
15920
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`, "tile"),
15921
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, "tile"),
15922
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile")
15844
15923
  ];
15845
15924
  DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
15846
15925
  BattleBoard.displayName = "BattleBoard";
@@ -15879,61 +15958,64 @@ function BattleTemplate({
15879
15958
  }
15880
15959
  );
15881
15960
  }
15882
- var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
15961
+ var CDN, STONE, DIRT, GRASS, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
15883
15962
  var init_BattleTemplate = __esm({
15884
15963
  "components/game/templates/BattleTemplate.tsx"() {
15885
15964
  init_BattleBoard();
15965
+ init_makeAsset();
15886
15966
  CDN = "https://almadar-kflow-assets.web.app/shared";
15967
+ STONE = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`, "tile");
15968
+ DIRT = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`, "tile");
15969
+ GRASS = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`, "tile");
15887
15970
  DEFAULT_BATTLE_TILES2 = [
15888
- { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15889
- { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15890
- { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15891
- { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15892
- { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15893
- { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15894
- { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
15895
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15896
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15897
- { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15898
- { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15899
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15900
- { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
15901
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15902
- { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15903
- { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15904
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15905
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15906
- { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
15907
- { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15908
- { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15909
- { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15910
- { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15911
- { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15912
- { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` }
15971
+ { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15972
+ { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15973
+ { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15974
+ { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15975
+ { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
15976
+ { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
15977
+ { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: DIRT },
15978
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
15979
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
15980
+ { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
15981
+ { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
15982
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
15983
+ { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: DIRT },
15984
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
15985
+ { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
15986
+ { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
15987
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
15988
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
15989
+ { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: DIRT },
15990
+ { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
15991
+ { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
15992
+ { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
15993
+ { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
15994
+ { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
15995
+ { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: STONE }
15913
15996
  ];
15914
15997
  DEFAULT_BATTLE_UNITS = [
15915
- { 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` },
15916
- { 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` }
15998
+ { 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") },
15999
+ { 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") }
15917
16000
  ];
15918
16001
  DEFAULT_BATTLE_FEATURES = [
15919
- { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: `${CDN}/world-map/gold_mine.png` },
15920
- { id: "f2", x: 3, y: 1, type: "portal", sprite: `${CDN}/world-map/portal_open.png` }
16002
+ { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: makeAsset(`${CDN}/world-map/gold_mine.png`, "decoration") },
16003
+ { id: "f2", x: 3, y: 1, type: "portal", sprite: makeAsset(`${CDN}/world-map/portal_open.png`, "decoration") }
15921
16004
  ];
15922
16005
  DEFAULT_BATTLE_MANIFEST = {
15923
- baseUrl: CDN,
15924
- terrains: {
15925
- stone: "/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png",
15926
- dirt: "/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png",
15927
- grass: "/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png"
15928
- },
15929
- units: {
15930
- worker: "/sprite-sheets/amir-sprite-sheet-se.png",
15931
- guardian: "/sprite-sheets/destroyer-sprite-sheet-sw.png"
15932
- },
15933
- features: {
15934
- gold_mine: "/world-map/gold_mine.png",
15935
- portal: "/world-map/portal_open.png"
15936
- }
16006
+ terrains: makeAssetMap({
16007
+ stone: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`,
16008
+ dirt: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`,
16009
+ grass: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`
16010
+ }, "tile"),
16011
+ units: makeAssetMap({
16012
+ worker: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png`,
16013
+ guardian: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`
16014
+ }, "npc"),
16015
+ features: makeAssetMap({
16016
+ gold_mine: `${CDN}/world-map/gold_mine.png`,
16017
+ portal: `${CDN}/world-map/portal_open.png`
16018
+ }, "decoration")
15937
16019
  };
15938
16020
  BattleTemplate.displayName = "BattleTemplate";
15939
16021
  }
@@ -17321,7 +17403,6 @@ function BoardgameBoard({
17321
17403
  units,
17322
17404
  features,
17323
17405
  assetManifest,
17324
- assetBaseUrl,
17325
17406
  scale,
17326
17407
  showMinimap,
17327
17408
  enableCamera,
@@ -22391,7 +22472,7 @@ function CardHand({
22391
22472
  /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsx(
22392
22473
  "img",
22393
22474
  {
22394
- src: card.iconUrl,
22475
+ src: card.iconUrl.url,
22395
22476
  alt: card.title ?? card.id,
22396
22477
  width: art,
22397
22478
  height: art,
@@ -22449,15 +22530,6 @@ var init_CardHand = __esm({
22449
22530
  CardHand.displayName = "CardHand";
22450
22531
  }
22451
22532
  });
22452
- function resolveManifestUrl(manifest, relative) {
22453
- if (relative == null) return void 0;
22454
- if (/^https?:\/\//.test(relative)) return relative;
22455
- const base = manifest?.baseUrl;
22456
- if (base == null) return relative;
22457
- const cleanBase = base.replace(/\/$/, "");
22458
- const cleanRel = relative.replace(/^\//, "");
22459
- return `${cleanBase}/${cleanRel}`;
22460
- }
22461
22533
  function rowToCard(r2) {
22462
22534
  return {
22463
22535
  id: str(r2.id),
@@ -22471,7 +22543,7 @@ function rowToCard(r2) {
22471
22543
  function toHandCards(cards, manifest, mana) {
22472
22544
  return cards.map((c) => {
22473
22545
  const key = c.iconKey ?? c.id;
22474
- const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
22546
+ const iconUrl = manifest?.cards?.[key];
22475
22547
  return {
22476
22548
  id: c.id,
22477
22549
  iconUrl,
@@ -23585,7 +23657,6 @@ function CastleBoard({
23585
23657
  onTileHover: (x, y) => setHoveredTile({ x, y }),
23586
23658
  onTileLeave: () => setHoveredTile(null),
23587
23659
  scale,
23588
- assetBaseUrl: assetManifest?.baseUrl,
23589
23660
  assetManifest,
23590
23661
  backgroundImage
23591
23662
  }
@@ -23661,60 +23732,63 @@ function CastleTemplate({
23661
23732
  }
23662
23733
  );
23663
23734
  }
23664
- var CDN2, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
23735
+ var CDN2, WALL, FLOOR, FLOOR_CENTER, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
23665
23736
  var init_CastleTemplate = __esm({
23666
23737
  "components/game/templates/CastleTemplate.tsx"() {
23667
23738
  init_CastleBoard();
23739
+ init_makeAsset();
23668
23740
  CDN2 = "https://almadar-kflow-assets.web.app/shared";
23741
+ WALL = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`, "tile");
23742
+ FLOOR = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
23743
+ FLOOR_CENTER = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`, "tile");
23669
23744
  DEFAULT_CASTLE_TILES = [
23670
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23671
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23672
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23673
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23674
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23675
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23676
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23677
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23678
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23679
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23680
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23681
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23682
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png` },
23683
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23684
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23685
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23686
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23687
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23688
- { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23689
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23690
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23691
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23692
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23693
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23694
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` }
23745
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23746
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23747
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23748
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23749
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23750
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
23751
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23752
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23753
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23754
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
23755
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
23756
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
23757
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR_CENTER },
23758
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
23759
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
23760
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
23761
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23762
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23763
+ { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23764
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
23765
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23766
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23767
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23768
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23769
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: WALL }
23695
23770
  ];
23696
23771
  DEFAULT_CASTLE_UNITS = [
23697
- { 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` },
23698
- { 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` }
23772
+ { 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") },
23773
+ { 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") }
23699
23774
  ];
23700
23775
  DEFAULT_CASTLE_FEATURES = [
23701
- { id: "f1", x: 2, y: 2, type: "chest", sprite: `${CDN2}/world-map/treasure_chest_closed.png` },
23702
- { id: "f2", x: 3, y: 1, type: "crystal", sprite: `${CDN2}/world-map/resonance_crystal.png` }
23776
+ { id: "f1", x: 2, y: 2, type: "chest", sprite: makeAsset(`${CDN2}/world-map/treasure_chest_closed.png`, "decoration") },
23777
+ { id: "f2", x: 3, y: 1, type: "crystal", sprite: makeAsset(`${CDN2}/world-map/resonance_crystal.png`, "decoration") }
23703
23778
  ];
23704
23779
  DEFAULT_CASTLE_MANIFEST = {
23705
- baseUrl: CDN2,
23706
- terrains: {
23707
- wall: "/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png",
23708
- floor: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png"
23709
- },
23710
- units: {
23711
- worker: "/sprite-sheets/coordinator-sprite-sheet-se.png",
23712
- guardian: "/sprite-sheets/forger-sprite-sheet-se.png"
23713
- },
23714
- features: {
23715
- chest: "/world-map/treasure_chest_closed.png",
23716
- crystal: "/world-map/resonance_crystal.png"
23717
- }
23780
+ terrains: makeAssetMap({
23781
+ wall: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
23782
+ floor: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`
23783
+ }, "tile"),
23784
+ units: makeAssetMap({
23785
+ worker: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`,
23786
+ guardian: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`
23787
+ }, "player"),
23788
+ features: makeAssetMap({
23789
+ chest: `${CDN2}/world-map/treasure_chest_closed.png`,
23790
+ crystal: `${CDN2}/world-map/resonance_crystal.png`
23791
+ }, "decoration")
23718
23792
  };
23719
23793
  CastleTemplate.displayName = "CastleTemplate";
23720
23794
  }
@@ -24702,15 +24776,6 @@ var init_ChatBar = __esm({
24702
24776
  ChatBar.displayName = "ChatBar";
24703
24777
  }
24704
24778
  });
24705
- function resolveManifestUrl2(manifest, relative) {
24706
- if (relative == null) return void 0;
24707
- if (/^https?:\/\//.test(relative)) return relative;
24708
- const base = manifest?.baseUrl;
24709
- if (base == null) return relative;
24710
- const cleanBase = base.replace(/\/$/, "");
24711
- const cleanRel = relative.replace(/^\//, "");
24712
- return `${cleanBase}/${cleanRel}`;
24713
- }
24714
24779
  function buildDefaultCBTiles() {
24715
24780
  const tiles = [];
24716
24781
  for (let y = 0; y < CB_GRID_H; y++) {
@@ -24725,12 +24790,12 @@ function buildDefaultCBTiles() {
24725
24790
  function tilesToIso(tiles, manifest) {
24726
24791
  return tiles.map((t) => {
24727
24792
  const key = t.terrain ?? "grass";
24728
- const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
24793
+ const terrainSprite = t.terrainSprite ?? manifest?.terrains?.[key] ?? manifest?.terrains?.grass;
24729
24794
  return {
24730
24795
  x: t.x,
24731
24796
  y: t.y,
24732
24797
  terrain: t.terrain,
24733
- terrainSprite: sprite,
24798
+ terrainSprite,
24734
24799
  passable: t.passable
24735
24800
  };
24736
24801
  });
@@ -24741,7 +24806,7 @@ function buildingsToFeatures(buildings, manifest) {
24741
24806
  x: b.x,
24742
24807
  y: b.y,
24743
24808
  type: b.type,
24744
- sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
24809
+ sprite: manifest?.features?.[b.type]
24745
24810
  }));
24746
24811
  }
24747
24812
  function CityBuilderBoard({
@@ -24773,7 +24838,7 @@ function CityBuilderBoard({
24773
24838
  x: num(r2.x),
24774
24839
  y: num(r2.y),
24775
24840
  terrain: r2.terrain == null ? void 0 : str(r2.terrain),
24776
- terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
24841
+ terrainSprite: r2.terrainSprite == null ? void 0 : makeAsset(str(r2.terrainSprite), "tile"),
24777
24842
  passable: r2.passable !== false
24778
24843
  })),
24779
24844
  [board.tiles]
@@ -24882,7 +24947,6 @@ function CityBuilderBoard({
24882
24947
  {
24883
24948
  tiles: isoTiles,
24884
24949
  features: buildingFeatures,
24885
- assetBaseUrl: assetManifest?.baseUrl,
24886
24950
  assetManifest,
24887
24951
  validMoves,
24888
24952
  hoveredTile,
@@ -24917,6 +24981,7 @@ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
24917
24981
  var init_CityBuilderBoard = __esm({
24918
24982
  "components/game/organisms/CityBuilderBoard.tsx"() {
24919
24983
  "use client";
24984
+ init_makeAsset();
24920
24985
  init_cn();
24921
24986
  init_useEventBus();
24922
24987
  init_Box();
@@ -30911,7 +30976,7 @@ function StatBadge({
30911
30976
  resolvedAsset ? /* @__PURE__ */ jsx(
30912
30977
  "img",
30913
30978
  {
30914
- src: resolvedAsset,
30979
+ src: resolvedAsset.url,
30915
30980
  alt: "",
30916
30981
  width: 16,
30917
30982
  height: 16,
@@ -31218,7 +31283,7 @@ function GameCanvas2D({
31218
31283
  tickEvent,
31219
31284
  drawEvent,
31220
31285
  fps = 60,
31221
- backgroundImage = "",
31286
+ backgroundImage,
31222
31287
  assetBaseUrl,
31223
31288
  className
31224
31289
  }) {
@@ -31282,7 +31347,7 @@ function GameCanvas2D({
31282
31347
  emitRef.current(tickEventRef.current, { dt, frame });
31283
31348
  }
31284
31349
  if (backgroundImageRef.current) {
31285
- const bgImg = loadImage(backgroundImageRef.current);
31350
+ const bgImg = loadImage(backgroundImageRef.current.url);
31286
31351
  if (bgImg) {
31287
31352
  ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
31288
31353
  } else {
@@ -31653,7 +31718,7 @@ function EnemyPlate({
31653
31718
  assetUrl && /* @__PURE__ */ jsx(
31654
31719
  "img",
31655
31720
  {
31656
- src: assetUrl,
31721
+ src: assetUrl.url,
31657
31722
  alt: name,
31658
31723
  width: 24,
31659
31724
  height: 24,
@@ -31995,7 +32060,7 @@ function DialogueBox({
31995
32060
  "div",
31996
32061
  {
31997
32062
  className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
31998
- style: { backgroundImage: `url(${backgroundImage})` },
32063
+ style: { backgroundImage: `url(${backgroundImage?.url})` },
31999
32064
  "aria-hidden": "true"
32000
32065
  }
32001
32066
  ),
@@ -32010,7 +32075,7 @@ function DialogueBox({
32010
32075
  children: /* @__PURE__ */ jsx(
32011
32076
  "img",
32012
32077
  {
32013
- src: portraitUrl,
32078
+ src: portraitUrl?.url,
32014
32079
  alt: dialogue.speaker,
32015
32080
  className: "h-full w-auto object-contain drop-shadow-2xl"
32016
32081
  }
@@ -43907,7 +43972,6 @@ var init_FeatureGridOrganism = __esm({
43907
43972
  });
43908
43973
  function FishingBoard({
43909
43974
  backgroundImage,
43910
- assetBaseUrl,
43911
43975
  scale = 1,
43912
43976
  showMinimap = false,
43913
43977
  enableCamera = true,
@@ -43925,8 +43989,7 @@ function FishingBoard({
43925
43989
  {
43926
43990
  width,
43927
43991
  height,
43928
- backgroundImage: backgroundImage ?? "",
43929
- assetBaseUrl,
43992
+ backgroundImage,
43930
43993
  fps: 60,
43931
43994
  className: "w-full h-full"
43932
43995
  }
@@ -46145,7 +46208,7 @@ var init_GameCanvas3D2 = __esm({
46145
46208
  children: /* @__PURE__ */ jsx(
46146
46209
  ModelLoader,
46147
46210
  {
46148
- url: tile.modelUrl,
46211
+ url: tile.modelUrl.url,
46149
46212
  scale: 0.95,
46150
46213
  fallbackGeometry: "box",
46151
46214
  castShadow: true,
@@ -46210,7 +46273,7 @@ var init_GameCanvas3D2 = __esm({
46210
46273
  /* @__PURE__ */ jsx(
46211
46274
  ModelLoader,
46212
46275
  {
46213
- url: unit.modelUrl,
46276
+ url: unit.modelUrl.url,
46214
46277
  scale: modelScale,
46215
46278
  fallbackGeometry: "box",
46216
46279
  castShadow: true
@@ -46270,7 +46333,7 @@ var init_GameCanvas3D2 = __esm({
46270
46333
  return /* @__PURE__ */ jsx(
46271
46334
  ModelLoader,
46272
46335
  {
46273
- url: feature.assetUrl,
46336
+ url: feature.assetUrl.url,
46274
46337
  position,
46275
46338
  scale: 0.5,
46276
46339
  rotation: [0, feature.rotation ?? 0, 0],
@@ -46491,7 +46554,18 @@ function GameBoard3D({
46491
46554
  const row = boardEntity(entity);
46492
46555
  const eventBus = useEventBus();
46493
46556
  const entityUnits = row ? rows(row.units) : [];
46494
- const units = entityUnits;
46557
+ const units = entityUnits.map((r2) => ({
46558
+ id: str(r2.id),
46559
+ x: num(r2.x),
46560
+ y: num(r2.y),
46561
+ z: num(r2.z),
46562
+ faction: str(r2.faction) || "neutral",
46563
+ team: str(r2.team) || str(r2.faction) || "neutral",
46564
+ unitType: r2.unitType == null ? void 0 : str(r2.unitType),
46565
+ name: r2.name == null ? void 0 : str(r2.name),
46566
+ health: r2.health == null ? void 0 : num(r2.health),
46567
+ maxHealth: r2.maxHealth == null ? void 0 : num(r2.maxHealth)
46568
+ }));
46495
46569
  const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
46496
46570
  const phase = row ? str(row.phase) : "observation";
46497
46571
  const result = row ? str(row.result) : "none";
@@ -47086,7 +47160,6 @@ function HexStrategyBoard({
47086
47160
  units,
47087
47161
  features,
47088
47162
  assetManifest,
47089
- assetBaseUrl,
47090
47163
  scale,
47091
47164
  showMinimap,
47092
47165
  enableCamera,
@@ -47128,7 +47201,6 @@ function HolidayRunnerBoard({
47128
47201
  units,
47129
47202
  features,
47130
47203
  assetManifest,
47131
- assetBaseUrl,
47132
47204
  scale,
47133
47205
  showMinimap,
47134
47206
  enableCamera,
@@ -47923,7 +47995,6 @@ function MatchPuzzleBoard({
47923
47995
  units,
47924
47996
  features,
47925
47997
  assetManifest,
47926
- assetBaseUrl,
47927
47998
  scale,
47928
47999
  showMinimap,
47929
48000
  enableCamera,
@@ -48184,7 +48255,6 @@ function MinigolfBoard({
48184
48255
  units,
48185
48256
  features,
48186
48257
  assetManifest,
48187
- assetBaseUrl,
48188
48258
  scale,
48189
48259
  showMinimap,
48190
48260
  enableCamera,
@@ -48490,7 +48560,6 @@ function PirateBoard({
48490
48560
  units,
48491
48561
  features,
48492
48562
  assetManifest,
48493
- assetBaseUrl,
48494
48563
  scale,
48495
48564
  showMinimap,
48496
48565
  enableCamera,
@@ -48611,8 +48680,8 @@ function PlatformerBoard({
48611
48680
  canvasHeight,
48612
48681
  followCamera: true,
48613
48682
  bgColor,
48614
- playerSprite,
48615
- tileSprites,
48683
+ playerSprite: playerSprite?.url,
48684
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
48616
48685
  leftEvent,
48617
48686
  rightEvent,
48618
48687
  jumpEvent,
@@ -48677,7 +48746,7 @@ function PlatformerTemplate({
48677
48746
  worldHeight = 400,
48678
48747
  canvasWidth = 800,
48679
48748
  canvasHeight = 400,
48680
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
48749
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
48681
48750
  tileSprites = DEFAULT_TILE_SPRITES,
48682
48751
  bgColor = "#5c94fc",
48683
48752
  gameEndEvent = "GAME_END",
@@ -48730,13 +48799,14 @@ var init_PlatformerTemplate = __esm({
48730
48799
  init_PlatformerBoard();
48731
48800
  init_GameHud();
48732
48801
  init_ScoreBoard();
48802
+ init_makeAsset();
48733
48803
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
48734
- DEFAULT_TILE_SPRITES = {
48804
+ DEFAULT_TILE_SPRITES = makeAssetMap({
48735
48805
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
48736
48806
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
48737
48807
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
48738
48808
  goal: `${CDN3}/tiles/platformPack_tile007.png`
48739
- };
48809
+ }, "tile");
48740
48810
  DEFAULT_PLATFORMS = [
48741
48811
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
48742
48812
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -48892,7 +48962,6 @@ function RacingBoard({
48892
48962
  units,
48893
48963
  features,
48894
48964
  assetManifest,
48895
- assetBaseUrl,
48896
48965
  scale,
48897
48966
  showMinimap,
48898
48967
  enableCamera,
@@ -48911,27 +48980,18 @@ var init_RacingBoard = __esm({
48911
48980
  RacingBoard.displayName = "RacingBoard";
48912
48981
  }
48913
48982
  });
48914
- function resolveManifestUrl3(manifest, relative) {
48915
- if (relative == null) return void 0;
48916
- if (/^https?:\/\//.test(relative)) return relative;
48917
- const base = manifest?.baseUrl;
48918
- if (base == null) return relative;
48919
- const cleanBase = base.replace(/\/$/, "");
48920
- const cleanRel = relative.replace(/^\//, "");
48921
- return `${cleanBase}/${cleanRel}`;
48922
- }
48923
48983
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
48924
48984
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
48925
48985
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
48926
48986
  const isWall = isBorder || isPillar;
48927
48987
  const terrains = manifest?.terrains;
48928
48988
  if (x === stairsX && y === stairsY) {
48929
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
48989
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
48930
48990
  }
48931
48991
  if (isWall) {
48932
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
48992
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
48933
48993
  }
48934
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
48994
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
48935
48995
  }
48936
48996
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
48937
48997
  const tiles = [];
@@ -48975,7 +49035,7 @@ function RoguelikeBoard({
48975
49035
  x: num(r2.x),
48976
49036
  y: num(r2.y),
48977
49037
  terrain: r2.terrain == null ? void 0 : str(r2.terrain),
48978
- terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
49038
+ terrainSprite: r2.terrainSprite == null ? void 0 : makeAsset(str(r2.terrainSprite), "tile"),
48979
49039
  passable: r2.passable !== false
48980
49040
  })),
48981
49041
  [board.tiles]
@@ -49055,7 +49115,7 @@ function RoguelikeBoard({
49055
49115
  health: playerHp,
49056
49116
  maxHealth: playerMaxHp,
49057
49117
  unitType: "player",
49058
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
49118
+ sprite: assetManifest?.units?.player
49059
49119
  },
49060
49120
  ...liveEnemies.map((e) => ({
49061
49121
  id: e.id,
@@ -49065,7 +49125,7 @@ function RoguelikeBoard({
49065
49125
  health: e.hp,
49066
49126
  maxHealth: 6,
49067
49127
  unitType: "enemy",
49068
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
49128
+ sprite: assetManifest?.units?.enemy
49069
49129
  }))
49070
49130
  ];
49071
49131
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -49075,7 +49135,7 @@ function RoguelikeBoard({
49075
49135
  x: it.x,
49076
49136
  y: it.y,
49077
49137
  type: it.kind,
49078
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
49138
+ sprite: assetManifest?.features?.[it.kind]
49079
49139
  })),
49080
49140
  [items, assetManifest]
49081
49141
  );
@@ -49136,7 +49196,6 @@ function RoguelikeBoard({
49136
49196
  onTileHover: (x, y) => setHoveredTile({ x, y }),
49137
49197
  onTileLeave: () => setHoveredTile(null),
49138
49198
  scale,
49139
- assetBaseUrl: assetManifest?.baseUrl,
49140
49199
  assetManifest,
49141
49200
  unitScale,
49142
49201
  spriteHeightRatio,
@@ -49196,6 +49255,7 @@ var init_RoguelikeBoard = __esm({
49196
49255
  init_Stack();
49197
49256
  init_IsometricCanvas();
49198
49257
  init_boardEntity();
49258
+ init_makeAsset();
49199
49259
  DUNGEON_GRID_W = 16;
49200
49260
  DUNGEON_GRID_H = 16;
49201
49261
  DEFAULT_ENEMIES = [
@@ -49246,55 +49306,59 @@ function RoguelikeTemplate({
49246
49306
  }
49247
49307
  );
49248
49308
  }
49249
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
49309
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
49250
49310
  var init_RoguelikeTemplate = __esm({
49251
49311
  "components/game/templates/RoguelikeTemplate.tsx"() {
49252
49312
  init_RoguelikeBoard();
49313
+ init_makeAsset();
49253
49314
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
49315
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
49316
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
49317
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
49318
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
49254
49319
  DEFAULT_ROGUELIKE_TILES = [
49255
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49256
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49257
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49258
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49259
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49260
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49261
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49262
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49263
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49264
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49265
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49266
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49267
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49268
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49269
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49270
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49271
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49272
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49273
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
49274
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49275
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49276
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49277
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49278
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49279
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
49320
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49321
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49322
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49323
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49324
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49325
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
49326
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49327
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49328
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49329
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
49330
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
49331
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
49332
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
49333
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
49334
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
49335
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
49336
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
49337
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
49338
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
49339
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
49340
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49341
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49342
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49343
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49344
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
49280
49345
  ];
49281
49346
  DEFAULT_ROGUELIKE_MANIFEST = {
49282
- baseUrl: CDN4,
49283
- terrains: {
49284
- floor: "/isometric-dungeon/Isometric/dirt_E.png",
49285
- wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
49286
- stairs: "/isometric-dungeon/Isometric/stairs_E.png",
49287
- planks: "/isometric-dungeon/Isometric/planks_E.png"
49288
- },
49347
+ terrains: makeAssetMap({
49348
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
49349
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
49350
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
49351
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
49352
+ }, "tile"),
49289
49353
  units: {
49290
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
49291
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
49354
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
49355
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
49292
49356
  },
49293
- features: {
49294
- health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
49295
- sword: "/isometric-dungeon/Isometric/barrel_E.png",
49296
- shield: "/isometric-dungeon/Isometric/barrel_E.png"
49297
- }
49357
+ features: makeAssetMap({
49358
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
49359
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
49360
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
49361
+ }, "item")
49298
49362
  };
49299
49363
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
49300
49364
  }
@@ -52168,7 +52232,6 @@ function SokobanBoard({
52168
52232
  units,
52169
52233
  features,
52170
52234
  assetManifest,
52171
- assetBaseUrl,
52172
52235
  scale,
52173
52236
  showMinimap,
52174
52237
  enableCamera,
@@ -52210,7 +52273,6 @@ function SpaceShmupBoard({
52210
52273
  units,
52211
52274
  features,
52212
52275
  assetManifest,
52213
- assetBaseUrl,
52214
52276
  scale,
52215
52277
  showMinimap,
52216
52278
  enableCamera,
@@ -52252,7 +52314,6 @@ function SpaceStationBoard({
52252
52314
  units,
52253
52315
  features,
52254
52316
  assetManifest,
52255
- assetBaseUrl,
52256
52317
  scale,
52257
52318
  showMinimap,
52258
52319
  enableCamera,
@@ -52387,7 +52448,6 @@ function SportsBoard({
52387
52448
  units,
52388
52449
  features,
52389
52450
  assetManifest,
52390
- assetBaseUrl,
52391
52451
  scale,
52392
52452
  showMinimap,
52393
52453
  enableCamera,
@@ -54231,7 +54291,6 @@ function TanksBoard({
54231
54291
  units,
54232
54292
  features,
54233
54293
  assetManifest,
54234
- assetBaseUrl,
54235
54294
  scale,
54236
54295
  showMinimap,
54237
54296
  enableCamera,
@@ -54509,15 +54568,6 @@ var init_ToastSlot = __esm({
54509
54568
  ToastSlot.displayName = "ToastSlot";
54510
54569
  }
54511
54570
  });
54512
- function resolveManifestUrl4(manifest, relative) {
54513
- if (relative == null || relative === "") return void 0;
54514
- if (/^https?:\/\//.test(relative)) return relative;
54515
- const base = manifest?.baseUrl;
54516
- if (base == null) return relative;
54517
- const cleanBase = base.replace(/\/$/, "");
54518
- const cleanRel = relative.replace(/^\//, "");
54519
- return `${cleanBase}/${cleanRel}`;
54520
- }
54521
54571
  function readPlayer(v) {
54522
54572
  if (v == null || typeof v !== "object") return void 0;
54523
54573
  const o = v;
@@ -54570,10 +54620,10 @@ function TopDownShooterBoard({
54570
54620
  const wave = propWave ?? num(board.wave, 1);
54571
54621
  const lives = propLives ?? num(board.lives, 3);
54572
54622
  const result = propResult ?? (str(board.result) || "none");
54573
- const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
54574
- const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
54575
- const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
54576
- const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
54623
+ const playerSprite = assetManifest?.units?.player?.url;
54624
+ const enemySprite = assetManifest?.units?.enemy?.url;
54625
+ const projectileSprite = assetManifest?.features?.projectile?.url;
54626
+ const backgroundSprite = assetManifest?.background;
54577
54627
  const spriteUrls = useMemo(
54578
54628
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
54579
54629
  [playerSprite, enemySprite, projectileSprite]
@@ -54740,7 +54790,6 @@ function TopDownShooterBoard({
54740
54790
  width,
54741
54791
  height,
54742
54792
  backgroundImage: backgroundSprite,
54743
- assetBaseUrl: assetManifest?.baseUrl,
54744
54793
  onDraw
54745
54794
  }
54746
54795
  ),
@@ -54865,15 +54914,6 @@ var init_TopDownShooterTemplate = __esm({
54865
54914
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
54866
54915
  }
54867
54916
  });
54868
- function resolveManifestUrl5(manifest, relative) {
54869
- if (relative == null) return void 0;
54870
- if (/^https?:\/\//.test(relative)) return relative;
54871
- const base = manifest?.baseUrl;
54872
- if (base == null) return relative;
54873
- const cleanBase = base.replace(/\/$/, "");
54874
- const cleanRel = relative.replace(/^\//, "");
54875
- return `${cleanBase}/${cleanRel}`;
54876
- }
54877
54917
  function buildDefaultTDTiles() {
54878
54918
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
54879
54919
  const tiles = [];
@@ -54893,18 +54933,18 @@ function buildDefaultTDTiles() {
54893
54933
  function tilesToIso2(tiles, manifest) {
54894
54934
  return tiles.map((t) => {
54895
54935
  const key = t.terrain ?? "ground";
54896
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
54936
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
54897
54937
  return {
54898
54938
  x: t.x,
54899
54939
  y: t.y,
54900
54940
  terrain: t.terrain,
54901
- terrainSprite: sprite,
54941
+ terrainSprite,
54902
54942
  passable: t.passable
54903
54943
  };
54904
54944
  });
54905
54945
  }
54906
54946
  function creepsToUnits(creeps, manifest) {
54907
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
54947
+ const sprite = manifest?.units?.creep;
54908
54948
  return creeps.map((c) => ({
54909
54949
  id: c.id,
54910
54950
  position: { x: c.x, y: c.y },
@@ -54922,14 +54962,14 @@ function heroToUnit(hero, manifest) {
54922
54962
  position: { x: hero.x, y: hero.y },
54923
54963
  name: "Hero",
54924
54964
  team: "player",
54925
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
54965
+ sprite: manifest?.units?.hero,
54926
54966
  unitType: "hero",
54927
54967
  health: 1,
54928
54968
  maxHealth: 1
54929
54969
  };
54930
54970
  }
54931
54971
  function towersToFeatures(towers, manifest) {
54932
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
54972
+ const sprite = manifest?.features?.tower;
54933
54973
  return towers.map((t) => ({
54934
54974
  id: t.id,
54935
54975
  x: t.x,
@@ -55127,7 +55167,6 @@ function TowerDefenseBoard({
55127
55167
  tiles: isoTiles,
55128
55168
  units: isoUnits,
55129
55169
  features: towerFeatures,
55130
- assetBaseUrl: assetManifest?.baseUrl,
55131
55170
  assetManifest,
55132
55171
  validMoves,
55133
55172
  hoveredTile,
@@ -55171,6 +55210,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
55171
55210
  var init_TowerDefenseBoard = __esm({
55172
55211
  "components/game/organisms/TowerDefenseBoard.tsx"() {
55173
55212
  "use client";
55213
+ init_makeAsset();
55174
55214
  init_cn();
55175
55215
  init_useEventBus();
55176
55216
  init_Box();
@@ -55500,15 +55540,6 @@ var init_UncontrolledBattleBoard = __esm({
55500
55540
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
55501
55541
  }
55502
55542
  });
55503
- function resolveManifestUrl6(manifest, relative) {
55504
- if (relative == null) return void 0;
55505
- if (/^https?:\/\//.test(relative)) return relative;
55506
- const base = manifest?.baseUrl;
55507
- if (base == null) return relative;
55508
- const cleanBase = base.replace(/\/$/, "");
55509
- const cleanRel = relative.replace(/^\//, "");
55510
- return `${cleanBase}/${cleanRel}`;
55511
- }
55512
55543
  function VisualNovelBoard({
55513
55544
  entity,
55514
55545
  nodes: propNodes,
@@ -55543,11 +55574,11 @@ function VisualNovelBoard({
55543
55574
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
55544
55575
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
55545
55576
  const backgroundImage = useMemo(
55546
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
55577
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
55547
55578
  [assetManifest, currentNode?.backgroundKey]
55548
55579
  );
55549
55580
  const portraitUrl = useMemo(
55550
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
55581
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
55551
55582
  [assetManifest, currentNode?.portraitKey]
55552
55583
  );
55553
55584
  const dialogueChoices = useMemo(
@@ -55721,7 +55752,7 @@ function buildDefaultWorldTiles() {
55721
55752
  for (let x = 0; x < WORLD_GRID_W; x++) {
55722
55753
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
55723
55754
  const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
55724
- tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
55755
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
55725
55756
  }
55726
55757
  }
55727
55758
  return tiles;
@@ -55765,7 +55796,12 @@ function WorldMapBoard({
55765
55796
  const resolved = boardEntity(entity);
55766
55797
  const entityUnits = rows(resolved?.units);
55767
55798
  const entityTiles = rows(resolved?.tiles);
55768
- const features = propFeatures ?? rows(resolved?.features);
55799
+ const features = propFeatures ?? rows(resolved?.features).map((r2) => ({
55800
+ id: r2.id == null ? void 0 : str(r2.id),
55801
+ x: num(r2.x),
55802
+ y: num(r2.y),
55803
+ type: str(r2.type)
55804
+ }));
55769
55805
  const selectedHeroId = resolved?.selectedHeroId ?? null;
55770
55806
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
55771
55807
  const backgroundImage = resolved?.backgroundImage;
@@ -55775,7 +55811,7 @@ function WorldMapBoard({
55775
55811
  x: num(t.x),
55776
55812
  y: num(t.y),
55777
55813
  terrain: str(t.terrain),
55778
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
55814
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
55779
55815
  passable: t.passable !== false
55780
55816
  })),
55781
55817
  [entityTiles]
@@ -55791,7 +55827,7 @@ function WorldMapBoard({
55791
55827
  team: str(u.team) === "enemy" ? "enemy" : "player",
55792
55828
  health: num(u.health) || 100,
55793
55829
  maxHealth: num(u.maxHealth) || 100,
55794
- sprite: u.sprite == null ? void 0 : str(u.sprite)
55830
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
55795
55831
  })),
55796
55832
  [entityUnits, propUnits]
55797
55833
  );
@@ -55973,7 +56009,6 @@ function WorldMapBoard({
55973
56009
  onTileHover: (x, y) => setHoveredTile({ x, y }),
55974
56010
  onTileLeave: () => setHoveredTile(null),
55975
56011
  scale,
55976
- assetBaseUrl: assetManifest?.baseUrl,
55977
56012
  assetManifest,
55978
56013
  backgroundImage,
55979
56014
  effectSpriteUrls,
@@ -55996,6 +56031,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
55996
56031
  var init_WorldMapBoard = __esm({
55997
56032
  "components/game/organisms/WorldMapBoard.tsx"() {
55998
56033
  "use client";
56034
+ init_makeAsset();
55999
56035
  init_cn();
56000
56036
  init_useEventBus();
56001
56037
  init_Stack();
@@ -56049,62 +56085,66 @@ function WorldMapTemplate({
56049
56085
  }
56050
56086
  );
56051
56087
  }
56052
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
56088
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
56053
56089
  var init_WorldMapTemplate = __esm({
56054
56090
  "components/game/templates/WorldMapTemplate.tsx"() {
56055
56091
  init_WorldMapBoard();
56092
+ init_makeAsset();
56056
56093
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
56094
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
56095
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
56096
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
56097
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
56057
56098
  DEFAULT_WORLDMAP_TILES = [
56058
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56059
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56060
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56061
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56062
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56063
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56064
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56065
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56066
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56067
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56068
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56069
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56070
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
56071
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56072
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56073
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56074
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56075
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56076
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
56077
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56078
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56079
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56080
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56081
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56082
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
56099
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56100
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56101
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
56102
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56103
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56104
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
56105
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56106
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56107
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56108
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
56109
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
56110
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
56111
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
56112
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
56113
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
56114
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
56115
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
56116
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
56117
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
56118
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
56119
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
56120
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
56121
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
56122
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
56123
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
56083
56124
  ];
56084
56125
  DEFAULT_WORLDMAP_UNITS = [
56085
- { 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` },
56086
- { 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` }
56126
+ { 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") },
56127
+ { 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") }
56087
56128
  ];
56088
56129
  DEFAULT_WORLDMAP_FEATURES = [
56089
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
56090
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
56130
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
56131
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
56091
56132
  ];
56092
56133
  DEFAULT_WORLDMAP_MANIFEST = {
56093
- baseUrl: CDN5,
56094
- terrains: {
56095
- grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
56096
- water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
56097
- mountain: "/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png",
56098
- road: "/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png"
56099
- },
56134
+ terrains: makeAssetMap({
56135
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
56136
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
56137
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
56138
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
56139
+ }, "tile"),
56100
56140
  units: {
56101
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
56102
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
56141
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
56142
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
56103
56143
  },
56104
- features: {
56105
- capital: "/scenes/world/capital.png",
56106
- power_node: "/world-map/power_node.png"
56107
- }
56144
+ features: makeAssetMap({
56145
+ capital: `${CDN5}/scenes/world/capital.png`,
56146
+ power_node: `${CDN5}/world-map/power_node.png`
56147
+ }, "decoration")
56108
56148
  };
56109
56149
  WorldMapTemplate.displayName = "WorldMapTemplate";
56110
56150
  }