motionloom 2.5.1 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/STATUS.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Current release posture
6
6
 
7
- MotionLoom's repository source and package manifest carry **2.5.1 release metadata**. The publication state of the npm registry and GitHub Release/tag must be verified against the latest release workflow rather than inferred from this document. The repository has a cross-platform CLI, one-command project onboarding, durable Project Memory, Agent interoperability surfaces, artifact-first handoff, runtime evidence, Visual Truth, Remediation Learning, signed attestation, AI-first asset provenance, a truthful code-authored runtime lane and a browser-based Dev Lab review contract. The protected manual release workflow verifies package/changelog/release-note alignment before publication.
7
+ MotionLoom's repository source and package manifest carry **2.6.1 release metadata**. The publication state of the npm registry and GitHub Release/tag must be verified against the latest release workflow rather than inferred from this document. The repository has a cross-platform CLI, one-command project onboarding, durable Project Memory, Agent interoperability surfaces, artifact-first handoff, runtime evidence, Visual Truth, Remediation Learning, signed attestation, AI-first asset provenance, a truthful code-authored runtime lane and an interactive browser-based Dev Lab review workbench. Dev Lab supports hash-bound live playback, arbitrary project-defined action libraries and optional state/transition review flows; generated frame sequences additionally use a machine-readable Frame Generation Lock plus fail-closed measured preflight so isolated source geometry is controlled before and after generation. The protected manual release workflow verifies package/changelog/release-note alignment before publication.
8
8
 
9
9
  The repository is **engineering-ready for continued integration work**, not a universal production certification for every animation framework or every host project. CI status must be read from the latest GitHub Actions run, not inferred from historical audit prose.
10
10
 
@@ -16,7 +16,7 @@ The repository is **engineering-ready for continued integration work**, not a un
16
16
  | Rive, GSAP and Framer Motion | Adapter and fixture evidence | Framework-specific runtime adapters and smoke checks can render representative scenes through browser/runtime paths | Equivalent coverage to the Lottie path across arbitrary projects |
17
17
  | Project Memory | Contract and relocation evidence | Stable project identity, atomic persistence, integrity guard, freshness states and path rebinding after relocation | Automatic correctness of an Agent's inferred decision |
18
18
  | Semantic intelligence | Deterministic evaluation evidence | Project graph, provenance, Motion IR, continuity, fix-plan and adversarial/deep-stress contracts; bounded analyzer reports scan budgets and truncation | Human-level design judgment, external-project product-value evidence or guaranteed first-pass acceptance |
19
- | Dev Lab | Review infrastructure evidence | Identity-bound candidate loading, deterministic scrub/snapshot, user checklist and review export | A visual editor, automatic approval or PR authorization |
19
+ | Dev Lab | Interactive review infrastructure evidence | Identity-bound candidate loading, live runtime playback controls, arbitrary Action Library discovery, state/transition and review-sequence testing, deterministic snapshots, user checklist and review export | A full visual authoring editor, automatic approval or PR authorization |
20
20
 
21
21
  ## Normative sources
22
22
 
@@ -30,4 +30,4 @@ Use the following order when sources disagree:
30
30
 
31
31
  ## Known next work
32
32
 
