@almadar/ui 5.134.0 → 5.135.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.
@@ -840,6 +840,32 @@ function formatValue(value, format) {
840
840
  return String(value);
841
841
  }
842
842
  }
843
+ function compareCellValues(a, b) {
844
+ const aEmpty = a === null || a === void 0 || a === "";
845
+ const bEmpty = b === null || b === void 0 || b === "";
846
+ if (aEmpty || bEmpty) return aEmpty && bEmpty ? 0 : aEmpty ? 1 : -1;
847
+ if (typeof a === "number" && typeof b === "number") return a - b;
848
+ if (typeof a === "boolean" && typeof b === "boolean") return Number(a) - Number(b);
849
+ const aNum = Number(a);
850
+ const bNum = Number(b);
851
+ if (Number.isFinite(aNum) && Number.isFinite(bNum)) return aNum - bNum;
852
+ const aTime = dateLikeTime(a);
853
+ const bTime = dateLikeTime(b);
854
+ if (aTime !== null && bTime !== null) return aTime - bTime;
855
+ return String(a).localeCompare(String(b));
856
+ }
857
+ function dateLikeTime(value) {
858
+ if (value instanceof Date) return value.getTime();
859
+ const text = String(value);
860
+ if (!/\d/.test(text) || !/[-/:T]/.test(text)) return null;
861
+ const time = Date.parse(text);
862
+ return Number.isNaN(time) ? null : time;
863
+ }
864
+ function sortRows(rows, field, direction = "asc") {
865
+ if (!field) return rows;
866
+ const dir = direction === "desc" ? -1 : 1;
867
+ return [...rows].sort((a, b) => dir * compareCellValues(a?.[field], b?.[field]));
868
+ }
843
869
 
844
870
  // lib/getNestedValue.ts
845
871
  function getNestedValue(obj, path) {
@@ -1914,6 +1940,7 @@ exports.clearTicks = clearTicks;
1914
1940
  exports.clearTraits = clearTraits;
1915
1941
  exports.clearVerification = clearVerification;
1916
1942
  exports.cn = cn;
1943
+ exports.compareCellValues = compareCellValues;
1917
1944
  exports.computeJazariLayout = computeJazariLayout;
1918
1945
  exports.debug = debug;
1919
1946
  exports.debugCollision = debugCollision;
@@ -1988,6 +2015,7 @@ exports.renderStateMachineToSvg = renderStateMachineToSvg;
1988
2015
  exports.setDebugEnabled = setDebugEnabled;
1989
2016
  exports.setEntityProvider = setEntityProvider;
1990
2017
  exports.setTickActive = setTickActive;
2018
+ exports.sortRows = sortRows;
1991
2019
  exports.subscribeToDebugEvents = subscribeToDebugEvents;
1992
2020
  exports.subscribeToGuardChanges = subscribeToGuardChanges;
1993
2021
  exports.subscribeToTickChanges = subscribeToTickChanges;
@@ -1,7 +1,7 @@
1
- export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseMarkdownWithCodeBlocks, B as recordServerResponse, F as recordTransition, G as registerCheck, H as registerTraitSnapshot, I as renderStateMachineToDomData, J as renderStateMachineToSvg, K as subscribeToVerification, L as updateAssetStatus, M as updateBridgeHealth, N as updateCheck, O as waitForTransition } from '../cn-D3H9UzCW.cjs';
1
+ export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseMarkdownWithCodeBlocks, B as recordServerResponse, F as recordTransition, G as registerCheck, H as registerTraitSnapshot, I as renderStateMachineToDomData, J as renderStateMachineToSvg, K as subscribeToVerification, L as updateAssetStatus, M as updateBridgeHealth, N as updateCheck, O as waitForTransition } from '../cn-B8GXqrtp.cjs';
2
2
  import { FieldValue, EntityRow, EventPayload } from '@almadar/core';
3
3
  export { AssetLoadStatus, BridgeHealth, CheckStatus, EffectTrace, EventLogEntry, OrbitalVerificationAPI, ServerResponseTrace, TraitStateSnapshot, TransitionTrace, VerificationCheck, VerificationSnapshot, VerificationSummary } from '@almadar/core';
