@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
@@ -6913,7 +6913,7 @@ function ScoreDisplay({
6913
6913
  assetUrl ? /* @__PURE__ */ jsx(
6914
6914
  "img",
6915
6915
  {
6916
- src: assetUrl,
6916
+ src: assetUrl.url,
6917
6917
  alt: "",
6918
6918
  width: 20,
6919
6919
  height: 20,
@@ -6938,7 +6938,11 @@ var init_ScoreDisplay = __esm({
6938
6938
  lg: "text-2xl",
6939
6939
  xl: "text-4xl"
6940
6940
  };
6941
- DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
6941
+ DEFAULT_ASSET_URL = {
6942
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png",
6943
+ role: "effect",
6944
+ category: "effect"
6945
+ };
6942
6946
  ScoreDisplay.displayName = "ScoreDisplay";
6943
6947
  }
6944
6948
  });
@@ -7014,7 +7018,7 @@ function ControlButton({
7014
7018
  children: assetUrl ? /* @__PURE__ */ jsx(
7015
7019
  "img",
7016
7020
  {
7017
- src: assetUrl,
7021
+ src: assetUrl.url,
7018
7022
  alt: "",
7019
7023
  width: 24,
7020
7024
  height: 24,
@@ -7054,7 +7058,11 @@ var init_ControlButton = __esm({
7054
7058
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
7055
7059
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
7056
7060
  };
7057
- DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
7061
+ DEFAULT_ASSET_URL2 = {
7062
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
7063
+ role: "effect",
7064
+ category: "effect"
7065
+ };
7058
7066
  ControlButton.displayName = "ControlButton";
7059
7067
  }
7060
7068
  });
@@ -7093,7 +7101,7 @@ var init_spriteAnimation = __esm({
7093
7101
  }
7094
7102
  });
7095
7103
  function Sprite({
7096
- spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
7104
+ spritesheet = DEFAULT_SPRITESHEET,
7097
7105
  frameWidth = 64,
7098
7106
  frameHeight = 64,
7099
7107
  frame = 0,
@@ -7146,7 +7154,7 @@ function Sprite({
7146
7154
  position: "absolute",
7147
7155
  width: frameWidth,
7148
7156
  height: frameHeight,
7149
- backgroundImage: `url(${spritesheet})`,
7157
+ backgroundImage: `url(${spritesheet.url})`,
7150
7158
  backgroundPosition,
7151
7159
  backgroundRepeat: "no-repeat",
7152
7160
  imageRendering: "pixelated",
@@ -7159,11 +7167,17 @@ function Sprite({
7159
7167
  }
7160
7168
  );
7161
7169
  }
7170
+ var DEFAULT_SPRITESHEET;
7162
7171
  var init_Sprite = __esm({
7163
7172
  "components/game/atoms/Sprite.tsx"() {
7164
7173
  "use client";
7165
7174
  init_useEventBus();
7166
7175
  init_spriteAnimation();
7176
+ DEFAULT_SPRITESHEET = {
7177
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
7178
+ role: "tile",
7179
+ category: "tile"
7180
+ };
7167
7181
  }
7168
7182
  });
7169
7183
  function StateIndicator({
@@ -7193,7 +7207,7 @@ function StateIndicator({
7193
7207
  /* @__PURE__ */ jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsx(
7194
7208
  "img",
7195
7209
  {
7196
- src: assetUrl,
7210
+ src: assetUrl.url,
7197
7211
  alt: displayLabel,
7198
7212
  width: 16,
7199
7213
  height: 16,
@@ -7212,7 +7226,11 @@ var init_StateIndicator = __esm({
7212
7226
  init_Box();
7213
7227
  init_Icon();
7214
7228
  init_cn();
7215
- DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
7229
+ DEFAULT_ASSET_URL3 = {
7230
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
7231
+ role: "effect",
7232
+ category: "item"
7233
+ };
7216
7234
  DEFAULT_STATE_STYLES = {
7217
7235
  idle: { icon: "\u23F8", bgClass: "bg-muted" },
7218
7236
  active: { icon: "\u25B6", bgClass: "bg-success" },
@@ -7310,7 +7328,7 @@ function ResourceCounter({
7310
7328
  assetUrl ? /* @__PURE__ */ jsx(
7311
7329
  "img",
7312
7330
  {
7313
- src: assetUrl,
7331
+ src: assetUrl.url,
7314
7332
  alt: label,
7315
7333
  width: sizes.img,
7316
7334
  height: sizes.img,
@@ -7343,7 +7361,11 @@ var init_ResourceCounter = __esm({
7343
7361
  error: "text-error",
7344
7362
  muted: "text-muted-foreground"
7345
7363
  };
7346
- DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
7364
+ DEFAULT_ASSET_URL4 = {
7365
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
7366
+ role: "effect",
7367
+ category: "world"
7368
+ };
7347
7369
  sizeMap5 = {
7348
7370
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
7349
7371
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -7389,7 +7411,7 @@ function ItemSlot({
7389
7411
  assetUrl ? /* @__PURE__ */ jsx(
7390
7412
  "img",
7391
7413
  {
7392
- src: assetUrl,
7414
+ src: assetUrl?.url,
7393
7415
  alt: label,
7394
7416
  width: px,
7395
7417
  height: px,
@@ -7437,7 +7459,11 @@ var init_ItemSlot = __esm({
7437
7459
  epic: "shadow-lg",
7438
7460
  legendary: "shadow-lg"
7439
7461
  };
7440
- DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
7462
+ DEFAULT_ASSET_URL5 = {
7463
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
7464
+ role: "effect",
7465
+ category: "item"
7466
+ };
7441
7467
  assetSizeMap = {
7442
7468
  sm: 28,
7443
7469
  md: 40,
@@ -7483,7 +7509,7 @@ function TurnIndicator({
7483
7509
  assetUrl ? /* @__PURE__ */ jsx(
7484
7510
  "img",
7485
7511
  {
7486
- src: assetUrl,
7512
+ src: assetUrl.url,
7487
7513
  alt: "",
7488
7514
  width: 12,
7489
7515
  height: 12,
@@ -7506,7 +7532,11 @@ var init_TurnIndicator = __esm({
7506
7532
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
7507
7533
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
7508
7534
  };
7509
- DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
7535
+ DEFAULT_ASSET_URL6 = {
7536
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
7537
+ role: "effect",
7538
+ category: "effect"
7539
+ };
7510
7540
  TurnIndicator.displayName = "TurnIndicator";
7511
7541
  }
7512
7542
  });
@@ -7545,7 +7575,7 @@ function ComboCounter({
7545
7575
  assetUrl && /* @__PURE__ */ jsx(
7546
7576
  "img",
7547
7577
  {
7548
- src: assetUrl,
7578
+ src: assetUrl.url,
7549
7579
  alt: "combo",
7550
7580
  width: 24,
7551
7581
  height: 24,
@@ -7571,7 +7601,11 @@ var DEFAULT_ASSET_URL7, sizeMap8;
7571
7601
  var init_ComboCounter = __esm({
7572
7602
  "components/game/atoms/ComboCounter.tsx"() {
7573
7603
  init_cn();
7574
- DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
7604
+ DEFAULT_ASSET_URL7 = {
7605
+ url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
7606
+ role: "effect",
7607
+ category: "effect"
7608
+ };
7575
7609
  sizeMap8 = {
7576
7610
  sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
7577
7611
  md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
@@ -7691,7 +7725,7 @@ function WaypointMarker({
7691
7725
  children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsx(
7692
7726
  "img",
7693
7727
  {
7694
- src: assetUrl,
7728
+ src: assetUrl.url,
7695
7729
  alt: label,
7696
7730
  width: sizes.img,
7697
7731
  height: sizes.img,
@@ -7720,7 +7754,11 @@ var init_WaypointMarker = __esm({
7720
7754
  "components/game/atoms/WaypointMarker.tsx"() {
7721
7755
  init_cn();
7722
7756
  init_Icon();
7723
- DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
7757
+ DEFAULT_ASSET_URL8 = {
7758
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
7759
+ role: "effect",
7760
+ category: "world"
7761
+ };
7724
7762
  sizeMap10 = {
7725
7763
  sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
7726
7764
  md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
@@ -7761,7 +7799,7 @@ function StatusEffect({
7761
7799
  /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsx(
7762
7800
  "img",
7763
7801
  {
7764
- src: assetUrl,
7802
+ src: assetUrl.url,
7765
7803
  alt: label,
7766
7804
  width: sizes.img,
7767
7805
  height: sizes.img,
@@ -7800,7 +7838,11 @@ var init_StatusEffect = __esm({
7800
7838
  "components/game/atoms/StatusEffect.tsx"() {
7801
7839
  init_cn();
7802
7840
  init_Icon();
7803
- DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
7841
+ DEFAULT_ASSET_URL9 = {
7842
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
7843
+ role: "effect",
7844
+ category: "effect"
7845
+ };
7804
7846
  sizeMap11 = {
7805
7847
  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 },
7806
7848
  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 },
@@ -7838,7 +7880,7 @@ function DamageNumber({
7838
7880
  assetUrl && /* @__PURE__ */ jsx(
7839
7881
  "img",
7840
7882
  {
7841
- src: assetUrl,
7883
+ src: assetUrl.url,
7842
7884
  alt: "",
7843
7885
  width: 14,
7844
7886
  height: 14,
@@ -7874,14 +7916,18 @@ var init_DamageNumber = __esm({
7874
7916
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
7875
7917
  }
7876
7918
  `;
7877
- DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
7919
+ DEFAULT_ASSET_URL10 = {
7920
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
7921
+ role: "effect",
7922
+ category: "effect"
7923
+ };
7878
7924
  DamageNumber.displayName = "DamageNumber";
7879
7925
  }
7880
7926
  });
7881
7927
  function DialogueBubble({
7882
7928
  speaker = "Hero",
7883
7929
  text = "The dungeon awaits. Choose your path wisely.",
7884
- portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
7930
+ portrait = DEFAULT_PORTRAIT,
7885
7931
  position = "bottom",
7886
7932
  className
7887
7933
  }) {
@@ -7897,7 +7943,7 @@ function DialogueBubble({
7897
7943
  portrait && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsx(
7898
7944
  "img",
7899
7945
  {
7900
- src: portrait,
7946
+ src: portrait?.url,
7901
7947
  alt: speaker ?? "speaker",
7902
7948
  className: "w-full h-full object-cover"
7903
7949
  }
@@ -7910,9 +7956,15 @@ function DialogueBubble({
7910
7956
  }
7911
7957
  );
7912
7958
  }
7959
+ var DEFAULT_PORTRAIT;
7913
7960
  var init_DialogueBubble = __esm({
7914
7961
  "components/game/atoms/DialogueBubble.tsx"() {
7915
7962
  init_cn();
7963
+ DEFAULT_PORTRAIT = {
7964
+ url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
7965
+ role: "effect",
7966
+ category: "character"
7967
+ };
7916
7968
  DialogueBubble.displayName = "DialogueBubble";
7917
7969
  }
7918
7970
  });
@@ -7956,7 +8008,7 @@ function ChoiceButton({
7956
8008
  assetUrl ? /* @__PURE__ */ jsx(
7957
8009
  "img",
7958
8010
  {
7959
- src: assetUrl,
8011
+ src: assetUrl.url,
7960
8012
  alt: "",
7961
8013
  width: 16,
7962
8014
  height: 16,
@@ -8026,7 +8078,7 @@ function ActionButton({
8026
8078
  assetUrl ? /* @__PURE__ */ jsx(
8027
8079
  "img",
8028
8080
  {
8029
- src: assetUrl,
8081
+ src: assetUrl.url,
8030
8082
  alt: "",
8031
8083
  width: 16,
8032
8084
  height: 16,
@@ -8070,7 +8122,11 @@ var init_ActionButton = __esm({
8070
8122
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
8071
8123
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
8072
8124
  };
8073
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
8125
+ DEFAULT_ASSET_URL11 = {
8126
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
8127
+ role: "effect",
8128
+ category: "effect"
8129
+ };
8074
8130
  ActionButton.displayName = "ActionButton";
8075
8131
  }
8076
8132
  });
@@ -11001,12 +11057,7 @@ var init_useCanvasGestures = __esm({
11001
11057
  }
11002
11058
  });
11003
11059
  function unitAtlasUrl(unit) {
11004
- if (unit.spriteSheet) return unit.spriteSheet;
11005
- const sprite = unit.sprite;
11006
- if (!sprite) return null;
11007
- const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
11008
- if (!match) return null;
11009
- return `${match[1]}.json`;
11060
+ return unit.spriteSheet?.url ?? null;
11010
11061
  }
11011
11062
  function resolveSheetUrl(atlasUrl, relativeSheetPath) {
11012
11063
  try {
@@ -11202,7 +11253,6 @@ function IsometricCanvas({
11202
11253
  // Tuning
11203
11254
  diamondTopY: diamondTopYProp,
11204
11255
  // Remote asset loading
11205
- assetBaseUrl,
11206
11256
  assetManifest
11207
11257
  }) {
11208
11258
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -11284,54 +11334,48 @@ function IsometricCanvas({
11284
11334
  const attackTargetSet = useMemo(() => {
11285
11335
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
11286
11336
  }, [attackTargets]);
11287
- const resolveManifestUrl7 = useCallback((relativePath) => {
11288
- if (!relativePath) return void 0;
11289
- if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
11290
- return relativePath;
11291
- }, [assetBaseUrl]);
11292
11337
  const spriteUrls = useMemo(() => {
11293
11338
  const urls = [];
11294
11339
  for (const tile of sortedTiles) {
11295
- if (tile.terrainSprite) urls.push(tile.terrainSprite);
11340
+ if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
11296
11341
  else if (getTerrainSprite) {
11297
11342
  const url = getTerrainSprite(tile.terrain ?? "");
11298
11343
  if (url) urls.push(url);
11299
11344
  } else {
11300
- const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
11345
+ const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
11301
11346
  if (url) urls.push(url);
11302
11347
  }
11303
11348
  }
11304
11349
  for (const feature of features) {
11305
- if (feature.sprite) urls.push(feature.sprite);
11350
+ if (feature.sprite) urls.push(feature.sprite.url);
11306
11351
  else if (getFeatureSprite) {
11307
11352
  const url = getFeatureSprite(feature.type);
11308
11353
  if (url) urls.push(url);
11309
11354
  } else {
11310
- const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
11355
+ const url = assetManifest?.features?.[feature.type]?.url;
11311
11356
  if (url) urls.push(url);
11312
11357
  }
11313
11358
  }
11314
11359
  for (const unit of units) {
11315
- if (unit.sprite) urls.push(unit.sprite);
11360
+ if (unit.sprite) urls.push(unit.sprite.url);
11316
11361
  else if (getUnitSprite) {
11317
11362
  const url = getUnitSprite(unit);
11318
11363
  if (url) urls.push(url);
11319
11364
  } else if (unit.unitType) {
11320
- const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
11365
+ const url = assetManifest?.units?.[unit.unitType]?.url;
11321
11366
  if (url) urls.push(url);
11322
11367
  }
11323
11368
  }
11324
11369
  if (assetManifest?.effects) {
11325
- for (const path of Object.values(assetManifest.effects)) {
11326
- const url = resolveManifestUrl7(path);
11327
- if (url) urls.push(url);
11370
+ for (const asset of Object.values(assetManifest.effects)) {
11371
+ if (asset.url) urls.push(asset.url);
11328
11372
  }
11329
11373
  }
11330
11374
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
11331
11375
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
11332
11376
  if (backgroundImage) urls.push(backgroundImage);
11333
11377
  return [...new Set(urls.filter(Boolean))];
11334
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
11378
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest]);
11335
11379
  const { getImage, pendingCount: _imagePendingCount } = useImageCache(spriteUrls);
11336
11380
  useEffect(() => {
11337
11381
  if (typeof window === "undefined") return;
@@ -11356,14 +11400,14 @@ function IsometricCanvas({
11356
11400
  lerpToTarget
11357
11401
  } = useCamera();
11358
11402
  const resolveTerrainSpriteUrl = useCallback((tile) => {
11359
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
11360
- }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
11403
+ return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
11404
+ }, [getTerrainSprite, assetManifest]);
11361
11405
  const resolveFeatureSpriteUrl = useCallback((featureType) => {
11362
- return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
11363
- }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
11406
+ return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
11407
+ }, [getFeatureSprite, assetManifest]);
11364
11408
  const resolveUnitSpriteUrl = useCallback((unit) => {
11365
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
11366
- }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
11409
+ return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
11410
+ }, [getUnitSprite, assetManifest]);
11367
11411
  const miniMapTiles = useMemo(() => {
11368
11412
  if (!showMinimap) return [];
11369
11413
  return sortedTiles.map((t2) => ({
@@ -11510,7 +11554,7 @@ function IsometricCanvas({
11510
11554
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11511
11555
  continue;
11512
11556
  }
11513
- const spriteUrl = feature.sprite || resolveFeatureSpriteUrl(feature.type);
11557
+ const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
11514
11558
  const img = spriteUrl ? getImage(spriteUrl) : null;
11515
11559
  const centerX = pos.x + scaledTileWidth / 2;
11516
11560
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
@@ -11559,12 +11603,12 @@ function IsometricCanvas({
11559
11603
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
11560
11604
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
11561
11605
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11606
+ const unitIsSheet = unit.sprite?.dimension === "2d" && (unit.sprite?.animations?.length ?? 0) > 0;
11562
11607
  const SHEET_ROWS = 5;
11563
11608
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
11564
11609
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
11565
- const imgIsSheet = img ? img.naturalWidth % SHEET_COLUMNS === 0 && img.naturalHeight % SHEET_ROWS === 0 && Math.abs(sheetFrameW - sheetFrameH) < 2 : false;
11566
- const frameW = imgIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11567
- const frameH = imgIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11610
+ const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11611
+ const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11568
11612
  const ar = frameW / (frameH || 1);
11569
11613
  let drawH = unitDrawH;
11570
11614
  let drawW = unitDrawH * ar;
@@ -11579,7 +11623,7 @@ function IsometricCanvas({
11579
11623
  ctx.save();
11580
11624
  ctx.globalAlpha = 0.25;
11581
11625
  if (img) {
11582
- if (imgIsSheet) {
11626
+ if (unitIsSheet) {
11583
11627
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11584
11628
  } else {
11585
11629
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
@@ -11627,7 +11671,7 @@ function IsometricCanvas({
11627
11671
  } else if (img) {
11628
11672
  const spriteY = groundY - drawH - breatheOffset;
11629
11673
  const drawUnit = (x) => {
11630
- if (imgIsSheet) {
11674
+ if (unitIsSheet) {
11631
11675
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
11632
11676
  } else {
11633
11677
  ctx.drawImage(img, x, spriteY, drawW, drawH);
@@ -11654,7 +11698,7 @@ function IsometricCanvas({
11654
11698
  }
11655
11699
  }
11656
11700
  for (const fx of effects) {
11657
- const spriteUrl = resolveManifestUrl7(assetManifest?.effects?.[fx.key]);
11701
+ const spriteUrl = assetManifest?.effects?.[fx.key]?.url;
11658
11702
  if (!spriteUrl) continue;
11659
11703
  const img = getImage(spriteUrl);
11660
11704
  if (!img) continue;
@@ -11698,7 +11742,6 @@ function IsometricCanvas({
11698
11742
  backgroundImage,
11699
11743
  cameraRef,
11700
11744
  unitScale,
11701
- resolveManifestUrl7,
11702
11745
  assetManifest
11703
11746
  ]);
11704
11747
  useEffect(() => {
@@ -11976,6 +12019,42 @@ var init_boardEntity = __esm({
11976
12019
  "components/game/organisms/boardEntity.ts"() {
11977
12020
  }
11978
12021
  });
12022
+
12023
+ // components/game/organisms/utils/makeAsset.ts
12024
+ function makeAsset(url, role, overrides = {}) {
12025
+ const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
12026
+ return {
12027
+ url,
12028
+ role,
12029
+ category: url.split("/").pop()?.replace(/\.[^.]+$/, "") ?? role,
12030
+ ...defaults,
12031
+ ...overrides
12032
+ };
12033
+ }
12034
+ function makeAssetMap(record, role, overrides = {}) {
12035
+ const result = {};
12036
+ for (const [key, url] of Object.entries(record)) {
12037
+ result[key] = makeAsset(url, role, overrides);
12038
+ }
12039
+ return result;
12040
+ }
12041
+ var ROLE_DEFAULTS;
12042
+ var init_makeAsset = __esm({
12043
+ "components/game/organisms/utils/makeAsset.ts"() {
12044
+ ROLE_DEFAULTS = {
12045
+ tile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12046
+ decoration: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12047
+ effect: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12048
+ item: { dimension: "2d", animations: ["static"], aspect: "5:7" },
12049
+ player: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12050
+ enemy: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12051
+ npc: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12052
+ projectile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12053
+ vehicle: { dimension: "2d", animations: ["idle", "walk"], aspect: "1:1" },
12054
+ ui: { dimension: "2d", animations: ["static"], aspect: "1:1" }
12055
+ };
12056
+ }
12057
+ });
11979
12058
  function buildDefaultBattleTiles() {
11980
12059
  const tiles = [];
11981
12060
  for (let y = 0; y < BATTLE_GRID_H; y++) {
@@ -12034,14 +12113,14 @@ function BattleBoard({
12034
12113
  if (o === null || typeof o.x !== "number" || typeof o.y !== "number") return [];
12035
12114
  const tile = { x: o.x, y: o.y };
12036
12115
  if (typeof o.terrain === "string") tile.terrain = o.terrain;
12037
- if (typeof o.terrainSprite === "string") tile.terrainSprite = o.terrainSprite;
12116
+ if (typeof o.terrainSprite === "string") tile.terrainSprite = makeAsset(o.terrainSprite, "tile");
12038
12117
  if (typeof o.passable === "boolean") tile.passable = o.passable;
12039
12118
  if (typeof o.movementCost === "number") tile.movementCost = o.movementCost;
12040
12119
  if (typeof o.elevation === "number") tile.elevation = o.elevation;
12041
12120
  if (typeof o.type === "string") tile.type = o.type;
12042
12121
  if (typeof o.tileType === "string") tile.tileType = o.tileType;
12043
12122
  if (typeof o.id === "string") tile.id = o.id;
12044
- if (typeof o.modelUrl === "string") tile.modelUrl = o.modelUrl;
12123
+ if (typeof o.modelUrl === "string") tile.modelUrl = makeAsset(o.modelUrl, "decoration", { dimension: "3d" });
12045
12124
  return [tile];
12046
12125
  }) : []);
12047
12126
  const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
@@ -12050,10 +12129,10 @@ function BattleBoard({
12050
12129
  if (o === null || typeof o.type !== "string" || typeof o.x !== "number" || typeof o.y !== "number") return [];
12051
12130
  const feat = { type: o.type, x: o.x, y: o.y };
12052
12131
  if (typeof o.id === "string") feat.id = o.id;
12053
- if (typeof o.sprite === "string") feat.sprite = o.sprite;
12132
+ if (typeof o.sprite === "string") feat.sprite = makeAsset(o.sprite, "decoration");
12054
12133
  if (typeof o.color === "string") feat.color = o.color;
12055
12134
  if (typeof o.elevation === "number") feat.elevation = o.elevation;
12056
- if (typeof o.assetUrl === "string") feat.assetUrl = o.assetUrl;
12135
+ if (typeof o.assetUrl === "string") feat.assetUrl = makeAsset(o.assetUrl, "decoration", { dimension: "3d" });
12057
12136
  return [feat];
12058
12137
  }) : []);
12059
12138
  const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
@@ -12169,7 +12248,7 @@ function BattleBoard({
12169
12248
  maxHealth: num(unit.maxHealth),
12170
12249
  unitType: unit.unitType == null ? void 0 : str(unit.unitType),
12171
12250
  heroId: unit.heroId == null ? void 0 : str(unit.heroId),
12172
- sprite: unit.sprite == null ? void 0 : str(unit.sprite),
12251
+ sprite: unit.sprite == null ? void 0 : makeAsset(str(unit.sprite), "npc"),
12173
12252
  traits: unitTraits?.map((tr) => ({
12174
12253
  name: tr.name,
12175
12254
  currentState: tr.currentState,
@@ -12319,7 +12398,6 @@ function BattleBoard({
12319
12398
  onTileHover: (x, y) => setHoveredTile({ x, y }),
12320
12399
  onTileLeave: () => setHoveredTile(null),
12321
12400
  scale,
12322
- assetBaseUrl: assetManifest?.baseUrl,
12323
12401
  assetManifest,
12324
12402
  backgroundImage,
12325
12403
  onDrawEffects,
@@ -12397,15 +12475,16 @@ var init_BattleBoard = __esm({
12397
12475
  init_IsometricCanvas();
12398
12476
  init_boardEntity();
12399
12477
  init_isometric();
12478
+ init_makeAsset();
12400
12479
  BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
12401
12480
  BATTLE_GRID_W = 16;
12402
12481
  BATTLE_GRID_H = 16;
12403
12482
  BATTLE_TERRAIN_SPRITES = [
12404
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
12405
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
12406
- `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
12407
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
12408
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
12483
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`, "tile"),
12484
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile"),
12485
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`, "tile"),
12486
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, "tile"),
12487
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile")
12409
12488
  ];
12410
12489
  DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
12411
12490
  BattleBoard.displayName = "BattleBoard";
@@ -12444,61 +12523,64 @@ function BattleTemplate({
12444
12523
  }
12445
12524
  );
12446
12525
  }
12447
- var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12526
+ var CDN, STONE, DIRT, GRASS, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12448
12527
  var init_BattleTemplate = __esm({
12449
12528
  "components/game/templates/BattleTemplate.tsx"() {
12450
12529
  init_BattleBoard();
12530
+ init_makeAsset();
12451
12531
  CDN = "https://almadar-kflow-assets.web.app/shared";
12532
+ STONE = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`, "tile");
12533
+ DIRT = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`, "tile");
12534
+ GRASS = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`, "tile");
12452
12535
  DEFAULT_BATTLE_TILES2 = [
12453
- { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12454
- { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12455
- { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12456
- { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12457
- { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12458
- { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12459
- { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12460
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12461
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12462
- { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12463
- { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12464
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12465
- { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12466
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12467
- { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12468
- { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12469
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12470
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12471
- { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12472
- { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12473
- { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12474
- { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12475
- { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12476
- { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12477
- { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` }
12536
+ { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12537
+ { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12538
+ { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12539
+ { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12540
+ { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12541
+ { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
12542
+ { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: DIRT },
12543
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
12544
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
12545
+ { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
12546
+ { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
12547
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
12548
+ { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: DIRT },
12549
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
12550
+ { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
12551
+ { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
12552
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
12553
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
12554
+ { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: DIRT },
12555
+ { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
12556
+ { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12557
+ { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12558
+ { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12559
+ { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12560
+ { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: STONE }
12478
12561
  ];
12479
12562
  DEFAULT_BATTLE_UNITS = [
12480
- { 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` },
12481
- { 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` }
12563
+ { 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") },
12564
+ { 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") }
12482
12565
  ];
12483
12566
  DEFAULT_BATTLE_FEATURES = [
12484
- { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: `${CDN}/world-map/gold_mine.png` },
12485
- { id: "f2", x: 3, y: 1, type: "portal", sprite: `${CDN}/world-map/portal_open.png` }
12567
+ { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: makeAsset(`${CDN}/world-map/gold_mine.png`, "decoration") },
12568
+ { id: "f2", x: 3, y: 1, type: "portal", sprite: makeAsset(`${CDN}/world-map/portal_open.png`, "decoration") }
12486
12569
  ];
12487
12570
  DEFAULT_BATTLE_MANIFEST = {
12488
- baseUrl: CDN,
12489
- terrains: {
12490
- stone: "/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png",
12491
- dirt: "/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png",
12492
- grass: "/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png"
12493
- },
12494
- units: {
12495
- worker: "/sprite-sheets/amir-sprite-sheet-se.png",
12496
- guardian: "/sprite-sheets/destroyer-sprite-sheet-sw.png"
12497
- },
12498
- features: {
12499
- gold_mine: "/world-map/gold_mine.png",
12500
- portal: "/world-map/portal_open.png"
12501
- }
12571
+ terrains: makeAssetMap({
12572
+ stone: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`,
12573
+ dirt: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`,
12574
+ grass: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`
12575
+ }, "tile"),
12576
+ units: makeAssetMap({
12577
+ worker: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png`,
12578
+ guardian: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`
12579
+ }, "npc"),
12580
+ features: makeAssetMap({
12581
+ gold_mine: `${CDN}/world-map/gold_mine.png`,
12582
+ portal: `${CDN}/world-map/portal_open.png`
12583
+ }, "decoration")
12502
12584
  };
12503
12585
  BattleTemplate.displayName = "BattleTemplate";
12504
12586
  }
@@ -14713,7 +14795,6 @@ function BoardgameBoard({
14713
14795
  units,
14714
14796
  features,
14715
14797
  assetManifest,
14716
- assetBaseUrl,
14717
14798
  scale,
14718
14799
  showMinimap,
14719
14800
  enableCamera,
@@ -19783,7 +19864,7 @@ function CardHand({
19783
19864
  /* @__PURE__ */ jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsx(
19784
19865
  "img",
19785
19866
  {
19786
- src: card.iconUrl,
19867
+ src: card.iconUrl.url,
19787
19868
  alt: card.title ?? card.id,
19788
19869
  width: art,
19789
19870
  height: art,
@@ -19841,15 +19922,6 @@ var init_CardHand = __esm({
19841
19922
  CardHand.displayName = "CardHand";
19842
19923
  }
19843
19924
  });
19844
- function resolveManifestUrl(manifest, relative) {
19845
- if (relative == null) return void 0;
19846
- if (/^https?:\/\//.test(relative)) return relative;
19847
- const base = manifest?.baseUrl;
19848
- if (base == null) return relative;
19849
- const cleanBase = base.replace(/\/$/, "");
19850
- const cleanRel = relative.replace(/^\//, "");
19851
- return `${cleanBase}/${cleanRel}`;
19852
- }
19853
19925
  function rowToCard(r) {
19854
19926
  return {
19855
19927
  id: str(r.id),
@@ -19863,7 +19935,7 @@ function rowToCard(r) {
19863
19935
  function toHandCards(cards, manifest, mana) {
19864
19936
  return cards.map((c) => {
19865
19937
  const key = c.iconKey ?? c.id;
19866
- const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
19938
+ const iconUrl = manifest?.cards?.[key];
19867
19939
  return {
19868
19940
  id: c.id,
19869
19941
  iconUrl,
@@ -20977,7 +21049,6 @@ function CastleBoard({
20977
21049
  onTileHover: (x, y) => setHoveredTile({ x, y }),
20978
21050
  onTileLeave: () => setHoveredTile(null),
20979
21051
  scale,
20980
- assetBaseUrl: assetManifest?.baseUrl,
20981
21052
  assetManifest,
20982
21053
  backgroundImage
20983
21054
  }
@@ -21053,60 +21124,63 @@ function CastleTemplate({
21053
21124
  }
21054
21125
  );
21055
21126
  }
21056
- var CDN2, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
21127
+ var CDN2, WALL, FLOOR, FLOOR_CENTER, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
21057
21128
  var init_CastleTemplate = __esm({
21058
21129
  "components/game/templates/CastleTemplate.tsx"() {
21059
21130
  init_CastleBoard();
21131
+ init_makeAsset();
21060
21132
  CDN2 = "https://almadar-kflow-assets.web.app/shared";
21133
+ WALL = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`, "tile");
21134
+ FLOOR = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
21135
+ FLOOR_CENTER = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`, "tile");
21061
21136
  DEFAULT_CASTLE_TILES = [
21062
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21063
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21064
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21065
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21066
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21067
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21068
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21069
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21070
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21071
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21072
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21073
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21074
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png` },
21075
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21076
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21077
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21078
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21079
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21080
- { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21081
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21082
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21083
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21084
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21085
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21086
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` }
21137
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21138
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21139
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21140
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21141
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21142
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
21143
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21144
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21145
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21146
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
21147
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
21148
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
21149
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR_CENTER },
21150
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
21151
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
21152
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
21153
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21154
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21155
+ { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21156
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
21157
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21158
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21159
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21160
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21161
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: WALL }
21087
21162
  ];
21088
21163
  DEFAULT_CASTLE_UNITS = [
21089
- { 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` },
21090
- { 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` }
21164
+ { 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") },
21165
+ { 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") }
21091
21166
  ];
21092
21167
  DEFAULT_CASTLE_FEATURES = [
21093
- { id: "f1", x: 2, y: 2, type: "chest", sprite: `${CDN2}/world-map/treasure_chest_closed.png` },
21094
- { id: "f2", x: 3, y: 1, type: "crystal", sprite: `${CDN2}/world-map/resonance_crystal.png` }
21168
+ { id: "f1", x: 2, y: 2, type: "chest", sprite: makeAsset(`${CDN2}/world-map/treasure_chest_closed.png`, "decoration") },
21169
+ { id: "f2", x: 3, y: 1, type: "crystal", sprite: makeAsset(`${CDN2}/world-map/resonance_crystal.png`, "decoration") }
21095
21170
  ];
21096
21171
  DEFAULT_CASTLE_MANIFEST = {
21097
- baseUrl: CDN2,
21098
- terrains: {
21099
- wall: "/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png",
21100
- floor: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png"
21101
- },
21102
- units: {
21103
- worker: "/sprite-sheets/coordinator-sprite-sheet-se.png",
21104
- guardian: "/sprite-sheets/forger-sprite-sheet-se.png"
21105
- },
21106
- features: {
21107
- chest: "/world-map/treasure_chest_closed.png",
21108
- crystal: "/world-map/resonance_crystal.png"
21109
- }
21172
+ terrains: makeAssetMap({
21173
+ wall: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
21174
+ floor: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`
21175
+ }, "tile"),
21176
+ units: makeAssetMap({
21177
+ worker: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`,
21178
+ guardian: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`
21179
+ }, "player"),
21180
+ features: makeAssetMap({
21181
+ chest: `${CDN2}/world-map/treasure_chest_closed.png`,
21182
+ crystal: `${CDN2}/world-map/resonance_crystal.png`
21183
+ }, "decoration")
21110
21184
  };
21111
21185
  CastleTemplate.displayName = "CastleTemplate";
21112
21186
  }
@@ -22094,15 +22168,6 @@ var init_ChatBar = __esm({
22094
22168
  ChatBar.displayName = "ChatBar";
22095
22169
  }
22096
22170
  });
22097
- function resolveManifestUrl2(manifest, relative) {
22098
- if (relative == null) return void 0;
22099
- if (/^https?:\/\//.test(relative)) return relative;
22100
- const base = manifest?.baseUrl;
22101
- if (base == null) return relative;
22102
- const cleanBase = base.replace(/\/$/, "");
22103
- const cleanRel = relative.replace(/^\//, "");
22104
- return `${cleanBase}/${cleanRel}`;
22105
- }
22106
22171
  function buildDefaultCBTiles() {
22107
22172
  const tiles = [];
22108
22173
  for (let y = 0; y < CB_GRID_H; y++) {
@@ -22117,12 +22182,12 @@ function buildDefaultCBTiles() {
22117
22182
  function tilesToIso(tiles, manifest) {
22118
22183
  return tiles.map((t) => {
22119
22184
  const key = t.terrain ?? "grass";
22120
- const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
22185
+ const terrainSprite = t.terrainSprite ?? manifest?.terrains?.[key] ?? manifest?.terrains?.grass;
22121
22186
  return {
22122
22187
  x: t.x,
22123
22188
  y: t.y,
22124
22189
  terrain: t.terrain,
22125
- terrainSprite: sprite,
22190
+ terrainSprite,
22126
22191
  passable: t.passable
22127
22192
  };
22128
22193
  });
@@ -22133,7 +22198,7 @@ function buildingsToFeatures(buildings, manifest) {
22133
22198
  x: b.x,
22134
22199
  y: b.y,
22135
22200
  type: b.type,
22136
- sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
22201
+ sprite: manifest?.features?.[b.type]
22137
22202
  }));
22138
22203
  }
22139
22204
  function CityBuilderBoard({
@@ -22165,7 +22230,7 @@ function CityBuilderBoard({
22165
22230
  x: num(r.x),
22166
22231
  y: num(r.y),
22167
22232
  terrain: r.terrain == null ? void 0 : str(r.terrain),
22168
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
22233
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
22169
22234
  passable: r.passable !== false
22170
22235
  })),
22171
22236
  [board.tiles]
@@ -22274,7 +22339,6 @@ function CityBuilderBoard({
22274
22339
  {
22275
22340
  tiles: isoTiles,
22276
22341
  features: buildingFeatures,
22277
- assetBaseUrl: assetManifest?.baseUrl,
22278
22342
  assetManifest,
22279
22343
  validMoves,
22280
22344
  hoveredTile,
@@ -22309,6 +22373,7 @@ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
22309
22373
  var init_CityBuilderBoard = __esm({
22310
22374
  "components/game/organisms/CityBuilderBoard.tsx"() {
22311
22375
  "use client";
22376
+ init_makeAsset();
22312
22377
  init_cn();
22313
22378
  init_useEventBus();
22314
22379
  init_Box();
@@ -28303,7 +28368,7 @@ function StatBadge({
28303
28368
  resolvedAsset ? /* @__PURE__ */ jsx(
28304
28369
  "img",
28305
28370
  {
28306
- src: resolvedAsset,
28371
+ src: resolvedAsset.url,
28307
28372
  alt: "",
28308
28373
  width: 16,
28309
28374
  height: 16,
@@ -28610,7 +28675,7 @@ function GameCanvas2D({
28610
28675
  tickEvent,
28611
28676
  drawEvent,
28612
28677
  fps = 60,
28613
- backgroundImage = "",
28678
+ backgroundImage,
28614
28679
  assetBaseUrl,
28615
28680
  className
28616
28681
  }) {
@@ -28674,7 +28739,7 @@ function GameCanvas2D({
28674
28739
  emitRef.current(tickEventRef.current, { dt, frame });
28675
28740
  }
28676
28741
  if (backgroundImageRef.current) {
28677
- const bgImg = loadImage(backgroundImageRef.current);
28742
+ const bgImg = loadImage(backgroundImageRef.current.url);
28678
28743
  if (bgImg) {
28679
28744
  ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
28680
28745
  } else {
@@ -29045,7 +29110,7 @@ function EnemyPlate({
29045
29110
  assetUrl && /* @__PURE__ */ jsx(
29046
29111
  "img",
29047
29112
  {
29048
- src: assetUrl,
29113
+ src: assetUrl.url,
29049
29114
  alt: name,
29050
29115
  width: 24,
29051
29116
  height: 24,
@@ -29387,7 +29452,7 @@ function DialogueBox({
29387
29452
  "div",
29388
29453
  {
29389
29454
  className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
29390
- style: { backgroundImage: `url(${backgroundImage})` },
29455
+ style: { backgroundImage: `url(${backgroundImage?.url})` },
29391
29456
  "aria-hidden": "true"
29392
29457
  }
29393
29458
  ),
@@ -29402,7 +29467,7 @@ function DialogueBox({
29402
29467
  children: /* @__PURE__ */ jsx(
29403
29468
  "img",
29404
29469
  {
29405
- src: portraitUrl,
29470
+ src: portraitUrl?.url,
29406
29471
  alt: dialogue.speaker,
29407
29472
  className: "h-full w-auto object-contain drop-shadow-2xl"
29408
29473
  }
@@ -41708,7 +41773,6 @@ var init_FeatureGridOrganism = __esm({
41708
41773
  });
41709
41774
  function FishingBoard({
41710
41775
  backgroundImage,
41711
- assetBaseUrl,
41712
41776
  scale = 1,
41713
41777
  showMinimap = false,
41714
41778
  enableCamera = true,
@@ -41726,8 +41790,7 @@ function FishingBoard({
41726
41790
  {
41727
41791
  width,
41728
41792
  height,
41729
- backgroundImage: backgroundImage ?? "",
41730
- assetBaseUrl,
41793
+ backgroundImage,
41731
41794
  fps: 60,
41732
41795
  className: "w-full h-full"
41733
41796
  }
@@ -43946,7 +44009,7 @@ var init_GameCanvas3D2 = __esm({
43946
44009
  children: /* @__PURE__ */ jsx(
43947
44010
  ModelLoader,
43948
44011
  {
43949
- url: tile.modelUrl,
44012
+ url: tile.modelUrl.url,
43950
44013
  scale: 0.95,
43951
44014
  fallbackGeometry: "box",
43952
44015
  castShadow: true,
@@ -44011,7 +44074,7 @@ var init_GameCanvas3D2 = __esm({
44011
44074
  /* @__PURE__ */ jsx(
44012
44075
  ModelLoader,
44013
44076
  {
44014
- url: unit.modelUrl,
44077
+ url: unit.modelUrl.url,
44015
44078
  scale: modelScale,
44016
44079
  fallbackGeometry: "box",
44017
44080
  castShadow: true
@@ -44071,7 +44134,7 @@ var init_GameCanvas3D2 = __esm({
44071
44134
  return /* @__PURE__ */ jsx(
44072
44135
  ModelLoader,
44073
44136
  {
44074
- url: feature.assetUrl,
44137
+ url: feature.assetUrl.url,
44075
44138
  position,
44076
44139
  scale: 0.5,
44077
44140
  rotation: [0, feature.rotation ?? 0, 0],
@@ -44292,7 +44355,18 @@ function GameBoard3D({
44292
44355
  const row = boardEntity(entity);
44293
44356
  const eventBus = useEventBus();
44294
44357
  const entityUnits = row ? rows(row.units) : [];
44295
- const units = entityUnits;
44358
+ const units = entityUnits.map((r) => ({
44359
+ id: str(r.id),
44360
+ x: num(r.x),
44361
+ y: num(r.y),
44362
+ z: num(r.z),
44363
+ faction: str(r.faction) || "neutral",
44364
+ team: str(r.team) || str(r.faction) || "neutral",
44365
+ unitType: r.unitType == null ? void 0 : str(r.unitType),
44366
+ name: r.name == null ? void 0 : str(r.name),
44367
+ health: r.health == null ? void 0 : num(r.health),
44368
+ maxHealth: r.maxHealth == null ? void 0 : num(r.maxHealth)
44369
+ }));
44296
44370
  const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
44297
44371
  const phase = row ? str(row.phase) : "observation";
44298
44372
  const result = row ? str(row.result) : "none";
@@ -44471,22 +44545,27 @@ function resolveDescriptor(value, idPrefix) {
44471
44545
  }
44472
44546
  if (typeof value === "object" && value !== null) {
44473
44547
  const desc = asDescriptor(value);
44474
- if (desc !== null && getComponentForPattern(desc.type) !== null) {
44548
+ const hasComp = desc !== null && getComponentForPattern(desc.type) !== null;
44549
+ shellLog.debug("resolve", { idPrefix, type: desc?.type ?? null, hasDesc: desc !== null, render: hasComp });
44550
+ if (hasComp) {
44475
44551
  const resolvedProps = desc.props ?? {};
44476
44552
  const content = { id: desc._id ?? idPrefix, pattern: desc.type, props: resolvedProps, priority: 0 };
44477
44553
  const SCR = getSlotContentRenderer2();
44478
- return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 });
44554
+ return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 }, content.id);
44479
44555
  }
44556
+ } else {
44557
+ shellLog.debug("resolve", { idPrefix, type: null, hasDesc: false, render: false, branch: typeof value });
44480
44558
  }
44481
44559
  return null;
44482
44560
  }
44483
- var _scr, GameShell;
44561
+ var shellLog, _scr, GameShell;
44484
44562
  var init_GameShell = __esm({
44485
44563
  "components/game/templates/GameShell.tsx"() {
44486
44564
  init_cn();
44487
44565
  init_Box();
44488
44566
  init_Stack();
44489
44567
  init_Typography();
44568
+ shellLog = createLogger("almadar:ui:game:game-shell");
44490
44569
  _scr = null;
44491
44570
  GameShell = ({
44492
44571
  appName = "Game",
@@ -44887,7 +44966,6 @@ function HexStrategyBoard({
44887
44966
  units,
44888
44967
  features,
44889
44968
  assetManifest,
44890
- assetBaseUrl,
44891
44969
  scale,
44892
44970
  showMinimap,
44893
44971
  enableCamera,
@@ -44929,7 +45007,6 @@ function HolidayRunnerBoard({
44929
45007
  units,
44930
45008
  features,
44931
45009
  assetManifest,
44932
- assetBaseUrl,
44933
45010
  scale,
44934
45011
  showMinimap,
44935
45012
  enableCamera,
@@ -45724,7 +45801,6 @@ function MatchPuzzleBoard({
45724
45801
  units,
45725
45802
  features,
45726
45803
  assetManifest,
45727
- assetBaseUrl,
45728
45804
  scale,
45729
45805
  showMinimap,
45730
45806
  enableCamera,
@@ -45985,7 +46061,6 @@ function MinigolfBoard({
45985
46061
  units,
45986
46062
  features,
45987
46063
  assetManifest,
45988
- assetBaseUrl,
45989
46064
  scale,
45990
46065
  showMinimap,
45991
46066
  enableCamera,
@@ -46291,7 +46366,6 @@ function PirateBoard({
46291
46366
  units,
46292
46367
  features,
46293
46368
  assetManifest,
46294
- assetBaseUrl,
46295
46369
  scale,
46296
46370
  showMinimap,
46297
46371
  enableCamera,
@@ -46412,8 +46486,8 @@ function PlatformerBoard({
46412
46486
  canvasHeight,
46413
46487
  followCamera: true,
46414
46488
  bgColor,
46415
- playerSprite,
46416
- tileSprites,
46489
+ playerSprite: playerSprite?.url,
46490
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
46417
46491
  leftEvent,
46418
46492
  rightEvent,
46419
46493
  jumpEvent,
@@ -46478,7 +46552,7 @@ function PlatformerTemplate({
46478
46552
  worldHeight = 400,
46479
46553
  canvasWidth = 800,
46480
46554
  canvasHeight = 400,
46481
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
46555
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
46482
46556
  tileSprites = DEFAULT_TILE_SPRITES,
46483
46557
  bgColor = "#5c94fc",
46484
46558
  gameEndEvent = "GAME_END",
@@ -46531,13 +46605,14 @@ var init_PlatformerTemplate = __esm({
46531
46605
  init_PlatformerBoard();
46532
46606
  init_GameHud();
46533
46607
  init_ScoreBoard();
46608
+ init_makeAsset();
46534
46609
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
46535
- DEFAULT_TILE_SPRITES = {
46610
+ DEFAULT_TILE_SPRITES = makeAssetMap({
46536
46611
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
46537
46612
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
46538
46613
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
46539
46614
  goal: `${CDN3}/tiles/platformPack_tile007.png`
46540
- };
46615
+ }, "tile");
46541
46616
  DEFAULT_PLATFORMS = [
46542
46617
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
46543
46618
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -46693,7 +46768,6 @@ function RacingBoard({
46693
46768
  units,
46694
46769
  features,
46695
46770
  assetManifest,
46696
- assetBaseUrl,
46697
46771
  scale,
46698
46772
  showMinimap,
46699
46773
  enableCamera,
@@ -46712,27 +46786,18 @@ var init_RacingBoard = __esm({
46712
46786
  RacingBoard.displayName = "RacingBoard";
46713
46787
  }
46714
46788
  });
46715
- function resolveManifestUrl3(manifest, relative) {
46716
- if (relative == null) return void 0;
46717
- if (/^https?:\/\//.test(relative)) return relative;
46718
- const base = manifest?.baseUrl;
46719
- if (base == null) return relative;
46720
- const cleanBase = base.replace(/\/$/, "");
46721
- const cleanRel = relative.replace(/^\//, "");
46722
- return `${cleanBase}/${cleanRel}`;
46723
- }
46724
46789
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
46725
46790
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
46726
46791
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
46727
46792
  const isWall = isBorder || isPillar;
46728
46793
  const terrains = manifest?.terrains;
46729
46794
  if (x === stairsX && y === stairsY) {
46730
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
46795
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
46731
46796
  }
46732
46797
  if (isWall) {
46733
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
46798
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
46734
46799
  }
46735
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
46800
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
46736
46801
  }
46737
46802
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
46738
46803
  const tiles = [];
@@ -46776,7 +46841,7 @@ function RoguelikeBoard({
46776
46841
  x: num(r.x),
46777
46842
  y: num(r.y),
46778
46843
  terrain: r.terrain == null ? void 0 : str(r.terrain),
46779
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
46844
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
46780
46845
  passable: r.passable !== false
46781
46846
  })),
46782
46847
  [board.tiles]
@@ -46856,7 +46921,7 @@ function RoguelikeBoard({
46856
46921
  health: playerHp,
46857
46922
  maxHealth: playerMaxHp,
46858
46923
  unitType: "player",
46859
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
46924
+ sprite: assetManifest?.units?.player
46860
46925
  },
46861
46926
  ...liveEnemies.map((e) => ({
46862
46927
  id: e.id,
@@ -46866,7 +46931,7 @@ function RoguelikeBoard({
46866
46931
  health: e.hp,
46867
46932
  maxHealth: 6,
46868
46933
  unitType: "enemy",
46869
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
46934
+ sprite: assetManifest?.units?.enemy
46870
46935
  }))
46871
46936
  ];
46872
46937
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -46876,7 +46941,7 @@ function RoguelikeBoard({
46876
46941
  x: it.x,
46877
46942
  y: it.y,
46878
46943
  type: it.kind,
46879
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
46944
+ sprite: assetManifest?.features?.[it.kind]
46880
46945
  })),
46881
46946
  [items, assetManifest]
46882
46947
  );
@@ -46937,7 +47002,6 @@ function RoguelikeBoard({
46937
47002
  onTileHover: (x, y) => setHoveredTile({ x, y }),
46938
47003
  onTileLeave: () => setHoveredTile(null),
46939
47004
  scale,
46940
- assetBaseUrl: assetManifest?.baseUrl,
46941
47005
  assetManifest,
46942
47006
  unitScale,
46943
47007
  spriteHeightRatio,
@@ -46997,6 +47061,7 @@ var init_RoguelikeBoard = __esm({
46997
47061
  init_Stack();
46998
47062
  init_IsometricCanvas();
46999
47063
  init_boardEntity();
47064
+ init_makeAsset();
47000
47065
  DUNGEON_GRID_W = 16;
47001
47066
  DUNGEON_GRID_H = 16;
47002
47067
  DEFAULT_ENEMIES = [
@@ -47047,55 +47112,59 @@ function RoguelikeTemplate({
47047
47112
  }
47048
47113
  );
47049
47114
  }
47050
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
47115
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
47051
47116
  var init_RoguelikeTemplate = __esm({
47052
47117
  "components/game/templates/RoguelikeTemplate.tsx"() {
47053
47118
  init_RoguelikeBoard();
47119
+ init_makeAsset();
47054
47120
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
47121
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
47122
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
47123
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
47124
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
47055
47125
  DEFAULT_ROGUELIKE_TILES = [
47056
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47057
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47058
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47059
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47060
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47061
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47062
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47063
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47064
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47065
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47066
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47067
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47068
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47069
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47070
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47071
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47072
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47073
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47074
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
47075
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47076
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47077
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47078
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47079
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47080
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
47126
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47127
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47128
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47129
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47130
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47131
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
47132
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47133
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47134
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47135
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
47136
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
47137
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
47138
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
47139
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
47140
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
47141
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
47142
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
47143
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
47144
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
47145
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
47146
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47147
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47148
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47149
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47150
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
47081
47151
  ];
47082
47152
  DEFAULT_ROGUELIKE_MANIFEST = {
47083
- baseUrl: CDN4,
47084
- terrains: {
47085
- floor: "/isometric-dungeon/Isometric/dirt_E.png",
47086
- wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
47087
- stairs: "/isometric-dungeon/Isometric/stairs_E.png",
47088
- planks: "/isometric-dungeon/Isometric/planks_E.png"
47089
- },
47153
+ terrains: makeAssetMap({
47154
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
47155
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
47156
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
47157
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
47158
+ }, "tile"),
47090
47159
  units: {
47091
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
47092
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
47160
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
47161
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
47093
47162
  },
47094
- features: {
47095
- health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
47096
- sword: "/isometric-dungeon/Isometric/barrel_E.png",
47097
- shield: "/isometric-dungeon/Isometric/barrel_E.png"
47098
- }
47163
+ features: makeAssetMap({
47164
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
47165
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
47166
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
47167
+ }, "item")
47099
47168
  };
47100
47169
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
47101
47170
  }
@@ -49950,7 +50019,6 @@ function SokobanBoard({
49950
50019
  units,
49951
50020
  features,
49952
50021
  assetManifest,
49953
- assetBaseUrl,
49954
50022
  scale,
49955
50023
  showMinimap,
49956
50024
  enableCamera,
@@ -49992,7 +50060,6 @@ function SpaceShmupBoard({
49992
50060
  units,
49993
50061
  features,
49994
50062
  assetManifest,
49995
- assetBaseUrl,
49996
50063
  scale,
49997
50064
  showMinimap,
49998
50065
  enableCamera,
@@ -50034,7 +50101,6 @@ function SpaceStationBoard({
50034
50101
  units,
50035
50102
  features,
50036
50103
  assetManifest,
50037
- assetBaseUrl,
50038
50104
  scale,
50039
50105
  showMinimap,
50040
50106
  enableCamera,
@@ -50169,7 +50235,6 @@ function SportsBoard({
50169
50235
  units,
50170
50236
  features,
50171
50237
  assetManifest,
50172
- assetBaseUrl,
50173
50238
  scale,
50174
50239
  showMinimap,
50175
50240
  enableCamera,
@@ -52013,7 +52078,6 @@ function TanksBoard({
52013
52078
  units,
52014
52079
  features,
52015
52080
  assetManifest,
52016
- assetBaseUrl,
52017
52081
  scale,
52018
52082
  showMinimap,
52019
52083
  enableCamera,
@@ -52291,15 +52355,6 @@ var init_ToastSlot = __esm({
52291
52355
  ToastSlot.displayName = "ToastSlot";
52292
52356
  }
52293
52357
  });
52294
- function resolveManifestUrl4(manifest, relative) {
52295
- if (relative == null || relative === "") return void 0;
52296
- if (/^https?:\/\//.test(relative)) return relative;
52297
- const base = manifest?.baseUrl;
52298
- if (base == null) return relative;
52299
- const cleanBase = base.replace(/\/$/, "");
52300
- const cleanRel = relative.replace(/^\//, "");
52301
- return `${cleanBase}/${cleanRel}`;
52302
- }
52303
52358
  function readPlayer(v) {
52304
52359
  if (v == null || typeof v !== "object") return void 0;
52305
52360
  const o = v;
@@ -52352,10 +52407,10 @@ function TopDownShooterBoard({
52352
52407
  const wave = propWave ?? num(board.wave, 1);
52353
52408
  const lives = propLives ?? num(board.lives, 3);
52354
52409
  const result = propResult ?? (str(board.result) || "none");
52355
- const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
52356
- const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
52357
- const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
52358
- const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
52410
+ const playerSprite = assetManifest?.units?.player?.url;
52411
+ const enemySprite = assetManifest?.units?.enemy?.url;
52412
+ const projectileSprite = assetManifest?.features?.projectile?.url;
52413
+ const backgroundSprite = assetManifest?.background;
52359
52414
  const spriteUrls = useMemo(
52360
52415
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
52361
52416
  [playerSprite, enemySprite, projectileSprite]
@@ -52522,7 +52577,6 @@ function TopDownShooterBoard({
52522
52577
  width,
52523
52578
  height,
52524
52579
  backgroundImage: backgroundSprite,
52525
- assetBaseUrl: assetManifest?.baseUrl,
52526
52580
  onDraw
52527
52581
  }
52528
52582
  ),
@@ -52647,15 +52701,6 @@ var init_TopDownShooterTemplate = __esm({
52647
52701
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
52648
52702
  }
52649
52703
  });
52650
- function resolveManifestUrl5(manifest, relative) {
52651
- if (relative == null) return void 0;
52652
- if (/^https?:\/\//.test(relative)) return relative;
52653
- const base = manifest?.baseUrl;
52654
- if (base == null) return relative;
52655
- const cleanBase = base.replace(/\/$/, "");
52656
- const cleanRel = relative.replace(/^\//, "");
52657
- return `${cleanBase}/${cleanRel}`;
52658
- }
52659
52704
  function buildDefaultTDTiles() {
52660
52705
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
52661
52706
  const tiles = [];
@@ -52675,18 +52720,18 @@ function buildDefaultTDTiles() {
52675
52720
  function tilesToIso2(tiles, manifest) {
52676
52721
  return tiles.map((t) => {
52677
52722
  const key = t.terrain ?? "ground";
52678
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
52723
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
52679
52724
  return {
52680
52725
  x: t.x,
52681
52726
  y: t.y,
52682
52727
  terrain: t.terrain,
52683
- terrainSprite: sprite,
52728
+ terrainSprite,
52684
52729
  passable: t.passable
52685
52730
  };
52686
52731
  });
52687
52732
  }
52688
52733
  function creepsToUnits(creeps, manifest) {
52689
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
52734
+ const sprite = manifest?.units?.creep;
52690
52735
  return creeps.map((c) => ({
52691
52736
  id: c.id,
52692
52737
  position: { x: c.x, y: c.y },
@@ -52704,14 +52749,14 @@ function heroToUnit(hero, manifest) {
52704
52749
  position: { x: hero.x, y: hero.y },
52705
52750
  name: "Hero",
52706
52751
  team: "player",
52707
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
52752
+ sprite: manifest?.units?.hero,
52708
52753
  unitType: "hero",
52709
52754
  health: 1,
52710
52755
  maxHealth: 1
52711
52756
  };
52712
52757
  }
52713
52758
  function towersToFeatures(towers, manifest) {
52714
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
52759
+ const sprite = manifest?.features?.tower;
52715
52760
  return towers.map((t) => ({
52716
52761
  id: t.id,
52717
52762
  x: t.x,
@@ -52909,7 +52954,6 @@ function TowerDefenseBoard({
52909
52954
  tiles: isoTiles,
52910
52955
  units: isoUnits,
52911
52956
  features: towerFeatures,
52912
- assetBaseUrl: assetManifest?.baseUrl,
52913
52957
  assetManifest,
52914
52958
  validMoves,
52915
52959
  hoveredTile,
@@ -52953,6 +52997,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
52953
52997
  var init_TowerDefenseBoard = __esm({
52954
52998
  "components/game/organisms/TowerDefenseBoard.tsx"() {
52955
52999
  "use client";
53000
+ init_makeAsset();
52956
53001
  init_cn();
52957
53002
  init_useEventBus();
52958
53003
  init_Box();
@@ -53282,15 +53327,6 @@ var init_UncontrolledBattleBoard = __esm({
53282
53327
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
53283
53328
  }
53284
53329
  });
53285
- function resolveManifestUrl6(manifest, relative) {
53286
- if (relative == null) return void 0;
53287
- if (/^https?:\/\//.test(relative)) return relative;
53288
- const base = manifest?.baseUrl;
53289
- if (base == null) return relative;
53290
- const cleanBase = base.replace(/\/$/, "");
53291
- const cleanRel = relative.replace(/^\//, "");
53292
- return `${cleanBase}/${cleanRel}`;
53293
- }
53294
53330
  function VisualNovelBoard({
53295
53331
  entity,
53296
53332
  nodes: propNodes,
@@ -53325,11 +53361,11 @@ function VisualNovelBoard({
53325
53361
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
53326
53362
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
53327
53363
  const backgroundImage = useMemo(
53328
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
53364
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
53329
53365
  [assetManifest, currentNode?.backgroundKey]
53330
53366
  );
53331
53367
  const portraitUrl = useMemo(
53332
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
53368
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
53333
53369
  [assetManifest, currentNode?.portraitKey]
53334
53370
  );
53335
53371
  const dialogueChoices = useMemo(
@@ -53503,7 +53539,7 @@ function buildDefaultWorldTiles() {
53503
53539
  for (let x = 0; x < WORLD_GRID_W; x++) {
53504
53540
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
53505
53541
  const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
53506
- tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
53542
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
53507
53543
  }
53508
53544
  }
53509
53545
  return tiles;
@@ -53547,7 +53583,12 @@ function WorldMapBoard({
53547
53583
  const resolved = boardEntity(entity);
53548
53584
  const entityUnits = rows(resolved?.units);
53549
53585
  const entityTiles = rows(resolved?.tiles);
53550
- const features = propFeatures ?? rows(resolved?.features);
53586
+ const features = propFeatures ?? rows(resolved?.features).map((r) => ({
53587
+ id: r.id == null ? void 0 : str(r.id),
53588
+ x: num(r.x),
53589
+ y: num(r.y),
53590
+ type: str(r.type)
53591
+ }));
53551
53592
  const selectedHeroId = resolved?.selectedHeroId ?? null;
53552
53593
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
53553
53594
  const backgroundImage = resolved?.backgroundImage;
@@ -53557,7 +53598,7 @@ function WorldMapBoard({
53557
53598
  x: num(t.x),
53558
53599
  y: num(t.y),
53559
53600
  terrain: str(t.terrain),
53560
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
53601
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
53561
53602
  passable: t.passable !== false
53562
53603
  })),
53563
53604
  [entityTiles]
@@ -53573,7 +53614,7 @@ function WorldMapBoard({
53573
53614
  team: str(u.team) === "enemy" ? "enemy" : "player",
53574
53615
  health: num(u.health) || 100,
53575
53616
  maxHealth: num(u.maxHealth) || 100,
53576
- sprite: u.sprite == null ? void 0 : str(u.sprite)
53617
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
53577
53618
  })),
53578
53619
  [entityUnits, propUnits]
53579
53620
  );
@@ -53755,7 +53796,6 @@ function WorldMapBoard({
53755
53796
  onTileHover: (x, y) => setHoveredTile({ x, y }),
53756
53797
  onTileLeave: () => setHoveredTile(null),
53757
53798
  scale,
53758
- assetBaseUrl: assetManifest?.baseUrl,
53759
53799
  assetManifest,
53760
53800
  backgroundImage,
53761
53801
  effectSpriteUrls,
@@ -53778,6 +53818,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
53778
53818
  var init_WorldMapBoard = __esm({
53779
53819
  "components/game/organisms/WorldMapBoard.tsx"() {
53780
53820
  "use client";
53821
+ init_makeAsset();
53781
53822
  init_cn();
53782
53823
  init_useEventBus();
53783
53824
  init_Stack();
@@ -53831,62 +53872,66 @@ function WorldMapTemplate({
53831
53872
  }
53832
53873
  );
53833
53874
  }
53834
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
53875
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
53835
53876
  var init_WorldMapTemplate = __esm({
53836
53877
  "components/game/templates/WorldMapTemplate.tsx"() {
53837
53878
  init_WorldMapBoard();
53879
+ init_makeAsset();
53838
53880
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
53881
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
53882
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
53883
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
53884
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
53839
53885
  DEFAULT_WORLDMAP_TILES = [
53840
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53841
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53842
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53843
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53844
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53845
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53846
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53847
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53848
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53849
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53850
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53851
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53852
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
53853
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53854
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53855
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53856
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53857
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53858
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
53859
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53860
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53861
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53862
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53863
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53864
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
53886
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53887
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53888
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
53889
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53890
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53891
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
53892
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53893
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53894
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53895
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
53896
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
53897
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
53898
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
53899
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
53900
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
53901
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
53902
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
53903
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
53904
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
53905
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
53906
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
53907
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
53908
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
53909
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
53910
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
53865
53911
  ];
53866
53912
  DEFAULT_WORLDMAP_UNITS = [
53867
- { 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` },
53868
- { 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` }
53913
+ { 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") },
53914
+ { 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") }
53869
53915
  ];
53870
53916
  DEFAULT_WORLDMAP_FEATURES = [
53871
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
53872
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
53917
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
53918
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
53873
53919
  ];
53874
53920
  DEFAULT_WORLDMAP_MANIFEST = {
53875
- baseUrl: CDN5,
53876
- terrains: {
53877
- grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
53878
- water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
53879
- mountain: "/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png",
53880
- road: "/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png"
53881
- },
53921
+ terrains: makeAssetMap({
53922
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
53923
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
53924
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
53925
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
53926
+ }, "tile"),
53882
53927
  units: {
53883
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
53884
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
53928
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
53929
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
53885
53930
  },
53886
- features: {
53887
- capital: "/scenes/world/capital.png",
53888
- power_node: "/world-map/power_node.png"
53889
- }
53931
+ features: makeAssetMap({
53932
+ capital: `${CDN5}/scenes/world/capital.png`,
53933
+ power_node: `${CDN5}/world-map/power_node.png`
53934
+ }, "decoration")
53890
53935
  };
53891
53936
  WorldMapTemplate.displayName = "WorldMapTemplate";
53892
53937
  }