@impractical-ai/motion 0.1.14 → 0.1.16

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/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # Impractical Motion CLI
2
2
 
3
- <!-- ARRIVAL-DRIFT-STANDARD START -->
4
- ## Default motion: arrival and residual drift
3
+ <!-- MOTION-STANDARD START -->
4
+ ## Default motion: arrival, hold and exit
5
5
 
6
- Foreground motion defaults to an energetic arrival, strong deceleration, and small continuing travel through the reading hold. Compose a deterministic residual trajectory with the native entrance; do not stop and restart with a disconnected tween. “Settled” and “hold” mean readable and visually stable, with subtle nonzero travel unless an explicit freeze, exact alignment or reduced-motion mode requires stillness.
6
+ Each foreground element follows one continuous trajectory: it arrives with energy, decelerates strongly to near-zero speed for the reading hold, then accelerates into its exit or its next authored move. Shape this with the entrance and exit eases themselves; there is no separate drift layer, no constant velocity floor and no perpetual creep. Finish the visible travel quickly: during the hold the ease tail moves the subject less than about 0.5 output px in total, so “settled” and “hold” mean visually still and readable. Exits ease in (or in-out) from that near-zero state, so nothing starts from a dead stop. This applies to whole entities, not to every element inside them: a card, product window, headline block or logo lockup arrives, holds and exits as one unit, and its children (labels, icons, rows, words, buttons) ride with it. Don't recurse and give each child its own arrival, deceleration and exit; that reads as fidgeting and splits attention. Children may still have their own discrete actions inside the hold (text typing in, a toggle flipping, a row highlighting, a number counting), but not their own arrive/hold/exit motion.
7
7
 
8
- Use the Rox `ambientOffset(seconds, amount, phase)` pattern: native 960×540 product groups start around amount 3.2–4, text around 0.8–1. Keep a signed velocity floor with gentle curvature, not a pure sine bob. Move attached labels, controls, connectors and shadows together, avoid double drift, preserve 3D hierarchy, and verify reverse/retimed seeks and late-hold displacement.
8
+ Why no creep: exports render in headless Linux Chromium, which snaps slowly moving text and elements to whole pixels, so a slow drift of about 1 px/s shows up as a visible 1 px tick every ~0.9 s. Move attached labels, controls, connectors and shadows together with their subject, preserve 3D hierarchy, and verify reverse/retimed seeks.
9
9
 
10
- The host owns the background environment. Animate foreground objects only; never move or retime the background to simulate object motion. Reusable foregrounds should be transparent. Keep one primary focus and room around it; purposeful object camera moves remain welcome, and a generic card is not the default visual container.
10
+ The host owns the background environment. Animate foreground objects only; never move or retime the background to simulate object motion. Reusable foregrounds should be transparent. Make things breathe: only one focus at a time, with generous negative space and comfortable margins around it. Keep supporting context subordinate; sequence competing text and actions. Let the focal idea land and be read before handing attention to the next event. If crowded, remove or sequence content before shrinking it. Check entry, hold and exit as well as playback. Purposeful object camera moves remain welcome; a generic card is not the default visual container.
11
11
 
12
12
  Full specification: [motion standard](../docs/motion-standard.md).
13
- <!-- ARRIVAL-DRIFT-STANDARD END -->
13
+ <!-- MOTION-STANDARD END -->
14
14
 
15
15
  Connect Claude Code, Codex, Cursor, or OpenCode to Impractical Motion through
16
16
  its MCP server.
@@ -134,5 +134,11 @@ Opt-in flags on the MCP process, for testing quality interventions without touch
134
134
  - `IMPRACTICAL_MOTION_LIBRARY_FILE=<path>` — overlay locally generated motion-library
135
135
  guidance onto the live catalog.
136
136
 
137
+ With quality-loop checks active, text-density findings (`OVERLOADED`) from `get_motion`
138
+ are advisory and never refuse `export_video`: UI labels can exceed the density threshold
139
+ without making a beat unreadable. Review the findings and simplify crowded beats when needed.
140
+ Other shot-list and study-timing findings still refuse export once per draft revision in each
141
+ MCP session; a second attempt on that revision can pass that gate. Other export gates still apply.
142
+
137
143
  If authorization is rejected, rerun the setup command. If the configuration file is malformed,
138
144
  the CLI reports its exact path instead of silently ignoring it.
@@ -5,17 +5,17 @@ description: Create and refine studio-quality motion-graphics launch videos with
5
5
 
6
6
  # Impractical Motion
7
7
 
8
- <!-- ARRIVAL-DRIFT-STANDARD START -->
9
- ## Default motion: arrival and residual drift
8
+ <!-- MOTION-STANDARD START -->
9
+ ## Default motion: arrival, hold and exit
10
10
 
11
- Foreground motion defaults to an energetic arrival, strong deceleration, and small continuing travel through the reading hold. Compose a deterministic residual trajectory with the native entrance; do not stop and restart with a disconnected tween. “Settled” and “hold” mean readable and visually stable, with subtle nonzero travel unless an explicit freeze, exact alignment or reduced-motion mode requires stillness.
11
+ Each foreground element follows one continuous trajectory: it arrives with energy, decelerates strongly to near-zero speed for the reading hold, then accelerates into its exit or its next authored move. Shape this with the entrance and exit eases themselves; there is no separate drift layer, no constant velocity floor and no perpetual creep. Finish the visible travel quickly: during the hold the ease tail moves the subject less than about 0.5 output px in total, so “settled” and “hold” mean visually still and readable. Exits ease in (or in-out) from that near-zero state, so nothing starts from a dead stop. This applies to whole entities, not to every element inside them: a card, product window, headline block or logo lockup arrives, holds and exits as one unit, and its children (labels, icons, rows, words, buttons) ride with it. Don't recurse and give each child its own arrival, deceleration and exit; that reads as fidgeting and splits attention. Children may still have their own discrete actions inside the hold (text typing in, a toggle flipping, a row highlighting, a number counting), but not their own arrive/hold/exit motion.
12
12
 
13
- Use the Rox `ambientOffset(seconds, amount, phase)` pattern: native 960×540 product groups start around amount 3.2–4, text around 0.8–1. Keep a signed velocity floor with gentle curvature, not a pure sine bob. Move attached labels, controls, connectors and shadows together, avoid double drift, preserve 3D hierarchy, and verify reverse/retimed seeks and late-hold displacement.
13
+ Why no creep: exports render in headless Linux Chromium, which snaps slowly moving text and elements to whole pixels, so a slow drift of about 1 px/s shows up as a visible 1 px tick every ~0.9 s. Move attached labels, controls, connectors and shadows together with their subject, preserve 3D hierarchy, and verify reverse/retimed seeks.
14
14
 
