@energy8platform/golem 0.5.0 → 0.7.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 (72) hide show
  1. package/README.md +18 -0
  2. package/dist/editor.css +3 -4
  3. package/dist/editor.js +177 -75
  4. package/dist/lib/cli.js +302 -126
  5. package/dist/lib/cli.js.map +4 -4
  6. package/dist/lib/e8/agent.d.ts +35 -0
  7. package/dist/lib/e8/host.d.ts +22 -0
  8. package/dist/lib/e8/node.d.ts +66 -0
  9. package/dist/lib/e8/runtime.d.ts +10 -0
  10. package/dist/lib/e8/schema.d.ts +3 -0
  11. package/dist/lib/e8/types.d.ts +80 -0
  12. package/dist/lib/e8-agent.js +6781 -0
  13. package/dist/lib/e8-agent.js.map +7 -0
  14. package/dist/lib/e8-client.js +116 -0
  15. package/dist/lib/e8-host.js +6929 -0
  16. package/dist/lib/e8-host.js.map +7 -0
  17. package/dist/lib/e8-runtime.js +2024 -0
  18. package/dist/lib/e8-runtime.js.map +7 -0
  19. package/dist/lib/e8-schema.js +7 -0
  20. package/dist/lib/e8-schema.js.map +7 -0
  21. package/dist/lib/editor/api.d.ts +1 -0
  22. package/dist/lib/editor/embed.d.ts +9 -0
  23. package/dist/lib/editor/server.d.ts +23 -1
  24. package/dist/lib/editor/store.d.ts +107 -0
  25. package/dist/lib/editor/timeline.d.ts +15 -0
  26. package/dist/lib/editor-entry.d.ts +1 -1
  27. package/dist/lib/editor-entry.js +303 -126
  28. package/dist/lib/editor-entry.js.map +4 -4
  29. package/dist/lib/harness.js +69 -14
  30. package/dist/lib/interactive-editor.js.map +1 -1
  31. package/dist/lib/rig-anim.d.ts +2 -0
  32. package/dist/lib/rig-control-qa.d.ts +27 -0
  33. package/dist/lib/rig-format.d.ts +989 -0
  34. package/dist/lib/rig-import-layers.d.ts +2 -0
  35. package/dist/lib/rig-version.d.ts +12 -0
  36. package/dist/lib/runtime.js +69 -14
  37. package/dist/lib/runtime.js.map +3 -3
  38. package/dist/lib/spine-import.d.ts +4 -0
  39. package/dist/lib/tool-schema.d.ts +3 -0
  40. package/dist/lib/tools.d.ts +2 -0
  41. package/dist/lib/tools.js +257 -73
  42. package/dist/lib/tools.js.map +4 -4
  43. package/editor.html +2 -2
  44. package/package.json +38 -3
  45. package/skills/e8-golem/SKILL.md +71 -0
  46. package/skills/golem-symbol-animation/SKILL.md +87 -0
  47. package/skills/golem-symbol-animation/agents/openai.yaml +4 -0
  48. package/skills/golem-symbol-animation/references/facial-controls.md +48 -0
  49. package/skills/golem-symbol-animation/references/game-engine-integration.md +133 -0
  50. package/skills/golem-symbol-animation/references/golem-authoring.md +138 -0
  51. package/skills/golem-symbol-animation/references/interactive-editor.md +17 -0
  52. package/skills/golem-symbol-animation/references/motion-craft.md +113 -0
  53. package/skills/golem-symbol-animation/references/packed-delivery.md +88 -0
  54. package/skills/golem-symbol-animation/references/quantitative-qa.md +106 -0
  55. package/skills/golem-symbol-animation/references/spine-rive-study.md +87 -0
  56. package/skills/golem-symbol-animation/scripts/atlas_parts.py +87 -0
  57. package/skills/golem-symbol-animation/scripts/check_package.py +71 -0
  58. package/skills/golem-symbol-animation/scripts/image_gates.py +143 -0
  59. package/skills/golem-symbol-cutting/SKILL.md +70 -0
  60. package/skills/golem-symbol-cutting/agents/openai.yaml +4 -0
  61. package/skills/golem-symbol-cutting/assets/h1/h1.atlas.png +0 -0
  62. package/skills/golem-symbol-cutting/assets/h1/h1.png +0 -0
  63. package/skills/golem-symbol-cutting/references/cutting-workflow.md +92 -0
  64. package/skills/golem-symbol-cutting/references/facial-layers.md +44 -0
  65. package/skills/golem-symbol-cutting/references/generation-workflow.md +109 -0
  66. package/skills/golem-symbol-cutting/references/golem-handoff.md +62 -0
  67. package/skills/golem-symbol-cutting/references/h1-example.md +46 -0
  68. package/skills/golem-symbol-cutting/references/hybrid-workflow.md +119 -0
  69. package/skills/golem-symbol-cutting/references/registration-and-motion.md +89 -0
  70. package/skills/golem-symbol-cutting/references/spine-rive-construction.md +73 -0
  71. package/skills/golem-symbol-cutting/scripts/atlas_parts.py +87 -0
  72. package/skills/golem-symbol-cutting/scripts/hybrid_parts.py +279 -0
