@almadar/ui 5.65.0 → 5.67.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.
package/dist/avl/index.js CHANGED
@@ -46,7 +46,7 @@ import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoade
46
46
  import { clone } from 'three/examples/jsm/utils/SkeletonUtils';
47
47
  import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
48
48
  import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
49
- import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1, isEntityAwarePattern } from '@almadar/patterns';
49
+ import { getPatternDefinition, getComponentForPattern, isEntityAwarePattern } from '@almadar/patterns';
50
50
  import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
51
51
  import { InMemoryPersistence, StateMachineManager, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, createContextFromBindings } from '@almadar/runtime';
52
52
 
@@ -11755,6 +11755,8 @@ var init_DialogueBubble = __esm({
11755
11755
  function ChoiceButton({
11756
11756
  text = "Charge forward into the fray",
11757
11757
  index,
11758
+ assetUrl,
11759
+ icon,
11758
11760
  disabled = false,
11759
11761
  selected = false,
11760
11762
  onClick,
@@ -11787,6 +11789,23 @@ function ChoiceButton({
11787
11789
  ]
11788
11790
  }
11789
11791
  ),
11792
+ assetUrl ? /* @__PURE__ */ jsx(
11793
+ "img",
11794
+ {
11795
+ src: assetUrl,
11796
+ alt: "",
11797
+ width: 16,
11798
+ height: 16,
11799
+ style: { imageRendering: "pixelated", objectFit: "contain" },
11800
+ className: "flex-shrink-0"
11801
+ }
11802
+ ) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-sm", children: typeof icon === "string" ? (() => {
11803
+ const I = resolveIcon(icon);
11804
+ return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : null;
11805
+ })() : /* @__PURE__ */ (() => {
11806
+ const I = icon;
11807
+ return /* @__PURE__ */ jsx(I, { className: "w-4 h-4" });
11808
+ })() }) : null,
11790
11809
  /* @__PURE__ */ jsx("span", { className: "text-sm leading-snug", children: text })
11791
11810
  ]
11792
11811
  }