33
- The bounded analyzer has now been exercised against a labeled external corpus; see the [dated evidence note](audits/external-project-corpus-2026-08-13.md). The 2.5.0 version–tag–GitHub Release–npm chain has been verified against public metadata. The highest-value remaining evidence work is paired product evaluation across more real projects and repeating the same provenance verification for each new release. Missing external projects are reported as `insufficient_evidence`, never as a pass. None of these items should weaken the user-review gate or convert heuristic warnings into approval.
33
+ The bounded analyzer has been exercised against a labeled external corpus; see the [dated evidence note](audits/external-project-corpus-2026-08-13.md). The 2.5.x publication chain established npm/GitHub release provenance, 2.6.0 added the richer Dev Lab review surface, and 2.6.1 adds proactive machine-readable frame-generation geometry control without weakening the human approval boundary. The highest-value next evidence work is consumer-project review of real action sets, transitions and generated frame sequences, followed by paired product evaluation across more real projects and repeating the same provenance verification for each new release. Missing external projects are reported as `insufficient_evidence`, never as a pass. None of these items should weaken the user-review gate or convert runtime success or heuristic warnings into approval.
@@ -0,0 +1,38 @@
1
+ # MotionLoom 2.6.0
2
+
3
+ ## Summary
4
+
5
+ MotionLoom 2.6.0 turns Dev Lab from a mostly checkpoint-oriented browser reviewer into an interactive runtime review workbench. The release keeps deterministic snapshots as evidence, but adds a live runtime lane for real playback, scalable project-defined action sets, and optional state/transition review flows so a user can inspect behavior much closer to the target runtime before approving a candidate.
6
+
7
+ ## Added
8
+
9
+ - Interactive Dev Lab transport controls for live candidates: play, pause, restart, normalized scrub, frame stepping, playback speed and loop control.
10
+ - Stage inspection tools including fullscreen, zoom/fit, background selection, grid, bounds, baseline and pivot overlays; sprite candidates can opt into crisp pixel-art rendering.
11
+ - Data-driven animation discovery from `devlab-runtime.json`. Action names such as `idle`, `walk`, `run`, `attack`, `jump`, skills, emotes or project-specific clips are not hard-coded into MotionLoom.
12
+ - Scalable Action Library support with project-defined groups/categories, tags, search, collapsible sections and filters for review-required, unreviewed, looping and one-shot actions.
13
+ - Optional hash-bound `devlab-state-machine.json` contract with explicit states, legal transitions, multi-step review sequences and independent transition/sequence review coverage.
14
+ - Portable `select-animation` transitions for sprite/clip runtimes and strict `runtime-trigger` transitions for iframe runtimes through `triggerTransition(request)`.
15
+ - Transition history and review evidence for inspected actions, transitions, sequences and observed runtime state.
16
+
17
+ ## Hardened
18
+
19
+ - Live runtime files, descriptors and state-machine bytes are bound into the browser-review candidate hash when declared; runtime-byte drift invalidates the candidate.
20
+ - Path traversal, absolute paths, symlink escapes, duplicate animation ids, undeclared runtime files and mismatched candidate/runtime animation sets fail closed.
21
+ - A declared live runtime that cannot load is shown as `LIVE RUNTIME UNAVAILABLE`; captured snapshots remain inspectable for diagnosis but approval is blocked.
22
+ - `runtime-trigger` transitions are counted only after the runtime reports the declared target state. MotionLoom never silently downgrades an unsupported runtime trigger into a clip switch.
23
+ - Search, grouping and filters affect presentation only. Hidden required actions or transitions still count as unreviewed.
24
+ - `runtime-bridge.js` is included in the npm package allowlist so installed-package iframe/state-machine review does not depend on source-checkout-only files.
25
+
26
+ ## Verified behavior
27
+
28
+ The Dev Lab CI harness covers deterministic snapshots, live sprite playback, iframe runtime bridging, a four-action interactive dogfood set, a twelve-action Action Library fixture, sprite state transitions, real iframe runtime-trigger transitions and browser-security smoke tests. The state/transition fixtures exercise flows such as `Idle -> Run -> Attack -> Hurt -> Idle` and verify that completing runtime coverage does not create a user approval decision.
29
+
30
+ The protected release workflow reruns documentation/package validation, Skill Doctor, the full regression harness, isolated installed-package consumer smoke and release traceability before npm publication.
31
+
32
+ ## Trust boundary
33
+
34
+ MotionLoom 2.6.0 does not turn runtime success into visual approval, production approval or PR authorization. Playback controls, action coverage, transition coverage, runtime state, hashes, snapshots, telemetry and automated sequence completion are evidence only. `approved` remains an explicit user decision bound to the exact browser-review candidate.
35
+
36
+ AI-generated or otherwise non-authoritative source assets retain their declared provenance and authority tier. Dev Lab review does not promote `ai_generated` material to `artist_authored`, `production_eligible` or `production_approved`.
37
+
38
+ The native macOS/iOS companion remains an unsigned source alpha. npm publication and GitHub Release creation remain explicit maintainer release actions through the protected GitHub Actions workflow.
@@ -0,0 +1,57 @@
1
+ # MotionLoom 2.6.1
2
+
3
+ MotionLoom 2.6.1 closes the generated multi-frame consistency gap discovered during real Codex animation work. The release makes frame consistency proactive: the Agent binds one accepted identity/reference into a machine-readable Frame Generation Lock before producing later poses, then validates the real PNG bytes after every generated frame before any atlas is packed.
4
+
5
+ ## What changed
6
+
7
+ ### Frame Generation Lock before generation
8
+
9
+ Generated frame sequences now have a provider-neutral contract in `schemas/frame-generation-lock.schema.json`. The lock records and verifies:
10
+
11
+ - accepted identity/reference path and SHA-256;
12
+ - exact canvas dimensions, alpha mode and color space;
13
+ - camera/orientation and apparent character scale;
14
+ - pivot and baseline/footline;
15
+ - safe rectangle, transparent padding and geometry tolerances;
16
+ - ordered frame ids, pose intent and one unique isolated output path per frame.
17
+
18
+ Agents use `motionloom frame-generation-lock validate` before generation and `motionloom frame-generation-lock compose` (or `compose-all`) to build each provider-facing pose instruction from the same lock. This removes dependence on an Agent remembering or rewriting the geometry prose consistently across frame 2, frame 6 or frame 20.
19
+
20
+ ### Strict preflight after each generated frame
21
+
22
+ `motionloom frame-set-preflight` is now a public CLI command. It re-measures actual PNG bytes and blocks shared/non-isolated source canvases, stale hashes, contamination, guard-band violations, pivot/footline drift and apparent-size drift beyond the declared tolerance.
23
+
24
+ The default source policy is deliberately strict: generate one isolated source PNG per frame, validate it, and only then continue. For long actions (including six or more frames), a generated contact sheet or multi-pose sheet must not be cropped into production source frames. Atlas/sprite-sheet packing happens only after all isolated source frames pass.
25
+
26
+ ## Agent behavior
27
+
28
+ `AGENTS.md` and the canonical Skill route Codex and other compatible Agents through this workflow automatically. The user does not need to remember to ask for equal scale, separate frames, padding, baseline consistency or pose-sheet avoidance.
29
+
30
+ If one frame fails, the Agent regenerates or repairs that frame under the same lock. It must not silently resize previously accepted frames or weaken tolerances merely to make the set pass.
31
+
32
+ ## Verification
33
+
34
+ PR #18 passed:
35
+
36
+ - the dedicated Frame Generation Lock workflow;
37
+ - MotionLoom Quality (including engine tests and cross-platform package checks);
38
+ - Security Analysis / CodeQL;
39
+ - Documentation and Package Hygiene.
40
+
41
+ The dedicated regression suite covers stale reference hashes, duplicate outputs, pose-sheet policy, path escape, post-generation resize, public CLI composition and strict preflight.
42
+
43
+ ## Trust boundary
44
+
45
+ This release improves source consistency and evidence quality; it does not change authority. A generator prompt, reference hash, frame lock, preflight pass, atlas pass, runtime render or signed evidence record does **not** create artist authorship, licence authority, production eligibility, production approval or user approval. Human review remains a separate bounded decision.
46
+
47
+ ## Updating a project
48
+
49
+ After `motionloom@2.6.1` is published, update the project-local development dependency and refresh the managed Agent surface:
50
+
51
+ ```bash
52
+ npm install --save-dev motionloom@2.6.1
53
+ npx --no-install motionloom repair --yes
54
+ npx --no-install motionloom status --json
55
+ ```
56
+
57
+ For a generated multi-frame task, the Agent should then use the Frame Generation Lock before later frames and `frame-set-preflight` after each accepted frame.
@@ -0,0 +1,84 @@
1
+ {
2
+ "schema_version": "0.1",
3
+ "lock_id": "hero-walk-v1",
4
+ "asset_identity": "character/hero-male",
5
+ "action_id": "walk",
6
+ "reference": {
7
+ "image": "asset-consistency/assets/hero-frame-00.png",
8
+ "sha256": "75ce90653a01a23bcfab1aef83647d6364d3edbf6e4a44b84c635338c12b9248",
9
+ "role": "accepted_frame_anchor"
10
+ },
11
+ "canvas": {
12
+ "width": 8,
13
+ "height": 8,
14
+ "color_space": "srgb",
15
+ "alpha_mode": "straight"
16
+ },
17
+ "geometry": {
18
+ "center_x": 4,
19
+ "pivot": { "x": 4, "y": 7, "space": "pixels" },
20
+ "footline_px": 6,
21
+ "safe_rect": { "x": 1, "y": 0, "width": 6, "height": 7 },
22
+ "min_padding_px": 1,
23
+ "target_alpha_bbox": { "width": 4, "height": 5 },
24
+ "tolerances": {
25
+ "pivot_px": 0.01,
26
+ "footline_px": 0.01,
27
+ "bbox_width_px": 0,
28
+ "bbox_height_px": 0
29
+ }
30
+ },
31
+ "appearance": {
32
+ "preserve": [
33
+ "same character identity and silhouette",
34
+ "same camera and left-to-right orientation",
35
+ "same palette, outline weight and apparent scale"
36
+ ],
37
+ "forbid": [
38
+ "second character or neighboring pose",
39
+ "background, shadow, text, prop or crop",
40
+ "camera change, mirror, recolor or post-generation resize"
41
+ ],
42
+ "pixel_art": {
43
+ "enabled": true,
44
+ "nearest_neighbor_only": true
45
+ }
46
+ },
47
+ "source_policy": {
48
+ "isolated_frames": true,
49
+ "max_frames_per_image": 1,
50
+ "allow_pose_sheet": false,
51
+ "allow_post_resize": false,
52
+ "reuse_reference": true
53
+ },
54
+ "frames": [
55
+ {
56
+ "frame_id": "walk.00",
57
+ "pose": "Contact-right: right foot forward on the shared footline, left leg trailing, natural counter-swing.",
58
+ "output": "frame-generation-lock/generated/hero-walk-00.png"
59
+ },
60
+ {
61
+ "frame_id": "walk.01",
62
+ "pose": "Passing: one leg passes beneath the upright body with compact stride and natural counter-swing.",
63
+ "output": "frame-generation-lock/generated/hero-walk-01.png"
64
+ },
65
+ {
66
+ "frame_id": "walk.02",
67
+ "pose": "Contact-left: left foot forward on the shared footline, right leg trailing, natural counter-swing.",
68
+ "output": "frame-generation-lock/generated/hero-walk-02.png"
69
+ },
70
+ {
71
+ "frame_id": "walk.03",
72
+ "pose": "Passing complement: opposite leg passes beneath the upright body; preserve the same body scale and baseline.",
73
+ "output": "frame-generation-lock/generated/hero-walk-03.png"
74
+ }
75
+ ],
76
+ "postflight": {
77
+ "frame_geometry": "asset-consistency/hero-walk-frame-geometry.json"
78
+ },
79
+ "trust": {
80
+ "authority": "ai_generated",
81
+ "review_only": true,
82
+ "approval": false
83
+ }
84
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "motionloom",
3
- "version": "2.5.1",
3
+ "version": "2.6.1",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@11.20.0",
6
6
  "description": "MotionLoom: project-aware animation Skill with Agent interoperability, graph, provenance, Motion IR, runtime telemetry, Visual Truth, Remediation Learning, DSSE-compatible signed attestation, external evidence verification and Dev Lab review.",
@@ -36,6 +36,8 @@
36
36
  "requirements.txt",
37
37
  "dev-lab/public/index.html",
38
38
  "dev-lab/public/devlab.js",
39
+ "dev-lab/public/action-library.js",
40
+ "dev-lab/public/runtime-bridge.js",
39
41
  "tests/runtime-harness",
40
42
  "tests/evals",
41
43
  "tests/scripts/run_tests.py",
@@ -74,11 +76,11 @@
74
76
  "scripts/rive-package-gate.py",
75
77
  "schemas/rive-package-manifest.schema.json",
76
78
  "examples/agent-consumer/rive-package-gate",
77
- "tests/scripts/test_rive_package_gate.py"
78
- ,"scripts/build-ai-pilot.py"
79
- ,"scripts/isolate-alpha-background.py"
80
- ,"tests/scripts/test_ai_pilot_builder.py"
81
- ,"tests/scripts/test_alpha_isolation.py"
79
+ "tests/scripts/test_rive_package_gate.py",
80
+ "scripts/build-ai-pilot.py",
81
+ "scripts/isolate-alpha-background.py",
82
+ "tests/scripts/test_ai_pilot_builder.py",
83
+ "tests/scripts/test_alpha_isolation.py"
82
84
  ],
