@almadar/ui 5.72.0 → 5.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/avl/index.cjs +410 -365
  2. package/dist/avl/index.js +410 -365
  3. package/dist/components/game/atoms/ActionButton.d.ts +3 -3
  4. package/dist/components/game/atoms/ChoiceButton.d.ts +3 -3
  5. package/dist/components/game/atoms/ComboCounter.d.ts +3 -3
  6. package/dist/components/game/atoms/ControlButton.d.ts +3 -3
  7. package/dist/components/game/atoms/DamageNumber.d.ts +3 -3
  8. package/dist/components/game/atoms/DialogueBubble.d.ts +3 -3
  9. package/dist/components/game/atoms/ItemSlot.d.ts +3 -3
  10. package/dist/components/game/atoms/ResourceCounter.d.ts +3 -3
  11. package/dist/components/game/atoms/ScoreDisplay.d.ts +3 -3
  12. package/dist/components/game/atoms/Sprite.d.ts +3 -20
  13. package/dist/components/game/atoms/StateIndicator.d.ts +2 -2
  14. package/dist/components/game/atoms/StatusEffect.d.ts +3 -3
  15. package/dist/components/game/atoms/TurnIndicator.d.ts +3 -3
  16. package/dist/components/game/atoms/WaypointMarker.d.ts +3 -3
  17. package/dist/components/game/molecules/CardHand.d.ts +2 -2
  18. package/dist/components/game/molecules/DialogueBox.d.ts +3 -3
  19. package/dist/components/game/molecules/EnemyPlate.d.ts +3 -3
  20. package/dist/components/game/molecules/GameCanvas2D.d.ts +3 -3
  21. package/dist/components/game/molecules/HealthPanel.d.ts +3 -3
  22. package/dist/components/game/molecules/IsometricCanvas.d.ts +8 -12
  23. package/dist/components/game/molecules/PowerupSlots.d.ts +3 -3
  24. package/dist/components/game/molecules/StatBadge.d.ts +5 -5
  25. package/dist/components/game/molecules/TurnPanel.d.ts +3 -3
  26. package/dist/components/game/molecules/three/index.cjs +51 -28
  27. package/dist/components/game/molecules/three/index.js +51 -28
  28. package/dist/components/game/molecules/useUnitSpriteAtlas.d.ts +3 -10
  29. package/dist/components/game/organisms/BattleBoard.d.ts +5 -6
  30. package/dist/components/game/organisms/CardBattlerBoard.d.ts +3 -4
  31. package/dist/components/game/organisms/CastleBoard.d.ts +5 -6
  32. package/dist/components/game/organisms/CityBuilderBoard.d.ts +6 -7
  33. package/dist/components/game/organisms/FishingBoard.d.ts +4 -6
  34. package/dist/components/game/organisms/PlatformerBoard.d.ts +5 -5
  35. package/dist/components/game/organisms/RoguelikeBoard.d.ts +4 -5
  36. package/dist/components/game/organisms/TopDownShooterBoard.d.ts +5 -6
  37. package/dist/components/game/organisms/TowerDefenseBoard.d.ts +5 -6
  38. package/dist/components/game/organisms/VisualNovelBoard.d.ts +4 -5
  39. package/dist/components/game/organisms/WorldMapBoard.d.ts +5 -6
  40. package/dist/components/game/organisms/types/effects.d.ts +7 -8
  41. package/dist/components/game/organisms/types/isometric.d.ts +8 -8
  42. package/dist/components/game/organisms/types/spriteAnimation.d.ts +3 -4
  43. package/dist/components/game/organisms/utils/makeAsset.d.ts +5 -0
  44. package/dist/components/game/templates/PlatformerTemplate.d.ts +5 -4
  45. package/dist/components/game/templates/game3dAssetManifest.d.ts +6 -8
  46. package/dist/components/index.cjs +425 -366
  47. package/dist/components/index.js +425 -366
  48. package/dist/providers/index.cjs +410 -365
  49. package/dist/providers/index.js +410 -365
  50. package/dist/runtime/index.cjs +410 -365
  51. package/dist/runtime/index.js +410 -365
  52. package/package.json +2 -2
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";
@@ -46670,22 +46744,27 @@ function resolveDescriptor(value, idPrefix) {
46670
46744
  }