@@ -11795,6 +11814,7 @@ function ChoiceButton({
11795
11814
  var init_ChoiceButton = __esm({
11796
11815
  "components/game/atoms/ChoiceButton.tsx"() {
11797
11816
  init_cn();
11817
+ init_Icon();
11798
11818
  ChoiceButton.displayName = "ChoiceButton";
11799
11819
  }
11800
11820
  });
@@ -14943,7 +14963,8 @@ function IsometricCanvas({
14943
14963
  const minX = Math.min(...allScreenPos.map((p2) => p2.x));
14944
14964
  const maxX = Math.max(...allScreenPos.map((p2) => p2.x + scaledTileWidth));
14945
14965
  const minY = Math.min(...allScreenPos.map((p2) => p2.y));
14946
- const maxY = Math.max(...allScreenPos.map((p2) => p2.y + scaledTileHeight));
14966
+ const tileBottomExtent = tileLayout === "hex" ? scaledTileWidth : scaledTileHeight;
14967
+ const maxY = Math.max(...allScreenPos.map((p2) => p2.y + tileBottomExtent));
14947
14968
  const worldW = maxX - minX;
14948
14969
  const worldH = maxY - minY;
14949
14970
  const scaleM = Math.min(mW / worldW, mH / worldH) * 0.9;
@@ -15035,7 +15056,7 @@ function IsometricCanvas({
15035
15056
  const drawW = scaledTileWidth;
15036
15057
  const drawH = scaledTileWidth * (img.naturalHeight / img.naturalWidth);
15037
15058
  const drawX = pos.x;
15038
- const drawY = pos.y + scaledTileHeight - drawH;
15059
+ const drawY = tileLayout === "hex" ? pos.y : pos.y + scaledTileHeight - drawH;
15039
15060
  ctx.drawImage(img, drawX, drawY, drawW, drawH);
15040
15061
  }
15041
15062
  } else {
@@ -30958,6 +30979,7 @@ function PowerupSlots({
30958
30979
  /* @__PURE__ */ jsx(
30959
30980
  ItemSlot,
30960
30981
  {
30982
+ assetUrl: powerup.assetUrl,
30961
30983
  icon: powerup.icon,
30962
30984
  label: powerup.label,
30963
30985
  rarity: "uncommon",
@@ -31207,13 +31229,26 @@ function HealthPanel({
31207
31229
  )
31208
31230
  }
31209
31231
  ),
31210
- effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsx(
31232
+ effects && effects.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1 flex-wrap", children: effects.map((effect, i) => /* @__PURE__ */ jsxs(
31211
31233
  Badge,
31212
31234
  {
31213
31235
  variant: effectVariantMap[effect.variant ?? "neutral"],
31214
31236
  size: "sm",
31215
- icon: effect.icon,
31216
- children: effect.label
31237
+ icon: effect.assetUrl ? void 0 : effect.icon,
31238
+ children: [
31239
+ effect.assetUrl && /* @__PURE__ */ jsx(
31240
+ "img",
31241
+ {
31242
+ src: effect.assetUrl,
31243
+ alt: "",
31244
+ width: 12,
31245
+ height: 12,
31246
+ style: { imageRendering: "pixelated", objectFit: "contain" },
31247
+ className: "flex-shrink-0 inline-block"
31248
+ }
31249
+ ),
31250
+ effect.label
31251
+ ]
31217
31252
  },
31218
31253
  i
31219
31254
  )) })
@@ -31396,15 +31431,28 @@ function TurnPanel({
31396
31431
  activeTeam
31397
31432
  }
31398
31433
  ),
31399
- actions && actions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsx(
31434
+ actions && actions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "flex items-center gap-1.5 ml-auto", children: actions.map((action, i) => /* @__PURE__ */ jsxs(
31400
31435
  Button,
31401
31436
  {
31402
31437
  variant: "ghost",
31403
31438
  size: "sm",
31404
31439
  disabled: action.disabled,
31405
- leftIcon: action.icon,
31440
+ leftIcon: action.assetUrl ? void 0 : action.icon,
31406
31441
  onClick: () => handleAction(action.event),
31407
- children: action.label
31442
+ children: [
31443
+ action.assetUrl && /* @__PURE__ */ jsx(
31444
+ "img",
31445
+ {
31446
+ src: action.assetUrl,
31447
+ alt: "",
31448
+ width: 14,
31449
+ height: 14,
31450
+ style: { imageRendering: "pixelated", objectFit: "contain" },
31451
+ className: "flex-shrink-0"
31452
+ }
31453
+ ),
31454
+ action.label
31455
+ ]
31408
31456
  },
31409
31457
  i
31410
31458
  )) })
@@ -45911,9 +45959,9 @@ var init_GameCanvas3D2 = __esm({
45911
45959
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
45912
45960
  const hasAtlas = unitAtlasUrl(unit) !== null;
45913
45961
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
45914
- const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
45915
- const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
45916
- const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
45962
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale * gridConfig.cellSize;
45963
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale * gridConfig.cellSize;
45964
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale * gridConfig.cellSize;
45917
45965
  return /* @__PURE__ */ jsxs(
45918
45966
  "group",
45919
45967
  {
@@ -45960,7 +46008,7 @@ var init_GameCanvas3D2 = __esm({
45960
46008
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
45961
46009
  ] })
45962
46010
  ] }),
45963
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, 1.2, 0], children: [
46011
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, billboardHeight, 0], children: [
45964
46012
  /* @__PURE__ */ jsxs("mesh", { position: [-0.25, 0, 0], children: [
45965
46013
  /* @__PURE__ */ jsx("planeGeometry", { args: [0.5, 0.05] }),
45966
46014
  /* @__PURE__ */ jsx("meshBasicMaterial", { color: 3355443 })
@@ -45989,7 +46037,7 @@ var init_GameCanvas3D2 = __esm({
45989
46037
  }
45990
46038
  );
45991
46039
  },
45992
- [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
46040
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale, gridConfig]
45993
46041
  );
45994
46042
  const DefaultFeatureRenderer = useCallback(
45995
46043
  ({
@@ -46077,7 +46125,7 @@ var init_GameCanvas3D2 = __esm({
46077
46125
  {
46078
46126
  ref: containerRef,
46079
46127
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
46080
- style: { height: "85vh" },
46128
+ style: { flex: "1 1 0", minHeight: "400px" },
46081
46129
  "data-orientation": orientation,
46082
46130
  "data-camera-mode": cameraMode,
46083
46131
  "data-overlay": overlay,
@@ -46377,13 +46425,39 @@ var init_GameBoard3D = __esm({
46377
46425
  GameBoard3D.displayName = "GameBoard3D";
46378
46426
  }
46379
46427
  });
46380
- var GameShell;
46428
+ function getSlotContentRenderer2() {
46429
+ if (_scr) return _scr;
46430
+ const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
46431
+ _scr = mod.SlotContentRenderer;
46432
+ return _scr;
46433
+ }
46434
+ function resolveDescriptor(value, idPrefix) {
46435
+ if (value === null || value === void 0) return value;
46436
+ if (React93__default.isValidElement(value)) return value;
46437
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
46438
+ if (Array.isArray(value)) {
46439
+ return value.map((item, i) => /* @__PURE__ */ jsx(React93__default.Fragment, { children: resolveDescriptor(item, `${idPrefix}-${i}`) }, i));
46440
+ }
46441
+ if (typeof value === "object") {
46442
+ const rec = value;
46443
+ if (typeof rec.type === "string" && getComponentForPattern(rec.type) !== null) {
46444
+ const { type, props: nestedProps, _id, ...flatProps } = rec;
46445
+ const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
46446
+ const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
46447
+ const SCR = getSlotContentRenderer2();
46448
+ return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 });
46449
+ }
46450
+ }
46451
+ return null;
46452
+ }
46453
+ var _scr, GameShell;
46381
46454
  var init_GameShell = __esm({
46382
46455
  "components/game/templates/GameShell.tsx"() {
46383
46456
  init_cn();
46384
46457
  init_Box();
46385
46458
  init_Stack();
46386
46459
  init_Typography();
46460
+ _scr = null;
46387
46461
  GameShell = ({
46388
46462
  appName = "Game",
46389
46463
  hud,
@@ -46432,7 +46506,7 @@ var init_GameShell = __esm({
46432
46506
  children: appName
46433
46507
  }
46434
46508
  ),
46435
- hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", children: hud })
46509
+ hud && /* @__PURE__ */ jsx(Box, { className: "game-shell__hud", children: resolveDescriptor(hud, "gs-hud") })
46436
46510
  ]
46437
46511
  }
46438
46512
  ),
@@ -46445,7 +46519,7 @@ var init_GameShell = __esm({
46445
46519
  overflow: "hidden",
46446
46520
  position: "relative"
46447
46521
  },
46448
- children
46522
+ children: resolveDescriptor(children, "gs-children")
46449
46523
  }
46450
46524
  )
46451
46525
  ]
@@ -46455,7 +46529,32 @@ var init_GameShell = __esm({
46455
46529
  GameShell.displayName = "GameShell";
46456
46530
  }
46457
46531
  });
46458
- var GameTemplate;
46532
+ function getSlotContentRenderer3() {
46533
+ if (_scr2) return _scr2;
46534
+ const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
46535
+ _scr2 = mod.SlotContentRenderer;
46536
+ return _scr2;
46537
+ }
46538
+ function resolveDescriptor2(value, idPrefix) {
46539
+ if (value === null || value === void 0) return value;
46540
+ if (React93__default.isValidElement(value)) return value;
46541
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
46542
+ if (Array.isArray(value)) {
46543
+ return value.map((item, i) => /* @__PURE__ */ jsx(React93__default.Fragment, { children: resolveDescriptor2(item, `${idPrefix}-${i}`) }, i));
46544
+ }
46545
+ if (typeof value === "object") {
46546
+ const rec = value;
46547
+ if (typeof rec.type === "string" && getComponentForPattern(rec.type) !== null) {
46548
+ const { type, props: nestedProps, _id, ...flatProps } = rec;
46549
+ const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
46550
+ const content = { id: _id ?? idPrefix, pattern: type, props: resolvedProps, priority: 0 };
46551
+ const SCR = getSlotContentRenderer3();
46552
+ return /* @__PURE__ */ jsx(SCR, { content, onDismiss: () => void 0 });
46553
+ }
46554
+ }
46555
+ return null;
46556
+ }
46557
+ var _scr2, GameTemplate;
46459
46558
  var init_GameTemplate = __esm({
46460
46559
  "components/game/templates/GameTemplate.tsx"() {
46461
46560
  init_cn();
@@ -46463,6 +46562,7 @@ var init_GameTemplate = __esm({
46463
46562
  init_Stack();
46464
46563
  init_Typography();
46465
46564
  init_Button();
46565
+ _scr2 = null;
46466
46566
  GameTemplate = ({
46467
46567
  entity,
46468
46568
  title = "Game",
@@ -46530,13 +46630,13 @@ var init_GameTemplate = __esm({
46530
46630
  fullWidth: true,
46531
46631
  className: "flex-1 bg-muted",
46532
46632
  children: [
46533
- children,
46633
+ resolveDescriptor2(children, "gt-children"),
46534
46634
  hud && /* @__PURE__ */ jsx(
46535
46635
  Box,
46536
46636
  {
46537
46637
  position: "absolute",
46538
46638
  className: "top-0 left-0 right-0 pointer-events-none",
46539
- children: /* @__PURE__ */ jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: hud })
46639
+ children: /* @__PURE__ */ jsx(Box, { padding: "md", className: "pointer-events-auto w-fit", children: resolveDescriptor2(hud, "gt-hud") })
46540
46640
  }
46541
46641
  )
46542
46642
  ]
@@ -46561,7 +46661,7 @@ var init_GameTemplate = __esm({
46561
46661
  children: /* @__PURE__ */ jsx(Typography, { variant: "h6", children: "Debug Panel" })
46562
46662
  }
46563
46663
  ),
46564
- /* @__PURE__ */ jsx(Box, { padding: "md", children: debugPanel })
46664
+ /* @__PURE__ */ jsx(Box, { padding: "md", children: resolveDescriptor2(debugPanel, "gt-debug") })
46565
46665
  ]
46566
46666
  }
46567
46667
  )
@@ -55140,8 +55240,8 @@ function getSlotFallback(slot, config) {
55140
55240
  const variant = SLOT_SKELETON_MAP[slot] ?? "text";
55141
55241
  return /* @__PURE__ */ jsx(Skeleton, { variant });
55142
55242
  }
55143
- function getComponentForPattern(patternType) {
55144
- const mapping = getComponentForPattern$1(patternType);
55243
+ function getComponentForPattern3(patternType) {
55244
+ const mapping = getComponentForPattern(patternType);
55145
55245
  if (!mapping) {
55146
55246
  return null;
55147
55247
  }
@@ -55663,7 +55763,7 @@ function isPatternConfig(value) {
55663
55763
  if (value instanceof Date) return false;
55664
55764
  if (typeof value === "function") return false;
55665
55765
  const record = value;
55666
- return "type" in record && typeof record.type === "string" && getComponentForPattern$1(record.type) !== null;
55766
+ return "type" in record && typeof record.type === "string" && getComponentForPattern(record.type) !== null;
55667
55767
  }
55668
55768
  function isPlainConfigObject(value) {
55669
55769
  if (React93__default.isValidElement(value)) return false;
@@ -55771,7 +55871,8 @@ function SlotContentRenderer({
55771
55871
  entityDef = schemaCtx.entities.get(linkedEntity);
55772
55872
  }
55773
55873
  }
55774
- const PatternComponent = getComponentForPattern(content.pattern);
55874
+ const orbitalName = schemaCtx && content.sourceTrait !== void 0 ? schemaCtx.orbitalsByTrait.get(content.sourceTrait) : void 0;
55875
+ const PatternComponent = getComponentForPattern3(content.pattern);
55775
55876
  if (PatternComponent) {
55776
55877
  const childrenConfig = content.props.children;
55777
55878
  const isSingleChild = typeof childrenConfig === "string" || typeof childrenConfig === "object" && childrenConfig !== null && !Array.isArray(childrenConfig) && "type" in childrenConfig;
@@ -55869,6 +55970,7 @@ function SlotContentRenderer({
55869
55970
  "data-orb-entity": content.entity,
55870
55971
  "data-orb-path": myPath,
55871
55972
  "data-orb-pattern": content.pattern,
55973
+ "data-orb-orbital": orbitalName,
55872
55974
  children: renderedChildren !== void 0 ? /* @__PURE__ */ jsx(PatternComponent, { ...finalProps, children: renderedChildren }) : /* @__PURE__ */ jsx(PatternComponent, { ...finalProps })
55873
55975
  }
55874
55976
  );
@@ -55888,6 +55990,7 @@ function SlotContentRenderer({
55888
55990
  "data-orb-entity": content.entity,
55889
55991
  "data-orb-path": patternPath ?? "root",
55890
55992
  "data-orb-pattern": content.pattern,
55993
+ "data-orb-orbital": orbitalName,
55891
55994
  children: content.props.children ?? /* @__PURE__ */ jsxs(Box, { className: "p-4 text-sm text-muted-foreground border border-dashed border-border rounded", children: [
55892
55995
  "Unknown pattern: ",
55893
55996
  content.pattern,
@@ -59530,7 +59633,7 @@ function resolveLambdaBindings(body, params, item, index) {
59530
59633
  return body;
59531
59634
  }
59532
59635
  var _slotContentRenderer2 = null;
59533
- function getSlotContentRenderer2() {
59636
+ function getSlotContentRenderer4() {
59534
59637
  if (_slotContentRenderer2) return _slotContentRenderer2;
59535
59638
  const mod = (init_UISlotRenderer(), __toCommonJS(UISlotRenderer_exports));
59536
59639
  _slotContentRenderer2 = mod.SlotContentRenderer;
@@ -59546,7 +59649,7 @@ function makeLambdaFn(params, lambdaBody, callerKey) {
59546
59649
  if (typeof record.type !== "string") {
59547
59650
  return null;
59548
59651
  }
59549
- const SlotContentRenderer2 = getSlotContentRenderer2();
59652
+ const SlotContentRenderer2 = getSlotContentRenderer4();
59550
59653
  const rawChildProps = {};
59551
59654
  for (const [k, v] of Object.entries(record)) {
59552
59655
  if (k !== "type") rawChildProps[k] = v;
@@ -61906,6 +62009,33 @@ function formatPayloadTooltip(fields) {
61906
62009
  );
61907
62010
  return `{ ${parts.join(", ")} }`;
61908
62011
  }
62012
+
62013
+ // components/avl/derive-edit-focus.ts
62014
+ function deriveEditFocusFromElement(el) {
62015
+ const orbitalEl = el.getAttribute("data-orb-orbital") !== null ? el : el.closest("[data-orb-orbital]");
62016
+ const orbital = orbitalEl?.getAttribute("data-orb-orbital") ?? "";
62017
+ if (!orbital) return null;
62018
+ const path = el.getAttribute("data-orb-path") ?? el.getAttribute("data-pattern-path");
62019
+ const patternType = el.getAttribute("data-orb-pattern") ?? el.getAttribute("data-pattern");
62020
+ const trait = el.getAttribute("data-orb-trait") ?? el.getAttribute("data-source-trait");
62021
+ const focus = {
62022
+ level: "node",
62023
+ orbital,
62024
+ label: patternType ?? trait ?? "element"
62025
+ };
62026
+ if (path !== null) focus.path = path;
62027
+ if (trait !== null) focus.trait = trait;
62028
+ if (patternType !== null) focus.patternType = patternType;
62029
+ const transition = el.getAttribute("data-orb-transition");
62030
+ if (transition !== null) focus.transition = transition;
62031
+ const state = el.getAttribute("data-orb-state");
62032
+ if (state !== null) focus.state = state;
62033
+ const slot = el.getAttribute("data-orb-slot");
62034
+ if (slot !== null) focus.slot = slot;
62035
+ const entity = el.getAttribute("data-orb-entity");
62036
+ if (entity !== null) focus.entity = entity;
62037
+ return focus;
62038
+ }
61909
62039
  function entityNameOf(ref) {
61910
62040
  if (!ref) return void 0;
61911
62041
  if (typeof ref === "string") return ref;
@@ -62191,29 +62321,6 @@ function rectRelativeTo(el, container, zoom) {
62191
62321
  height: (u.bottom - u.top) / z
62192
62322
  };
62193
62323
  }
62194
- function buildFocus(el, orbitalName) {
62195
- if (!orbitalName) return null;
62196
- const path = el.getAttribute("data-orb-path") ?? el.getAttribute("data-pattern-path");
62197
- const patternType = el.getAttribute("data-orb-pattern") ?? el.getAttribute("data-pattern");
62198
- const trait = el.getAttribute("data-orb-trait") ?? el.getAttribute("data-source-trait");
62199
- const focus = {
62200
- level: "node",
62201
- orbital: orbitalName,
62202
- label: patternType ?? trait ?? "element"
62203
- };
62204
- if (path !== null) focus.path = path;
62205
- if (trait !== null) focus.trait = trait;
62206
- if (patternType !== null) focus.patternType = patternType;
62207
- const transition = el.getAttribute("data-orb-transition");
62208
- if (transition !== null) focus.transition = transition;
62209
- const state = el.getAttribute("data-orb-state");
62210
- if (state !== null) focus.state = state;
62211
- const slot = el.getAttribute("data-orb-slot");
62212
- if (slot !== null) focus.slot = slot;
62213
- const entity = el.getAttribute("data-orb-entity");
62214
- if (entity !== null) focus.entity = entity;
62215
- return focus;
62216
- }
62217
62324
  var OrbPreviewNodeInner = (props) => {
62218
62325
  const data = props.data;
62219
62326
  const screenSize = useContext(ScreenSizeContext);
@@ -62282,7 +62389,7 @@ var OrbPreviewNodeInner = (props) => {
62282
62389
  nodeData: data,
62283
62390
  rect: rect ?? void 0
62284
62391
  });
62285
- const focus = buildFocus(patternEl, data.orbitalName);
62392
+ const focus = deriveEditFocusFromElement(patternEl);
62286
62393
  if (focus) eventBus.emit("UI:ELEMENT_SELECTED", { focus: { ...focus } });
62287
62394
  } else {
62288
62395
  setSelectedRect(null);
@@ -65523,4 +65630,4 @@ var AvlClickTarget = ({
65523
65630
  };
65524
65631
  AvlClickTarget.displayName = "AvlClickTarget";
65525
65632
 
65526
- export { AVL_FIELD_TYPE_SHAPES, AVL_OPERATOR_COLORS, AvlApplication, AvlBackwardEdge, AvlBehaviorGlyph, AvlBinding, AvlBindingEdge, AvlBindingRef, AvlClickTarget, AvlClosedCircuit, AvlCosmicZoom, AvlEffect, AvlEmitListen, AvlEntity, AvlEvent, AvlEventWireEdge, AvlExprTree, AvlField, AvlFieldType, AvlGuard, AvlLiteral, AvlOperator, AvlOrbital, AvlOrbitalNode, AvlOrbitalUnit, AvlOrbitalsCosmicZoom, AvlPage, AvlPageEdge, AvlPersistence, AvlSExpr, AvlSlotMap, AvlState, AvlStateMachine, AvlSwimLane, AvlTrait, AvlTraitScene, AvlTransition, AvlTransitionEdge, AvlTransitionLane, AvlTransitionScene, BehaviorComposeNode, BehaviorView, CONNECTION_COLORS, CanvasDndProvider, DOMAIN_COLORS, DetailView, EFFECT_CATEGORY_COLORS, EFFECT_TYPE_TO_CATEGORY, EventFlowEdge, FlowCanvas, MiniStateMachine, ModuleCard, OrbInspector, OrbPreviewNode, STATE_COLORS, SystemNode, ZOOM_BAND_THRESHOLDS, ZoomBandContext, ZoomBreadcrumb, ZoomLegend, arcPath, behaviorsToComposeGraph, computeTraitLayout, computeZoomBand, curveControlPoint, edgePath, getStateRole, gridPositions, orbitalToExpandedGraph, parseApplicationLevel, parseOrbitalLevel, parseTraitLevel, parseTransitionLevel, radialPositions, registryEntryToCanvasEntry, ringPositions, schemaToFlowGraph, schemaToOverviewGraph, useCanvasDraggable, useCanvasDroppable, useZoomBand, zoomProgress };
65633
+ export { AVL_FIELD_TYPE_SHAPES, AVL_OPERATOR_COLORS, AvlApplication, AvlBackwardEdge, AvlBehaviorGlyph, AvlBinding, AvlBindingEdge, AvlBindingRef, AvlClickTarget, AvlClosedCircuit, AvlCosmicZoom, AvlEffect, AvlEmitListen, AvlEntity, AvlEvent, AvlEventWireEdge, AvlExprTree, AvlField, AvlFieldType, AvlGuard, AvlLiteral, AvlOperator, AvlOrbital, AvlOrbitalNode, AvlOrbitalUnit, AvlOrbitalsCosmicZoom, AvlPage, AvlPageEdge, AvlPersistence, AvlSExpr, AvlSlotMap, AvlState, AvlStateMachine, AvlSwimLane, AvlTrait, AvlTraitScene, AvlTransition, AvlTransitionEdge, AvlTransitionLane, AvlTransitionScene, BehaviorComposeNode, BehaviorView, CONNECTION_COLORS, CanvasDndProvider, DOMAIN_COLORS, DetailView, EFFECT_CATEGORY_COLORS, EFFECT_TYPE_TO_CATEGORY, EventFlowEdge, FlowCanvas, MiniStateMachine, ModuleCard, OrbInspector, OrbPreviewNode, STATE_COLORS, SystemNode, ZOOM_BAND_THRESHOLDS, ZoomBandContext, ZoomBreadcrumb, ZoomLegend, arcPath, behaviorsToComposeGraph, computeTraitLayout, computeZoomBand, curveControlPoint, deriveEditFocusFromElement, edgePath, getStateRole, gridPositions, orbitalToExpandedGraph, parseApplicationLevel, parseOrbitalLevel, parseTraitLevel, parseTransitionLevel, radialPositions, registryEntryToCanvasEntry, ringPositions, schemaToFlowGraph, schemaToOverviewGraph, useCanvasDraggable, useCanvasDroppable, useZoomBand, zoomProgress };
@@ -0,0 +1,8 @@
1
+ import type { EditFocus } from '@almadar/core';
2
+ /**
3
+ * Build an `EditFocus` from a clicked element's `data-orb-*` address (stamped by
4
+ * UISlotRenderer). The owning orbital is read from the DOM (`data-orb-orbital`,
5
+ * walking up via `closest` when the clicked node itself doesn't carry it); since
6
+ * `EditFocus.orbital` is required, returns `null` when it can't be resolved.
7
+ */
8
+ export declare function deriveEditFocusFromElement(el: HTMLElement): EditFocus | null;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ChatBar Organism
3
+ *
4
+ * The always-visible bottom chat bar. A single-row input surface for talking
5
+ * to the agent: status icon, optional context badge, text input, and a
6
+ * status-driven action button (Send / Pause+Stop / Resume / Retry).
7
+ *
8
+ * The agent's activity stream lives in the dedicated Trace tab (see
9
+ * SubagentTracePanel). ChatBar emits generic EventBus events
10
+ * (`UI:CHAT_SEND`, `UI:ELEMENT_SELECTED`, plus the declarative `UI:*` actions
11
+ * the Button atom raises) — it owns no app-specific state.
12
+ */
13
+ import React from 'react';
14
+ import type { DisplayStateProps } from './types';
15
+ export type ChatBarStatus = 'idle' | 'running' | 'paused' | 'complete' | 'error';
16
+ export interface ChatBarProps extends DisplayStateProps {
17
+ /** Pipeline status */
18
+ status?: ChatBarStatus;
19
+ /** Currently active gate label, e.g. "Gate 2: State machines" */
20
+ activeGate?: string;
21
+ /** JEPA validity probability 0-1 */
22
+ jepaValidity?: number;
23
+ /** Input placeholder text */
24
+ placeholder?: string;
25
+ /** Agent context description */
26
+ context?: string;
27
+ }
28
+ export declare function ChatBar({ status, activeGate, jepaValidity, placeholder, context, className, }: ChatBarProps): React.ReactElement;
29
+ export declare namespace ChatBar {
30
+ var displayName: string;
31
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * SubagentTracePanel — contextual side panel that surfaces subagent activity.
3
+ *
4
+ * Density adapts to disclosure level:
5
+ * - L1/L2 (builder/designer): compact mode — name + role badge + last message
6
+ * - L3/L4 (architect): full mode — rich per-subagent activity streams
7
+ *
8
+ * Atomic design: composes Box / VStack / HStack / Typography / Badge / Icon /
9
+ * Button / Modal / Accordion / CodeBlock / MarkdownContent from this package.
10
+ * It reads the agent-trace view-model from `@almadar/core` (Trace* types) and
11
+ * owns no transport — the consumer feeds it already-mapped view-model props.
12
+ */
13
+ import React from 'react';
14
+ import type { DisplayStateProps } from './types';
15
+ import type { TraceActivity, TraceSubagent, TraceChatMessage } from '@almadar/core';
16
+ /** Disclosure level driving panel density (builder=1 … architect=4). */
17
+ export type TraceDisclosureLevel = 1 | 2 | 3 | 4;
18
+ export interface SubagentTracePanelProps extends DisplayStateProps {
19
+ /** All known subagents from the runner. */
20
+ subagents: TraceSubagent[];
21
+ /** Current canvas focus orbital — only used by overlay mode. Tab mode ignores this. */
22
+ focusedOrbital?: string;
23
+ /** Drives density: 1-2 → compact, 3-4 → full activity embed (when mode='overlay'). */
24
+ disclosureLevel: TraceDisclosureLevel;
25
+ /** Whether the panel is visible. Typically auto-opens during generation in overlay mode. */
26
+ open: boolean;
27
+ /** Optional dismiss handler. */
28
+ onClose?: () => void;
29
+ /** Full coordinator activities (tool calls, results, messages, errors). */
30
+ coordinatorActivities?: TraceActivity[];
31
+ /**
32
+ * Canonical Coordinator conversation — same shape live and on reload. When
33
+ * present, takes precedence over `coordinatorActivities` for the Coordinator
34
+ * section.
35
+ */
36
+ coordinatorMessages?: readonly TraceChatMessage[];
37
+ /**
38
+ * Rendering mode.
39
+ * - `'overlay'` (default): floating side panel positioned absolutely over the
40
+ * canvas. Density follows `disclosureLevel` (compact L1/L2, rich L3+). The
41
+ * `open` flag actually hides the panel when false.
42
+ * - `'tab'`: full-width content for a dedicated 'trace' supplemental tab.
43
+ * Always renders rich (regardless of disclosure level), always visible (the
44
+ * `open` flag is ignored), and includes an empty state when no subagents
45
+ * are present so users see the surface even before generation starts.
46
+ */
47
+ mode?: 'overlay' | 'tab';
48
+ }
49
+ export declare const SubagentTracePanel: React.FC<SubagentTracePanelProps>;
50
+ export default SubagentTracePanel;
@@ -28,3 +28,6 @@ export { TeamOrganism, type TeamOrganismProps, } from "../../marketing/organisms
28
28
  export { CaseStudyOrganism, type CaseStudyOrganismProps, } from "../../marketing/organisms/CaseStudyOrganism";
29
29
  export { CodeRunnerPanel, type CodeRunnerPanelProps, type CodeSimulationOutput, } from './CodeRunnerPanel';
30
30
  export { SegmentRenderer, type SegmentRendererProps, } from './SegmentRenderer';
31
+ export { ChatBar, type ChatBarProps, type ChatBarStatus } from './ChatBar';
32
+ export { ELEMENT_SELECTED_EVENT, parseEditFocus, } from './trace-edit-focus';
33
+ export { SubagentTracePanel, type SubagentTracePanelProps, type TraceDisclosureLevel, } from './SubagentTracePanel';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Edit Focus — the contextual-edit selection contract for the trace chat bar.
3
+ *
4
+ * A canvas element-pick emits `UI:ELEMENT_SELECTED` on the EventBus carrying an
5
+ * `EditFocus`. This module names that event and narrows the bus payload back
6
+ * into a typed `EditFocus` for `ChatBar`'s focus chip. It depends only on
7
+ * `@almadar/core` types; the DOM→focus build lives at the emitting canvas
8
+ * (`avl/derive-edit-focus`), not here.
9
+ */
10
+ import type { EditFocus, EventPayloadValue } from '@almadar/core';
11
+ /** The dedicated bus event a canvas element-pick emits. */
12
+ export declare const ELEMENT_SELECTED_EVENT = "UI:ELEMENT_SELECTED";
13
+ /** Narrow a `UI:ELEMENT_SELECTED` payload value back into an `EditFocus`. */
14
+ export declare function parseEditFocus(value: EventPayloadValue | undefined): EditFocus | null;
@@ -1,8 +1,14 @@
1
+ import { type IconInput } from '../../core/atoms/Icon';
2
+ import type { AssetUrl } from '@almadar/core';
1
3
  export interface ChoiceButtonProps {
2
4
  /** Choice text content */
3
5
  text: string;
4
6
  /** Choice index number (displayed as prefix) */
5
7
  index?: number;
8
+ /** Sprite image URL — takes precedence over icon when provided */
9
+ assetUrl?: AssetUrl;
10
+ /** Icon displayed before the text */
11
+ icon?: IconInput;
6
12
  /** Whether the choice is disabled */
7
13
  disabled?: boolean;
8
14
  /** Whether the choice is currently selected */
@@ -12,7 +18,7 @@ export interface ChoiceButtonProps {
12
18
  /** Additional CSS classes */
13
19
  className?: string;
14
20
  }
15
- export declare function ChoiceButton({ text, index, disabled, selected, onClick, className, }: ChoiceButtonProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function ChoiceButton({ text, index, assetUrl, icon, disabled, selected, onClick, className, }: ChoiceButtonProps): import("react/jsx-runtime").JSX.Element;
16
22
  export declare namespace ChoiceButton {
17
23
  var displayName: string;
18
24
  }
@@ -1,6 +1,9 @@
1
1
  import type { IconInput } from '../../core/atoms';
2
+ import type { AssetUrl } from '@almadar/core';
2
3
  export interface HealthEffect {
3
4
  icon: IconInput;
5
+ /** Sprite image URL — takes precedence over icon when provided */
6
+ assetUrl?: AssetUrl;
4
7
  label?: string;
5
8
  variant?: 'buff' | 'debuff' | 'neutral';
6
9
  }
@@ -1,7 +1,10 @@
1
1
  import type { IconInput } from '../../core/atoms';
2
+ import type { AssetUrl } from '@almadar/core';
2
3
  export interface ActivePowerup {
3
4
  /** Unique powerup ID */
4
5
  id: string;
6
+ /** Sprite image URL — takes precedence over icon when provided */
7
+ assetUrl?: AssetUrl;
5
8
  /** Icon component or emoji */
6
9
  icon?: IconInput;
7
10
  /** Powerup label */
@@ -1,7 +1,10 @@
1
1
  import type { IconInput } from '../../core/atoms';
2
+ import type { AssetUrl } from '@almadar/core';
2
3
  export interface TurnPanelAction {
3
4
  /** Action button label */
4
5
  label: string;
6
+ /** Sprite image URL — takes precedence over icon when provided */
7
+ assetUrl?: AssetUrl;
5
8
  /** Icon for the button */
6
9
  icon?: IconInput;
7
10
  /** Event name to emit when clicked */
@@ -2845,9 +2845,9 @@ var GameCanvas3D = React11.forwardRef(
2845
2845
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
2846
2846
  const hasAtlas = unitAtlasUrl(unit) !== null;
2847
2847
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
2848
- const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
2849
- const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
2850
- const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
2848
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale * gridConfig.cellSize;
2849
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale * gridConfig.cellSize;
2850
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale * gridConfig.cellSize;
2851
2851
  return /* @__PURE__ */ jsxRuntime.jsxs(
2852
2852
  "group",
2853
2853
  {
@@ -2894,7 +2894,7 @@ var GameCanvas3D = React11.forwardRef(
2894
2894
  /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
2895
2895
  ] })
2896
2896
  ] }),
2897
- unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
2897
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, billboardHeight, 0], children: [
2898
2898
  /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
2899
2899
  /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
2900
2900
  /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
@@ -2923,7 +2923,7 @@ var GameCanvas3D = React11.forwardRef(
2923
2923
  }
2924
2924
  );
2925
2925
  },
2926
- [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
2926
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale, gridConfig]
2927
2927
  );
2928
2928
  const DefaultFeatureRenderer = React11.useCallback(
2929
2929
  ({
@@ -3011,7 +3011,7 @@ var GameCanvas3D = React11.forwardRef(
3011
3011
  {
3012
3012
  ref: containerRef,
3013
3013
  className: cn("game-canvas-3d relative w-full overflow-hidden", className),
3014
- style: { height: "85vh" },
3014
+ style: { flex: "1 1 0", minHeight: "400px" },
3015
3015
  "data-orientation": orientation,
3016
3016
  "data-camera-mode": cameraMode,
3017
3017
  "data-overlay": overlay,