@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
@@ -10739,7 +10739,7 @@ function ScoreDisplay({
10739
10739
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
10740
10740
  "img",
10741
10741
  {
10742
- src: assetUrl,
10742
+ src: assetUrl.url,
10743
10743
  alt: "",
10744
10744
  width: 20,
10745
10745
  height: 20,
@@ -10764,7 +10764,11 @@ var init_ScoreDisplay = __esm({
10764
10764
  lg: "text-2xl",
10765
10765
  xl: "text-4xl"
10766
10766
  };
10767
- DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
10767
+ DEFAULT_ASSET_URL = {
10768
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png",
10769
+ role: "effect",
10770
+ category: "effect"
10771
+ };
10768
10772
  ScoreDisplay.displayName = "ScoreDisplay";
10769
10773
  }
10770
10774
  });
@@ -10840,7 +10844,7 @@ function ControlButton({
10840
10844
  children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
10841
10845
  "img",
10842
10846
  {
10843
- src: assetUrl,
10847
+ src: assetUrl.url,
10844
10848
  alt: "",
10845
10849
  width: 24,
10846
10850
  height: 24,
@@ -10880,7 +10884,11 @@ var init_ControlButton = __esm({
10880
10884
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
10881
10885
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
10882
10886
  };
10883
- DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
10887
+ DEFAULT_ASSET_URL2 = {
10888
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
10889
+ role: "effect",
10890
+ category: "effect"
10891
+ };
10884
10892
  ControlButton.displayName = "ControlButton";
10885
10893
  }
10886
10894
  });
@@ -10919,7 +10927,7 @@ var init_spriteAnimation = __esm({
10919
10927
  }
10920
10928
  });
10921
10929
  function Sprite({
10922
- spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
10930
+ spritesheet = DEFAULT_SPRITESHEET,
10923
10931
  frameWidth = 64,
10924
10932
  frameHeight = 64,
10925
10933
  frame = 0,
@@ -10972,7 +10980,7 @@ function Sprite({
10972
10980
  position: "absolute",
10973
10981
  width: frameWidth,
10974
10982
  height: frameHeight,
10975
- backgroundImage: `url(${spritesheet})`,
10983
+ backgroundImage: `url(${spritesheet.url})`,
10976
10984
  backgroundPosition,
10977
10985
  backgroundRepeat: "no-repeat",
10978
10986
  imageRendering: "pixelated",
@@ -10985,11 +10993,17 @@ function Sprite({
10985
10993
  }
10986
10994
  );
10987
10995
  }
10996
+ var DEFAULT_SPRITESHEET;
10988
10997
  var init_Sprite = __esm({
10989
10998
  "components/game/atoms/Sprite.tsx"() {
10990
10999
  "use client";
10991
11000
  init_useEventBus();
10992
11001
  init_spriteAnimation();
11002
+ DEFAULT_SPRITESHEET = {
11003
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
11004
+ role: "tile",
11005
+ category: "tile"
11006
+ };
10993
11007
  }
10994
11008
  });
10995
11009
  function StateIndicator({
@@ -11019,7 +11033,7 @@ function StateIndicator({
11019
11033
  /* @__PURE__ */ jsxRuntime.jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
11020
11034
  "img",
11021
11035
  {
11022
- src: assetUrl,
11036
+ src: assetUrl.url,
11023
11037
  alt: displayLabel,
11024
11038
  width: 16,
11025
11039
  height: 16,
@@ -11038,7 +11052,11 @@ var init_StateIndicator = __esm({
11038
11052
  init_Box();
11039
11053
  init_Icon();
11040
11054
  init_cn();
11041
- DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
11055
+ DEFAULT_ASSET_URL3 = {
11056
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
11057
+ role: "effect",
11058
+ category: "item"
11059
+ };
11042
11060
  DEFAULT_STATE_STYLES = {
11043
11061
  idle: { icon: "\u23F8", bgClass: "bg-muted" },
11044
11062
  active: { icon: "\u25B6", bgClass: "bg-success" },
@@ -11136,7 +11154,7 @@ function ResourceCounter({
11136
11154
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
11137
11155
  "img",
11138
11156
  {
11139
- src: assetUrl,
11157
+ src: assetUrl.url,
11140
11158
  alt: label,
11141
11159
  width: sizes.img,
11142
11160
  height: sizes.img,
@@ -11169,7 +11187,11 @@ var init_ResourceCounter = __esm({
11169
11187
  error: "text-error",
11170
11188
  muted: "text-muted-foreground"
11171
11189
  };
11172
- DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
11190
+ DEFAULT_ASSET_URL4 = {
11191
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
11192
+ role: "effect",
11193
+ category: "world"
11194
+ };
11173
11195
  sizeMap5 = {
11174
11196
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
11175
11197
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -11215,7 +11237,7 @@ function ItemSlot({
11215
11237
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
11216
11238
  "img",
11217
11239
  {
11218
- src: assetUrl,
11240
+ src: assetUrl?.url,
11219
11241
  alt: label,
11220
11242
  width: px,
11221
11243
  height: px,
@@ -11263,7 +11285,11 @@ var init_ItemSlot = __esm({
11263
11285
  epic: "shadow-lg",
11264
11286
  legendary: "shadow-lg"
11265
11287
  };
11266
- DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
11288
+ DEFAULT_ASSET_URL5 = {
11289
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
11290
+ role: "effect",
11291
+ category: "item"
11292
+ };
11267
11293
  assetSizeMap = {
11268
11294
  sm: 28,
11269
11295
  md: 40,
@@ -11309,7 +11335,7 @@ function TurnIndicator({
11309
11335
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
11310
11336
  "img",
11311
11337
  {
11312
- src: assetUrl,
11338
+ src: assetUrl.url,
11313
11339
  alt: "",
11314
11340
  width: 12,
11315
11341
  height: 12,
@@ -11332,7 +11358,11 @@ var init_TurnIndicator = __esm({
11332
11358
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
11333
11359
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
11334
11360
  };
11335
- DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
11361
+ DEFAULT_ASSET_URL6 = {
11362
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
11363
+ role: "effect",
11364
+ category: "effect"
11365
+ };
11336
11366
  TurnIndicator.displayName = "TurnIndicator";
11337
11367
  }
11338
11368
  });
@@ -11371,7 +11401,7 @@ function ComboCounter({
11371
11401
  assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
11372
11402
  "img",
11373
11403
  {
11374
- src: assetUrl,
11404
+ src: assetUrl.url,
11375
11405
  alt: "combo",
11376
11406
  width: 24,
11377
11407
  height: 24,
@@ -11397,7 +11427,11 @@ var DEFAULT_ASSET_URL7, sizeMap8;
11397
11427
  var init_ComboCounter = __esm({
11398
11428
  "components/game/atoms/ComboCounter.tsx"() {
11399
11429
  init_cn();
11400
- DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
11430
+ DEFAULT_ASSET_URL7 = {
11431
+ url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
11432
+ role: "effect",
11433
+ category: "effect"
11434
+ };
11401
11435
  sizeMap8 = {
11402
11436
  sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
11403
11437
  md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
@@ -11517,7 +11551,7 @@ function WaypointMarker({
11517
11551
  children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
11518
11552
  "img",
11519
11553
  {
11520
- src: assetUrl,
11554
+ src: assetUrl.url,
11521
11555
  alt: label,
11522
11556
  width: sizes.img,
11523
11557
  height: sizes.img,
@@ -11546,7 +11580,11 @@ var init_WaypointMarker = __esm({
11546
11580
  "components/game/atoms/WaypointMarker.tsx"() {
11547
11581
  init_cn();
11548
11582
  init_Icon();
11549
- DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
11583
+ DEFAULT_ASSET_URL8 = {
11584
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
11585
+ role: "effect",
11586
+ category: "world"
11587
+ };
11550
11588
  sizeMap10 = {
11551
11589
  sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
11552
11590
  md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
@@ -11587,7 +11625,7 @@ function StatusEffect({
11587
11625
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
11588
11626
  "img",
11589
11627
  {
11590
- src: assetUrl,
11628
+ src: assetUrl.url,
11591
11629
  alt: label,
11592
11630
  width: sizes.img,
11593
11631
  height: sizes.img,
@@ -11626,7 +11664,11 @@ var init_StatusEffect = __esm({
11626
11664
  "components/game/atoms/StatusEffect.tsx"() {
11627
11665
  init_cn();
11628
11666
  init_Icon();
11629
- DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
11667
+ DEFAULT_ASSET_URL9 = {
11668
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
11669
+ role: "effect",
11670
+ category: "effect"
11671
+ };
11630
11672
  sizeMap11 = {
11631
11673
  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 },
11632
11674
  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 },
@@ -11664,7 +11706,7 @@ function DamageNumber({
11664
11706
  assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
11665
11707
  "img",
11666
11708
  {
11667
- src: assetUrl,
11709
+ src: assetUrl.url,
11668
11710
  alt: "",
11669
11711
  width: 14,
11670
11712
  height: 14,
@@ -11700,14 +11742,18 @@ var init_DamageNumber = __esm({
11700
11742
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
11701
11743
  }
11702
11744
  `;
11703
- DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
11745
+ DEFAULT_ASSET_URL10 = {
11746
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
11747
+ role: "effect",
11748
+ category: "effect"
11749
+ };
11704
11750
  DamageNumber.displayName = "DamageNumber";
11705
11751
  }
11706
11752
  });
11707
11753
  function DialogueBubble({
11708
11754
  speaker = "Hero",
11709
11755
  text = "The dungeon awaits. Choose your path wisely.",
11710
- portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
11756
+ portrait = DEFAULT_PORTRAIT,
11711
11757
  position = "bottom",
11712
11758
  className
11713
11759
  }) {
@@ -11723,7 +11769,7 @@ function DialogueBubble({
11723
11769
  portrait && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsxRuntime.jsx(
11724
11770
  "img",
11725
11771
  {
11726
- src: portrait,
11772
+ src: portrait?.url,
11727
11773
  alt: speaker ?? "speaker",
11728
11774
  className: "w-full h-full object-cover"
11729
11775
  }
@@ -11736,9 +11782,15 @@ function DialogueBubble({
11736
11782
  }
11737
11783
  );
11738
11784
  }
11785
+ var DEFAULT_PORTRAIT;
11739
11786
  var init_DialogueBubble = __esm({
11740
11787
  "components/game/atoms/DialogueBubble.tsx"() {
11741
11788
  init_cn();
11789
+ DEFAULT_PORTRAIT = {
11790
+ url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
11791
+ role: "effect",
11792
+ category: "character"
11793
+ };
11742
11794
  DialogueBubble.displayName = "DialogueBubble";
11743
11795
  }
11744
11796
  });
@@ -11782,7 +11834,7 @@ function ChoiceButton({
11782
11834
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
11783
11835
  "img",
11784
11836
  {
11785
- src: assetUrl,
11837
+ src: assetUrl.url,
11786
11838
  alt: "",
11787
11839
  width: 16,
11788
11840
  height: 16,
@@ -11852,7 +11904,7 @@ function ActionButton({
11852
11904
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
11853
11905
  "img",
11854
11906
  {
11855
- src: assetUrl,
11907
+ src: assetUrl.url,
11856
11908
  alt: "",
11857
11909
  width: 16,
11858
11910
  height: 16,
@@ -11896,7 +11948,11 @@ var init_ActionButton = __esm({
11896
11948
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
11897
11949
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
11898
11950
  };
11899
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
11951
+ DEFAULT_ASSET_URL11 = {
11952
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
11953
+ role: "effect",
11954
+ category: "effect"
11955
+ };
11900
11956
  ActionButton.displayName = "ActionButton";
11901
11957
  }
11902
11958
  });
@@ -14483,12 +14539,7 @@ var init_useCanvasGestures = __esm({
14483
14539
  }
14484
14540
  });
14485
14541
  function unitAtlasUrl(unit) {
14486
- if (unit.spriteSheet) return unit.spriteSheet;
14487
- const sprite = unit.sprite;
14488
- if (!sprite) return null;
14489
- const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
14490
- if (!match) return null;
14491
- return `${match[1]}.json`;
14542
+ return unit.spriteSheet?.url ?? null;
14492
14543
  }
14493
14544
  function resolveSheetUrl(atlasUrl, relativeSheetPath) {
14494
14545
  try {
@@ -14684,7 +14735,6 @@ function IsometricCanvas({
14684
14735
  // Tuning
14685
14736
  diamondTopY: diamondTopYProp,
14686
14737
  // Remote asset loading
14687
- assetBaseUrl,
14688
14738
  assetManifest
14689
14739
  }) {
14690
14740
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -14766,54 +14816,48 @@ function IsometricCanvas({
14766
14816
  const attackTargetSet = React96.useMemo(() => {
14767
14817
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
14768
14818
  }, [attackTargets]);
14769
- const resolveManifestUrl7 = React96.useCallback((relativePath) => {
14770
- if (!relativePath) return void 0;
14771
- if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
14772
- return relativePath;
14773
- }, [assetBaseUrl]);
14774
14819
  const spriteUrls = React96.useMemo(() => {
14775
14820
  const urls = [];
14776
14821
  for (const tile of sortedTiles) {
14777
- if (tile.terrainSprite) urls.push(tile.terrainSprite);
14822
+ if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
14778
14823
  else if (getTerrainSprite) {
14779
14824
  const url = getTerrainSprite(tile.terrain ?? "");
14780
14825
  if (url) urls.push(url);
14781
14826
  } else {
14782
- const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14827
+ const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
14783
14828
  if (url) urls.push(url);
14784
14829
  }
14785
14830
  }
14786
14831
  for (const feature of features) {
14787
- if (feature.sprite) urls.push(feature.sprite);
14832
+ if (feature.sprite) urls.push(feature.sprite.url);
14788
14833
  else if (getFeatureSprite) {
14789
14834
  const url = getFeatureSprite(feature.type);
14790
14835
  if (url) urls.push(url);
14791
14836
  } else {
14792
- const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
14837
+ const url = assetManifest?.features?.[feature.type]?.url;
14793
14838
  if (url) urls.push(url);
14794
14839
  }
14795
14840
  }
14796
14841
  for (const unit of units) {
14797
- if (unit.sprite) urls.push(unit.sprite);
14842
+ if (unit.sprite) urls.push(unit.sprite.url);
14798
14843
  else if (getUnitSprite) {
14799
14844
  const url = getUnitSprite(unit);
14800
14845
  if (url) urls.push(url);
14801
14846
  } else if (unit.unitType) {
14802
- const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
14847
+ const url = assetManifest?.units?.[unit.unitType]?.url;
14803
14848
  if (url) urls.push(url);
14804
14849
  }
14805
14850
  }
14806
14851
  if (assetManifest?.effects) {
14807
- for (const path of Object.values(assetManifest.effects)) {
14808
- const url = resolveManifestUrl7(path);
14809
- if (url) urls.push(url);
14852
+ for (const asset of Object.values(assetManifest.effects)) {
14853
+ if (asset.url) urls.push(asset.url);
14810
14854
  }
14811
14855
  }
14812
14856
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
14813
14857
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
14814
14858
  if (backgroundImage) urls.push(backgroundImage);
14815
14859
  return [...new Set(urls.filter(Boolean))];
14816
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
14860
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest]);
14817
14861
  const { getImage, pendingCount: _imagePendingCount } = useImageCache(spriteUrls);
14818
14862
  React96.useEffect(() => {
14819
14863
  if (typeof window === "undefined") return;
@@ -14838,14 +14882,14 @@ function IsometricCanvas({
14838
14882
  lerpToTarget
14839
14883
  } = useCamera();
14840
14884
  const resolveTerrainSpriteUrl = React96.useCallback((tile) => {
14841
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
14842
- }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
14885
+ return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
14886
+ }, [getTerrainSprite, assetManifest]);
14843
14887
  const resolveFeatureSpriteUrl = React96.useCallback((featureType) => {
14844
- return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
14845
- }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
14888
+ return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
14889
+ }, [getFeatureSprite, assetManifest]);
14846
14890
  const resolveUnitSpriteUrl = React96.useCallback((unit) => {
14847
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
14848
- }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
14891
+ return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
14892
+ }, [getUnitSprite, assetManifest]);
14849
14893
  const miniMapTiles = React96.useMemo(() => {
14850
14894
  if (!showMinimap) return [];
14851
14895
  return sortedTiles.map((t2) => ({
@@ -14992,7 +15036,7 @@ function IsometricCanvas({
14992
15036
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
14993
15037
  continue;
14994
15038
  }
14995
- const spriteUrl = feature.sprite || resolveFeatureSpriteUrl(feature.type);
15039
+ const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
14996
15040
  const img = spriteUrl ? getImage(spriteUrl) : null;
14997
15041
  const centerX = pos.x + scaledTileWidth / 2;
14998
15042
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
@@ -15041,12 +15085,12 @@ function IsometricCanvas({
15041
15085
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
15042
15086
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
15043
15087
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
15088
+ const unitIsSheet = unit.sprite?.dimension === "2d" && (unit.sprite?.animations?.length ?? 0) > 0;
15044
15089
  const SHEET_ROWS = 5;
15045
15090
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
15046
15091
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
15047
- const imgIsSheet = img ? img.naturalWidth % SHEET_COLUMNS === 0 && img.naturalHeight % SHEET_ROWS === 0 && Math.abs(sheetFrameW - sheetFrameH) < 2 : false;
15048
- const frameW = imgIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
15049
- const frameH = imgIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
15092
+ const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
15093
+ const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
15050
15094
  const ar = frameW / (frameH || 1);
15051
15095
  let drawH = unitDrawH;
15052
15096
  let drawW = unitDrawH * ar;
@@ -15061,7 +15105,7 @@ function IsometricCanvas({
15061
15105
  ctx.save();
15062
15106
  ctx.globalAlpha = 0.25;
15063
15107
  if (img) {
15064
- if (imgIsSheet) {
15108
+ if (unitIsSheet) {
15065
15109
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
15066
15110
  } else {
15067
15111
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
@@ -15109,7 +15153,7 @@ function IsometricCanvas({
15109
15153
  } else if (img) {
15110
15154
  const spriteY = groundY - drawH - breatheOffset;
15111
15155
  const drawUnit = (x) => {
15112
- if (imgIsSheet) {
15156
+ if (unitIsSheet) {
15113
15157
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
15114
15158
  } else {
15115
15159
  ctx.drawImage(img, x, spriteY, drawW, drawH);
@@ -15136,7 +15180,7 @@ function IsometricCanvas({
15136
15180
  }
15137
15181
  }
15138
15182
  for (const fx of effects) {
15139
- const spriteUrl = resolveManifestUrl7(assetManifest?.effects?.[fx.key]);
15183
+ const spriteUrl = assetManifest?.effects?.[fx.key]?.url;
15140
15184
  if (!spriteUrl) continue;
15141
15185
  const img = getImage(spriteUrl);
15142
15186
  if (!img) continue;
@@ -15180,7 +15224,6 @@ function IsometricCanvas({
15180
15224
  backgroundImage,
15181
15225
  cameraRef,
15182
15226
  unitScale,
15183
- resolveManifestUrl7,
15184
15227
  assetManifest
15185
15228
  ]);
15186
15229
  React96.useEffect(() => {
@@ -15458,6 +15501,42 @@ var init_boardEntity = __esm({
15458
15501
  "components/game/organisms/boardEntity.ts"() {
15459
15502
  }
15460
15503
  });
15504
+
15505
+ // components/game/organisms/utils/makeAsset.ts
15506
+ function makeAsset(url, role, overrides = {}) {
15507
+ const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
15508
+ return {
15509
+ url,
15510
+ role,
15511
+ category: url.split("/").pop()?.replace(/\.[^.]+$/, "") ?? role,
15512
+ ...defaults,
15513
+ ...overrides
15514
+ };
15515
+ }
15516
+ function makeAssetMap(record, role, overrides = {}) {
15517
+ const result = {};
15518
+ for (const [key, url] of Object.entries(record)) {
15519
+ result[key] = makeAsset(url, role, overrides);
15520
+ }
15521
+ return result;
15522
+ }
15523
+ var ROLE_DEFAULTS;
15524
+ var init_makeAsset = __esm({
15525
+ "components/game/organisms/utils/makeAsset.ts"() {
15526
+ ROLE_DEFAULTS = {
15527
+ tile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15528
+ decoration: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15529
+ effect: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15530
+ item: { dimension: "2d", animations: ["static"], aspect: "5:7" },
15531
+ player: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15532
+ enemy: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15533
+ npc: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
15534
+ projectile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
15535
+ vehicle: { dimension: "2d", animations: ["idle", "walk"], aspect: "1:1" },
15536
+ ui: { dimension: "2d", animations: ["static"], aspect: "1:1" }
15537
+ };
15538
+ }
15539
+ });
15461
15540
  function buildDefaultBattleTiles() {
15462
15541
  const tiles = [];
15463
15542
  for (let y = 0; y < BATTLE_GRID_H; y++) {
@@ -15516,14 +15595,14 @@ function BattleBoard({
15516
15595
  if (o === null || typeof o.x !== "number" || typeof o.y !== "number") return [];
15517
15596
  const tile = { x: o.x, y: o.y };
15518
15597
  if (typeof o.terrain === "string") tile.terrain = o.terrain;
15519
- if (typeof o.terrainSprite === "string") tile.terrainSprite = o.terrainSprite;
15598
+ if (typeof o.terrainSprite === "string") tile.terrainSprite = makeAsset(o.terrainSprite, "tile");
15520
15599
  if (typeof o.passable === "boolean") tile.passable = o.passable;
15521
15600
  if (typeof o.movementCost === "number") tile.movementCost = o.movementCost;
15522
15601
  if (typeof o.elevation === "number") tile.elevation = o.elevation;
15523
15602
  if (typeof o.type === "string") tile.type = o.type;
15524
15603
  if (typeof o.tileType === "string") tile.tileType = o.tileType;
15525
15604
  if (typeof o.id === "string") tile.id = o.id;
15526
- if (typeof o.modelUrl === "string") tile.modelUrl = o.modelUrl;
15605
+ if (typeof o.modelUrl === "string") tile.modelUrl = makeAsset(o.modelUrl, "decoration", { dimension: "3d" });
15527
15606
  return [tile];
15528
15607
  }) : []);
15529
15608
  const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
@@ -15532,10 +15611,10 @@ function BattleBoard({
15532
15611
  if (o === null || typeof o.type !== "string" || typeof o.x !== "number" || typeof o.y !== "number") return [];
15533
15612
  const feat = { type: o.type, x: o.x, y: o.y };
15534
15613
  if (typeof o.id === "string") feat.id = o.id;
15535
- if (typeof o.sprite === "string") feat.sprite = o.sprite;
15614
+ if (typeof o.sprite === "string") feat.sprite = makeAsset(o.sprite, "decoration");
15536
15615
  if (typeof o.color === "string") feat.color = o.color;
15537
15616
  if (typeof o.elevation === "number") feat.elevation = o.elevation;
15538
- if (typeof o.assetUrl === "string") feat.assetUrl = o.assetUrl;
15617
+ if (typeof o.assetUrl === "string") feat.assetUrl = makeAsset(o.assetUrl, "decoration", { dimension: "3d" });
15539
15618
  return [feat];
15540
15619
  }) : []);
15541
15620
  const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
@@ -15651,7 +15730,7 @@ function BattleBoard({
15651
15730
  maxHealth: num(unit.maxHealth),
15652
15731
  unitType: unit.unitType == null ? void 0 : str(unit.unitType),
15653
15732
  heroId: unit.heroId == null ? void 0 : str(unit.heroId),
15654
- sprite: unit.sprite == null ? void 0 : str(unit.sprite),
15733
+ sprite: unit.sprite == null ? void 0 : makeAsset(str(unit.sprite), "npc"),
15655
15734
  traits: unitTraits?.map((tr) => ({
15656
15735
  name: tr.name,
15657
15736
  currentState: tr.currentState,
@@ -15801,7 +15880,6 @@ function BattleBoard({
15801
15880
  onTileHover: (x, y) => setHoveredTile({ x, y }),
15802
15881
  onTileLeave: () => setHoveredTile(null),
15803
15882
  scale,
15804
- assetBaseUrl: assetManifest?.baseUrl,
15805
15883
  assetManifest,
15806
15884
  backgroundImage,
15807
15885
  onDrawEffects,
@@ -15879,15 +15957,16 @@ var init_BattleBoard = __esm({
15879
15957
  init_IsometricCanvas();
15880
15958
  init_boardEntity();
15881
15959
  init_isometric();
15960
+ init_makeAsset();
15882
15961
  BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
15883
15962
  BATTLE_GRID_W = 16;
15884
15963
  BATTLE_GRID_H = 16;
15885
15964
  BATTLE_TERRAIN_SPRITES = [
15886
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
15887
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
15888
- `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
15889
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
15890
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
15965
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`, "tile"),
15966
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile"),
15967
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`, "tile"),
15968
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, "tile"),
15969
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile")
15891
15970
  ];
15892
15971
  DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
15893
15972
  BattleBoard.displayName = "BattleBoard";
@@ -15926,61 +16005,64 @@ function BattleTemplate({
15926
16005
  }
15927
16006
  );
15928
16007
  }
15929
- var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
16008
+ var CDN, STONE, DIRT, GRASS, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
15930
16009
  var init_BattleTemplate = __esm({
15931
16010
  "components/game/templates/BattleTemplate.tsx"() {
15932
16011
  init_BattleBoard();
16012
+ init_makeAsset();
15933
16013
  CDN = "https://almadar-kflow-assets.web.app/shared";
16014
+ STONE = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`, "tile");
16015
+ DIRT = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`, "tile");
16016
+ GRASS = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`, "tile");
15934
16017
  DEFAULT_BATTLE_TILES2 = [
15935
- { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15936
- { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15937
- { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15938
- { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15939
- { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15940
- { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15941
- { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
15942
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15943
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15944
- { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15945
- { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15946
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15947
- { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
15948
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15949
- { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15950
- { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15951
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15952
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
15953
- { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
15954
- { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15955
- { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15956
- { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15957
- { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15958
- { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
15959
- { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` }
16018
+ { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
16019
+ { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
16020
+ { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
16021
+ { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
16022
+ { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
16023
+ { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
16024
+ { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: DIRT },
16025
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
16026
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
16027
+ { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
16028
+ { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
16029
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
16030
+ { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: DIRT },
16031
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
16032
+ { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
16033
+ { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
16034
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
16035
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
16036
+ { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: DIRT },
16037
+ { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
16038
+ { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
16039
+ { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
16040
+ { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
16041
+ { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
16042
+ { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: STONE }
15960
16043
  ];
15961
16044
  DEFAULT_BATTLE_UNITS = [
15962
- { 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` },
15963
- { 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` }
16045
+ { 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") },
16046
+ { 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") }
15964
16047
  ];
15965
16048
  DEFAULT_BATTLE_FEATURES = [
15966
- { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: `${CDN}/world-map/gold_mine.png` },
15967
- { id: "f2", x: 3, y: 1, type: "portal", sprite: `${CDN}/world-map/portal_open.png` }
16049
+ { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: makeAsset(`${CDN}/world-map/gold_mine.png`, "decoration") },
16050
+ { id: "f2", x: 3, y: 1, type: "portal", sprite: makeAsset(`${CDN}/world-map/portal_open.png`, "decoration") }
15968
16051
  ];
15969
16052
  DEFAULT_BATTLE_MANIFEST = {
15970
- baseUrl: CDN,
15971
- terrains: {
15972
- stone: "/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png",
15973
- dirt: "/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png",
15974
- grass: "/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png"
15975
- },
15976
- units: {
15977
- worker: "/sprite-sheets/amir-sprite-sheet-se.png",
15978
- guardian: "/sprite-sheets/destroyer-sprite-sheet-sw.png"
15979
- },
15980
- features: {
15981
- gold_mine: "/world-map/gold_mine.png",
15982
- portal: "/world-map/portal_open.png"
15983
- }
16053
+ terrains: makeAssetMap({
16054
+ stone: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`,
16055
+ dirt: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`,
16056
+ grass: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`
16057
+ }, "tile"),
16058
+ units: makeAssetMap({
16059
+ worker: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png`,
16060
+ guardian: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`
16061
+ }, "npc"),
16062
+ features: makeAssetMap({
16063
+ gold_mine: `${CDN}/world-map/gold_mine.png`,
16064
+ portal: `${CDN}/world-map/portal_open.png`
16065
+ }, "decoration")
15984
16066
  };
15985
16067
  BattleTemplate.displayName = "BattleTemplate";
15986
16068
  }
@@ -17368,7 +17450,6 @@ function BoardgameBoard({
17368
17450
  units,
17369
17451
  features,
17370
17452
  assetManifest,
17371
- assetBaseUrl,
17372
17453
  scale,
17373
17454
  showMinimap,
17374
17455
  enableCamera,
@@ -22438,7 +22519,7 @@ function CardHand({
22438
22519
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsxRuntime.jsx(
22439
22520
  "img",
22440
22521
  {
22441
- src: card.iconUrl,
22522
+ src: card.iconUrl.url,
22442
22523
  alt: card.title ?? card.id,
22443
22524
  width: art,
22444
22525
  height: art,
@@ -22496,15 +22577,6 @@ var init_CardHand = __esm({
22496
22577
  CardHand.displayName = "CardHand";
22497
22578
  }
22498
22579
  });
22499
- function resolveManifestUrl(manifest, relative) {
22500
- if (relative == null) return void 0;
22501
- if (/^https?:\/\//.test(relative)) return relative;
22502
- const base = manifest?.baseUrl;
22503
- if (base == null) return relative;
22504
- const cleanBase = base.replace(/\/$/, "");
22505
- const cleanRel = relative.replace(/^\//, "");
22506
- return `${cleanBase}/${cleanRel}`;
22507
- }
22508
22580
  function rowToCard(r2) {
22509
22581
  return {
22510
22582
  id: str(r2.id),
@@ -22518,7 +22590,7 @@ function rowToCard(r2) {
22518
22590
  function toHandCards(cards, manifest, mana) {
22519
22591
  return cards.map((c) => {
22520
22592
  const key = c.iconKey ?? c.id;
22521
- const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
22593
+ const iconUrl = manifest?.cards?.[key];
22522
22594
  return {
22523
22595
  id: c.id,
22524
22596
  iconUrl,
@@ -23632,7 +23704,6 @@ function CastleBoard({
23632
23704
  onTileHover: (x, y) => setHoveredTile({ x, y }),
23633
23705
  onTileLeave: () => setHoveredTile(null),
23634
23706
  scale,
23635
- assetBaseUrl: assetManifest?.baseUrl,
23636
23707
  assetManifest,
23637
23708
  backgroundImage
23638
23709
  }
@@ -23708,60 +23779,63 @@ function CastleTemplate({
23708
23779
  }
23709
23780
  );
23710
23781
  }
23711
- var CDN2, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
23782
+ var CDN2, WALL, FLOOR, FLOOR_CENTER, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
23712
23783
  var init_CastleTemplate = __esm({
23713
23784
  "components/game/templates/CastleTemplate.tsx"() {
23714
23785
  init_CastleBoard();
23786
+ init_makeAsset();
23715
23787
  CDN2 = "https://almadar-kflow-assets.web.app/shared";
23788
+ WALL = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`, "tile");
23789
+ FLOOR = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
23790
+ FLOOR_CENTER = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`, "tile");
23716
23791
  DEFAULT_CASTLE_TILES = [
23717
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23718
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23719
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23720
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23721
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23722
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23723
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23724
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23725
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23726
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23727
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23728
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23729
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png` },
23730
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23731
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23732
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23733
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23734
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23735
- { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
23736
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23737
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23738
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23739
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23740
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
23741
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` }
23792
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23793
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23794
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23795
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23796
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
23797
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
23798
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23799
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23800
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
23801
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
23802
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
23803
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
23804
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR_CENTER },
23805
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
23806
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
23807
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
23808
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23809
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23810
+ { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
23811
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
23812
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23813
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23814
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23815
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
23816
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: WALL }
23742
23817
  ];
23743
23818
  DEFAULT_CASTLE_UNITS = [
23744
- { 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` },
23745
- { 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` }
23819
+ { 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") },
23820
+ { 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") }
23746
23821
  ];
23747
23822
  DEFAULT_CASTLE_FEATURES = [
23748
- { id: "f1", x: 2, y: 2, type: "chest", sprite: `${CDN2}/world-map/treasure_chest_closed.png` },
23749
- { id: "f2", x: 3, y: 1, type: "crystal", sprite: `${CDN2}/world-map/resonance_crystal.png` }
23823
+ { id: "f1", x: 2, y: 2, type: "chest", sprite: makeAsset(`${CDN2}/world-map/treasure_chest_closed.png`, "decoration") },
23824
+ { id: "f2", x: 3, y: 1, type: "crystal", sprite: makeAsset(`${CDN2}/world-map/resonance_crystal.png`, "decoration") }
23750
23825
  ];
23751
23826
  DEFAULT_CASTLE_MANIFEST = {
23752
- baseUrl: CDN2,
23753
- terrains: {
23754
- wall: "/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png",
23755
- floor: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png"
23756
- },
23757
- units: {
23758
- worker: "/sprite-sheets/coordinator-sprite-sheet-se.png",
23759
- guardian: "/sprite-sheets/forger-sprite-sheet-se.png"
23760
- },
23761
- features: {
23762
- chest: "/world-map/treasure_chest_closed.png",
23763
- crystal: "/world-map/resonance_crystal.png"
23764
- }
23827
+ terrains: makeAssetMap({
23828
+ wall: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
23829
+ floor: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`
23830
+ }, "tile"),
23831
+ units: makeAssetMap({
23832
+ worker: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`,
23833
+ guardian: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`
23834
+ }, "player"),
23835
+ features: makeAssetMap({
23836
+ chest: `${CDN2}/world-map/treasure_chest_closed.png`,
23837
+ crystal: `${CDN2}/world-map/resonance_crystal.png`
23838
+ }, "decoration")
23765
23839
  };
23766
23840
  CastleTemplate.displayName = "CastleTemplate";
23767
23841
  }
@@ -24749,15 +24823,6 @@ var init_ChatBar = __esm({
24749
24823
  ChatBar.displayName = "ChatBar";
24750
24824
  }
24751
24825
  });
24752
- function resolveManifestUrl2(manifest, relative) {
24753
- if (relative == null) return void 0;
24754
- if (/^https?:\/\//.test(relative)) return relative;
24755
- const base = manifest?.baseUrl;
24756
- if (base == null) return relative;
24757
- const cleanBase = base.replace(/\/$/, "");
24758
- const cleanRel = relative.replace(/^\//, "");
24759
- return `${cleanBase}/${cleanRel}`;
24760
- }
24761
24826
  function buildDefaultCBTiles() {
24762
24827
  const tiles = [];
24763
24828
  for (let y = 0; y < CB_GRID_H; y++) {
@@ -24772,12 +24837,12 @@ function buildDefaultCBTiles() {
24772
24837
  function tilesToIso(tiles, manifest) {
24773
24838
  return tiles.map((t) => {
24774
24839
  const key = t.terrain ?? "grass";
24775
- const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
24840
+ const terrainSprite = t.terrainSprite ?? manifest?.terrains?.[key] ?? manifest?.terrains?.grass;
24776
24841
  return {
24777
24842
  x: t.x,
24778
24843
  y: t.y,
24779
24844
  terrain: t.terrain,
24780
- terrainSprite: sprite,
24845
+ terrainSprite,
24781
24846
  passable: t.passable
24782
24847
  };
24783
24848
  });
@@ -24788,7 +24853,7 @@ function buildingsToFeatures(buildings, manifest) {
24788
24853
  x: b.x,
24789
24854
  y: b.y,
24790
24855
  type: b.type,
24791
- sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
24856
+ sprite: manifest?.features?.[b.type]
24792
24857
  }));
24793
24858
  }
24794
24859
  function CityBuilderBoard({
@@ -24820,7 +24885,7 @@ function CityBuilderBoard({
24820
24885
  x: num(r2.x),
24821
24886
  y: num(r2.y),
24822
24887
  terrain: r2.terrain == null ? void 0 : str(r2.terrain),
24823
- terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
24888
+ terrainSprite: r2.terrainSprite == null ? void 0 : makeAsset(str(r2.terrainSprite), "tile"),
24824
24889
  passable: r2.passable !== false
24825
24890
  })),
24826
24891
  [board.tiles]
@@ -24929,7 +24994,6 @@ function CityBuilderBoard({
24929
24994
  {
24930
24995
  tiles: isoTiles,
24931
24996
  features: buildingFeatures,
24932
- assetBaseUrl: assetManifest?.baseUrl,
24933
24997
  assetManifest,
24934
24998
  validMoves,
24935
24999
  hoveredTile,
@@ -24964,6 +25028,7 @@ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
24964
25028
  var init_CityBuilderBoard = __esm({
24965
25029
  "components/game/organisms/CityBuilderBoard.tsx"() {
24966
25030
  "use client";
25031
+ init_makeAsset();
24967
25032
  init_cn();
24968
25033
  init_useEventBus();
24969
25034
  init_Box();
@@ -30958,7 +31023,7 @@ function StatBadge({
30958
31023
  resolvedAsset ? /* @__PURE__ */ jsxRuntime.jsx(
30959
31024
  "img",
30960
31025
  {
30961
- src: resolvedAsset,
31026
+ src: resolvedAsset.url,
30962
31027
  alt: "",
30963
31028
  width: 16,
30964
31029
  height: 16,
@@ -31265,7 +31330,7 @@ function GameCanvas2D({
31265
31330
  tickEvent,
31266
31331
  drawEvent,
31267
31332
  fps = 60,
31268
- backgroundImage = "",
31333
+ backgroundImage,
31269
31334
  assetBaseUrl,
31270
31335
  className
31271
31336
  }) {
@@ -31329,7 +31394,7 @@ function GameCanvas2D({
31329
31394
  emitRef.current(tickEventRef.current, { dt, frame });
31330
31395
  }
31331
31396
  if (backgroundImageRef.current) {
31332
- const bgImg = loadImage(backgroundImageRef.current);
31397
+ const bgImg = loadImage(backgroundImageRef.current.url);
31333
31398
  if (bgImg) {
31334
31399
  ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
31335
31400
  } else {
@@ -31700,7 +31765,7 @@ function EnemyPlate({
31700
31765
  assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
31701
31766
  "img",
31702
31767
  {
31703
- src: assetUrl,
31768
+ src: assetUrl.url,
31704
31769
  alt: name,
31705
31770
  width: 24,
31706
31771
  height: 24,
@@ -32042,7 +32107,7 @@ function DialogueBox({
32042
32107
  "div",
32043
32108
  {
32044
32109
  className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
32045
- style: { backgroundImage: `url(${backgroundImage})` },
32110
+ style: { backgroundImage: `url(${backgroundImage?.url})` },
32046
32111
  "aria-hidden": "true"
32047
32112
  }
32048
32113
  ),
@@ -32057,7 +32122,7 @@ function DialogueBox({
32057
32122
  children: /* @__PURE__ */ jsxRuntime.jsx(
32058
32123
  "img",
32059
32124
  {
32060
- src: portraitUrl,
32125
+ src: portraitUrl?.url,
32061
32126
  alt: dialogue.speaker,
32062
32127
  className: "h-full w-auto object-contain drop-shadow-2xl"
32063
32128
  }
@@ -43954,7 +44019,6 @@ var init_FeatureGridOrganism = __esm({
43954
44019
  });
43955
44020
  function FishingBoard({
43956
44021
  backgroundImage,
43957
- assetBaseUrl,
43958
44022
  scale = 1,
43959
44023
  showMinimap = false,
43960
44024
  enableCamera = true,
@@ -43972,8 +44036,7 @@ function FishingBoard({
43972
44036
  {
43973
44037
  width,
43974
44038
  height,
43975
- backgroundImage: backgroundImage ?? "",
43976
- assetBaseUrl,
44039
+ backgroundImage,
43977
44040
  fps: 60,
43978
44041
  className: "w-full h-full"
43979
44042
  }
@@ -46192,7 +46255,7 @@ var init_GameCanvas3D2 = __esm({
46192
46255
  children: /* @__PURE__ */ jsxRuntime.jsx(
46193
46256
  ModelLoader,
46194
46257
  {
46195
- url: tile.modelUrl,
46258
+ url: tile.modelUrl.url,
46196
46259
  scale: 0.95,
46197
46260
  fallbackGeometry: "box",
46198
46261
  castShadow: true,
@@ -46257,7 +46320,7 @@ var init_GameCanvas3D2 = __esm({
46257
46320
  /* @__PURE__ */ jsxRuntime.jsx(
46258
46321
  ModelLoader,
46259
46322
  {
46260
- url: unit.modelUrl,
46323
+ url: unit.modelUrl.url,
46261
46324
  scale: modelScale,
46262
46325
  fallbackGeometry: "box",
46263
46326
  castShadow: true
@@ -46317,7 +46380,7 @@ var init_GameCanvas3D2 = __esm({
46317
46380
  return /* @__PURE__ */ jsxRuntime.jsx(
46318
46381
  ModelLoader,
46319
46382
  {
46320
- url: feature.assetUrl,
46383
+ url: feature.assetUrl.url,
46321
46384
  position,
46322
46385
  scale: 0.5,
46323
46386
  rotation: [0, feature.rotation ?? 0, 0],
@@ -46538,7 +46601,18 @@ function GameBoard3D({
46538
46601
  const row = boardEntity(entity);
46539
46602
  const eventBus = useEventBus();
46540
46603
  const entityUnits = row ? rows(row.units) : [];
46541
- const units = entityUnits;
46604
+ const units = entityUnits.map((r2) => ({
46605
+ id: str(r2.id),
46606
+ x: num(r2.x),
46607
+ y: num(r2.y),
46608
+ z: num(r2.z),
46609
+ faction: str(r2.faction) || "neutral",
46610
+ team: str(r2.team) || str(r2.faction) || "neutral",
46611
+ unitType: r2.unitType == null ? void 0 : str(r2.unitType),
46612
+ name: r2.name == null ? void 0 : str(r2.name),
46613
+ health: r2.health == null ? void 0 : num(r2.health),
46614
+ maxHealth: r2.maxHealth == null ? void 0 : num(r2.maxHealth)
46615
+ }));
46542
46616
  const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
46543
46617
  const phase = row ? str(row.phase) : "observation";
46544
46618
  const result = row ? str(row.result) : "none";
@@ -46717,22 +46791,27 @@ function resolveDescriptor(value, idPrefix) {
46717
46791
  }
46718
46792
  if (typeof value === "object" && value !== null) {
46719
46793
  const desc = asDescriptor(value);
46720
- if (desc !== null && patterns.getComponentForPattern(desc.type) !== null) {
46794
+ const hasComp = desc !== null && patterns.getComponentForPattern(desc.type) !== null;
46795
+ shellLog.debug("resolve", { idPrefix, type: desc?.type ?? null, hasDesc: desc !== null, render: hasComp });
46796
+ if (hasComp) {
46721
46797
  const resolvedProps = desc.props ?? {};
46722
46798
  const content = { id: desc._id ?? idPrefix, pattern: desc.type, props: resolvedProps, priority: 0 };
46723
46799
  const SCR = getSlotContentRenderer2();
46724
- return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 });
46800
+ return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 }, content.id);
46725
46801
  }
46802
+ } else {
46803
+ shellLog.debug("resolve", { idPrefix, type: null, hasDesc: false, render: false, branch: typeof value });
46726
46804
  }
46727
46805
  return null;
46728
46806
  }
46729
- var _scr, GameShell;
46807
+ var shellLog, _scr, GameShell;
46730
46808
  var init_GameShell = __esm({
46731
46809
  "components/game/templates/GameShell.tsx"() {
46732
46810
  init_cn();
46733
46811
  init_Box();
46734
46812
  init_Stack();
46735
46813
  init_Typography();
46814
+ shellLog = logger.createLogger("almadar:ui:game:game-shell");
46736
46815
  _scr = null;
46737
46816
  GameShell = ({
46738
46817
  appName = "Game",
@@ -47133,7 +47212,6 @@ function HexStrategyBoard({
47133
47212
  units,
47134
47213
  features,
47135
47214
  assetManifest,
47136
- assetBaseUrl,
47137
47215
  scale,
47138
47216
  showMinimap,
47139
47217
  enableCamera,
@@ -47175,7 +47253,6 @@ function HolidayRunnerBoard({
47175
47253
  units,
47176
47254
  features,
47177
47255
  assetManifest,
47178
- assetBaseUrl,
47179
47256
  scale,
47180
47257
  showMinimap,
47181
47258
  enableCamera,
@@ -47970,7 +48047,6 @@ function MatchPuzzleBoard({
47970
48047
  units,
47971
48048
  features,
47972
48049
  assetManifest,
47973
- assetBaseUrl,
47974
48050
  scale,
47975
48051
  showMinimap,
47976
48052
  enableCamera,
@@ -48231,7 +48307,6 @@ function MinigolfBoard({
48231
48307
  units,
48232
48308
  features,
48233
48309
  assetManifest,
48234
- assetBaseUrl,
48235
48310
  scale,
48236
48311
  showMinimap,
48237
48312
  enableCamera,
@@ -48537,7 +48612,6 @@ function PirateBoard({
48537
48612
  units,
48538
48613
  features,
48539
48614
  assetManifest,
48540
- assetBaseUrl,
48541
48615
  scale,
48542
48616
  showMinimap,
48543
48617
  enableCamera,
@@ -48658,8 +48732,8 @@ function PlatformerBoard({
48658
48732
  canvasHeight,
48659
48733
  followCamera: true,
48660
48734
  bgColor,
48661
- playerSprite,
48662
- tileSprites,
48735
+ playerSprite: playerSprite?.url,
48736
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
48663
48737
  leftEvent,
48664
48738
  rightEvent,
48665
48739
  jumpEvent,
@@ -48724,7 +48798,7 @@ function PlatformerTemplate({
48724
48798
  worldHeight = 400,
48725
48799
  canvasWidth = 800,
48726
48800
  canvasHeight = 400,
48727
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
48801
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
48728
48802
  tileSprites = DEFAULT_TILE_SPRITES,
48729
48803
  bgColor = "#5c94fc",
48730
48804
  gameEndEvent = "GAME_END",
@@ -48777,13 +48851,14 @@ var init_PlatformerTemplate = __esm({
48777
48851
  init_PlatformerBoard();
48778
48852
  init_GameHud();
48779
48853
  init_ScoreBoard();
48854
+ init_makeAsset();
48780
48855
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
48781
- DEFAULT_TILE_SPRITES = {
48856
+ DEFAULT_TILE_SPRITES = makeAssetMap({
48782
48857
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
48783
48858
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
48784
48859
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
48785
48860
  goal: `${CDN3}/tiles/platformPack_tile007.png`
48786
- };
48861
+ }, "tile");
48787
48862
  DEFAULT_PLATFORMS = [
48788
48863
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
48789
48864
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -48939,7 +49014,6 @@ function RacingBoard({
48939
49014
  units,
48940
49015
  features,
48941
49016
  assetManifest,
48942
- assetBaseUrl,
48943
49017
  scale,
48944
49018
  showMinimap,
48945
49019
  enableCamera,
@@ -48958,27 +49032,18 @@ var init_RacingBoard = __esm({
48958
49032
  RacingBoard.displayName = "RacingBoard";
48959
49033
  }
48960
49034
  });
48961
- function resolveManifestUrl3(manifest, relative) {
48962
- if (relative == null) return void 0;
48963
- if (/^https?:\/\//.test(relative)) return relative;
48964
- const base = manifest?.baseUrl;
48965
- if (base == null) return relative;
48966
- const cleanBase = base.replace(/\/$/, "");
48967
- const cleanRel = relative.replace(/^\//, "");
48968
- return `${cleanBase}/${cleanRel}`;
48969
- }
48970
49035
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
48971
49036
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
48972
49037
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
48973
49038
  const isWall = isBorder || isPillar;
48974
49039
  const terrains = manifest?.terrains;
48975
49040
  if (x === stairsX && y === stairsY) {
48976
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
49041
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
48977
49042
  }
48978
49043
  if (isWall) {
48979
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
49044
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
48980
49045
  }
48981
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
49046
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
48982
49047
  }
48983
49048
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
48984
49049
  const tiles = [];
@@ -49022,7 +49087,7 @@ function RoguelikeBoard({
49022
49087
  x: num(r2.x),
49023
49088
  y: num(r2.y),
49024
49089
  terrain: r2.terrain == null ? void 0 : str(r2.terrain),
49025
- terrainSprite: r2.terrainSprite == null ? void 0 : str(r2.terrainSprite),
49090
+ terrainSprite: r2.terrainSprite == null ? void 0 : makeAsset(str(r2.terrainSprite), "tile"),
49026
49091
  passable: r2.passable !== false
49027
49092
  })),
49028
49093
  [board.tiles]
@@ -49102,7 +49167,7 @@ function RoguelikeBoard({
49102
49167
  health: playerHp,
49103
49168
  maxHealth: playerMaxHp,
49104
49169
  unitType: "player",
49105
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
49170
+ sprite: assetManifest?.units?.player
49106
49171
  },
49107
49172
  ...liveEnemies.map((e) => ({
49108
49173
  id: e.id,
@@ -49112,7 +49177,7 @@ function RoguelikeBoard({
49112
49177
  health: e.hp,
49113
49178
  maxHealth: 6,
49114
49179
  unitType: "enemy",
49115
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
49180
+ sprite: assetManifest?.units?.enemy
49116
49181
  }))
49117
49182
  ];
49118
49183
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -49122,7 +49187,7 @@ function RoguelikeBoard({
49122
49187
  x: it.x,
49123
49188
  y: it.y,
49124
49189
  type: it.kind,
49125
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
49190
+ sprite: assetManifest?.features?.[it.kind]
49126
49191
  })),
49127
49192
  [items, assetManifest]
49128
49193
  );
@@ -49183,7 +49248,6 @@ function RoguelikeBoard({
49183
49248
  onTileHover: (x, y) => setHoveredTile({ x, y }),
49184
49249
  onTileLeave: () => setHoveredTile(null),
49185
49250
  scale,
49186
- assetBaseUrl: assetManifest?.baseUrl,
49187
49251
  assetManifest,
49188
49252
  unitScale,
49189
49253
  spriteHeightRatio,
@@ -49243,6 +49307,7 @@ var init_RoguelikeBoard = __esm({
49243
49307
  init_Stack();
49244
49308
  init_IsometricCanvas();
49245
49309
  init_boardEntity();
49310
+ init_makeAsset();
49246
49311
  DUNGEON_GRID_W = 16;
49247
49312
  DUNGEON_GRID_H = 16;
49248
49313
  DEFAULT_ENEMIES = [
@@ -49293,55 +49358,59 @@ function RoguelikeTemplate({
49293
49358
  }
49294
49359
  );
49295
49360
  }
49296
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
49361
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
49297
49362
  var init_RoguelikeTemplate = __esm({
49298
49363
  "components/game/templates/RoguelikeTemplate.tsx"() {
49299
49364
  init_RoguelikeBoard();
49365
+ init_makeAsset();
49300
49366
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
49367
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
49368
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
49369
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
49370
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
49301
49371
  DEFAULT_ROGUELIKE_TILES = [
49302
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49303
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49304
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49305
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49306
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49307
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49308
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49309
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49310
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49311
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49312
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49313
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49314
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49315
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49316
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49317
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49318
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
49319
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
49320
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
49321
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49322
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49323
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49324
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49325
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
49326
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
49372
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49373
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49374
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49375
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49376
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
49377
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
49378
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49379
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49380
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
49381
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
49382
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
49383
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
49384
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
49385
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
49386
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
49387
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
49388
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
49389
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
49390
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
49391
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
49392
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49393
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49394
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49395
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
49396
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
49327
49397
  ];
49328
49398
  DEFAULT_ROGUELIKE_MANIFEST = {
49329
- baseUrl: CDN4,
49330
- terrains: {
49331
- floor: "/isometric-dungeon/Isometric/dirt_E.png",
49332
- wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
49333
- stairs: "/isometric-dungeon/Isometric/stairs_E.png",
49334
- planks: "/isometric-dungeon/Isometric/planks_E.png"
49335
- },
49399
+ terrains: makeAssetMap({
49400
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
49401
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
49402
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
49403
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
49404
+ }, "tile"),
49336
49405
  units: {
49337
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
49338
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
49406
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
49407
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
49339
49408
  },
49340
- features: {
49341
- health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
49342
- sword: "/isometric-dungeon/Isometric/barrel_E.png",
49343
- shield: "/isometric-dungeon/Isometric/barrel_E.png"
49344
- }
49409
+ features: makeAssetMap({
49410
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
49411
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
49412
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
49413
+ }, "item")
49345
49414
  };
49346
49415
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
49347
49416
  }
@@ -52215,7 +52284,6 @@ function SokobanBoard({
52215
52284
  units,
52216
52285
  features,
52217
52286
  assetManifest,
52218
- assetBaseUrl,
52219
52287
  scale,
52220
52288
  showMinimap,
52221
52289
  enableCamera,
@@ -52257,7 +52325,6 @@ function SpaceShmupBoard({
52257
52325
  units,
52258
52326
  features,
52259
52327
  assetManifest,
52260
- assetBaseUrl,
52261
52328
  scale,
52262
52329
  showMinimap,
52263
52330
  enableCamera,
@@ -52299,7 +52366,6 @@ function SpaceStationBoard({
52299
52366
  units,
52300
52367
  features,
52301
52368
  assetManifest,
52302
- assetBaseUrl,
52303
52369
  scale,
52304
52370
  showMinimap,
52305
52371
  enableCamera,
@@ -52434,7 +52500,6 @@ function SportsBoard({
52434
52500
  units,
52435
52501
  features,
52436
52502
  assetManifest,
52437
- assetBaseUrl,
52438
52503
  scale,
52439
52504
  showMinimap,
52440
52505
  enableCamera,
@@ -54278,7 +54343,6 @@ function TanksBoard({
54278
54343
  units,
54279
54344
  features,
54280
54345
  assetManifest,
54281
- assetBaseUrl,
54282
54346
  scale,
54283
54347
  showMinimap,
54284
54348
  enableCamera,
@@ -54556,15 +54620,6 @@ var init_ToastSlot = __esm({
54556
54620
  ToastSlot.displayName = "ToastSlot";
54557
54621
  }
54558
54622
  });
54559
- function resolveManifestUrl4(manifest, relative) {
54560
- if (relative == null || relative === "") return void 0;
54561
- if (/^https?:\/\//.test(relative)) return relative;
54562
- const base = manifest?.baseUrl;
54563
- if (base == null) return relative;
54564
- const cleanBase = base.replace(/\/$/, "");
54565
- const cleanRel = relative.replace(/^\//, "");
54566
- return `${cleanBase}/${cleanRel}`;
54567
- }
54568
54623
  function readPlayer(v) {
54569
54624
  if (v == null || typeof v !== "object") return void 0;
54570
54625
  const o = v;
@@ -54617,10 +54672,10 @@ function TopDownShooterBoard({
54617
54672
  const wave = propWave ?? num(board.wave, 1);
54618
54673
  const lives = propLives ?? num(board.lives, 3);
54619
54674
  const result = propResult ?? (str(board.result) || "none");
54620
- const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
54621
- const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
54622
- const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
54623
- const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
54675
+ const playerSprite = assetManifest?.units?.player?.url;
54676
+ const enemySprite = assetManifest?.units?.enemy?.url;
54677
+ const projectileSprite = assetManifest?.features?.projectile?.url;
54678
+ const backgroundSprite = assetManifest?.background;
54624
54679
  const spriteUrls = React96.useMemo(
54625
54680
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
54626
54681
  [playerSprite, enemySprite, projectileSprite]
@@ -54787,7 +54842,6 @@ function TopDownShooterBoard({
54787
54842
  width,
54788
54843
  height,
54789
54844
  backgroundImage: backgroundSprite,
54790
- assetBaseUrl: assetManifest?.baseUrl,
54791
54845
  onDraw
54792
54846
  }
54793
54847
  ),
@@ -54912,15 +54966,6 @@ var init_TopDownShooterTemplate = __esm({
54912
54966
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
54913
54967
  }
54914
54968
  });
54915
- function resolveManifestUrl5(manifest, relative) {
54916
- if (relative == null) return void 0;
54917
- if (/^https?:\/\//.test(relative)) return relative;
54918
- const base = manifest?.baseUrl;
54919
- if (base == null) return relative;
54920
- const cleanBase = base.replace(/\/$/, "");
54921
- const cleanRel = relative.replace(/^\//, "");
54922
- return `${cleanBase}/${cleanRel}`;
54923
- }
54924
54969
  function buildDefaultTDTiles() {
54925
54970
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
54926
54971
  const tiles = [];
@@ -54940,18 +54985,18 @@ function buildDefaultTDTiles() {
54940
54985
  function tilesToIso2(tiles, manifest) {
54941
54986
  return tiles.map((t) => {
54942
54987
  const key = t.terrain ?? "ground";
54943
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
54988
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
54944
54989
  return {
54945
54990
  x: t.x,
54946
54991
  y: t.y,
54947
54992
  terrain: t.terrain,
54948
- terrainSprite: sprite,
54993
+ terrainSprite,
54949
54994
  passable: t.passable
54950
54995
  };
54951
54996
  });
54952
54997
  }
54953
54998
  function creepsToUnits(creeps, manifest) {
54954
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
54999
+ const sprite = manifest?.units?.creep;
54955
55000
  return creeps.map((c) => ({
54956
55001
  id: c.id,
54957
55002
  position: { x: c.x, y: c.y },
@@ -54969,14 +55014,14 @@ function heroToUnit(hero, manifest) {
54969
55014
  position: { x: hero.x, y: hero.y },
54970
55015
  name: "Hero",
54971
55016
  team: "player",
54972
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
55017
+ sprite: manifest?.units?.hero,
54973
55018
  unitType: "hero",
54974
55019
  health: 1,
54975
55020
  maxHealth: 1
54976
55021
  };
54977
55022
  }
54978
55023
  function towersToFeatures(towers, manifest) {
54979
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
55024
+ const sprite = manifest?.features?.tower;
54980
55025
  return towers.map((t) => ({
54981
55026
  id: t.id,
54982
55027
  x: t.x,
@@ -55174,7 +55219,6 @@ function TowerDefenseBoard({
55174
55219
  tiles: isoTiles,
55175
55220
  units: isoUnits,
55176
55221
  features: towerFeatures,
55177
- assetBaseUrl: assetManifest?.baseUrl,
55178
55222
  assetManifest,
55179
55223
  validMoves,
55180
55224
  hoveredTile,
@@ -55218,6 +55262,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
55218
55262
  var init_TowerDefenseBoard = __esm({
55219
55263
  "components/game/organisms/TowerDefenseBoard.tsx"() {
55220
55264
  "use client";
55265
+ init_makeAsset();
55221
55266
  init_cn();
55222
55267
  init_useEventBus();
55223
55268
  init_Box();
@@ -55547,15 +55592,6 @@ var init_UncontrolledBattleBoard = __esm({
55547
55592
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
55548
55593
  }
55549
55594
  });
55550
- function resolveManifestUrl6(manifest, relative) {
55551
- if (relative == null) return void 0;
55552
- if (/^https?:\/\//.test(relative)) return relative;
55553
- const base = manifest?.baseUrl;
55554
- if (base == null) return relative;
55555
- const cleanBase = base.replace(/\/$/, "");
55556
- const cleanRel = relative.replace(/^\//, "");
55557
- return `${cleanBase}/${cleanRel}`;
55558
- }
55559
55595
  function VisualNovelBoard({
55560
55596
  entity,
55561
55597
  nodes: propNodes,
@@ -55590,11 +55626,11 @@ function VisualNovelBoard({
55590
55626
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
55591
55627
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
55592
55628
  const backgroundImage = React96.useMemo(
55593
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
55629
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
55594
55630
  [assetManifest, currentNode?.backgroundKey]
55595
55631
  );
55596
55632
  const portraitUrl = React96.useMemo(
55597
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
55633
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
55598
55634
  [assetManifest, currentNode?.portraitKey]
55599
55635
  );
55600
55636
  const dialogueChoices = React96.useMemo(
@@ -55768,7 +55804,7 @@ function buildDefaultWorldTiles() {
55768
55804
  for (let x = 0; x < WORLD_GRID_W; x++) {
55769
55805
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
55770
55806
  const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
55771
- tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
55807
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
55772
55808
  }
55773
55809
  }
55774
55810
  return tiles;
@@ -55812,7 +55848,12 @@ function WorldMapBoard({
55812
55848
  const resolved = boardEntity(entity);
55813
55849
  const entityUnits = rows(resolved?.units);
55814
55850
  const entityTiles = rows(resolved?.tiles);
55815
- const features = propFeatures ?? rows(resolved?.features);
55851
+ const features = propFeatures ?? rows(resolved?.features).map((r2) => ({
55852
+ id: r2.id == null ? void 0 : str(r2.id),
55853
+ x: num(r2.x),
55854
+ y: num(r2.y),
55855
+ type: str(r2.type)
55856
+ }));
55816
55857
  const selectedHeroId = resolved?.selectedHeroId ?? null;
55817
55858
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
55818
55859
  const backgroundImage = resolved?.backgroundImage;
@@ -55822,7 +55863,7 @@ function WorldMapBoard({
55822
55863
  x: num(t.x),
55823
55864
  y: num(t.y),
55824
55865
  terrain: str(t.terrain),
55825
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
55866
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
55826
55867
  passable: t.passable !== false
55827
55868
  })),
55828
55869
  [entityTiles]
@@ -55838,7 +55879,7 @@ function WorldMapBoard({
55838
55879
  team: str(u.team) === "enemy" ? "enemy" : "player",
55839
55880
  health: num(u.health) || 100,
55840
55881
  maxHealth: num(u.maxHealth) || 100,
55841
- sprite: u.sprite == null ? void 0 : str(u.sprite)
55882
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
55842
55883
  })),
55843
55884
  [entityUnits, propUnits]
55844
55885
  );
@@ -56020,7 +56061,6 @@ function WorldMapBoard({
56020
56061
  onTileHover: (x, y) => setHoveredTile({ x, y }),
56021
56062
  onTileLeave: () => setHoveredTile(null),
56022
56063
  scale,
56023
- assetBaseUrl: assetManifest?.baseUrl,
56024
56064
  assetManifest,
56025
56065
  backgroundImage,
56026
56066
  effectSpriteUrls,
@@ -56043,6 +56083,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
56043
56083
  var init_WorldMapBoard = __esm({
56044
56084
  "components/game/organisms/WorldMapBoard.tsx"() {
56045
56085
  "use client";
56086
+ init_makeAsset();
56046
56087
  init_cn();
56047
56088
  init_useEventBus();
56048
56089
  init_Stack();
@@ -56096,62 +56137,66 @@ function WorldMapTemplate({
56096
56137
  }
56097
56138
  );
56098
56139
  }
56099
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
56140
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
56100
56141
  var init_WorldMapTemplate = __esm({
56101
56142
  "components/game/templates/WorldMapTemplate.tsx"() {
56102
56143
  init_WorldMapBoard();
56144
+ init_makeAsset();
56103
56145
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
56146
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
56147
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
56148
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
56149
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
56104
56150
  DEFAULT_WORLDMAP_TILES = [
56105
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56106
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56107
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56108
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56109
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56110
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56111
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56112
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56113
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56114
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56115
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56116
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56117
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
56118
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56119
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56120
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56121
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56122
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56123
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
56124
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56125
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56126
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
56127
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
56128
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
56129
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
56151
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56152
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56153
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
56154
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56155
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
56156
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
56157
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56158
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56159
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
56160
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
56161
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
56162
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
56163
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
56164
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
56165
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
56166
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
56167
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
56168
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
56169
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
56170
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
56171
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
56172
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
56173
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
56174
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
56175
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
56130
56176
  ];
56131
56177
  DEFAULT_WORLDMAP_UNITS = [
56132
- { 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` },
56133
- { 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` }
56178
+ { 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") },
56179
+ { 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") }
56134
56180
  ];
56135
56181
  DEFAULT_WORLDMAP_FEATURES = [
56136
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
56137
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
56182
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
56183
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
56138
56184
  ];
56139
56185
  DEFAULT_WORLDMAP_MANIFEST = {
56140
- baseUrl: CDN5,
56141
- terrains: {
56142
- grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
56143
- water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
56144
- mountain: "/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png",
56145
- road: "/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png"
56146
- },
56186
+ terrains: makeAssetMap({
56187
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
56188
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
56189
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
56190
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
56191
+ }, "tile"),
56147
56192
  units: {
56148
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
56149
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
56193
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
56194
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
56150
56195
  },
56151
- features: {
56152
- capital: "/scenes/world/capital.png",
56153
- power_node: "/world-map/power_node.png"
56154
- }
56196
+ features: makeAssetMap({
56197
+ capital: `${CDN5}/scenes/world/capital.png`,
56198
+ power_node: `${CDN5}/world-map/power_node.png`
56199
+ }, "decoration")
56155
56200
  };
56156
56201
  WorldMapTemplate.displayName = "WorldMapTemplate";
56157
56202
  }