@energy8platform/golem 0.6.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 (64) hide show
  1. package/README.md +14 -0
  2. package/dist/editor.css +3 -4
  3. package/dist/editor.js +108 -61
  4. package/dist/lib/cli.js +101 -70
  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 +2 -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 +102 -70
  28. package/dist/lib/editor-entry.js.map +4 -4
  29. package/dist/lib/rig-import-layers.d.ts +2 -0
  30. package/dist/lib/rig-version.d.ts +12 -0
  31. package/dist/lib/tool-schema.d.ts +3 -0
  32. package/dist/lib/tools.d.ts +2 -0
  33. package/dist/lib/tools.js +49 -10
  34. package/dist/lib/tools.js.map +4 -4
  35. package/editor.html +2 -2
  36. package/package.json +38 -3
  37. package/skills/e8-golem/SKILL.md +71 -0
  38. package/skills/golem-symbol-animation/SKILL.md +87 -0
  39. package/skills/golem-symbol-animation/agents/openai.yaml +4 -0
  40. package/skills/golem-symbol-animation/references/facial-controls.md +48 -0
  41. package/skills/golem-symbol-animation/references/game-engine-integration.md +133 -0
  42. package/skills/golem-symbol-animation/references/golem-authoring.md +138 -0
  43. package/skills/golem-symbol-animation/references/interactive-editor.md +17 -0
  44. package/skills/golem-symbol-animation/references/motion-craft.md +113 -0
  45. package/skills/golem-symbol-animation/references/packed-delivery.md +88 -0
  46. package/skills/golem-symbol-animation/references/quantitative-qa.md +106 -0
  47. package/skills/golem-symbol-animation/references/spine-rive-study.md +87 -0
  48. package/skills/golem-symbol-animation/scripts/atlas_parts.py +87 -0
  49. package/skills/golem-symbol-animation/scripts/check_package.py +71 -0
  50. package/skills/golem-symbol-animation/scripts/image_gates.py +143 -0
  51. package/skills/golem-symbol-cutting/SKILL.md +70 -0
  52. package/skills/golem-symbol-cutting/agents/openai.yaml +4 -0
  53. package/skills/golem-symbol-cutting/assets/h1/h1.atlas.png +0 -0
  54. package/skills/golem-symbol-cutting/assets/h1/h1.png +0 -0
  55. package/skills/golem-symbol-cutting/references/cutting-workflow.md +92 -0
  56. package/skills/golem-symbol-cutting/references/facial-layers.md +44 -0
  57. package/skills/golem-symbol-cutting/references/generation-workflow.md +109 -0
  58. package/skills/golem-symbol-cutting/references/golem-handoff.md +62 -0
  59. package/skills/golem-symbol-cutting/references/h1-example.md +46 -0
  60. package/skills/golem-symbol-cutting/references/hybrid-workflow.md +119 -0
  61. package/skills/golem-symbol-cutting/references/registration-and-motion.md +89 -0
  62. package/skills/golem-symbol-cutting/references/spine-rive-construction.md +73 -0
  63. package/skills/golem-symbol-cutting/scripts/atlas_parts.py +87 -0
  64. package/skills/golem-symbol-cutting/scripts/hybrid_parts.py +279 -0
package/editor.html CHANGED
@@ -1,3 +1,3 @@
1
1
  <!doctype html>
2
- <html><head><meta charset="utf-8"><title>rig editor</title><link rel="stylesheet" href="/dist/editor.css"></head>
3
- <body><div id="app"></div><script type="module" src="/dist/editor.js"></script></body></html>
2
+ <html><head><meta charset="utf-8"><title>rig editor</title><link rel="stylesheet" href="dist/editor.css"></head>
3
+ <body><div id="app"></div><script type="module" src="dist/editor.js"></script></body></html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energy8platform/golem",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "AI-first 2D rigging for slot games: rig.json format, PixiJS v8 runtime, MCP tools and a browser editor",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -49,7 +49,9 @@
49
49
  "playwright": "^1.50.0",
50
50
  "pngjs": "^7.0.0",
51
51
  "preact": "^10.29.8",
52
- "zod": "^3.24.0"
52
+ "schemastery": "^3.18.0",
53
+ "zod": "^3.24.0",
54
+ "zod-to-json-schema": "^3.25.2"
53
55
  },
54
56
  "devDependencies": {
55
57
  "@esotericsoftware/spine-core": "^4.2.109",
@@ -73,12 +75,19 @@
73
75
  "dist/editor.js",
74
76
  "dist/editor.css",
75
77
  "editor.html",
76
- "bin"
78
+ "bin",
79
+ "skills",
80
+ "!skills/**/__pycache__"
77
81
  ],
78
82
  "bin": {
79
83
  "golem": "bin/golem.js"
80
84
  },