@@ -28,5 +28,7 @@ export interface LayerSpec {
28
28
  blend?: "normal" | "add" | "multiply" | "screen";
29
29
  }
30
30
  export declare function pngSize(buf: Buffer): [number, number];
31
+ /** `file`, named by a sidecar inside `dir` (layers.json, a Spine atlas), leaves `dir`: absolute or climbing out. */
32
+ export declare function outsideDir(dir: string, file: string): boolean;
31
33
  export declare function importLayers(doc: Doc, dir: string, relPrefix?: string): Promise<Doc>;
32
34
  export {};
@@ -0,0 +1,12 @@
1
+ import { type ToolResult } from "./rig-api";
2
+ /** `mtimeMs:size` of the file, or "missing" */
3
+ export declare function rigVersion(abs: string): Promise<string>;
4
+ /**
5
+ * callTool with the rig's version just before and just after, both read inside the rig's queue, so no other writer in
6
+ * this process lands between them. `args.path` must be absolute; a call without one reads "missing" twice.
7
+ */
8
+ export declare function callToolVersioned(name: string, args: Record<string, unknown>): Promise<{
9
+ result: ToolResult;
10
+ before: string;
11
+ after: string;
12
+ }>;
@@ -159,7 +159,9 @@ var PathAttachment = z.object({
159
159
  /** curve lengths for constant-speed positioning */
160
160
  lengths: z.array(z.number()).default([]),
161
161
  closed: z.boolean().default(false),
162
- constantSpeed: z.boolean().default(true)
162
+ constantSpeed: z.boolean().default(true),
163
+ /** Spine-style active clipping span in the posed draw order; end slot is inclusive. */
164
+ clipping: z.object({ end: Id.optional() }).optional()
163
165
  });
164
166
  var Attachment = z.discriminatedUnion("type", [RegionAttachment, MeshAttachment, PathAttachment]);