83
85
  "keywords": [
84
86
  "animation",
@@ -182,9 +184,9 @@
182
184
  "artifact:intake": "node bin/motionloom.mjs artifact-intake intake --root . --registry artifact-adapter-registry.json --receipt examples/agent-consumer/artifact-intake/hero-motion-receipt.json --controls examples/agent-consumer/artifact-intake/hero-motion-controls.json --export-manifest examples/agent-consumer/artifact-intake/hero-motion-export.json --json",
183
185
  "runtime:candidate": "node bin/motionloom.mjs runtime-candidate validate --root . --input examples/agent-consumer/runtime-candidate/hero-walk-candidate.json --json",
184
186
  "rig:compatibility": "node bin/motionloom.mjs rig-compatibility validate --root . --registry rig-adapter-registry.json --input examples/agent-consumer/rig-compatibility/hero-walk-fixture-rig.json --json",
185
- "rive:gate": "node bin/motionloom.mjs rive-package-gate --help"
186
- ,"pilot:build": "node bin/motionloom.mjs pilot-build --help"
187
- ,"alpha:isolate": "node bin/motionloom.mjs alpha-isolate --help"
187
+ "rive:gate": "node bin/motionloom.mjs rive-package-gate --help",
188
+ "pilot:build": "node bin/motionloom.mjs pilot-build --help",
189
+ "alpha:isolate": "node bin/motionloom.mjs alpha-isolate --help"
188
190
  },