4
- import '../paintDispatch-BXJgISot.cjs';
4
+ import '../paintDispatch-Bl2sfRFb.cjs';
5
5
  import 'clsx';
6
6
 
7
7
  /**
@@ -311,6 +311,24 @@ declare function formatDateTime(value: FieldValue | undefined): string;
311
311
  * of the declared format (a raw `true`/`false` cell is never intended output).
312
312
  */
313
313
  declare function formatValue(value: FieldValue | undefined, format?: string): string;
314
+ /** Sort direction for {@link sortRows}. */
315
+ type SortDirection = 'asc' | 'desc';
316
+ /**
317
+ * Order two cell values by their own type, never by what the field is called.
318
+ *
319
+ * Numbers compare numerically, date-like strings chronologically, everything
320
+ * else by locale string order. `null`/`undefined` sort last in both directions
321
+ * so empty cells never displace real data at the top of a list.
322
+ */
323
+ declare function compareCellValues(a: FieldValue | undefined, b: FieldValue | undefined): number;
324
+ /**
325
+ * Return a new array ordered by `field`. Non-mutating, and a no-op without a
326
+ * field so callers can pass the prop through unconditionally.
327
+ *
328
+ * NOTE: this orders only the rows already fetched. A collection larger than its
329
+ * `limit` still needs ordering at the data layer — see `L-NO-COLLECTION-ORDERING`.
330
+ */
331
+ declare function sortRows<T extends Record<string, FieldValue | undefined>>(rows: readonly T[], field?: string, direction?: SortDirection): readonly T[];
314
332
 
315
333
  /**
316
334
  * Get Nested Value Utility
@@ -531,4 +549,4 @@ declare function eightPointedStarPath(cx: number, cy: number, outerR: number, in
531
549
  */
532
550
  declare function arrowheadPath(size: number): string;
533
551
 
534
- export { ApiError, type DebugEvent, type DebugEventType, type EntitySnapshot, type EntityState, type GuardContext, type GuardEvaluation, JAZARI_COLORS, type JazariArmLayout, type JazariEffectInfo, type JazariGearLayout, type JazariGuardInfo, type JazariLayout, type LayoutInput, type LayoutState, type LayoutTransition, type PersistentEntityInfo, type RuntimeEntity, type TickExecution, type TraitDebugInfo, type TraitGuard, type TraitTransition, type ValueFormat, apiClient, arrowheadPath, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, formatDate, formatDateTime, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, pipeIconPath, recordGuardEvaluation, registerTick, registerTrait, setDebugEnabled, setEntityProvider, setTickActive, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState };
552
+ export { ApiError, type DebugEvent, type DebugEventType, type EntitySnapshot, type EntityState, type GuardContext, type GuardEvaluation, JAZARI_COLORS, type JazariArmLayout, type JazariEffectInfo, type JazariGearLayout, type JazariGuardInfo, type JazariLayout, type LayoutInput, type LayoutState, type LayoutTransition, type PersistentEntityInfo, type RuntimeEntity, type SortDirection, type TickExecution, type TraitDebugInfo, type TraitGuard, type TraitTransition, type ValueFormat, apiClient, arrowheadPath, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, compareCellValues, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, formatDate, formatDateTime, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, pipeIconPath, recordGuardEvaluation, registerTick, registerTrait, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState };
@@ -1,7 +1,7 @@
1
- export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseMarkdownWithCodeBlocks, B as recordServerResponse, F as recordTransition, G as registerCheck, H as registerTraitSnapshot, I as renderStateMachineToDomData, J as renderStateMachineToSvg, K as subscribeToVerification, L as updateAssetStatus, M as updateBridgeHealth, N as updateCheck, O as waitForTransition } from '../cn-Dm0VrLRG.js';
1
+ export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseMarkdownWithCodeBlocks, B as recordServerResponse, F as recordTransition, G as registerCheck, H as registerTraitSnapshot, I as renderStateMachineToDomData, J as renderStateMachineToSvg, K as subscribeToVerification, L as updateAssetStatus, M as updateBridgeHealth, N as updateCheck, O as waitForTransition } from '../cn-CZq0uJLA.js';
2
2
  import { FieldValue, EntityRow, EventPayload } from '@almadar/core';
