@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
@@ -6960,7 +6960,7 @@ function ScoreDisplay({
6960
6960
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
6961
6961
  "img",
6962
6962
  {
6963
- src: assetUrl,
6963
+ src: assetUrl.url,
6964
6964
  alt: "",
6965
6965
  width: 20,
6966
6966
  height: 20,
@@ -6985,7 +6985,11 @@ var init_ScoreDisplay = __esm({
6985
6985
  lg: "text-2xl",
6986
6986
  xl: "text-4xl"
6987
6987
  };
6988
- DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
6988
+ DEFAULT_ASSET_URL = {
6989
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png",
6990
+ role: "effect",
6991
+ category: "effect"
6992
+ };
6989
6993
  ScoreDisplay.displayName = "ScoreDisplay";
6990
6994
  }
6991
6995
  });
@@ -7061,7 +7065,7 @@ function ControlButton({
7061
7065
  children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
7062
7066
  "img",
7063
7067
  {
7064
- src: assetUrl,
7068
+ src: assetUrl.url,
7065
7069
  alt: "",
7066
7070
  width: 24,
7067
7071
  height: 24,
@@ -7101,7 +7105,11 @@ var init_ControlButton = __esm({
7101
7105
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
7102
7106
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
7103
7107
  };
7104
- DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
7108
+ DEFAULT_ASSET_URL2 = {
7109
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
7110
+ role: "effect",
7111
+ category: "effect"
7112
+ };
7105
7113
  ControlButton.displayName = "ControlButton";
7106
7114
  }
7107
7115
  });
@@ -7140,7 +7148,7 @@ var init_spriteAnimation = __esm({
7140
7148
  }
7141
7149
  });
7142
7150
  function Sprite({
7143
- spritesheet = "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
7151
+ spritesheet = DEFAULT_SPRITESHEET,
7144
7152
  frameWidth = 64,
7145
7153
  frameHeight = 64,
7146
7154
  frame = 0,
@@ -7193,7 +7201,7 @@ function Sprite({
7193
7201
  position: "absolute",
7194
7202
  width: frameWidth,
7195
7203
  height: frameHeight,
7196
- backgroundImage: `url(${spritesheet})`,
7204
+ backgroundImage: `url(${spritesheet.url})`,
7197
7205
  backgroundPosition,
7198
7206
  backgroundRepeat: "no-repeat",
7199
7207
  imageRendering: "pixelated",
@@ -7206,11 +7214,17 @@ function Sprite({
7206
7214
  }
7207
7215
  );
7208
7216
  }
7217
+ var DEFAULT_SPRITESHEET;
7209
7218
  var init_Sprite = __esm({
7210
7219
  "components/game/atoms/Sprite.tsx"() {
7211
7220
  "use client";
7212
7221
  init_useEventBus();
7213
7222
  init_spriteAnimation();
7223
+ DEFAULT_SPRITESHEET = {
7224
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-blocks/Spritesheet/allTiles_sheet.png",
7225
+ role: "tile",
7226
+ category: "tile"
7227
+ };
7214
7228
  }
7215
7229
  });
7216
7230
  function StateIndicator({
@@ -7240,7 +7254,7 @@ function StateIndicator({
7240
7254
  /* @__PURE__ */ jsxRuntime.jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
7241
7255
  "img",
7242
7256
  {
7243
- src: assetUrl,
7257
+ src: assetUrl.url,
7244
7258
  alt: displayLabel,
7245
7259
  width: 16,
7246
7260
  height: 16,
@@ -7259,7 +7273,11 @@ var init_StateIndicator = __esm({
7259
7273
  init_Box();
7260
7274
  init_Icon();
7261
7275
  init_cn();
7262
- DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
7276
+ DEFAULT_ASSET_URL3 = {
7277
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
7278
+ role: "effect",
7279
+ category: "item"
7280
+ };
7263
7281
  DEFAULT_STATE_STYLES = {
7264
7282
  idle: { icon: "\u23F8", bgClass: "bg-muted" },
7265
7283
  active: { icon: "\u25B6", bgClass: "bg-success" },
@@ -7357,7 +7375,7 @@ function ResourceCounter({
7357
7375
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
7358
7376
  "img",
7359
7377
  {
7360
- src: assetUrl,
7378
+ src: assetUrl.url,
7361
7379
  alt: label,
7362
7380
  width: sizes.img,
7363
7381
  height: sizes.img,
@@ -7390,7 +7408,11 @@ var init_ResourceCounter = __esm({
7390
7408
  error: "text-error",
7391
7409
  muted: "text-muted-foreground"
7392
7410
  };
7393
- DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
7411
+ DEFAULT_ASSET_URL4 = {
7412
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
7413
+ role: "effect",
7414
+ category: "world"
7415
+ };
7394
7416
  sizeMap5 = {
7395
7417
  sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
7396
7418
  md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
@@ -7436,7 +7458,7 @@ function ItemSlot({
7436
7458
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
7437
7459
  "img",
7438
7460
  {
7439
- src: assetUrl,
7461
+ src: assetUrl?.url,
7440
7462
  alt: label,
7441
7463
  width: px,
7442
7464
  height: px,
@@ -7484,7 +7506,11 @@ var init_ItemSlot = __esm({
7484
7506
  epic: "shadow-lg",
7485
7507
  legendary: "shadow-lg"
7486
7508
  };
7487
- DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
7509
+ DEFAULT_ASSET_URL5 = {
7510
+ url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
7511
+ role: "effect",
7512
+ category: "item"
7513
+ };
7488
7514
  assetSizeMap = {
7489
7515
  sm: 28,
7490
7516
  md: 40,
@@ -7530,7 +7556,7 @@ function TurnIndicator({
7530
7556
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
7531
7557
  "img",
7532
7558
  {
7533
- src: assetUrl,
7559
+ src: assetUrl.url,
7534
7560
  alt: "",
7535
7561
  width: 12,
7536
7562
  height: 12,
@@ -7553,7 +7579,11 @@ var init_TurnIndicator = __esm({
7553
7579
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
7554
7580
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
7555
7581
  };
7556
- DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
7582
+ DEFAULT_ASSET_URL6 = {
7583
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
7584
+ role: "effect",
7585
+ category: "effect"
7586
+ };
7557
7587
  TurnIndicator.displayName = "TurnIndicator";
7558
7588
  }
7559
7589
  });
@@ -7592,7 +7622,7 @@ function ComboCounter({
7592
7622
  assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
7593
7623
  "img",
7594
7624
  {
7595
- src: assetUrl,
7625
+ src: assetUrl.url,
7596
7626
  alt: "combo",
7597
7627
  width: 24,
7598
7628
  height: 24,
@@ -7618,7 +7648,11 @@ var DEFAULT_ASSET_URL7, sizeMap8;
7618
7648
  var init_ComboCounter = __esm({
7619
7649
  "components/game/atoms/ComboCounter.tsx"() {
7620
7650
  init_cn();
7621
- DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
7651
+ DEFAULT_ASSET_URL7 = {
7652
+ url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
7653
+ role: "effect",
7654
+ category: "effect"
7655
+ };
7622
7656
  sizeMap8 = {
7623
7657
  sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
7624
7658
  md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
@@ -7738,7 +7772,7 @@ function WaypointMarker({
7738
7772
  children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
7739
7773
  "img",
7740
7774
  {
7741
- src: assetUrl,
7775
+ src: assetUrl.url,
7742
7776
  alt: label,
7743
7777
  width: sizes.img,
7744
7778
  height: sizes.img,
@@ -7767,7 +7801,11 @@ var init_WaypointMarker = __esm({
7767
7801
  "components/game/atoms/WaypointMarker.tsx"() {
7768
7802
  init_cn();
7769
7803
  init_Icon();
7770
- DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
7804
+ DEFAULT_ASSET_URL8 = {
7805
+ url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
7806
+ role: "effect",
7807
+ category: "world"
7808
+ };
7771
7809
  sizeMap10 = {
7772
7810
  sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
7773
7811
  md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
@@ -7808,7 +7846,7 @@ function StatusEffect({
7808
7846
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
7809
7847
  "img",
7810
7848
  {
7811
- src: assetUrl,
7849
+ src: assetUrl.url,
7812
7850
  alt: label,
7813
7851
  width: sizes.img,
7814
7852
  height: sizes.img,
@@ -7847,7 +7885,11 @@ var init_StatusEffect = __esm({
7847
7885
  "components/game/atoms/StatusEffect.tsx"() {
7848
7886
  init_cn();
7849
7887
  init_Icon();
7850
- DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
7888
+ DEFAULT_ASSET_URL9 = {
7889
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
7890
+ role: "effect",
7891
+ category: "effect"
7892
+ };
7851
7893
  sizeMap11 = {
7852
7894
  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 },
7853
7895
  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 },
@@ -7885,7 +7927,7 @@ function DamageNumber({
7885
7927
  assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
7886
7928
  "img",
7887
7929
  {
7888
- src: assetUrl,
7930
+ src: assetUrl.url,
7889
7931
  alt: "",
7890
7932
  width: 14,
7891
7933
  height: 14,
@@ -7921,14 +7963,18 @@ var init_DamageNumber = __esm({
7921
7963
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
7922
7964
  }
7923
7965
  `;
7924
- DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
7966
+ DEFAULT_ASSET_URL10 = {
7967
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
7968
+ role: "effect",
7969
+ category: "effect"
7970
+ };
7925
7971
  DamageNumber.displayName = "DamageNumber";
7926
7972
  }
7927
7973
  });
7928
7974
  function DialogueBubble({
7929
7975
  speaker = "Hero",
7930
7976
  text = "The dungeon awaits. Choose your path wisely.",
7931
- portrait = "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
7977
+ portrait = DEFAULT_PORTRAIT,
7932
7978
  position = "bottom",
7933
7979
  className
7934
7980
  }) {
@@ -7944,7 +7990,7 @@ function DialogueBubble({
7944
7990
  portrait && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 w-12 h-12 rounded-full overflow-hidden border-2 border-warning/60", children: /* @__PURE__ */ jsxRuntime.jsx(
7945
7991
  "img",
7946
7992
  {
7947
- src: portrait,
7993
+ src: portrait?.url,
7948
7994
  alt: speaker ?? "speaker",
7949
7995
  className: "w-full h-full object-cover"
7950
7996
  }
@@ -7957,9 +8003,15 @@ function DialogueBubble({
7957
8003
  }
7958
8004
  );
7959
8005
  }
8006
+ var DEFAULT_PORTRAIT;
7960
8007
  var init_DialogueBubble = __esm({
7961
8008
  "components/game/atoms/DialogueBubble.tsx"() {
7962
8009
  init_cn();
8010
+ DEFAULT_PORTRAIT = {
8011
+ url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
8012
+ role: "effect",
8013
+ category: "character"
8014
+ };
7963
8015
  DialogueBubble.displayName = "DialogueBubble";
7964
8016
  }
7965
8017
  });
@@ -8003,7 +8055,7 @@ function ChoiceButton({
8003
8055
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
8004
8056
  "img",
8005
8057
  {
8006
- src: assetUrl,
8058
+ src: assetUrl.url,
8007
8059
  alt: "",
8008
8060
  width: 16,
8009
8061
  height: 16,
@@ -8073,7 +8125,7 @@ function ActionButton({
8073
8125
  assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
8074
8126
  "img",
8075
8127
  {
8076
- src: assetUrl,
8128
+ src: assetUrl.url,
8077
8129
  alt: "",
8078
8130
  width: 16,
8079
8131
  height: 16,
@@ -8117,7 +8169,11 @@ var init_ActionButton = __esm({
8117
8169
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
8118
8170
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
8119
8171
  };
8120
- DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
8172
+ DEFAULT_ASSET_URL11 = {
8173
+ url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
8174
+ role: "effect",
8175
+ category: "effect"
8176
+ };
8121
8177
  ActionButton.displayName = "ActionButton";
8122
8178
  }
8123
8179
  });
@@ -11048,12 +11104,7 @@ var init_useCanvasGestures = __esm({
11048
11104
  }
11049
11105
  });
11050
11106
  function unitAtlasUrl(unit) {
11051
- if (unit.spriteSheet) return unit.spriteSheet;
11052
- const sprite = unit.sprite;
11053
- if (!sprite) return null;
11054
- const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
11055
- if (!match) return null;
11056
- return `${match[1]}.json`;
11107
+ return unit.spriteSheet?.url ?? null;
11057
11108
  }
11058
11109
  function resolveSheetUrl(atlasUrl, relativeSheetPath) {
11059
11110
  try {
@@ -11249,7 +11300,6 @@ function IsometricCanvas({
11249
11300
  // Tuning
11250
11301
  diamondTopY: diamondTopYProp,
11251
11302
  // Remote asset loading
11252
- assetBaseUrl,
11253
11303
  assetManifest
11254
11304
  }) {
11255
11305
  const tilesProp = Array.isArray(_tilesPropRaw) ? _tilesPropRaw : [];
@@ -11331,54 +11381,48 @@ function IsometricCanvas({
11331
11381
  const attackTargetSet = React88.useMemo(() => {
11332
11382
  return new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`));
11333
11383
  }, [attackTargets]);
11334
- const resolveManifestUrl7 = React88.useCallback((relativePath) => {
11335
- if (!relativePath) return void 0;
11336
- if (assetBaseUrl) return `${assetBaseUrl.replace(/\/$/, "")}${relativePath.startsWith("/") ? "" : "/"}${relativePath}`;
11337
- return relativePath;
11338
- }, [assetBaseUrl]);
11339
11384
  const spriteUrls = React88.useMemo(() => {
11340
11385
  const urls = [];
11341
11386
  for (const tile of sortedTiles) {
11342
- if (tile.terrainSprite) urls.push(tile.terrainSprite);
11387
+ if (tile.terrainSprite) urls.push(tile.terrainSprite.url);
11343
11388
  else if (getTerrainSprite) {
11344
11389
  const url = getTerrainSprite(tile.terrain ?? "");
11345
11390
  if (url) urls.push(url);
11346
11391
  } else {
11347
- const url = resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
11392
+ const url = assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
11348
11393
  if (url) urls.push(url);
11349
11394
  }
11350
11395
  }
11351
11396
  for (const feature of features) {
11352
- if (feature.sprite) urls.push(feature.sprite);
11397
+ if (feature.sprite) urls.push(feature.sprite.url);
11353
11398
  else if (getFeatureSprite) {
11354
11399
  const url = getFeatureSprite(feature.type);
11355
11400
  if (url) urls.push(url);
11356
11401
  } else {
11357
- const url = resolveManifestUrl7(assetManifest?.features?.[feature.type]);
11402
+ const url = assetManifest?.features?.[feature.type]?.url;
11358
11403
  if (url) urls.push(url);
11359
11404
  }
11360
11405
  }
11361
11406
  for (const unit of units) {
11362
- if (unit.sprite) urls.push(unit.sprite);
11407
+ if (unit.sprite) urls.push(unit.sprite.url);
11363
11408
  else if (getUnitSprite) {
11364
11409
  const url = getUnitSprite(unit);
11365
11410
  if (url) urls.push(url);
11366
11411
  } else if (unit.unitType) {
11367
- const url = resolveManifestUrl7(assetManifest?.units?.[unit.unitType]);
11412
+ const url = assetManifest?.units?.[unit.unitType]?.url;
11368
11413
  if (url) urls.push(url);
11369
11414
  }
11370
11415
  }
11371
11416
  if (assetManifest?.effects) {
11372
- for (const path of Object.values(assetManifest.effects)) {
11373
- const url = resolveManifestUrl7(path);
11374
- if (url) urls.push(url);
11417
+ for (const asset of Object.values(assetManifest.effects)) {
11418
+ if (asset.url) urls.push(asset.url);
11375
11419
  }
11376
11420
  }
11377
11421
  if (effectSpriteUrls) urls.push(...effectSpriteUrls);
11378
11422
  if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
11379
11423
  if (backgroundImage) urls.push(backgroundImage);
11380
11424
  return [...new Set(urls.filter(Boolean))];
11381
- }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl7]);
11425
+ }, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest]);
11382
11426
  const { getImage, pendingCount: _imagePendingCount } = useImageCache(spriteUrls);
11383
11427
  React88.useEffect(() => {
11384
11428
  if (typeof window === "undefined") return;
@@ -11403,14 +11447,14 @@ function IsometricCanvas({
11403
11447
  lerpToTarget
11404
11448
  } = useCamera();
11405
11449
  const resolveTerrainSpriteUrl = React88.useCallback((tile) => {
11406
- return tile.terrainSprite || getTerrainSprite?.(tile.terrain ?? "") || resolveManifestUrl7(assetManifest?.terrains?.[tile.terrain ?? ""]);
11407
- }, [getTerrainSprite, assetManifest, resolveManifestUrl7]);
11450
+ return tile.terrainSprite?.url || getTerrainSprite?.(tile.terrain ?? "") || assetManifest?.terrains?.[tile.terrain ?? ""]?.url;
11451
+ }, [getTerrainSprite, assetManifest]);
11408
11452
  const resolveFeatureSpriteUrl = React88.useCallback((featureType) => {
11409
- return getFeatureSprite?.(featureType) || resolveManifestUrl7(assetManifest?.features?.[featureType]);
11410
- }, [getFeatureSprite, assetManifest, resolveManifestUrl7]);
11453
+ return getFeatureSprite?.(featureType) || assetManifest?.features?.[featureType]?.url;
11454
+ }, [getFeatureSprite, assetManifest]);
11411
11455
  const resolveUnitSpriteUrl = React88.useCallback((unit) => {
11412
- return unit.sprite || getUnitSprite?.(unit) || (unit.unitType ? resolveManifestUrl7(assetManifest?.units?.[unit.unitType]) : void 0);
11413
- }, [getUnitSprite, assetManifest, resolveManifestUrl7]);
11456
+ return unit.sprite?.url || getUnitSprite?.(unit) || (unit.unitType ? assetManifest?.units?.[unit.unitType]?.url : void 0);
11457
+ }, [getUnitSprite, assetManifest]);
11414
11458
  const miniMapTiles = React88.useMemo(() => {
11415
11459
  if (!showMinimap) return [];
11416
11460
  return sortedTiles.map((t2) => ({
@@ -11557,7 +11601,7 @@ function IsometricCanvas({
11557
11601
  if (pos.x + scaledTileWidth < visLeft || pos.x > visRight || pos.y + scaledTileHeight < visTop || pos.y > visBottom) {
11558
11602
  continue;
11559
11603
  }
11560
- const spriteUrl = feature.sprite || resolveFeatureSpriteUrl(feature.type);
11604
+ const spriteUrl = feature.sprite?.url || resolveFeatureSpriteUrl(feature.type);
11561
11605
  const img = spriteUrl ? getImage(spriteUrl) : null;
11562
11606
  const centerX = pos.x + scaledTileWidth / 2;
11563
11607
  const featureGroundY = pos.y + scaledDiamondTopY + scaledFloorHeight * 0.5;
@@ -11606,12 +11650,12 @@ function IsometricCanvas({
11606
11650
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
11607
11651
  const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
11608
11652
  const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11653
+ const unitIsSheet = unit.sprite?.dimension === "2d" && (unit.sprite?.animations?.length ?? 0) > 0;
11609
11654
  const SHEET_ROWS = 5;
11610
11655
  const sheetFrameW = img ? img.naturalWidth / SHEET_COLUMNS : 0;
11611
11656
  const sheetFrameH = img ? img.naturalHeight / SHEET_ROWS : 0;
11612
- const imgIsSheet = img ? img.naturalWidth % SHEET_COLUMNS === 0 && img.naturalHeight % SHEET_ROWS === 0 && Math.abs(sheetFrameW - sheetFrameH) < 2 : false;
11613
- const frameW = imgIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11614
- const frameH = imgIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11657
+ const frameW = unitIsSheet ? sheetFrameW : img?.naturalWidth ?? 1;
11658
+ const frameH = unitIsSheet ? sheetFrameH : img?.naturalHeight ?? 1;
11615
11659
  const ar = frameW / (frameH || 1);
11616
11660
  let drawH = unitDrawH;
11617
11661
  let drawW = unitDrawH * ar;
@@ -11626,7 +11670,7 @@ function IsometricCanvas({
11626
11670
  ctx.save();
11627
11671
  ctx.globalAlpha = 0.25;
11628
11672
  if (img) {
11629
- if (imgIsSheet) {
11673
+ if (unitIsSheet) {
11630
11674
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
11631
11675
  } else {
11632
11676
  ctx.drawImage(img, ghostCenterX - drawW / 2, ghostGroundY - drawH, drawW, drawH);
@@ -11674,7 +11718,7 @@ function IsometricCanvas({
11674
11718
  } else if (img) {
11675
11719
  const spriteY = groundY - drawH - breatheOffset;
11676
11720
  const drawUnit = (x) => {
11677
- if (imgIsSheet) {
11721
+ if (unitIsSheet) {
11678
11722
  ctx.drawImage(img, 0, 0, sheetFrameW, sheetFrameH, x, spriteY, drawW, drawH);
11679
11723
  } else {
11680
11724
  ctx.drawImage(img, x, spriteY, drawW, drawH);
@@ -11701,7 +11745,7 @@ function IsometricCanvas({
11701
11745
  }
11702
11746
  }
11703
11747
  for (const fx of effects) {
11704
- const spriteUrl = resolveManifestUrl7(assetManifest?.effects?.[fx.key]);
11748
+ const spriteUrl = assetManifest?.effects?.[fx.key]?.url;
11705
11749
  if (!spriteUrl) continue;
11706
11750
  const img = getImage(spriteUrl);
11707
11751
  if (!img) continue;
@@ -11745,7 +11789,6 @@ function IsometricCanvas({
11745
11789
  backgroundImage,
11746
11790
  cameraRef,
11747
11791
  unitScale,
11748
- resolveManifestUrl7,
11749
11792
  assetManifest
11750
11793
  ]);
11751
11794
  React88.useEffect(() => {
@@ -12023,6 +12066,42 @@ var init_boardEntity = __esm({
12023
12066
  "components/game/organisms/boardEntity.ts"() {
12024
12067
  }
12025
12068
  });
12069
+
12070
+ // components/game/organisms/utils/makeAsset.ts
12071
+ function makeAsset(url, role, overrides = {}) {
12072
+ const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
12073
+ return {
12074
+ url,
12075
+ role,
12076
+ category: url.split("/").pop()?.replace(/\.[^.]+$/, "") ?? role,
12077
+ ...defaults,
12078
+ ...overrides
12079
+ };
12080
+ }
12081
+ function makeAssetMap(record, role, overrides = {}) {
12082
+ const result = {};
12083
+ for (const [key, url] of Object.entries(record)) {
12084
+ result[key] = makeAsset(url, role, overrides);
12085
+ }
12086
+ return result;
12087
+ }
12088
+ var ROLE_DEFAULTS;
12089
+ var init_makeAsset = __esm({
12090
+ "components/game/organisms/utils/makeAsset.ts"() {
12091
+ ROLE_DEFAULTS = {
12092
+ tile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12093
+ decoration: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12094
+ effect: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12095
+ item: { dimension: "2d", animations: ["static"], aspect: "5:7" },
12096
+ player: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12097
+ enemy: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12098
+ npc: { dimension: "2d", animations: ["idle", "walk", "attack", "hit", "death"], aspect: "1:1" },
12099
+ projectile: { dimension: "2d", animations: ["static"], aspect: "1:1" },
12100
+ vehicle: { dimension: "2d", animations: ["idle", "walk"], aspect: "1:1" },
12101
+ ui: { dimension: "2d", animations: ["static"], aspect: "1:1" }
12102
+ };
12103
+ }
12104
+ });
12026
12105
  function buildDefaultBattleTiles() {
12027
12106
  const tiles = [];
12028
12107
  for (let y = 0; y < BATTLE_GRID_H; y++) {
@@ -12081,14 +12160,14 @@ function BattleBoard({
12081
12160
  if (o === null || typeof o.x !== "number" || typeof o.y !== "number") return [];
12082
12161
  const tile = { x: o.x, y: o.y };
12083
12162
  if (typeof o.terrain === "string") tile.terrain = o.terrain;
12084
- if (typeof o.terrainSprite === "string") tile.terrainSprite = o.terrainSprite;
12163
+ if (typeof o.terrainSprite === "string") tile.terrainSprite = makeAsset(o.terrainSprite, "tile");
12085
12164
  if (typeof o.passable === "boolean") tile.passable = o.passable;
12086
12165
  if (typeof o.movementCost === "number") tile.movementCost = o.movementCost;
12087
12166
  if (typeof o.elevation === "number") tile.elevation = o.elevation;
12088
12167
  if (typeof o.type === "string") tile.type = o.type;
12089
12168
  if (typeof o.tileType === "string") tile.tileType = o.tileType;
12090
12169
  if (typeof o.id === "string") tile.id = o.id;
12091
- if (typeof o.modelUrl === "string") tile.modelUrl = o.modelUrl;
12170
+ if (typeof o.modelUrl === "string") tile.modelUrl = makeAsset(o.modelUrl, "decoration", { dimension: "3d" });
12092
12171
  return [tile];
12093
12172
  }) : []);
12094
12173
  const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
@@ -12097,10 +12176,10 @@ function BattleBoard({
12097
12176
  if (o === null || typeof o.type !== "string" || typeof o.x !== "number" || typeof o.y !== "number") return [];
12098
12177
  const feat = { type: o.type, x: o.x, y: o.y };
12099
12178
  if (typeof o.id === "string") feat.id = o.id;
12100
- if (typeof o.sprite === "string") feat.sprite = o.sprite;
12179
+ if (typeof o.sprite === "string") feat.sprite = makeAsset(o.sprite, "decoration");
12101
12180
  if (typeof o.color === "string") feat.color = o.color;
12102
12181
  if (typeof o.elevation === "number") feat.elevation = o.elevation;
12103
- if (typeof o.assetUrl === "string") feat.assetUrl = o.assetUrl;
12182
+ if (typeof o.assetUrl === "string") feat.assetUrl = makeAsset(o.assetUrl, "decoration", { dimension: "3d" });
12104
12183
  return [feat];
12105
12184
  }) : []);
12106
12185
  const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
@@ -12216,7 +12295,7 @@ function BattleBoard({
12216
12295
  maxHealth: num(unit.maxHealth),
12217
12296
  unitType: unit.unitType == null ? void 0 : str(unit.unitType),
12218
12297
  heroId: unit.heroId == null ? void 0 : str(unit.heroId),
12219
- sprite: unit.sprite == null ? void 0 : str(unit.sprite),
12298
+ sprite: unit.sprite == null ? void 0 : makeAsset(str(unit.sprite), "npc"),
12220
12299
  traits: unitTraits?.map((tr) => ({
12221
12300
  name: tr.name,
12222
12301
  currentState: tr.currentState,
@@ -12366,7 +12445,6 @@ function BattleBoard({
12366
12445
  onTileHover: (x, y) => setHoveredTile({ x, y }),
12367
12446
  onTileLeave: () => setHoveredTile(null),
12368
12447
  scale,
12369
- assetBaseUrl: assetManifest?.baseUrl,
12370
12448
  assetManifest,
12371
12449
  backgroundImage,
12372
12450
  onDrawEffects,
@@ -12444,15 +12522,16 @@ var init_BattleBoard = __esm({
12444
12522
  init_IsometricCanvas();
12445
12523
  init_boardEntity();
12446
12524
  init_isometric();
12525
+ init_makeAsset();
12447
12526
  BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
12448
12527
  BATTLE_GRID_W = 16;
12449
12528
  BATTLE_GRID_H = 16;
12450
12529
  BATTLE_TERRAIN_SPRITES = [
12451
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
12452
- `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
12453
- `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
12454
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
12455
- `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
12530
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`, "tile"),
12531
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile"),
12532
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`, "tile"),
12533
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, "tile"),
12534
+ makeAsset(`${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile")
12456
12535
  ];
12457
12536
  DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
12458
12537
  BattleBoard.displayName = "BattleBoard";
@@ -12491,61 +12570,64 @@ function BattleTemplate({
12491
12570
  }
12492
12571
  );
12493
12572
  }
12494
- var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12573
+ var CDN, STONE, DIRT, GRASS, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12495
12574
  var init_BattleTemplate = __esm({
12496
12575
  "components/game/templates/BattleTemplate.tsx"() {
12497
12576
  init_BattleBoard();
12577
+ init_makeAsset();
12498
12578
  CDN = "https://almadar-kflow-assets.web.app/shared";
12579
+ STONE = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`, "tile");
12580
+ DIRT = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`, "tile");
12581
+ GRASS = makeAsset(`${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`, "tile");
12499
12582
  DEFAULT_BATTLE_TILES2 = [
12500
- { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12501
- { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12502
- { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12503
- { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12504
- { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12505
- { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12506
- { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12507
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12508
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12509
- { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12510
- { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12511
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12512
- { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12513
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12514
- { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12515
- { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12516
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12517
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png` },
12518
- { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png` },
12519
- { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12520
- { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12521
- { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12522
- { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12523
- { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12524
- { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` }
12583
+ { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12584
+ { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12585
+ { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12586
+ { x: 3, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12587
+ { x: 4, y: 0, terrain: "stone", passable: false, terrainSprite: STONE },
12588
+ { x: 0, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
12589
+ { x: 1, y: 1, terrain: "dirt", passable: true, terrainSprite: DIRT },
12590
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
12591
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: GRASS },
12592
+ { x: 4, y: 1, terrain: "stone", passable: false, terrainSprite: STONE },
12593
+ { x: 0, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
12594
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
12595
+ { x: 2, y: 2, terrain: "dirt", passable: true, terrainSprite: DIRT },
12596
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: GRASS },
12597
+ { x: 4, y: 2, terrain: "stone", passable: false, terrainSprite: STONE },
12598
+ { x: 0, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
12599
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
12600
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: GRASS },
12601
+ { x: 3, y: 3, terrain: "dirt", passable: true, terrainSprite: DIRT },
12602
+ { x: 4, y: 3, terrain: "stone", passable: false, terrainSprite: STONE },
12603
+ { x: 0, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12604
+ { x: 1, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12605
+ { x: 2, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12606
+ { x: 3, y: 4, terrain: "stone", passable: false, terrainSprite: STONE },
12607
+ { x: 4, y: 4, terrain: "stone", passable: false, terrainSprite: STONE }
12525
12608
  ];
12526
12609
  DEFAULT_BATTLE_UNITS = [
12527
- { 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` },
12528
- { 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` }
12610
+ { 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") },
12611
+ { 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") }
12529
12612
  ];
12530
12613
  DEFAULT_BATTLE_FEATURES = [
12531
- { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: `${CDN}/world-map/gold_mine.png` },
12532
- { id: "f2", x: 3, y: 1, type: "portal", sprite: `${CDN}/world-map/portal_open.png` }
12614
+ { id: "f1", x: 2, y: 2, type: "gold_mine", sprite: makeAsset(`${CDN}/world-map/gold_mine.png`, "decoration") },
12615
+ { id: "f2", x: 3, y: 1, type: "portal", sprite: makeAsset(`${CDN}/world-map/portal_open.png`, "decoration") }
12533
12616
  ];
12534
12617
  DEFAULT_BATTLE_MANIFEST = {
12535
- baseUrl: CDN,
12536
- terrains: {
12537
- stone: "/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png",
12538
- dirt: "/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png",
12539
- grass: "/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png"
12540
- },
12541
- units: {
12542
- worker: "/sprite-sheets/amir-sprite-sheet-se.png",
12543
- guardian: "/sprite-sheets/destroyer-sprite-sheet-sw.png"
12544
- },
12545
- features: {
12546
- gold_mine: "/world-map/gold_mine.png",
12547
- portal: "/world-map/portal_open.png"
12548
- }
12618
+ terrains: makeAssetMap({
12619
+ stone: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png`,
12620
+ dirt: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_01.png`,
12621
+ grass: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_13.png`
12622
+ }, "tile"),
12623
+ units: makeAssetMap({
12624
+ worker: `${CDN}/sprite-sheets/amir-sprite-sheet-se.png`,
12625
+ guardian: `${CDN}/sprite-sheets/destroyer-sprite-sheet-sw.png`
12626
+ }, "npc"),
12627
+ features: makeAssetMap({
12628
+ gold_mine: `${CDN}/world-map/gold_mine.png`,
12629
+ portal: `${CDN}/world-map/portal_open.png`
12630
+ }, "decoration")
12549
12631
  };
12550
12632
  BattleTemplate.displayName = "BattleTemplate";
12551
12633
  }
@@ -14760,7 +14842,6 @@ function BoardgameBoard({
14760
14842
  units,
14761
14843
  features,
14762
14844
  assetManifest,
14763
- assetBaseUrl,
14764
14845
  scale,
14765
14846
  showMinimap,
14766
14847
  enableCamera,
@@ -19830,7 +19911,7 @@ function CardHand({
19830
19911
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 flex items-center justify-center w-full", children: card.iconUrl ? /* @__PURE__ */ jsxRuntime.jsx(
19831
19912
  "img",
19832
19913
  {
19833
- src: card.iconUrl,
19914
+ src: card.iconUrl.url,
19834
19915
  alt: card.title ?? card.id,
19835
19916
  width: art,
19836
19917
  height: art,
@@ -19888,15 +19969,6 @@ var init_CardHand = __esm({
19888
19969
  CardHand.displayName = "CardHand";
19889
19970
  }
19890
19971
  });
19891
- function resolveManifestUrl(manifest, relative) {
19892
- if (relative == null) return void 0;
19893
- if (/^https?:\/\//.test(relative)) return relative;
19894
- const base = manifest?.baseUrl;
19895
- if (base == null) return relative;
19896
- const cleanBase = base.replace(/\/$/, "");
19897
- const cleanRel = relative.replace(/^\//, "");
19898
- return `${cleanBase}/${cleanRel}`;
19899
- }
19900
19972
  function rowToCard(r) {
19901
19973
  return {
19902
19974
  id: str(r.id),
@@ -19910,7 +19982,7 @@ function rowToCard(r) {
19910
19982
  function toHandCards(cards, manifest, mana) {
19911
19983
  return cards.map((c) => {
19912
19984
  const key = c.iconKey ?? c.id;
19913
- const iconUrl = resolveManifestUrl(manifest, manifest?.cards?.[key]);
19985
+ const iconUrl = manifest?.cards?.[key];
19914
19986
  return {
19915
19987
  id: c.id,
19916
19988
  iconUrl,
@@ -21024,7 +21096,6 @@ function CastleBoard({
21024
21096
  onTileHover: (x, y) => setHoveredTile({ x, y }),
21025
21097
  onTileLeave: () => setHoveredTile(null),
21026
21098
  scale,
21027
- assetBaseUrl: assetManifest?.baseUrl,
21028
21099
  assetManifest,
21029
21100
  backgroundImage
21030
21101
  }
@@ -21100,60 +21171,63 @@ function CastleTemplate({
21100
21171
  }
21101
21172
  );
21102
21173
  }
21103
- var CDN2, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
21174
+ var CDN2, WALL, FLOOR, FLOOR_CENTER, DEFAULT_CASTLE_TILES, DEFAULT_CASTLE_UNITS, DEFAULT_CASTLE_FEATURES, DEFAULT_CASTLE_MANIFEST;
21104
21175
  var init_CastleTemplate = __esm({
21105
21176
  "components/game/templates/CastleTemplate.tsx"() {
21106
21177
  init_CastleBoard();
21178
+ init_makeAsset();
21107
21179
  CDN2 = "https://almadar-kflow-assets.web.app/shared";
21180
+ WALL = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`, "tile");
21181
+ FLOOR = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
21182
+ FLOOR_CENTER = makeAsset(`${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`, "tile");
21108
21183
  DEFAULT_CASTLE_TILES = [
21109
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21110
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21111
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21112
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21113
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21114
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21115
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21116
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21117
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21118
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21119
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21120
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21121
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_09.png` },
21122
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21123
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21124
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21125
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21126
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21127
- { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
21128
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21129
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21130
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21131
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21132
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` },
21133
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png` }
21184
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21185
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21186
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21187
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21188
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: WALL },
21189
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
21190
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21191
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21192
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: FLOOR },
21193
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: WALL },
21194
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
21195
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
21196
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR_CENTER },
21197
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: FLOOR },
21198
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: WALL },
21199
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
21200
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21201
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21202
+ { x: 3, y: 3, terrain: "floor", passable: true, terrainSprite: FLOOR },
21203
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: WALL },
21204
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21205
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21206
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21207
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: WALL },
21208
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: WALL }
21134
21209
  ];
21135
21210
  DEFAULT_CASTLE_UNITS = [
21136
- { 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` },
21137
- { 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` }
21211
+ { 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") },
21212
+ { 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") }
21138
21213
  ];
21139
21214
  DEFAULT_CASTLE_FEATURES = [
21140
- { id: "f1", x: 2, y: 2, type: "chest", sprite: `${CDN2}/world-map/treasure_chest_closed.png` },
21141
- { id: "f2", x: 3, y: 1, type: "crystal", sprite: `${CDN2}/world-map/resonance_crystal.png` }
21215
+ { id: "f1", x: 2, y: 2, type: "chest", sprite: makeAsset(`${CDN2}/world-map/treasure_chest_closed.png`, "decoration") },
21216
+ { id: "f2", x: 3, y: 1, type: "crystal", sprite: makeAsset(`${CDN2}/world-map/resonance_crystal.png`, "decoration") }
21142
21217
  ];
21143
21218
  DEFAULT_CASTLE_MANIFEST = {
21144
- baseUrl: CDN2,
21145
- terrains: {
21146
- wall: "/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png",
21147
- floor: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png"
21148
- },
21149
- units: {
21150
- worker: "/sprite-sheets/coordinator-sprite-sheet-se.png",
21151
- guardian: "/sprite-sheets/forger-sprite-sheet-se.png"
21152
- },
21153
- features: {
21154
- chest: "/world-map/treasure_chest_closed.png",
21155
- crystal: "/world-map/resonance_crystal.png"
21156
- }
21219
+ terrains: makeAssetMap({
21220
+ wall: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
21221
+ floor: `${CDN2}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`
21222
+ }, "tile"),
21223
+ units: makeAssetMap({
21224
+ worker: `${CDN2}/sprite-sheets/coordinator-sprite-sheet-se.png`,
21225
+ guardian: `${CDN2}/sprite-sheets/forger-sprite-sheet-se.png`
21226
+ }, "player"),
21227
+ features: makeAssetMap({
21228
+ chest: `${CDN2}/world-map/treasure_chest_closed.png`,
21229
+ crystal: `${CDN2}/world-map/resonance_crystal.png`
21230
+ }, "decoration")
21157
21231
  };
21158
21232
  CastleTemplate.displayName = "CastleTemplate";
21159
21233
  }
@@ -22141,15 +22215,6 @@ var init_ChatBar = __esm({
22141
22215
  ChatBar.displayName = "ChatBar";
22142
22216
  }
22143
22217
  });
22144
- function resolveManifestUrl2(manifest, relative) {
22145
- if (relative == null) return void 0;
22146
- if (/^https?:\/\//.test(relative)) return relative;
22147
- const base = manifest?.baseUrl;
22148
- if (base == null) return relative;
22149
- const cleanBase = base.replace(/\/$/, "");
22150
- const cleanRel = relative.replace(/^\//, "");
22151
- return `${cleanBase}/${cleanRel}`;
22152
- }
22153
22218
  function buildDefaultCBTiles() {
22154
22219
  const tiles = [];
22155
22220
  for (let y = 0; y < CB_GRID_H; y++) {
@@ -22164,12 +22229,12 @@ function buildDefaultCBTiles() {
22164
22229
  function tilesToIso(tiles, manifest) {
22165
22230
  return tiles.map((t) => {
22166
22231
  const key = t.terrain ?? "grass";
22167
- const sprite = t.terrainSprite ?? resolveManifestUrl2(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl2(manifest, manifest?.terrains?.grass);
22232
+ const terrainSprite = t.terrainSprite ?? manifest?.terrains?.[key] ?? manifest?.terrains?.grass;
22168
22233
  return {
22169
22234
  x: t.x,
22170
22235
  y: t.y,
22171
22236
  terrain: t.terrain,
22172
- terrainSprite: sprite,
22237
+ terrainSprite,
22173
22238
  passable: t.passable
22174
22239
  };
22175
22240
  });
@@ -22180,7 +22245,7 @@ function buildingsToFeatures(buildings, manifest) {
22180
22245
  x: b.x,
22181
22246
  y: b.y,
22182
22247
  type: b.type,
22183
- sprite: resolveManifestUrl2(manifest, manifest?.features?.[b.type])
22248
+ sprite: manifest?.features?.[b.type]
22184
22249
  }));
22185
22250
  }
22186
22251
  function CityBuilderBoard({
@@ -22212,7 +22277,7 @@ function CityBuilderBoard({
22212
22277
  x: num(r.x),
22213
22278
  y: num(r.y),
22214
22279
  terrain: r.terrain == null ? void 0 : str(r.terrain),
22215
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
22280
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
22216
22281
  passable: r.passable !== false
22217
22282
  })),
22218
22283
  [board.tiles]
@@ -22321,7 +22386,6 @@ function CityBuilderBoard({
22321
22386
  {
22322
22387
  tiles: isoTiles,
22323
22388
  features: buildingFeatures,
22324
- assetBaseUrl: assetManifest?.baseUrl,
22325
22389
  assetManifest,
22326
22390
  validMoves,
22327
22391
  hoveredTile,
@@ -22356,6 +22420,7 @@ var CB_GRID_W, CB_GRID_H, DEFAULT_BUILD_TYPES, DEFAULT_CB_TILES;
22356
22420
  var init_CityBuilderBoard = __esm({
22357
22421
  "components/game/organisms/CityBuilderBoard.tsx"() {
22358
22422
  "use client";
22423
+ init_makeAsset();
22359
22424
  init_cn();
22360
22425
  init_useEventBus();
22361
22426
  init_Box();
@@ -28350,7 +28415,7 @@ function StatBadge({
28350
28415
  resolvedAsset ? /* @__PURE__ */ jsxRuntime.jsx(
28351
28416
  "img",
28352
28417
  {
28353
- src: resolvedAsset,
28418
+ src: resolvedAsset.url,
28354
28419
  alt: "",
28355
28420
  width: 16,
28356
28421
  height: 16,
@@ -28657,7 +28722,7 @@ function GameCanvas2D({
28657
28722
  tickEvent,
28658
28723
  drawEvent,
28659
28724
  fps = 60,
28660
- backgroundImage = "",
28725
+ backgroundImage,
28661
28726
  assetBaseUrl,
28662
28727
  className
28663
28728
  }) {
@@ -28721,7 +28786,7 @@ function GameCanvas2D({
28721
28786
  emitRef.current(tickEventRef.current, { dt, frame });
28722
28787
  }
28723
28788
  if (backgroundImageRef.current) {
28724
- const bgImg = loadImage(backgroundImageRef.current);
28789
+ const bgImg = loadImage(backgroundImageRef.current.url);
28725
28790
  if (bgImg) {
28726
28791
  ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
28727
28792
  } else {
@@ -29092,7 +29157,7 @@ function EnemyPlate({
29092
29157
  assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
29093
29158
  "img",
29094
29159
  {
29095
- src: assetUrl,
29160
+ src: assetUrl.url,
29096
29161
  alt: name,
29097
29162
  width: 24,
29098
29163
  height: 24,
@@ -29434,7 +29499,7 @@ function DialogueBox({
29434
29499
  "div",
29435
29500
  {
29436
29501
  className: "fixed inset-0 z-20 bg-center bg-cover bg-no-repeat",
29437
- style: { backgroundImage: `url(${backgroundImage})` },
29502
+ style: { backgroundImage: `url(${backgroundImage?.url})` },
29438
29503
  "aria-hidden": "true"
29439
29504
  }
29440
29505
  ),
@@ -29449,7 +29514,7 @@ function DialogueBox({
29449
29514
  children: /* @__PURE__ */ jsxRuntime.jsx(
29450
29515
  "img",
29451
29516
  {
29452
- src: portraitUrl,
29517
+ src: portraitUrl?.url,
29453
29518
  alt: dialogue.speaker,
29454
29519
  className: "h-full w-auto object-contain drop-shadow-2xl"
29455
29520
  }
@@ -41755,7 +41820,6 @@ var init_FeatureGridOrganism = __esm({
41755
41820
  });
41756
41821
  function FishingBoard({
41757
41822
  backgroundImage,
41758
- assetBaseUrl,
41759
41823
  scale = 1,
41760
41824
  showMinimap = false,
41761
41825
  enableCamera = true,
@@ -41773,8 +41837,7 @@ function FishingBoard({
41773
41837
  {
41774
41838
  width,
41775
41839
  height,
41776
- backgroundImage: backgroundImage ?? "",
41777
- assetBaseUrl,
41840
+ backgroundImage,
41778
41841
  fps: 60,
41779
41842
  className: "w-full h-full"
41780
41843
  }
@@ -43993,7 +44056,7 @@ var init_GameCanvas3D2 = __esm({
43993
44056
  children: /* @__PURE__ */ jsxRuntime.jsx(
43994
44057
  ModelLoader,
43995
44058
  {
43996
- url: tile.modelUrl,
44059
+ url: tile.modelUrl.url,
43997
44060
  scale: 0.95,
43998
44061
  fallbackGeometry: "box",
43999
44062
  castShadow: true,
@@ -44058,7 +44121,7 @@ var init_GameCanvas3D2 = __esm({
44058
44121
  /* @__PURE__ */ jsxRuntime.jsx(
44059
44122
  ModelLoader,
44060
44123
  {
44061
- url: unit.modelUrl,
44124
+ url: unit.modelUrl.url,
44062
44125
  scale: modelScale,
44063
44126
  fallbackGeometry: "box",
44064
44127
  castShadow: true
@@ -44118,7 +44181,7 @@ var init_GameCanvas3D2 = __esm({
44118
44181
  return /* @__PURE__ */ jsxRuntime.jsx(
44119
44182
  ModelLoader,
44120
44183
  {
44121
- url: feature.assetUrl,
44184
+ url: feature.assetUrl.url,
44122
44185
  position,
44123
44186
  scale: 0.5,
44124
44187
  rotation: [0, feature.rotation ?? 0, 0],
@@ -44339,7 +44402,18 @@ function GameBoard3D({
44339
44402
  const row = boardEntity(entity);
44340
44403
  const eventBus = useEventBus();
44341
44404
  const entityUnits = row ? rows(row.units) : [];
44342
- const units = entityUnits;
44405
+ const units = entityUnits.map((r) => ({
44406
+ id: str(r.id),
44407
+ x: num(r.x),
44408
+ y: num(r.y),
44409
+ z: num(r.z),
44410
+ faction: str(r.faction) || "neutral",
44411
+ team: str(r.team) || str(r.faction) || "neutral",
44412
+ unitType: r.unitType == null ? void 0 : str(r.unitType),
44413
+ name: r.name == null ? void 0 : str(r.name),
44414
+ health: r.health == null ? void 0 : num(r.health),
44415
+ maxHealth: r.maxHealth == null ? void 0 : num(r.maxHealth)
44416
+ }));
44343
44417
  const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
44344
44418
  const phase = row ? str(row.phase) : "observation";
44345
44419
  const result = row ? str(row.result) : "none";
@@ -44518,22 +44592,27 @@ function resolveDescriptor(value, idPrefix) {
44518
44592
  }
44519
44593
  if (typeof value === "object" && value !== null) {
44520
44594
  const desc = asDescriptor(value);
44521
- if (desc !== null && patterns.getComponentForPattern(desc.type) !== null) {
44595
+ const hasComp = desc !== null && patterns.getComponentForPattern(desc.type) !== null;
44596
+ shellLog.debug("resolve", { idPrefix, type: desc?.type ?? null, hasDesc: desc !== null, render: hasComp });
44597
+ if (hasComp) {
44522
44598
  const resolvedProps = desc.props ?? {};
44523
44599
  const content = { id: desc._id ?? idPrefix, pattern: desc.type, props: resolvedProps, priority: 0 };
44524
44600
  const SCR = getSlotContentRenderer2();
44525
- return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 });
44601
+ return /* @__PURE__ */ jsxRuntime.jsx(SCR, { content, onDismiss: () => void 0 }, content.id);
44526
44602
  }
44603
+ } else {
44604
+ shellLog.debug("resolve", { idPrefix, type: null, hasDesc: false, render: false, branch: typeof value });
44527
44605
  }
44528
44606
  return null;
44529
44607
  }
44530
- var _scr, GameShell;
44608
+ var shellLog, _scr, GameShell;
44531
44609
  var init_GameShell = __esm({
44532
44610
  "components/game/templates/GameShell.tsx"() {
44533
44611
  init_cn();
44534
44612
  init_Box();
44535
44613
  init_Stack();
44536
44614
  init_Typography();
44615
+ shellLog = logger.createLogger("almadar:ui:game:game-shell");
44537
44616
  _scr = null;
44538
44617
  GameShell = ({
44539
44618
  appName = "Game",
@@ -44934,7 +45013,6 @@ function HexStrategyBoard({
44934
45013
  units,
44935
45014
  features,
44936
45015
  assetManifest,
44937
- assetBaseUrl,
44938
45016
  scale,
44939
45017
  showMinimap,
44940
45018
  enableCamera,
@@ -44976,7 +45054,6 @@ function HolidayRunnerBoard({
44976
45054
  units,
44977
45055
  features,
44978
45056
  assetManifest,
44979
- assetBaseUrl,
44980
45057
  scale,
44981
45058
  showMinimap,
44982
45059
  enableCamera,
@@ -45771,7 +45848,6 @@ function MatchPuzzleBoard({
45771
45848
  units,
45772
45849
  features,
45773
45850
  assetManifest,
45774
- assetBaseUrl,
45775
45851
  scale,
45776
45852
  showMinimap,
45777
45853
  enableCamera,
@@ -46032,7 +46108,6 @@ function MinigolfBoard({
46032
46108
  units,
46033
46109
  features,
46034
46110
  assetManifest,
46035
- assetBaseUrl,
46036
46111
  scale,
46037
46112
  showMinimap,
46038
46113
  enableCamera,
@@ -46338,7 +46413,6 @@ function PirateBoard({
46338
46413
  units,
46339
46414
  features,
46340
46415
  assetManifest,
46341
- assetBaseUrl,
46342
46416
  scale,
46343
46417
  showMinimap,
46344
46418
  enableCamera,
@@ -46459,8 +46533,8 @@ function PlatformerBoard({
46459
46533
  canvasHeight,
46460
46534
  followCamera: true,
46461
46535
  bgColor,
46462
- playerSprite,
46463
- tileSprites,
46536
+ playerSprite: playerSprite?.url,
46537
+ tileSprites: tileSprites ? Object.fromEntries(Object.entries(tileSprites).map(([k, a]) => [k, a.url])) : void 0,
46464
46538
  leftEvent,
46465
46539
  rightEvent,
46466
46540
  jumpEvent,
@@ -46525,7 +46599,7 @@ function PlatformerTemplate({
46525
46599
  worldHeight = 400,
46526
46600
  canvasWidth = 800,
46527
46601
  canvasHeight = 400,
46528
- playerSprite = `${CDN3}/characters/platformChar_idle.png`,
46602
+ playerSprite = makeAsset(`${CDN3}/characters/platformChar_idle.png`, "player"),
46529
46603
  tileSprites = DEFAULT_TILE_SPRITES,
46530
46604
  bgColor = "#5c94fc",
46531
46605
  gameEndEvent = "GAME_END",
@@ -46578,13 +46652,14 @@ var init_PlatformerTemplate = __esm({
46578
46652
  init_PlatformerBoard();
46579
46653
  init_GameHud();
46580
46654
  init_ScoreBoard();
46655
+ init_makeAsset();
46581
46656
  CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
46582
- DEFAULT_TILE_SPRITES = {
46657
+ DEFAULT_TILE_SPRITES = makeAssetMap({
46583
46658
  ground: `${CDN3}/tiles/platformPack_tile001.png`,
46584
46659
  platform: `${CDN3}/tiles/platformPack_tile004.png`,
46585
46660
  hazard: `${CDN3}/tiles/platformPack_tile017.png`,
46586
46661
  goal: `${CDN3}/tiles/platformPack_tile007.png`
46587
- };
46662
+ }, "tile");
46588
46663
  DEFAULT_PLATFORMS = [
46589
46664
  { x: 0, y: 368, width: 800, height: 32, type: "ground" },
46590
46665
  { x: 150, y: 280, width: 160, height: 16, type: "platform" },
@@ -46740,7 +46815,6 @@ function RacingBoard({
46740
46815
  units,
46741
46816
  features,
46742
46817
  assetManifest,
46743
- assetBaseUrl,
46744
46818
  scale,
46745
46819
  showMinimap,
46746
46820
  enableCamera,
@@ -46759,27 +46833,18 @@ var init_RacingBoard = __esm({
46759
46833
  RacingBoard.displayName = "RacingBoard";
46760
46834
  }
46761
46835
  });
46762
- function resolveManifestUrl3(manifest, relative) {
46763
- if (relative == null) return void 0;
46764
- if (/^https?:\/\//.test(relative)) return relative;
46765
- const base = manifest?.baseUrl;
46766
- if (base == null) return relative;
46767
- const cleanBase = base.replace(/\/$/, "");
46768
- const cleanRel = relative.replace(/^\//, "");
46769
- return `${cleanBase}/${cleanRel}`;
46770
- }
46771
46836
  function dungeonTerrain(x, y, stairsX, stairsY, manifest) {
46772
46837
  const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
46773
46838
  const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
46774
46839
  const isWall = isBorder || isPillar;
46775
46840
  const terrains = manifest?.terrains;
46776
46841
  if (x === stairsX && y === stairsY) {
46777
- return { terrain: "stairs", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.stairs) };
46842
+ return { terrain: "stairs", passable: true, terrainSprite: terrains?.stairs };
46778
46843
  }
46779
46844
  if (isWall) {
46780
- return { terrain: "wall", passable: false, terrainSprite: resolveManifestUrl3(manifest, terrains?.wall) };
46845
+ return { terrain: "wall", passable: false, terrainSprite: terrains?.wall };
46781
46846
  }
46782
- return { terrain: "floor", passable: true, terrainSprite: resolveManifestUrl3(manifest, terrains?.floor) };
46847
+ return { terrain: "floor", passable: true, terrainSprite: terrains?.floor };
46783
46848
  }
46784
46849
  function buildDefaultDungeonTiles(stairsX, stairsY, manifest) {
46785
46850
  const tiles = [];
@@ -46823,7 +46888,7 @@ function RoguelikeBoard({
46823
46888
  x: num(r.x),
46824
46889
  y: num(r.y),
46825
46890
  terrain: r.terrain == null ? void 0 : str(r.terrain),
46826
- terrainSprite: r.terrainSprite == null ? void 0 : str(r.terrainSprite),
46891
+ terrainSprite: r.terrainSprite == null ? void 0 : makeAsset(str(r.terrainSprite), "tile"),
46827
46892
  passable: r.passable !== false
46828
46893
  })),
46829
46894
  [board.tiles]
@@ -46903,7 +46968,7 @@ function RoguelikeBoard({
46903
46968
  health: playerHp,
46904
46969
  maxHealth: playerMaxHp,
46905
46970
  unitType: "player",
46906
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.player)
46971
+ sprite: assetManifest?.units?.player
46907
46972
  },
46908
46973
  ...liveEnemies.map((e) => ({
46909
46974
  id: e.id,
@@ -46913,7 +46978,7 @@ function RoguelikeBoard({
46913
46978
  health: e.hp,
46914
46979
  maxHealth: 6,
46915
46980
  unitType: "enemy",
46916
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.units?.enemy)
46981
+ sprite: assetManifest?.units?.enemy
46917
46982
  }))
46918
46983
  ];
46919
46984
  }, [player, enemies, playerHp, playerMaxHp, assetManifest, t]);
@@ -46923,7 +46988,7 @@ function RoguelikeBoard({
46923
46988
  x: it.x,
46924
46989
  y: it.y,
46925
46990
  type: it.kind,
46926
- sprite: resolveManifestUrl3(assetManifest, assetManifest?.features?.[it.kind])
46991
+ sprite: assetManifest?.features?.[it.kind]
46927
46992
  })),
46928
46993
  [items, assetManifest]
46929
46994
  );
@@ -46984,7 +47049,6 @@ function RoguelikeBoard({
46984
47049
  onTileHover: (x, y) => setHoveredTile({ x, y }),
46985
47050
  onTileLeave: () => setHoveredTile(null),
46986
47051
  scale,
46987
- assetBaseUrl: assetManifest?.baseUrl,
46988
47052
  assetManifest,
46989
47053
  unitScale,
46990
47054
  spriteHeightRatio,
@@ -47044,6 +47108,7 @@ var init_RoguelikeBoard = __esm({
47044
47108
  init_Stack();
47045
47109
  init_IsometricCanvas();
47046
47110
  init_boardEntity();
47111
+ init_makeAsset();
47047
47112
  DUNGEON_GRID_W = 16;
47048
47113
  DUNGEON_GRID_H = 16;
47049
47114
  DEFAULT_ENEMIES = [
@@ -47094,55 +47159,59 @@ function RoguelikeTemplate({
47094
47159
  }
47095
47160
  );
47096
47161
  }
47097
- var CDN4, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
47162
+ var CDN4, wall, floor, tiles2, stairs, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
47098
47163
  var init_RoguelikeTemplate = __esm({
47099
47164
  "components/game/templates/RoguelikeTemplate.tsx"() {
47100
47165
  init_RoguelikeBoard();
47166
+ init_makeAsset();
47101
47167
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
47168
+ wall = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`, "tile");
47169
+ floor = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirt_E.png`, "tile");
47170
+ tiles2 = makeAsset(`${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`, "tile");
47171
+ stairs = makeAsset(`${CDN4}/isometric-dungeon/Isometric/stairs_E.png`, "tile");
47102
47172
  DEFAULT_ROGUELIKE_TILES = [
47103
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47104
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47105
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47106
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47107
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47108
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47109
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47110
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47111
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47112
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47113
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47114
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47115
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47116
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47117
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47118
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47119
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
47120
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
47121
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
47122
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47123
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47124
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47125
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47126
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
47127
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
47173
+ { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47174
+ { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47175
+ { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47176
+ { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47177
+ { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: wall },
47178
+ { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
47179
+ { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47180
+ { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47181
+ { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: floor },
47182
+ { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: wall },
47183
+ { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
47184
+ { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
47185
+ { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: tiles2 },
47186
+ { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: floor },
47187
+ { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: wall },
47188
+ { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
47189
+ { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: floor },
47190
+ { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: tiles2 },
47191
+ { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: stairs },
47192
+ { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: wall },
47193
+ { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47194
+ { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47195
+ { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47196
+ { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: wall },
47197
+ { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: wall }
47128
47198
  ];
47129
47199
  DEFAULT_ROGUELIKE_MANIFEST = {
47130
- baseUrl: CDN4,
47131
- terrains: {
47132
- floor: "/isometric-dungeon/Isometric/dirt_E.png",
47133
- wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
47134
- stairs: "/isometric-dungeon/Isometric/stairs_E.png",
47135
- planks: "/isometric-dungeon/Isometric/planks_E.png"
47136
- },
47200
+ terrains: makeAssetMap({
47201
+ floor: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
47202
+ wall: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png`,
47203
+ stairs: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png`,
47204
+ planks: `${CDN4}/isometric-dungeon/Isometric/planks_E.png`
47205
+ }, "tile"),
47137
47206
  units: {
47138
- player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
47139
- enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
47207
+ player: makeAsset(`${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`, "player"),
47208
+ enemy: makeAsset(`${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`, "enemy")
47140
47209
  },
47141
- features: {
47142
- health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
47143
- sword: "/isometric-dungeon/Isometric/barrel_E.png",
47144
- shield: "/isometric-dungeon/Isometric/barrel_E.png"
47145
- }
47210
+ features: makeAssetMap({
47211
+ health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
47212
+ sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
47213
+ shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
47214
+ }, "item")
47146
47215
  };
47147
47216
  RoguelikeTemplate.displayName = "RoguelikeTemplate";
47148
47217
  }
@@ -49997,7 +50066,6 @@ function SokobanBoard({
49997
50066
  units,
49998
50067
  features,
49999
50068
  assetManifest,
50000
- assetBaseUrl,
50001
50069
  scale,
50002
50070
  showMinimap,
50003
50071
  enableCamera,
@@ -50039,7 +50107,6 @@ function SpaceShmupBoard({
50039
50107
  units,
50040
50108
  features,
50041
50109
  assetManifest,
50042
- assetBaseUrl,
50043
50110
  scale,
50044
50111
  showMinimap,
50045
50112
  enableCamera,
@@ -50081,7 +50148,6 @@ function SpaceStationBoard({
50081
50148
  units,
50082
50149
  features,
50083
50150
  assetManifest,
50084
- assetBaseUrl,
50085
50151
  scale,
50086
50152
  showMinimap,
50087
50153
  enableCamera,
@@ -50216,7 +50282,6 @@ function SportsBoard({
50216
50282
  units,
50217
50283
  features,
50218
50284
  assetManifest,
50219
- assetBaseUrl,
50220
50285
  scale,
50221
50286
  showMinimap,
50222
50287
  enableCamera,
@@ -52060,7 +52125,6 @@ function TanksBoard({
52060
52125
  units,
52061
52126
  features,
52062
52127
  assetManifest,
52063
- assetBaseUrl,
52064
52128
  scale,
52065
52129
  showMinimap,
52066
52130
  enableCamera,
@@ -52338,15 +52402,6 @@ var init_ToastSlot = __esm({
52338
52402
  ToastSlot.displayName = "ToastSlot";
52339
52403
  }
52340
52404
  });
52341
- function resolveManifestUrl4(manifest, relative) {
52342
- if (relative == null || relative === "") return void 0;
52343
- if (/^https?:\/\//.test(relative)) return relative;
52344
- const base = manifest?.baseUrl;
52345
- if (base == null) return relative;
52346
- const cleanBase = base.replace(/\/$/, "");
52347
- const cleanRel = relative.replace(/^\//, "");
52348
- return `${cleanBase}/${cleanRel}`;
52349
- }
52350
52405
  function readPlayer(v) {
52351
52406
  if (v == null || typeof v !== "object") return void 0;
52352
52407
  const o = v;
@@ -52399,10 +52454,10 @@ function TopDownShooterBoard({
52399
52454
  const wave = propWave ?? num(board.wave, 1);
52400
52455
  const lives = propLives ?? num(board.lives, 3);
52401
52456
  const result = propResult ?? (str(board.result) || "none");
52402
- const playerSprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.player);
52403
- const enemySprite = resolveManifestUrl4(assetManifest, assetManifest?.units?.enemy);
52404
- const projectileSprite = resolveManifestUrl4(assetManifest, assetManifest?.features?.projectile);
52405
- const backgroundSprite = resolveManifestUrl4(assetManifest, assetManifest?.background);
52457
+ const playerSprite = assetManifest?.units?.player?.url;
52458
+ const enemySprite = assetManifest?.units?.enemy?.url;
52459
+ const projectileSprite = assetManifest?.features?.projectile?.url;
52460
+ const backgroundSprite = assetManifest?.background;
52406
52461
  const spriteUrls = React88.useMemo(
52407
52462
  () => [playerSprite, enemySprite, projectileSprite].filter((u) => u != null),
52408
52463
  [playerSprite, enemySprite, projectileSprite]
@@ -52569,7 +52624,6 @@ function TopDownShooterBoard({
52569
52624
  width,
52570
52625
  height,
52571
52626
  backgroundImage: backgroundSprite,
52572
- assetBaseUrl: assetManifest?.baseUrl,
52573
52627
  onDraw
52574
52628
  }
52575
52629
  ),
@@ -52694,15 +52748,6 @@ var init_TopDownShooterTemplate = __esm({
52694
52748
  TopDownShooterTemplate.displayName = "TopDownShooterTemplate";
52695
52749
  }
52696
52750
  });
52697
- function resolveManifestUrl5(manifest, relative) {
52698
- if (relative == null) return void 0;
52699
- if (/^https?:\/\//.test(relative)) return relative;
52700
- const base = manifest?.baseUrl;
52701
- if (base == null) return relative;
52702
- const cleanBase = base.replace(/\/$/, "");
52703
- const cleanRel = relative.replace(/^\//, "");
52704
- return `${cleanBase}/${cleanRel}`;
52705
- }
52706
52751
  function buildDefaultTDTiles() {
52707
52752
  const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
52708
52753
  const tiles = [];
@@ -52722,18 +52767,18 @@ function buildDefaultTDTiles() {
52722
52767
  function tilesToIso2(tiles, manifest) {
52723
52768
  return tiles.map((t) => {
52724
52769
  const key = t.terrain ?? "ground";
52725
- const sprite = t.terrainSprite ?? resolveManifestUrl5(manifest, manifest?.terrains?.[key]) ?? resolveManifestUrl5(manifest, manifest?.terrains?.ground);
52770
+ const terrainSprite = t.terrainSprite != null ? makeAsset(t.terrainSprite, "tile") : manifest?.terrains?.[key] ?? manifest?.terrains?.ground;
52726
52771
  return {
52727
52772
  x: t.x,
52728
52773
  y: t.y,
52729
52774
  terrain: t.terrain,
52730
- terrainSprite: sprite,
52775
+ terrainSprite,
52731
52776
  passable: t.passable
52732
52777
  };
52733
52778
  });
52734
52779
  }
52735
52780
  function creepsToUnits(creeps, manifest) {
52736
- const sprite = resolveManifestUrl5(manifest, manifest?.units?.creep);
52781
+ const sprite = manifest?.units?.creep;
52737
52782
  return creeps.map((c) => ({
52738
52783
  id: c.id,
52739
52784
  position: { x: c.x, y: c.y },
@@ -52751,14 +52796,14 @@ function heroToUnit(hero, manifest) {
52751
52796
  position: { x: hero.x, y: hero.y },
52752
52797
  name: "Hero",
52753
52798
  team: "player",
52754
- sprite: resolveManifestUrl5(manifest, manifest?.units?.hero),
52799
+ sprite: manifest?.units?.hero,
52755
52800
  unitType: "hero",
52756
52801
  health: 1,
52757
52802
  maxHealth: 1
52758
52803
  };
52759
52804
  }
52760
52805
  function towersToFeatures(towers, manifest) {
52761
- const sprite = resolveManifestUrl5(manifest, manifest?.features?.tower);
52806
+ const sprite = manifest?.features?.tower;
52762
52807
  return towers.map((t) => ({
52763
52808
  id: t.id,
52764
52809
  x: t.x,
@@ -52956,7 +53001,6 @@ function TowerDefenseBoard({
52956
53001
  tiles: isoTiles,
52957
53002
  units: isoUnits,
52958
53003
  features: towerFeatures,
52959
- assetBaseUrl: assetManifest?.baseUrl,
52960
53004
  assetManifest,
52961
53005
  validMoves,
52962
53006
  hoveredTile,
@@ -53000,6 +53044,7 @@ var TD_GRID_W, TD_GRID_H, DEFAULT_TD_PATH, DEFAULT_TD_TILES;
53000
53044
  var init_TowerDefenseBoard = __esm({
53001
53045
  "components/game/organisms/TowerDefenseBoard.tsx"() {
53002
53046
  "use client";
53047
+ init_makeAsset();
53003
53048
  init_cn();
53004
53049
  init_useEventBus();
53005
53050
  init_Box();
@@ -53329,15 +53374,6 @@ var init_UncontrolledBattleBoard = __esm({
53329
53374
  UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
53330
53375
  }
53331
53376
  });
53332
- function resolveManifestUrl6(manifest, relative) {
53333
- if (relative == null) return void 0;
53334
- if (/^https?:\/\//.test(relative)) return relative;
53335
- const base = manifest?.baseUrl;
53336
- if (base == null) return relative;
53337
- const cleanBase = base.replace(/\/$/, "");
53338
- const cleanRel = relative.replace(/^\//, "");
53339
- return `${cleanBase}/${cleanRel}`;
53340
- }
53341
53377
  function VisualNovelBoard({
53342
53378
  entity,
53343
53379
  nodes: propNodes,
@@ -53372,11 +53408,11 @@ function VisualNovelBoard({
53372
53408
  const currentNodeId = propCurrentNodeId ?? (str(board.currentNodeId) || nodes[0]?.id);
53373
53409
  const currentNode = nodes.find((n) => n.id === currentNodeId) ?? nodes[0];
53374
53410
  const backgroundImage = React88.useMemo(
53375
- () => resolveManifestUrl6(assetManifest, assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""]),
53411
+ () => assetManifest?.backgrounds?.[currentNode?.backgroundKey ?? ""],
53376
53412
  [assetManifest, currentNode?.backgroundKey]
53377
53413
  );
53378
53414
  const portraitUrl = React88.useMemo(
53379
- () => resolveManifestUrl6(assetManifest, assetManifest?.portraits?.[currentNode?.portraitKey ?? ""]),
53415
+ () => assetManifest?.portraits?.[currentNode?.portraitKey ?? ""],
53380
53416
  [assetManifest, currentNode?.portraitKey]
53381
53417
  );
53382
53418
  const dialogueChoices = React88.useMemo(
@@ -53550,7 +53586,7 @@ function buildDefaultWorldTiles() {
53550
53586
  for (let x = 0; x < WORLD_GRID_W; x++) {
53551
53587
  const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
53552
53588
  const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
53553
- tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
53589
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: makeAsset(def.sprite, "tile"), passable: def.passable });
53554
53590
  }
53555
53591
  }
53556
53592
  return tiles;
@@ -53594,7 +53630,12 @@ function WorldMapBoard({
53594
53630
  const resolved = boardEntity(entity);
53595
53631
  const entityUnits = rows(resolved?.units);
53596
53632
  const entityTiles = rows(resolved?.tiles);
53597
- const features = propFeatures ?? rows(resolved?.features);
53633
+ const features = propFeatures ?? rows(resolved?.features).map((r) => ({
53634
+ id: r.id == null ? void 0 : str(r.id),
53635
+ x: num(r.x),
53636
+ y: num(r.y),
53637
+ type: str(r.type)
53638
+ }));
53598
53639
  const selectedHeroId = resolved?.selectedHeroId ?? null;
53599
53640
  const assetManifest = propAssetManifest ?? resolved?.assetManifest;
53600
53641
  const backgroundImage = resolved?.backgroundImage;
@@ -53604,7 +53645,7 @@ function WorldMapBoard({
53604
53645
  x: num(t.x),
53605
53646
  y: num(t.y),
53606
53647
  terrain: str(t.terrain),
53607
- terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
53648
+ terrainSprite: t.terrainSprite == null ? void 0 : makeAsset(str(t.terrainSprite), "tile"),
53608
53649
  passable: t.passable !== false
53609
53650
  })),
53610
53651
  [entityTiles]
@@ -53620,7 +53661,7 @@ function WorldMapBoard({
53620
53661
  team: str(u.team) === "enemy" ? "enemy" : "player",
53621
53662
  health: num(u.health) || 100,
53622
53663
  maxHealth: num(u.maxHealth) || 100,
53623
- sprite: u.sprite == null ? void 0 : str(u.sprite)
53664
+ sprite: u.sprite == null ? void 0 : makeAsset(str(u.sprite), "player")
53624
53665
  })),
53625
53666
  [entityUnits, propUnits]
53626
53667
  );
@@ -53802,7 +53843,6 @@ function WorldMapBoard({
53802
53843
  onTileHover: (x, y) => setHoveredTile({ x, y }),
53803
53844
  onTileLeave: () => setHoveredTile(null),
53804
53845
  scale,
53805
- assetBaseUrl: assetManifest?.baseUrl,
53806
53846
  assetManifest,
53807
53847
  backgroundImage,
53808
53848
  effectSpriteUrls,
@@ -53825,6 +53865,7 @@ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TIL
53825
53865
  var init_WorldMapBoard = __esm({
53826
53866
  "components/game/organisms/WorldMapBoard.tsx"() {
53827
53867
  "use client";
53868
+ init_makeAsset();
53828
53869
  init_cn();
53829
53870
  init_useEventBus();
53830
53871
  init_Stack();
@@ -53878,62 +53919,66 @@ function WorldMapTemplate({
53878
53919
  }
53879
53920
  );
53880
53921
  }
53881
- var CDN5, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
53922
+ var CDN5, mountain, water, grass, road, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
53882
53923
  var init_WorldMapTemplate = __esm({
53883
53924
  "components/game/templates/WorldMapTemplate.tsx"() {
53884
53925
  init_WorldMapBoard();
53926
+ init_makeAsset();
53885
53927
  CDN5 = "https://almadar-kflow-assets.web.app/shared";
53928
+ mountain = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`, "tile");
53929
+ water = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`, "tile");
53930
+ grass = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`, "tile");
53931
+ road = makeAsset(`${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`, "tile");
53886
53932
  DEFAULT_WORLDMAP_TILES = [
53887
- { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53888
- { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53889
- { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53890
- { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53891
- { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53892
- { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53893
- { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53894
- { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53895
- { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53896
- { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53897
- { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53898
- { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53899
- { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
53900
- { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53901
- { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53902
- { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53903
- { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53904
- { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53905
- { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
53906
- { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53907
- { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53908
- { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
53909
- { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
53910
- { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
53911
- { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
53933
+ { x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53934
+ { x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53935
+ { x: 2, y: 0, terrain: "water", passable: false, terrainSprite: water },
53936
+ { x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53937
+ { x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: mountain },
53938
+ { x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: mountain },
53939
+ { x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53940
+ { x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53941
+ { x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: grass },
53942
+ { x: 4, y: 1, terrain: "water", passable: false, terrainSprite: water },
53943
+ { x: 0, y: 2, terrain: "water", passable: false, terrainSprite: water },
53944
+ { x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
53945
+ { x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: road },
53946
+ { x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: grass },
53947
+ { x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: mountain },
53948
+ { x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
53949
+ { x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
53950
+ { x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: grass },
53951
+ { x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: road },
53952
+ { x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: mountain },
53953
+ { x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
53954
+ { x: 1, y: 4, terrain: "water", passable: false, terrainSprite: water },
53955
+ { x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: grass },
53956
+ { x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain },
53957
+ { x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: mountain }
53912
53958
  ];
53913
53959
  DEFAULT_WORLDMAP_UNITS = [
53914
- { 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` },
53915
- { 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` }
53960
+ { 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") },
53961
+ { 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") }
53916
53962
  ];
53917
53963
  DEFAULT_WORLDMAP_FEATURES = [
53918
- { id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN5}/scenes/world/capital.png` },
53919
- { id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN5}/world-map/power_node.png` }
53964
+ { id: "f1", x: 2, y: 2, type: "capital", sprite: makeAsset(`${CDN5}/scenes/world/capital.png`, "decoration") },
53965
+ { id: "f2", x: 4, y: 2, type: "power_node", sprite: makeAsset(`${CDN5}/world-map/power_node.png`, "decoration") }
53920
53966
  ];
53921
53967
  DEFAULT_WORLDMAP_MANIFEST = {
53922
- baseUrl: CDN5,
53923
- terrains: {
53924
- grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
53925
- water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
53926
- mountain: "/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png",
53927
- road: "/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png"
53928
- },
53968
+ terrains: makeAssetMap({
53969
+ grass: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
53970
+ water: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png`,
53971
+ mountain: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png`,
53972
+ road: `${CDN5}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png`
53973
+ }, "tile"),
53929
53974
  units: {
53930
- hero: "/sprite-sheets/amir-sprite-sheet-se.png",
53931
- scout: "/sprite-sheets/archivist-sprite-sheet-se.png"
53975
+ hero: makeAsset(`${CDN5}/sprite-sheets/amir-sprite-sheet-se.png`, "player"),
53976
+ scout: makeAsset(`${CDN5}/sprite-sheets/archivist-sprite-sheet-se.png`, "npc")
53932
53977
  },
53933
- features: {
53934
- capital: "/scenes/world/capital.png",
53935
- power_node: "/world-map/power_node.png"
53936
- }
53978
+ features: makeAssetMap({
53979
+ capital: `${CDN5}/scenes/world/capital.png`,
53980
+ power_node: `${CDN5}/world-map/power_node.png`
53981
+ }, "decoration")
53937
53982
  };
53938
53983
  WorldMapTemplate.displayName = "WorldMapTemplate";
53939
53984
  }