@almadar/ui 6.13.0 → 6.15.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 (47) hide show
  1. package/dist/{UserContext-g_LcDiGN.d.cts → CurrentPagePathContext-J1lqjvAq.d.cts} +2 -97
  2. package/dist/{UserContext-g_LcDiGN.d.ts → CurrentPagePathContext-J1lqjvAq.d.ts} +2 -97
  3. package/dist/{EntityBindingContext-D5lRu6p1.d.cts → EntityBindingContext-EJoTtuTR.d.cts} +9 -3
  4. package/dist/{EntityBindingContext-D5lRu6p1.d.ts → EntityBindingContext-EJoTtuTR.d.ts} +9 -3
  5. package/dist/{GameAudioProvider-D8GynTNq.d.cts → GameAudioProvider-Cpw_lMPY.d.cts} +1 -1
  6. package/dist/{GameAudioProvider-Dozqx4sL.d.ts → GameAudioProvider-DIjFiy70.d.ts} +1 -1
  7. package/dist/UserContext-D566nfWA.d.cts +99 -0
  8. package/dist/UserContext-D566nfWA.d.ts +99 -0
  9. package/dist/avl/index.cjs +373 -61
  10. package/dist/avl/index.d.cts +1 -1
  11. package/dist/avl/index.d.ts +1 -1
  12. package/dist/avl/index.js +375 -63
  13. package/dist/{avl-schema-parser-PVu8rgsy.d.cts → avl-schema-parser-B25PL-a8.d.cts} +1 -1
  14. package/dist/{avl-schema-parser-DX-aVCCm.d.ts → avl-schema-parser-CM0pQo8E.d.ts} +1 -1
  15. package/dist/components/index.cjs +360 -108
  16. package/dist/components/index.d.cts +8 -24
  17. package/dist/components/index.d.ts +8 -24
  18. package/dist/components/index.js +362 -109
  19. package/dist/context/index.d.cts +2 -1
  20. package/dist/context/index.d.ts +2 -1
  21. package/dist/lib/drawable/three/index.cjs +126 -3
  22. package/dist/lib/drawable/three/index.d.cts +3 -3
  23. package/dist/lib/drawable/three/index.d.ts +3 -3
  24. package/dist/lib/drawable/three/index.js +126 -3
  25. package/dist/lib/index.cjs +1 -4
  26. package/dist/lib/index.d.cts +2 -2
  27. package/dist/lib/index.d.ts +2 -2
  28. package/dist/lib/index.js +1 -4
  29. package/dist/{offline-executor-QUdKOj7f.d.cts → offline-executor-DdV2o0Zu.d.cts} +4 -19
  30. package/dist/{offline-executor-QUdKOj7f.d.ts → offline-executor-DdV2o0Zu.d.ts} +4 -19
  31. package/dist/{paintDispatch-CK5uwYEq.d.cts → paintDispatch-Dh1pgljl.d.cts} +79 -1
  32. package/dist/{paintDispatch-CK5uwYEq.d.ts → paintDispatch-Dh1pgljl.d.ts} +79 -1
  33. package/dist/providers/index.cjs +366 -55
  34. package/dist/providers/index.d.cts +10 -9
  35. package/dist/providers/index.d.ts +10 -9
  36. package/dist/providers/index.js +367 -56
  37. package/dist/renderer/index.cjs +0 -15
  38. package/dist/renderer/index.d.cts +4 -9
  39. package/dist/renderer/index.d.ts +4 -9
  40. package/dist/renderer/index.js +1 -15
  41. package/dist/runtime/index.cjs +375 -72
  42. package/dist/runtime/index.d.cts +14 -11
  43. package/dist/runtime/index.d.ts +14 -11
  44. package/dist/runtime/index.js +377 -74
  45. package/dist/{verificationRegistry-D8bHWD8Q.d.ts → verificationRegistry-Cwa52VyK.d.ts} +1 -1
  46. package/dist/{verificationRegistry-BLsjb1oU.d.cts → verificationRegistry-DTrKDRoa.d.cts} +1 -1
  47. package/package.json +4 -4
