@almadar/ui 5.97.0 → 5.98.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.
@@ -7737,11 +7737,14 @@ function recordTransition(trace) {
7737
7737
  }
7738
7738
  if (entry.event === "INIT") {
7739
7739
  const hasFetch = entry.effects.some((e) => e.type === "fetch");
7740
+ const hasEntitySeed = entry.effects.some(
7741
+ (e) => e.type === "set" && typeof e.args[0] === "string" && e.args[0].startsWith("@entity.")
7742
+ );
7740
7743
  const checkId = `init-fetch-${entry.traitName}`;
7741
- if (hasFetch) {
7744
+ if (hasFetch || hasEntitySeed) {
7742
7745
  registerCheck(
7743
7746
  checkId,
7744
- `INIT transition for "${entry.traitName}" has fetch effect`,
7747
+ `INIT transition for "${entry.traitName}" has fetch or entity-seed effect`,
7745
7748
  "pass"
7746
7749
  );
7747
7750
  } else {
@@ -8396,7 +8399,7 @@ var init_ScoreDisplay = __esm({
8396
8399
  }
8397
8400
  });
8398
8401
  function ControlButton({
8399
- assetUrl = DEFAULT_ASSET_URL,
8402
+ assetUrl,
8400
8403
  label,
8401
8404
  icon,
8402
8405
  size = "md",
@@ -8474,7 +8477,7 @@ function ControlButton({
8474
8477
  }
8475
8478
  );
8476
8479
  }
8477
- var sizeMap4, shapeMap, variantMap, DEFAULT_ASSET_URL;
8480
+ var sizeMap4, shapeMap, variantMap;
8478
8481
  var init_ControlButton = __esm({
8479
8482
  "components/game/2d/atoms/ControlButton.tsx"() {
8480
8483
  "use client";
@@ -8501,11 +8504,6 @@ var init_ControlButton = __esm({
8501
8504
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
8502
8505
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
8503
8506
  };
8504
- DEFAULT_ASSET_URL = {
8505
- url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
8506
- role: "ui",
8507
- category: "control"
8508
- };
8509
8507
  ControlButton.displayName = "ControlButton";
8510
8508
  }
8511
8509
  });
@@ -8594,7 +8592,7 @@ function isKnownState(s) {
8594
8592
  return s in DEFAULT_STATE_STYLES;
8595
8593
  }
8596
8594
  function StateIndicator({
8597
- assetUrl = DEFAULT_ASSET_URL2,
8595
+ assetUrl = DEFAULT_ASSET_URL,
8598
8596
  state = "idle",
8599
8597
  label,
8600
8598
  size = "md",
@@ -8624,14 +8622,14 @@ function StateIndicator({
8624
8622
  }
8625
8623
  );
8626
8624
  }
8627
- var DEFAULT_ASSET_URL2, DEFAULT_STATE_STYLES, DEFAULT_STYLE, STATIC_STATES, SIZE_CLASSES;
8625
+ var DEFAULT_ASSET_URL, DEFAULT_STATE_STYLES, DEFAULT_STYLE, STATIC_STATES, SIZE_CLASSES;
8628
8626
  var init_StateIndicator = __esm({
8629
8627
  "components/game/2d/atoms/StateIndicator.tsx"() {
8630
8628
  init_Box();
8631
8629
  init_Icon();
8632
8630
  init_cn();
8633
8631
  init_GameIcon();
8634
- DEFAULT_ASSET_URL2 = {
8632
+ DEFAULT_ASSET_URL = {
8635
8633
  url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
8636
8634
  role: "ui",
8637
8635
  category: "state"
@@ -8717,7 +8715,7 @@ var init_TimerDisplay = __esm({
8717
8715
  }
8718
8716
  });
8719
8717
  function ResourceCounter({
8720
- assetUrl = DEFAULT_ASSET_URL3,
8718
+ assetUrl = DEFAULT_ASSET_URL2,
8721
8719
  icon,
8722
8720
  label = "Gold",
8723
8721
  value = 250,
@@ -8750,7 +8748,7 @@ function ResourceCounter({
8750
8748
  }
8751
8749
  );
8752
8750
  }
8753
- var colorTokenClasses2, DEFAULT_ASSET_URL3, sizeMap6;
8751
+ var colorTokenClasses2, DEFAULT_ASSET_URL2, sizeMap6;
8754
8752
  var init_ResourceCounter = __esm({
8755
8753
  "components/game/2d/atoms/ResourceCounter.tsx"() {
8756
8754
  init_cn();
@@ -8766,7 +8764,7 @@ var init_ResourceCounter = __esm({
8766
8764
  error: "text-error",
8767
8765
  muted: "text-muted-foreground"
8768
8766
  };
8769
- DEFAULT_ASSET_URL3 = {
8767
+ DEFAULT_ASSET_URL2 = {
8770
8768
  url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
8771
8769
  role: "ui",
8772
8770
  category: "coin"
@@ -8780,7 +8778,7 @@ var init_ResourceCounter = __esm({
8780
8778
  }
8781
8779
  });
8782
8780
  function ItemSlot({
8783
- assetUrl = DEFAULT_ASSET_URL4,
8781
+ assetUrl = DEFAULT_ASSET_URL3,
8784
8782
  icon = "sword",
8785
8783
  label = "Iron Sword",
8786
8784
  quantity,
@@ -8835,7 +8833,7 @@ function ItemSlot({
8835
8833
  }
8836
8834
  );
8837
8835
  }
8838
- var sizeMap7, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL4, assetSizeMap;
8836
+ var sizeMap7, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL3, assetSizeMap;
8839
8837
  var init_ItemSlot = __esm({
8840
8838
  "components/game/2d/atoms/ItemSlot.tsx"() {
8841
8839
  "use client";
@@ -8865,7 +8863,7 @@ var init_ItemSlot = __esm({
8865
8863
  epic: "shadow-lg",
8866
8864
  legendary: "shadow-lg"
8867
8865
  };
8868
- DEFAULT_ASSET_URL4 = {
8866
+ DEFAULT_ASSET_URL3 = {
8869
8867
  url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
8870
8868
  role: "item",
8871
8869
  category: "item"
@@ -8879,7 +8877,7 @@ var init_ItemSlot = __esm({
8879
8877
  }
8880
8878
  });
8881
8879
  function TurnIndicator({
8882
- assetUrl = DEFAULT_ASSET_URL5,
8880
+ assetUrl = DEFAULT_ASSET_URL4,
8883
8881
  currentTurn = 1,
8884
8882
  maxTurns,
8885
8883
  activeTeam,
@@ -8919,7 +8917,7 @@ function TurnIndicator({
8919
8917
  }
8920
8918
  );
8921
8919
  }
8922
- var sizeMap8, DEFAULT_ASSET_URL5;
8920
+ var sizeMap8, DEFAULT_ASSET_URL4;
8923
8921
  var init_TurnIndicator = __esm({
8924
8922
  "components/game/2d/atoms/TurnIndicator.tsx"() {
8925
8923
  init_cn();
@@ -8931,7 +8929,7 @@ var init_TurnIndicator = __esm({
8931
8929
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
8932
8930
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
8933
8931
  };
8934
- DEFAULT_ASSET_URL5 = {
8932
+ DEFAULT_ASSET_URL4 = {
8935
8933
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
8936
8934
  role: "ui",
8937
8935
  category: "turn"
@@ -8951,7 +8949,7 @@ function getComboScale(combo) {
8951
8949
  return "";
8952
8950
  }
8953
8951
  function ComboCounter({
8954
- assetUrl = DEFAULT_ASSET_URL6,
8952
+ assetUrl = DEFAULT_ASSET_URL5,
8955
8953
  combo = 5,
8956
8954
  multiplier,
8957
8955
  streak,
@@ -8986,14 +8984,14 @@ function ComboCounter({
8986
8984
  }
8987
8985
  );
8988
8986
  }
8989
- var DEFAULT_ASSET_URL6, sizeMap9;
8987
+ var DEFAULT_ASSET_URL5, sizeMap9;
8990
8988
  var init_ComboCounter = __esm({
8991
8989
  "components/game/2d/atoms/ComboCounter.tsx"() {
8992
8990
  init_cn();
8993
8991
  init_Box();
8994
8992
  init_Typography();
8995
8993
  init_GameIcon();
8996
- DEFAULT_ASSET_URL6 = {
8994
+ DEFAULT_ASSET_URL5 = {
8997
8995
  url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
8998
8996
  role: "effect",
8999
8997
  category: "effect"
@@ -9007,7 +9005,7 @@ var init_ComboCounter = __esm({
9007
9005
  }
9008
9006
  });
9009
9007
  function WaypointMarker({
9010
- assetUrl = DEFAULT_ASSET_URL7,
9008
+ assetUrl = DEFAULT_ASSET_URL6,
9011
9009
  label,
9012
9010
  icon,
9013
9011
  active = true,
@@ -9067,7 +9065,7 @@ function WaypointMarker({
9067
9065
  )
9068
9066
  ] });
9069
9067
  }
9070
- var DEFAULT_ASSET_URL7, sizeMap10, checkIcon;
9068
+ var DEFAULT_ASSET_URL6, sizeMap10, checkIcon;
9071
9069
  var init_WaypointMarker = __esm({
9072
9070
  "components/game/2d/atoms/WaypointMarker.tsx"() {
9073
9071
  init_cn();
@@ -9075,7 +9073,7 @@ var init_WaypointMarker = __esm({
9075
9073
  init_Box();
9076
9074
  init_Typography();
9077
9075
  init_GameIcon();
9078
- DEFAULT_ASSET_URL7 = {
9076
+ DEFAULT_ASSET_URL6 = {
9079
9077
  url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
9080
9078
  role: "ui",
9081
9079
  category: "waypoint"
@@ -9096,7 +9094,7 @@ function formatDuration(seconds) {
9096
9094
  return `${Math.round(seconds)}s`;
9097
9095
  }
9098
9096
  function StatusEffect({
9099
- assetUrl = DEFAULT_ASSET_URL8,
9097
+ assetUrl = DEFAULT_ASSET_URL7,
9100
9098
  icon,
9101
9099
  label = "Shield",
9102
9100
  duration = 30,
@@ -9147,7 +9145,7 @@ function StatusEffect({
9147
9145
  label && /* @__PURE__ */ jsxRuntime.jsx(Typography, { as: "span", className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
9148
9146
  ] });
9149
9147
  }
9150
- var DEFAULT_ASSET_URL8, sizeMap11, variantStyles7;
9148
+ var DEFAULT_ASSET_URL7, sizeMap11, variantStyles7;
9151
9149
  var init_StatusEffect = __esm({
9152
9150
  "components/game/2d/atoms/StatusEffect.tsx"() {
9153
9151
  init_cn();
@@ -9155,7 +9153,7 @@ var init_StatusEffect = __esm({
9155
9153
  init_Box();
9156
9154
  init_Typography();
9157
9155
  init_GameIcon();
9158
- DEFAULT_ASSET_URL8 = {
9156
+ DEFAULT_ASSET_URL7 = {
9159
9157
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
9160
9158
  role: "ui",
9161
9159
  category: "effect"
@@ -9174,7 +9172,7 @@ var init_StatusEffect = __esm({
9174
9172
  }
9175
9173
  });
9176
9174
  function DamageNumber({
9177
- assetUrl = DEFAULT_ASSET_URL9,
9175
+ assetUrl = DEFAULT_ASSET_URL8,
9178
9176
  value = 42,
9179
9177
  type = "damage",
9180
9178
  size = "md",
@@ -9202,7 +9200,7 @@ function DamageNumber({
9202
9200
  )
9203
9201
  ] });
9204
9202
  }
9205
- var sizeMap12, typeStyles, floatKeyframes, DEFAULT_ASSET_URL9;
9203
+ var sizeMap12, typeStyles, floatKeyframes, DEFAULT_ASSET_URL8;
9206
9204
  var init_DamageNumber = __esm({
9207
9205
  "components/game/2d/atoms/DamageNumber.tsx"() {
9208
9206
  init_cn();
@@ -9226,7 +9224,7 @@ var init_DamageNumber = __esm({
9226
9224
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
9227
9225
  }
9228
9226
  `;
9229
- DEFAULT_ASSET_URL9 = {
9227
+ DEFAULT_ASSET_URL8 = {
9230
9228
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
9231
9229
  role: "effect",
9232
9230
  category: "effect"
@@ -9352,7 +9350,7 @@ var init_ChoiceButton = __esm({
9352
9350
  }
9353
9351
  });
9354
9352
  function ActionButton({
9355
- assetUrl = DEFAULT_ASSET_URL10,
9353
+ assetUrl = DEFAULT_ASSET_URL9,
9356
9354
  label = "Attack",
9357
9355
  icon,
9358
9356
  cooldown = 0,
@@ -9421,7 +9419,7 @@ function ActionButton({
9421
9419
  }
9422
9420
  );
9423
9421
  }
9424
- var sizeMap13, variantStyles8, DEFAULT_ASSET_URL10;
9422
+ var sizeMap13, variantStyles8, DEFAULT_ASSET_URL9;
9425
9423
  var init_ActionButton = __esm({
9426
9424
  "components/game/2d/atoms/ActionButton.tsx"() {
9427
9425
  init_cn();
@@ -9441,7 +9439,7 @@ var init_ActionButton = __esm({
9441
9439
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
9442
9440
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
9443
9441
  };
9444
- DEFAULT_ASSET_URL10 = {
9442
+ DEFAULT_ASSET_URL9 = {
9445
9443
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
9446
9444
  role: "ui",
9447
9445
  category: "action"
@@ -9661,15 +9659,17 @@ function ControlGrid({
9661
9659
  },
9662
9660
  d
9663
9661
  );
9662
+ const usesSemantic = !!directionEvents;
9663
+ const cell = (d) => !usesSemantic || directionEvents?.[d] ? dir(d) : /* @__PURE__ */ jsxRuntime.jsx(Box, {}, d);
9664
9664
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("inline-grid grid-cols-3", ds.gap, ds.container, className), children: [
9665
9665
  /* @__PURE__ */ jsxRuntime.jsx(Box, {}),
9666
- dir("up"),
9666
+ cell("up"),
9667
9667
  /* @__PURE__ */ jsxRuntime.jsx(Box, {}),
9668
- dir("left"),
9668
+ cell("left"),
9669
9669
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-6 h-6 rounded-interactive bg-muted border-2 border-muted-foreground" }) }),
9670
- dir("right"),
9670
+ cell("right"),
9671
9671
  /* @__PURE__ */ jsxRuntime.jsx(Box, {}),
9672
- dir("down"),
9672
+ cell("down"),
9673
9673
  /* @__PURE__ */ jsxRuntime.jsx(Box, {})
9674
9674
  ] });
9675
9675
  }
@@ -47749,6 +47749,7 @@ var crossTraitLog = logger.createLogger("almadar:ui:cross-trait");
47749
47749
  var flushLog = logger.createLogger("almadar:ui:slot-flush");
47750
47750
  var stateLog = logger.createLogger("almadar:ui:state-transitions");
47751
47751
  var tickLog = logger.createLogger("almadar:ui:tick-effects");
47752
+ logger.setNamespaceLevel("almadar:ui:tick-effects", "WARN");
47752
47753
  var SYNC_TICK_OPERATORS = /* @__PURE__ */ new Set([
47753
47754
  "set",
47754
47755
  "emit",
@@ -48168,8 +48169,15 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
48168
48169
  const scheduler = runtime.createTickScheduler();
48169
48170
  for (const binding of traitBindings) {
48170
48171
  for (const tick of binding.trait.ticks ?? []) {
48171
- const intervalMs = tick.interval === "frame" ? 0 : tick.interval;
48172
- scheduler.add(intervalMs, () => runTickEffects(tick, binding));
48172
+ if (tick.interval === "frame") {
48173
+ scheduler.add(0, () => runTickEffects(tick, binding));
48174
+ } else if (typeof tick.interval === "number") {
48175
+ scheduler.add(tick.interval, () => runTickEffects(tick, binding));
48176
+ } else if (runtime.isValidCronExpression(tick.interval)) {
48177
+ scheduler.addCron(tick.interval, () => runTickEffects(tick, binding));
48178
+ } else {
48179
+ scheduler.add(runtime.parseDurationString(tick.interval), () => runTickEffects(tick, binding));
48180
+ }
48173
48181
  }
48174
48182
  }
48175
48183
  return () => scheduler.stopAll();
@@ -2,7 +2,7 @@ import * as React96 from 'react';
2
2
  import React96__default, { useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, createContext, useSyncExternalStore, useLayoutEffect, lazy, useId } from 'react';
3
3
  import { EventBusContext, useTraitScope, useEntitySchemaOptional, useEntitySchema, getAllPages, OrbitalProvider, TraitScopeProvider, ServerBridgeProvider, useCurrentPagePath, VerificationProvider, EntitySchemaProvider, OrbitalThemeProvider, useServerBridge } from '@almadar/ui/providers';
4
4
  export { EntitySchemaProvider, ServerBridgeProvider, TraitContext, TraitProvider, useEntitySchema, useEntitySchemaOptional, useServerBridge, useTrait, useTraitContext } from '@almadar/ui/providers';
5
- import { createLogger, isLogLevelEnabled } from '@almadar/logger';
5
+ import { createLogger, setNamespaceLevel, isLogLevelEnabled } from '@almadar/logger';
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
8
  import * as LucideIcons2 from 'lucide-react';
@@ -43,7 +43,7 @@ import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, r
43
43
  import { CSS } from '@dnd-kit/utilities';
44
44
  import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
45
45
  import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
46
- import { StateMachineManager, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, createContextFromBindings, createTickScheduler, InMemoryPersistence } from '@almadar/runtime';
46
+ import { StateMachineManager, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, createContextFromBindings, createTickScheduler, isValidCronExpression, parseDurationString, InMemoryPersistence } from '@almadar/runtime';
47
47
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
48
48
 
49
49
  var __defProp = Object.defineProperty;
@@ -7692,11 +7692,14 @@ function recordTransition(trace) {
7692
7692
  }
7693
7693
  if (entry.event === "INIT") {
7694
7694
  const hasFetch = entry.effects.some((e) => e.type === "fetch");
7695
+ const hasEntitySeed = entry.effects.some(
7696
+ (e) => e.type === "set" && typeof e.args[0] === "string" && e.args[0].startsWith("@entity.")
7697
+ );
7695
7698
  const checkId = `init-fetch-${entry.traitName}`;
7696
- if (hasFetch) {
7699
+ if (hasFetch || hasEntitySeed) {
7697
7700
  registerCheck(
7698
7701
  checkId,
7699
- `INIT transition for "${entry.traitName}" has fetch effect`,
7702
+ `INIT transition for "${entry.traitName}" has fetch or entity-seed effect`,
7700
7703
  "pass"
7701
7704
  );
7702
7705
  } else {
@@ -8351,7 +8354,7 @@ var init_ScoreDisplay = __esm({
8351
8354
  }
8352
8355
  });
8353
8356
  function ControlButton({
8354
- assetUrl = DEFAULT_ASSET_URL,
8357
+ assetUrl,
8355
8358
  label,
8356
8359
  icon,
8357
8360
  size = "md",
@@ -8429,7 +8432,7 @@ function ControlButton({
8429
8432
  }
8430
8433
  );
8431
8434
  }
8432
- var sizeMap4, shapeMap, variantMap, DEFAULT_ASSET_URL;
8435
+ var sizeMap4, shapeMap, variantMap;
8433
8436
  var init_ControlButton = __esm({
8434
8437
  "components/game/2d/atoms/ControlButton.tsx"() {
8435
8438
  "use client";
@@ -8456,11 +8459,6 @@ var init_ControlButton = __esm({
8456
8459
  secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
8457
8460
  ghost: "bg-transparent text-foreground border-border hover:bg-muted"
8458
8461
  };
8459
- DEFAULT_ASSET_URL = {
8460
- url: "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png",
8461
- role: "ui",
8462
- category: "control"
8463
- };
8464
8462
  ControlButton.displayName = "ControlButton";
8465
8463
  }
8466
8464
  });
@@ -8549,7 +8547,7 @@ function isKnownState(s) {
8549
8547
  return s in DEFAULT_STATE_STYLES;
8550
8548
  }
8551
8549
  function StateIndicator({
8552
- assetUrl = DEFAULT_ASSET_URL2,
8550
+ assetUrl = DEFAULT_ASSET_URL,
8553
8551
  state = "idle",
8554
8552
  label,
8555
8553
  size = "md",
@@ -8579,14 +8577,14 @@ function StateIndicator({
8579
8577
  }
8580
8578
  );
8581
8579
  }
8582
- var DEFAULT_ASSET_URL2, DEFAULT_STATE_STYLES, DEFAULT_STYLE, STATIC_STATES, SIZE_CLASSES;
8580
+ var DEFAULT_ASSET_URL, DEFAULT_STATE_STYLES, DEFAULT_STYLE, STATIC_STATES, SIZE_CLASSES;
8583
8581
  var init_StateIndicator = __esm({
8584
8582
  "components/game/2d/atoms/StateIndicator.tsx"() {
8585
8583
  init_Box();
8586
8584
  init_Icon();
8587
8585
  init_cn();
8588
8586
  init_GameIcon();
8589
- DEFAULT_ASSET_URL2 = {
8587
+ DEFAULT_ASSET_URL = {
8590
8588
  url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
8591
8589
  role: "ui",
8592
8590
  category: "state"
@@ -8672,7 +8670,7 @@ var init_TimerDisplay = __esm({
8672
8670
  }
8673
8671
  });
8674
8672
  function ResourceCounter({
8675
- assetUrl = DEFAULT_ASSET_URL3,
8673
+ assetUrl = DEFAULT_ASSET_URL2,
8676
8674
  icon,
8677
8675
  label = "Gold",
8678
8676
  value = 250,
@@ -8705,7 +8703,7 @@ function ResourceCounter({
8705
8703
  }
8706
8704
  );
8707
8705
  }
8708
- var colorTokenClasses2, DEFAULT_ASSET_URL3, sizeMap6;
8706
+ var colorTokenClasses2, DEFAULT_ASSET_URL2, sizeMap6;
8709
8707
  var init_ResourceCounter = __esm({
8710
8708
  "components/game/2d/atoms/ResourceCounter.tsx"() {
8711
8709
  init_cn();
@@ -8721,7 +8719,7 @@ var init_ResourceCounter = __esm({
8721
8719
  error: "text-error",
8722
8720
  muted: "text-muted-foreground"
8723
8721
  };
8724
- DEFAULT_ASSET_URL3 = {
8722
+ DEFAULT_ASSET_URL2 = {
8725
8723
  url: "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png",
8726
8724
  role: "ui",
8727
8725
  category: "coin"
@@ -8735,7 +8733,7 @@ var init_ResourceCounter = __esm({
8735
8733
  }
8736
8734
  });
8737
8735
  function ItemSlot({
8738
- assetUrl = DEFAULT_ASSET_URL4,
8736
+ assetUrl = DEFAULT_ASSET_URL3,
8739
8737
  icon = "sword",
8740
8738
  label = "Iron Sword",
8741
8739
  quantity,
@@ -8790,7 +8788,7 @@ function ItemSlot({
8790
8788
  }
8791
8789
  );
8792
8790
  }
8793
- var sizeMap7, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL4, assetSizeMap;
8791
+ var sizeMap7, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL3, assetSizeMap;
8794
8792
  var init_ItemSlot = __esm({
8795
8793
  "components/game/2d/atoms/ItemSlot.tsx"() {
8796
8794
  "use client";
@@ -8820,7 +8818,7 @@ var init_ItemSlot = __esm({
8820
8818
  epic: "shadow-lg",
8821
8819
  legendary: "shadow-lg"
8822
8820
  };
8823
- DEFAULT_ASSET_URL4 = {
8821
+ DEFAULT_ASSET_URL3 = {
8824
8822
  url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
8825
8823
  role: "item",
8826
8824
  category: "item"
@@ -8834,7 +8832,7 @@ var init_ItemSlot = __esm({
8834
8832
  }
8835
8833
  });
8836
8834
  function TurnIndicator({
8837
- assetUrl = DEFAULT_ASSET_URL5,
8835
+ assetUrl = DEFAULT_ASSET_URL4,
8838
8836
  currentTurn = 1,
8839
8837
  maxTurns,
8840
8838
  activeTeam,
@@ -8874,7 +8872,7 @@ function TurnIndicator({
8874
8872
  }
8875
8873
  );
8876
8874
  }
8877
- var sizeMap8, DEFAULT_ASSET_URL5;
8875
+ var sizeMap8, DEFAULT_ASSET_URL4;
8878
8876
  var init_TurnIndicator = __esm({
8879
8877
  "components/game/2d/atoms/TurnIndicator.tsx"() {
8880
8878
  init_cn();
@@ -8886,7 +8884,7 @@ var init_TurnIndicator = __esm({
8886
8884
  md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
8887
8885
  lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
8888
8886
  };
8889
- DEFAULT_ASSET_URL5 = {
8887
+ DEFAULT_ASSET_URL4 = {
8890
8888
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png",
8891
8889
  role: "ui",
8892
8890
  category: "turn"
@@ -8906,7 +8904,7 @@ function getComboScale(combo) {
8906
8904
  return "";
8907
8905
  }
8908
8906
  function ComboCounter({
8909
- assetUrl = DEFAULT_ASSET_URL6,
8907
+ assetUrl = DEFAULT_ASSET_URL5,
8910
8908
  combo = 5,
8911
8909
  multiplier,
8912
8910
  streak,
@@ -8941,14 +8939,14 @@ function ComboCounter({
8941
8939
  }
8942
8940
  );
8943
8941
  }
8944
- var DEFAULT_ASSET_URL6, sizeMap9;
8942
+ var DEFAULT_ASSET_URL5, sizeMap9;
8945
8943
  var init_ComboCounter = __esm({
8946
8944
  "components/game/2d/atoms/ComboCounter.tsx"() {
8947
8945
  init_cn();
8948
8946
  init_Box();
8949
8947
  init_Typography();
8950
8948
  init_GameIcon();
8951
- DEFAULT_ASSET_URL6 = {
8949
+ DEFAULT_ASSET_URL5 = {
8952
8950
  url: "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png",
8953
8951
  role: "effect",
8954
8952
  category: "effect"
@@ -8962,7 +8960,7 @@ var init_ComboCounter = __esm({
8962
8960
  }
8963
8961
  });
8964
8962
  function WaypointMarker({
8965
- assetUrl = DEFAULT_ASSET_URL7,
8963
+ assetUrl = DEFAULT_ASSET_URL6,
8966
8964
  label,
8967
8965
  icon,
8968
8966
  active = true,
@@ -9022,7 +9020,7 @@ function WaypointMarker({
9022
9020
  )
9023
9021
  ] });
9024
9022
  }
9025
- var DEFAULT_ASSET_URL7, sizeMap10, checkIcon;
9023
+ var DEFAULT_ASSET_URL6, sizeMap10, checkIcon;
9026
9024
  var init_WaypointMarker = __esm({
9027
9025
  "components/game/2d/atoms/WaypointMarker.tsx"() {
9028
9026
  init_cn();
@@ -9030,7 +9028,7 @@ var init_WaypointMarker = __esm({
9030
9028
  init_Box();
9031
9029
  init_Typography();
9032
9030
  init_GameIcon();
9033
- DEFAULT_ASSET_URL7 = {
9031
+ DEFAULT_ASSET_URL6 = {
9034
9032
  url: "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png",
9035
9033
  role: "ui",
9036
9034
  category: "waypoint"
@@ -9051,7 +9049,7 @@ function formatDuration(seconds) {
9051
9049
  return `${Math.round(seconds)}s`;
9052
9050
  }
9053
9051
  function StatusEffect({
9054
- assetUrl = DEFAULT_ASSET_URL8,
9052
+ assetUrl = DEFAULT_ASSET_URL7,
9055
9053
  icon,
9056
9054
  label = "Shield",
9057
9055
  duration = 30,
@@ -9102,7 +9100,7 @@ function StatusEffect({
9102
9100
  label && /* @__PURE__ */ jsx(Typography, { as: "span", className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
9103
9101
  ] });
9104
9102
  }
9105
- var DEFAULT_ASSET_URL8, sizeMap11, variantStyles7;
9103
+ var DEFAULT_ASSET_URL7, sizeMap11, variantStyles7;
9106
9104
  var init_StatusEffect = __esm({
9107
9105
  "components/game/2d/atoms/StatusEffect.tsx"() {
9108
9106
  init_cn();
@@ -9110,7 +9108,7 @@ var init_StatusEffect = __esm({
9110
9108
  init_Box();
9111
9109
  init_Typography();
9112
9110
  init_GameIcon();
9113
- DEFAULT_ASSET_URL8 = {
9111
+ DEFAULT_ASSET_URL7 = {
9114
9112
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png",
9115
9113
  role: "ui",
9116
9114
  category: "effect"
@@ -9129,7 +9127,7 @@ var init_StatusEffect = __esm({
9129
9127
  }
9130
9128
  });
9131
9129
  function DamageNumber({
9132
- assetUrl = DEFAULT_ASSET_URL9,
9130
+ assetUrl = DEFAULT_ASSET_URL8,
9133
9131
  value = 42,
9134
9132
  type = "damage",
9135
9133
  size = "md",
@@ -9157,7 +9155,7 @@ function DamageNumber({
9157
9155
  )
9158
9156
  ] });
9159
9157
  }
9160
- var sizeMap12, typeStyles, floatKeyframes, DEFAULT_ASSET_URL9;
9158
+ var sizeMap12, typeStyles, floatKeyframes, DEFAULT_ASSET_URL8;
9161
9159
  var init_DamageNumber = __esm({
9162
9160
  "components/game/2d/atoms/DamageNumber.tsx"() {
9163
9161
  init_cn();
@@ -9181,7 +9179,7 @@ var init_DamageNumber = __esm({
9181
9179
  100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
9182
9180
  }
9183
9181
  `;
9184
- DEFAULT_ASSET_URL9 = {
9182
+ DEFAULT_ASSET_URL8 = {
9185
9183
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png",
9186
9184
  role: "effect",
9187
9185
  category: "effect"
@@ -9307,7 +9305,7 @@ var init_ChoiceButton = __esm({
9307
9305
  }
9308
9306
  });
9309
9307
  function ActionButton({
9310
- assetUrl = DEFAULT_ASSET_URL10,
9308
+ assetUrl = DEFAULT_ASSET_URL9,
9311
9309
  label = "Attack",
9312
9310
  icon,
9313
9311
  cooldown = 0,
@@ -9376,7 +9374,7 @@ function ActionButton({
9376
9374
  }
9377
9375
  );
9378
9376
  }
9379
- var sizeMap13, variantStyles8, DEFAULT_ASSET_URL10;
9377
+ var sizeMap13, variantStyles8, DEFAULT_ASSET_URL9;
9380
9378
  var init_ActionButton = __esm({
9381
9379
  "components/game/2d/atoms/ActionButton.tsx"() {
9382
9380
  init_cn();
@@ -9396,7 +9394,7 @@ var init_ActionButton = __esm({
9396
9394
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
9397
9395
  danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
9398
9396
  };
9399
- DEFAULT_ASSET_URL10 = {
9397
+ DEFAULT_ASSET_URL9 = {
9400
9398
  url: "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png",
9401
9399
  role: "ui",
9402
9400
  category: "action"
@@ -9616,15 +9614,17 @@ function ControlGrid({
9616
9614
  },
9617
9615
  d
9618
9616
  );
9617
+ const usesSemantic = !!directionEvents;
9618
+ const cell = (d) => !usesSemantic || directionEvents?.[d] ? dir(d) : /* @__PURE__ */ jsx(Box, {}, d);
9619
9619
  return /* @__PURE__ */ jsxs(Box, { className: cn("inline-grid grid-cols-3", ds.gap, ds.container, className), children: [
9620
9620
  /* @__PURE__ */ jsx(Box, {}),
9621
- dir("up"),
9621
+ cell("up"),
9622
9622
  /* @__PURE__ */ jsx(Box, {}),
9623
- dir("left"),
9623
+ cell("left"),
9624
9624
  /* @__PURE__ */ jsx(Box, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(Box, { className: "w-6 h-6 rounded-interactive bg-muted border-2 border-muted-foreground" }) }),
9625
- dir("right"),
9625
+ cell("right"),
9626
9626
  /* @__PURE__ */ jsx(Box, {}),
9627
- dir("down"),
9627
+ cell("down"),
9628
9628
  /* @__PURE__ */ jsx(Box, {})
9629
9629
  ] });
9630
9630
  }
@@ -47704,6 +47704,7 @@ var crossTraitLog = createLogger("almadar:ui:cross-trait");
47704
47704
  var flushLog = createLogger("almadar:ui:slot-flush");
47705
47705
  var stateLog = createLogger("almadar:ui:state-transitions");
47706
47706
  var tickLog = createLogger("almadar:ui:tick-effects");
47707
+ setNamespaceLevel("almadar:ui:tick-effects", "WARN");
47707
47708
  var SYNC_TICK_OPERATORS = /* @__PURE__ */ new Set([
47708
47709
  "set",
47709
47710
  "emit",
@@ -48123,8 +48124,15 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
48123
48124
  const scheduler = createTickScheduler();
48124
48125
  for (const binding of traitBindings) {
48125
48126
  for (const tick of binding.trait.ticks ?? []) {
48126
- const intervalMs = tick.interval === "frame" ? 0 : tick.interval;
48127
- scheduler.add(intervalMs, () => runTickEffects(tick, binding));
48127
+ if (tick.interval === "frame") {
48128
+ scheduler.add(0, () => runTickEffects(tick, binding));
48129
+ } else if (typeof tick.interval === "number") {
48130
+ scheduler.add(tick.interval, () => runTickEffects(tick, binding));
48131
+ } else if (isValidCronExpression(tick.interval)) {
48132
+ scheduler.addCron(tick.interval, () => runTickEffects(tick, binding));
48133
+ } else {
48134
+ scheduler.add(parseDurationString(tick.interval), () => runTickEffects(tick, binding));
48135
+ }
48128
48136
  }
48129
48137
  }
48130
48138
  return () => scheduler.stopAll();