3
3
  export { AssetLoadStatus, BridgeHealth, CheckStatus, EffectTrace, EventLogEntry, OrbitalVerificationAPI, ServerResponseTrace, TraitStateSnapshot, TransitionTrace, VerificationCheck, VerificationSnapshot, VerificationSummary } from '@almadar/core';
4
- import '../paintDispatch-BXJgISot.js';
4
+ import '../paintDispatch-Bl2sfRFb.js';
5
5
  import 'clsx';
6
6
 
7
7
  /**
@@ -311,6 +311,24 @@ declare function formatDateTime(value: FieldValue | undefined): string;
311
311
  * of the declared format (a raw `true`/`false` cell is never intended output).
312
312
  */
313
313
  declare function formatValue(value: FieldValue | undefined, format?: string): string;
314
+ /** Sort direction for {@link sortRows}. */
315
+ type SortDirection = 'asc' | 'desc';
316
+ /**
317
+ * Order two cell values by their own type, never by what the field is called.
318
+ *
319
+ * Numbers compare numerically, date-like strings chronologically, everything
320
+ * else by locale string order. `null`/`undefined` sort last in both directions
321
+ * so empty cells never displace real data at the top of a list.
322
+ */
323
+ declare function compareCellValues(a: FieldValue | undefined, b: FieldValue | undefined): number;
324
+ /**
325
+ * Return a new array ordered by `field`. Non-mutating, and a no-op without a
326
+ * field so callers can pass the prop through unconditionally.
327
+ *
328
+ * NOTE: this orders only the rows already fetched. A collection larger than its
329
+ * `limit` still needs ordering at the data layer — see `L-NO-COLLECTION-ORDERING`.
330
+ */
331
+ declare function sortRows<T extends Record<string, FieldValue | undefined>>(rows: readonly T[], field?: string, direction?: SortDirection): readonly T[];
314
332
 
315
333
  /**
316
334
  * Get Nested Value Utility
@@ -531,4 +549,4 @@ declare function eightPointedStarPath(cx: number, cy: number, outerR: number, in
531
549
  */
532
550
  declare function arrowheadPath(size: number): string;
533
551
 
534
- export { ApiError, type DebugEvent, type DebugEventType, type EntitySnapshot, type EntityState, type GuardContext, type GuardEvaluation, JAZARI_COLORS, type JazariArmLayout, type JazariEffectInfo, type JazariGearLayout, type JazariGuardInfo, type JazariLayout, type LayoutInput, type LayoutState, type LayoutTransition, type PersistentEntityInfo, type RuntimeEntity, type TickExecution, type TraitDebugInfo, type TraitGuard, type TraitTransition, type ValueFormat, apiClient, arrowheadPath, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, formatDate, formatDateTime, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, pipeIconPath, recordGuardEvaluation, registerTick, registerTrait, setDebugEnabled, setEntityProvider, setTickActive, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState };
552
+ export { ApiError, type DebugEvent, type DebugEventType, type EntitySnapshot, type EntityState, type GuardContext, type GuardEvaluation, JAZARI_COLORS, type JazariArmLayout, type JazariEffectInfo, type JazariGearLayout, type JazariGuardInfo, type JazariLayout, type LayoutInput, type LayoutState, type LayoutTransition, type PersistentEntityInfo, type RuntimeEntity, type SortDirection, type TickExecution, type TraitDebugInfo, type TraitGuard, type TraitTransition, type ValueFormat, apiClient, arrowheadPath, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, compareCellValues, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, formatDate, formatDateTime, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllTicks, getAllTraits, getDebugEvents, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getTick, getTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, pipeIconPath, recordGuardEvaluation, registerTick, registerTrait, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, toggleDebug, unregisterTick, unregisterTrait, updateGuardResult, updateTickExecution, updateTraitState };
package/dist/lib/index.js CHANGED
@@ -838,6 +838,32 @@ function formatValue(value, format) {
838
838
  return String(value);
839
839
  }
840
840
  }