165
167
  var IkConstraint = z.object({
@@ -223,7 +225,9 @@ var Key = z.object({
223
225
  t: z.number().nonnegative(),
224
226
  v: KeyValue,
225
227
  /** easing INTO the next key */
226
- ease: Ease.default("ease_in_out")
228
+ ease: Ease.default("ease_in_out"),
229
+ /** Optional independent easing for numeric-array components (for example Spine RGBA curves). */
230
+ componentEase: z.array(Ease).min(1).optional()
227
231
  });
228
232
  var Interpolation = { interpolation: z.enum(["segment", "pchip"]).optional() };
229
233
  var Track = z.discriminatedUnion("target", [
@@ -410,6 +414,10 @@ function validate(doc) {
410
414
  else if (a.slot !== s.id) errs.push(`slot "${s.id}": attachment "${s.attachment}" belongs to slot "${a.slot}"`);
411
415
  }
412
416
  }
417
+ for (const a of doc.attachments) if (a.type === "path" && a.clipping) {
418
+ if (!a.closed) errs.push(`attachment "${a.id}": clipping path must be closed`);
419
+ if (a.clipping.end && !slots.has(a.clipping.end)) errs.push(`attachment "${a.id}": unknown clipping end slot "${a.clipping.end}"`);
420
+ }
413
421
  const vertexCount = (a) => {
414
422
  if (a.type === "region") return 4;
415
423
  if (a.type === "mesh") return a.uvs.length / 2;
@@ -493,6 +501,7 @@ function validate(doc) {
493
501
  const att = t.target === "deform" ? attachments.get(t.id) : void 0;
494
502
  let prev = -1;
495
503
  for (const k of t.keys) {
504
+ if (k.componentEase && (!Array.isArray(k.v) || !k.v.every((v) => typeof v === "number") || k.componentEase.length !== k.v.length)) errs.push(`animation "${a.id}" ${tid}: componentEase must match the numeric-array value length`);
496
505
  if (k.t <= prev && prev >= 0) errs.push(`animation "${a.id}" ${tid}: keys not strictly increasing`);
497
506
  if (k.t > a.duration) errs.push(`animation "${a.id}" ${tid}: key at ${k.t}s exceeds duration`);
498
507
  if (t.target === "control") {
@@ -657,8 +666,8 @@ function sample(track, t, loop = false) {
657
666
  }
658
667
  if (Array.isArray(a.v) && Array.isArray(b.v) && typeof a.v[0] === "number") {
659
668
  if (track.interpolation === "pchip") return a.v.map((_, j) => smoothValue(track, i, t, j, loop));
660
- const u = ease(a.ease)((t - a.t) / (b.t - a.t)), av = a.v, bv = b.v;
661
- return av.map((v, k) => v + ((bv[k] ?? v) - v) * u);
669
+ const phase = (t - a.t) / (b.t - a.t), av = a.v, bv = b.v;
670
+ return av.map((v, k) => v + ((bv[k] ?? v) - v) * ease(a.componentEase?.[k] ?? a.ease)(phase));
662
671
  }
663
672
  return a.v;
664
673
  }
@@ -746,6 +755,13 @@ function boneWorldOf(bone, s, parent) {
746
755
  if (!parent) return local;
747
756
  if (bone.inherit === "normal") return mul(parent, local);
748
757
  const [tx, ty] = apply(parent, s.x, s.y);
758
+ if (bone.inherit === "noScale" || bone.inherit === "noScaleOrReflection") {
759
+ const r = s.rotation * DEG2, x = parent.a * Math.cos(r) + parent.c * Math.sin(r), y = parent.b * Math.cos(r) + parent.d * Math.sin(r);
760
+ const length = Math.hypot(x, y), a = length > 1e-5 ? x / length : x, b = length > 1e-5 ? y / length : y;
761
+ const sign = bone.inherit === "noScale" && parent.a * parent.d - parent.b * parent.c < 0 ? -1 : 1;
762
+ const basis2 = { a, b, c: -b * sign, d: a * sign, tx: 0, ty: 0 };
763
+ return { ...mul(basis2, affineOf(0, 0, 0, s.scaleX, s.scaleY, s.shearX, s.shearY)), tx, ty };
764
+ }
749
765
  return { ...mul(inheritedParentLinear(bone, parent), { ...local, tx: 0, ty: 0 }), tx, ty };
750
766
  }
751
767
  var orderCache = /* @__PURE__ */ new WeakMap();
@@ -778,11 +794,11 @@ var localOf = (doc, pose, b) => {
778
794
  shearY: num(pose, pk("bone", id, "shearY"), r.shearY)
779
795
  };
780
796
  };
781
- function updateSubtree(skel, root) {
797
+ function updateSubtree(skel, root, includeRoot = true) {
782
798
  const doc = skel.doc;
783
799
  const kids = /* @__PURE__ */ new Map();
784
800
  for (const b of doc.bones) if (b.parent) (kids.get(b.parent) ?? kids.set(b.parent, []).get(b.parent)).push(b);
785
- const stack = [root];
801
+ const stack = includeRoot ? [root] : (kids.get(root) ?? []).map((b) => b.id);
786
802
  while (stack.length) {
787
803
  const id = stack.pop(), b = boneOf(doc, id), st = skel.bones.get(id);
788
804
  st.world = boneWorldOf(b, st, b.parent ? skel.bones.get(b.parent).world : void 0);
@@ -816,6 +832,23 @@ function evaluate(doc, pose, modifiers) {
816
832
  }
817
833
  return skel;
818
834
  }
835
+ function slotClips(skel) {
836
+ const keyed = skel.pose.get(pk("drawOrder", "order", "order"));
837
+ const order = Array.isArray(keyed) ? keyed : [...skel.doc.slots].sort((a, b) => a.z - b.z).map((s) => s.id);
838
+ const masks = /* @__PURE__ */ new Map();
839
+ let active;
840
+ for (const id of order) {
841
+ const att = skel.attachment.get(id);
842
+ if (!active && att?.type === "path" && att.clipping) {
843
+ active = att;
844
+ continue;
845
+ }
846
+ if (active) masks.set(id, active.id);
847
+ if (active?.clipping?.end === id) active = void 0;
848
+ }
849
+ for (const s of skel.doc.slots) if (s.clip) masks.set(s.id, s.clip);
850
+ return masks;
851
+ }
819
852
  var cnum = (skel, kind, id, prop, rest) => num(skel.pose, pk(kind, id, prop), typeof rest === "boolean" ? rest ? 1 : 0 : rest);
820
853
  var IDENTITY = { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 };
821
854
  var wrapRad = (r) => r > Math.PI ? r - 2 * Math.PI : r < -Math.PI ? r + 2 * Math.PI : r;
@@ -1025,7 +1058,8 @@ function applyTransformConstraint(skel, c) {
1025
1058
  if (!mixRotate && !mixX && !mixY && !mixScaleX && !mixScaleY && !mixShearY) return;
1026
1059
  c = { ...c, ...Object.fromEntries(["x", "y", "rotation", "scaleX", "scaleY", "shearY"].map((p) => [p, cnum(skel, "transform", c.id, p, c[p])])) };
1027
1060
  const target = skel.bones.get(c.target), tw = target.world;
1028
- const offsetRotation = c.rotation * DEG2, offsetShearY = c.shearY * DEG2;
1061
+ const handedness = tw.a * tw.d - tw.b * tw.c < 0 ? -1 : 1;
1062
+ const offsetRotation = c.rotation * DEG2 * (c.local ? 1 : handedness), offsetShearY = c.shearY * DEG2 * (c.local ? 1 : handedness);
1029
1063
  for (const id of c.bones) {
1030
1064
  const b = boneOf(skel.doc, id), st = skel.bones.get(id);
1031
1065
  if (c.local) {
@@ -1187,6 +1221,7 @@ function applyPathConstraint(skel, c) {
1187
1221
  const position = cnum(skel, "path", c.id, "position", c.position), spacing = cnum(skel, "path", c.id, "spacing", c.spacing);
1188
1222
  const tangents = c.rotateMode === "tangent", scale = c.rotateMode === "chainScale";
1189
1223
  const bones = c.bones.map((id) => ({ b: boneOf(skel.doc, id), st: skel.bones.get(id) }));
1224
+ const inputWorlds = bones.map(({ st }) => ({ ...st.world }));
1190
1225
  const spacesCount = tangents ? bones.length : bones.length + 1;
1191
1226
  const spaces = new Array(spacesCount).fill(0), worldLengths = [];
1192
1227
  let sum = 0;
@@ -1221,9 +1256,10 @@ function applyPathConstraint(skel, c) {
1221
1256
  if (tw.a * tw.d - tw.b * tw.c < 0) offsetRotation = -offsetRotation;
1222
1257
  }
1223
1258
  let boneX = samples[0].x, boneY = samples[0].y;
1259
+ const solvedWorlds = /* @__PURE__ */ new Map();
1224
1260
  for (let i = 0; i < bones.length; i++) {
1225
1261
  const { b, st } = bones[i];
1226
- let w = { ...st.world };
1262
+ let w = { ...inputWorlds[i] };
1227
1263
  w.tx += (boneX - w.tx) * mixX;
1228
1264
  w.ty += (boneY - w.ty) * mixY;
1229
1265
  const next = samples[i + 1] ?? { x: 0, y: 0, angle: 0 };
@@ -1253,7 +1289,11 @@ function applyPathConstraint(skel, c) {
1253
1289
  const cos = Math.cos(r), sin = Math.sin(r);
1254
1290
  w = { a: cos * a - sin * bb, b: sin * a + cos * bb, c: cos * cc - sin * d, d: sin * cc + cos * d, tx: w.tx, ty: w.ty };
1255
1291
  }
1256
- setEffectiveWorld(skel, b, st, w);
1292
+ solvedWorlds.set(b.id, w);
1293
+ }
1294
+ for (const b of boneOrder(skel.doc)) {
1295
+ const world = solvedWorlds.get(b.id);
1296
+ if (world) setEffectiveWorld(skel, b, skel.bones.get(b.id), world);
1257
1297
  }
1258
1298
  }
1259
1299
  function measuredPathLength(points, closed, lengths, constantSpeed) {
@@ -1282,9 +1322,14 @@ function inheritedParentLinear(bone, parent) {
1282
1322
  case "onlyTranslation":
1283
1323
  return { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 };
1284
1324
  case "noRotationOrReflection": {
1285
- const lenX = Math.hypot(parent.a, parent.b) || 1;
1325
+ const lenX = Math.hypot(parent.a, parent.b);
1286
1326
  const det = parent.a * parent.d - parent.b * parent.c;
1287
- return { a: lenX, b: 0, c: 0, d: Math.abs(det) / lenX, tx: 0, ty: 0 };
1327
+ if (lenX * lenX <= 1e-4) {
1328
+ const lenY = Math.hypot(parent.c, parent.d), ux2 = lenY ? parent.c / lenY : 0, uy2 = lenY ? parent.d / lenY : 0;
1329
+ return { a: lenY * ux2 * ux2, b: lenY * ux2 * uy2, c: lenY * ux2 * uy2, d: lenY * uy2 * uy2, tx: 0, ty: 0 };
1330
+ }
1331
+ const ux = parent.a / lenX, uy = parent.b / lenX, sy = Math.abs(det) / lenX;
1332
+ return { a: lenX * ux * ux + sy * uy * uy, b: (lenX - sy) * ux * uy, c: (lenX - sy) * ux * uy, d: lenX * uy * uy + sy * ux * ux, tx: 0, ty: 0 };
1288
1333
  }
1289
1334
  case "noScale":
1290
1335
  case "noScaleOrReflection": {
@@ -1310,7 +1355,16 @@ function setEffectiveWorld(skel, bone, st, world) {
1310
1355
  st.scaleY = Math.hypot(lin.c, lin.d);
1311
1356
  st.shearX = 0;
1312
1357
  st.shearY = shortest(Math.atan2(lin.d, lin.c) / DEG2 - st.rotation - 90);
1313
- updateSubtree(skel, bone.id);
1358
+ if (parent && (bone.inherit === "noScale" || bone.inherit === "noScaleOrReflection")) {
1359
+ const direction = mul(invert({ ...parent, tx: 0, ty: 0 }), { ...world, tx: 0, ty: 0 });
1360
+ st.rotation = Math.atan2(direction.b, direction.a) / DEG2;
1361
+ st.scaleX = Math.hypot(world.a, world.b);
1362
+ st.scaleY = Math.hypot(world.c, world.d);
1363
+ const sign = bone.inherit === "noScale" && parent.a * parent.d - parent.b * parent.c < 0 ? -1 : 1;
1364
+ st.shearY = shortest((Math.atan2(world.d, world.c) - Math.atan2(world.b, world.a)) / DEG2 * sign - 90);
1365
+ }
1366
+ st.world = world;
1367
+ updateSubtree(skel, bone.id, false);
1314
1368
  }
1315
1369
  function attachmentWorldVertices(skel, slotId, att) {
1316
1370
  const deform = skel.pose.get(pk("deform", att.id, "vertices"));
@@ -1709,7 +1763,7 @@ var RigPlayer = class {
1709
1763
  this.clipPoints.clear();
1710
1764
  const skel = this.skel = evaluate(this.doc, pose, this.beforePose);
1711
1765
  pose = skel.pose;
1712
- const clips = new Set(this.doc.slots.flatMap((s) => s.clip ? [s.clip] : []));
1766
+ const masks = slotClips(skel), clips = new Set(masks.values());
1713
1767
  for (const [id, g] of this.clipGraphics) if (!clips.has(id)) {
1714
1768
  g.destroy();
1715
1769
  this.clipGraphics.delete(id);
@@ -1736,7 +1790,8 @@ var RigPlayer = class {
1736
1790
  if (Array.isArray(orderV)) orderV.forEach((id, i) => order.set(id, i));
1737
1791
  for (const it of this.items) {
1738
1792
  const s = it.slot, shown = skel.attachment.get(s.id);
1739
- it.node.mask = s.clip ? this.clipGraphics.get(s.clip) ?? null : null;
1793
+ const mask = masks.get(s.id);
1794
+ it.node.mask = mask ? this.clipGraphics.get(mask) ?? null : null;
1740
1795
  if (shown !== it.att || this.hidden.has(s.id)) {
1741
1796
  it.node.visible = false;
1742
1797
  continue;