@almadar/ui 5.54.0 → 5.56.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.
@@ -8426,6 +8426,16 @@ var init_Skeleton = __esm({
8426
8426
  Skeleton.displayName = "Skeleton";
8427
8427
  }
8428
8428
  });
8429
+ function isKnownPattern(type) {
8430
+ return type in componentMapping;
8431
+ }
8432
+ var componentMapping;
8433
+ var init_pattern_resolver = __esm({
8434
+ "renderer/pattern-resolver.ts"() {
8435
+ logger.createLogger("almadar:ui:pattern-resolver");
8436
+ componentMapping = {};
8437
+ }
8438
+ });
8429
8439
  function executeClientEffects(effects, config) {
8430
8440
  if (!effects || effects.length === 0) {
8431
8441
  return;
@@ -8434,7 +8444,7 @@ function executeClientEffects(effects, config) {
8434
8444
  try {
8435
8445
  executeEffect(effect, config);
8436
8446
  } catch (error) {
8437
- log3.error("Error executing effect", () => ({
8447
+ log4.error("Error executing effect", () => ({
8438
8448
  effect: JSON.stringify(effect),
8439
8449
  error: error instanceof Error ? error : String(error)
8440
8450
  }));
@@ -8466,7 +8476,7 @@ function executeEffect(effect, config) {
8466
8476
  break;
8467
8477
  }
8468
8478
  default:
8469
- log3.warn("Unknown effect type", { effectType: String(effectType) });
8479
+ log4.warn("Unknown effect type", { effectType: String(effectType) });
8470
8480
  }
8471
8481
  }
8472
8482
  function executeRenderUI(slot, patternConfig, config) {
@@ -8481,10 +8491,10 @@ function executeNotify(message, options, config) {
8481
8491
  function executeEmit(event, payload, config) {
8482
8492
  config.eventBus.emit(event, payload);
8483
8493
  }
8484
- var log3;
8494
+ var log4;
8485
8495
  var init_client_effect_executor = __esm({
8486
8496
  "renderer/client-effect-executor.ts"() {
8487
- log3 = logger.createLogger("almadar:ui:effects:client");
8497
+ log4 = logger.createLogger("almadar:ui:effects:client");
8488
8498
  }
8489
8499
  });
8490
8500
 
@@ -8645,12 +8655,12 @@ function useOfflineExecutor(options) {
8645
8655
  clearQueue
8646
8656
  };
8647
8657
  }
8648
- var log4, effectIdCounter, OfflineExecutor;
8658
+ var log5, effectIdCounter, OfflineExecutor;
8649
8659
  var init_offline_executor = __esm({
8650
8660
  "renderer/offline-executor.ts"() {
8651
8661
  "use client";
8652
8662
  init_client_effect_executor();
8653
- log4 = logger.createLogger("almadar:ui:effects:offline");
8663
+ log5 = logger.createLogger("almadar:ui:effects:offline");
8654
8664
  effectIdCounter = 0;
8655
8665
  OfflineExecutor = class {
8656
8666
  constructor(config) {
@@ -8704,7 +8714,7 @@ var init_offline_executor = __esm({
8704
8714
  this.state.syncQueue = JSON.parse(stored);
8705
8715
  }
8706
8716
  } catch (error) {
8707
- log4.warn("Failed to load sync queue", { error: error instanceof Error ? error : String(error) });
8717
+ log5.warn("Failed to load sync queue", { error: error instanceof Error ? error : String(error) });
8708
8718
  }
8709
8719
  }
8710
8720
  /**
@@ -8715,7 +8725,7 @@ var init_offline_executor = __esm({
8715
8725
  try {
8716
8726
  this.storage.setItem("orbital-offline-queue", JSON.stringify(this.state.syncQueue));
8717
8727
  } catch (error) {
8718
- log4.warn("Failed to save sync queue", { error: error instanceof Error ? error : String(error) });
8728
+ log5.warn("Failed to save sync queue", { error: error instanceof Error ? error : String(error) });
8719
8729
  }
8720
8730
  }
8721
8731
  /**
@@ -8785,7 +8795,7 @@ var init_offline_executor = __esm({
8785
8795
  this.queueForSync(type, { args, event, payload });
8786
8796
  break;
8787
8797
  default:
8788
- log4.warn("Unknown effect type", { type });
8798
+ log5.warn("Unknown effect type", { type });
8789
8799
  }
8790
8800
  }
8791
8801
  }
@@ -8890,6 +8900,7 @@ var init_offline_executor = __esm({
8890
8900
  // renderer/index.ts
8891
8901
  var init_renderer = __esm({
8892
8902
  "renderer/index.ts"() {
8903
+ init_pattern_resolver();
8893
8904
  init_slot_definitions();
8894
8905
  }
8895
8906
  });
@@ -10593,7 +10604,7 @@ function recordTransition(trace) {
10593
10604
  ...trace,
10594
10605
  id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
10595
10606
  };
10596
- log5.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
10607
+ log6.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
10597
10608
  getState().transitions.push(entry);
10598
10609
  if (getState().transitions.length > MAX_TRANSITIONS) {
10599
10610
  getState().transitions.shift();
@@ -10662,7 +10673,7 @@ function getTraitSnapshots() {
10662
10673
  try {
10663
10674
  snapshots.push(getter());
10664
10675
  } catch (err) {
10665
- log5.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
10676
+ log6.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
10666
10677
  }
10667
10678
  }
10668
10679
  return snapshots;
@@ -10725,12 +10736,12 @@ function waitForTransition(event, timeoutMs = 1e4) {
10725
10736
  }
10726
10737
  function bindEventBus(eventBus) {
10727
10738
  if (typeof window === "undefined") return;
10728
- log5.info("bindEventBus", { hasOnAny: !!eventBus.onAny });
10739
+ log6.info("bindEventBus", { hasOnAny: !!eventBus.onAny });
10729
10740
  exposeOnWindow();
10730
10741
  if (window.__orbitalVerification) {
10731
10742
  window.__orbitalVerification.sendEvent = (event, payload, traitScope) => {
10732
10743
  const prefixed = event.startsWith("UI:") ? event : traitScope ? `UI:${traitScope}.${event}` : `UI:${event}`;
10733
- log5.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
10744
+ log6.debug("sendEvent", { event: prefixed, traitScope, payloadKeys: payload ? Object.keys(payload) : [] });
10734
10745
  eventBus.emit(prefixed, payload);
10735
10746
  };
10736
10747
  const eventLog = [];
@@ -10779,10 +10790,10 @@ function updateAssetStatus(url, status) {
10779
10790
  window.__orbitalVerification.assetStatus[url] = status;
10780
10791
  }
10781
10792
  }
10782
- var log5, MAX_TRANSITIONS;
10793
+ var log6, MAX_TRANSITIONS;
10783
10794
  var init_verificationRegistry = __esm({
10784
10795
  "lib/verificationRegistry.ts"() {
10785
- log5 = logger.createLogger("almadar:bridge");
10796
+ log6 = logger.createLogger("almadar:bridge");
10786
10797
  MAX_TRANSITIONS = 500;
10787
10798
  exposeOnWindow();
10788
10799
  }
@@ -11133,6 +11144,8 @@ function IsometricCanvas({
11133
11144
  showMinimap = true,
11134
11145
  enableCamera = true,
11135
11146
  unitScale = 1,
11147
+ spriteHeightRatio = 1.5,
11148
+ spriteMaxWidthRatio = 0.6,
11136
11149
  // Asset resolution
11137
11150
  getTerrainSprite,
11138
11151
  getFeatureSprite,
@@ -11523,8 +11536,8 @@ function IsometricCanvas({
11523
11536
  const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
11524
11537
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
11525
11538
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
11526
- const unitDrawH = scaledFloorHeight * 1.5 * unitScale;
11527
- const maxUnitW = scaledTileWidth * 0.6 * unitScale;
11539
+ const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
11540
+ const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11528
11541
  const ar = img ? img.naturalWidth / img.naturalHeight : 0.5;
11529
11542
  let drawH = unitDrawH;
11530
11543
  let drawW = unitDrawH * ar;
@@ -11908,6 +11921,8 @@ function BattleBoard({
11908
11921
  assetManifest: propAssetManifest,
11909
11922
  scale = 0.45,
11910
11923
  unitScale = 1,
11924
+ spriteHeightRatio = 1.5,
11925
+ spriteMaxWidthRatio = 0.6,
11911
11926
  header,
11912
11927
  sidebar,
11913
11928
  actions,
@@ -12198,7 +12213,9 @@ function BattleBoard({
12198
12213
  hasActiveEffects: hasActiveEffects2,
12199
12214
  effectSpriteUrls,
12200
12215
  resolveUnitFrame,
12201
- unitScale
12216
+ unitScale,
12217
+ spriteHeightRatio,
12218
+ spriteMaxWidthRatio
12202
12219
  }
12203
12220
  ),
12204
12221
  overlay && overlay(ctx)
@@ -13076,7 +13093,7 @@ var init_avl_elk_layout = __esm({
13076
13093
  elk = new ELK__default.default();
13077
13094
  }
13078
13095
  });
13079
- var log6, SWIM_GUTTER, CENTER_W, BehaviorView;
13096
+ var log7, SWIM_GUTTER, CENTER_W, BehaviorView;
13080
13097
  var init_BehaviorView = __esm({
13081
13098
  "components/avl/molecules/BehaviorView.tsx"() {
13082
13099
  "use client";
@@ -13085,7 +13102,7 @@ var init_BehaviorView = __esm({
13085
13102
  init_AvlSwimLane();
13086
13103
  init_types();
13087
13104
  init_avl_elk_layout();
13088
- log6 = logger.createLogger("almadar:ui:avl:behavior-view");
13105
+ log7 = logger.createLogger("almadar:ui:avl:behavior-view");
13089
13106
  SWIM_GUTTER = 120;
13090
13107
  CENTER_W = 360;
13091
13108
  BehaviorView = ({ data }) => {
@@ -13096,7 +13113,7 @@ var init_BehaviorView = __esm({
13096
13113
  const dataKey = React82.useMemo(() => JSON.stringify(traitData), [traitData]);
13097
13114
  React82.useEffect(() => {
13098
13115
  if (!traitData) return;
13099
- computeTraitLayout(traitData).then(setLayout).catch((err) => log6.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
13116
+ computeTraitLayout(traitData).then(setLayout).catch((err) => log7.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
13100
13117
  }, [dataKey]);
13101
13118
  if (!traitData) {
13102
13119
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-[var(--color-border)] bg-[var(--color-card)] p-4 text-center text-[var(--color-muted-foreground)] text-sm", children: t("avl.noTraitData") });
@@ -13507,7 +13524,7 @@ function generateDiff(oldVal, newVal) {
13507
13524
  }
13508
13525
  return diff;
13509
13526
  }
13510
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log7, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
13527
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log8, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
13511
13528
  var init_CodeBlock = __esm({
13512
13529
  "components/core/molecules/markdown/CodeBlock.tsx"() {
13513
13530
  init_cn();
@@ -13590,7 +13607,7 @@ var init_CodeBlock = __esm({
13590
13607
  "lolo-op-async": { color: syntax.ORB_COLORS.dark.async }
13591
13608
  };
13592
13609
  loloStyle = { ...dark__default.default, ...loloStyleOverrides };
13593
- log7 = logger.createLogger("almadar:ui:markdown-code");
13610
+ log8 = logger.createLogger("almadar:ui:markdown-code");
13594
13611
  CODE_LANGUAGES = [
13595
13612
  "text",
13596
13613
  "json",
@@ -13854,7 +13871,7 @@ var init_CodeBlock = __esm({
13854
13871
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
13855
13872
  setTimeout(() => setCopied(false), 2e3);
13856
13873
  } catch (err) {
13857
- log7.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
13874
+ log8.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
13858
13875
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
13859
13876
  }
13860
13877
  };
@@ -17735,14 +17752,14 @@ function useSafeEventBus2() {
17735
17752
  } };
17736
17753
  }
17737
17754
  }
17738
- var log8, lookStyles4, ButtonGroup;
17755
+ var log9, lookStyles4, ButtonGroup;
17739
17756
  var init_ButtonGroup = __esm({
17740
17757
  "components/core/molecules/ButtonGroup.tsx"() {
17741
17758
  "use client";
17742
17759
  init_cn();
17743
17760
  init_atoms2();
17744
17761
  init_useEventBus();
17745
- log8 = logger.createLogger("almadar:ui:button-group");
17762
+ log9 = logger.createLogger("almadar:ui:button-group");
17746
17763
  lookStyles4 = {
17747
17764
  "right-aligned-buttons": "",
17748
17765
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -17823,7 +17840,7 @@ var init_ButtonGroup = __esm({
17823
17840
  {
17824
17841
  variant: "ghost",
17825
17842
  onClick: () => {
17826
- log8.debug("Filter clicked", { field: filter.field });
17843
+ log9.debug("Filter clicked", { field: filter.field });
17827
17844
  },
17828
17845
  children: filter.label
17829
17846
  },
@@ -25485,9 +25502,9 @@ function debug(...args) {
25485
25502
  const [first, ...rest] = args;
25486
25503
  const message = typeof first === "string" ? first : "<debug>";
25487
25504
  if (rest.length === 0 && typeof first === "string") {
25488
- log9.debug(message);
25505
+ log10.debug(message);
25489
25506
  } else {
25490
- log9.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
25507
+ log10.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
25491
25508
  }
25492
25509
  }
25493
25510
  function debugGroup(label) {
@@ -25515,11 +25532,11 @@ function toLogMetaValue(v) {
25515
25532
  }
25516
25533
  return String(v);
25517
25534
  }
25518
- var NAMESPACE, log9;
25535
+ var NAMESPACE, log10;
25519
25536
  var init_debug = __esm({
25520
25537
  "lib/debug.ts"() {
25521
25538
  NAMESPACE = "almadar:ui:debug";
25522
- log9 = logger.createLogger(NAMESPACE);
25539
+ log10 = logger.createLogger(NAMESPACE);
25523
25540
  logger.createLogger("almadar:ui:debug:input");
25524
25541
  logger.createLogger("almadar:ui:debug:collision");
25525
25542
  logger.createLogger("almadar:ui:debug:physics");
@@ -41810,11 +41827,11 @@ var init_Canvas3DErrorBoundary = __esm({
41810
41827
  "components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
41811
41828
  }
41812
41829
  });
41813
- var log10, Canvas3DErrorBoundary;
41830
+ var log11, Canvas3DErrorBoundary;
41814
41831
  var init_Canvas3DErrorBoundary2 = __esm({
41815
41832
  "components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
41816
41833
  init_Canvas3DErrorBoundary();
41817
- log10 = logger.createLogger("almadar:ui:game:canvas3d:error-boundary");
41834
+ log11 = logger.createLogger("almadar:ui:game:canvas3d:error-boundary");
41818
41835
  Canvas3DErrorBoundary = class extends React82.Component {
41819
41836
  constructor(props) {
41820
41837
  super(props);
@@ -41842,8 +41859,8 @@ var init_Canvas3DErrorBoundary2 = __esm({
41842
41859
  componentDidCatch(error, errorInfo) {
41843
41860
  this.setState({ errorInfo });
41844
41861
  this.props.onError?.(error, errorInfo);
41845
- log10.error("Error caught", { error });
41846
- log10.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
41862
+ log11.error("Error caught", { error });
41863
+ log11.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
41847
41864
  }
41848
41865
  render() {
41849
41866
  if (this.state.hasError) {
@@ -41906,7 +41923,7 @@ function useGLTFModel(url, resourceBasePath) {
41906
41923
  setState({ model: null, isLoading: false, error: null });
41907
41924
  return;
41908
41925
  }
41909
- log11.debug("Loading", { url });
41926
+ log12.debug("Loading", { url });
41910
41927
  setState((prev) => ({ ...prev, isLoading: true, error: null }));
41911
41928
  const assetRoot = resourceBasePath || detectAssetRoot2(url);
41912
41929
  const loader = new GLTFLoader.GLTFLoader();
@@ -41914,7 +41931,7 @@ function useGLTFModel(url, resourceBasePath) {
41914
41931
  loader.load(
41915
41932
  url,
41916
41933
  (gltf) => {
41917
- log11.debug("Loaded", { url });
41934
+ log12.debug("Loaded", { url });
41918
41935
  setState({
41919
41936
  model: gltf.scene,
41920
41937
  isLoading: false,
@@ -41923,7 +41940,7 @@ function useGLTFModel(url, resourceBasePath) {
41923
41940
  },
41924
41941
  void 0,
41925
41942
  (err) => {
41926
- log11.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
41943
+ log12.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
41927
41944
  setState({
41928
41945
  model: null,
41929
41946
  isLoading: false,
@@ -42039,11 +42056,11 @@ function ModelLoader({
42039
42056
  }
42040
42057
  );
42041
42058
  }
42042
- var log11;
42059
+ var log12;
42043
42060
  var init_ModelLoader = __esm({
42044
42061
  "components/game/molecules/three/components/ModelLoader.tsx"() {
42045
42062
  "use client";
42046
- log11 = logger.createLogger("almadar:ui:game:model-loader");
42063
+ log12 = logger.createLogger("almadar:ui:game:model-loader");
42047
42064
  }
42048
42065
  });
42049
42066
 
@@ -42169,6 +42186,8 @@ var init_GameCanvas3D2 = __esm({
42169
42186
  attackTargets = [],
42170
42187
  selectedTileIds = [],
42171
42188
  selectedUnitId = null,
42189
+ unitScale = 1,
42190
+ scale = 0.45,
42172
42191
  children
42173
42192
  }, ref) => {
42174
42193
  const containerRef = React82.useRef(null);
@@ -42385,12 +42404,18 @@ var init_GameCanvas3D2 = __esm({
42385
42404
  },
42386
42405
  [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
42387
42406
  );
42407
+ const UNIT_BASE_MODEL_SCALE = 0.5;
42408
+ const UNIT_BASE_BILLBOARD_HEIGHT = 1.2;
42409
+ const UNIT_BASE_PRIMITIVE_RADIUS = 0.3;
42388
42410
  const DefaultUnitRenderer = React82.useCallback(
42389
42411
  ({ unit, position }) => {
42390
42412
  const isSelected = selectedUnitId === unit.id;
42391
42413
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
42392
42414
  const hasAtlas = unitAtlasUrl(unit) !== null;
42393
42415
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
42416
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
42417
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
42418
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
42394
42419
  return /* @__PURE__ */ jsxRuntime.jsxs(
42395
42420
  "group",
42396
42421
  {
@@ -42408,7 +42433,8 @@ var init_GameCanvas3D2 = __esm({
42408
42433
  UnitSpriteBillboard,
42409
42434
  {
42410
42435
  sheetUrl: initialFrame.sheetUrl,
42411
- resolveFrame: () => resolveUnitFrame(unit.id)
42436
+ resolveFrame: () => resolveUnitFrame(unit.id),
42437
+ height: billboardHeight
42412
42438
  }
42413
42439
  ) })
42414
42440
  ) : unit.modelUrl ? (
@@ -42417,22 +42443,22 @@ var init_GameCanvas3D2 = __esm({
42417
42443
  ModelLoader,
42418
42444
  {
42419
42445
  url: unit.modelUrl,
42420
- scale: 0.5,
42446
+ scale: modelScale,
42421
42447
  fallbackGeometry: "box",
42422
42448
  castShadow: true
42423
42449
  }
42424
42450
  )
42425
42451
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
42426
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
42427
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
42452
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius, 0], children: [
42453
+ /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [primitiveRadius, primitiveRadius, primitiveRadius * 0.33, 8] }),
42428
42454
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
42429
42455
  ] }),
42430
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
42431
- /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
42456
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius * 2, 0], children: [
42457
+ /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [primitiveRadius * 0.67, primitiveRadius * 1.33, 4, 8] }),
42432
42458
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
42433
42459
  ] }),
42434
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
42435
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
42460
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius * 3, 0], children: [
42461
+ /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [primitiveRadius * 0.4, 8, 8] }),
42436
42462
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
42437
42463
  ] })