189
191
  "dependencies": {
190
192
  "@lottiefiles/dotlottie-web": "^0.79.0",
@@ -0,0 +1,109 @@
1
+ # Multi-frame asset generation discipline
2
+
3
+ This contract applies whenever MotionLoom or an Agent creates two or more source frames for the same character, object, effect or other frame-based animation. It is automatic: the user should not have to ask for consistent frame geometry, isolated source frames or atlas hygiene.
4
+
5
+ ## Default source policy
6
+
7
+ Generated source frames are **isolated-frame assets**, not a pose sheet.
8
+
9
+ - Generate exactly one animation source frame per image/canvas by default.
10
+ - For long actions (including actions with six or more frames), never ask an image generator for one contact sheet, sprite sheet or multi-pose canvas and then crop the poses out as production source frames.
11
+ - Do not pack an atlas or sprite sheet until every isolated source frame has passed identity and frame-geometry validation.
12
+ - Imported third-party atlases may still use the atlas contract; this rule is about Agent-generated source material.
13
+
14
+ If a generator cannot preserve isolated source canvases reliably, regenerate in smaller isolated calls or use provider outputs that are already separate files. Do not convert one contaminated multi-pose canvas into accepted source frames merely because crops can be extracted from it.
15
+
16
+ This avoids neighboring poses leaking into a crop, shared-canvas bleed, accidental partial limbs from adjacent frames and ambiguous ownership of opaque pixels.
17
+
18
+ ## Lock geometry before the second frame
19
+
20
+ Before generating frame 2, establish one canonical geometry lock from the accepted identity/reference frame and keep it unchanged for the rest of the action:
21
+
22
+ - exact canvas width and height;
23
+ - transparent alpha mode and color space;
24
+ - camera and left/right orientation;
25
+ - target apparent character scale;
26
+ - pivot point;
27
+ - baseline / footline;
28
+ - safe rectangle and transparent guard band;
29
+ - palette/style/identity reference;
30
+ - frame naming and action order.
31
+
32
+ Create or update the matching `action-set` and `frame-geometry` contracts before continuing the sequence. The first accepted frame is the geometry anchor; later poses may move limbs, but they must not silently change canvas size, camera, character scale, pivot or baseline.
33
+
34
+ For AI-generated frames, every subsequent generation request should carry the same locked identity reference and geometry requirements. When the image tool can accept an image reference, reuse the accepted identity/anchor frame rather than relying on prose alone.
35
+
36
+ ## Frame Generation Lock
37
+
38
+ Do not rely on the Agent remembering the same geometry prose across many provider calls. Persist the generation-side constraints in `frame-generation-lock.json` using `schemas/frame-generation-lock.schema.json`.
39
+
40
+ The lock binds:
41
+
42
+ - the exact identity/accepted-frame reference path and SHA-256;
43
+ - canvas dimensions, color space and alpha mode;
44
+ - center, pivot, footline, safe rectangle and minimum transparent padding;
45
+ - target measured alpha-bounds plus permitted width/height drift;
46
+ - appearance features that must be preserved and changes that are forbidden;
47
+ - a hard source policy of one isolated frame per image, no pose sheet and no post-generation resize;
48
+ - every `frame_id`, its pose intent and its unique PNG output path;
49
+ - the post-generation `frame-geometry` contract used by deterministic preflight;
50
+ - a review-only trust boundary with `approval: false`.
51
+
52
+ Before a provider call, validate the lock and compose the exact frame instruction from it:
53
+
54
+ ```bash
55
+ motionloom frame-generation-lock validate \
56
+ --input src/output/<scene>/<action>-frame-generation-lock.json \
57
+ --root src/output/<scene> --json
58
+
59
+ motionloom frame-generation-lock compose \
60
+ --input src/output/<scene>/<action>-frame-generation-lock.json \
61
+ --root src/output/<scene> --frame-id <action.frame-id> --json
62
+ ```
63
+
64
+ For batch planning, `compose-all` emits one independent instruction per frame while preserving the same lock hash and reference hash. It does **not** authorize asking a provider for one multi-frame canvas; each returned instruction still represents one isolated source image.
65
+
66
+ If the reference bytes change, an output path escapes the asset root, two frames target the same PNG, the lock permits a pose sheet/post-resize, or the trust boundary is weakened, validation fails closed before generation.
67
+
68
+ ## Validate incrementally
69
+
70
+ Do not generate the complete action and only inspect it at the end. After each candidate frame:
71
+
72
+ 1. verify the image is an isolated source canvas rather than a shared pose sheet;
73
+ 2. verify exact canvas dimensions and alpha transparency;
74
+ 3. measure the real alpha bounding box from pixels;
75
+ 4. compare apparent size against the anchor within the declared `bbox_drift_tolerance_px`;
76
+ 5. verify pivot and footline tolerance;
77
+ 6. verify the alpha bounding box remains inside `safe_rect` with the declared `bleed_margin_px` guard band;
78
+ 7. reject unexpected opaque contamination;
79
+ 8. only then accept the frame and continue.
80
+
81
+ Use:
82
+
83
+ ```bash
84
+ motionloom frame-set-preflight \
85
+ --input src/output/<scene>/<action>-frame-geometry.json \
86
+ --root src/output/<scene> --json
87
+ ```
88
+
89
+ The preflight is intentionally stricter than a visual warning: shared source images, non-isolated frame rectangles, scale drift beyond the declared tolerance, guard-band violations, pivot/footline drift, hash mismatch or other deterministic frame-geometry failures block the sequence.
90
+
91
+ If one frame fails, regenerate or repair **that frame only** using the same generation lock. Do not silently rescale every previously accepted frame to match a bad frame, and do not weaken tolerances merely to make the set pass.
92
+
93
+ ## Apparent-size consistency
94
+
95
+ Equal canvas dimensions are not enough. A 1920 × 1920 PNG can still contain a character that is 20% smaller than the previous frame. MotionLoom therefore treats measured alpha-bounds drift as a real source defect when it exceeds the declared tolerance.
96
+
97
+ Pose motion can legitimately change the bounding box, so choose a tolerance that allows expected limb extension while preventing whole-character zoom drift. For actions with large reaches, jumps or weapons, lock the body pivot/footline and define a safe rectangle large enough for those poses instead of changing the character scale between frames.
98
+
99
+ For pixel art, any intentional normalization step must preserve nearest-neighbor pixel density and the locked pivot/baseline. Large scale corrections should trigger regeneration rather than interpolation.
100
+
101
+ ## Packing happens last
102
+
103
+ Only after every source frame passes preflight may the Agent build a sprite sheet or atlas. The packed result must then pass the atlas contract: no region overlap, no opaque pixels outside declared regions when required, explicit padding/extrusion, and no ambiguous neighboring-frame bleed.
104
+
105
+ Source-frame acceptance and atlas acceptance are separate gates. A clean atlas cannot repair inconsistent source-frame scale, and consistent source frames do not prove the packed atlas is clean.
106
+
107
+ ## Agent decision rule
108
+
109
+ When the user asks for an animation such as idle, walk, run, attack, hurt, jump or any project-defined multi-frame action, the Agent should apply this contract automatically. Do not ask the user whether they want frame consistency checks or a generation lock; they are part of the default MotionLoom workflow. Only ask the user when a genuine artistic decision is required, such as choosing between materially different silhouettes or motion intent.
@@ -15,6 +15,43 @@
15
15
  "source_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
16
16
  "runtime": {"type": "string"},
17
17
  "checkpoints": {"type": "array", "items": {"type": "integer", "enum": [0, 50, 100]}},
18
+ "runtime_review": {
19
+ "oneOf": [
20
+ {
21
+ "type": "object",
22
+ "additionalProperties": false,
23
+ "required": ["live", "mode", "checkpoints"],
24
+ "properties": {
25
+ "live": {"const": false},
26
+ "mode": {"const": "captured-evidence"},
27
+ "checkpoints": {"type": "array", "items": {"type": "integer", "enum": [0, 50, 100]}}
28
+ }
29
+ },
30
+ {
31
+ "type": "object",
32
+ "additionalProperties": false,
33
+ "required": ["live", "mode", "descriptor", "bundle_sha256", "animations", "review_policy"],
34
+ "properties": {
35
+ "live": {"const": true},
36
+ "mode": {"enum": ["sprite-sequence", "iframe"]},
37
+ "descriptor": {"const": "devlab-runtime.json"},
38
+ "bundle_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
39
+ "animations": {
40
+ "type": "array",
41
+ "minItems": 1,
42
+ "uniqueItems": true,
43
+ "items": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"}
44
+ },
45
+ "review_policy": {
46
+ "type": "object",
47
+ "additionalProperties": false,
48
+ "required": ["require_all_animations"],
49
+ "properties": {"require_all_animations": {"type": "boolean"}}
50
+ }
51
+ }
52
+ }
53
+ ]
54
+ },
18
55
  "review_artifact": {"type": "string"},
19
56
  "requires_user_approval": {"type": "boolean"},
20
57
  "prepared_at": {"type": "string", "format": "date-time"},
@@ -0,0 +1,140 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://motionloom.dev/schemas/devlab-runtime.schema.json",
4
+ "title": "MotionLoom Dev Lab live runtime descriptor",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schema_version", "mode", "files", "animations", "default_animation", "controls", "review_policy"],
8
+ "properties": {
9
+ "schema_version": { "const": "1.0" },
10
+ "mode": { "enum": ["sprite-sequence", "iframe"] },
11
+ "files": {
12
+ "type": "array",
13
+ "minItems": 1,
14
+ "uniqueItems": true,
15
+ "items": { "$ref": "#/$defs/relativePath" }
16
+ },
17
+ "entrypoint": { "$ref": "#/$defs/relativePath" },
18
+ "default_animation": { "$ref": "#/$defs/animationId" },
19
+ "groups": {
20
+ "type": "array",
21
+ "uniqueItems": true,
22
+ "items": { "$ref": "#/$defs/group" }
23
+ },
24
+ "animations": {
25
+ "type": "array",
26
+ "minItems": 1,
27
+ "items": { "$ref": "#/$defs/animation" }
28
+ },
29
+ "controls": {
30
+ "type": "object",
31
+ "additionalProperties": false,
32
+ "required": ["play", "pause", "restart", "seek", "step", "speed", "loop"],
33
+ "properties": {
34
+ "play": { "type": "boolean" },
35
+ "pause": { "type": "boolean" },
36
+ "restart": { "type": "boolean" },
37
+ "seek": { "type": "boolean" },
38
+ "step": { "type": "boolean" },
39
+ "speed": { "type": "boolean" },
40
+ "loop": { "type": "boolean" }
41
+ }
42
+ },
43
+ "viewport": {
44
+ "type": "object",
45
+ "additionalProperties": false,
46
+ "properties": {
47
+ "canvas_width": { "type": "number", "exclusiveMinimum": 0 },
48
+ "canvas_height": { "type": "number", "exclusiveMinimum": 0 },
49
+ "pixel_art": { "type": "boolean" },
50
+ "baseline_y": { "type": "number" },
51
+ "pivot": {
52
+ "type": "object",
53
+ "additionalProperties": false,
54
+ "required": ["x", "y"],
55
+ "properties": {
56
+ "x": { "type": "number" },
57
+ "y": { "type": "number" }
58
+ }
59
+ },
60
+ "background": { "enum": ["checker", "dark", "light", "transparent", "project"] }
61
+ }
62
+ },
63
+ "review_policy": {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "required": ["require_all_animations"],
67
+ "properties": {
68
+ "require_all_animations": { "type": "boolean" }
69
+ }
70
+ }
71
+ },
72
+ "allOf": [
73
+ {
74
+ "if": { "properties": { "mode": { "const": "iframe" } } },
75
+ "then": { "required": ["entrypoint"] }
76
+ },
77
+ {
78
+ "if": { "properties": { "mode": { "const": "sprite-sequence" } } },
79
+ "then": {
80
+ "properties": {
81
+ "animations": {
82
+ "items": {
83
+ "required": ["id", "fps", "frames", "loop"]
84
+ }
85
+ }
86
+ }
87
+ }
88
+ }
89
+ ],
90
+ "$defs": {
91
+ "animationId": {
92
+ "type": "string",
93
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"
94
+ },
95
+ "groupId": {
96
+ "type": "string",
97
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"
98
+ },
99
+ "relativePath": {
100
+ "type": "string",
101
+ "minLength": 1,
102
+ "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*\\\\).+"
103
+ },
104
+ "group": {
105
+ "type": "object",
106
+ "additionalProperties": false,
107
+ "required": ["id"],
108
+ "properties": {
109
+ "id": { "$ref": "#/$defs/groupId" },
110
+ "label": { "type": "string", "minLength": 1, "maxLength": 120 },
111
+ "order": { "type": "integer", "minimum": -10000, "maximum": 10000 }
112
+ }
113
+ },
114
+ "animation": {
115
+ "type": "object",
116
+ "additionalProperties": false,
117
+ "required": ["id", "loop"],
118
+ "properties": {
119
+ "id": { "$ref": "#/$defs/animationId" },
120
+ "label": { "type": "string", "minLength": 1, "maxLength": 120 },
121
+ "group": { "$ref": "#/$defs/groupId" },
122
+ "tags": {
123
+ "type": "array",
124
+ "uniqueItems": true,
125
+ "items": { "type": "string", "minLength": 1, "maxLength": 64 }
126
+ },
127
+ "fps": { "type": "number", "exclusiveMinimum": 0 },
128
+ "frames": {
129
+ "type": "array",
130
+ "minItems": 1,
131
+ "items": { "$ref": "#/$defs/relativePath" }
132
+ },
133
+ "loop": { "type": "boolean" },
134
+ "duration_s": { "type": "number", "exclusiveMinimum": 0 },
135
+ "review_required": { "type": "boolean", "default": true },
136
+ "events": { "type": "array", "items": { "type": "string" } }
137
+ }
138
+ }
139
+ }
140
+ }