46671
46745
  if (typeof value === "object" && value !== null) {
46672
46746
  const desc = asDescriptor(value);
46673
- if (desc !== null && getComponentForPattern(desc.type) !== null) {
46747
+ const hasComp = desc !== null && getComponentForPattern(desc.type) !== null;
46748
+ shellLog.debug("resolve", { idPrefix, type: desc?.type ?? null, hasDesc: desc !== null, render: hasComp });
46749
+ if (hasComp) {
46674
46750
  const resolvedProps = desc.props ?? {};
46675
46751
  const content = { id: desc._id ?? idPrefix, pattern: desc.type, props: resolvedProps, priority: 0 };
46676
46752
  const SCR = getSlotContentRenderer2();
46677
- return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 });
46753
+ return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 }, content.id);
46678
46754
  }
46755
+ } else {
46756
+ shellLog.debug("resolve", { idPrefix, type: null, hasDesc: false, render: false, branch: typeof value });
46679
46757
  }
46680
46758
  return null;
46681
46759
  }
46682
- var _scr, GameShell;
46760
+ var shellLog, _scr, GameShell;
46683
46761
  var init_GameShell = __esm({
46684
46762
  "components/game/templates/GameShell.tsx"() {
46685
46763
  init_cn();
46686
46764
  init_Box();
46687
46765
  init_Stack();
46688
46766
  init_Typography();
46767
+ shellLog = createLogger("almadar:ui:game:game-shell");
46689
46768
  _scr = null;
46690
46769
  GameShell = ({
46691
46770
  appName = "Game",
@@ -47086,7 +47165,6 @@ function HexStrategyBoard({
47086
47165
  units,
47087
47166
  features,
47088
47167
  assetManifest,
47089
- assetBaseUrl,
47090
47168
  scale,
47091
47169
  showMinimap,
47092
47170
  enableCamera,
@@ -47128,7 +47206,6 @@ function HolidayRunnerBoard({
47128
47206
  units,
47129
47207
  features,
47130
47208
  assetManifest,
47131
- assetBaseUrl,
47132
47209
  scale,
47133
47210
  showMinimap,
47134
47211
  enableCamera,
@@ -47923,7 +48000,6 @@ function MatchPuzzleBoard({
47923
48000
  units,
47924
48001
  features,
47925
48002
  assetManifest,
47926
- assetBaseUrl,
47927
48003
  scale,
47928
48004
  showMinimap,
47929
48005
  enableCamera,
@@ -48184,7 +48260,6 @@ function MinigolfBoard({
48184
48260
  units,
48185
48261
  features,
48186
48262
  assetManifest,
48187
- assetBaseUrl,
48188
48263
  scale,
48189
48264
  showMinimap,
48190
48265
  enableCamera,
@@ -48490,7 +48565,6 @@ function PirateBoard({
48490
48565
  units,
48491
48566
  features,
48492
48567
  assetManifest,
48493
- assetBaseUrl,
48494
48568
  scale,
48495
48569
  showMinimap,
48496
48570
  enableCamera,
@@ -48611,8 +48685,8 @@ function PlatformerBoard({
48611
48685
  canvasHeight,
48612
48686
  followCamera: true,
48613
48687
  bgColor,
48614
- playerSprite,
48615
- tileSprites,
48688
+ playerSprite: playerSprite?.url,
48689
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
48616
48690
  leftEvent,
48617
48691
  rightEvent,
48618
48692
  jumpEvent,
@@ -48677,7 +48751,7 @@ function PlatformerTemplate({
48677
48751
  worldHeight = 400,
48678
48752
  canvasWidth = 800,
48679
48753
  canvasHeight = 400,
48680
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
48754
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
48681
48755
  tileSprites = DEFAULT_TILE_SPRITES,
48682
48756
  bgColor = "#5c94fc",
48683
48757
  gameEndEvent = "GAME_END",
@@ -48730,13 +48804,14 @@ var init_PlatformerTemplate = __esm({
48730
48804
  init_PlatformerBoard();
48731
48805
  init_GameHud();
48732
48806
  init_ScoreBoard();
48807
+ init_makeAsset();
48733
48808
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
48734
- DEFAULT_TILE_SPRITES = {
48809
+ DEFAULT_TILE_SPRITES = makeAssetMap({
48735
48810
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
48736
48811
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
48737
48812
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
48738
48813
  goal: `${CDN3}/tiles/platformPack_tile007.png`
48739
- };
48814
+ }, "tile");
48740
48815
  DEFAULT_PLATFORMS = [
48741
48816
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
48742
48817
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -48892,7 +48967,6 @@ function RacingBoard({
48892
48967
  units,
48893
48968
  features,
48894
48969
  assetManifest,
48895
- assetBaseUrl,
48896
48970
  scale,
48897
48971
  showMinimap,
48898
48972
  enableCamera,
@@ -48911,27 +48985,18 @@ var init_RacingBoard = __esm({
48911
48985
  RacingBoard.displayName = "RacingBoard";
48912
48986
  }
48913
48987
  });
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
48988
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
48924
48989
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
48925
48990
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
48926
48991
  const isWall = isBorder || isPillar;
48927
48992
  const terrains = manifest?.terrains;
48928
48993
  if (x === stairsX && y === stairsY) {
48929
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
48994
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
48930
48995
  }
48931
48996
  if (isWall) {
48932
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
48997
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
48933
48998
  }
48934
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
48999
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
48935
49000
  }
48936
49001
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
48937
49002
  const tiles = [];
@@ -48975,7 +49040,7 @@ function RoguelikeBoard({
48975
49040
  x: num(r2.x),
48976
49041
  y: num(r2.y),
48977
49042
  terrain: r2.terrain == null ? void 0 : str(r2.terrain),
48978
- terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
49043
+ terrainSprite: r2.terrainSprite == null ? void 0 : makeAsset(str(r2.terrainSprite), "tile"),
48979
49044
  passable: r2.passable !== false
48980
49045
  })),
48981
49046
  [board.tiles]
@@ -49055,7 +49120,7 @@ function RoguelikeBoard({
49055
49120
  health: playerHp,
49056
49121
  maxHealth: playerMaxHp,
49057
49122
  unitType: "player",
49058
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
49123
+ sprite: assetManifest?.units?.player
49059
49124
  },
49060
49125
  ...liveEnemies.map((e) => ({
49061
49126
  id: e.id,
@@ -49065,7 +49130,7 @@ function RoguelikeBoard({
49065
49130
  health: e.hp,
49066
49131
  maxHealth: 6,
49067
49132
  unitType: "enemy",
49068
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
49133
+ sprite: assetManifest?.units?.enemy
49069
49134
  }))
49070
49135
  ];
49071
49136
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -49075,7 +49140,7 @@ function RoguelikeBoard({
49075
49140
  x: it.x,
49076
49141
  y: it.y,
49077
49142
  type: it.kind,
49078
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
49143
+ sprite: assetManifest?.features?.[it.kind]
49079
49144
  })),
49080
49145
  [items, assetManifest]
49081
49146
  );
@@ -49136,7 +49201,6 @@ function RoguelikeBoard({
49136
49201
  onTileHover: (x, y) => setHoveredTile({ x, y }),
49137
49202
  onTileLeave: () => setHoveredTile(null),
49138
49203
  scale,
49139
- assetBaseUrl: assetManifest?.baseUrl,
49140
49204
  assetManifest,
49141
49205
  unitScale,
49142
49206
  spriteHeightRatio,
@@ -49196,6 +49260,7 @@ var init_RoguelikeBoard = __esm({
49196
49260
  init_Stack();
49197
49261
  init_IsometricCanvas();
49198
49262
  init_boardEntity();
49263
+ init_makeAsset();
49199
49264
  DUNGEON_GRID_W = 16;
49200
49265
  DUNGEON_GRID_H = 16;
49201
49266
  DEFAULT_ENEMIES = [
@@ -49246,55 +49311,59 @@ function RoguelikeTemplate({
49246
49311
  }
49247
49312
  );
49248
49313
  }
49249
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
49314
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
49250
49315
  var init_RoguelikeTemplate = __esm({
49251
49316
  "components/game/templates/RoguelikeTemplate.tsx"() {
49252
49317
  init_RoguelikeBoard();
49318
+ init_makeAsset();
49253
49319
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
49320
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
49321
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
49322
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
49323
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
49254
49324
  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` }
49325
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49326
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49327
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49328
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49329
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49330
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
49331
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49332
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49333
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49334
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
49335
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
49336
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
49337
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
49338
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
49339
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
49340
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
49341
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
49342
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
49343
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
49344
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
49345
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49346
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49347
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49348
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49349
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
49280
49350
  ];
49281
49351
  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
- },
49352
+ terrains: makeAssetMap({
49353
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
49354
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
49355
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
49356
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
49357
+ }, "tile"),
49289
49358
  units: {
49290
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
49291
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
49359
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
49360
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
49292
49361
  },
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
- }
49362
+ features: makeAssetMap({
49363
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
49364
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
49365
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
49366
+ }, "item")
49298
49367
  };
49299
49368
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
49300
49369
  }
@@ -52168,7 +52237,6 @@ function SokobanBoard({
52168
52237
  units,
52169
52238
  features,
52170
52239
  assetManifest,
52171
- assetBaseUrl,
52172
52240
  scale,
52173
52241
  showMinimap,
52174
52242
  enableCamera,
@@ -52210,7 +52278,6 @@ function SpaceShmupBoard({
52210
52278
  units,
52211
52279
  features,
52212
52280
  assetManifest,
52213
- assetBaseUrl,
52214
52281
  scale,
52215
52282
  showMinimap,
52216
52283
  enableCamera,
@@ -52252,7 +52319,6 @@ function SpaceStationBoard({
52252
52319
  units,
52253
52320
  features,
52254
52321
  assetManifest,
52255
- assetBaseUrl,
52256
52322
  scale,
52257
52323
  showMinimap,
52258
52324
  enableCamera,
@@ -52387,7 +52453,6 @@ function SportsBoard({
52387
52453
  units,
52388
52454
  features,
52389
52455
  assetManifest,
52390
- assetBaseUrl,
52391
52456
  scale,
52392
52457
  showMinimap,
52393
52458
  enableCamera,
@@ -54231,7 +54296,6 @@ function TanksBoard({
54231
54296
  units,
54232
54297
  features,
54233
54298
  assetManifest,
54234
- assetBaseUrl,
54235
54299
  scale,
54236
54300
  showMinimap,
54237
54301
  enableCamera,
@@ -54509,15 +54573,6 @@ var init_ToastSlot = __esm({
54509
54573
  ToastSlot.displayName = "ToastSlot";
54510
54574
  }
54511
54575
  });
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
54576
  function readPlayer(v) {
54522
54577
  if (v == null || typeof v !== "object") return void 0;
54523
54578
  const o = v;
@@ -54570,10 +54625,10 @@ function TopDownShooterBoard({
54570
54625
  const wave = propWave ?? num(board.wave, 1);
54571
54626
  const lives = propLives ?? num(board.lives, 3);
54572
54627
  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);
54628
+ const playerSprite = assetManifest?.units?.player?.url;
54629
+ const enemySprite = assetManifest?.units?.enemy?.url;
54630
+ const projectileSprite = assetManifest?.features?.projectile?.url;
54631
+ const backgroundSprite = assetManifest?.background;
54577
54632
  const spriteUrls = useMemo(
54578
54633
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
54579
54634
  [playerSprite, enemySprite, projectileSprite]
@@ -54740,7 +54795,6 @@ function TopDownShooterBoard({
54740
54795
  width,
54741
54796
  height,
54742
54797
  backgroundImage: backgroundSprite,
54743
- assetBaseUrl: assetManifest?.baseUrl,
54744
54798
  onDraw
54745
54799
  }
54746
54800
  ),
@@ -54865,15 +54919,6 @@ var init_TopDownShooterTemplate = __esm({
54865
54919
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
54866
54920
  }
54867
54921
  });
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
54922
  function buildDefaultTDTiles() {
54878
54923
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
54879
54924
  const tiles = [];
@@ -54893,18 +54938,18 @@ function buildDefaultTDTiles() {
54893
54938
  function tilesToIso2(tiles, manifest) {
54894
54939
  return tiles.map((t) => {
54895
54940
  const key = t.terrain ?? "ground";
54896
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
54941
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
54897
54942
  return {
54898
54943
  x: t.x,
54899
54944
  y: t.y,
54900
54945
  terrain: t.terrain,
54901
- terrainSprite: sprite,
54946
+ terrainSprite,
54902
54947
  passable: t.passable
54903
54948
  };
54904
54949
  });
54905
54950
  }
54906
54951
  function creepsToUnits(creeps, manifest) {
54907
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
54952
+ const sprite = manifest?.units?.creep;
54908
54953
  return creeps.map((c) => ({
54909
54954
  id: c.id,
54910
54955
  position: { x: c.x, y: c.y },
@@ -54922,14 +54967,14 @@ function heroToUnit(hero, manifest) {
54922
54967
  position: { x: hero.x, y: hero.y },
54923
54968
  name: "Hero",
54924
54969
  team: "player",
54925
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
54970
+ sprite: manifest?.units?.hero,
54926
54971
  unitType: "hero",
54927
54972
  health: 1,
54928
54973
  maxHealth: 1
54929
54974
  };
54930
54975
  }
54931
54976
  function towersToFeatures(towers, manifest) {
54932
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
54977
+ const sprite = manifest?.features?.tower;
54933
54978
  return towers.map((t) => ({
54934
54979
  id: t.id,
54935
54980
  x: t.x,
@@ -55127,7 +55172,6 @@ function TowerDefenseBoard({
55127
55172
  tiles: isoTiles,
55128
55173
  units: isoUnits,
55129
55174
  features: towerFeatures,
55130
- assetBaseUrl: assetManifest?.baseUrl,
55131
55175
  assetManifest,
55132
55176
  validMoves,
55133
55177
  hoveredTile,
@@ -55171,6 +55215,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
55171
55215
  var init_TowerDefenseBoard = __esm({
55172
55216
  "components/game/organisms/TowerDefenseBoard.tsx"() {
55173
55217
  "use client";
55218
+ init_makeAsset();
55174
55219
  init_cn();
55175
55220
  init_useEventBus();
55176
55221
  init_Box();
@@ -55500,15 +55545,6 @@ var init_UncontrolledBattleBoard = __esm({
55500
55545
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
55501
55546
  }
55502
55547
  });
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
55548
  function VisualNovelBoard({
55513
55549
  entity,
55514
55550
  nodes: propNodes,
@@ -55543,11 +55579,11 @@ function VisualNovelBoard({
55543
55579
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
55544
55580
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
55545
55581
  const backgroundImage = useMemo(
55546
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
55582
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
55547
55583
  [assetManifest, currentNode?.backgroundKey]
55548
55584
  );
55549
55585
  const portraitUrl = useMemo(
55550
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
55586
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
55551
55587
  [assetManifest, currentNode?.portraitKey]
55552
55588
  );
55553
55589
  const dialogueChoices = useMemo(
@@ -55721,7 +55757,7 @@ function buildDefaultWorldTiles() {
55721
55757
  for (let x = 0; x < WORLD_GRID_W; x++) {
55722
55758
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
55723
55759
  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 });
55760
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
55725
55761
  }
55726
55762
  }
55727
55763
  return tiles;
@@ -55765,7 +55801,12 @@ function WorldMapBoard({
55765
55801
  const resolved = boardEntity(entity);
55766
55802
  const entityUnits = rows(resolved?.units);
55767
55803
  const entityTiles = rows(resolved?.tiles);
55768
- const features = propFeatures ?? rows(resolved?.features);
55804
+ const features = propFeatures ?? rows(resolved?.features).map((r2) => ({
55805
+ id: r2.id == null ? void 0 : str(r2.id),
55806
+ x: num(r2.x),
55807
+ y: num(r2.y),
55808
+ type: str(r2.type)
55809
+ }));
55769
55810
  const selectedHeroId = resolved?.selectedHeroId ?? null;
55770
55811
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
55771
55812
  const backgroundImage = resolved?.backgroundImage;
@@ -55775,7 +55816,7 @@ function WorldMapBoard({
55775
55816
  x: num(t.x),
55776
55817
  y: num(t.y),
55777
55818
  terrain: str(t.terrain),
55778
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
55819
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
55779
55820
  passable: t.passable !== false
55780
55821
  })),
55781
55822
  [entityTiles]
@@ -55791,7 +55832,7 @@ function WorldMapBoard({
55791
55832
  team: str(u.team) === "enemy" ? "enemy" : "player",
55792
55833
  health: num(u.health) || 100,
55793
55834
  maxHealth: num(u.maxHealth) || 100,
55794
- sprite: u.sprite == null ? void 0 : str(u.sprite)
55835
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
55795
55836
  })),
55796
55837
  [entityUnits, propUnits]
55797
55838
  );
@@ -55973,7 +56014,6 @@ function WorldMapBoard({
55973
56014
  onTileHover: (x, y) => setHoveredTile({ x, y }),
55974
56015
  onTileLeave: () => setHoveredTile(null),
55975
56016
  scale,
55976
- assetBaseUrl: assetManifest?.baseUrl,
55977
56017
  assetManifest,
55978
56018
  backgroundImage,
55979
56019
  effectSpriteUrls,
@@ -55996,6 +56036,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
55996
56036
  var init_WorldMapBoard = __esm({
55997
56037
  "components/game/organisms/WorldMapBoard.tsx"() {
55998
56038
  "use client";
56039
+ init_makeAsset();
55999
56040
  init_cn();
56000
56041
  init_useEventBus();
56001
56042
  init_Stack();
@@ -56049,62 +56090,66 @@ function WorldMapTemplate({
56049
56090
  }
56050
56091
  );
56051
56092
  }
56052
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
56093
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
56053
56094
  var init_WorldMapTemplate = __esm({
56054
56095
  "components/game/templates/WorldMapTemplate.tsx"() {
56055
56096
  init_WorldMapBoard();
56097
+ init_makeAsset();
56056
56098
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
56099
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
56100
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
56101
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
56102
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
56057
56103
  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` }
56104
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56105
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56106
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
56107
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56108
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56109
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
56110
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56111
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56112
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56113
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
56114
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
56115
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
56116
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
56117
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
56118
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
56119
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
56120
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
56121
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
56122
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
56123
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
56124
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
56125
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
56126
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
56127
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
56128
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
56083
56129
  ];
56084
56130
  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` }
56131
+ { 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") },
56132
+ { 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
56133
  ];
56088
56134
  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` }
56135
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
56136
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
56091
56137
  ];
56092
56138
  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
- },
56139
+ terrains: makeAssetMap({
56140
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
56141
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
56142
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
56143
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
56144
+ }, "tile"),
56100
56145
  units: {
56101
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
56102
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
56146
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
56147
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
56103
56148
  },
56104
- features: {
56105
- capital: "/scenes/world/capital.png",
56106
- power_node: "/world-map/power_node.png"
56107
- }
56149
+ features: makeAssetMap({
56150
+ capital: `${CDN5}/scenes/world/capital.png`,
56151
+ power_node: `${CDN5}/world-map/power_node.png`
56152
+ }, "decoration")
56108
56153
  };
56109
56154
  WorldMapTemplate.displayName = "WorldMapTemplate";
56110
56155
  }