841
+ function compareCellValues(a, b) {
842
+ const aEmpty = a === null || a === void 0 || a === "";
843
+ const bEmpty = b === null || b === void 0 || b === "";
844
+ if (aEmpty || bEmpty) return aEmpty && bEmpty ? 0 : aEmpty ? 1 : -1;
845
+ if (typeof a === "number" && typeof b === "number") return a - b;
846
+ if (typeof a === "boolean" && typeof b === "boolean") return Number(a) - Number(b);
847
+ const aNum = Number(a);
848
+ const bNum = Number(b);
849
+ if (Number.isFinite(aNum) && Number.isFinite(bNum)) return aNum - bNum;
850
+ const aTime = dateLikeTime(a);
851
+ const bTime = dateLikeTime(b);
852
+ if (aTime !== null && bTime !== null) return aTime - bTime;
853
+ return String(a).localeCompare(String(b));
854
+ }
855
+ function dateLikeTime(value) {
856
+ if (value instanceof Date) return value.getTime();
857
+ const text = String(value);
858
+ if (!/\d/.test(text) || !/[-/:T]/.test(text)) return null;
859
+ const time = Date.parse(text);
860
+ return Number.isNaN(time) ? null : time;
861
+ }
862
+ function sortRows(rows, field, direction = "asc") {
863
+ if (!field) return rows;
864
+ const dir = direction === "desc" ? -1 : 1;
865
+ return [...rows].sort((a, b) => dir * compareCellValues(a?.[field], b?.[field]));
866
+ }
841
867
 
842
868
  // lib/getNestedValue.ts