15
- The host owns the background environment. Animate foreground objects only; never move or retime the background to simulate object motion. Reusable foregrounds should be transparent. Keep one primary focus and room around it; purposeful object camera moves remain welcome, and a generic card is not the default visual container.
15
+ The host owns the background environment. Animate foreground objects only; never move or retime the background to simulate object motion. Reusable foregrounds should be transparent. Make things breathe: only one focus at a time, with generous negative space and comfortable margins around it. Keep supporting context subordinate; sequence competing text and actions. Let the focal idea land and be read before handing attention to the next event. If crowded, remove or sequence content before shrinking it. Check entry, hold and exit as well as playback. Purposeful object camera moves remain welcome; a generic card is not the default visual container.
16
16
 
17
- For the complete trajectory and review checks, read `motion_context` → `guidance.director` before authoring.
18
- <!-- ARRIVAL-DRIFT-STANDARD END -->
17
+ For the complete standard and review checks, read `motion_context` → `guidance.director` before authoring.
18
+ <!-- MOTION-STANDARD END -->
19
19
 
20
20
  You direct the video yourself. Impractical provides the engine, the preview
21
21
  build, the render, and the studio the user tweaks in — you provide the
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ AGENT_HEADER,
3
4
  ApiContractError,
4
5
  ApiError,
5
6
  ApiTransportError,
@@ -9,16 +10,18 @@ import {
9
10
  invoke,
10
11
  invokeAt,
11
12
  jobStatus,
13
+ setAgentName,
12
14
  studioLink,
13
15
  studioQuery,
14
16
  validateApiResponse,
15
17
  waitForJobs,
16
18
  withAdmissionReceipt,
17
19
  withMeteredCall
18
- } from "./chunk-O3BUN66P.js";
19
- import "./chunk-7SNCVSTA.js";
20
+ } from "./chunk-CJLGKZMD.js";
21
+ import "./chunk-AP27EKRR.js";
20
22
  import "./chunk-77HVPD4G.js";
21
23
  export {
24
+ AGENT_HEADER,
22
25
  ApiContractError,
23
26
  ApiError,
24
27
  ApiTransportError,
@@ -28,6 +31,7 @@ export {
28
31
  invoke,
29
32
  invokeAt,
30
33
  jobStatus,
34
+ setAgentName,
31
35
  studioLink,
32
36
  studioQuery,
33
37
  validateApiResponse,
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@impractical-ai/motion",
6
- version: "0.1.14",
6
+ version: "0.1.16",
7
7
  private: false,
8
8
  description: "Create and refine Impractical Motion videos from coding agents and the terminal.",
9
9
  homepage: "https://github.com/Openpod/impractical-motion#readme",
@@ -57,7 +57,7 @@ var PRODUCTION_APP_URL = "https://motion.impractical.ai";
57
57
  var PRODUCTION_SUPABASE_URL = "https://uaxjweednprtbhbceify.supabase.co";
58
58
  var PACKAGE_NAME = "@impractical-ai/motion";
59
59
  var PACKAGE_VERSION = package_default.version;
60
- var BUILD_COMMIT = "e734492" ? "e734492" : "dev";
60
+ var BUILD_COMMIT = "a212b8f" ? "a212b8f" : "dev";
61
61
  var BUILD_ID = `${PACKAGE_VERSION}+${BUILD_COMMIT}`;
62
62
  var PACKAGE_COMMAND = `npx --yes ${PACKAGE_NAME}`;
63
63
 
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  PRODUCTION_APP_URL,
4
4
  PRODUCTION_SUPABASE_URL
5
- } from "./chunk-7SNCVSTA.js";
5
+ } from "./chunk-AP27EKRR.js";
6
6
 
7
7
  // src/config.ts
8
8
  import {
@@ -199,6 +199,11 @@ function validateApiResponse(name, body, data) {
199
199
  return data;
200
200
  }
201
201
  var WORKSPACE_HEADER = "x-impractical-workspace";
202
+ var AGENT_HEADER = "x-impractical-agent";
203
+ var agentName;
204
+ function setAgentName(name) {
205
+ agentName = name?.replace(/[^\x20-\x7e]/g, "").trim().slice(0, 80) || void 0;
206
+ }
202
207
  async function invoke(name, body = {}) {
203
208
  const { apiKey, supabaseUrl, workspace } = requireConfig();
204
209
  const call = admissionContext.getStore();
@@ -214,6 +219,7 @@ async function invokeAt(supabaseUrl, name, body = {}, apiKey, admissionReceipt,
214
219
  ...apiKey ? { authorization: `Bearer ${apiKey}` } : {},
215
220
  ...admissionReceipt ? { "x-impractical-admission": admissionReceipt } : {},
216
221
  ...apiKey && workspace ? { [WORKSPACE_HEADER]: workspace } : {},
222
+ ...agentName ? { [AGENT_HEADER]: agentName } : {},
217
223
  "content-type": "application/json"
218
224
  },
219
225
  body: JSON.stringify(body)
@@ -308,6 +314,8 @@ export {
308
314
  ApiTransportError,
309
315
  validateApiResponse,
310
316
  WORKSPACE_HEADER,
317
+ AGENT_HEADER,
318
+ setAgentName,
311
319
  invoke,
312
320
  invokeAt,
313
321
  admitMcpCall,
@@ -7,14 +7,14 @@ import {
7
7
  loadConfig,
8
8
  recoverCorruptConfig,
9
9
  saveConfig
10
- } from "./chunk-O3BUN66P.js";
10
+ } from "./chunk-CJLGKZMD.js";
11
11
  import {
12
12
  PACKAGE_COMMAND,
13
13
  PACKAGE_NAME,
14
14
  PACKAGE_VERSION,
15
15
  PRODUCTION_APP_URL,
16
16
  PRODUCTION_SUPABASE_URL
17
- } from "./chunk-7SNCVSTA.js";
17
+ } from "./chunk-AP27EKRR.js";
18
18
 
19
19
  // src/onboarding.ts
20
20
  import {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  setup
4
- } from "./chunk-L5ERED5A.js";
4
+ } from "./chunk-UEPY33MB.js";
5
5
  import {
6
6
  invoke,
7
7
  invokeAt,
@@ -11,8 +11,8 @@ import {
11
11
  saveConfig,
12
12
  studioLink,
13
13
  waitForJobs
14
- } from "./chunk-O3BUN66P.js";
15
- import "./chunk-7SNCVSTA.js";
14
+ } from "./chunk-CJLGKZMD.js";
15
+ import "./chunk-AP27EKRR.js";
16
16
  import "./chunk-77HVPD4G.js";
17
17
 
18
18
  // src/commands.ts
@@ -1438,9 +1438,14 @@ async function generate(flags) {
1438
1438
  }
1439
1439
  const projectId = flagString(flags, "project");
1440
1440
  const feedback = flagString(flags, "feedback");
