@almadar/ui 5.101.0 → 5.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/avl/index.cjs +253 -49
  2. package/dist/avl/index.css +3 -3
  3. package/dist/avl/index.js +255 -51
  4. package/dist/components/core/atoms/AtlasImage.d.ts +2 -2
  5. package/dist/components/core/atoms/FlipContainer.d.ts +1 -1
  6. package/dist/components/core/molecules/Card.d.ts +1 -1
  7. package/dist/components/core/molecules/Chart.d.ts +3 -3
  8. package/dist/components/core/molecules/DataGrid.d.ts +1 -1
  9. package/dist/components/core/molecules/DataList.d.ts +1 -1
  10. package/dist/components/core/molecules/DocPagination.d.ts +8 -1
  11. package/dist/components/core/molecules/DocSearch.d.ts +8 -1
  12. package/dist/components/core/molecules/FlipCard.d.ts +1 -1
  13. package/dist/components/core/molecules/LineChart.d.ts +3 -1
  14. package/dist/components/core/molecules/MapView.d.ts +18 -1
  15. package/dist/components/core/molecules/SortableList.d.ts +1 -1
  16. package/dist/components/core/molecules/TableView.d.ts +1 -1
  17. package/dist/components/core/organisms/DataTable.d.ts +7 -3
  18. package/dist/components/core/organisms/debug/RuntimeDebugger.d.ts +10 -1
  19. package/dist/components/core/organisms/debug/tabs/EntitiesTab.d.ts +2 -1
  20. package/dist/components/core/organisms/debug/tabs/EventDispatcherTab.d.ts +2 -1
  21. package/dist/components/core/organisms/debug/tabs/EventFlowTab.d.ts +6 -1
  22. package/dist/components/core/organisms/debug/tabs/GuardsPanel.d.ts +6 -1
  23. package/dist/components/core/organisms/debug/tabs/ServerBridgeTab.d.ts +12 -1
  24. package/dist/components/core/organisms/debug/tabs/TicksTab.d.ts +2 -1
  25. package/dist/components/core/organisms/debug/tabs/TraitsTab.d.ts +2 -1
  26. package/dist/components/core/organisms/debug/tabs/TransitionTimeline.d.ts +11 -1
  27. package/dist/components/core/organisms/debug/tabs/VerificationTab.d.ts +8 -1
  28. package/dist/components/game/2d/atoms/ActionButton.d.ts +2 -1
  29. package/dist/components/game/2d/atoms/ChoiceButton.d.ts +2 -1
  30. package/dist/components/game/2d/atoms/ComboCounter.d.ts +2 -1
  31. package/dist/components/game/2d/atoms/ControlButton.d.ts +2 -1
  32. package/dist/components/game/2d/atoms/DamageNumber.d.ts +2 -1
  33. package/dist/components/game/2d/atoms/DialogueBubble.d.ts +2 -1
  34. package/dist/components/game/2d/atoms/GameIcon.d.ts +2 -1
  35. package/dist/components/game/2d/atoms/HealthBar.d.ts +2 -1
  36. package/dist/components/game/2d/atoms/ItemSlot.d.ts +2 -1
  37. package/dist/components/game/2d/atoms/MiniMap.d.ts +2 -1
  38. package/dist/components/game/2d/atoms/ResourceCounter.d.ts +2 -1
  39. package/dist/components/game/2d/atoms/ScoreDisplay.d.ts +2 -1
  40. package/dist/components/game/2d/atoms/StatusEffect.d.ts +2 -1
  41. package/dist/components/game/2d/atoms/TimerDisplay.d.ts +2 -1
  42. package/dist/components/game/2d/atoms/TurnIndicator.d.ts +2 -1
  43. package/dist/components/game/2d/atoms/WaypointMarker.d.ts +2 -1
  44. package/dist/components/game/2d/molecules/Canvas2D.d.ts +5 -4
  45. package/dist/components/game/2d/molecules/GameHud.d.ts +2 -1
  46. package/dist/components/game/2d/molecules/GameMenu.d.ts +2 -1
  47. package/dist/components/game/2d/molecules/InventoryGrid.d.ts +2 -1
  48. package/dist/components/game/2d/molecules/ResourceBar.d.ts +2 -1
  49. package/dist/components/game/2d/molecules/StatBadge.d.ts +2 -1
  50. package/dist/components/game/shared/lib/editorUtils.d.ts +8 -8
  51. package/dist/components/index.cjs +100 -24
  52. package/dist/components/index.css +3 -3
  53. package/dist/components/index.js +85 -13
  54. package/dist/hooks/index.cjs +71 -0
  55. package/dist/hooks/index.d.ts +1 -0
  56. package/dist/hooks/index.js +69 -2
  57. package/dist/hooks/useGitHub.d.ts +7 -7
  58. package/dist/hooks/useSharedEntityStore.d.ts +53 -0
  59. package/dist/hooks/useTraitStateMachine.d.ts +32 -1
  60. package/dist/marketing/index.cjs +2 -2
  61. package/dist/marketing/index.js +2 -2
  62. package/dist/providers/EventBusProvider.d.ts +1 -1
  63. package/dist/providers/SelectionProvider.d.ts +1 -1
  64. package/dist/providers/ServerBridge.d.ts +1 -1
  65. package/dist/providers/index.cjs +11 -5
  66. package/dist/providers/index.css +3 -3
  67. package/dist/providers/index.js +11 -5
  68. package/dist/runtime/index.cjs +253 -49
  69. package/dist/runtime/index.css +3 -3
  70. package/dist/runtime/index.js +255 -51
  71. package/package.json +11 -16