42438
42464
  ] }),
@@ -42465,7 +42491,7 @@ var init_GameCanvas3D2 = __esm({
42465
42491
  }
42466
42492
  );
42467
42493
  },
42468
- [selectedUnitId, handleUnitClick, resolveUnitFrame]
42494
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
42469
42495
  );
42470
42496
  const DefaultFeatureRenderer = React82.useCallback(
42471
42497
  ({
@@ -42608,33 +42634,35 @@ var init_GameCanvas3D2 = __esm({
42608
42634
  fadeStrength: 1
42609
42635
  }
42610
42636
  ),
42611
- tiles.map((tile, index) => {
42612
- const position = gridToWorld(
42613
- tile.x,
42614
- tile.z ?? tile.y ?? 0,
42615
- tile.elevation ?? 0
42616
- );
42617
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
42618
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
42619
- }),
42620
- features.map((feature, index) => {
42621
- const position = gridToWorld(
42622
- feature.x,
42623
- feature.z ?? feature.y ?? 0,
42624
- (feature.elevation ?? 0) + 0.5
42625
- );
42626
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
42627
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
42628
- }),
42629
- units.map((unit) => {
42630
- const position = gridToWorld(
42631
- unit.x ?? 0,
42632
- unit.z ?? unit.y ?? 0,
42633
- (unit.elevation ?? 0) + 0.5
42634
- );
42635
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
42636
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
42637
- }),
42637
+ /* @__PURE__ */ jsxRuntime.jsxs("group", { scale, children: [
42638
+ tiles.map((tile, index) => {
42639
+ const position = gridToWorld(
42640
+ tile.x,
42641
+ tile.z ?? tile.y ?? 0,
42642
+ tile.elevation ?? 0
42643
+ );
42644
+ const Renderer = CustomTileRenderer || DefaultTileRenderer;
42645
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
42646
+ }),
42647
+ features.map((feature, index) => {
42648
+ const position = gridToWorld(
42649
+ feature.x,
42650
+ feature.z ?? feature.y ?? 0,
42651
+ (feature.elevation ?? 0) + 0.5
42652
+ );
42653
+ const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
42654
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
42655
+ }),
42656
+ units.map((unit) => {
42657
+ const position = gridToWorld(
42658
+ unit.x ?? 0,
42659
+ unit.z ?? unit.y ?? 0,
42660
+ (unit.elevation ?? 0) + 0.5
42661
+ );
42662
+ const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
42663
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
42664
+ })
42665
+ ] }),
42638
42666
  children,
42639
42667
  /* @__PURE__ */ jsxRuntime.jsx(
42640
42668
  drei.OrbitControls,
@@ -42677,6 +42705,8 @@ function GameBoard3D({
42677
42705
  features = [],
42678
42706
  cameraMode = "perspective",
42679
42707
  backgroundColor = "#2a1a1a",
42708
+ unitScale = 1,
42709
+ scale = 0.45,
42680
42710
  tileClickEvent,
42681
42711
  unitClickEvent,
42682
42712
  attackEvent,
@@ -42777,6 +42807,8 @@ function GameBoard3D({
42777
42807
  selectedUnitId,
42778
42808
  validMoves,
42779
42809
  attackTargets,
42810
+ unitScale,
42811
+ scale,
42780
42812
  className: "game-board-3d__canvas w-full min-h-[85vh]"
42781
42813
  }
42782
42814
  ),
@@ -44762,6 +44794,8 @@ function RoguelikeBoard({
44762
44794
  assetManifest: propAssetManifest,
44763
44795
  scale = 0.45,
44764
44796
  unitScale = 1,
44797
+ spriteHeightRatio = 1.5,
44798
+ spriteMaxWidthRatio = 0.6,
44765
44799
  moveEvent,
44766
44800
  playAgainEvent,
44767
44801
  gameEndEvent,
@@ -44909,7 +44943,9 @@ function RoguelikeBoard({
44909
44943
  scale,
44910
44944
  assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
44911
44945
  assetManifest: propAssetManifest,
44912
- unitScale
44946
+ unitScale,
44947
+ spriteHeightRatio,
44948
+ spriteMaxWidthRatio
44913
44949
  }
44914
44950
  ) }),
44915
44951
  !isGameOver && /* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
@@ -46329,7 +46365,7 @@ function getAllEvents(traits2) {
46329
46365
  function EventDispatcherTab({ traits: traits2, schema }) {
46330
46366
  const eventBus = useEventBus();
46331
46367
  const { t } = hooks.useTranslate();
46332
- const [log13, setLog] = React82__namespace.useState([]);
46368
+ const [log14, setLog] = React82__namespace.useState([]);
46333
46369
  const prevStatesRef = React82__namespace.useRef(/* @__PURE__ */ new Map());
46334
46370
  React82__namespace.useEffect(() => {
46335
46371
  for (const trait of traits2) {
@@ -46393,9 +46429,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
46393
46429
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
46394
46430
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
46395
46431
  ] }),
46396
- log13.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
46432
+ log14.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
46397
46433
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
46398
- /* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log13.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
46434
+ /* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log14.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
46399
46435
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-400", children: entry.traitName }),
46400
46436
  " ",
46401
46437
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500", children: entry.from }),
@@ -49262,6 +49298,9 @@ function TowerDefenseBoard({
49262
49298
  waveActive: propWaveActive,
49263
49299
  towerCost = 25,
49264
49300
  scale = 0.45,
49301
+ unitScale = 1,
49302
+ spriteHeightRatio = 1.5,
49303
+ spriteMaxWidthRatio = 0.6,
49265
49304
  placeTowerEvent,
49266
49305
  startWaveEvent,
49267
49306
  playAgainEvent,
@@ -49369,7 +49408,10 @@ function TowerDefenseBoard({
49369
49408
  onTileClick: handleTileClick,
49370
49409
  onTileHover: (x, y) => setHoveredTile({ x, y }),
49371
49410
  onTileLeave: () => setHoveredTile(null),
49372
- scale
49411
+ scale,
49412
+ unitScale,
49413
+ spriteHeightRatio,
49414
+ spriteMaxWidthRatio
49373
49415
  }
49374
49416
  ),
49375
49417
  hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
@@ -49705,6 +49747,8 @@ function WorldMapBoard({
49705
49747
  isLoading,
49706
49748
  scale = 0.4,
49707
49749
  unitScale = 2.5,
49750
+ spriteHeightRatio = 1.5,
49751
+ spriteMaxWidthRatio = 0.6,
49708
49752
  allowMoveAllHeroes = false,
49709
49753
  isInRange = defaultIsInRange,
49710
49754
  heroSelectEvent,
@@ -49942,6 +49986,8 @@ function WorldMapBoard({
49942
49986
  effectSpriteUrls,
49943
49987
  resolveUnitFrame,
49944
49988
  unitScale,
49989
+ spriteHeightRatio,
49990
+ spriteMaxWidthRatio,
49945
49991
  diamondTopY,
49946
49992
  enableCamera
49947
49993
  }
@@ -51260,7 +51306,7 @@ function isPatternConfig(value) {
51260
51306
  if (value instanceof Date) return false;
51261
51307
  if (typeof value === "function") return false;
51262
51308
  const record = value;
51263
- return "type" in record && typeof record.type === "string";
51309
+ return "type" in record && typeof record.type === "string" && isKnownPattern(record.type);
51264
51310
  }
51265
51311
  function isPlainConfigObject(value) {
51266
51312
  if (React82__namespace.default.isValidElement(value)) return false;
@@ -51854,7 +51900,7 @@ init_UISlotRenderer();
51854
51900
  // providers/VerificationProvider.tsx
51855
51901
  init_useEventBus();
51856
51902
  init_verificationRegistry();
51857
- var log12 = logger.createLogger("almadar:verify");
51903
+ var log13 = logger.createLogger("almadar:verify");
51858
51904
  var DISPATCH_SUFFIX = ":DISPATCH";
51859
51905
  var SUCCESS_SUFFIX = ":SUCCESS";
51860
51906
  var ERROR_SUFFIX = ":ERROR";
@@ -51901,7 +51947,7 @@ function VerificationProvider({
51901
51947
  const verificationProviderLifecycleListener = (evt) => {
51902
51948
  const parsed = parseLifecycleEvent(evt.type);
51903
51949
  if (!parsed) return;
51904
- log12.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
51950
+ log13.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
51905
51951
  const payload = evt.payload ?? {};
51906
51952
  if (parsed.kind === "dispatch") {
51907
51953
  const key = `${parsed.traitName}:${String(payload["event"] ?? "")}`;
@@ -51956,7 +52002,7 @@ function VerificationProvider({
51956
52002
  },
51957
52003
  timestamp: Date.now()
51958
52004
  });
51959
- log12.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
52005
+ log13.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
51960
52006
  } else if (parsed.kind === "error" && parsed.event) {
51961
52007
  const key = `${parsed.traitName}:${parsed.event}`;
51962
52008
  const pending = pendingRef.current.get(key);
@@ -51986,7 +52032,7 @@ function VerificationProvider({
51986
52032
  },
51987
52033
  timestamp: Date.now()
51988
52034
  });
51989
- log12.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
52035
+ log13.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
51990
52036
  }
51991
52037
  };
51992
52038
  Object.defineProperty(verificationProviderLifecycleListener, "name", {