@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
@@ -8904,6 +8904,14 @@ function createWebPainter(ctx, onAssetLoad) {
8904
8904
  ctx.drawImage(img, dest.x, dest.y, dw, dh);
8905
8905
  }
8906
8906
  },
8907
+ blitTransformed(tex, src, affine) {
8908
+ const img = imageByHandle.get(tex);
8909
+ if (!img) return;
8910
+ ctx.save();
8911
+ ctx.transform(affine[0], affine[1], affine[2], affine[3], affine[4], affine[5]);
8912
+ ctx.drawImage(img, src.x, src.y, src.w, src.h, src.x, src.y, src.w, src.h);
8913
+ ctx.restore();
8914
+ },
8907
8915
  fillRect(x, y, w, h, style) {
8908
8916
  ctx.fillStyle = toCanvasStyle(style);
8909
8917
  ctx.fillRect(x, y, w, h);
@@ -9493,6 +9501,271 @@ var init_DrawGroup = __esm({
9493
9501
  init_registry();
9494
9502
  }
9495
9503
  });
9504
+
9505
+ // lib/skinning.ts
9506
+ function composeAffine(a, b) {
9507
+ return [
9508
+ a[0] * b[0] + a[2] * b[1],
9509
+ a[1] * b[0] + a[3] * b[1],
9510
+ a[0] * b[2] + a[2] * b[3],
9511
+ a[1] * b[2] + a[3] * b[3],
9512
+ a[0] * b[4] + a[2] * b[5] + a[4],
9513
+ a[1] * b[4] + a[3] * b[5] + a[5]
9514
+ ];
9515
+ }
9516
+ function invertAffine(m) {
9517
+ const det = m[0] * m[3] - m[1] * m[2];
9518
+ if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return IDENTITY;
9519
+ const inv = 1 / det;
9520
+ return [
9521
+ m[3] * inv,
9522
+ -m[1] * inv,
9523
+ -m[2] * inv,
9524
+ m[0] * inv,
9525
+ (m[2] * m[5] - m[3] * m[4]) * inv,
9526
+ (m[1] * m[4] - m[0] * m[5]) * inv
9527
+ ];
9528
+ }
9529
+ function applyAffine(m, x, y) {
9530
+ return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
9531
+ }
9532
+ function rotationAbout(pivot, degrees) {
9533
+ const r = degrees * Math.PI / 180;
9534
+ const cos = Math.cos(r);
9535
+ const sin = Math.sin(r);
9536
+ const [px, py] = pivot;
9537
+ return [cos, sin, -sin, cos, px - cos * px + sin * py, py - sin * px - cos * py];
9538
+ }
9539
+ function computeWorldMatrices(bones, pose) {
9540
+ const indexByName = /* @__PURE__ */ new Map();
9541
+ bones.forEach((b, i) => indexByName.set(b.name, i));
9542
+ const world = new Array(bones.length);
9543
+ const visiting = /* @__PURE__ */ new Set();
9544
+ const resolve = (i) => {
9545
+ const cached = world[i];
9546
+ if (cached) return cached;
9547
+ if (visiting.has(i)) return IDENTITY;
9548
+ visiting.add(i);
9549
+ const b = bones[i];
9550
+ const parentIndex = b.parent === null ? void 0 : indexByName.get(b.parent);
9551
+ const parentWorld = parentIndex === void 0 ? IDENTITY : resolve(parentIndex);
9552
+ const local = rotationAbout(b.pivot, pose[b.name] ?? 0);
9553
+ const m = composeAffine(parentWorld, local);
9554
+ visiting.delete(i);
9555
+ world[i] = m;
9556
+ return m;
9557
+ };
9558
+ return bones.map((_, i) => resolve(i));
9559
+ }
9560
+ function skinVertices(mesh, bindWorld, curWorld) {
9561
+ const skinMats = /* @__PURE__ */ new Map();
9562
+ const skinMat = (bone) => {
9563
+ let m = skinMats.get(bone);
9564
+ if (!m) {
9565
+ m = composeAffine(curWorld[bone] ?? IDENTITY, invertAffine(bindWorld[bone] ?? IDENTITY));
9566
+ skinMats.set(bone, m);
9567
+ }
9568
+ return m;
9569
+ };
9570
+ return mesh.vertices.map((v) => {
9571
+ if (v.weights.length === 0) return [v.x, v.y];
9572
+ let x = 0;
9573
+ let y = 0;
9574
+ for (const { bone, w } of v.weights) {
9575
+ const [bx, by] = applyAffine(skinMat(bone), v.x, v.y);
9576
+ x += w * bx;
9577
+ y += w * by;
9578
+ }
9579
+ return [x, y];
9580
+ });
9581
+ }
9582
+ function triangleAffine(src, dst) {
9583
+ const [s0, s1, s2] = src;
9584
+ const det = s0[0] * (s1[1] - s2[1]) + s1[0] * (s2[1] - s0[1]) + s2[0] * (s0[1] - s1[1]);
9585
+ if (!Number.isFinite(det) || Math.abs(det) < 1e-12) return null;
9586
+ const [d0, d1, d2] = dst;
9587
+ const a = (d0[0] * (s1[1] - s2[1]) + d1[0] * (s2[1] - s0[1]) + d2[0] * (s0[1] - s1[1])) / det;
9588
+ const c = (d0[0] * (s2[0] - s1[0]) + d1[0] * (s0[0] - s2[0]) + d2[0] * (s1[0] - s0[0])) / det;
9589
+ 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;
9590
+ const b = (d0[1] * (s1[1] - s2[1]) + d1[1] * (s2[1] - s0[1]) + d2[1] * (s0[1] - s1[1])) / det;
9591
+ const d = (d0[1] * (s2[0] - s1[0]) + d1[1] * (s0[0] - s2[0]) + d2[1] * (s1[0] - s0[0])) / det;
9592
+ 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;
9593
+ return [a, b, c, d, e, f3];
9594
+ }
9595
+ function isRigBundle(json) {
9596
+ return json.mesh !== void 0 || json.bones !== void 0;
9597
+ }
9598
+ function getRigBundle(url, onReady) {
9599
+ if (meshCache.has(url)) return meshCache.get(url) ?? void 0;
9600
+ meshCache.set(url, void 0);
9601
+ fetch(url).then((r) => {
9602
+ if (!r.ok) throw new Error(`rigbundle fetch failed: HTTP ${r.status}`);
9603
+ return r.json();
9604
+ }).then((json) => {
9605
+ const ok = isRigBundle(json) || Array.isArray(json.vertices);
9606
+ if (!ok) throw new Error("rigbundle payload is neither a SkinMesh nor a rigbundle");
9607
+ meshCache.set(url, json);
9608
+ onReady();
9609
+ }).catch(() => {
9610
+ meshCache.set(url, null);
9611
+ onReady();
9612
+ });
9613
+ return void 0;
9614
+ }
9615
+ function skinMeshFailed(url) {
9616
+ return meshCache.get(url) === null;
9617
+ }
9618
+ function vertexBounds(points) {
9619
+ if (points.length === 0) return null;
9620
+ let minX = Infinity;
9621
+ let minY = Infinity;
9622
+ let maxX = -Infinity;
9623
+ let maxY = -Infinity;
9624
+ for (const [x, y] of points) {
9625
+ if (x < minX) minX = x;
9626
+ if (y < minY) minY = y;
9627
+ if (x > maxX) maxX = x;
9628
+ if (y > maxY) maxY = y;
9629
+ }
9630
+ return { minX, minY, maxX, maxY };
9631
+ }
9632
+ var IDENTITY, meshCache;
9633
+ var init_skinning = __esm({
9634
+ "lib/skinning.ts"() {
9635
+ IDENTITY = [1, 0, 0, 1, 0, 0];
9636
+ meshCache = /* @__PURE__ */ new Map();
9637
+ }
9638
+ });
9639
+ function warnMissingOnce2(reason, node) {
9640
+ const key = `${reason}:${node.asset.url}:${String(node.meshUrl)}`;
9641
+ if (loggedMissing2.has(key)) return;
9642
+ loggedMissing2.add(key);
9643
+ skinnedLog.warn("draw-skinned-mesh unresolvable \u2014 painting fallback", { reason, url: node.asset.url, meshUrl: node.meshUrl });
9644
+ }
9645
+ function dominantBone(v) {
9646
+ let best = -1;
9647
+ let bestW = 0;
9648
+ for (const { bone, w } of v.weights) {
9649
+ if (w > bestW) {
9650
+ bestW = w;
9651
+ best = bone;
9652
+ }
9653
+ }
9654
+ return best;
9655
+ }
9656
+ function resolveSkinPose(node, clip) {
9657
+ const effectiveClip = clip ?? node.clip;
9658
+ if (effectiveClip && node.frame !== void 0 && effectiveClip.frames.length > 0) {
9659
+ return effectiveClip.frames[node.frame % effectiveClip.frames.length];
9660
+ }
9661
+ return node.pose ?? {};
9662
+ }
9663
+ function resolveRig(node, dctx) {
9664
+ const fetched = node.meshUrl ? getRigBundle(node.meshUrl, dctx.invalidate) : void 0;
9665
+ if (node.meshUrl && fetched === void 0) return void 0;
9666
+ const rb = fetched && isRigBundle(fetched) ? fetched : void 0;
9667
+ const mesh = node.mesh ?? rb?.mesh ?? (!rb ? fetched : void 0);
9668
+ if (!mesh) return void 0;
9669
+ const bones = node.bones.length > 0 ? node.bones : rb?.bones ?? [];
9670
+ if (bones.length === 0) return void 0;
9671
+ const clip = node.clip ?? (node.clipName ? rb?.clips?.[node.clipName] : void 0);
9672
+ return { mesh, bones, clip };
9673
+ }
9674
+ function meshHasPixelUVs(mesh) {
9675
+ const cached = pixelUVByMesh.get(mesh);
9676
+ if (cached !== void 0) return cached;
9677
+ let pixel = false;
9678
+ for (const v of mesh.vertices) {
9679
+ if (v.u < 0 || v.u > 1 || v.v < 0 || v.v > 1) {
9680
+ pixel = true;
9681
+ break;
9682
+ }
9683
+ }
9684
+ pixelUVByMesh.set(mesh, pixel);
9685
+ return pixel;
9686
+ }
9687
+ function paintMeshPass(painter, node, bones, mesh, tex, dctx, pose, opacity) {
9688
+ const bindWorld = computeWorldMatrices(bones, {});
9689
+ const curWorld = computeWorldMatrices(bones, pose);
9690
+ const skinned = skinVertices(mesh, bindWorld, curWorld);
9691
+ const origin = dctx.projector.project(node.position);
9692
+ const tw = dctx.projector.tileWidth;
9693
+ painter.save();
9694
+ if (opacity !== 1) painter.setAlpha(opacity);
9695
+ for (const [i0, i1, i2] of mesh.triangles) {
9696
+ const v0 = mesh.vertices[i0];
9697
+ const v1 = mesh.vertices[i1];
9698
+ const v2 = mesh.vertices[i2];
9699
+ const p0 = skinned[i0];
9700
+ const p1 = skinned[i1];
9701
+ const p2 = skinned[i2];
9702
+ if (!v0 || !v1 || !v2 || !p0 || !p1 || !p2) continue;
9703
+ const dst = [
9704
+ [origin.x + p0[0] * tw, origin.y + p0[1] * tw],
9705
+ [origin.x + p1[0] * tw, origin.y + p1[1] * tw],
9706
+ [origin.x + p2[0] * tw, origin.y + p2[1] * tw]
9707
+ ];
9708
+ if (node.weightsOverlay || !tex) {
9709
+ if (!node.weightsOverlay) continue;
9710
+ const bone = dominantBone(v0);
9711
+ painter.fillPoly(
9712
+ dst.map(([x, y]) => ({ x, y })),
9713
+ WEIGHT_PALETTE[(bone % WEIGHT_PALETTE.length + WEIGHT_PALETTE.length) % WEIGHT_PALETTE.length]
9714
+ );
9715
+ continue;
9716
+ }
9717
+ const pixelUV = meshHasPixelUVs(mesh);
9718
+ const uv = pixelUV ? [[v0.u, v0.v], [v1.u, v1.v], [v2.u, v2.v]] : [
9719
+ [v0.u * tex.width, v0.v * tex.height],
9720
+ [v1.u * tex.width, v1.v * tex.height],
9721
+ [v2.u * tex.width, v2.v * tex.height]
9722
+ ];
9723
+ const affine = triangleAffine(uv, dst);
9724
+ if (!affine) continue;
9725
+ painter.save();
9726
+ painter.clipPath(`M ${dst[0][0]} ${dst[0][1]} L ${dst[1][0]} ${dst[1][1]} L ${dst[2][0]} ${dst[2][1]} Z`);
9727
+ painter.blitTransformed(tex, { x: 0, y: 0, w: tex.width, h: tex.height }, affine);
9728
+ painter.restore();
9729
+ }
9730
+ painter.restore();
9731
+ }
9732
+ function DrawSkinnedMesh(props) {
9733
+ const register = React79.useContext(DrawableRegistryContext);
9734
+ if (register) register({ ...props, type: "draw-skinned-mesh" });
9735
+ return null;
9736
+ }
9737
+ var skinnedLog, loggedMissing2, WEIGHT_PALETTE, pixelUVByMesh, paintSkinnedMesh;
9738
+ var init_DrawSkinnedMesh = __esm({
9739
+ "components/game/atoms/DrawSkinnedMesh.tsx"() {
9740
+ "use client";
9741
+ init_imageCache();
9742
+ init_contract();
9743
+ init_registry();
9744
+ init_skinning();
9745
+ skinnedLog = logger.createLogger("almadar:ui:draw-skinned-mesh");
9746
+ loggedMissing2 = /* @__PURE__ */ new Set();
9747
+ WEIGHT_PALETTE = Array.from({ length: 10 }, (_, i) => `hsl(${i * 36 % 360}, 70%, 55%)`);
9748
+ pixelUVByMesh = /* @__PURE__ */ new WeakMap();
9749
+ paintSkinnedMesh = (painter, node, dctx) => {
9750
+ if (!isValidScenePos(node.position)) return;
9751
+ const rig = resolveRig(node, dctx);
9752
+ if (!rig) {
9753
+ if (node.meshUrl && skinMeshFailed(node.meshUrl)) warnMissingOnce2("mesh-failed", node);
9754
+ else if (!node.mesh && !node.meshUrl) warnMissingOnce2("mesh-missing", node);
9755
+ return;
9756
+ }
9757
+ const tex = node.weightsOverlay ? null : painter.resolveTexture(node.asset.url);
9758
+ if (!node.weightsOverlay && !tex) {
9759
+ if (getImageStatus(node.asset.url) === "failed") warnMissingOnce2("texture-failed", node);
9760
+ return;
9761
+ }
9762
+ if (node.ghost && rig.clip && rig.clip.frames.length > 0) {
9763
+ paintMeshPass(painter, node, rig.bones, rig.mesh, tex, dctx, rig.clip.frames[node.ghost.frame % rig.clip.frames.length], node.ghost.opacity);
9764
+ }
9765
+ paintMeshPass(painter, node, rig.bones, rig.mesh, tex, dctx, resolveSkinPose(node, rig.clip), node.opacity ?? 1);
9766
+ };
9767
+ }
9768
+ });
9496
9769
  function applyMeshAnimation(node, timeMs) {
9497
9770
  const anim = node.animation;
9498
9771
  if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return null;
@@ -9817,6 +10090,9 @@ function paintDrawable(painter, node, dctx) {
9817
10090
  case "draw-mesh":
9818
10091
  warnUnsupported2d("draw-mesh");
9819
10092
  break;
10093
+ case "draw-skinned-mesh":
10094
+ paintSkinnedMesh(painter, node, dctx);
10095
+ break;
9820
10096
  case "draw-sprite-layer":
9821
10097
  paintSpriteLayer(painter, node, dctx);
9822
10098
  break;
@@ -9841,6 +10117,7 @@ var init_paintDispatch = __esm({
9841
10117
  init_DrawShape();
9842
10118
  init_DrawText();
9843
10119
  init_DrawGroup();
10120
+ init_DrawSkinnedMesh();
9844
10121
  init_DrawMesh();
9845
10122
  init_DrawSpriteLayer();
9846
10123
  init_DrawShapeLayer();
@@ -11501,7 +11778,6 @@ var init_avl_atom_types = __esm({
11501
11778
  "persist": "data",
11502
11779
  "fetch": "data",
11503
11780
  "emit": "communication",
11504
- "notify": "communication",
11505
11781
  "call-service": "communication",
11506
11782
  "spawn": "lifecycle",
11507
11783
  "despawn": "lifecycle",
@@ -11649,12 +11925,6 @@ function effectIcon(type, x, y, s, color) {
11649
11925
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: x - s, y1: y, x2: x + s * 0.6, y2: y, stroke: color, strokeWidth: 1.5 }),
11650
11926
  /* @__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" })
11651
11927
  ] });
11652
- case "notify":
11653
- return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
11654
- /* @__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 }),
11655
- /* @__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 }),
11656
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: x, cy: y + s * 0.7, r: s * 0.2, fill: color })
11657
- ] });
11658
11928
  case "call-service":
11659
11929
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
11660
11930
  /* @__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 }),
@@ -16911,9 +17181,6 @@ function getEffectSummary(effects) {
16911
17181
  case "emit":
16912
17182
  summaries.push(`\u2191 ${effect[1] || "event"}`);
16913
17183
  break;
16914
- case "notify":
16915
- summaries.push(`\u{1F4E7} ${effect[1] || ""}`);
16916
- break;
16917
17184
  case "persist":
16918
17185
  summaries.push(`\u{1F4BE} ${effect[1] || "save"}`);
16919
17186
  break;
@@ -16939,7 +17206,7 @@ function extractOutputsFromTransitions(transitions) {
16939
17206
  t.effects.forEach((effect) => {
16940
17207
  if (Array.isArray(effect)) {
16941
17208
  const op = effect[0];
16942
- if (["emit", "notify", "persist", "navigate", "call-service"].includes(op)) {
17209
+ if (["emit", "persist", "navigate", "call-service"].includes(op)) {
16943
17210
  if (isArraySExpr(effect)) {
16944
17211
  const humanText = formatSExprEffectToDomain(effect);
16945
17212
  outputs.add(humanText);
@@ -19903,6 +20170,21 @@ function shapeDrawnItem(n) {
19903
20170
  if (n.shape !== "rect") return { pos: n.position, id: n.id };
19904
20171
  return { pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotate };
19905
20172
  }
20173
+ function skinnedMeshDrawnItem(n) {
20174
+ const mesh = n.mesh;
20175
+ if (!mesh || n.bones.length === 0) return { pos: n.position, id: n.id };
20176
+ const bindWorld = computeWorldMatrices(n.bones, {});
20177
+ const curWorld = computeWorldMatrices(n.bones, resolveSkinPose(n));
20178
+ const bounds = vertexBounds(skinVertices(mesh, bindWorld, curWorld));
20179
+ if (!bounds) return { pos: n.position, id: n.id };
20180
+ return {
20181
+ pos: { ...n.position, x: n.position.x + bounds.minX, y: n.position.y + bounds.minY },
20182
+ id: n.id,
20183
+ anchor: "top-left",
20184
+ width: bounds.maxX - bounds.minX,
20185
+ height: bounds.maxY - bounds.minY
20186
+ };
20187
+ }
19906
20188
  function collectDrawnItems(nodes) {
19907
20189
  const out = [];
19908
20190
  for (const n of nodes) {
@@ -19913,6 +20195,9 @@ function collectDrawnItems(nodes) {
19913
20195
  case "draw-shape":
19914
20196
  if (isValidScenePos(n.position)) out.push(shapeDrawnItem(n));
19915
20197
  break;
20198
+ case "draw-skinned-mesh":
20199
+ if (isValidScenePos(n.position)) out.push(skinnedMeshDrawnItem(n));
20200
+ break;
19916
20201
  case "draw-text":
19917
20202
  case "draw-group":
19918
20203
  case "draw-mesh":
@@ -19980,6 +20265,8 @@ function rotatePoint(p, center, radians) {
19980
20265
  var init_hitTest = __esm({
19981
20266
  "lib/drawable/hitTest.ts"() {
19982
20267
  init_contract();
20268
+ init_DrawSkinnedMesh();
20269
+ init_skinning();
19983
20270
  }
19984
20271
  });
19985
20272
  function normalizeBackdrop(bg) {
@@ -25757,7 +26044,9 @@ function DataGrid({
25757
26044
  const cardClickAction = actionDefs.find((a) => a.variant !== "danger");
25758
26045
  const handleCardClick = cardClickAction ? (itemData) => () => fireAction(cardClickAction, itemData) : void 0;
25759
26046
  const stopCardClick = handleCardClick ? (e) => e.stopPropagation() : void 0;
25760
- const hasRenderProp = typeof children === "function";
26047
+ const renderItemFn = typeof schemaRenderItem === "function" ? schemaRenderItem : void 0;
26048
+ const itemRenderer = typeof children === "function" ? children : renderItemFn;
26049
+ const hasRenderProp = typeof itemRenderer === "function";
25761
26050
  React79.useEffect(() => {
25762
26051
  if (data.length > 0 && !hasRenderProp && fieldDefs.length === 0) {
25763
26052
  const schemaArr = Array.isArray(schemaRenderItem) ? schemaRenderItem : null;
@@ -25831,7 +26120,7 @@ function DataGrid({
25831
26120
  onClick: handleCardClick?.(itemData),
25832
26121
  className: cn("relative group/rowactions", handleCardClick && "cursor-pointer", isSelected && "ring-2 ring-primary rounded-lg"),
25833
26122
  children: [
25834
- children(itemData, index),
26123
+ itemRenderer(itemData, index),
25835
26124
  actionDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.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(exports.HStack, { gap: "xs", className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5", children: [
25836
26125
  inlineCardActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
25837
26126
  exports.Button,
@@ -26164,7 +26453,9 @@ function DataList({
26164
26453
  );
26165
26454
  const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
26166
26455
  const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
26167
- const hasRenderProp = typeof children === "function";
26456
+ const renderItemFn = typeof schemaRenderItem === "function" ? schemaRenderItem : void 0;
26457
+ const itemRenderer = typeof children === "function" ? children : renderItemFn;
26458
+ const hasRenderProp = typeof itemRenderer === "function";
26168
26459
  React79__namespace.default.useEffect(() => {
26169
26460
  const renderItemTypeOf = typeof schemaRenderItem;
26170
26461
  const childrenTypeOf = typeof children;
@@ -26382,7 +26673,7 @@ function DataList({
26382
26673
  const actions = renderItemActions(itemData);
26383
26674
  return wrapDnd(
26384
26675
  /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { "data-entity-row": true, "data-entity-id": id2, onClick: rowClickEvent ? handleRowClick(itemData) : void 0, className: cn("relative group/rowactions", rowClickEvent && "cursor-pointer"), children: [
26385
- children(itemData, index),
26676
+ itemRenderer(itemData, index),
26386
26677
  actions && /* @__PURE__ */ jsxRuntime.jsxs(exports.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: [
26387
26678
  /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "rounded-md border border-border bg-card/95 backdrop-blur-sm shadow-sm p-0.5 [@media(pointer:coarse)]:hidden", children: actions }),
26388
26679
  /* @__PURE__ */ jsxRuntime.jsx(exports.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(
@@ -31735,7 +32026,7 @@ var init_DialogueBubble = __esm({
31735
32026
  init_Typography();
31736
32027
  init_GameIcon();
31737
32028
  DEFAULT_PORTRAIT = {
31738
- url: "https://almadar-kflow-assets.web.app/shared/characters/archetypes/04_hero.png",
32029
+ url: "https://almadar-kflow-assets.web.app/shared/ui-winter-ski-board/default/units/hero/hero.png",
31739
32030
  role: "effect",
31740
32031
  category: "character"
31741
32032
  };
@@ -32727,7 +33018,7 @@ var init_StateIndicator = __esm({
32727
33018
  init_cn();
32728
33019
  init_GameIcon();
32729
33020
  DEFAULT_ASSET_URL = {
32730
- url: "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png",
33021
+ url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-dungeon-board/default/features/chest/chest.png",
32731
33022
  role: "ui",
32732
33023
  category: "state"
32733
33024
  };
@@ -35428,13 +35719,13 @@ var init_MapView = __esm({
35428
35719
  shadowSize: [41, 41]
35429
35720
  });
35430
35721
  L.Marker.prototype.options.icon = defaultIcon;
35431
- const { useEffect: useEffect73, useRef: useRef70, useCallback: useCallback110, useState: useState110 } = React79__namespace.default;
35722
+ const { useEffect: useEffect72, useRef: useRef70, useCallback: useCallback109, useState: useState109 } = React79__namespace.default;
35432
35723
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
35433
35724
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
35434
35725
  function MapUpdater({ centerLat, centerLng, zoom }) {
35435
35726
  const map = useMap();
35436
35727
  const prevRef = useRef70({ centerLat, centerLng, zoom });
35437
- useEffect73(() => {
35728
+ useEffect72(() => {
35438
35729
  const prev = prevRef.current;
35439
35730
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
35440
35731
  map.setView([centerLat, centerLng], zoom);
@@ -35445,7 +35736,7 @@ var init_MapView = __esm({
35445
35736
  }
35446
35737
  function MapClickHandler({ onMapClick }) {
35447
35738
  const map = useMap();
35448
- useEffect73(() => {
35739
+ useEffect72(() => {
35449
35740
  if (!onMapClick) return;
35450
35741
  const handler = (e) => {
35451
35742
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -35473,8 +35764,8 @@ var init_MapView = __esm({
35473
35764
  showAttribution = true
35474
35765
  }) {
35475
35766
  const eventBus = useEventBus2();
35476
- const [clickedPosition, setClickedPosition] = useState110(null);
35477
- const handleMapClick = useCallback110((lat, lng) => {
35767
+ const [clickedPosition, setClickedPosition] = useState109(null);
35768
+ const handleMapClick = useCallback109((lat, lng) => {
35478
35769
  if (showClickedPin) {
35479
35770
  setClickedPosition({ lat, lng });
35480
35771
  }
@@ -35483,7 +35774,7 @@ var init_MapView = __esm({
35483
35774
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
35484
35775
  }
35485
35776
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
35486
- const handleMarkerClick = useCallback110((marker) => {
35777
+ const handleMarkerClick = useCallback109((marker) => {
35487
35778
  onMarkerClick?.(marker);
35488
35779
  if (markerClickEvent) {
35489
35780
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -36344,7 +36635,7 @@ function TableView({
36344
36635
  columns,
36345
36636
  fields,
36346
36637
  itemActions,
36347
- maxInlineActions: _maxInlineActions,
36638
+ maxInlineActions,
36348
36639
  itemClickEvent = "",
36349
36640
  selectable = false,
36350
36641
  selectEvent,
@@ -36377,6 +36668,12 @@ function TableView({
36377
36668
  const [localSelected, setLocalSelected] = React79__namespace.default.useState(/* @__PURE__ */ new Set());
36378
36669
  const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
36379
36670
  const actionDefs = Array.isArray(itemActions) ? itemActions : [];
36671
+ const inlineActions = maxInlineActions != null ? actionDefs.slice(0, maxInlineActions) : [];
36672
+ const overflowActions = maxInlineActions != null ? actionDefs.slice(maxInlineActions) : actionDefs;
36673
+ const fireAction = (action, row) => eventBus.emit(`UI:${action.event}`, {
36674
+ id: row.id,
36675
+ row
36676
+ });
36380
36677
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
36381
36678
  const dnd = useDataDnd({
36382
36679
  items: allDataRaw,
@@ -36552,7 +36849,7 @@ function TableView({
36552
36849
  }
36553
36850
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format) }) }, col.key);
36554
36851
  }),
36555
- hasActions && /* @__PURE__ */ jsxRuntime.jsx(
36852
+ hasActions && /* @__PURE__ */ jsxRuntime.jsxs(
36556
36853
  exports.HStack,
36557
36854
  {
36558
36855
  gap: "xs",
@@ -36566,23 +36863,38 @@ function TableView({
36566
36863
  "border-l border-[var(--color-border)]",
36567
36864
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
36568
36865
  ),
36569
- children: /* @__PURE__ */ jsxRuntime.jsx(
36570
- exports.Menu,
36571
- {
36572
- position: "bottom-end",
36573
- trigger: /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "more-horizontal", size: "xs" }) }),
36574
- items: actionDefs.map((action) => ({
36575
- label: action.label,
36576
- icon: action.icon,
36577
- event: action.event,
36578
- variant: action.variant === "danger" ? "danger" : "default",
36579
- onClick: () => eventBus.emit(`UI:${action.event}`, {
36580
- id: row.id,
36581
- row
36582
- })
36583
- }))
36584
- }
36585
- )
36866
+ children: [
36867
+ inlineActions.map((action) => /* @__PURE__ */ jsxRuntime.jsxs(
36868
+ exports.Button,
36869
+ {
36870
+ variant: action.variant ?? "ghost",
36871
+ size: "sm",
36872
+ onClick: () => fireAction(action, row),
36873
+ "data-testid": `action-${action.event}`,
36874
+ "data-row-id": String(row.id),
36875
+ className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
36876
+ children: [
36877
+ action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
36878
+ action.label
36879
+ ]
36880
+ },
36881
+ action.event
36882
+ )),
36883
+ overflowActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
36884
+ exports.Menu,
36885
+ {
36886
+ position: "bottom-end",
36887
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", "data-row-id": String(row.id), children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "more-horizontal", size: "xs" }) }),
36888
+ items: overflowActions.map((action) => ({
36889
+ label: action.label,
36890
+ icon: action.icon,
36891
+ event: action.event,
36892
+ variant: action.variant === "danger" ? "danger" : "default",
36893
+ onClick: () => fireAction(action, row)
36894
+ }))
36895
+ }
36896
+ )
36897
+ ]
36586
36898
  }
36587
36899
  )
36588
36900
  ]
@@ -52643,6 +52955,7 @@ var init_component_registry_generated = __esm({
52643
52955
  init_DrawMesh();
52644
52956
  init_DrawShape();
52645
52957
  init_DrawShapeLayer();
52958
+ init_DrawSkinnedMesh();
52646
52959
  init_DrawSprite();
52647
52960
  init_DrawSpriteLayer();
52648
52961
  init_DrawText();
@@ -52921,6 +53234,7 @@ var init_component_registry_generated = __esm({
52921
53234
  "DrawMesh": DrawMesh,
52922
53235
  "DrawShape": DrawShape,
52923
53236
  "DrawShapeLayer": DrawShapeLayer,
53237
+ "DrawSkinnedMesh": DrawSkinnedMesh,
52924
53238
  "DrawSprite": DrawSprite,
52925
53239
  "DrawSpriteLayer": DrawSpriteLayer,
52926
53240
  "DrawText": DrawText,
@@ -53249,7 +53563,7 @@ function renderContainedPortal(t, slot, content, onDismiss) {
53249
53563
  const slotId = `slot-${slot}`;
53250
53564
  switch (slot) {
53251
53565
  case "modal":
53252
- if (SELF_OVERLAY_PATTERNS.has(content.pattern)) {
53566
+ if (patterns.SELF_OVERLAY_PATTERN_TYPES.has(content.pattern)) {
53253
53567
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { id: slotId, className: "contents", children: slotContent });
53254
53568
  }
53255
53569
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -53592,7 +53906,7 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
53592
53906
  children
53593
53907
  }
53594
53908
  );
53595
- wrapper = pattern !== void 0 && SELF_OVERLAY_PATTERNS.has(pattern) ? innerContent : /* @__PURE__ */ jsxRuntime.jsx(exports.Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, size: "lg", children: innerContent });
53909
+ wrapper = pattern !== void 0 && patterns.SELF_OVERLAY_PATTERN_TYPES.has(pattern) ? innerContent : /* @__PURE__ */ jsxRuntime.jsx(exports.Modal, { isOpen: true, onClose: handleDismiss, showCloseButton: true, size: "lg", children: innerContent });
53596
53910
  break;
53597
53911
  }
53598
53912
  case "drawer":
@@ -53652,7 +53966,7 @@ function SlotPortal({
53652
53966
  let wrapper;
53653
53967
  switch (slot) {
53654
53968
  case "modal":
53655
- wrapper = SELF_OVERLAY_PATTERNS.has(content.pattern) ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { id: slotId, children: slotContent }) : /* @__PURE__ */ jsxRuntime.jsx(
53969
+ wrapper = patterns.SELF_OVERLAY_PATTERN_TYPES.has(content.pattern) ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { id: slotId, children: slotContent }) : /* @__PURE__ */ jsxRuntime.jsx(
53656
53970
  exports.Modal,
53657
53971
  {
53658
53972
  isOpen: true,
@@ -54159,7 +54473,7 @@ function UISlotRenderer({
54159
54473
  }
54160
54474
  return wrapped;
54161
54475
  }
54162
- var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, SELF_OVERLAY_PATTERNS, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
54476
+ var scopeWrapLog, TRAIT_BINDING_RE, SuspenseConfigContext, SlotContainedContext, SLOT_SKELETON_MAP, CONTENT_NODE_SLOTS, PATTERNS_WITH_CHILDREN, traitRefPresenceCache;
54163
54477
  var init_UISlotRenderer = __esm({
54164
54478
  "components/core/organisms/UISlotRenderer.tsx"() {
54165
54479
  "use client";
@@ -54190,7 +54504,6 @@ var init_UISlotRenderer = __esm({
54190
54504
  modal: "form",
54191
54505
  drawer: "form"
54192
54506
  };
54193
- SELF_OVERLAY_PATTERNS = /* @__PURE__ */ new Set(["modal", "confirm-dialog"]);
54194
54507
  CONTENT_NODE_SLOTS = /* @__PURE__ */ new Set([
54195
54508
  "logo",
54196
54509
  "master",
@@ -54383,66 +54696,6 @@ init_UISlotRenderer();
54383
54696
  init_ModalSlot();
54384
54697
  init_DrawerSlot();
54385
54698
  init_ToastSlot();
54386
-
54387
- // components/core/organisms/NotifyListener.tsx
54388
- init_useEventBus();
54389
- init_Toast();
54390
- init_Box();
54391
- var nextId = 0;
54392
- function NotifyListener() {
54393
- const eventBus = useEventBus();
54394
- const [items, setItems] = React79.useState([]);
54395
- const [portalRoot, setPortalRoot] = React79.useState(null);
54396
- React79.useEffect(() => {
54397
- let root = document.getElementById("ui-notify-portal-root");
54398
- if (!root) {
54399
- root = document.createElement("div");
54400
- root.id = "ui-notify-portal-root";
54401
- document.body.appendChild(root);
54402
- }
54403
- setPortalRoot(root);
54404
- }, []);
54405
- const handleDismiss = React79.useCallback((id) => {
54406
- setItems((prev) => prev.filter((item) => item.id !== id));
54407
- }, []);
54408
- React79.useEffect(() => {
54409
- const unsubscribe = eventBus.on("UI:NOTIFY", (event) => {
54410
- const payload = event.payload;
54411
- const message = payload && typeof payload.message === "string" ? payload.message : "Notification";
54412
- const severityMap = {
54413
- success: "success",
54414
- error: "error",
54415
- warning: "warning",
54416
- info: "info"
54417
- };
54418
- const variant = payload && String(payload.severity) in severityMap ? severityMap[String(payload.severity)] : "info";
54419
- const id = ++nextId;
54420
- setItems((prev) => {
54421
- const last = prev[prev.length - 1];
54422
- if (last && last.message === message && last.variant === variant) return prev;
54423
- return [...prev, { id, message, variant }].slice(-4);
54424
- });
54425
- });
54426
- return unsubscribe;
54427
- }, [eventBus]);
54428
- if (!portalRoot || items.length === 0) return null;
54429
- return reactDom.createPortal(
54430
- /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "fixed bottom-4 right-4 z-50 pointer-events-auto flex flex-col gap-2", children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
54431
- exports.Toast,
54432
- {
54433
- variant: item.variant,
54434
- message: item.message,
54435
- duration: 5e3,
54436
- onDismiss: () => handleDismiss(item.id)
54437
- },
54438
- item.id
54439
- )) }),
54440
- portalRoot
54441
- );
54442
- }
54443
- NotifyListener.displayName = "NotifyListener";
54444
-
54445
- // components/core/organisms/index.ts
54446
54699
  init_Timeline();
54447
54700
  init_MediaGallery();
54448
54701
 
@@ -56838,7 +57091,6 @@ exports.I18nProvider = I18nProvider;
56838
57091
  exports.LearningScene3D = LearningScene3D;
56839
57092
  exports.MapView = MapView;
56840
57093
  exports.MasterDetail = MasterDetail;
56841
- exports.NotifyListener = NotifyListener;
56842
57094
  exports.OrbitalStateMachineView = exports.StateMachineView;
56843
57095
  exports.RuntimeDebugger = RuntimeDebugger;
56844
57096
  exports.ScoreDisplay = ScoreDisplay;