81
85
  "exports": {
86
+ "./package.json": "./package.json",
87
+ ".": {
88
+ "types": "./dist/lib/e8/host.d.ts",
89
+ "import": "./dist/lib/e8-host.js"
90
+ },
82
91
  "./runtime": {
83
92
  "types": "./dist/lib/runtime.d.ts",
84
93
  "import": "./dist/lib/runtime.js"
@@ -94,9 +103,35 @@
94
103
  "./interactive-editor": {
95
104
  "types": "./dist/lib/interactive-editor.d.ts",
96
105
  "import": "./dist/lib/interactive-editor.js"
106
+ },
107
+ "./e8/runtime": {
108
+ "types": "./dist/lib/e8/runtime.d.ts",
109
+ "import": "./dist/lib/e8-runtime.js"
110
+ },
111
+ "./e8/agent": {
112
+ "types": "./dist/lib/e8/agent.d.ts",
113
+ "import": "./dist/lib/e8-agent.js"
97
114
  }
98
115
  },
99
116
  "peerDependencies": {
100
117
  "pixi.js": "^8.6.0"
118
+ },
119
+ "e8": {
120
+ "runtime": {
121
+ "entry": "./dist/lib/e8-runtime.js",
122
+ "schema": "./dist/lib/e8-schema.js"
123
+ },
124
+ "agent": {
125
+ "entry": "./dist/lib/e8-agent.js",
126
+ "skills": "./skills"
127
+ },
128
+ "client": {
129
+ "entry": "./dist/lib/e8-client.js",
130
+ "inject": [
131
+ "viewers",
132
+ "history",
133
+ "connection"
134
+ ]
135
+ }
101
136
  }
102
137
  }
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: e8-golem
3
+ description: Use in an e8-engine project to build, animate and place Golem rigs — the rig_* tools, the golem scene node, the rig editor tab and undo.
4
+ ---
5
+
6
+ # Golem rigs in e8
7
+
8
+ The `golem1` row (`@energy8platform/golem`) gives the agent every `rig_*` tool, registers the `golem` scene node type and opens `rig.json` files in the rig editor inside the IDE. Rigging and animation craft lives in `golem-symbol-animation` (and `golem-symbol-cutting` for flat art); this skill is how that work lands in an e8 project.
9
+
10
+ ## Where rigs live
11
+
12
+ One directory per rig under `assets/` (the build copies only `assets/`):
13
+
14
+ ```
15
+ assets/rigs/<name>/rig.json the document
16
+ assets/rigs/<name>/layers/*.png parts (or one atlas.png after rig_export)
17
+ ```
18
+
19
+ `path` in every `rig_*` call is project-relative (`assets/rigs/gem/rig.json`); other file arguments (`layersDir`, `image`, `outDir`…) are relative to the rig's directory. Anything outside the project is refused.
20
+
21
+ ## Build a rig
22
+
23
+ 1. `files_list` — find the layers (PNG parts) or the single symbol image.
24
+ 2. One image: `rig_create_symbol` with `{ "path": "assets/rigs/gem/rig.json", "image": "../../symbols/6.png" }`. Layers: `rig_create`, then `rig_import_layers` with `{ "layersDir": "layers" }`.
25
+ 3. Animate with `rig_apply_preset` / `rig_set_keys` (see `golem-symbol-animation`), checking each step with `rig_render_preview` — it answers with a picture.
26
+ 4. `rig_check` before placing it.
27
+
28
+ ## Place it
29
+
30
+ A `golem` node goes in a scene document (`e8-scenes`) or a symbol state (`e8-symbols`). Its props:
31
+
32
+ - `rig` (required) — the `rig.json`, project-relative;
33
+ - `animation` — empty means the rig's first animation;
34
+ - `loop` (default true), `speed` (default 1);
35
+ - `controls` — expression controls by id, `{ "smile": 0.8 }`. A set control overrides that control's animated track; an empty map gives the tracks back.
36
+
37
+ The node's origin is the centre of the rig's canvas (`meta.width` × `meta.height`), so `x`/`y` place that centre.
38
+
39
+ ### In `base_game`
40
+
41
+ `scenes_get` with `{ "id": "base_game" }`, append the node, `scenes_put` the whole document:
42
+
43
+ ```json
44
+ { "id": "gem_hero", "type": "golem", "props": { "rig": "assets/rigs/gem/rig.json", "animation": "idle", "x": 400, "y": 260 } }
45
+ ```
46
+
47
+ ### A symbol that wins with a rig
48
+
49
+ `symbols_get`; give the symbol a `win` state and `symbols_put` the whole document:
50
+
51
+ ```json
52
+ { "id": "6", "name": "gem",
53
+ "static": { "type": "image", "props": { "src": "assets/symbols/6.png" } },
54
+ "win": { "type": "golem", "props": { "rig": "assets/rigs/gem/rig.json", "animation": "win", "loop": false } } }
55
+ ```
56
+
57
+ As a symbol state the node plays its `animation` once to the end.
58
+
59
+ ## Live editing and undo
60
+
61
+ - A `rig_*` write reaches the open rig tab and the running preview without a reload.
62
+ - Each of your writes is one undo step in the IDE: Mod+Z on the rig's tab runs `rig_undo` for the latest, again for the one before, and redo walks forward. A step is refused, file untouched, when the rig changed since (a human edit, or your own `rig_undo`).
63
+ - Your `rig_undo`, `rig_redo` and `rig_export` calls are not IDE steps. Ctrl+Z inside the editor and `rig_undo` walk the same history.
64
+ - `rig_render_preview`, `rig_export_video` and `rig_verify_render` need Chromium on the host machine (`npx playwright install chromium`).
65
+
66
+ ## Traps
67
+
68
+ - An `animation` the rig does not have falls back to the first animation, silently. `rig_get` lists the ids.
69
+ - A `.json` that is not a rig (no `"format": "energy8.rig"`) is an error on the node.
70
+ - Replacing a PNG by hand does not refresh a placed rig; a `rig_*` call that rewrites `rig.json` does.
71
+ - `anchor` does nothing on a `golem` node.
@@ -0,0 +1,87 @@
1
+ ---
2
+ name: golem-symbol-animation
3
+ description: Build or continue editable symbol and full-character rigs and animations in Golem from prepared PNG layers, an atlas, or an existing rig. Use for motion briefs, layered rigging, playback verification, Golem exports and integration with @energy8platform/game-engine. Use golem-symbol-cutting when flat artwork needs animation-driven separation or hidden-surface repair.
4
+ ---
5
+
6
+ # Golem symbol animation
7
+
8
+ Create an editable Golem rig, animation tracks matching the requested performance, and reviewable playback. Use Golem's tool registry for rig operations.
9
+
10
+ ## Inputs
11
+
12
+ Accept prepared layers, an atlas with any available metadata, an assembled reference, or an existing Golem rig. Preserve source artwork. For follow-up changes, continue from the working rig and retain useful tracks rather than rebuilding unnecessarily. If the user supplies a Spine skeleton and atlas, inspect `rig_import_spine` and its warnings before deciding what must be reconstructed manually.
13
+
14
+ ## Establish the performance before rigging
15
+
16
+ Reuse the supplied animation plan, prepared `layers/layers.json` sidecar and extraction provenance. Establish each action's trigger, emotional intent, main beats, extreme poses, duration or timing constraints, loop behavior and entry/exit state. Include display size, contact point and intended FX. When the rig will run in a game, identify the actual engine lifecycle hook for every action; an animation existing in `rig.json` does not make the game call it. Ask only for missing decisions that materially affect the work; use stated working assumptions when the user delegates creative direction.
17
+
18
+ Map each beat to required controls and visibility changes. If flat art needs separation, hidden surfaces are missing, or a new action exceeds the prepared art's coverage, use [golem-symbol-cutting](../golem-symbol-cutting/SKILL.md) for the affected parts. Pass back the same brief and preserve decisions that remain valid. If that sibling is unavailable, document the required preparation and complete what the available art supports.
19
+
20
+ Do not infer the original animation set, emotion or FX sequence from atlas packing. An existing brief takes priority over the illustrative `land`/`idle`/`win` patterns below.
21
+
22
+ ## Establish the working surface
23
+
24
+ Locate Golem through the workspace checkout or the installed `@energy8platform/golem` package. Read applicable repository instructions and inspect package exports/scripts before choosing commands: the installed `golem` binary may expose only the editor, while the checkout has a separate rig CLI. If neither is available, ask for the Golem environment rather than silently substituting another product.
25
+
26
+ Read [references/golem-authoring.md](references/golem-authoring.md) before building the rig or writing tracks. When the target is an `@energy8platform/game-engine` project, also read [references/game-engine-integration.md](references/game-engine-integration.md). Verify needed tool schemas and package exports against the current installation. Use a connected Golem MCP, the supported rig CLI, or `callTool` from `@energy8platform/golem/tools` (checkout: `src/rig-api.ts`); these share mutation validation and history. Do not hand-write the finished rig around the tools.
27
+
28
+ Keep authoring work outside the delivered rig directory, for example in `art/symbol-work/<id>/`. The delivered symbol directory contains exactly `rig.json` and one `atlas.png` shared by all its actions, expression variants and FX. No layers, scripts, QA, history, duplicate rig or nested `packed/` directory belongs there. Read [references/packed-delivery.md](references/packed-delivery.md) before creating output paths; it defines staging, history preservation, packing and package verification. Use the user's destination and preserve unrelated work and existing deletions.
29
+
30
+ ## Editable in-page previews
31
+
32
+ When the user requests a preview they can adjust with the mouse, read [the interactive editor workflow](references/interactive-editor.md) and verify that the installed package exports `@energy8platform/golem/interactive-editor` before using it. Group coupled artwork under one logical control so, for example, a hand and its companion layers stay registered during edits. Keep editor patches separate from the canonical rig and animation keys; export and reapply them explicitly through the documented workflow rather than claiming that a preview adjustment has rewritten the source animation.
33
+
34
+ After editing, check selection and manipulation at the actual display size, replay affected actions at normal speed, and inspect extremes, overlaps and contacts with the patch reapplied. Record the patch and its limitations outside the packed rig directory. An editable Golem preview or patch is not a Spine project or proof of Spine export compatibility.
35
+
36
+ ## Reconstruct the artwork
37
+
38
+ 1. Inspect supplied layers/atlas and assembled reference. Use a light/checker background: black strokes and transparent cutouts are easily missed on black. Record actual pixel dimensions; convert resized inspection coordinates back to original pixels.
39
+ 2. Reuse verified source metadata and the cutting manifest before making new visual guesses. Keep extraction rectangles separate from document placement, joints, parents and slot draw order. A horn or ear can span several atlas regions. Preserve the handoff's side convention; otherwise use viewer-left/right consistently.
40
+ 3. If extraction is still needed, use `scripts/atlas_parts.py` for checker inspection and deterministic rectangular crops. Run `--help`. It requires Pillow, preserves decoded RGBA values and performs no rotation, masking or reconstruction. Undo packing rotation separately. Skip re-extraction when prepared layers already exist.
41
+ 4. Fit translations, rotations and scale using the supplied assembled PNG. Optional pixel matching must tolerate occluded surfaces, try quadrant rotations, and remain subordinate to visual inspection. A low matching error alone does not prove correct part identity or assembly.
42
+ 5. Inspect each crop, then a Golem rest render. Check missing tips, truncated contours, doubled strokes, neighboring atlas fragments and seams at overlaps. Do not globally discard small alpha components: fangs, chin strokes, spark fragments and lower eyelids may be intentional. Make any cleanup local, reversible and documented.
43
+
44
+ Without an assembled reference, use a clearly stated interpretation of the visible parts; do not invent claims of exact original reconstruction. Ask only when ambiguity prevents a usable symbol.
45
+
46
+ ## Author motion
47
+
48
+ For Spine imports, flexible full characters or interacting expression/motion layers, read [references/spine-rive-study.md](references/spine-rive-study.md). Verify selected skins, inherited deformation, clipping spans, component curves and actual runtime transitions before claiming fidelity.
49
+
50
+ For reusable adjustable eyes, gaze and mouth expressions, read [facial-controls.md](references/facial-controls.md). It covers optional Golem 0.4 parameter grids, ownership, editor keyforms and combined-pose validation.
51
+
52
+ Read [motion-craft.md](references/motion-craft.md) for continuous curves, minimum-jerk contacts,
53
+ planted-foot IK, cloth/hair chains, mesh limits, grip changes and baked secondary motion.
54
+ Use a pilot containing the hardest extreme and transition before multiplying the approach
55
+ across animations or characters. Seek user review when the brief calls for it or the pilot
56
+ changes approved appearance; existing approval remains valid.
57
+
58
+
59
+ For independently generated facial parts or corrections to scale, placement or FX, read [registration-and-motion.md](../golem-symbol-cutting/references/registration-and-motion.md). Verify every expression in the composed rig before polishing motion. Equal PNG dimensions, a shared scale factor or matching bbox centers do not establish matching facial proportions. Prefer a clean head base plus local feature controls for local expression changes; use full-head swaps only when the performance needs a whole-head redraw.
60
+
61
+ Build controls around the actual artwork and performance. For a bust with a cell landing, this often means a contact-point root, a head pivot near the neck, and controls for independently moving features. Other symbols may need a different hierarchy. Keep fragments of one rigid part registered to the same logical control; put simultaneously visible images in separate slots. Use one slot for mutually exclusive variants where appropriate. Check painted overlap and facial backing against the planned extreme poses before polishing timing.
62
+
63
+ Match the user's requested set and tone. If the request matches the usual three-state slot workflow, use these as starting points, not fixed timings or universal presets:
64
+
65
+ - `land`: quick descent, readable contact compression, restrained rebound and settling of ears/horns. Maintain a believable cell contact point and leave room above the symbol.
66
+ - `idle`: small breathing and head/ear movement with an occasional blink. Make t=0 the approved setup pose unless the brief explicitly defines another base; match first/last pose and velocity, including attachment visibility and other animated channels.
67
+ - `win`: anticipation, a clear celebratory accent, expression change if the atlas supports it, secondary motion and a return suitable for idle. Effects should support the face and remain legible at cell size.
68
+
69
+ Author local motion where the performance calls for it; a deliberate whole-symbol pulse does not require artificial facial movement. Use meshes where bending or surface deformation is part of the brief. If the prepared art cannot support a required extreme, return that specific issue to cutting/repair or explicitly revise the brief instead of silently reducing the requested action.
70
+
71
+ For blinks, coordinate lids and eye visibility; squashing the eyeball alone can leave a white hairline. Keep the mouth cavity behind an open-mouth cutout throughout its movement. Verify facial landmark registration and companion-slot visibility on both sides of an expression switch. Hide transient effects in setup and outside their active interval, unless the brief specifies a persistent effect. Use supplied FX only with a verified or explicitly authored sequence and stable frame alignment; packing order is not playback order.
72
+
73
+ When mouth opening requires jaw travel, animate the lower face/chin with a suitable mesh or jaw control and coordinate the mouth, cavity and teeth with it. Anchor the upper face and nose unless the brief calls for their movement; a moving mouth sticker alone does not move the jaw. Inspect opening, maximum extension, closing and return for folds, detached contours and pops. Do not add a mesh merely to increase the vertex count.
74
+
75
+ ## Verify and deliver
76
+
77
+ Use [quantitative-qa.md](references/quantitative-qa.md) for reproducible numerical gates and current render evidence. Run `rig_validate` and `rig_check` and read their text: a successful tool invocation alone does not mean there are no findings. Render setup and the meaningful phases of the actual brief, including extremes and frames around visibility switches. Inspect at intended symbol size as well as larger detail views. Refine until assembly and motion are visually sound.
78
+
79
+ Play each action at its actual speed and intended cell size. Check that idle is perceptible without zooming or scrubbing and that the main beat and secondary motion read clearly; restrained does not mean invisible. A contact sheet, error-free load, build or checker result cannot establish this. For a reported visual defect, compare before/after at the same framing, inspect all affected variants and both sides of switches, and state what was observed. Do not declare a visual issue fixed from PNG measurements or technical checks alone.
80
+
81
+ Resolve clipping, broken references, folds, unintentional discontinuities and loop seams. Investigate `motion_pop` warnings with nearby frames and timing: a deliberate fast impact can trigger the heuristic, but warnings are not automatically harmless. Preserve any accepted findings with their concrete explanation; never claim all checks pass while leaving unexamined warnings.
82
+
83
+ Compare loop endpoints and action-to-action transitions across transforms, constraint channels, deformations, attachments, alpha, colors and draw order. Inspect motion immediately around loop boundaries as well as matching values. A looping preview at exactly its duration wraps to the start; inspect the true terminal keys/pose separately as described in the authoring reference. Matching bone matrices alone does not establish a seamless transition. Use denser sampling when brief extrema could be missed, through the supported preview options or the direct checker API described in the reference.
84
+
85
+ Deliver one editable packed rig and one atlas through the workflow in [packed-delivery.md](references/packed-delivery.md). Packing is required for each delivered revision, including follow-up fixes. Render representative setup, expression, deformation and FX states from the packed package against the working rig and inspect meaningful differences. For a game-engine target, load this same pair through the engine entry point. Keep requested GIF/MP4 previews and demonstrations outside the rig directory.
86
+
87
+ Record sources, placement decisions, durations, animation IDs, trigger mappings, reproducible scripts and limitations in the external authoring workspace. Open the delivered packed rig in Golem when a local editor is available; reuse its server before starting another, and do not terminate somebody else's process. Keep the editor and game pointed at the same canonical package; use a staging copy for further mutations. Report visual, authoring, package and integration checks separately. Link the rig, atlas and external preview in the final response.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Golem Symbol Animation"
3
+ short_description: "Rig, animate and integrate Golem characters and symbols"
4
+ default_prompt: "Use $golem-symbol-animation to build or continue a Golem symbol rig, animate it according to the supplied motion brief, and integrate it with the game engine when requested."
@@ -0,0 +1,48 @@
1
+ # Parametric facial animation
2
+
3
+ Use this workflow when several actions reuse independently adjustable eyes, gaze,
4
+ mouth opening or expression. Confirm the installed Golem supports `rig_set_control`,
5
+ `rig_set_control_binding` and `rig_sweep_controls` (0.4+). Existing attachment swaps
6
+ remain appropriate for fully redrawn expressions.
7
+
8
+ Keep the approved neutral face. Plan controls and ranges from the requested performance;
9
+ measure each side separately. A smile and an opening mouth often need a joint 2D grid,
10
+ not the sum of two independent deformations. Use one owner per output channel. The grid
11
+ contains absolute bone/alpha values and mesh vertex offsets, with the first axis varying
12
+ fastest. Axes span the full declared ranges. Match the default keyform to approved setup.
13
+
14
+ Author through the registry. `rig_set_control` declares id/label/min/max/default;
15
+ `rig_set_control_binding` declares 1–2 axes and channels. Supported outputs are bone
16
+ transforms, slot alpha and mesh/path vertex offsets. Key `target: control`, `prop: value`
17
+ with existing track tools. Direct keys on bound channels are rejected. Constraints run
18
+ after controls; check ownership when both affect a bone. Keyform editing and temporary
19
+ preview sliders are in the editor's expressions mode; record a preview with Key expression.
20
+
21
+ Check mouth form × mouth opening, separate winks, near-open eyes, gaze extremes and
22
+ head/body counter-motion relevant to this rig. For `rig_sweep_controls`, pass explicit
23
+ probe arrays and a new output directory outside the packed rig. Add samples on both
24
+ sides of geometry/opacity handoffs; the 256-pose budget is a bound, not a coverage target.
25
+ The report binds listed cases to actual PNG/rig/texture/renderer hashes. A geometric
26
+ effect or numerical pass does not prove visible pixel movement or attractive artwork.
27
+ Inspect the frames at cell size and facial closeups, and play the actual animation.
28
+
29
+ For blinks, coordinate a continuous eyelid curve with eye-white/iris coverage and closed
30
+ lashes. Two overlapping half-alpha strokes yield 0.75 coverage, so a naive crossfade can
31
+ create a pale seam. Evaluate the actual composite around handoffs. Avoid zero-area mesh
32
+ triangles; hide a fully closed aperture with explicit opacity/masking if needed.
33
+
34
+ An opaque closed-lash repair should enter when the aperture and lash are already aligned.
35
+ Fading it across a still-white opening can create a grey band even when geometry passes.
36
+ Sample densely near that handoff. For boundary-pinned surface patches, check actual
37
+ rendered alpha during head rotation as well as setup; see the cutting skill's facial-layer
38
+ reference for source-derived underlap that preserves soft external contours.
39
+
40
+ For neutral and packed comparisons, retain raw RGBA diagnostics and also compare composites
41
+ over black and white. Unpremultiplication can amplify tiny RGB errors at low alpha. An
42
+ unmodified source rendered through the same pipeline helps distinguish those errors from
43
+ an authoring change; retain the raw-source comparison too, and report concrete tolerances.
44
+
45
+ Use `RigPlayer.setControls(values)` for runtime manual input; each call replaces the input
46
+ set, and `resetControls()` returns ownership to animation/defaults. Generic preset export
47
+ currently lists control tracks as skipped; do not claim automatic transfer to other faces.
48
+ Pack and compare the working/packed expressions through the normal delivery workflow.
@@ -0,0 +1,133 @@
1
+ # Integrating a Golem rig with game-engine
2
+
3
+ Use this workflow when the target project depends on
4
+ `@energy8platform/game-engine` and `@energy8platform/golem`. Verify the installed
5
+ package versions and their current exports before changing game code; the
6
+ examples describe the implemented 0.43/0.1 integration and may evolve.
7
+
8
+ ## Deliver one canonical package
9
+
10
+ The editable package loaded by the game is:
11
+
12
+ ```text
13
+ public/assets/rigs/<symbol-id>/
14
+ rig.json
15
+ atlas.png
16
+ ```
17
+
18
+ Every asset `src` resolves to this same `atlas.png`; frame metadata selects each
19
+ part. All actions share the pair. Keep layers, working rigs, scripts, previews
20
+ and history outside the delivered rig directory, following
21
+ [packed-delivery.md](packed-delivery.md). Stage edits there, export and verify,
22
+ then update the canonical pair. Do not keep an editable/packed duplicate inside
23
+ `public/assets/rigs/<symbol-id>/`.
24
+
25
+ Prefer the project's `npm run rigs` and inspect its configured root. With
26
+ `golem editor --root public/assets/rigs`, the query is
27
+ `editor.html?rig=<symbol-id>/rig.json`; with a root at the symbol directory it is
28
+ `editor.html?rig=rig.json`. Do not give users different rigs for editor and game.
29
+ Use a staging copy for mutations and preserve its `.rig-history/` for undo.
30
+
31
+ For production builds, verify no authoring files or `.rig-history/` reach the
32
+ output. If the game has an engine history-strip plugin, keep it enabled, but a
33
+ build filter does not replace the clean source-package check.
34
+
35
+ ## Load through the engine entry point
36
+
37
+ In game code, use the engine adapter so the rig shares the game's PixiJS and
38
+ the `SymbolView` contract:
39
+
40
+ ```ts
41
+ import {
42
+ loadRigs,
43
+ RigSymbol,
44
+ type Rig,
45
+ } from '@energy8platform/game-engine/golem';
46
+
47
+ const rigIds = ['h1'] as const;
48
+ let rigs: Record<string, Rig> = {};
49
+
50
+ export async function loadSymbolRigs() {
51
+ rigs = await loadRigs(Object.fromEntries(
52
+ rigIds.map(id => [id, `assets/rigs/${id}/rig.json`]),
53
+ ));
54
+ }
55
+
56
+ export const resolveSymbol = (id: string) => rigs[id]
57
+ ? new RigSymbol(rigs[id].doc, rigs[id].textures, { size: 110 })
58
+ : createOrdinarySymbol(id);
59
+ ```
60
+
61
+ Call the loader before the first symbol resolution. List rigged symbols
62
+ explicitly: `loadRigs` rejects missing named files rather than probing 404s.
63
+ Do not import the Node tools or editor entry into browser game code. Avoid a
64
+ second PixiJS installation; `@energy8platform/golem` uses the game's `pixi.js`
65
+ as a peer.
66
+
67
+ For a character outside the reels, create a `RigPlayer`, add `player.view` to a
68
+ Pixi container and advance `player.tick(seconds)` from the scene update.
69
+ `RigSymbol` advances itself with a ticker and removes its callback on destroy.
70
+
71
+ ## Map animations to game lifecycle
72
+
73
+ `RigSymbol` defaults to these animation IDs:
74
+
75
+ - `idle`: looping base state used by `playIdle()`.
76
+ - `win`: non-looping action used by `playWin()`; the returned promise resolves
77
+ on completion, and playback returns to the base state when one is established.
78
+ - `dim`: optional held state used by `setDim(true)`.
79
+
80
+ Different IDs can be mapped with
81
+ `animations: { idle: 'breath', win: 'celebrate', dim: 'lose' }`. Verify that the
82
+ mapped actions have the required loop and terminal behavior. `showStatic()`
83
+ clears animation state and displays the rig's setup pose.
84
+
85
+ `land`, `hit`, overlays and other custom actions are not automatic
86
+ `SymbolView` lifecycle hooks. Record and implement their game-owned trigger,
87
+ for example through `symbol.player.state.play('land')` or the scene's own
88
+ controller. Do not call an action integrated merely because it exists and plays
89
+ inside Golem.
90
+
91
+ ## Verify in the real container
92
+
93
+ In addition to `rig_validate`, `rig_check` and Golem previews:
94
+
95
+ 1. Load the rig with `loadRig`/`loadRigs` from the game-engine entry.
96
+ 2. Mount `RigSymbol` in a real `SymbolCell` or the project's actual resolver.
97
+ 3. Exercise `playIdle`, `playWin`, `showStatic`, `resize` and destruction.
98
+ 4. Test both a square numeric size and a rectangular `{ width, height }` size.
99
+ The rig canvas is fitted and centered, so inspect cell clipping, perceived
100
+ scale, contact point and motion margins rather than only type success.
101
+ 5. Exercise every custom game trigger and the transition back to idle.
102
+ 6. Run the Golem checkout's `npm run verify:engine` when its expected sibling
103
+ engine or target game is available, then run the target game's typecheck and
104
+ relevant build/test command.
105
+
106
+ Report exactly which layers were checked: Golem authoring, packed equivalence,
107
+ engine adapter loading, real-cell lifecycle, target-game typecheck and
108
+ production build are separate claims.
109
+
110
+ ## Transition and animation-ID contract
111
+
112
+ Inspect the runtime actually installed in the game. In the updated checkout, `RigPlayer`
113
+ defaults to a 0.18-second mix and `play()` inherits the constructor mix unless overridden;
114
+ `mix: 0` is an explicit hard cut. Older versions force `play()` to mix 0 even when the
115
+ constructor supplies another mix. Always pass the intended mix at the game call site when
116
+ supporting those versions. `AnimationState.play()` also accepts a per-call mix; direct state
117
+ calls and player calls must be tested separately when the game uses both.
118
+
119
+ The updated runtime warns for an unknown animation and drops the invalid request, resolving
120
+ pending work and returning to its existing base (or setup if no base exists). For strict QA,
121
+ construct the player/state with `missingAnimation: "throw"`; `onWarning` can capture warnings
122
+ in a game log. Older versions throw on missing IDs unconditionally. Runtime recovery is not
123
+ permission to deploy an incomplete action set: before replacing the game's canonical pair,
124
+ compare every lifecycle mapping and custom trigger against the delivered document's IDs.
125
+ Stage a partial pilot outside the game until its required action contract is complete.
126
+
127
+ Transition gates must execute the real `AnimationState`, or `RigPlayer` where wrapper options
128
+ matter. Use the same base, overlays, priorities, explicit/default mixes and update cadence as
129
+ the scene. Exercise action → base, action interruption, missing IDs, visibility swaps, colour,
130
+ constraint mixes, draw order and deform arrays. Do not replace this with a handwritten lerp:
131
+ it can pass a transition the game never performs. In a mixed transition, newly introduced
132
+ numeric channels blend from setup; discrete channels remain at the previous state until the
133
+ mix ends. Inspect those actual intermediate poses for contact and layering problems.
@@ -0,0 +1,138 @@
1
+ # Golem authoring mechanics
2
+
3
+ Use this as guidance, then check the current checkout's schemas. Golem APIs can change.
4
+
5
+ ## Tool entry points
6
+
7
+ First distinguish a Golem source checkout from a game with the installed package.
8
+ The commands below require the checkout's `rig` npm script. The published `golem`
9
+ binary currently exposes `editor`, not `list` or `rig list`. In a game, inspect its
10
+ scripts and use `@energy8platform/golem/tools` for registry operations:
11
+
12
+ ```js
13
+ import { tools, callTool, closeTools } from '@energy8platform/golem/tools';
14
+ const entry = tools.find(tool => tool.name === 'rig_import_layers');
15
+ console.log(entry?.description, entry?.input.shape);
16
+ ```
17
+
18
+ Use the exported schema's `safeParse` to check arguments; do not repeatedly guess
19
+ CLI variants or dump bundled source maps. Installed packages may contain only
20
+ `dist/lib`, not `src`, and may not export `package.json` as a module subpath. Resolve
21
+ the supported `tools` entry and inspect the package files from there if necessary.
22
+
23
+ ```sh
24
+ npm run rig -- list
25
+ npm run rig -- rig_validate '{"path":"symbols/example/rig.json"}'
26
+ ```
27
+
28
+ For many related calls, place an authoring TypeScript script inside the checkout and import its current registry with the appropriate relative path:
29
+
30
+ ```ts
31
+ import { callTool, closeTools } from '../../src/rig-api';
32
+ const path = 'symbols/example/rig.json';
33
+ async function tool(name: string, args: Record<string, unknown> = {}) {
34
+ const result = await callTool(name, { path, ...args });
35
+ if (result.isError) throw new Error(result.text);
36
+ // Persist request + response in the authoring log.
37
+ return result;
38
+ }
39
+ try {
40
+ await tool('rig_create', { name: 'Example', width: 640, height: 640 });
41
+ // Add bones, import authored layers, place attachments, set tracks.
42
+ } finally {
43
+ await closeTools();
44
+ }
45
+ ```
46
+
47
+ Use `node --import tsx path/to/authoring.ts`. Apply dependent mutations sequentially. Stop on `isError`; a failed operation must not be treated as saved. Rebuilding starts from `rig_create` and reapplies the authored steps; do not rerun only a stage that adds already-existing IDs.
48
+
49
+ The wrapper above catches invocation/mutation failures. `rig_validate` can return validation problems in `text` without `isError`; `rig_check` also returns findings as text. Read both reports. For programmatic checks, `validate` in `src/rig-format.ts` returns validation errors and `checkRig` in `src/rig-check.ts` returns structured findings. Do not use CLI exit status alone as a quality gate. Creating at an existing path replaces the rig after saving history, so use a fresh output path for experiments.
50
+
51
+ ## Editing setup after animation exists
52
+
53
+ Setup changes and animation changes are distinct. Bone keys are absolute: moving a
54
+ setup bone does not rebase its keyed x/y/rotation. Before accepting an editor fix,
55
+ compare the new setup with every track addressing the changed control, including
56
+ unkeyed actions and inherited child motion. For a translation-only registration
57
+ change, add the setup delta to the affected absolute keys while preserving timing
58
+ and motion offsets; do not apply that shortcut to a changed parent, pivot, scale or
59
+ rotation without re-evaluating world-space poses. Check both action entry/exit and
60
+ all loop channels, then re-render the current file. Previous QA is stale after an
61
+ editor mutation even when its atlas did not change.
62
+
63
+ ## Coordinates and layer import
64
+
65
+ Resolve `layersDir` from the rig's directory, not the shell working directory.
66
+ `relPrefix` independently describes how `asset.src` reaches those same PNGs from
67
+ the rig. For a staging rig `work/rig.json` and layers at `work/layers/`, both are
68
+ `layers`; passing `art/symbol-work/id/work/layers` again would duplicate the path.
69
+ Check that both resolved locations agree and exist before calling the importer.
70
+
71
+ Golem uses pixels, origin top-left, positive Y downward, and degrees clockwise. Bone transforms and animation values are local to parents. Bone key values are **absolute**, not deltas: if setup Y is -115, an offset of -4 means a key value of -119.
72
+
73
+ `rig_create` starts the root at bottom-center. Reposition it deliberately before importing. Leave canvas margins for the entire motion, including rotated rectangle corners and effects, not only setup opaque bounds.
74
+
75
+ `rig_import_layers` reads an agent-authored `layers/layers.json` sidecar, for example:
76
+
77
+ ```json
78
+ [
79
+ {
80
+ "id": "head", "file": "head.png", "parent": "root", "z": 10,
81
+ "bbox": [170, 140, 280, 280], "joint": [310, 400]
82
+ },
83
+ {
84
+ "id": "smile", "file": "smile.png", "bone": "head",
85
+ "slot": "head", "swap": true, "z": 10,
86
+ "bbox": [170, 140, 280, 280], "joint": [310, 400]
87
+ }
88
+ ]
89
+ ```
90
+
91
+ These `bbox` and `joint` values describe **placement in the document**, not source-atlas crop coordinates. Keep extraction rectangles in a separate authoring manifest. Use original source rectangles as provenance, not as document placement.
92
+
93
+ The current importer uses the full evaluated host matrix and its inverse for both joints and images, including parent rotations, scales, reflections and shear. `bbox` is the intended document-space rectangle; its width/height may differ from the PNG size and determine the drawn size. When the host would require shear that a region cannot express, the importer creates a four-vertex mesh preserving all corners. Check the assembled result under the actual constraints. Legacy releases added translations only and treated `bbox` as provenance: for those, import with neutral parent transforms or place attachments explicitly; do not assume the new behavior until the installed tool is verified.
94
+
95
+ The cutting skill delivers this sidecar together with its animation brief and extraction provenance. Use it directly after checking paths and dimensions. If only an older `parts-plan.json` is available, convert it: for an unrotated, unscaled crop at `[x,y]` with final PNG dimensions `[w,h]` and local pivot `[px,py]`, use `bbox: [x,y,w,h]` and `joint: [x+px,y+py]`. Source-atlas `rect` stays in provenance. Keep `parent`, `bone` and `slot` references valid, and ensure `relPrefix` points from the rig directory to the actual PNG folder. Validate JSON before import: the current importer uses filename inference only when the sidecar is absent; malformed JSON fails. Older versions may silently fall back.
96
+
97
+ `rig_set_attachment` x/y are image-center coordinates in the slot bone's space. Rotation on the attachment preserves a convenient bone axis for animation. Use `rig_get_pose` to inspect placements numerically; its slot bbox is `[minX,minY,maxX,maxY]`, unlike the importer's `[x,y,width,height]`. Hidden swap layers use `swap: true`; a new swap slot starts empty, while importing swaps into an existing slot leaves its current attachment selected. Explicitly choose setup visibility with `rig_set_slot`. Attachment IDs may differ from asset IDs; slot attachment keys select attachment IDs.
98
+
99
+ Use a feature hierarchy such as root → head → ear or root → head → horn_base → horn_tip. Face switches can reuse a head slot. For effects, a dedicated bone avoids accidentally scaling all face geometry to enlarge a flash.
100
+
101
+ ## Tracks and visibility
102
+
103
+ `rig_set_tracks` accepts `animation`, `duration`, `loop` and an array of tracks:
104
+
105
+ ```json
106
+ {
107
+ "target": "bone", "id": "root", "prop": "scaleY",
108
+ "keys": [
109
+ {"t": 0, "v": 1, "ease": "ease_in"},
110
+ {"t": 0.2, "v": 0.9, "ease": "ease_out"},
111
+ {"t": 0.5, "v": 1}
112
+ ]
113
+ }
114
+ ```
115
+
116
+ Easing belongs to the interval **from this key into the next key**; omitted easing defaults to `ease_in_out`, which gives zero velocity at both ends of every segment. For continuous pass-through motion set track `interpolation: "pchip"`; it calculates shared tangents across numeric keys and still honours `step`. Use `minimum_jerk` easing only at deliberate stops (zero endpoint velocity and acceleration). See [motion-craft.md](motion-craft.md). Use explicit `step` for discrete attachments and intentional continuous curves for motion. Give entry and endpoint values explicitly. Sampling before the first key already returns that first key's value: a delayed FX activation needs a null/hidden key at t=0.
117
+
118
+ With `merge: false` (default), each addressed track's keys are replaced, but unrelated tracks remain. With `merge: true`, keys at supplied times are replaced and other times remain. Inspect for obsolete tracks when revising. If rebuilding an animation is necessary, preserve its desired tracks, events and loop/timing settings, then use `rig_remove_animation` and recreate it through tools. Do not mistake a partial `rig_set_tracks` call for replacement of the entire animation.
119
+
120
+ Slot `attachment` tracks take attachment IDs or null; alpha is a separate numeric channel. Both affect visibility. A hidden effect bone can have a nontrivial transform without making the effect visible; check its slot too. Background mouth art must cover the full aperture throughout the animation, not merely at setup.
121
+
122
+ ## Rendering and export
123
+
124
+ Use `rig_render_preview` with explicit `times`, `scale`, `sheetColumns` and `saveTo`. Create the output directory first. Use close-ups or onion skin only when they answer a concrete assembly/motion question. The registry's preview calls include rig-check findings; read them. The tool exposes `background`, `transparent`, `weightBone`, `debugFillMasks` and `framesDir`. Transparent mode writes actual alpha; opaque mode is needed to assess additive/multiply blending against the game background. `framesDir` saves frames and a capture manifest for `rig_verify_render`.
125
+
126
+ For individual frames, the current `src/preview/render-preview.ts` exports `renderPreview`. It takes a parsed document plus `assetsDir`, explicit sample times, scale and optional background, returning `frames` and a contact `sheet`. Use `rig_export_video` for MP4 at `fps: 60` (local ffmpeg required), or its returned frames for another encoder. MP4 output is opaque and duration is rounded to a whole frame, then reported. Close the preview browser in `finally`. A preview video may have an opaque presentation background while the source PNGs and exported atlas retain transparency.
127
+
128
+ For loop playback, use N evenly spaced times `D*i/N`, `i=0..N-1`, where `N=max(1,round(D*F))`. This covers `[0,D)` without duplicating the start. An encoder running at F FPS gives duration N/F; if D*F is not integral, explicitly choose whether to quantize duration or adjust the encoding rate. A presentation hold is separate from game timing.
129
+
130
+ At `t=D`, the current preview player wraps looping animations to t=0. It therefore cannot reveal a mismatched terminal pose by rendering `[0,D]` on the loop unchanged. Use `rig_get_pose` and direct `poseOf(animation,D)`/`evaluate` for unwrapped inspection. For a visual terminal check, pass an in-memory document copy with that animation's `loop: false` to `renderPreview`; do not change the saved animation solely for QA. Render just before/at/after the wrap for playback continuity. Also inspect terminal slot state, deformations, constraint values and draw order; `rig_get_pose` does not expose every animated channel.
131
+
132
+ The `rig_check` tool accepts `path`, optional `animation`, `fps`, `deformFps`, `secondaryBones`, `frontOf`, `landmarks` and `landmarkTolerance`. The same options work in direct `checkRig`. Semantic rules and landmark maps come from the brief, not inferred anatomy. Explicit preview times should include short extrema and both sides of attachment changes, which a uniform grid may miss.
133
+
134
+ `rig_export` takes an output directory relative to the rig directory (or absolute). It packs PNG assets into one Golem `atlas.png` and writes Golem `rig.json`. Export to external staging, compare with the working copy, then install only the verified pair in the delivery folder. Follow [packed-delivery.md](packed-delivery.md); packing is required for each delivered revision.
135
+
136
+ Check both rig schema and motion. Compare setup/endpoint bone matrices **and** the visible slot state, deformations and draw order. Render packed and working documents at the same time, scale and background; measure differing pixels and maximum channel deltas, then inspect any meaningful difference.
137
+
138
+ Chromium may need normal execution permission outside a restrictive sandbox. Use the environment's permission mechanism when necessary; do not change renderer semantics or disable checks to conceal a launch failure. If a local editor port is occupied, check whether the existing editor already serves the intended checkout.
@@ -0,0 +1,17 @@
1
+ # Editable in-page previews
2
+
3
+ Use this workflow when the user wants to adjust artwork with the mouse while keeping the existing Golem animation. Verify the installed package exports `@energy8platform/golem/interactive-editor`; a package version number alone does not prove that the new module is available. The complete API reference is `docs/interactive-editor.md` in the corresponding [Golem source checkout](https://github.com/Energy8Platform/golem). This skill-local reference remains available when the skill is installed separately from that checkout.
4
+
5
+ Import `createInteractiveEditor` from that entry and give it the current `RigPlayer`, a dedicated transparent canvas overlay, and a stable `documentId` derived from the rig **and group configuration**. Size the overlay in renderer logical pixels and align its CSS rectangle with the rendered viewport. Keep playback and Pixi rendering in the host application; pause playback with `onGestureStart` when the user needs a stable pose for dragging. For custom cameras, provide matching `screenToDocument` and `documentToOverlay` conversions.
6
+
7
+ Use `groups: [{ id, members, pivotBone }]` to couple attachments such as palm/finger layers or both halves of a collar. `members` are attachment IDs, not bone or slot IDs. An attachment can belong to only one group. The optional pivot bone defines the local space for adjustments; otherwise the first member's bone is used. Test groups at the requested extreme poses: grouping does not automatically preserve a weapon grip or solve IK.
8
+
9
+ The returned editor supports `select`, `setTransform`, `undo`, `redo`, `reset`, `exportPatch` and `importPatch`. Patches store local X/Y, rotation in degrees and scaleX/scaleY. `setEnabled(false)` disables manipulation while retaining edits; `setVisible(false)` temporarily compares against the unedited pose. Call `dispose()` before destroying the player or scene.
10
+
11
+ Keep exported `golem.interactive-edits` patches outside the packed `rig.json`/`atlas.png` directory and separate from animation keys. Import validates the format, version, document identity, part IDs and transforms. Saving or downloading belongs to the host UI; do not imply that the module saved a file, uploaded anything, or changed the canonical rig unless that action was actually performed. It does not export a Spine project or bake edits into animation tracks.
12
+
13
+ Verify selection through transparent pixels, related-part registration, drag/scale/rotation, undo/redo, patch roundtrip and disposal in the real preview. Replay affected actions at normal speed and inspect contacts, seams, clipping and action switches at the intended display size. Alpha picking requires readable same-origin/CORS texture sources; use `alphaFallback: 'geometry'` only as an explicit documented fallback. Report unsupported texture sources or camera setups rather than calling a technically loading preview visually verified.
14
+
15
+ For editable bone support points and numeric coordinates, use `createInteractiveBoneEditor` from the same entry. It adds local pose offsets before native skinning; it does not rebind artwork or change bind pivots. A direct chain edit may disable that chain's IK, while editing its target or shared ancestor preserves IK. Combine part and bone patches only after validating both; expose an explicit “Apply edits” action when the user wants localStorage persistence. Restore only a matching document identity after reload, and keep failure atomic. Do not replace a request for support-point editing with controls that only move images.
16
+
17
+ With expression controls (Golem 0.5+), the frame order is animation → manual control inputs → control bindings → bone edits → constraints/skinning → part edits. Bone offsets add to resolved keyforms: a 1.5° head-tilt control plus a 5° bone edit must render at 6.5°. Use `setControls` for control inputs; `onBeforePose` receives resolved output channels. Check animated and manual expressions, reset/hide/dispose, and repeated `refreshPose()` together: offsets must neither disappear nor accumulate. Keep control-driven alpha and mesh deformations active during these checks.