843
869
  function getNestedValue(obj, path) {
@@ -1895,4 +1921,4 @@ var JAZARI_COLORS = {
1895
1921
  darkBg: "#1a1a2e"
1896
1922
  };
1897
1923
 
1898
- export { ApiError, DEFAULT_CONFIG, JAZARI_COLORS, apiClient, arrowheadPath, bindCanvasCapture, bindEventBus, bindLastDrawables, bindTraitStateGetter, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, extractOutputsFromTransitions, extractStateMachine, formatDate, formatDateTime, formatGuard, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTraitSnapshots, getTransitions, getTransitionsForTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseMarkdownWithCodeBlocks, pipeIconPath, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, registerTraitSnapshot, renderStateMachineToDomData, renderStateMachineToSvg, setDebugEnabled, setEntityProvider, setTickActive, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, waitForTransition };
1924
+ export { ApiError, DEFAULT_CONFIG, JAZARI_COLORS, apiClient, arrowheadPath, bindCanvasCapture, bindEventBus, bindLastDrawables, bindTraitStateGetter, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, compareCellValues, computeJazariLayout, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, extractOutputsFromTransitions, extractStateMachine, formatDate, formatDateTime, formatGuard, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTraitSnapshots, getTransitions, getTransitionsForTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseMarkdownWithCodeBlocks, pipeIconPath, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, registerTraitSnapshot, renderStateMachineToDomData, renderStateMachineToSvg, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, waitForTransition };
@@ -100,16 +100,16 @@ interface DrawSpriteProps extends DrawableBase {
100
100
  * ONE descriptor (`DrawShapeProps`, grounded in core `ScenePos`) with TWO
101
101
  * backends: `paintShape` (2D, here) and an R3F ground-plane mesh (`Shape3D` in
102
102
  * `lib/drawable/mesh3d`, kept OUT of this file so the 2D path never pulls R3F).
103
- * Paints a cell footprint, an axis-aligned rect, an ellipse, or a poly at a scene
104
- * position, fill and/or stroke. Genre uses (tile fallback, iso/hex diamond
105
- * fallback, cell highlight, feature disc, unit selection ring, unit fallback
106
- * circle, ground/ghost discs, solid backgrounds, side-view platform rects) are
107
- * all this atom with different `shape`/`anchor`/geometry — composed in `.lolo`,
108
- * not here. The React component renders `null`; it exists so the pattern pipeline
103
+ * Paints a cell footprint, an axis-aligned rect, an ellipse, a poly, or an SVG
104
+ * path at a scene position, fill and/or stroke. Genre uses (tile fallback, iso/hex
105
+ * diamond fallback, cell highlight, feature disc, unit selection ring, unit
106
+ * fallback circle, ground/ghost discs, solid backgrounds, side-view platform
107
+ * rects, hand-authored vector art) are all this atom with different
108
+ * `shape`/`anchor`/geometry — composed in `.lolo`, not here. The React component renders `null`; it exists so the pattern pipeline
109
109
  * registers a `draw-shape` pattern and standalone pages stay inspectable.
110
110
  */
111
111
 
112
- type ShapeKind = 'cell' | 'rect' | 'ellipse' | 'poly';
112
+ type ShapeKind = 'cell' | 'rect' | 'ellipse' | 'poly' | 'path';
113
113
  interface DrawShapeProps extends DrawableBase {
114
114
  type: 'draw-shape';
115
115
  shape: ShapeKind;
@@ -130,6 +130,8 @@ interface DrawShapeProps extends DrawableBase {
130
130
  offsetY?: number;
131
131
  /** Poly vertices as world-unit offsets relative to the cell's projected top-left. */
132
132
  points?: PainterPoint[];
133
+ /** SVG path data in world units relative to the cell's projected top-left — same coordinate convention as `points`. */
134
+ d?: string;
133
135
  fill?: string;
134
136
  stroke?: string;
135
137
  strokeWidth?: number;
@@ -162,6 +164,33 @@ interface DrawTextProps extends DrawableBase {
162
164
  opacity?: number;
163
165
  }
164
166
 
167
+ /**
168
+ * `draw-group` — the drawable CONTAINER atom (dimension-agnostic).
169
+ *
170
+ * Multi-shape art (a hero token = cloak + head + sword shapes) travels as ONE
171
+ * node: the host paints the group by translating to its projected position,
172
+ * applying `scale`/`rotate`/`opacity`, then painting each `items` descriptor
173
+ * through the normal dispatch. `items` is a plain data prop (NOT `children`,
174
+ * which UISlotRenderer special-cases) — same convention as the `draw-*-layer`
175
+ * molecules. The React component renders `null`; it exists so the pattern
176
+ * pipeline registers a `draw-group` pattern and standalone pages stay
177
+ * inspectable. 2D-canvas only — the 3D backend skips it with a warn.
178
+ */
179
+
180
+ interface DrawGroupProps extends DrawableBase {
181
+ type: 'draw-group';
182
+ /** Logical scene position; the projector maps it to pixels / world. */
183
+ position: ScenePos;
184
+ /** Uniform scale applied to the whole group. */
185
+ scale?: number;
186
+ /** Rotation in radians (painter units). */
187
+ rotate?: number;
188
+ /** 0..1 opacity. */
189
+ opacity?: number;
190
+ /** The grouped drawables, painted through the normal dispatch. */
191
+ items: DrawableNode[];
192
+ }
193
+
165
194
  /**
166
195
  * `draw-sprite-layer` — batch multiple sprites in one descriptor for O(layers) rendering.
167
196
  *
@@ -218,6 +247,6 @@ interface DrawTextLayerProps extends DrawableBase {
218
247
  */
219
248
 
220
249
  /** Every drawable descriptor. The host's `children` are a `DrawableNode[]`. */
221
- type DrawableNode = DrawSpriteProps | DrawShapeProps | DrawTextProps | DrawSpriteLayerProps | DrawShapeLayerProps | DrawTextLayerProps;
250
+ type DrawableNode = DrawSpriteProps | DrawShapeProps | DrawTextProps | DrawGroupProps | DrawSpriteLayerProps | DrawShapeLayerProps | DrawTextLayerProps;
222
251
 
223
252
  export type { DrawableNode as D };
@@ -100,16 +100,16 @@ interface DrawSpriteProps extends DrawableBase {
100
100
  * ONE descriptor (`DrawShapeProps`, grounded in core `ScenePos`) with TWO
101
101
  * backends: `paintShape` (2D, here) and an R3F ground-plane mesh (`Shape3D` in
102
102
  * `lib/drawable/mesh3d`, kept OUT of this file so the 2D path never pulls R3F).
103
- * Paints a cell footprint, an axis-aligned rect, an ellipse, or a poly at a scene
104
- * position, fill and/or stroke. Genre uses (tile fallback, iso/hex diamond
105
- * fallback, cell highlight, feature disc, unit selection ring, unit fallback
106
- * circle, ground/ghost discs, solid backgrounds, side-view platform rects) are
107
- * all this atom with different `shape`/`anchor`/geometry — composed in `.lolo`,
108
- * not here. The React component renders `null`; it exists so the pattern pipeline
103
+ * Paints a cell footprint, an axis-aligned rect, an ellipse, a poly, or an SVG
104
+ * path at a scene position, fill and/or stroke. Genre uses (tile fallback, iso/hex
105
+ * diamond fallback, cell highlight, feature disc, unit selection ring, unit
106
+ * fallback circle, ground/ghost discs, solid backgrounds, side-view platform
107
+ * rects, hand-authored vector art) are all this atom with different
108
+ * `shape`/`anchor`/geometry — composed in `.lolo`, not here. The React component renders `null`; it exists so the pattern pipeline
109
109
  * registers a `draw-shape` pattern and standalone pages stay inspectable.
110
110
  */
111
111
 
112
- type ShapeKind = 'cell' | 'rect' | 'ellipse' | 'poly';
112
+ type ShapeKind = 'cell' | 'rect' | 'ellipse' | 'poly' | 'path';
113
113
  interface DrawShapeProps extends DrawableBase {
114
114
  type: 'draw-shape';
115
115
  shape: ShapeKind;
@@ -130,6 +130,8 @@ interface DrawShapeProps extends DrawableBase {
130
130
  offsetY?: number;
131
131
  /** Poly vertices as world-unit offsets relative to the cell's projected top-left. */
132
132
  points?: PainterPoint[];
133
+ /** SVG path data in world units relative to the cell's projected top-left — same coordinate convention as `points`. */
134
+ d?: string;
133
135
  fill?: string;
134
136
  stroke?: string;
135
137
  strokeWidth?: number;
@@ -162,6 +164,33 @@ interface DrawTextProps extends DrawableBase {
162
164
  opacity?: number;
163
165
  }
164
166
 
167
+ /**
168
+ * `draw-group` — the drawable CONTAINER atom (dimension-agnostic).
169
+ *
170
+ * Multi-shape art (a hero token = cloak + head + sword shapes) travels as ONE
171
+ * node: the host paints the group by translating to its projected position,
172
+ * applying `scale`/`rotate`/`opacity`, then painting each `items` descriptor
173
+ * through the normal dispatch. `items` is a plain data prop (NOT `children`,
174
+ * which UISlotRenderer special-cases) — same convention as the `draw-*-layer`
175
+ * molecules. The React component renders `null`; it exists so the pattern
176
+ * pipeline registers a `draw-group` pattern and standalone pages stay
177
+ * inspectable. 2D-canvas only — the 3D backend skips it with a warn.
178
+ */
179
+
180
+ interface DrawGroupProps extends DrawableBase {
181
+ type: 'draw-group';
182
+ /** Logical scene position; the projector maps it to pixels / world. */
183
+ position: ScenePos;
184
+ /** Uniform scale applied to the whole group. */
185
+ scale?: number;
186
+ /** Rotation in radians (painter units). */
187
+ rotate?: number;
188
+ /** 0..1 opacity. */
189
+ opacity?: number;
190
+ /** The grouped drawables, painted through the normal dispatch. */
191
+ items: DrawableNode[];
192
+ }
193
+
165
194
  /**
166
195
  * `draw-sprite-layer` — batch multiple sprites in one descriptor for O(layers) rendering.
167
196
  *
@@ -218,6 +247,6 @@ interface DrawTextLayerProps extends DrawableBase {
218
247
  */
219
248
 
220
249
  /** Every drawable descriptor. The host's `children` are a `DrawableNode[]`. */
221
- type DrawableNode = DrawSpriteProps | DrawShapeProps | DrawTextProps | DrawSpriteLayerProps | DrawShapeLayerProps | DrawTextLayerProps;
250
+ type DrawableNode = DrawSpriteProps | DrawShapeProps | DrawTextProps | DrawGroupProps | DrawSpriteLayerProps | DrawShapeLayerProps | DrawTextLayerProps;
222
251
 
223
252
  export type { DrawableNode as D };