@@ -7730,7 +7730,7 @@ function recordTransition(trace) {
7730
7730
  ...trace,
7731
7731
  id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
7732
7732
  };
7733
- log3.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
7733
+ log4.debug("transition:recorded", { trait: trace.traitName, from: trace.from, to: trace.to, event: trace.event, effectCount: trace.effects.length });
7734
7734
  getState().transitions.push(entry);
7735
7735
  if (getState().transitions.length > MAX_TRANSITIONS) {
7736
7736
  getState().transitions.shift();
@@ -7832,7 +7832,7 @@ function getTraitSnapshots() {
7832
7832
  try {
7833
7833
  snapshots.push(getter());
7834
7834
  } catch (err) {
7835
- log3.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
7835
+ log4.error("traitSnapshot getter failed", { trait: traitName, err: String(err) });
7836
7836
  }
7837
7837
  }
7838
7838
  return snapshots;
@@ -7931,10 +7931,10 @@ function updateAssetStatus(url, status) {
7931
7931
  window.__orbitalVerification.assetStatus[url] = status;
7932
7932
  }
7933
7933
  }
7934
- var log3, MAX_TRANSITIONS;
7934
+ var log4, MAX_TRANSITIONS;
7935
7935
  var init_verificationRegistry = __esm({
7936
7936
  "lib/verificationRegistry.ts"() {
7937
- log3 = logger.createLogger("almadar:bridge");
7937
+ log4 = logger.createLogger("almadar:bridge");
7938
7938
  MAX_TRANSITIONS = 500;
7939
7939
  exposeOnWindow();
7940
7940
  }
@@ -10595,6 +10595,9 @@ var init_useUnitSpriteAtlas = __esm({
10595
10595
  init_spriteAnimation();
10596
10596
  }
10597
10597
  });
10598
+ function normalizeBackdrop(bg) {
10599
+ return typeof bg === "string" ? { url: bg, role: "decoration", category: "background" } : bg;
10600
+ }
10598
10601
  function SideView({
10599
10602
  player,
10600
10603
  platforms,
@@ -10604,7 +10607,7 @@ function SideView({
10604
10607
  canvasHeight,
10605
10608
  follow,
10606
10609
  bgColor,
10607
- backgroundImage,
10610
+ backgroundImage: backgroundImageRaw,
10608
10611
  playerSprite,
10609
10612
  tileSprites,
10610
10613
  effects,
@@ -10612,6 +10615,7 @@ function SideView({
10612
10615
  keyUpMap,
10613
10616
  className
10614
10617
  }) {
10618
+ const backgroundImage = normalizeBackdrop(backgroundImageRaw);
10615
10619
  const canvasRef = React96.useRef(null);
10616
10620
  const eventBus = useEventBus();
10617
10621
  const keysRef = React96.useRef(/* @__PURE__ */ new Set());
@@ -10903,7 +10907,7 @@ function Canvas2D({
10903
10907
  effects: _effectsPropRaw = [],
10904
10908
  platforms,
10905
10909
  player,
10906
- backgroundImage,
10910
+ backgroundImage: backgroundImageRaw,
10907
10911
  // Interaction state
10908
10912
  selectedUnitId = null,
10909
10913
  validMoves = [],
@@ -10944,6 +10948,7 @@ function Canvas2D({
10944
10948
  // Remote asset loading
10945
10949
  assetManifest
10946
10950
  }) {
10951
+ const backgroundImage = normalizeBackdrop(backgroundImageRaw);
10947
10952
  const isSide = projection === "side";
10948
10953
  const isFree = projection === "free";
10949
10954
  const flatLike = projection === "hex" || projection === "flat" || isFree;
@@ -17542,7 +17547,7 @@ var init_avl_elk_layout = __esm({
17542
17547
  elk = new ELK__default.default();
17543
17548
  }
17544
17549
  });
17545
- var log4, SWIM_GUTTER, CENTER_W, BehaviorView;
17550
+ var log5, SWIM_GUTTER, CENTER_W, BehaviorView;
17546
17551
  var init_BehaviorView = __esm({
17547
17552
  "components/avl/molecules/BehaviorView.tsx"() {
17548
17553
  "use client";
@@ -17551,7 +17556,7 @@ var init_BehaviorView = __esm({
17551
17556
  init_AvlSwimLane();
17552
17557
  init_avl_atom_types();
17553
17558
  init_avl_elk_layout();
17554
- log4 = logger.createLogger("almadar:ui:avl:behavior-view");
17559
+ log5 = logger.createLogger("almadar:ui:avl:behavior-view");
17555
17560
  SWIM_GUTTER = 120;
17556
17561
  CENTER_W = 360;
17557
17562
  BehaviorView = ({ data }) => {
@@ -17562,7 +17567,7 @@ var init_BehaviorView = __esm({
17562
17567
  const dataKey = React96.useMemo(() => JSON.stringify(traitData), [traitData]);
17563
17568
  React96.useEffect(() => {
17564
17569
  if (!traitData) return;
17565
- computeTraitLayout(traitData).then(setLayout).catch((err) => log4.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
17570
+ computeTraitLayout(traitData).then(setLayout).catch((err) => log5.error("compute-trait-layout-failed", { error: err instanceof Error ? err : String(err) }));
17566
17571
  }, [dataKey]);
17567
17572
  if (!traitData) {
17568
17573
  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") });
@@ -17754,9 +17759,9 @@ var init_BiologyCanvas = __esm({
17754
17759
  }
17755
17760
  });
17756
17761
 
17757
- // node_modules/katex/dist/katex.min.css
17762
+ // node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
17758
17763
  var init_katex_min = __esm({
17759
- "node_modules/katex/dist/katex.min.css"() {
17764
+ "node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
17760
17765
  }
17761
17766
  });
17762
17767
  var Tabs;
@@ -18114,7 +18119,7 @@ function generateDiff(oldVal, newVal) {
18114
18119
  }
18115
18120
  return diff;
18116
18121
  }
18117
- var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log5, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, DIFF_STYLE_FALLBACK, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
18122
+ var orbStyleOverrides, orbStyle, loloStyleOverrides, loloStyle, log6, CODE_LANGUAGES, CODE_LANGUAGE_SET, DIFF_STYLES, DIFF_STYLE_FALLBACK, LINE_PROPS_FN, HIDDEN_LINE_NUMBERS, CodeBlock;
18118
18123
  var init_CodeBlock = __esm({
18119
18124
  "components/core/molecules/markdown/CodeBlock.tsx"() {
18120
18125
  init_cn();
@@ -18197,7 +18202,7 @@ var init_CodeBlock = __esm({
18197
18202
  "lolo-op-async": { color: syntax.ORB_COLORS.dark.async }
18198
18203
  };
18199
18204
  loloStyle = { ...dark__default.default, ...loloStyleOverrides };
18200
- log5 = logger.createLogger("almadar:ui:markdown-code");
18205
+ log6 = logger.createLogger("almadar:ui:markdown-code");
18201
18206
  CODE_LANGUAGES = [
18202
18207
  "text",
18203
18208
  "json",
@@ -18465,7 +18470,7 @@ var init_CodeBlock = __esm({
18465
18470
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: true });
18466
18471
  setTimeout(() => setCopied(false), 2e3);
18467
18472
  } catch (err) {
18468
- log5.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
18473
+ log6.error("Failed to copy code", { error: err instanceof Error ? err : String(err) });
18469
18474
  eventBus.emit("UI:COPY_CODE", { language: activeLanguage, success: false });
18470
18475
  }
18471
18476
  };
@@ -27330,14 +27335,14 @@ function useSafeEventBus3() {
27330
27335
  } };
27331
27336
  }
27332
27337
  }
27333
- var log6, lookStyles5, ButtonGroup;
27338
+ var log7, lookStyles5, ButtonGroup;
27334
27339
  var init_ButtonGroup = __esm({
27335
27340
  "components/core/molecules/ButtonGroup.tsx"() {
27336
27341
  "use client";
27337
27342
  init_cn();
27338
27343
  init_atoms();
27339
27344
  init_useEventBus();
27340
- log6 = logger.createLogger("almadar:ui:button-group");
27345
+ log7 = logger.createLogger("almadar:ui:button-group");
27341
27346
  lookStyles5 = {
27342
27347
  "right-aligned-buttons": "",
27343
27348
  "floating-bar": "fixed bottom-section left-1/2 -translate-x-1/2 shadow-elevation-toast bg-card p-card-sm rounded-container",
@@ -27418,7 +27423,7 @@ var init_ButtonGroup = __esm({
27418
27423
  {
27419
27424
  variant: "ghost",
27420
27425
  onClick: () => {
27421
- log6.debug("Filter clicked", { field: filter.field });
27426
+ log7.debug("Filter clicked", { field: filter.field });
27422
27427
  },
27423
27428
  children: filter.label
27424
27429
  },
@@ -28327,9 +28332,9 @@ function debug(...args) {
28327
28332
  const [first, ...rest] = args;
28328
28333
  const message = typeof first === "string" ? first : "<debug>";
28329
28334
  if (rest.length === 0 && typeof first === "string") {
28330
- log7.debug(message);
28335
+ log8.debug(message);
28331
28336
  } else {
28332
- log7.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28337
+ log8.debug(message, { args: rest.length > 0 ? formatArgs(rest) : formatArgs([first]) });
28333
28338
  }
28334
28339
  }
28335
28340
  function debugGroup(label) {
@@ -28357,11 +28362,11 @@ function toLogMetaValue(v) {
28357
28362
  }
28358
28363
  return String(v);
28359
28364
  }
28360
- var NAMESPACE, log7;
28365
+ var NAMESPACE, log8;
28361
28366
  var init_debug = __esm({
28362
28367
  "lib/debug.ts"() {
28363
28368
  NAMESPACE = "almadar:ui:debug";
28364
- log7 = logger.createLogger(NAMESPACE);
28369
+ log8 = logger.createLogger(NAMESPACE);
28365
28370
  logger.createLogger("almadar:ui:debug:input");
28366
28371
  logger.createLogger("almadar:ui:debug:collision");
28367
28372
  logger.createLogger("almadar:ui:debug:physics");
@@ -29767,8 +29772,9 @@ var init_LineChart = __esm({
29767
29772
  const safeData = data ?? [];
29768
29773
  const sortedData = React96.useMemo(() => {
29769
29774
  if (safeData.length === 0) return [];
29775
+ if (!safeData.some((d) => d.date != null)) return [...safeData];
29770
29776
  return [...safeData].sort(
29771
- (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
29777
+ (a, b) => new Date(a.date ?? 0).getTime() - new Date(b.date ?? 0).getTime()
29772
29778
  );
29773
29779
  }, [safeData]);
29774
29780
  const points = React96.useMemo(() => {
@@ -30519,12 +30525,12 @@ var init_MapView = __esm({
30519
30525
  shadowSize: [41, 41]
30520
30526
  });
30521
30527
  L.Marker.prototype.options.icon = defaultIcon;
30522
- const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback98, useState: useState97 } = React96__namespace.default;
30528
+ const { useEffect: useEffect67, useRef: useRef66, useCallback: useCallback98, useState: useState97 } = React96__namespace.default;
30523
30529
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
30524
30530
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
30525
30531
  function MapUpdater({ centerLat, centerLng, zoom }) {
30526
30532
  const map = useMap();
30527
- const prevRef = useRef65({ centerLat, centerLng, zoom });
30533
+ const prevRef = useRef66({ centerLat, centerLng, zoom });
30528
30534
  useEffect67(() => {
30529
30535
  const prev = prevRef.current;
30530
30536
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
@@ -43786,7 +43792,7 @@ function getAllEvents(traits2) {
43786
43792
  function EventDispatcherTab({ traits: traits2, schema }) {
43787
43793
  const eventBus = useEventBus();
43788
43794
  const { t } = hooks.useTranslate();
43789
- const [log9, setLog] = React96__namespace.useState([]);
43795
+ const [log10, setLog] = React96__namespace.useState([]);
43790
43796
  const prevStatesRef = React96__namespace.useRef(/* @__PURE__ */ new Map());
43791
43797
  React96__namespace.useEffect(() => {
43792
43798
  for (const trait of traits2) {
@@ -43850,9 +43856,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
43850
43856
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
43851
43857
  /* @__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)) })
43852
43858
  ] }),
43853
- log9.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
43859
+ log10.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
43854
43860
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
43855
- /* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log9.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
43861
+ /* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log10.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
43856
43862
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-400", children: entry.traitName }),
43857
43863
  " ",
43858
43864
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500", children: entry.from }),
@@ -47562,7 +47568,67 @@ var init_UISlotRenderer = __esm({
47562
47568
 
47563
47569
  // hooks/index.ts
47564
47570
  init_useEventBus();
47565
- var log2 = logger.createLogger("almadar:ui:effects:client-handlers");
47571
+ var log2 = logger.createLogger("almadar:ui:shared-entity-store");
47572
+ var EMPTY_ENTITY_STATE = {};
47573
+ function createSharedEntityStore() {
47574
+ const states = /* @__PURE__ */ new Map();
47575
+ const subscribers2 = /* @__PURE__ */ new Map();
47576
+ const getSnapshot3 = (entityId) => states.get(entityId) ?? EMPTY_ENTITY_STATE;
47577
+ const subscribe2 = (entityId, callback) => {
47578
+ let set = subscribers2.get(entityId);
47579
+ if (!set) {
47580
+ set = /* @__PURE__ */ new Set();
47581
+ subscribers2.set(entityId, set);
47582
+ }
47583
+ set.add(callback);
47584
+ return () => {
47585
+ const current = subscribers2.get(entityId);
47586
+ if (!current) return;
47587
+ current.delete(callback);
47588
+ if (current.size === 0) {
47589
+ subscribers2.delete(entityId);
47590
+ }
47591
+ };
47592
+ };
47593
+ const commit = (entityId, nextState) => {
47594
+ states.set(entityId, nextState);
47595
+ const set = subscribers2.get(entityId);
47596
+ if (!set) return;
47597
+ set.forEach((callback) => {
47598
+ try {
47599
+ callback();
47600
+ } catch (error) {
47601
+ log2.error("Shared entity subscriber error", {
47602
+ entityId,
47603
+ error: error instanceof Error ? error : String(error)
47604
+ });
47605
+ }
47606
+ });
47607
+ };
47608
+ const seed = (entityId, initialState) => {
47609
+ if (!states.has(entityId)) {
47610
+ states.set(entityId, initialState);
47611
+ }
47612
+ };
47613
+ return { getSnapshot: getSnapshot3, subscribe: subscribe2, commit, seed };
47614
+ }
47615
+ function useSharedEntityStore() {
47616
+ const storeRef = React96.useRef(null);
47617
+ if (storeRef.current === null) {
47618
+ storeRef.current = createSharedEntityStore();
47619
+ }
47620
+ return storeRef.current;
47621
+ }
47622
+ function runTickFrame(entityId, orderedWriters, store) {
47623
+ let scratch = store.getSnapshot(entityId);
47624
+ for (const writer of orderedWriters) {
47625
+ const writes = writer(scratch);
47626
+ scratch = core.mergeEntityFrame(scratch, writes);
47627
+ }
47628
+ store.commit(entityId, scratch);
47629
+ return scratch;
47630
+ }
47631
+ var log3 = logger.createLogger("almadar:ui:effects:client-handlers");
47566
47632
  function createClientEffectHandlers(options) {
47567
47633
  const { eventBus, slotSetter, navigate, notify, callService, liveEntity } = options;
47568
47634
  return {
@@ -47571,12 +47637,12 @@ function createClientEffectHandlers(options) {
47571
47637
  eventBus.emit(prefixedEvent, payload);
47572
47638
  },
47573
47639
  persist: async () => {
47574
- log2.warn("persist is server-side only, ignored on client");
47640
+ log3.warn("persist is server-side only, ignored on client");
47575
47641
  },
47576
47642
  // @almadar/runtime EffectHandlers.set types value:unknown — should be FieldValue (upstream fix queued)
47577
47643
  set: ((_entityId, field, value) => {
47578
47644
  if (!liveEntity) {
47579
- log2.warn("set is server-side only, ignored on client (no live entity)");
47645
+ log3.warn("set is server-side only, ignored on client (no live entity)");
47580
47646
  return;
47581
47647
  }
47582
47648
  liveEntity[field] = value;
@@ -47608,10 +47674,10 @@ function createClientEffectHandlers(options) {
47608
47674
  slotSetter.addPattern(slot, pattern, props);
47609
47675
  },
47610
47676
  navigate: navigate ?? ((path) => {
47611
- log2.warn("No navigate handler, ignoring", { path });
47677
+ log3.warn("No navigate handler, ignoring", { path });
47612
47678
  }),
47613
47679
  notify: notify ?? ((msg, type) => {
47614
- log2.debug("notify", { type, message: msg });
47680
+ log3.debug("notify", { type, message: msg });
47615
47681
  })
47616
47682
  };
47617
47683
  }
@@ -47782,11 +47848,101 @@ function toTraitDefinition(binding) {
47782
47848
  function normalizeEventKey(eventKey) {
47783
47849
  return eventKey.startsWith("UI:") ? eventKey.slice(3) : eventKey;
47784
47850
  }
47851
+ var SHARED_ENTITY_WRITE_OPS = /* @__PURE__ */ new Set(["set"]);
47852
+ var SHARED_ENTITY_RENDER_OPS = /* @__PURE__ */ new Set(["render-ui", "render"]);
47853
+ function collectAllTraitEffects(trait) {
47854
+ return [
47855
+ ...trait.ticks.flatMap((t) => t.effects),
47856
+ ...trait.transitions.flatMap((t) => t.effects)
47857
+ ];
47858
+ }
47859
+ function effectsCallOp(effects, ops) {
47860
+ for (const effect of effects) {
47861
+ let found = false;
47862
+ core.walkSExpr(effect, (node) => {
47863
+ if (!found && Array.isArray(node) && typeof node[0] === "string" && ops.has(node[0])) {
47864
+ found = true;
47865
+ }
47866
+ });
47867
+ if (found) return true;
47868
+ }
47869
+ return false;
47870
+ }
47871
+ function createSharedEntityWriter(binding, tick, traitStatesRef, emit) {
47872
+ return (scratch) => {
47873
+ const traitName = binding.trait.name;
47874
+ const currentState = traitStatesRef.current.get(traitName)?.currentState ?? "";
47875
+ if (tick.appliesTo.length > 0 && !tick.appliesTo.includes(currentState)) return [];
47876
+ const scratchEntity = { ...scratch };
47877
+ const writes = [];
47878
+ const ctx = evaluator.createMinimalContext(scratchEntity, {}, currentState);
47879
+ const declaredDefaults = runtime.collectDeclaredConfigDefaults(binding.trait);
47880
+ const callSiteConfig = binding.config;
47881
+ if (declaredDefaults || callSiteConfig) {
47882
+ ctx.config = { ...declaredDefaults ?? {}, ...callSiteConfig ?? {} };
47883
+ }
47884
+ ctx.mutateEntity = (changes) => {
47885
+ for (const [field, value] of Object.entries(changes)) {
47886
+ const fieldValue = value;
47887
+ scratchEntity[field] = fieldValue;
47888
+ writes.push({ field, value: fieldValue });
47889
+ }
47890
+ };
47891
+ ctx.emit = (event, payload) => {
47892
+ emit(event, payload);
47893
+ };
47894
+ if (tick.guard !== void 0 && !evaluator.evaluateGuard(tick.guard, ctx)) {
47895
+ tickLog.debug("guard-blocked", { traitName, tick: tick.name, state: currentState });
47896
+ return [];
47897
+ }
47898
+ evaluator.executeEffects(tick.effects, ctx);
47899
+ return writes;
47900
+ };
47901
+ }
47785
47902
  function useTraitStateMachine(traitBindings, uiSlots, options) {
47786
47903
  const eventBus = useEventBus();
47787
47904
  const { entities } = providers.useEntitySchema();
47788
47905
  const traitConfigsByName = options?.traitConfigsByName;
47789
47906
  const orbitalsByTrait = options?.orbitalsByTrait;
47907
+ const sharedEntityStore = useSharedEntityStore();
47908
+ const sharedGroups = React96.useMemo(() => {
47909
+ const groups = /* @__PURE__ */ new Map();
47910
+ for (const binding of traitBindings) {
47911
+ const linkedEntityName = binding.linkedEntity ?? binding.trait.linkedEntity;
47912
+ if (!linkedEntityName) continue;
47913
+ const entityDef = entities.get(linkedEntityName);
47914
+ if (!entityDef?.shared) continue;
47915
+ const orbitalName = orbitalsByTrait?.[binding.trait.name] ?? "";
47916
+ const storeKey = `${orbitalName}::${linkedEntityName}`;
47917
+ let group = groups.get(storeKey);
47918
+ if (!group) {
47919
+ let defaults;
47920
+ for (const field of entityDef.fields) {
47921
+ if (field.default !== void 0) {
47922
+ (defaults ?? (defaults = {}))[field.name] = field.default;
47923
+ }
47924
+ }
47925
+ group = { storeKey, entityName: linkedEntityName, writerBindings: [], renderBindings: [], defaults };
47926
+ groups.set(storeKey, group);
47927
+ }
47928
+ const allEffects = collectAllTraitEffects(binding.trait);
47929
+ if (effectsCallOp(allEffects, SHARED_ENTITY_WRITE_OPS)) group.writerBindings.push(binding);
47930
+ if (effectsCallOp(allEffects, SHARED_ENTITY_RENDER_OPS)) group.renderBindings.push(binding);
47931
+ }
47932
+ return groups;
47933
+ }, [traitBindings, entities, orbitalsByTrait]);
47934
+ for (const group of sharedGroups.values()) {
47935
+ if (group.defaults) sharedEntityStore.seed(group.storeKey, group.defaults);
47936
+ }
47937
+ const sharedKeyByTraitNameRef = React96.useRef(/* @__PURE__ */ new Map());
47938
+ React96.useEffect(() => {
47939
+ const map = /* @__PURE__ */ new Map();
47940
+ for (const group of sharedGroups.values()) {
47941
+ for (const binding of group.writerBindings) map.set(binding.trait.name, group.storeKey);
47942
+ for (const binding of group.renderBindings) map.set(binding.trait.name, group.storeKey);
47943
+ }
47944
+ sharedKeyByTraitNameRef.current = map;
47945
+ }, [sharedGroups]);
47790
47946
  const manager = React96.useMemo(() => {
47791
47947
  const traitDefs = traitBindings.map(toTraitDefinition);
47792
47948
  const m = new runtime.StateMachineManager(traitDefs);
@@ -47969,14 +48125,21 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
47969
48125
  };
47970
48126
  }, [traitBindings]);
47971
48127
  const executeTransitionEffects = React96.useCallback(async (params) => {
47972
- const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log9 } = params;
48128
+ const { binding, previousState, newState, payload, flushEvent, syncOnly, log: log10 } = params;
47973
48129
  const traitName = binding.trait.name;
47974
48130
  const linkedEntity = binding.linkedEntity || "";
47975
48131
  const entityId = payload?.entityId;
47976
- let liveEntity = traitFieldStatesRef.current.get(traitName);
47977
- if (!liveEntity) {
47978
- liveEntity = {};
47979
- traitFieldStatesRef.current.set(traitName, liveEntity);
48132
+ const sharedKey = sharedKeyByTraitNameRef.current.get(traitName);
48133
+ let liveEntity;
48134
+ if (sharedKey !== void 0) {
48135
+ liveEntity = { ...sharedEntityStore.getSnapshot(sharedKey) };
48136
+ } else {
48137
+ let existing = traitFieldStatesRef.current.get(traitName);
48138
+ if (!existing) {
48139
+ existing = {};
48140
+ traitFieldStatesRef.current.set(traitName, existing);
48141
+ }
48142
+ liveEntity = existing;
47980
48143
  }
47981
48144
  const effects = syncOnly ? params.effects.filter(
47982
48145
  (e) => Array.isArray(e) && SYNC_TICK_OPERATORS.has(String(e[0]))
@@ -48058,7 +48221,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
48058
48221
  ...handlers,
48059
48222
  set: async (targetId, field, value) => {
48060
48223
  if (baseSet) await baseSet(targetId, field, value);
48061
- log9.debug("set:write", {
48224
+ log10.debug("set:write", {
48062
48225
  traitName,
48063
48226
  field,
48064
48227
  value: JSON.stringify(value),
@@ -48098,17 +48261,20 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
48098
48261
  const executor = new runtime.EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
48099
48262
  try {
48100
48263
  await executor.executeAll(effects);
48101
- log9.debug("effects:executed", () => ({
48264
+ if (sharedKey !== void 0) {
48265
+ sharedEntityStore.commit(sharedKey, liveEntity);
48266
+ }
48267
+ log10.debug("effects:executed", () => ({
48102
48268
  traitName,
48103
48269
  transition: `${previousState}->${newState}`,
48104
48270
  event: flushEvent,
48105
48271
  effectCount: effects.length,
48106
48272
  emitted: emittedDuringExec.join(","),
48107
- entityAfter: JSON.stringify(traitFieldStatesRef.current.get(traitName) ?? {}),
48273
+ entityAfter: JSON.stringify(liveEntity ?? {}),
48108
48274
  slotsTouched: Array.from(pendingSlots.keys()).join(",")
48109
48275
  }));
48110
48276
  for (const [slot, patterns] of pendingSlots) {
48111
- log9.debug("flush:slot", {
48277
+ log10.debug("flush:slot", {
48112
48278
  traitName,
48113
48279
  slot,
48114
48280
  patternCount: patterns.length,
@@ -48123,7 +48289,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
48123
48289
  });
48124
48290
  }
48125
48291
  } catch (error) {
48126
- log9.error("effects:error", {
48292
+ log10.error("effects:error", {
48127
48293
  traitName,
48128
48294
  transition: `${previousState}->${newState}`,
48129
48295
  event: flushEvent,
@@ -48132,14 +48298,16 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
48132
48298
  });
48133
48299
  }
48134
48300
  return emittedDuringExec;
48135
- }, [eventBus, flushSlot]);
48301
+ }, [eventBus, flushSlot, sharedEntityStore]);
48136
48302
  const runTickEffects = React96.useCallback((tick, binding) => {
48137
48303
  const traitName = binding.trait.name;
48138
48304
  const currentState = traitStatesRef.current.get(traitName)?.currentState ?? "";
48139
48305
  if (tick.appliesTo.length > 0 && !tick.appliesTo.includes(currentState)) return;
48140
48306
  if (tick.guard !== void 0) {
48307
+ const sharedKey = sharedKeyByTraitNameRef.current.get(traitName);
48308
+ const entity = sharedKey !== void 0 ? sharedEntityStore.getSnapshot(sharedKey) : traitFieldStatesRef.current.get(traitName) ?? {};
48141
48309
  const guardCtx = {
48142
- entity: traitFieldStatesRef.current.get(traitName) ?? {},
48310
+ entity,
48143
48311
  payload: {},
48144
48312
  state: currentState
48145
48313
  };
@@ -48164,10 +48332,46 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
48164
48332
  syncOnly: true,
48165
48333
  log: tickLog
48166
48334
  });
48167
- }, [executeTransitionEffects]);
48335
+ }, [executeTransitionEffects, sharedEntityStore]);
48336
+ const emitFromSharedWriter = React96.useCallback((event, payload) => {
48337
+ const prefixedEvent = event.startsWith("UI:") ? event : `UI:${event}`;
48338
+ eventBus.emit(prefixedEvent, payload);
48339
+ }, [eventBus]);
48168
48340
  React96.useEffect(() => {
48169
48341
  const scheduler = runtime.createTickScheduler();
48342
+ const writerTraitNames = /* @__PURE__ */ new Set();
48343
+ for (const group of sharedGroups.values()) {
48344
+ const ticksByInterval = /* @__PURE__ */ new Map();
48345
+ for (const binding of group.writerBindings) {
48346
+ writerTraitNames.add(binding.trait.name);
48347
+ for (const tick of binding.trait.ticks ?? []) {
48348
+ const intervalKey = String(tick.interval);
48349
+ const entries = ticksByInterval.get(intervalKey) ?? [];
48350
+ entries.push({ binding, tick });
48351
+ ticksByInterval.set(intervalKey, entries);
48352
+ }
48353
+ }
48354
+ for (const entries of ticksByInterval.values()) {
48355
+ const interval = entries[0].tick.interval;
48356
+ const onDue = () => {
48357
+ const writers = entries.map(
48358
+ ({ binding, tick }) => createSharedEntityWriter(binding, tick, traitStatesRef, emitFromSharedWriter)
48359
+ );
48360
+ runTickFrame(group.storeKey, writers, sharedEntityStore);
48361
+ };
48362
+ if (interval === "frame") {
48363
+ scheduler.add(0, onDue);
48364
+ } else if (typeof interval === "number") {
48365
+ scheduler.add(interval, onDue);
48366
+ } else if (runtime.isValidCronExpression(interval)) {
48367
+ scheduler.addCron(interval, onDue);
48368
+ } else {
48369
+ scheduler.add(runtime.parseDurationString(interval), onDue);
48370
+ }
48371
+ }
48372
+ }
48170
48373
  for (const binding of traitBindings) {
48374
+ if (writerTraitNames.has(binding.trait.name)) continue;
48171
48375
  for (const tick of binding.trait.ticks ?? []) {
48172
48376
  if (tick.interval === "frame") {
48173
48377
  scheduler.add(0, () => runTickEffects(tick, binding));
@@ -48181,7 +48385,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
48181
48385
  }
48182
48386
  }
48183
48387
  return () => scheduler.stopAll();
48184
- }, [traitBindings, runTickEffects]);
48388
+ }, [traitBindings, runTickEffects, sharedGroups, sharedEntityStore, emitFromSharedWriter]);
48185
48389
  const processEventQueued = React96.useCallback(async (eventKey, payload) => {
48186
48390
  const normalizedEvent = normalizeEventKey(eventKey);
48187
48391
  const bindings = traitBindingsRef.current;
@@ -48701,7 +48905,7 @@ function buildOrbitalsByTrait(schema, resolvedPages = []) {
48701
48905
  // runtime/OrbPreview.tsx
48702
48906
  init_verificationRegistry();
48703
48907
  var PERF_NAMESPACE = "almadar:perf:canvas";
48704
- var log8 = logger.createLogger(PERF_NAMESPACE);
48908
+ var log9 = logger.createLogger(PERF_NAMESPACE);
48705
48909
  var RING_SIZE = 50;
48706
48910
  var ring = [];
48707
48911
  var writeIdx = 0;
@@ -48756,7 +48960,7 @@ function perfEnd(name, startToken, detail) {
48756
48960
  }
48757
48961
  }
48758
48962
  push({ name, durationMs, ts: endTs, detail });
48759
- log8.debug(name, () => ({ durationMs, ...detail ?? {} }));
48963
+ log9.debug(name, () => ({ durationMs, ...detail ?? {} }));
48760
48964
  }
48761
48965
  function perfTime(name, fn, detail) {
48762
48966
  const t = perfStart(name);
@@ -48774,7 +48978,7 @@ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, com
48774
48978
  ts: commitTime,
48775
48979
  detail: { baseDuration }
48776
48980
  });
48777
- log8.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
48981
+ log9.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
48778
48982
  };
48779
48983
  function getPerfSnapshot() {
48780
48984
  if (ring.length < RING_SIZE) return ring.slice();
@@ -1,4 +1,4 @@
1
- /* node_modules/katex/dist/katex.min.css */
1
+ /* node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css */
2
2
  @font-face {
3
3
  font-display: block;
4
4
  font-family: KaTeX_AMS;
@@ -214,11 +214,11 @@
214
214
  border-color: currentColor;
215
215
  }
216
216
  .katex .katex-version:after {
217
- content: "0.16.45";
217
+ content: "0.16.47";
218
218
  }
219
219
  .katex .katex-mathml {
220
- clip: rect(1px, 1px, 1px, 1px);
221
220
  border: 0;
221
+ clip-path: inset(50%);
222
222
  height: 1px;
223
223
  overflow: hidden;
224
224
  padding: 0;