@@ -7856,7 +7856,7 @@ var init_DialogueBubble = __esm({
7856
7856
  init_Typography();
7857
7857
  init_GameIcon();
7858
7858
  DEFAULT_PORTRAIT = {
7859
- url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
7859
+ url: "https://almadar-kflow-assets.web.app/shared/ui-winter-ski-board/default/units/hero/hero.png",
7860
7860
  role: "effect",
7861
7861
  category: "character"
7862
7862
  };
@@ -9180,6 +9180,14 @@ function createWebPainter(ctx, onAssetLoad) {
9180
9180
  ctx.drawImage(img, dest.x, dest.y, dw, dh);
9181
9181
  }
9182
9182
  },
9183
+ blitTransformed(tex, src, affine) {
9184
+ const img = imageByHandle.get(tex);
9185
+ if (!img) return;
9186
+ ctx.save();
9187
+ ctx.transform(affine[0], affine[1], affine[2], affine[3], affine[4], affine[5]);
9188
+ ctx.drawImage(img, src.x, src.y, src.w, src.h, src.x, src.y, src.w, src.h);
9189
+ ctx.restore();
9190
+ },
9183
9191
  fillRect(x, y, w, h, style) {
9184
9192
  ctx.fillStyle = toCanvasStyle(style);
9185
9193
  ctx.fillRect(x, y, w, h);
@@ -9686,6 +9694,271 @@ var init_DrawGroup = __esm({
9686
9694
  init_registry();
9687
9695
  }
9688
9696
  });
9697
+
9698
+ // lib/skinning.ts
9699
+ function composeAffine(a, b) {
9700
+ return [
9701
+ a[0] * b[0] + a[2] * b[1],
9702
+ a[1] * b[0] + a[3] * b[1],
9703
+ a[0] * b[2] + a[2] * b[3],
9704
+ a[1] * b[2] + a[3] * b[3],
9705
+ a[0] * b[4] + a[2] * b[5] + a[4],
9706
+ a[1] * b[4] + a[3] * b[5] + a[5]
9707
+ ];
9708
+ }
9709
+ function invertAffine(m) {
9710
+ const det = m[0] * m[3] - m[1] * m[2];
9711
+ if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return IDENTITY;
9712
+ const inv = 1 / det;
9713
+ return [
9714
+ m[3] * inv,
9715
+ -m[1] * inv,
9716
+ -m[2] * inv,
9717
+ m[0] * inv,
9718
+ (m[2] * m[5] - m[3] * m[4]) * inv,
9719
+ (m[1] * m[4] - m[0] * m[5]) * inv
9720
+ ];
9721
+ }
9722
+ function applyAffine(m, x, y) {
9723
+ return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
9724
+ }
9725
+ function rotationAbout(pivot, degrees) {
9726
+ const r = degrees * Math.PI / 180;
9727
+ const cos = Math.cos(r);
9728
+ const sin = Math.sin(r);
9729
+ const [px, py] = pivot;
9730
+ return [cos, sin, -sin, cos, px - cos * px + sin * py, py - sin * px - cos * py];
9731
+ }
9732
+ function computeWorldMatrices(bones, pose) {
9733
+ const indexByName = /* @__PURE__ */ new Map();
9734
+ bones.forEach((b, i) => indexByName.set(b.name, i));
9735
+ const world = new Array(bones.length);
9736
+ const visiting = /* @__PURE__ */ new Set();
9737
+ const resolve = (i) => {
9738
+ const cached = world[i];
9739
+ if (cached) return cached;
9740
+ if (visiting.has(i)) return IDENTITY;
9741
+ visiting.add(i);
9742
+ const b = bones[i];
9743
+ const parentIndex = b.parent === null ? void 0 : indexByName.get(b.parent);
9744
+ const parentWorld = parentIndex === void 0 ? IDENTITY : resolve(parentIndex);
9745
+ const local = rotationAbout(b.pivot, pose[b.name] ?? 0);
9746
+ const m = composeAffine(parentWorld, local);
9747
+ visiting.delete(i);
9748
+ world[i] = m;
9749
+ return m;
9750
+ };
9751
+ return bones.map((_, i) => resolve(i));
9752
+ }
9753
+ function skinVertices(mesh, bindWorld, curWorld) {
9754
+ const skinMats = /* @__PURE__ */ new Map();
9755
+ const skinMat = (bone) => {
9756
+ let m = skinMats.get(bone);
9757
+ if (!m) {
9758
+ m = composeAffine(curWorld[bone] ?? IDENTITY, invertAffine(bindWorld[bone] ?? IDENTITY));
9759
+ skinMats.set(bone, m);
9760
+ }
9761
+ return m;
9762
+ };
9763
+ return mesh.vertices.map((v) => {
9764
+ if (v.weights.length === 0) return [v.x, v.y];
9765
+ let x = 0;
9766
+ let y = 0;
9767
+ for (const { bone, w } of v.weights) {
9768
+ const [bx, by] = applyAffine(skinMat(bone), v.x, v.y);
9769
+ x += w * bx;
9770
+ y += w * by;
9771
+ }
9772
+ return [x, y];
9773
+ });
9774
+ }
9775
+ function triangleAffine(src, dst) {
9776
+ const [s0, s1, s2] = src;
9777
+ const det = s0[0] * (s1[1] - s2[1]) + s1[0] * (s2[1] - s0[1]) + s2[0] * (s0[1] - s1[1]);
9778
+ if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return null;
9779
+ const [d0, d1, d2] = dst;
9780
+ const a = (d0[0] * (s1[1] - s2[1]) + d1[0] * (s2[1] - s0[1]) + d2[0] * (s0[1] - s1[1])) / det;
9781
+ const c = (d0[0] * (s2[0] - s1[0]) + d1[0] * (s0[0] - s2[0]) + d2[0] * (s1[0] - s0[0])) / det;
9782
+ const e = (d0[0] * (s1[0] * s2[1] - s2[0] * s1[1]) + d1[0] * (s2[0] * s0[1] - s0[0] * s2[1]) + d2[0] * (s0[0] * s1[1] - s1[0] * s0[1])) / det;
9783
+ const b = (d0[1] * (s1[1] - s2[1]) + d1[1] * (s2[1] - s0[1]) + d2[1] * (s0[1] - s1[1])) / det;
9784
+ const d = (d0[1] * (s2[0] - s1[0]) + d1[1] * (s0[0] - s2[0]) + d2[1] * (s1[0] - s0[0])) / det;
9785
+ const f3 = (d0[1] * (s1[0] * s2[1] - s2[0] * s1[1]) + d1[1] * (s2[0] * s0[1] - s0[0] * s2[1]) + d2[1] * (s0[0] * s1[1] - s1[0] * s0[1])) / det;
9786
+ return [a, b, c, d, e, f3];
9787
+ }
9788
+ function isRigBundle(json) {
9789
+ return json.mesh !== void 0 || json.bones !== void 0;
9790
+ }
9791
+ function getRigBundle(url, onReady) {
9792
+ if (meshCache.has(url)) return meshCache.get(url) ?? void 0;
9793
+ meshCache.set(url, void 0);
9794
+ fetch(url).then((r) => {
9795
+ if (!r.ok) throw new Error(`rigbundle fetch failed: HTTP ${r.status}`);
9796
+ return r.json();
9797
+ }).then((json) => {
9798
+ const ok = isRigBundle(json) || Array.isArray(json.vertices);
9799
+ if (!ok) throw new Error("rigbundle payload is neither a SkinMesh nor a rigbundle");
9800
+ meshCache.set(url, json);
9801
+ onReady();
9802
+ }).catch(() => {
9803
+ meshCache.set(url, null);
9804
+ onReady();
9805
+ });
9806
+ return void 0;
9807
+ }
9808
+ function skinMeshFailed(url) {
9809
+ return meshCache.get(url) === null;
9810
+ }
9811
+ function vertexBounds(points) {
9812
+ if (points.length === 0) return null;
9813
+ let minX = Infinity;
9814
+ let minY = Infinity;
9815
+ let maxX = -Infinity;
9816
+ let maxY = -Infinity;
9817
+ for (const [x, y] of points) {
9818
+ if (x < minX) minX = x;
9819
+ if (y < minY) minY = y;
9820
+ if (x > maxX) maxX = x;
9821
+ if (y > maxY) maxY = y;
9822
+ }
9823
+ return { minX, minY, maxX, maxY };
9824
+ }
9825
+ var IDENTITY, meshCache;
9826
+ var init_skinning = __esm({
9827
+ "lib/skinning.ts"() {
9828
+ IDENTITY = [1, 0, 0, 1, 0, 0];
9829
+ meshCache = /* @__PURE__ */ new Map();
9830
+ }
9831
+ });
9832
+ function warnMissingOnce2(reason, node) {
9833
+ const key = `${reason}:${node.asset.url}:${String(node.meshUrl)}`;
9834
+ if (loggedMissing2.has(key)) return;
9835
+ loggedMissing2.add(key);
9836
+ skinnedLog.warn("draw-skinned-mesh unresolvable \u2014 painting fallback", { reason, url: node.asset.url, meshUrl: node.meshUrl });
9837
+ }
9838
+ function dominantBone(v) {
9839
+ let best = -1;
9840
+ let bestW = 0;
9841
+ for (const { bone, w } of v.weights) {
9842
+ if (w > bestW) {
9843
+ bestW = w;
9844
+ best = bone;
9845
+ }
9846
+ }
9847
+ return best;
9848
+ }
9849
+ function resolveSkinPose(node, clip) {
9850
+ const effectiveClip = clip ?? node.clip;
9851
+ if (effectiveClip && node.frame !== void 0 && effectiveClip.frames.length > 0) {
9852
+ return effectiveClip.frames[node.frame % effectiveClip.frames.length];
9853
+ }
9854
+ return node.pose ?? {};
9855
+ }
9856
+ function resolveRig(node, dctx) {
9857
+ const fetched = node.meshUrl ? getRigBundle(node.meshUrl, dctx.invalidate) : void 0;
9858
+ if (node.meshUrl && fetched === void 0) return void 0;
9859
+ const rb = fetched && isRigBundle(fetched) ? fetched : void 0;
9860
+ const mesh = node.mesh ?? rb?.mesh ?? (!rb ? fetched : void 0);
9861
+ if (!mesh) return void 0;
9862
+ const bones = node.bones.length > 0 ? node.bones : rb?.bones ?? [];
9863
+ if (bones.length === 0) return void 0;
9864
+ const clip = node.clip ?? (node.clipName ? rb?.clips?.[node.clipName] : void 0);
9865
+ return { mesh, bones, clip };
9866
+ }
9867
+ function meshHasPixelUVs(mesh) {
9868
+ const cached = pixelUVByMesh.get(mesh);
9869
+ if (cached !== void 0) return cached;
9870
+ let pixel = false;
9871
+ for (const v of mesh.vertices) {
9872
+ if (v.u < 0 || v.u > 1 || v.v < 0 || v.v > 1) {
9873
+ pixel = true;
9874
+ break;
9875
+ }
9876
+ }
9877
+ pixelUVByMesh.set(mesh, pixel);
9878
+ return pixel;
9879
+ }
9880
+ function paintMeshPass(painter, node, bones, mesh, tex, dctx, pose, opacity) {
9881
+ const bindWorld = computeWorldMatrices(bones, {});
9882
+ const curWorld = computeWorldMatrices(bones, pose);
9883
+ const skinned = skinVertices(mesh, bindWorld, curWorld);
9884
+ const origin = dctx.projector.project(node.position);
9885
+ const tw = dctx.projector.tileWidth;
9886
+ painter.save();
9887
+ if (opacity !== 1) painter.setAlpha(opacity);
9888
+ for (const [i0, i1, i2] of mesh.triangles) {
9889
+ const v0 = mesh.vertices[i0];
9890
+ const v1 = mesh.vertices[i1];
9891
+ const v2 = mesh.vertices[i2];
9892
+ const p0 = skinned[i0];
9893
+ const p1 = skinned[i1];
9894
+ const p2 = skinned[i2];
9895
+ if (!v0 || !v1 || !v2 || !p0 || !p1 || !p2) continue;
9896
+ const dst = [
9897
+ [origin.x + p0[0] * tw, origin.y + p0[1] * tw],
9898
+ [origin.x + p1[0] * tw, origin.y + p1[1] * tw],
9899
+ [origin.x + p2[0] * tw, origin.y + p2[1] * tw]
9900
+ ];
9901
+ if (node.weightsOverlay || !tex) {
9902
+ if (!node.weightsOverlay) continue;
9903
+ const bone = dominantBone(v0);
9904
+ painter.fillPoly(
9905
+ dst.map(([x, y]) => ({ x, y })),
9906
+ WEIGHT_PALETTE[(bone % WEIGHT_PALETTE.length + WEIGHT_PALETTE.length) % WEIGHT_PALETTE.length]
9907
+ );
9908
+ continue;
9909
+ }
9910
+ const pixelUV = meshHasPixelUVs(mesh);
9911
+ const uv = pixelUV ? [[v0.u, v0.v], [v1.u, v1.v], [v2.u, v2.v]] : [
9912
+ [v0.u * tex.width, v0.v * tex.height],
9913
+ [v1.u * tex.width, v1.v * tex.height],
9914
+ [v2.u * tex.width, v2.v * tex.height]
9915
+ ];
9916
+ const affine = triangleAffine(uv, dst);
9917
+ if (!affine) continue;
9918
+ painter.save();
9919
+ painter.clipPath(`M ${dst[0][0]} ${dst[0][1]} L ${dst[1][0]} ${dst[1][1]} L ${dst[2][0]} ${dst[2][1]} Z`);
9920
+ painter.blitTransformed(tex, { x: 0, y: 0, w: tex.width, h: tex.height }, affine);
9921
+ painter.restore();
9922
+ }
9923
+ painter.restore();
9924
+ }
9925
+ function DrawSkinnedMesh(props) {
9926
+ const register = React89.useContext(DrawableRegistryContext);
9927
+ if (register) register({ ...props, type: "draw-skinned-mesh" });
9928
+ return null;
9929
+ }
9930
+ var skinnedLog, loggedMissing2, WEIGHT_PALETTE, pixelUVByMesh, paintSkinnedMesh;
9931
+ var init_DrawSkinnedMesh = __esm({
9932
+ "components/game/atoms/DrawSkinnedMesh.tsx"() {
9933
+ "use client";
9934
+ init_imageCache();
9935
+ init_contract();
9936
+ init_registry();
9937
+ init_skinning();
9938
+ skinnedLog = logger.createLogger("almadar:ui:draw-skinned-mesh");
9939
+ loggedMissing2 = /* @__PURE__ */ new Set();
9940
+ WEIGHT_PALETTE = Array.from({ length: 10 }, (_, i) => `hsl(${i * 36 % 360}, 70%, 55%)`);
9941
+ pixelUVByMesh = /* @__PURE__ */ new WeakMap();
9942
+ paintSkinnedMesh = (painter, node, dctx) => {
9943
+ if (!isValidScenePos(node.position)) return;
9944
+ const rig = resolveRig(node, dctx);
9945
+ if (!rig) {
9946
+ if (node.meshUrl && skinMeshFailed(node.meshUrl)) warnMissingOnce2("mesh-failed", node);
9947
+ else if (!node.mesh && !node.meshUrl) warnMissingOnce2("mesh-missing", node);
9948
+ return;
9949
+ }
9950
+ const tex = node.weightsOverlay ? null : painter.resolveTexture(node.asset.url);
9951
+ if (!node.weightsOverlay && !tex) {
9952
+ if (getImageStatus(node.asset.url) === "failed") warnMissingOnce2("texture-failed", node);
9953
+ return;
9954
+ }
9955
+ if (node.ghost && rig.clip && rig.clip.frames.length > 0) {
9956
+ paintMeshPass(painter, node, rig.bones, rig.mesh, tex, dctx, rig.clip.frames[node.ghost.frame % rig.clip.frames.length], node.ghost.opacity);
9957
+ }
9958
+ paintMeshPass(painter, node, rig.bones, rig.mesh, tex, dctx, resolveSkinPose(node, rig.clip), node.opacity ?? 1);
9959
+ };
9960
+ }
9961
+ });
9689
9962
  function applyMeshAnimation(node, timeMs) {
9690
9963
  const anim = node.animation;
9691
9964
  if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return null;
@@ -10010,6 +10283,9 @@ function paintDrawable(painter, node, dctx) {
10010
10283
  case "draw-mesh":
10011
10284
  warnUnsupported2d("draw-mesh");
10012
10285
  break;
10286
+ case "draw-skinned-mesh":
10287
+ paintSkinnedMesh(painter, node, dctx);
10288
+ break;
10013
10289
  case "draw-sprite-layer":
10014
10290
  paintSpriteLayer(painter, node, dctx);
10015
10291
  break;
@@ -10034,6 +10310,7 @@ var init_paintDispatch = __esm({
10034
10310
  init_DrawShape();
10035
10311
  init_DrawText();
10036
10312
  init_DrawGroup();
10313
+ init_DrawSkinnedMesh();
10037
10314
  init_DrawMesh();
10038
10315
  init_DrawSpriteLayer();
10039
10316
  init_DrawShapeLayer();
@@ -10054,6 +10331,21 @@ function shapeDrawnItem(n) {
10054
10331
  if (n.shape !== "rect") return { pos: n.position, id: n.id };
10055
10332
  return { pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotate };
10056
10333
  }
10334
+ function skinnedMeshDrawnItem(n) {
10335
+ const mesh = n.mesh;
10336
+ if (!mesh || n.bones.length === 0) return { pos: n.position, id: n.id };
10337
+ const bindWorld = computeWorldMatrices(n.bones, {});
10338
+ const curWorld = computeWorldMatrices(n.bones, resolveSkinPose(n));
10339
+ const bounds = vertexBounds(skinVertices(mesh, bindWorld, curWorld));
10340
+ if (!bounds) return { pos: n.position, id: n.id };
10341
+ return {
10342
+ pos: { ...n.position, x: n.position.x + bounds.minX, y: n.position.y + bounds.minY },
10343
+ id: n.id,
10344
+ anchor: "top-left",
10345
+ width: bounds.maxX - bounds.minX,
10346
+ height: bounds.maxY - bounds.minY
10347
+ };
10348
+ }
10057
10349
  function collectDrawnItems(nodes) {
10058
10350
  const out = [];
10059
10351
  for (const n of nodes) {
@@ -10064,6 +10356,9 @@ function collectDrawnItems(nodes) {
10064
10356
  case "draw-shape":
10065
10357
  if (isValidScenePos(n.position)) out.push(shapeDrawnItem(n));
10066
10358
  break;
10359
+ case "draw-skinned-mesh":
10360
+ if (isValidScenePos(n.position)) out.push(skinnedMeshDrawnItem(n));
10361
+ break;
10067
10362
  case "draw-text":
10068
10363
  case "draw-group":
10069
10364
  case "draw-mesh":
@@ -10131,6 +10426,8 @@ function rotatePoint(p, center, radians) {
10131
10426
  var init_hitTest = __esm({
10132
10427
  "lib/drawable/hitTest.ts"() {
10133
10428
  init_contract();
10429
+ init_DrawSkinnedMesh();
10430
+ init_skinning();
10134
10431
  }
10135
10432
  });
10136
10433
  function normalizeBackdrop(bg) {
@@ -11320,7 +11617,7 @@ var init_StateIndicator = __esm({
11320
11617
  init_cn();
11321
11618
  init_GameIcon();
11322
11619
  DEFAULT_ASSET_URL = {
11323
- url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
11620
+ url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-dungeon-board/default/features/chest/chest.png",
11324
11621
  role: "ui",
11325
11622
  category: "state"
11326
11623
  };
@@ -12936,11 +13233,6 @@ function executeEffect(effect, config) {
12936
13233
  executeNavigate(path, params, config);
12937
13234
  break;
12938
13235
  }
12939
- case "notify": {
12940
- const [message, options] = args;
12941
- executeNotify(message, options, config);
12942
- break;
12943
- }
12944
13236
  case "emit": {
12945
13237
  const [event, payload] = args;
12946
13238
  executeEmit(event, payload, config);
@@ -12956,9 +13248,6 @@ function executeRenderUI(slot, patternConfig, config) {
12956
13248
  function executeNavigate(path, params, config) {
12957
13249
  config.navigate(path, params);
12958
13250
  }
12959
- function executeNotify(message, options, config) {
12960
- config.notify(message, options);
12961
- }
12962
13251
  function executeEmit(event, payload, config) {
12963
13252
  config.eventBus.emit(event, payload);
12964
13253
  }
@@ -13246,7 +13535,6 @@ var init_offline_executor = __esm({
13246
13535
  // Client effects - execute immediately
13247
13536
  case "render-ui":
13248
13537
  case "navigate":
13249
- case "notify":
13250
13538
  case "emit":
13251
13539
  clientEffects.push(effect);
13252
13540
  break;
@@ -15674,7 +15962,6 @@ var init_avl_atom_types = __esm({
15674
15962
  "persist": "data",
15675
15963
  "fetch": "data",
15676
15964
  "emit": "communication",
15677
- "notify": "communication",
15678
15965
  "call-service": "communication",
15679
15966
  "spawn": "lifecycle",
15680
15967
  "despawn": "lifecycle",
@@ -15822,12 +16109,6 @@ function effectIcon(type, x, y, s, color) {
15822
16109
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: x - s, y1: y, x2: x + s * 0.6, y2: y, stroke: color, strokeWidth: 1.5 }),
15823
16110
  /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: `${x + s * 0.1},${y - s * 0.5} ${x + s},${y} ${x + s * 0.1},${y + s * 0.5}`, fill: "none", stroke: color, strokeWidth: 1.5, strokeLinejoin: "round" })
15824
16111
  ] });
15825
- case "notify":
15826
- return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
15827
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: `M${x - s * 0.7},${y + s * 0.3} Q${x - s * 0.7},${y - s} ${x},${y - s} Q${x + s * 0.7},${y - s} ${x + s * 0.7},${y + s * 0.3} Z`, fill: "none", stroke: color, strokeWidth: 1.5 }),
15828
- /* @__PURE__ */ jsxRuntime.jsx("line", { x1: x - s * 0.8, y1: y + s * 0.3, x2: x + s * 0.8, y2: y + s * 0.3, stroke: color, strokeWidth: 1.5 }),
15829
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: x, cy: y + s * 0.7, r: s * 0.2, fill: color })
15830
- ] });
15831
16112
  case "call-service":
15832
16113
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
15833
16114
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: x - s, y1: y - s * 0.3, x2: x + s, y2: y - s * 0.3, stroke: color, strokeWidth: 1.5 }),
@@ -21081,9 +21362,6 @@ function getEffectSummary(effects) {
21081
21362
  case "emit":
21082
21363
  summaries.push(`\u2191 ${effect[1] || "event"}`);
21083
21364
  break;
21084
- case "notify":
21085
- summaries.push(`\u{1F4E7} ${effect[1] || ""}`);
21086
- break;
21087
21365
  case "persist":
21088
21366
  summaries.push(`\u{1F4BE} ${effect[1] || "save"}`);
21089
21367
  break;
@@ -21109,7 +21387,7 @@ function extractOutputsFromTransitions(transitions) {
21109
21387
  t.effects.forEach((effect) => {
21110
21388
  if (Array.isArray(effect)) {
21111
21389
  const op = effect[0];
21112
- if (["emit", "notify", "persist", "navigate", "call-service"].includes(op)) {
21390
+ if (["emit", "persist", "navigate", "call-service"].includes(op)) {
21113
21391
  if (isArraySExpr(effect)) {
21114
21392
  const humanText = formatSExprEffectToDomain(effect);
21115
21393
  outputs.add(humanText);
@@ -28133,7 +28411,9 @@ function DataGrid({
28133
28411
  const cardClickAction = actionDefs.find((a) => a.variant !== "danger");
28134
28412
  const handleCardClick = cardClickAction ? (itemData) => () => fireAction(cardClickAction, itemData) : void 0;
28135
28413
  const stopCardClick = handleCardClick ? (e) => e.stopPropagation() : void 0;
28136
- const hasRenderProp = typeof children === "function";
28414
+ const renderItemFn = typeof schemaRenderItem === "function" ? schemaRenderItem : void 0;
28415
+ const itemRenderer = typeof children === "function" ? children : renderItemFn;
28416
+ const hasRenderProp = typeof itemRenderer === "function";
28137
28417
  React89.useEffect(() => {
28138
28418
  if (data.length > 0 && !hasRenderProp && fieldDefs.length === 0) {
28139
28419
  const schemaArr = Array.isArray(schemaRenderItem) ? schemaRenderItem : null;
@@ -28207,7 +28487,7 @@ function DataGrid({
28207
28487
  onClick: handleCardClick?.(itemData),
28208
28488
  className: cn("relative group/rowactions", handleCardClick && "cursor-pointer", isSelected && "ring-2 ring-primary rounded-lg"),
28209
28489
  children: [
28210
- children(itemData, index),
28490
+ itemRenderer(itemData, index),
28211
28491
  actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { onClick: stopCardClick, className: "absolute top-2 right-2 z-10 opacity-0 group-hover/rowactions:opacity-100 focus-within:opacity-100 [@media(pointer:coarse)]:opacity-100 transition-opacity duration-fast", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: [
28212
28492
  inlineCardActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
28213
28493
  Button,
@@ -28540,7 +28820,9 @@ function DataList({
28540
28820
  );
28541
28821
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
28542
28822
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
28543
- const hasRenderProp = typeof children === "function";
28823
+ const renderItemFn = typeof schemaRenderItem === "function" ? schemaRenderItem : void 0;
28824
+ const itemRenderer = typeof children === "function" ? children : renderItemFn;
28825
+ const hasRenderProp = typeof itemRenderer === "function";
28544
28826
  React89__namespace.default.useEffect(() => {
28545
28827
  const renderItemTypeOf = typeof schemaRenderItem;
28546
28828
  const childrenTypeOf = typeof children;
@@ -28758,7 +29040,7 @@ function DataList({
28758
29040
  const actions = renderItemActions(itemData);
28759
29041
  return wrapDnd(
28760
29042
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn("relative group/rowactions", rowClickEvent && "cursor-pointer"), children: [
28761
- children(itemData, index),
29043
+ itemRenderer(itemData, index),
28762
29044
  actions && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "absolute top-2 right-2 z-10 opacity-0 group-hover/rowactions:opacity-100 focus-within:opacity-100 [@media(pointer:coarse)]:opacity-100 transition-opacity duration-fast", children: [
28763
29045
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5 [@media(pointer:coarse)]:hidden", children: actions }),
28764
29046
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "hidden [@media(pointer:coarse)]:block rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -35302,7 +35584,7 @@ function TableView({
35302
35584
  columns,
35303
35585
  fields,
35304
35586
  itemActions,
35305
- maxInlineActions: _maxInlineActions,
35587
+ maxInlineActions,
35306
35588
  itemClickEvent = "",
35307
35589
  selectable = false,
35308
35590
  selectEvent,
@@ -35335,6 +35617,12 @@ function TableView({
35335
35617
  const [localSelected, setLocalSelected] = React89__namespace.default.useState(/* @__PURE__ */ new Set());
35336
35618
  const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
35337
35619
  const actionDefs = Array.isArray(itemActions) ? itemActions : [];
35620
+ const inlineActions = maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : [];
35621
+ const overflowActions = maxInlineActions != null ? actionDefs.slice(maxInlineActions) : actionDefs;
35622
+ const fireAction = (action, row) => eventBus.emit(`UI:${action.event}`, {
35623
+ id: row.id,
35624
+ row
35625
+ });
35338
35626
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
35339
35627
  const dnd = useDataDnd({
35340
35628
  items: allDataRaw,
@@ -35510,7 +35798,7 @@ function TableView({
35510
35798
  }
35511
35799
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format) }) }, col.key);
35512
35800
  }),
35513
- hasActions && /* @__PURE__ */ jsxRuntime.jsx(
35801
+ hasActions && /* @__PURE__ */ jsxRuntime.jsxs(
35514
35802
  HStack,
35515
35803
  {
35516
35804
  gap: "xs",
@@ -35524,23 +35812,38 @@ function TableView({
35524
35812
  "border-l border-[var(--color-border)]",
35525
35813
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
35526
35814
  ),
35527
- children: /* @__PURE__ */ jsxRuntime.jsx(
35528
- Menu,
35529
- {
35530
- position: "bottom-end",
35531
- trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
35532
- items: actionDefs.map((action) => ({
35533
- label: action.label,
35534
- icon: action.icon,
35535
- event: action.event,
35536
- variant: action.variant === "danger" ? "danger" : "default",
35537
- onClick: () => eventBus.emit(`UI:${action.event}`, {
35538
- id: row.id,
35539
- row
35540
- })
35541
- }))
35542
- }
35543
- )
35815
+ children: [
35816
+ inlineActions.map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
35817
+ Button,
35818
+ {
35819
+ variant: action.variant ?? "ghost",
35820
+ size: "sm",
35821
+ onClick: () => fireAction(action, row),
35822
+ "data-testid": `action-${action.event}`,
35823
+ "data-row-id": String(row.id),
35824
+ className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
35825
+ children: [
35826
+ action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
35827
+ action.label
35828
+ ]
35829
+ },
35830
+ action.event
35831
+ )),
35832
+ overflowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
35833
+ Menu,
35834
+ {
35835
+ position: "bottom-end",
35836
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
35837
+ items: overflowActions.map((action) => ({
35838
+ label: action.label,
35839
+ icon: action.icon,
35840
+ event: action.event,
35841
+ variant: action.variant === "danger" ? "danger" : "default",
35842
+ onClick: () => fireAction(action, row)
35843
+ }))
35844
+ }
35845
+ )
35846
+ ]
35544
35847
  }
35545
35848
  )
35546
35849
  ]
@@ -51372,6 +51675,7 @@ var init_component_registry_generated = __esm({
51372
51675
  init_DrawMesh();
51373
51676
  init_DrawShape();
51374
51677
  init_DrawShapeLayer();
51678
+ init_DrawSkinnedMesh();
51375
51679
  init_DrawSprite();
51376
51680
  init_DrawSpriteLayer();
51377
51681
  init_DrawText();
@@ -51650,6 +51954,7 @@ var init_component_registry_generated = __esm({
51650
51954
  "DrawMesh": DrawMesh,
51651
51955
  "DrawShape": DrawShape,
51652
51956
  "DrawShapeLayer": DrawShapeLayer,
51957
+ "DrawSkinnedMesh": DrawSkinnedMesh,
51653
51958
  "DrawSprite": DrawSprite,
51654
51959
  "DrawSpriteLayer": DrawSpriteLayer,
51655
51960
  "DrawText": DrawText,
@@ -51978,7 +52283,7 @@ function renderContainedPortal(t, slot, content, onDismiss) {
51978
52283
  const slotId = `slot-${slot}`;
51979
52284
  switch (slot) {
51980
52285
  case "modal":
51981
- if (SELF_OVERLAY_PATTERNS.has(content.pattern)) {
52286
+ if (patterns.SELF_OVERLAY_PATTERN_TYPES.has(content.pattern)) {
51982
52287
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { id: slotId, className: "contents", children: slotContent });
51983
52288
  }
51984
52289
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -52321,7 +52626,7 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
52321
52626
  children
52322
52627
  }
52323
52628
  );
52324
- wrapper = pattern !== void 0 && SELF_OVERLAY_PATTERNS.has(pattern) ? innerContent : /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, size: "lg", children: innerContent });
52629
+ wrapper = pattern !== void 0 && patterns.SELF_OVERLAY_PATTERN_TYPES.has(pattern) ? innerContent : /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, size: "lg", children: innerContent });
52325
52630
  break;
52326
52631
  }
52327
52632
  case "drawer":
@@ -52381,7 +52686,7 @@ function SlotPortal({
52381
52686
  let wrapper;
52382
52687
  switch (slot) {
52383
52688
  case "modal":
52384
- wrapper = SELF_OVERLAY_PATTERNS.has(content.pattern) ? /* @__PURE__ */ jsxRuntime.jsx(Box, { id: slotId, children: slotContent }) : /* @__PURE__ */ jsxRuntime.jsx(
52689
+ wrapper = patterns.SELF_OVERLAY_PATTERN_TYPES.has(content.pattern) ? /* @__PURE__ */ jsxRuntime.jsx(Box, { id: slotId, children: slotContent }) : /* @__PURE__ */ jsxRuntime.jsx(
52385
52690
  Modal,
52386
52691
  {
52387
52692
  isOpen: true,
@@ -52888,7 +53193,7 @@ function UISlotRenderer({
52888
53193
  }
52889
53194
  return wrapped;
52890
53195
  }
52891
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
53196
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
52892
53197
  var init_UISlotRenderer = __esm({
52893
53198
  "components/core/organisms/UISlotRenderer.tsx"() {
52894
53199
  "use client";
@@ -52919,7 +53224,6 @@ var init_UISlotRenderer = __esm({
52919
53224
  modal: "form",
52920
53225
  drawer: "form"
52921
53226
  };
52922
- SELF_OVERLAY_PATTERNS = /* @__PURE__ */ new Set(["modal", "confirm-dialog"]);
52923
53227
  CONTENT_NODE_SLOTS = /* @__PURE__ */ new Set([
52924
53228
  "logo",
52925
53229
  "master",
@@ -53316,6 +53620,11 @@ function VerificationProvider({
53316
53620
  }
53317
53621
  const emittedEventsRaw = Array.isArray(payload["emittedEvents"]) ? payload["emittedEvents"] : [];
53318
53622
  const emittedEvents = emittedEventsRaw.map((e) => typeof e.event === "string" ? e.event : null).filter((e) => e !== null);
53623
+ const emitted = emittedEventsRaw.flatMap((e) => {
53624
+ if (typeof e.event !== "string") return [];
53625
+ const p = e["payload"];
53626
+ return [{ event: e.event, ...p !== null && typeof p === "object" && !Array.isArray(p) && { payload: p } }];
53627
+ });
53319
53628
  recordTransition({
53320
53629
  traitName: parsed.traitName,
53321
53630
  from: pending?.from ?? payload["currentState"] ?? newState,
@@ -53325,9 +53634,11 @@ function VerificationProvider({
53325
53634
  serverResponse: {
53326
53635
  orbitalName: parsed.traitName,
53327
53636
  success: true,
53637
+ ...typeof payload["transitioned"] === "boolean" && { transitioned: payload["transitioned"] },
53328
53638
  clientEffects: clientEffectsArr.length,
53329
53639
  dataEntities,
53330
53640
  emittedEvents,
53641
+ emitted,
53331
53642
  timestamp: Date.now()
53332
53643
  },
53333
53644
  timestamp: Date.now()
@@ -53354,6 +53665,7 @@ function VerificationProvider({
53354
53665
  serverResponse: {
53355
53666
  orbitalName: parsed.traitName,
53356
53667
  success: false,
53668
+ transitioned: false,
53357
53669
  clientEffects: 0,
53358
53670
  dataEntities: {},
53359
53671
  emittedEvents: [],
@@ -54238,7 +54550,7 @@ var ServerBridgeContext = React89.createContext(null);
54238
54550
  function useServerBridge() {
54239
54551
  const ctx = React89.useContext(ServerBridgeContext);
54240
54552
  if (!ctx) {
54241
- const emptyMeta = { success: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
54553
+ const emptyMeta = { success: false, transitioned: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
54242
54554
  return { connected: false, sendEvent: async () => ({ effects: [], meta: emptyMeta }) };
54243
54555
  }
54244
54556
  return ctx;
@@ -54286,7 +54598,7 @@ function ServerBridgeProvider({
54286
54598
  };
54287
54599
  }, []);
54288
54600
  const sendEvent = React89.useCallback(async (orbitalName, event, payload, tick, sourceTrait) => {
54289
- const emptyMeta = { success: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
54601
+ const emptyMeta = { success: false, transitioned: false, clientEffects: 0, dataEntities: {}, emittedEvents: [] };
54290
54602
  if (!connected) return { effects: [], meta: emptyMeta };
54291
54603
  if (tick !== void 0) {
54292
54604
  tickRelay.send(`${orbitalName}:${event}`, { orbitalName, event, payload, tick, sourceTrait });
@@ -54304,10 +54616,12 @@ function ServerBridgeProvider({
54304
54616
  }
54305
54617
  const meta = {
54306
54618
  success: !!result.success,
54619
+ transitioned: result.transitioned === true,
54307
54620
  clientEffects: result.clientEffects?.length ?? 0,
54308
54621
  dataEntities,
54309
54622
  data: responseData,
54310
54623
  emittedEvents: result.emittedEvents?.map((e) => e.event) ?? [],
54624
+ emitted: result.emittedEvents?.map((e) => ({ event: e.event, ...e.payload !== void 0 && { payload: e.payload } })) ?? [],
54311
54625
  effectResults: result.effectResults,
54312
54626
  error: result.error
54313
54627
  };
@@ -54340,9 +54654,6 @@ function ServerBridgeProvider({
54340
54654
  });
54341
54655
  } else if (effectType === "navigate-back") {
54342
54656
  effects.push({ type: "navigate-back", traitName });
54343
- } else if (effectType === "notify") {
54344
- const message = effect[1];
54345
- effects.push({ type: "notify", message: typeof message === "string" ? message : void 0, traitName });
54346
54657
  }
54347
54658
  }
54348
54659
  if (result.emittedEvents) {