1441
- const append = Boolean(projectId && feedback);
1441
+ if (projectId && feedback) {
1442
+ throw new Error(
1443
+ "Projects have one draft now. To revise this video, edit its draft with the MCP tools edit_draft_file / write_draft_files; every save is kept as a version."
1444
+ );
1445
+ }
1446
+ const append = false;
1442
1447
  const slug = flagString(flags, "slug") ?? `${slugify(valueProp)}-${randomBytes(2).toString("hex")}`;
1443
- const directorIds = (flagString(flags, "directors") ?? "d1,d2").split(",").map((d) => d.trim());
1448
+ const directorIds = (flagString(flags, "directors") ?? "d1").split(",").map((d) => d.trim()).slice(0, 1);
1444
1449
  const files = buildInitialFiles({ valueProp, appCode, brand: brand2 });
1445
1450
  const prepared = await invoke("prepare-generation", {
1446
1451
  ...projectId ? { projectId } : {},
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  PACKAGE_VERSION
4
- } from "./chunk-7SNCVSTA.js";
4
+ } from "./chunk-AP27EKRR.js";
5
5
  import "./chunk-77HVPD4G.js";
6
6
 
7
7
  // src/cli-args.ts
@@ -65,7 +65,7 @@ Agents
65
65
  Make videos
66
66
  generate --value-prop "..." [--directors d1,d2] [--vibe confident]
67
67
  [--code-file app.md] [--brand <slug>] [--asset file ...]
68
- [--project <id> --feedback "..."] [--model <id>] [--wait]
68
+ [--project <id>] [--model <id>] [--wait]
69
69
  status --project <id> | --jobs <id,id> [--wait]
70
70
  export [draftId] [--wait] [--out video.mp4]
71
71
 
