@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.
@@ -12207,6 +12207,16 @@ var init_Skeleton = __esm({
12207
12207
  Skeleton.displayName = "Skeleton";
12208
12208
  }
12209
12209
  });
12210
+ function isKnownPattern(type) {
12211
+ return type in componentMapping;
12212
+ }
12213
+ var componentMapping;
12214
+ var init_pattern_resolver = __esm({
12215
+ "renderer/pattern-resolver.ts"() {
12216
+ logger.createLogger("almadar:ui:pattern-resolver");
12217
+ componentMapping = {};
12218
+ }
12219
+ });
12210
12220
 
12211
12221
  // renderer/slot-definitions.ts
12212
12222
  function isPortalSlot(slot) {
@@ -12315,6 +12325,7 @@ var init_navigation = __esm({
12315
12325
  // renderer/index.ts
12316
12326
  var init_renderer = __esm({
12317
12327
  "renderer/index.ts"() {
12328
+ init_pattern_resolver();
12318
12329
  init_slot_definitions();
12319
12330
  }
12320
12331
  });
@@ -14018,7 +14029,7 @@ function recordTransition(trace) {
14018
14029
  ...trace,
14019
14030
  id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
14020
14031
  };
14021
- log4.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
14032
+ log5.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
14022
14033
  getState().transitions.push(entry);
14023
14034
  if (getState().transitions.length > MAX_TRANSITIONS) {
14024
14035
  getState().transitions.shift();
@@ -14117,7 +14128,7 @@ function getTraitSnapshots() {
14117
14128
  try {
14118
14129
  snapshots.push(getter());
14119
14130
  } catch (err) {
14120
- log4.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
14131
+ log5.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
14121
14132
  }
14122
14133
  }
14123
14134
  return snapshots;
@@ -14216,10 +14227,10 @@ function updateAssetStatus(url, status) {
14216
14227
  window.__orbitalVerification.assetStatus[url] = status;
14217
14228
  }
14218
14229
  }
14219
- var log4, MAX_TRANSITIONS;
14230
+ var log5, MAX_TRANSITIONS;
14220
14231
  var init_verificationRegistry = __esm({
14221
14232
  "lib/verificationRegistry.ts"() {
14222
- log4 = logger.createLogger("almadar:bridge");
14233
+ log5 = logger.createLogger("almadar:bridge");
14223
14234
  MAX_TRANSITIONS = 500;
14224
14235
  exposeOnWindow();
14225
14236
  }
@@ -14570,6 +14581,8 @@ function IsometricCanvas({
14570
14581
  showMinimap = true,
14571
14582
  enableCamera = true,
14572
14583
  unitScale = 1,
14584
+ spriteHeightRatio = 1.5,
14585
+ spriteMaxWidthRatio = 0.6,
14573
14586
  // Asset resolution
14574
14587
  getTerrainSprite,
14575
14588
  getFeatureSprite,
@@ -14960,8 +14973,8 @@ function IsometricCanvas({
14960
14973
  const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
14961
14974
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
14962
14975
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
14963
- const unitDrawH = scaledFloorHeight * 1.5 * unitScale;
14964
- const maxUnitW = scaledTileWidth * 0.6 * unitScale;
14976
+ const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
14977
+ const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
14965
14978
  const ar = img ? img.naturalWidth / img.naturalHeight : 0.5;
14966
14979
  let drawH = unitDrawH;
14967
14980
  let drawW = unitDrawH * ar;
@@ -15345,6 +15358,8 @@ function BattleBoard({
15345
15358
  assetManifest: propAssetManifest,
15346
15359
  scale = 0.45,
15347
15360
  unitScale = 1,
15361
+ spriteHeightRatio = 1.5,
15362
+ spriteMaxWidthRatio = 0.6,
15348
15363
  header,
15349
15364
  sidebar,
15350
15365
  actions,
@@ -15635,7 +15650,9 @@ function BattleBoard({
15635
15650
  hasActiveEffects: hasActiveEffects2,
15636
15651
  effectSpriteUrls,
15637
15652
  resolveUnitFrame,
15638
- unitScale
15653
+ unitScale,
15654
+ spriteHeightRatio,
15655
+ spriteMaxWidthRatio
15639
15656
  }
15640
15657
  ),
15641
15658
  overlay && overlay(ctx)
@@ -16115,7 +16132,7 @@ function generateDiff(oldVal, newVal) {
16115
16132
  }
16116
16133
  return diff;
16117
16134
  }
16118
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log5, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
16135
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log6, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
16119
16136
  var init_CodeBlock = __esm({
16120
16137
  "components/core/molecules/markdown/CodeBlock.tsx"() {
16121
16138
  init_cn();
@@ -16198,7 +16215,7 @@ var init_CodeBlock = __esm({
16198
16215
  "lolo-op-async": { color: syntax.ORB_COLORS.dark.async }
16199
16216
  };
16200
16217
  loloStyle = { ...dark__default.default, ...loloStyleOverrides };
16201
- log5 = logger.createLogger("almadar:ui:markdown-code");
16218
+ log6 = logger.createLogger("almadar:ui:markdown-code");
16202
16219
  CODE_LANGUAGES = [
16203
16220
  "text",
16204
16221
  "json",
@@ -16462,7 +16479,7 @@ var init_CodeBlock = __esm({
16462
16479
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
16463
16480
  setTimeout(() => setCopied(false), 2e3);
16464
16481
  } catch (err) {
16465
- log5.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
16482
+ log6.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
16466
16483
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
16467
16484
  }
16468
16485
  };
@@ -20343,14 +20360,14 @@ function useSafeEventBus2() {
20343
20360
  } };
20344
20361
  }
20345
20362
  }
20346
- var log6, lookStyles4, ButtonGroup;
20363
+ var log7, lookStyles4, ButtonGroup;
20347
20364
  var init_ButtonGroup = __esm({
20348
20365
  "components/core/molecules/ButtonGroup.tsx"() {
20349
20366
  "use client";
20350
20367
  init_cn();
20351
20368
  init_atoms2();
20352
20369
  init_useEventBus();
20353
- log6 = logger.createLogger("almadar:ui:button-group");
20370
+ log7 = logger.createLogger("almadar:ui:button-group");
20354
20371
  lookStyles4 = {
20355
20372
  "right-aligned-buttons": "",
20356
20373
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -20431,7 +20448,7 @@ var init_ButtonGroup = __esm({
20431
20448
  {
20432
20449
  variant: "ghost",
20433
20450
  onClick: () => {
20434
- log6.debug("Filter clicked", { field: filter.field });
20451
+ log7.debug("Filter clicked", { field: filter.field });
20435
20452
  },
20436
20453
  children: filter.label
20437
20454
  },
@@ -28093,9 +28110,9 @@ function debug(...args) {
28093
28110
  const [first, ...rest] = args;
28094
28111
  const message = typeof first === "string" ? first : "<debug>";
28095
28112
  if (rest.length === 0 && typeof first === "string") {
28096
- log7.debug(message);
28113
+ log8.debug(message);
28097
28114
  } else {
28098
- log7.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28115
+ log8.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28099
28116
  }
28100
28117
  }
28101
28118
  function debugGroup(label) {
@@ -28123,11 +28140,11 @@ function toLogMetaValue(v) {
28123
28140
  }
28124
28141
  return String(v);
28125
28142
  }
28126
- var NAMESPACE, log7;
28143
+ var NAMESPACE, log8;
28127
28144
  var init_debug = __esm({
28128
28145
  "lib/debug.ts"() {
28129
28146
  NAMESPACE = "almadar:ui:debug";
28130
- log7 = logger.createLogger(NAMESPACE);
28147
+ log8 = logger.createLogger(NAMESPACE);
28131
28148
  logger.createLogger("almadar:ui:debug:input");
28132
28149
  logger.createLogger("almadar:ui:debug:collision");
28133
28150
  logger.createLogger("almadar:ui:debug:physics");
@@ -44009,11 +44026,11 @@ var init_Canvas3DErrorBoundary = __esm({
44009
44026
  "components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
44010
44027
  }
44011
44028
  });
44012
- var log8, Canvas3DErrorBoundary;
44029
+ var log9, Canvas3DErrorBoundary;
44013
44030
  var init_Canvas3DErrorBoundary2 = __esm({
44014
44031
  "components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
44015
44032
  init_Canvas3DErrorBoundary();
44016
- log8 = logger.createLogger("almadar:ui:game:canvas3d:error-boundary");
44033
+ log9 = logger.createLogger("almadar:ui:game:canvas3d:error-boundary");
44017
44034
  Canvas3DErrorBoundary = class extends React90.Component {
44018
44035
  constructor(props) {
44019
44036
  super(props);
@@ -44041,8 +44058,8 @@ var init_Canvas3DErrorBoundary2 = __esm({
44041
44058
  componentDidCatch(error, errorInfo) {
44042
44059
  this.setState({ errorInfo });
44043
44060
  this.props.onError?.(error, errorInfo);
44044
- log8.error("Error caught", { error });
44045
- log8.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
44061
+ log9.error("Error caught", { error });
44062
+ log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
44046
44063
  }
44047
44064
  render() {
44048
44065
  if (this.state.hasError) {
@@ -44105,7 +44122,7 @@ function useGLTFModel(url, resourceBasePath) {
44105
44122
  setState({ model: null, isLoading: false, error: null });
44106
44123
  return;
44107
44124
  }
44108
- log9.debug("Loading", { url });
44125
+ log10.debug("Loading", { url });
44109
44126
  setState((prev) => ({ ...prev, isLoading: true, error: null }));
44110
44127
  const assetRoot = resourceBasePath || detectAssetRoot2(url);
44111
44128
  const loader = new GLTFLoader.GLTFLoader();
@@ -44113,7 +44130,7 @@ function useGLTFModel(url, resourceBasePath) {
44113
44130
  loader.load(
44114
44131
  url,
44115
44132
  (gltf) => {
44116
- log9.debug("Loaded", { url });
44133
+ log10.debug("Loaded", { url });
44117
44134
  setState({
44118
44135
  model: gltf.scene,
44119
44136
  isLoading: false,
@@ -44122,7 +44139,7 @@ function useGLTFModel(url, resourceBasePath) {
44122
44139
  },
44123
44140
  void 0,
44124
44141
  (err) => {
44125
- log9.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
44142
+ log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
44126
44143
  setState({
44127
44144
  model: null,
44128
44145
  isLoading: false,
@@ -44238,11 +44255,11 @@ function ModelLoader({
44238
44255
  }
44239
44256
  );
44240
44257
  }
44241
- var log9;
44258
+ var log10;
44242
44259
  var init_ModelLoader = __esm({
44243
44260
  "components/game/molecules/three/components/ModelLoader.tsx"() {
44244
44261
  "use client";
44245
- log9 = logger.createLogger("almadar:ui:game:model-loader");
44262
+ log10 = logger.createLogger("almadar:ui:game:model-loader");
44246
44263
  }
44247
44264
  });
44248
44265
 
@@ -44368,6 +44385,8 @@ var init_GameCanvas3D2 = __esm({
44368
44385
  attackTargets = [],
44369
44386
  selectedTileIds = [],
44370
44387
  selectedUnitId = null,
44388
+ unitScale = 1,
44389
+ scale = 0.45,
44371
44390
  children
44372
44391
  }, ref) => {
44373
44392
  const containerRef = React90.useRef(null);
@@ -44584,12 +44603,18 @@ var init_GameCanvas3D2 = __esm({
44584
44603
  },
44585
44604
  [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
44586
44605
  );
44606
+ const UNIT_BASE_MODEL_SCALE = 0.5;
44607
+ const UNIT_BASE_BILLBOARD_HEIGHT = 1.2;
44608
+ const UNIT_BASE_PRIMITIVE_RADIUS = 0.3;
44587
44609
  const DefaultUnitRenderer = React90.useCallback(
44588
44610
  ({ unit, position }) => {
44589
44611
  const isSelected = selectedUnitId === unit.id;
44590
44612
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
44591
44613
  const hasAtlas = unitAtlasUrl(unit) !== null;
44592
44614
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
44615
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
44616
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
44617
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
44593
44618
  return /* @__PURE__ */ jsxRuntime.jsxs(
44594
44619
  "group",
44595
44620
  {
@@ -44607,7 +44632,8 @@ var init_GameCanvas3D2 = __esm({
44607
44632
  UnitSpriteBillboard,
44608
44633
  {
44609
44634
  sheetUrl: initialFrame.sheetUrl,
44610
- resolveFrame: () => resolveUnitFrame(unit.id)
44635
+ resolveFrame: () => resolveUnitFrame(unit.id),
44636
+ height: billboardHeight
44611
44637
  }
44612
44638
  ) })
44613
44639
  ) : unit.modelUrl ? (
@@ -44616,22 +44642,22 @@ var init_GameCanvas3D2 = __esm({
44616
44642
  ModelLoader,
44617
44643
  {
44618
44644
  url: unit.modelUrl,
44619
- scale: 0.5,
44645
+ scale: modelScale,
44620
44646
  fallbackGeometry: "box",
44621
44647
  castShadow: true
44622
44648
  }
44623
44649
  )
44624
44650
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
44625
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
44626
- /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
44651
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius, 0], children: [
44652
+ /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [primitiveRadius, primitiveRadius, primitiveRadius * 0.33, 8] }),
44627
44653
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
44628
44654
  ] }),
44629
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
44630
- /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
44655
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius * 2, 0], children: [
44656
+ /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [primitiveRadius * 0.67, primitiveRadius * 1.33, 4, 8] }),
44631
44657
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
44632
44658
  ] }),
44633
- /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
44634
- /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
44659
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, primitiveRadius * 3, 0], children: [
44660
+ /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [primitiveRadius * 0.4, 8, 8] }),
44635
44661
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
44636
44662
  ] })
44637
44663
  ] }),
@@ -44664,7 +44690,7 @@ var init_GameCanvas3D2 = __esm({
44664
44690
  }
44665
44691
  );
44666
44692
  },
44667
- [selectedUnitId, handleUnitClick, resolveUnitFrame]
44693
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
44668
44694
  );
44669
44695
  const DefaultFeatureRenderer = React90.useCallback(
44670
44696
  ({
@@ -44807,33 +44833,35 @@ var init_GameCanvas3D2 = __esm({
44807
44833
  fadeStrength: 1
44808
44834
  }
44809
44835
  ),
44810
- tiles.map((tile, index) => {
44811
- const position = gridToWorld(
44812
- tile.x,
44813
- tile.z ?? tile.y ?? 0,
44814
- tile.elevation ?? 0
44815
- );
44816
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
44817
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
44818
- }),
44819
- features.map((feature, index) => {
44820
- const position = gridToWorld(
44821
- feature.x,
44822
- feature.z ?? feature.y ?? 0,
44823
- (feature.elevation ?? 0) + 0.5
44824
- );
44825
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
44826
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
44827
- }),
44828
- units.map((unit) => {
44829
- const position = gridToWorld(
44830
- unit.x ?? 0,
44831
- unit.z ?? unit.y ?? 0,
44832
- (unit.elevation ?? 0) + 0.5
44833
- );
44834
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
44835
- return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
44836
- }),
44836
+ /* @__PURE__ */ jsxRuntime.jsxs("group", { scale, children: [
44837
+ tiles.map((tile, index) => {
44838
+ const position = gridToWorld(
44839
+ tile.x,
44840
+ tile.z ?? tile.y ?? 0,
44841
+ tile.elevation ?? 0
44842
+ );
44843
+ const Renderer = CustomTileRenderer || DefaultTileRenderer;
44844
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
44845
+ }),
44846
+ features.map((feature, index) => {
44847
+ const position = gridToWorld(
44848
+ feature.x,
44849
+ feature.z ?? feature.y ?? 0,
44850
+ (feature.elevation ?? 0) + 0.5
44851
+ );
44852
+ const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
44853
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
44854
+ }),
44855
+ units.map((unit) => {
44856
+ const position = gridToWorld(
44857
+ unit.x ?? 0,
44858
+ unit.z ?? unit.y ?? 0,
44859
+ (unit.elevation ?? 0) + 0.5
44860
+ );
44861
+ const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
44862
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
44863
+ })
44864
+ ] }),
44837
44865
  children,
44838
44866
  /* @__PURE__ */ jsxRuntime.jsx(
44839
44867
  drei.OrbitControls,
@@ -44876,6 +44904,8 @@ function GameBoard3D({
44876
44904
  features = [],
44877
44905
  cameraMode = "perspective",
44878
44906
  backgroundColor = "#2a1a1a",
44907
+ unitScale = 1,
44908
+ scale = 0.45,
44879
44909
  tileClickEvent,
44880
44910
  unitClickEvent,
44881
44911
  attackEvent,
@@ -44976,6 +45006,8 @@ function GameBoard3D({
44976
45006
  selectedUnitId,
44977
45007
  validMoves,
44978
45008
  attackTargets,
45009
+ unitScale,
45010
+ scale,
44979
45011
  className: "game-board-3d__canvas w-full min-h-[85vh]"
44980
45012
  }
44981
45013
  ),
@@ -46961,6 +46993,8 @@ function RoguelikeBoard({
46961
46993
  assetManifest: propAssetManifest,
46962
46994
  scale = 0.45,
46963
46995
  unitScale = 1,
46996
+ spriteHeightRatio = 1.5,
46997
+ spriteMaxWidthRatio = 0.6,
46964
46998
  moveEvent,
46965
46999
  playAgainEvent,
46966
47000
  gameEndEvent,
@@ -47108,7 +47142,9 @@ function RoguelikeBoard({
47108
47142
  scale,
47109
47143
  assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
47110
47144
  assetManifest: propAssetManifest,
47111
- unitScale
47145
+ unitScale,
47146
+ spriteHeightRatio,
47147
+ spriteMaxWidthRatio
47112
47148
  }
47113
47149
  ) }),
47114
47150
  !isGameOver && /* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
@@ -48547,7 +48583,7 @@ function getAllEvents(traits2) {
48547
48583
  function EventDispatcherTab({ traits: traits2, schema }) {
48548
48584
  const eventBus = useEventBus();
48549
48585
  const { t } = hooks.useTranslate();
48550
- const [log15, setLog] = React90__namespace.useState([]);
48586
+ const [log16, setLog] = React90__namespace.useState([]);
48551
48587
  const prevStatesRef = React90__namespace.useRef(/* @__PURE__ */ new Map());
48552
48588
  React90__namespace.useEffect(() => {
48553
48589
  for (const trait of traits2) {
@@ -48611,9 +48647,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
48611
48647
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
48612
48648
  /* @__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)) })
48613
48649
  ] }),
48614
- log15.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
48650
+ log16.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
48615
48651
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
48616
- /* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log15.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
48652
+ /* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log16.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
48617
48653
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-400", children: entry.traitName }),
48618
48654
  " ",
48619
48655
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500", children: entry.from }),
@@ -51480,6 +51516,9 @@ function TowerDefenseBoard({
51480
51516
  waveActive: propWaveActive,
51481
51517
  towerCost = 25,
51482
51518
  scale = 0.45,
51519
+ unitScale = 1,
51520
+ spriteHeightRatio = 1.5,
51521
+ spriteMaxWidthRatio = 0.6,
51483
51522
  placeTowerEvent,
51484
51523
  startWaveEvent,
51485
51524
  playAgainEvent,
@@ -51587,7 +51626,10 @@ function TowerDefenseBoard({
51587
51626
  onTileClick: handleTileClick,
51588
51627
  onTileHover: (x, y) => setHoveredTile({ x, y }),
51589
51628
  onTileLeave: () => setHoveredTile(null),
51590
- scale
51629
+ scale,
51630
+ unitScale,
51631
+ spriteHeightRatio,
51632
+ spriteMaxWidthRatio
51591
51633
  }
51592
51634
  ),
51593
51635
  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)` }) })
@@ -51923,6 +51965,8 @@ function WorldMapBoard({
51923
51965
  isLoading,
51924
51966
  scale = 0.4,
51925
51967
  unitScale = 2.5,
51968
+ spriteHeightRatio = 1.5,
51969
+ spriteMaxWidthRatio = 0.6,
51926
51970
  allowMoveAllHeroes = false,
51927
51971
  isInRange = defaultIsInRange,
51928
51972
  heroSelectEvent,
@@ -52160,6 +52204,8 @@ function WorldMapBoard({
52160
52204
  effectSpriteUrls,
52161
52205
  resolveUnitFrame,
52162
52206
  unitScale,
52207
+ spriteHeightRatio,
52208
+ spriteMaxWidthRatio,
52163
52209
  diamondTopY,
52164
52210
  enableCamera
52165
52211
  }
@@ -53478,7 +53524,7 @@ function isPatternConfig(value) {
53478
53524
  if (value instanceof Date) return false;
53479
53525
  if (typeof value === "function") return false;
53480
53526
  const record = value;
53481
- return "type" in record && typeof record.type === "string";
53527
+ return "type" in record && typeof record.type === "string" && isKnownPattern(record.type);
53482
53528
  }
53483
53529
  function isPlainConfigObject(value) {
53484
53530
  if (React90__namespace.default.isValidElement(value)) return false;
@@ -57390,7 +57436,7 @@ function convertObjectProps(props) {
57390
57436
  function convertFnFormLambdasInProps(props) {
57391
57437
  return convertObjectProps(props);
57392
57438
  }
57393
- var log10 = logger.createLogger("almadar:ui:effects:client-handlers");
57439
+ var log11 = logger.createLogger("almadar:ui:effects:client-handlers");
57394
57440
  function createClientEffectHandlers(options) {
57395
57441
  const { eventBus, slotSetter, navigate, notify, callService, liveEntity } = options;
57396
57442
  return {
@@ -57399,11 +57445,11 @@ function createClientEffectHandlers(options) {
57399
57445
  eventBus.emit(prefixedEvent, payload);
57400
57446
  },
57401
57447
  persist: async () => {
57402
- log10.warn("persist is server-side only, ignored on client");
57448
+ log11.warn("persist is server-side only, ignored on client");
57403
57449
  },
57404
57450
  set: (_entityId, field, value) => {
57405
57451
  if (!liveEntity) {
57406
- log10.warn("set is server-side only, ignored on client (no live entity)");
57452
+ log11.warn("set is server-side only, ignored on client (no live entity)");
57407
57453
  return;
57408
57454
  }
57409
57455
  liveEntity[field] = value;
@@ -57435,10 +57481,10 @@ function createClientEffectHandlers(options) {
57435
57481
  slotSetter.addPattern(slot, pattern, props);
57436
57482
  },
57437
57483
  navigate: navigate ?? ((path) => {
57438
- log10.warn("No navigate handler, ignoring", { path });
57484
+ log11.warn("No navigate handler, ignoring", { path });
57439
57485
  }),
57440
57486
  notify: notify ?? ((msg, type) => {
57441
- log10.debug("notify", { type, message: msg });
57487
+ log11.debug("notify", { type, message: msg });
57442
57488
  })
57443
57489
  };
57444
57490
  }
@@ -57670,7 +57716,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57670
57716
  };
57671
57717
  }, [traitBindings]);
57672
57718
  const executeTransitionEffects = React90.useCallback(async (params) => {
57673
- const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log15 } = params;
57719
+ const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log16 } = params;
57674
57720
  const traitName = binding.trait.name;
57675
57721
  const linkedEntity = binding.linkedEntity || "";
57676
57722
  const entityId = payload?.entityId;
@@ -57758,7 +57804,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57758
57804
  ...handlers,
57759
57805
  set: async (targetId, field, value) => {
57760
57806
  if (baseSet) await baseSet(targetId, field, value);
57761
- log15.debug("set:write", {
57807
+ log16.debug("set:write", {
57762
57808
  traitName,
57763
57809
  field,
57764
57810
  value: JSON.stringify(value),
@@ -57798,7 +57844,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57798
57844
  const executor = new runtime.EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
57799
57845
  try {
57800
57846
  await executor.executeAll(effects);
57801
- log15.debug("effects:executed", () => ({
57847
+ log16.debug("effects:executed", () => ({
57802
57848
  traitName,
57803
57849
  transition: `${previousState}->${newState}`,
57804
57850
  event: flushEvent,
@@ -57808,7 +57854,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57808
57854
  slotsTouched: Array.from(pendingSlots.keys()).join(",")
57809
57855
  }));
57810
57856
  for (const [slot, patterns] of pendingSlots) {
57811
- log15.debug("flush:slot", {
57857
+ log16.debug("flush:slot", {
57812
57858
  traitName,
57813
57859
  slot,
57814
57860
  patternCount: patterns.length,
@@ -57823,7 +57869,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57823
57869
  });
57824
57870
  }
57825
57871
  } catch (error) {
57826
- log15.error("effects:error", {
57872
+ log16.error("effects:error", {
57827
57873
  traitName,
57828
57874
  transition: `${previousState}->${newState}`,
57829
57875
  event: flushEvent,
@@ -57846,7 +57892,10 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
57846
57892
  if (binding.config) {
57847
57893
  guardCtx.config = binding.config;
57848
57894
  }
57849
- const passed = runtime.interpolateValue(tick.guard, runtime.createContextFromBindings(guardCtx));
57895
+ const passed = evaluator.evaluateGuard(
57896
+ tick.guard,
57897
+ runtime.createContextFromBindings(guardCtx)
57898
+ );
57850
57899
  if (!passed) {
57851
57900
  tickLog.debug("guard-blocked", { traitName, tick: tick.name, state: currentState });
57852
57901
  return;
@@ -58815,7 +58864,7 @@ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
58815
58864
  init_navigation();
58816
58865
  init_verificationRegistry();
58817
58866
  var PERF_NAMESPACE = "almadar:perf:canvas";
58818
- var log12 = logger.createLogger(PERF_NAMESPACE);
58867
+ var log13 = logger.createLogger(PERF_NAMESPACE);
58819
58868
  var RING_SIZE = 50;
58820
58869
  var ring = [];
58821
58870
  var writeIdx = 0;
@@ -58866,7 +58915,7 @@ function perfEnd(name, startToken, detail) {
58866
58915
  }
58867
58916
  }
58868
58917
  push({ name, durationMs, ts: endTs, detail });
58869
- log12.debug(name, () => ({ durationMs, ...detail ?? {} }));
58918
+ log13.debug(name, () => ({ durationMs, ...detail ?? {} }));
58870
58919
  }
58871
58920
  var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
58872
58921
  if (!isEnabled()) return;
@@ -58876,7 +58925,7 @@ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, com
58876
58925
  ts: commitTime,
58877
58926
  detail: { baseDuration }
58878
58927
  });
58879
- log12.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
58928
+ log13.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
58880
58929
  };
58881
58930
 
58882
58931
  // runtime/prepareSchemaForPreview.ts
@@ -59519,7 +59568,7 @@ init_useEventBus();
59519
59568
  // components/avl/molecules/useCanvasDnd.tsx
59520
59569
  init_useEventBus();
59521
59570
  init_useAlmadarDndCollision();
59522
- var log13 = logger.createLogger("almadar:ui:canvas-dnd");
59571
+ var log14 = logger.createLogger("almadar:ui:canvas-dnd");
59523
59572
  function useCanvasDraggable({
59524
59573
  id,
59525
59574
  payload,
@@ -59558,7 +59607,7 @@ function defaultEmit(eventBus, drop) {
59558
59607
  if (payload.kind === "pattern") {
59559
59608
  const patternType = payload.data.type;
59560
59609
  if (typeof patternType !== "string") {
59561
- log13.warn("default-emit:pattern:missing-type");
59610
+ log14.warn("default-emit:pattern:missing-type");
59562
59611
  return;
59563
59612
  }
59564
59613
  const out = { patternType, containerNode: target.containerNode };
@@ -59567,23 +59616,23 @@ function defaultEmit(eventBus, drop) {
59567
59616
  out.index = resolved.index;
59568
59617
  }
59569
59618
  eventBus.emit("UI:PATTERN_DROP", out);
59570
- log13.info("default-emit:pattern", { patternType, level: target.level });
59619
+ log14.info("default-emit:pattern", { patternType, level: target.level });
59571
59620
  return;
59572
59621
  }
59573
59622
  if (payload.kind === "behavior") {
59574
59623
  const behaviorName = payload.data.name;
59575
59624
  if (typeof behaviorName !== "string") {
59576
- log13.warn("default-emit:behavior:missing-name");
59625
+ log14.warn("default-emit:behavior:missing-name");
59577
59626
  return;
59578
59627
  }
59579
59628
  eventBus.emit("UI:BEHAVIOR_DROP", {
59580
59629
  behaviorName,
59581
59630
  containerNode: target.containerNode
59582
59631
  });
59583
- log13.info("default-emit:behavior", { behaviorName, level: target.level });
59632
+ log14.info("default-emit:behavior", { behaviorName, level: target.level });
59584
59633
  return;
59585
59634
  }
59586
- log13.debug("default-emit:unhandled-kind", { kind: payload.kind });
59635
+ log14.debug("default-emit:unhandled-kind", { kind: payload.kind });
59587
59636
  }
59588
59637
  function CanvasDndProvider({
59589
59638
  children,
@@ -59599,9 +59648,9 @@ function CanvasDndProvider({
59599
59648
  if (payload) {
59600
59649
  setActivePayload(payload);
59601
59650
  eventBus.emit("UI:DRAG_START", { kind: payload.kind, data: payload.data });
59602
- log13.info("dragStart", { id: e.active.id, kind: payload.kind });
59651
+ log14.info("dragStart", { id: e.active.id, kind: payload.kind });
59603
59652
  } else {
59604
- log13.warn("dragStart:missing-payload", { id: e.active.id });
59653
+ log14.warn("dragStart:missing-payload", { id: e.active.id });
59605
59654
  }
59606
59655
  }, [eventBus]);
59607
59656
  const handleDragEnd = React90__namespace.default.useCallback((e) => {
@@ -59611,7 +59660,7 @@ function CanvasDndProvider({
59611
59660
  const overData = e.over?.data.current;
59612
59661
  const target = overData?.target;
59613
59662
  const accepts = overData?.accepts;
59614
- log13.info("dragEnd", {
59663
+ log14.info("dragEnd", {
59615
59664
  activeId: e.active.id,
59616
59665
  overId: e.over?.id,
59617
59666
  hasPayload: !!payload,
@@ -59623,7 +59672,7 @@ function CanvasDndProvider({
59623
59672
  }
59624
59673
  if (!payload || !target) return;
59625
59674
  if (accepts && !accepts.includes(payload.kind)) {
59626
- log13.debug("dragEnd:rejected:kind", { kind: payload.kind, accepts: [...accepts] });
59675
+ log14.debug("dragEnd:rejected:kind", { kind: payload.kind, accepts: [...accepts] });
59627
59676
  return;
59628
59677
  }
59629
59678
  const activator = e.activatorEvent;
@@ -59635,7 +59684,7 @@ function CanvasDndProvider({
59635
59684
  }, [eventBus, onDrop]);
59636
59685
  const handleDragCancel = React90__namespace.default.useCallback(() => {
59637
59686
  setActivePayload(null);
59638
- log13.info("dragCancel");
59687
+ log14.info("dragCancel");
59639
59688
  }, []);
59640
59689
  return /* @__PURE__ */ jsxRuntime.jsxs(
59641
59690
  core$1.DndContext,
@@ -61450,7 +61499,7 @@ init_AvlTransitionLane();
61450
61499
  init_AvlSwimLane();
61451
61500
  init_types();
61452
61501
  init_avl_elk_layout();
61453
- var log14 = logger.createLogger("almadar:ui:avl:trait-scene");
61502
+ var log15 = logger.createLogger("almadar:ui:avl:trait-scene");
61454
61503
  var SWIM_GUTTER2 = 120;
61455
61504
  var CENTER_W2 = 360;
61456
61505
  var AvlTraitScene = ({
@@ -61463,7 +61512,7 @@ var AvlTraitScene = ({
61463
61512
  const dataKey = React90.useMemo(() => JSON.stringify(data), [data]);
61464
61513
  React90.useEffect(() => {
61465
61514
  computeTraitLayout(data).then(setLayout).catch((error) => {
61466
- log14.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
61515
+ log15.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
61467
61516
  });
61468
61517
  }, [dataKey]);
61469
61518
  if (!layout) {