@@ -160,11 +160,11 @@ async function runCli(args, deps) {
160
160
  // src/index.ts
161
161
  runCli(process.argv.slice(2), {
162
162
  writeLine: (line) => console.log(line),
163
- loadCommands: () => import("./commands-3PIMUGYP.js"),
164
- loadApi: () => import("./api-VLQHOCLI.js"),
165
- loadMcp: () => import("./stdio-M2YRHGFJ.js")
163
+ loadCommands: () => import("./commands-6F7HITZN.js"),
164
+ loadApi: () => import("./api-V7Q3PIWY.js"),
165
+ loadMcp: () => import("./stdio-R4RCWJIS.js")
166
166
  }).catch(async (error) => {
167
- const { ApiError } = await import("./api-VLQHOCLI.js");
167
+ const { ApiError } = await import("./api-V7Q3PIWY.js");
168
168
  if (error instanceof ApiError) {
169
169
  console.error(`Error (${error.status} from ${error.fn}): ${error.message}`);
170
170
  if (error.status === 429) console.error("Weekly MCP allowance reached. Upgrade or wait for Monday UTC.");
@@ -5,7 +5,7 @@ import {
5
5
  grantScope,
6
6
  openBrowser,
7
7
  workspaceLabel
8
- } from "./chunk-L5ERED5A.js";
8
+ } from "./chunk-UEPY33MB.js";
9
9
  import {
10
10
  ApiError,
11
11
  admitMcpCall,
@@ -14,16 +14,17 @@ import {
14
14
  loadConfig,
15
15
  requireConfig,
16
16
  saveConfig,
17
+ setAgentName,
17
18
  studioQuery,
18
19
  validateApiResponse,
19
20
  withAdmissionReceipt
20
- } from "./chunk-O3BUN66P.js";
21
+ } from "./chunk-CJLGKZMD.js";
21
22
  import {
22
23
  BUILD_COMMIT,
23
24
  PACKAGE_VERSION,
24
25
  PRODUCTION_APP_URL,
25
26
  PRODUCTION_SUPABASE_URL
26
- } from "./chunk-7SNCVSTA.js";
27
+ } from "./chunk-AP27EKRR.js";
27
28
  import {
28
29
  __commonJS,
29
30
  __export,
@@ -66969,7 +66970,7 @@ function holdLifeAnalysis(intervals, options = {}) {
66969
66970
  flush();
66970
66971
  return holds;
66971
66972
  }
66972
- var HOLD_LIFE_FIX = "add motion to this scene: an element appearing, jiggling, a chart animating, a counter ticking, a subtle reveal. References keep holds alive. Author the fill from the beat itself \u2014 the number that just changed, the chart this beat earned \u2014 at a subliminal amplitude, inside the scene that is holding.";
66973
+ var HOLD_LIFE_FIX = "trim the hold or add a discrete event from the beat itself: an element appearing, a chart animating, a counter ticking, a reveal \u2014 at full, readable amplitude. Never fill it with a slow drift or sub-pixel creep: exports snap slow movement to whole pixels, so it renders as a periodic 1 px tick (house standard: holds are still).";
66973
66974
  function holdLifeReport(holds) {
66974
66975
  const lines = [];
66975
66976
  lines.push("HOLD LIFE \u2014 every settled hold, and whether anything in it is visibly animating:");
@@ -66993,7 +66994,7 @@ function holdLifeReport(holds) {
66993
66994
  lines.push(`${label} ALIVE \u2014 something visibly animates ${Math.round(hold.aliveShare * 100)}% of it.`);
66994
66995
  } else {
66995
66996
  lines.push(
66996
- `${label} quiet \u2014 only ${Math.round(hold.aliveShare * 100)}% of it shows visible change. Fine for a reading beat; anything longer wants a touch of life.`
66997
+ `${label} quiet \u2014 only ${Math.round(hold.aliveShare * 100)}% of it shows visible change. Fine for a reading beat; a longer one wants a discrete event, never a drift.`
66997
66998
  );
66998
66999
  }
66999
67000
  }
@@ -68727,7 +68728,7 @@ var getMotionTool = {
68727
68728
  const n = smp.blocks.filter((blk) => blk.inViewport && blk.text.trim().length >= 3 && blk.fontSize * (blk.scale ?? 1) >= 8).length;
68728
68729
  if (n > beatPeak) beatPeak = n;
68729
68730
  }
68730
- if (beatPeak > 14) problems.push(`overloaded (up to ${beatPeak} text blocks at once inside this beat)`);
68731
+ if (beatPeak > 14) notes.push(`ADVISORY \u2014 overloaded (up to ${beatPeak} text blocks at once inside this beat); text density does not block export`);
68731
68732
  if (b.component && strict) {
68732
68733
  const plan2 = plans[i];
68733
68734
  const verdict = plan2.early ?? beatChangeVerdict(plan2.pairs, shares.slice(cursor, cursor + plan2.pairs.length), frameTimes);
@@ -68773,7 +68774,8 @@ var getMotionTool = {
68773
68774
  \u2717 ${problems.join("\n \u2717 ")}${noteText}`);
68774
68775
  shotListFailures.push(`BEAT ${i + 1} (${b.start}\u2013${b.end}s, ${b.component ?? b.subject}): ${problems.join("; ")}`);
68775
68776
  } else {
68776
- const measured = strict ? ["copy read", "camera as declared", changeMeasured ? "change happened" : "change unmeasured", "no plate", "not overloaded"] : ["copy read", "camera as declared", "not overloaded"];
68777
+ const measured = strict ? ["copy read", "camera as declared", changeMeasured ? "change happened" : "change unmeasured", "no plate"] : ["copy read", "camera as declared"];
68778
+ if (beatPeak <= 14) measured.push("not overloaded");
68777
68779
  out.push(`${head}
68778
68780
  \u2713 ${measured.join(", ")}${noteText}`);
68779
68781
  }
@@ -68852,7 +68854,7 @@ var getMotionTool = {
68852
68854
  reviewSection = "REVIEW MODULES: the preview session carried no draft files \u2014 nothing swept.";
68853
68855
  }
68854
68856
  const readingFailures = censusOn && textSamples.length ? readingSizeFindings(textSamples).findings.filter((f) => f.kind === "OVERLOADED").map((f) => `OVERLOADED ${f.start.toFixed(2)}\u2013${f.end.toFixed(2)}s: up to ${f.peak} text blocks visible at once`) : [];
68855
- readingFailures.push(...shotListFailures, ...atelierTimingFailures);
68857
+ const beatFailures = [...shotListFailures, ...atelierTimingFailures];
68856
68858
  let contractSection = "";
68857
68859
  if (textContractEnabled() && textSamples.length >= 2) {
68858
68860
  try {
@@ -69072,6 +69074,7 @@ var getMotionTool = {
69072
69074
  connectorFailures: connectorGate,
69073
69075
  exposedGroundFailures: exposedGroundGate,
69074
69076
  readingFailures,
69077
+ beatFailures,
69075
69078
  reviewFailures: reviewResult?.failures
69076
69079
  });
69077
69080
  lines.push(
@@ -71214,7 +71217,7 @@ var decoder = new TextDecoder();
71214
71217
  // src/mcp/tools.ts
71215
71218
  var createSessionState = () => ({
71216
71219
  lastCaptureByDraft: /* @__PURE__ */ new Map(),
71217
- overloadRefused: /* @__PURE__ */ new Set(),
71220
+ beatReviewRefused: /* @__PURE__ */ new Set(),
71218
71221
  reviewRefused: /* @__PURE__ */ new Set(),
71219
71222
  readingBaselineByDraft: /* @__PURE__ */ new Map(),
71220
71223
  shotListByDraft: /* @__PURE__ */ new Map(),
@@ -71455,12 +71458,12 @@ function reportBuildStart(draftId, saved, changed, deleted, staleNotes = [], adv
71455
71458
  (legibilityEnabled() ? " That build report also carries the LEGIBILITY CHECK \u2014 whether anything you just changed renders too small to be noticed, and what camera move fixes it. It is measured from layout, so this reply cannot contain it." : "")
71456
71459
  });
71457
71460
  }
71458
- function overloadMotionFailure(capture, session, draftId) {
71459
- if (!capture?.readingFailures?.length || !session) return null;
71461
+ function beatReviewMotionFailure(capture, session, draftId) {
71462
+ if (!capture?.beatFailures?.length || !session) return null;
71460
71463
  const key = `${draftId}:${capture.revision}`;
71461
- if (session.overloadRefused.has(key)) return null;
71462
- session.overloadRefused.add(key);
71463
- return "EXPORT REFUSED ONCE \u2014 the final review found the viewer overloaded:\n " + capture.readingFailures.join("\n ") + "\nOne subject per beat: show the component that changes, at reading scale, and push in on it; a dense dashboard is a brief establishing shot only. Fix the beats you agree with, re-run get_motion, and export again \u2014 the second export of this revision goes through; say in your summary which findings you kept and why.";
71464
+ if (session.beatReviewRefused.has(key)) return null;
71465
+ session.beatReviewRefused.add(key);
71466
+ return "EXPORT REFUSED ONCE \u2014 the final review found shot-list or study-timing issues:\n " + capture.beatFailures.join("\n ") + "\nFix the beats you agree with, re-run get_motion, and export again \u2014 the second export of this revision goes through; say in your summary which findings you kept and why.";
71464
71467
  }
71465
71468
  function reviewModulesFailure(capture, session, draftId) {
71466
71469
  if (!capture?.reviewFailures?.length || !session) return null;
@@ -71926,7 +71929,7 @@ var exportVideo = {
71926
71929
  rasterDensityMotionFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId))) ?? connectorMotionFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId))) ?? // Signal 8 exposed ground: the film letterboxed inside its own markup
71927
71930
  // (batch-10 INB). Same always-blocking engine-side layout-assertion
71928
71931
  // category — no gateReform argument by design.
71929
- exposedGroundMotionFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId))) ?? reviewModulesFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId)), ctx.sessionState, String(args.draftId)) ?? overloadMotionFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId)), ctx.sessionState, String(args.draftId)) ?? framingMotionFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId)), {
71932
+ exposedGroundMotionFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId))) ?? reviewModulesFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId)), ctx.sessionState, String(args.draftId)) ?? beatReviewMotionFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId)), ctx.sessionState, String(args.draftId)) ?? framingMotionFailure(ctx.qualityLoopState?.finalMotionReviewByDraft.get(String(args.draftId)), {
71930
71933
  gateReform
71931
71934
  }) ?? holdLifeMotionFailure({
71932
71935
  holdLifeGate: ctx.holdLifeGate === true,
@@ -72082,7 +72085,7 @@ var motionProfile = {
72082
72085
  var studioLinkTool = {
72083
72086
  name: "studio_link",
72084
72087
  title: "Get the studio URL",
72085
- description: "Get the web studio URL where the user watches the cuts and tweaks them visually. Always give this to the user after a change lands.",
72088
+ description: "Get the web studio URL where the user watches the video and tweaks it visually. Always give this to the user after a change lands.",
72086
72089
  inputSchema: {
72087
72090
  projectId: external_exports.string().describe("The project id."),
72088
72091
  slug: external_exports.string().optional().describe("Draft slug to open directly.")
@@ -72560,7 +72563,7 @@ function componentManifestPath(env = process.env, cwd = process.cwd()) {
72560
72563
  return void 0;
72561
72564
  }
72562
72565
  function componentServerInstructions(path7) {
72563
- return path7 ? "\n\nVIDEO CREATIVE DIRECTION:\nYou are a professional motion graphics designer and pro social media specialist. You need to design an eye catching, popping video that will stand out to people scrolling social media or catch the eye when run on ads. You need to be harsh, critical on yourself when designing, and meeting the bar of a motion graphics video isn't enough. your work needs to rival other motion designers that are making stuff with adobe after effects.\n\nLOCAL COMPONENT HANDOFF IS ENABLED. When a brief names Explore component IDs or slugs, call components_catalog and component_study for those exact selections before authoring. These tools expose a versioned snapshot of the local app, including source, selectors, and usage. Call install_components to copy the selected sources and runtime into your draft, then import them using the returned examples. Keep all selected components; never substitute a similarly named house style. A missing ID is a handoff failure to report, not permission to invent it. Read engine_types and use the normal create_video, write_draft_files, job_status, get_frames and export_video workflow. Components use their own deterministic timeline through the supplied runtime. \nCOMPONENT PROMO EDITORIAL REQUIREMENTS FOR THIS LOCAL EXPERIMENT: the user requires each shot to last at most THREE SECONDS, including its transition and reading hold. Plan the shot boundaries before writing code; a 24-second film needs at least eight substantive visual beats. Connected shots can develop one concrete scene without cutting away or reintroducing its subject. A new label, another card landing, or a cut to the same unchanged screen does not make a new beat. Each beat must advance the product story with a new visible action, state change, or benefit. Cover the real workflow from input through transformation, decision, and outcome; do not spend an entire promo on three cards and a static list. For fictional test products, keep added workflow clearly illustrative; for real products use verified capabilities only. Study each selected component as a motion primitive, not a full scene whose demo duration must be preserved. Use playComponent duration to fit the choreography inside the shot, trim native demo holds, and author short readable copy. User pacing requirements override generic slower house defaults. A continuous ambient backdrop may span scenes, but cannot count as new content. Vary scale, composition, camera direction and transitions with narrative purpose. Review the complete sequence in motion: prove every shot is <=3 seconds and show the meaningful product change in every interval. Do not excuse dead time as a reading hold or dismiss actual pacing warnings because compilation and still frames pass. \nVISUAL COMPREHENSION: the user must understand the component at a glance. Do not fill product cards with paragraphs, quotations, opportunity briefs, or marketing explanations. Show the capability through imagery, a recognizable control, a visible interaction, and its result. Keep only essential short UI labels inside the component. Give explanatory primary copy its own clear hierarchy in the scene, separate from the product UI contents. More content means more visible product behavior, not more words or denser dashboards. Each selected entrance introduces a distinct component or concept. After an entrance, develop that subject through interactions and purposeful camera framing; do not repeatedly reintroduce the same dashboard to demonstrate different styles. Connected three-second shots may follow the same subject as long as the visible action and framing advance. Before expanding the film, review a short product proof with captions hidden: its action and outcome should still be understandable. Treat a need to read the card to understand the scene as a creative defect, even if every word is technically legible. \nSILENT VIDEO NARRATIVE: minimal component text does not mean minimal explanation. When there is no voiceover, primary copy must carry a complete, understandable product story: who the product is for or what it does, the capabilities being demonstrated, and the payoff. Before authoring, extract only the intended message text and read it in sequence without the visuals or UI labels. It must make sense as a concise standalone script, not a few disconnected slogans. Then pair each line with a visual demonstration of that claim. Use short meaningful titles, timed for comfortable reading, rather than paragraphs, redundant labels, or title-only slides between every action. Reserve real space for this copy; do not cover important controls, crowd components, or shrink everything to fit. Budget entrance, fully readable hold, and exit separately. Start the reading hold only after the complete line has landed; end it when motion or occlusion starts obscuring it. Let words arrive and leave deliberately, with deceleration and enough time to follow their motion. Reclaim empty success holds before rushing the message or slowing the entire video. Check the reading rhythm in playback, not just on paused frames. Review both layers independently: the primary-copy transcript should explain the story, and the caption-free product view should demonstrate an immediately recognizable action. \nCOPY IN THE SCENE: primary copy is part of the authored visual world, not a pinned webpage header or a fixed caption band pasted over the film. Plan where the words live relative to the subject, their depth or plane when appropriate, and how the subject or camera affects their entrance, action, and exit. Use specific readable relationships: a subject can make room for words, carry or push them, pass in front of them, or reveal them as the camera reframes. Share the relevant world/camera transform when that is the intended relationship. Keep clear reading moments, but do not equate readable with permanently locked to the screen. Solve collisions with scene composition and timing, not an opaque header strip covering the product. Do not force every line into the same interaction or bury explanatory copy inside a dense product card. \nSELECTED MOTION FIDELITY: preserve what makes each selected reference recognizable. An imported source ID is not proof that the effect works. Inspect the actual motion and transform hierarchy; avoid competing animations on one node and wrappers that flatten the intended perspective. If a reference combines continuous subject movement with editorial camera cuts, preserve both and their relationship. Do not silently remove defining motion to accommodate another reference; reorganize the sequence or assign a distinct subject instead. Compare the result against the selected reference at the moments that demonstrate its distinctive behavior. \nCURSOR ACCURACY: verify the visible cursor hotspot lands inside the intended control at the actual press frame, after camera transforms and component motion. Use compatible coordinate spaces or scope the cursor to the product world; do not compensate with guessed offsets. Check that direct seeks and continuous playback agree. Tie the visible UI response to that press and leave enough time to see the resulting state. \nAMBIENT COMPONENT MOTION: during settled holds, consider a very light continuous drift of the component or its camera so the composition still feels alive. Background motion alone is not a substitute. Keep it barely perceptible, coherent with perspective, and subordinate to the primary interaction. Preserve readable copy and maintain the relationship between controls and any cursor; settle the drift during precise clicks or tracking if needed. Use a separate wrapper or compose transforms so drift does not fight the selected entrance, camera, or exit. Evaluate it deterministically from timeline time, without an independent clock or reset at shot boundaries. Do not bob every element, force motion where stillness is intentional, or count ambient drift as a substantive story beat. \nSCENE HANDOFFS: plan how each concrete scene exits as deliberately as how its subject enters. Do not default to entrance, token action, then unrelated cut. In the shot plan, name the outgoing subject and state, the action or camera move that carries us out, and the incoming subject and relationship that makes the connection understandable. Build the transition from what is already happening: an artifact can carry forward, an interaction can change the framing, or a meaningful object can occlude and reveal the next view. These are options, not a mandatory recipe; choose a connection specific to the product story. A selected transition effect supplies motion language, not the narrative reason for the handoff. Preserve recognizable details through the connection and do not imply a product feature or causal relationship that does not exist. Three-second shot pacing does not require a cut or a fresh entrance every three seconds. A motivated cut can be right; do not force every connection into a morph or add decorative travel that delays the story. Review at least one complete entrance, developed action, and outgoing handoff in the caption-free proof, then review all scene boundaries in motion before delivery. This local extension does not mean these components are available in the published CLI." : "";
72566
+ return path7 ? "\n\nVIDEO CREATIVE DIRECTION:\nYou are a professional motion graphics designer and pro social media specialist. You need to design an eye catching, popping video that will stand out to people scrolling social media or catch the eye when run on ads. You need to be harsh, critical on yourself when designing, and meeting the bar of a motion graphics video isn't enough. your work needs to rival other motion designers that are making stuff with adobe after effects.\n\nLOCAL COMPONENT HANDOFF IS ENABLED. When a brief names Explore component IDs or slugs, call components_catalog and component_study for those exact selections before authoring. These tools expose a versioned snapshot of the local app, including source, selectors, and usage. Call install_components to copy the selected sources and runtime into your draft, then import them using the returned examples. Keep all selected components; never substitute a similarly named house style. A missing ID is a handoff failure to report, not permission to invent it. Read engine_types and use the normal create_video, write_draft_files, job_status, get_frames and export_video workflow. Components use their own deterministic timeline through the supplied runtime. \nCOMPONENT PROMO EDITORIAL REQUIREMENTS FOR THIS LOCAL EXPERIMENT: the user requires each shot to last at most THREE SECONDS, including its transition and reading hold. Plan the shot boundaries before writing code; a 24-second film needs at least eight substantive visual beats. Connected shots can develop one concrete scene without cutting away or reintroducing its subject. A new label, another card landing, or a cut to the same unchanged screen does not make a new beat. Each beat must advance the product story with a new visible action, state change, or benefit. Cover the real workflow from input through transformation, decision, and outcome; do not spend an entire promo on three cards and a static list. For fictional test products, keep added workflow clearly illustrative; for real products use verified capabilities only. Study each selected component as a motion primitive, not a full scene whose demo duration must be preserved. Use playComponent duration to fit the choreography inside the shot, trim native demo holds, and author short readable copy. User pacing requirements override generic slower house defaults. A continuous ambient backdrop may span scenes, but cannot count as new content. Vary scale, composition, camera direction and transitions with narrative purpose. Review the complete sequence in motion: prove every shot is <=3 seconds and show the meaningful product change in every interval. Do not excuse dead time as a reading hold or dismiss actual pacing warnings because compilation and still frames pass. \nVISUAL COMPREHENSION: the user must understand the component at a glance. Do not fill product cards with paragraphs, quotations, opportunity briefs, or marketing explanations. Show the capability through imagery, a recognizable control, a visible interaction, and its result. Keep only essential short UI labels inside the component. Give explanatory primary copy its own clear hierarchy in the scene, separate from the product UI contents. More content means more visible product behavior, not more words or denser dashboards. Each selected entrance introduces a distinct component or concept. After an entrance, develop that subject through interactions and purposeful camera framing; do not repeatedly reintroduce the same dashboard to demonstrate different styles. Connected three-second shots may follow the same subject as long as the visible action and framing advance. Before expanding the film, review a short product proof with captions hidden: its action and outcome should still be understandable. Treat a need to read the card to understand the scene as a creative defect, even if every word is technically legible. \nSILENT VIDEO NARRATIVE: minimal component text does not mean minimal explanation. When there is no voiceover, primary copy must carry a complete, understandable product story: who the product is for or what it does, the capabilities being demonstrated, and the payoff. Before authoring, extract only the intended message text and read it in sequence without the visuals or UI labels. It must make sense as a concise standalone script, not a few disconnected slogans. Then pair each line with a visual demonstration of that claim. Use short meaningful titles, timed for comfortable reading, rather than paragraphs, redundant labels, or title-only slides between every action. Reserve real space for this copy; do not cover important controls, crowd components, or shrink everything to fit. Budget entrance, fully readable hold, and exit separately. Start the reading hold only after the complete line has landed; end it when motion or occlusion starts obscuring it. Let words arrive and leave deliberately, with deceleration and enough time to follow their motion. Reclaim empty success holds before rushing the message or slowing the entire video. Check the reading rhythm in playback, not just on paused frames. Review both layers independently: the primary-copy transcript should explain the story, and the caption-free product view should demonstrate an immediately recognizable action. \nCOPY IN THE SCENE: primary copy is part of the authored visual world, not a pinned webpage header or a fixed caption band pasted over the film. Plan where the words live relative to the subject, their depth or plane when appropriate, and how the subject or camera affects their entrance, action, and exit. Use specific readable relationships: a subject can make room for words, carry or push them, pass in front of them, or reveal them as the camera reframes. Share the relevant world/camera transform when that is the intended relationship. Keep clear reading moments, but do not equate readable with permanently locked to the screen. Solve collisions with scene composition and timing, not an opaque header strip covering the product. Do not force every line into the same interaction or bury explanatory copy inside a dense product card. \nSELECTED MOTION FIDELITY: preserve what makes each selected reference recognizable. An imported source ID is not proof that the effect works. Inspect the actual motion and transform hierarchy; avoid competing animations on one node and wrappers that flatten the intended perspective. If a reference combines continuous subject movement with editorial camera cuts, preserve both and their relationship. Do not silently remove defining motion to accommodate another reference; reorganize the sequence or assign a distinct subject instead. Compare the result against the selected reference at the moments that demonstrate its distinctive behavior. \nCURSOR ACCURACY: verify the visible cursor hotspot lands inside the intended control at the actual press frame, after camera transforms and component motion. Use compatible coordinate spaces or scope the cursor to the product world; do not compensate with guessed offsets. Check that direct seeks and continuous playback agree. Tie the visible UI response to that press and leave enough time to see the resulting state. \nSETTLED HOLDS ARE STILL: a component arrives with energy, decelerates to near-zero speed and holds visually still (its ease tail moves it less than ~0.5 px across the hold), then accelerates into its exit or next move. Never add a continuous drift or slow creep to a component or its camera during a hold: exports snap slow movement to whole pixels, so it reads as a periodic tick. Give a long hold life with a discrete event instead. \nSCENE HANDOFFS: plan how each concrete scene exits as deliberately as how its subject enters. Do not default to entrance, token action, then unrelated cut. In the shot plan, name the outgoing subject and state, the action or camera move that carries us out, and the incoming subject and relationship that makes the connection understandable. Build the transition from what is already happening: an artifact can carry forward, an interaction can change the framing, or a meaningful object can occlude and reveal the next view. These are options, not a mandatory recipe; choose a connection specific to the product story. A selected transition effect supplies motion language, not the narrative reason for the handoff. Preserve recognizable details through the connection and do not imply a product feature or causal relationship that does not exist. Three-second shot pacing does not require a cut or a fresh entrance every three seconds. A motivated cut can be right; do not force every connection into a morph or add decorative travel that delays the story. Review at least one complete entrance, developed action, and outgoing handoff in the caption-free proof, then review all scene boundaries in motion before delivery. This local extension does not mean these components are available in the published CLI." : "";
72564
72567
  }
72565
72568
  function localLibrary(pathArg) {
72566
72569
  const load = () => loadComponentManifest(pathArg);
@@ -73133,9 +73136,11 @@ Impractical Motion makes studio-quality motion-graphics videos. Draft source liv
73133
73136
 
73134
73137
  THE USER'S EDITS COME FIRST. While watching a draft in the Studio the user queues timecoded edit requests into its notes.json ("Edits for agent"). Before directing an existing draft, read_draft_file notes.json (it may not exist \u2014 that is fine); address the open items, and mark each one you have handled by setting its \`done\` to true with edit_draft_file, leaving the rest of the entry intact. The Studio shows the user what you resolved.
73135
73138
 
73139
+ ONE VIDEO, ONE DRAFT. To revise an existing video, edit its draft in place with edit_draft_file / write_draft_files. Every save is kept as a version the user can go back to in the Studio, so never make a new project or draft to hold another attempt; create_video is for a new video only.
73140
+
73136
73141
  You are the director. Call engine_types first to learn the API, then motion_context to study the current house library and production references, then create_video, then write App.tsx (the stage markup) and direction.ts (the GSAP choreography) with edit_draft_file / write_draft_files. Every save returns its committed revision and preview-build job id immediately. Follow that id with job_status and fix any build error it returns. Call get_frames to SEE the result before telling the user it is done, then call export_video, follow its returned job id with job_status, and hand the user the studio_link.
73137
73142
 
73138
- ` + ATELIER_FIRST_PASS_RULE + "\n\n" + POSITIONING_RULE + "\n\n" + CAMERA_RULE + "\n\n" + COMPOSITION_RULE + "\n\n" + (shotListEnabled() ? SHOT_LIST_RULE + "\n\n" : "") + (refInjectDir() ? REF_INJECT_RULE + "\n\n" : "") + (reviewModulesEnabled() ? REVIEW_RULE + "\n\n" : "") + (atelierEnabled() ? ATELIER_RULE + "\n\n" : "") + "JOBS OUTLIVE TOOL CALLS. Job-producing mutations return their durable job id BEFORE any wait; resume that exact id with job_status({ jobIds: [...], wait: true }). Never start a second export or re-apply an edit after a committed revision. If the MCP client kills a call and shows only a timeout, assume the acknowledgment may have been lost: DO NOT blindly retry a mutating or metered tool. Verify state first. For a write/edit, use list_draft_files and read_draft_file to confirm the intended source and revision. For an export or other project mutation, use get_project/list_projects to check whether it already started or completed. brand_extract returns a durable run handle; continue that exact jobId in status mode and never re-extract blindly. If its start acknowledgement is lost, check brand_list/brand_get before starting again. Retry only when those reads prove the mutation did not commit; otherwise continue from the observed state.\n\nTHE MOTION FLOOR \u2014 these hold even if you read nothing else:\n1. Beat out the story before writing code: every beat needs a time, a visible subject, and a narrative purpose. An intentional reading hold is a valid beat.\n2. Text enters on RISE \u2014 text.reveal(el, 'rise') on promo-out, lines ~0.2s apart. Do NOT default type to 'blur': word-by-word de-blur reads as out-of-focus and a staggered blur turns to mush. Blur is for whole-frame moves \u2014 fx.spike(el, 'blur') alongside a whip or dive, where it hides the cut. Never animate blur above 20px.\n3. Every ease is a named house curve \u2014 ease-out-* for entrances, ease-in-out-* for travel and ALL camera moves, ease-in-* for exits and dives only. Never leave an ease unspecified, and never put an ease-in-* on an entrance.\n4. Motion is decisive: entrances 0.4-0.6s, exits shorter, line staggers ~0.2s apart. Longer movement needs a narrative reason; important states hold readable with subtle residual foreground drift; explicit freezes may be still.\n5. One primary and at most one supporting motion at a time. Keep backgrounds stable unless their movement is explicitly authored. Cuts are HARD (tl.set), never crossfades.\n6. Determinism: no Date.now, Math.random, setTimeout, or CSS transitions. The exporter renders by seeking, so wall-clock motion shimmers or vanishes.\n7. Never claim a video is done without calling get_frames and judging the visible story, hierarchy, proof, legibility, reference fidelity, and technical integrity \u2014 artifact-free is not the same as good.\n" + // Item 8 is the content doctrine, which is still under experiment: it ships
73143
+ ` + ATELIER_FIRST_PASS_RULE + "\n\n" + POSITIONING_RULE + "\n\n" + CAMERA_RULE + "\n\n" + COMPOSITION_RULE + "\n\n" + (shotListEnabled() ? SHOT_LIST_RULE + "\n\n" : "") + (refInjectDir() ? REF_INJECT_RULE + "\n\n" : "") + (reviewModulesEnabled() ? REVIEW_RULE + "\n\n" : "") + (atelierEnabled() ? ATELIER_RULE + "\n\n" : "") + "JOBS OUTLIVE TOOL CALLS. Job-producing mutations return their durable job id BEFORE any wait; resume that exact id with job_status({ jobIds: [...], wait: true }). Never start a second export or re-apply an edit after a committed revision. If the MCP client kills a call and shows only a timeout, assume the acknowledgment may have been lost: DO NOT blindly retry a mutating or metered tool. Verify state first. For a write/edit, use list_draft_files and read_draft_file to confirm the intended source and revision. For an export or other project mutation, use get_project/list_projects to check whether it already started or completed. brand_extract returns a durable run handle; continue that exact jobId in status mode and never re-extract blindly. If its start acknowledgement is lost, check brand_list/brand_get before starting again. Retry only when those reads prove the mutation did not commit; otherwise continue from the observed state.\n\nTHE MOTION FLOOR \u2014 these hold even if you read nothing else:\n1. Beat out the story before writing code: every beat needs a time, a visible subject, and a narrative purpose. An intentional reading hold is a valid beat.\n2. Text enters on RISE \u2014 text.reveal(el, 'rise') on promo-out, lines ~0.2s apart. Do NOT default type to 'blur': word-by-word de-blur reads as out-of-focus and a staggered blur turns to mush. Blur is for whole-frame moves \u2014 fx.spike(el, 'blur') alongside a whip or dive, where it hides the cut. Never animate blur above 20px.\n3. Every ease is a named house curve \u2014 ease-out-* for entrances, ease-in-out-* for travel and ALL camera moves, ease-in-* for exits and dives only. Never leave an ease unspecified, and never put an ease-in-* on an entrance.\n4. Motion is decisive: entrances 0.4-0.6s, exits shorter, line staggers ~0.2s apart. Longer movement needs a narrative reason; important states hold readable and still (no foreground drift).\n5. One primary and at most one supporting motion at a time. Keep backgrounds stable unless their movement is explicitly authored. Cuts are HARD (tl.set), never crossfades.\n6. Determinism: no Date.now, Math.random, setTimeout, or CSS transitions. The exporter renders by seeking, so wall-clock motion shimmers or vanishes.\n7. Never claim a video is done without calling get_frames and judging the visible story, hierarchy, proof, legibility, reference fidelity, and technical integrity \u2014 artifact-free is not the same as good.\n" + // Item 8 is the content doctrine, which is still under experiment: it ships
73139
73144
  // only when IMPRACTICAL_CONTENT_DOCTRINE is set, so the same switch governs
73140
73145
  // the doctrine here and in the phased flow's phase 2.
73141
73146
  (contentDoctrineEnabled() ? "8. CONTENT: pretend the viewer has never heard of this product. Figure out the one thing they should walk away knowing, and say it in as few words as possible. If a smart 16-year-old could not repeat a line back in their own words, the line means nothing \u2014 cut it. No buzzwords, no vague taglines. Say a thing, then show it happening \u2014 in that order, one after the other, never both at once. Give the viewer exactly one thing to read at a time: no little label above a headline, no subtitle under it." : "") + `
@@ -73143,8 +73148,8 @@ You are the director. Call engine_types first to learn the API, then motion_cont
73143
73148
  10. FOCAL BUDGET: one focal point at a time. At most ONE region of the frame changes at once (a full-frame camera move is one change; a subject plus its direct reaction is the limit). A claim and the product may NEVER share the same space: while a statement is up, the product is fully cleared or fully hidden \u2014 dimming it under the words is not separation. Never stack anything on top of a dashboard while the dashboard is the subject. An element that finished its job exits before the next enters; the motion report now measures split focus and stacked text, and the film is not done while either fires.
73144
73149
  11. COMPONENT REHEARSAL: build and judge the hero components BEFORE choreographing the film. For each component that must look real (the dashboard, the inbox, the editor): build it, render it with get_frames in each state the beats will put it through, compare it against the reference you studied, and iterate until it holds up as a still. Only then write the timeline. A component that cannot survive a paused frame will not survive motion, and choreographing a broken component wastes every revision that follows.
73145
73150
  12. SCALE TRUTH: a product element never exceeds its native proportion. When a toast, button, or label must be readable, push the CAMERA to it so the whole UI scales together \u2014 never blow one element up inside otherwise-small chrome; an oversized toast over tiny UI text reads as a fake. The same for pointers: a cursor or caret is sized relative to the UI it operates on (match the product's zoom factor; at 67% zoom the cursor is 67% size), a caret pins to its text baseline, and a cursor tip lands ON its target, never near it. The census measures inflated elements; the film is not done while it fires.
73146
- RESIDUAL DRIFT STANDARD: foreground subjects arrive with energy, decelerate strongly, then retain small coherent travel through the reading hold. Compose deterministic residual motion with the native entrance from the same timeline; do not stop and restart or use reversing sine bobs. Rox amount defaults at 960x540 are 3.2-4 for product groups and 0.8-1 for text. Group attached content and shadows, avoid double drift, preserve legibility, and verify reverse seeks and late-hold displacement. Explicit freezes, exact alignment and reduced-motion playback may stop. The host owns the background: object animation must never transform or retime it. Read motion_context guidance.director for the reference ambientOffset formula.
73147
- 13. PACING: slow down. Reading holds are deliberate, not dead air \u2014 the dead-air check finds UNOWNED time, not quiet time. After every claim and every proof, HOLD: the viewer needs settled time to focus before the next change. The motion report flags nonstop motion (TOO FAST) exactly like it flags dead air, and the film is not done while either fires. THE CADENCE: one action at a time, about one every 1\u20131.5 seconds \u2014 a click, a panel opening, a card landing each count as one action. Let each settle before the next. The kit and camera defaults are already tuned to this; never override their durations to be FASTER. The report measures action frequency and flags stretches that pack more.
73151
+ MOTION STANDARD (arrival, hold, exit): each foreground subject follows one continuous trajectory: it arrives with energy, decelerates strongly to near-zero speed for the reading hold, then accelerates into its exit or next authored move. No separate drift layer, no velocity floor, no perpetual creep: the ease tail moves a held subject less than ~0.5 output px across the hold, so holds read still. Exports snap slow movement to whole pixels (a ~1 px/s creep becomes a 1 px tick every ~0.9 s). This applies to whole entities (a card, window, headline block, logo lockup), not recursively to every child: children ride with their entity and may only have discrete actions in the hold (typing, a toggle, a highlight), never their own arrive/hold/exit. Group attached content and shadows and verify reverse seeks. The host owns the background: object animation must never transform or retime it. Full standard: motion_context guidance.director.
73152
+ 13. PACING: slow down. Reading holds are deliberate, not dead air \u2014 the dead-air check finds UNOWNED time, not quiet time. After every claim and every proof, HOLD: the viewer needs settled time to focus before the next change. The motion report flags nonstop motion (TOO FAST) and the film is not done while it fires. Dead air (a still span longer than a ~1.5s reading hold) is advisory: trim the hold or add a discrete event, never a drift. THE CADENCE: one action at a time, about one every 1\u20131.5 seconds \u2014 a click, a panel opening, a card landing each count as one action. Let each settle before the next. The kit and camera defaults are already tuned to this; never override their durations to be FASTER. The report measures action frequency and flags stretches that pack more.
73148
73153
  14. CUTS: a scene change lands ONLY on a declared beat boundary \u2014 never mid-beat, never mid-read. If the direction uses the semantic film sequencer, wrap staggered text with createTextPlans() and schedule the boundary with film.cut(...): action ordering may continue at SETTLE, but a scene cut must wait for END. Use coveredCut() only when a named visible carrier genuinely hides the seam. A transition is either a real camera move (the house dolly) or a hard cut covered by the incoming element; a 0.1\u20130.3s squash-collapse is neither. Vary how scenes leave \u2014 the same exit mechanism back to back reads as a loop, and a scene alive under ~2 seconds never registered. The motion score measures all of this.
73149
73154
  15. THE GO-THROUGH: to dive into a button/card/color until it takes over the frame and becomes the next scene, ALWAYS use transition.through(target, { swap, land }) \u2014 never hand-roll it with a big camera zoom plus a timed tl.set swap. Hand-rolled dives aim at build-time positions and miss; through() measures the target at the dive's start time, computes the exact cover scale, and guarantees the cut lands under full cover. It has modes: { via: "glyph", char: "o" } dives through a character's enclosed counter on PLAIN text (never wrap glyphs in spans or tune margins by hand \u2014 the hole is measured from the glyph outline), { via: "word", word: "..." } dives through a word, and { via: "anchor" } is the match-cut: the subject persists across the cut while the world changes around it.` + (ctx.qualityLoop ? qualityLoopServerInstructions({ gateReform: ctx.gateReform }) : "") + (ctx.motionLab ? motionLabServerInstructions() : "") + (ctx.holdLifeGate && !ctx.gateReform ? `
73150
73155
 
@@ -73174,6 +73179,7 @@ function createServer(ctx) {
73174
73179
  instructions: buildServerInstructions(validatedCtx)
73175
73180
  }
73176
73181
  );
73182
+ server.server.oninitialized = () => setAgentName(server.server.getClientVersion()?.name);
73177
73183
  const tools = [
73178
73184
  ...TOOLS,
73179
73185
  installKitsTool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@impractical-ai/motion",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "private": false,
5
5
  "description": "Create and refine Impractical Motion videos from coding agents and the terminal.",
6
6
  "homepage": "https://github.com/Openpod/impractical-motion#readme",