@prestyj/cli 5.28.0 → 5.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/README.md +2 -2
  2. package/assets/motion/THIRD-PARTY.md +14 -19
  3. package/assets/motion/bin/contact-sheet.mjs +9 -3
  4. package/assets/motion/bin/cues.mjs +337 -0
  5. package/assets/motion/bin/flash-check.mjs +314 -0
  6. package/assets/motion/bin/fonts.mjs +17 -13
  7. package/assets/motion/bin/library.mjs +61 -18
  8. package/assets/motion/bin/motion-blur.mjs +943 -0
  9. package/assets/motion/bin/motion-check.mjs +366 -9
  10. package/assets/motion/bin/music-fit.mjs +436 -0
  11. package/assets/motion/bin/pdf-extract.mjs +22 -10
  12. package/assets/motion/bin/reference-study.mjs +346 -0
  13. package/assets/motion/bin/score-synth.mjs +1052 -93
  14. package/assets/motion/fonts/finger-paint/OFL.txt +93 -0
  15. package/assets/motion/fonts/finger-paint/finger-paint-normal.woff2 +0 -0
  16. package/assets/motion/fonts/fonts.json +56 -0
  17. package/assets/motion/fonts/short-stack/OFL.txt +94 -0
  18. package/assets/motion/fonts/short-stack/short-stack-normal.woff2 +0 -0
  19. package/assets/motion/fonts/sora/OFL.txt +93 -0
  20. package/assets/motion/fonts/sora/sora-normal.woff2 +0 -0
  21. package/assets/motion/fonts/specimen.jpg +0 -0
  22. package/assets/motion/fonts/unbounded/OFL.txt +93 -0
  23. package/assets/motion/fonts/unbounded/unbounded-normal.woff2 +0 -0
  24. package/assets/motion/library/README.md +52 -14
  25. package/assets/motion/library/kit/moves.js +1981 -0
  26. package/assets/motion/library/library.json +232 -0
  27. package/assets/motion/library/pieces/camera-rig/meta.json +13 -0
  28. package/assets/motion/library/pieces/camera-rig/piece.html +153 -0
  29. package/assets/motion/library/pieces/camera-rig/preview.jpg +0 -0
  30. package/assets/motion/library/pieces/chain-knock/meta.json +13 -0
  31. package/assets/motion/library/pieces/chain-knock/piece.html +195 -0
  32. package/assets/motion/library/pieces/chain-knock/preview.jpg +0 -0
  33. package/assets/motion/library/pieces/gather-to-logo/meta.json +13 -0
  34. package/assets/motion/library/pieces/gather-to-logo/piece.html +159 -0
  35. package/assets/motion/library/pieces/gather-to-logo/preview.jpg +0 -0
  36. package/assets/motion/library/pieces/morph-carry/meta.json +13 -0
  37. package/assets/motion/library/pieces/morph-carry/piece.html +173 -0
  38. package/assets/motion/library/pieces/morph-carry/preview.jpg +0 -0
  39. package/assets/motion/library/pieces/one-shape-journey/meta.json +13 -0
  40. package/assets/motion/library/pieces/one-shape-journey/piece.html +195 -0
  41. package/assets/motion/library/pieces/one-shape-journey/preview.jpg +0 -0
  42. package/assets/motion/library/pieces/open-from-subject/meta.json +13 -0
  43. package/assets/motion/library/pieces/open-from-subject/piece.html +168 -0
  44. package/assets/motion/library/pieces/open-from-subject/preview.jpg +0 -0
  45. package/assets/motion/library/pieces/request-to-result/meta.json +13 -0
  46. package/assets/motion/library/pieces/request-to-result/piece.html +212 -0
  47. package/assets/motion/library/pieces/request-to-result/preview.jpg +0 -0
  48. package/assets/motion/library/pieces/scale-dive/meta.json +13 -0
  49. package/assets/motion/library/pieces/scale-dive/piece.html +321 -0
  50. package/assets/motion/library/pieces/scale-dive/preview.jpg +0 -0
  51. package/assets/motion/library/pieces/screen-replica-steps/meta.json +13 -0
  52. package/assets/motion/library/pieces/screen-replica-steps/piece.html +366 -0
  53. package/assets/motion/library/pieces/screen-replica-steps/preview.jpg +0 -0
  54. package/assets/motion/library/pieces/zoom-into-card/meta.json +13 -0
  55. package/assets/motion/library/pieces/zoom-into-card/piece.html +179 -0
  56. package/assets/motion/library/pieces/zoom-into-card/preview.jpg +0 -0
  57. package/assets/motion/library/sheets/diagram.jpg +0 -0
  58. package/assets/motion/library/sheets/frame.jpg +0 -0
  59. package/assets/motion/library/sheets/transition.jpg +0 -0
  60. package/assets/motion/library/sheets/ui.jpg +0 -0
  61. package/assets/motion/plugin.json +1 -1
  62. package/assets/motion/references/build-sheet.md +206 -0
  63. package/assets/motion/references/runtime/determinism-rules.md +3 -3
  64. package/assets/motion/references/runtime/gsap-easing-and-stagger.md +28 -28
  65. package/assets/motion/references/runtime/gsap.md +3 -3
  66. package/assets/motion/references/runtime/inputs-and-assets.md +21 -16
  67. package/assets/motion/references/runtime/lint-validate-inspect.md +3 -3
  68. package/assets/motion/references/runtime/minimal-composition.md +6 -0
  69. package/assets/motion/references/runtime/preview-render.md +3 -3
  70. package/assets/motion/skills/app-walkthrough/SKILL.md +66 -0
  71. package/assets/motion/skills/before-after/SKILL.md +53 -0
  72. package/assets/motion/skills/brand-kit/SKILL.md +17 -16
  73. package/assets/motion/skills/dev-tool-video/SKILL.md +57 -0
  74. package/assets/motion/skills/launch-video/SKILL.md +62 -0
  75. package/assets/motion/skills/match-reference/SKILL.md +58 -0
  76. package/assets/motion/skills/motion/SKILL.md +167 -98
  77. package/assets/motion/skills/source-ingest/SKILL.md +23 -15
  78. package/assets/motion/skills/website-video/SKILL.md +59 -0
  79. package/assets/skills/bulletproof/SKILL.md +36 -11
  80. package/assets/skills/bulletproof/references/agent-surface.md +19 -9
  81. package/assets/skills/bulletproof/references/audit-protocol.md +20 -5
  82. package/assets/skills/bulletproof/references/platform-playbooks.md +5 -4
  83. package/assets/skills/bulletproof/references/provenance.md +26 -1
  84. package/assets/skills/bulletproof/references/secure-defaults.md +6 -5
  85. package/assets/skills/bulletproof/references/supply-chain.md +21 -17
  86. package/assets/skills/bulletproof/references/threat-landscape.md +28 -26
  87. package/assets/skills/bulletproof/references/verification.md +2 -0
  88. package/assets/skills/clarify/SKILL.md +25 -16
  89. package/assets/skills/code-review/SKILL.md +71 -13
  90. package/assets/skills/code-review/references/agent-diffs.md +27 -0
  91. package/assets/skills/code-review/references/tests.md +19 -0
  92. package/assets/skills/compliance-guard/SKILL.md +20 -5
  93. package/assets/skills/compliance-guard/references/artifacts.md +1 -1
  94. package/assets/skills/compliance-guard/references/eu-uk.md +16 -16
  95. package/assets/skills/compliance-guard/references/lawsuit-vectors.md +5 -5
  96. package/assets/skills/compliance-guard/references/provenance.md +41 -2
  97. package/assets/skills/compliance-guard/references/sector-gates.md +3 -3
  98. package/assets/skills/compliance-guard/references/security-baseline.md +2 -2
  99. package/assets/skills/compliance-guard/references/trigger-map.md +5 -5
  100. package/assets/skills/compliance-guard/references/us.md +27 -21
  101. package/assets/skills/durable/SKILL.md +87 -79
  102. package/assets/skills/durable/references/agent-db-safety.md +69 -0
  103. package/assets/skills/durable/references/backups-and-runtime.md +19 -12
  104. package/assets/skills/durable/references/migrations-and-schema.md +13 -6
  105. package/assets/skills/evidence-led-ui/SKILL.md +69 -127
  106. package/assets/skills/evidence-led-ui/references/anti-defaults.md +107 -208
  107. package/assets/skills/evidence-led-ui/references/direction.md +124 -0
  108. package/assets/skills/evidence-led-ui/references/production-contract.md +8 -0
  109. package/assets/skills/evidence-led-ui/references/provenance.md +24 -1
  110. package/assets/skills/lean/SKILL.md +90 -71
  111. package/assets/skills/lean/references/memory-and-processes.md +3 -2
  112. package/assets/skills/lean/references/playbooks.md +37 -12
  113. package/assets/skills/refactoring/SKILL.md +24 -3
  114. package/assets/skills/refactoring/references/agent-pitfalls.md +4 -1
  115. package/assets/skills/refactoring/references/legacy.md +21 -0
  116. package/assets/skills/root-cause/SKILL.md +20 -10
  117. package/assets/skills/shared-language/SKILL.md +16 -14
  118. package/assets/skills/tdd/SKILL.md +27 -15
  119. package/dist/app-sidecar.js +203 -47
  120. package/dist/app-sidecar.js.map +1 -1
  121. package/dist/cli.js +20 -28
  122. package/dist/cli.js.map +1 -1
  123. package/dist/core/acceptance-checks.d.ts +48 -0
  124. package/dist/core/acceptance-checks.js +144 -0
  125. package/dist/core/acceptance-checks.js.map +1 -0
  126. package/dist/core/agent-session.d.ts +119 -75
  127. package/dist/core/agent-session.js +561 -395
  128. package/dist/core/agent-session.js.map +1 -1
  129. package/dist/core/agents.d.ts +6 -5
  130. package/dist/core/agents.js +12 -3
  131. package/dist/core/agents.js.map +1 -1
  132. package/dist/core/ask-user.d.ts +90 -8
  133. package/dist/core/ask-user.js +124 -13
  134. package/dist/core/ask-user.js.map +1 -1
  135. package/dist/core/auth-providers.js +1 -1
  136. package/dist/core/auth-providers.js.map +1 -1
  137. package/dist/core/autopilot-verdict.d.ts +5 -1
  138. package/dist/core/autopilot-verdict.js +30 -13
  139. package/dist/core/autopilot-verdict.js.map +1 -1
  140. package/dist/core/bundled-agents.js +1 -3
  141. package/dist/core/bundled-agents.js.map +1 -1
  142. package/dist/core/cache-diagnostics.d.ts +68 -0
  143. package/dist/core/cache-diagnostics.js +196 -0
  144. package/dist/core/cache-diagnostics.js.map +1 -0
  145. package/dist/core/cache-expiry.d.ts +87 -0
  146. package/dist/core/cache-expiry.js +111 -0
  147. package/dist/core/cache-expiry.js.map +1 -0
  148. package/dist/core/compaction/compactor.js +78 -48
  149. package/dist/core/compaction/compactor.js.map +1 -1
  150. package/dist/core/compaction/plan-step-policy.d.ts +46 -0
  151. package/dist/core/compaction/plan-step-policy.js +57 -0
  152. package/dist/core/compaction/plan-step-policy.js.map +1 -0
  153. package/dist/core/destructive-git-guard.d.ts +90 -0
  154. package/dist/core/destructive-git-guard.js +871 -0
  155. package/dist/core/destructive-git-guard.js.map +1 -0
  156. package/dist/core/event-bus.d.ts +3 -0
  157. package/dist/core/event-bus.js +5 -0
  158. package/dist/core/event-bus.js.map +1 -1
  159. package/dist/core/fast-apply-benchmark.d.ts +1 -1
  160. package/dist/core/fast-apply-benchmark.js +2 -2
  161. package/dist/core/fast-apply-benchmark.js.map +1 -1
  162. package/dist/core/injection-detect.d.ts +38 -0
  163. package/dist/core/injection-detect.js +232 -0
  164. package/dist/core/injection-detect.js.map +1 -0
  165. package/dist/core/keep-awake.d.ts +88 -0
  166. package/dist/core/keep-awake.js +251 -0
  167. package/dist/core/keep-awake.js.map +1 -0
  168. package/dist/core/mcp/client.d.ts +72 -0
  169. package/dist/core/mcp/client.js +264 -41
  170. package/dist/core/mcp/client.js.map +1 -1
  171. package/dist/core/mcp/content.js +6 -2
  172. package/dist/core/mcp/content.js.map +1 -1
  173. package/dist/core/mcp/store.d.ts +6 -1
  174. package/dist/core/mcp/store.js +12 -1
  175. package/dist/core/mcp/store.js.map +1 -1
  176. package/dist/core/mcp/types.d.ts +18 -0
  177. package/dist/core/model-unavailable.d.ts +14 -0
  178. package/dist/core/model-unavailable.js +23 -0
  179. package/dist/core/model-unavailable.js.map +1 -0
  180. package/dist/core/node-debugger.d.ts +148 -0
  181. package/dist/core/node-debugger.js +642 -0
  182. package/dist/core/node-debugger.js.map +1 -0
  183. package/dist/core/nolan-context.d.ts +7 -5
  184. package/dist/core/nolan-context.js +106 -16
  185. package/dist/core/nolan-context.js.map +1 -1
  186. package/dist/core/nolan-prompt.js +24 -21
  187. package/dist/core/nolan-prompt.js.map +1 -1
  188. package/dist/core/package-threats.d.ts +18 -0
  189. package/dist/core/package-threats.js +168 -0
  190. package/dist/core/package-threats.js.map +1 -0
  191. package/dist/core/persistent-shell.d.ts +58 -6
  192. package/dist/core/persistent-shell.js +331 -49
  193. package/dist/core/persistent-shell.js.map +1 -1
  194. package/dist/core/process-manager.d.ts +14 -0
  195. package/dist/core/process-manager.js +61 -0
  196. package/dist/core/process-manager.js.map +1 -1
  197. package/dist/core/progress/git-xp.js +8 -14
  198. package/dist/core/progress/git-xp.js.map +1 -1
  199. package/dist/core/project-discovery.js +77 -26
  200. package/dist/core/project-discovery.js.map +1 -1
  201. package/dist/core/semantic-search-benchmark.d.ts +1 -1
  202. package/dist/core/semantic-search-benchmark.js +2 -2
  203. package/dist/core/semantic-search-benchmark.js.map +1 -1
  204. package/dist/core/session-history.d.ts +12 -0
  205. package/dist/core/session-history.js +27 -0
  206. package/dist/core/session-history.js.map +1 -1
  207. package/dist/core/session-manager.d.ts +13 -1
  208. package/dist/core/session-manager.js +38 -18
  209. package/dist/core/session-manager.js.map +1 -1
  210. package/dist/core/session-summary-index.d.ts +37 -0
  211. package/dist/core/session-summary-index.js +172 -0
  212. package/dist/core/session-summary-index.js.map +1 -0
  213. package/dist/core/settings-manager.d.ts +2 -0
  214. package/dist/core/settings-manager.js +10 -0
  215. package/dist/core/settings-manager.js.map +1 -1
  216. package/dist/core/shell-threats-popular-packages.d.ts +11 -0
  217. package/dist/core/shell-threats-popular-packages.js +675 -0
  218. package/dist/core/shell-threats-popular-packages.js.map +1 -0
  219. package/dist/core/shell-threats.d.ts +8 -0
  220. package/dist/core/shell-threats.js +186 -0
  221. package/dist/core/shell-threats.js.map +1 -0
  222. package/dist/core/skills.js +16 -4
  223. package/dist/core/skills.js.map +1 -1
  224. package/dist/core/stream-rules.d.ts +30 -0
  225. package/dist/core/stream-rules.js +151 -0
  226. package/dist/core/stream-rules.js.map +1 -0
  227. package/dist/core/subagent-manager.d.ts +23 -6
  228. package/dist/core/subagent-manager.js +25 -9
  229. package/dist/core/subagent-manager.js.map +1 -1
  230. package/dist/core/subagent-policy.js +1 -1
  231. package/dist/core/subagent-policy.js.map +1 -1
  232. package/dist/core/subagent-receipt.d.ts +54 -0
  233. package/dist/core/subagent-receipt.js +276 -0
  234. package/dist/core/subagent-receipt.js.map +1 -0
  235. package/dist/core/subagent-turn-record.d.ts +2 -0
  236. package/dist/core/subagent-turn-record.js.map +1 -1
  237. package/dist/core/test-impact.d.ts +73 -0
  238. package/dist/core/test-impact.js +467 -0
  239. package/dist/core/test-impact.js.map +1 -0
  240. package/dist/core/thinking-level.d.ts +1 -1
  241. package/dist/core/thinking-level.js +1 -1
  242. package/dist/core/thinking-level.js.map +1 -1
  243. package/dist/core/verification-gate.d.ts +2 -0
  244. package/dist/core/verification-gate.js +4 -0
  245. package/dist/core/verification-gate.js.map +1 -1
  246. package/dist/core/verification-snapshot.js +3 -5
  247. package/dist/core/verification-snapshot.js.map +1 -1
  248. package/dist/core/workspace-guard.d.ts +18 -7
  249. package/dist/core/workspace-guard.js +227 -60
  250. package/dist/core/workspace-guard.js.map +1 -1
  251. package/dist/core/worktree-setup.d.ts +23 -0
  252. package/dist/core/worktree-setup.js +128 -9
  253. package/dist/core/worktree-setup.js.map +1 -1
  254. package/dist/core/worktree.d.ts +20 -2
  255. package/dist/core/worktree.js +74 -31
  256. package/dist/core/worktree.js.map +1 -1
  257. package/dist/interactive.js +2 -1
  258. package/dist/interactive.js.map +1 -1
  259. package/dist/modes/json-mode.js +11 -2
  260. package/dist/modes/json-mode.js.map +1 -1
  261. package/dist/modes/subagent-worker-mode.d.ts +36 -1
  262. package/dist/modes/subagent-worker-mode.js +100 -42
  263. package/dist/modes/subagent-worker-mode.js.map +1 -1
  264. package/dist/motion-agent/motion-agent.d.ts +7 -3
  265. package/dist/motion-agent/motion-agent.js +6 -8
  266. package/dist/motion-agent/motion-agent.js.map +1 -1
  267. package/dist/motion-agent/motion-prompt.d.ts +1 -1
  268. package/dist/motion-agent/motion-prompt.js +16 -25
  269. package/dist/motion-agent/motion-prompt.js.map +1 -1
  270. package/dist/motion-agent/motion-review-session.js +1 -1
  271. package/dist/motion-agent/motion-review-session.js.map +1 -1
  272. package/dist/motion-agent/motion-review.d.ts +10 -3
  273. package/dist/motion-agent/motion-review.js +15 -7
  274. package/dist/motion-agent/motion-review.js.map +1 -1
  275. package/dist/motion-agent/motion-studio-context.js +1 -1
  276. package/dist/motion-agent/motion-studio-context.js.map +1 -1
  277. package/dist/system-prompt.d.ts +2 -1
  278. package/dist/system-prompt.js +15 -4
  279. package/dist/system-prompt.js.map +1 -1
  280. package/dist/test-support/keep-alive.d.ts +14 -0
  281. package/dist/test-support/keep-alive.js +17 -0
  282. package/dist/test-support/keep-alive.js.map +1 -0
  283. package/dist/tools/ask-user.js +3 -3
  284. package/dist/tools/ask-user.js.map +1 -1
  285. package/dist/tools/bash-read-evidence.d.ts +10 -0
  286. package/dist/tools/bash-read-evidence.js +133 -0
  287. package/dist/tools/bash-read-evidence.js.map +1 -0
  288. package/dist/tools/bash.d.ts +10 -1
  289. package/dist/tools/bash.js +179 -7
  290. package/dist/tools/bash.js.map +1 -1
  291. package/dist/tools/debug.d.ts +54 -0
  292. package/dist/tools/debug.js +233 -0
  293. package/dist/tools/debug.js.map +1 -0
  294. package/dist/tools/edit.js +13 -5
  295. package/dist/tools/edit.js.map +1 -1
  296. package/dist/tools/goals.d.ts +1 -1
  297. package/dist/tools/index.d.ts +25 -2
  298. package/dist/tools/index.js +48 -7
  299. package/dist/tools/index.js.map +1 -1
  300. package/dist/tools/prompt-hints.js +2 -0
  301. package/dist/tools/prompt-hints.js.map +1 -1
  302. package/dist/tools/read-tracker.d.ts +35 -2
  303. package/dist/tools/read-tracker.js +108 -11
  304. package/dist/tools/read-tracker.js.map +1 -1
  305. package/dist/tools/read.js +39 -7
  306. package/dist/tools/read.js.map +1 -1
  307. package/dist/tools/skill.js +5 -0
  308. package/dist/tools/skill.js.map +1 -1
  309. package/dist/tools/subagent-control.js +44 -8
  310. package/dist/tools/subagent-control.js.map +1 -1
  311. package/dist/tools/subagent-shared.d.ts +48 -8
  312. package/dist/tools/subagent-shared.js +75 -14
  313. package/dist/tools/subagent-shared.js.map +1 -1
  314. package/dist/tools/subagent.d.ts +8 -2
  315. package/dist/tools/subagent.js +28 -10
  316. package/dist/tools/subagent.js.map +1 -1
  317. package/dist/tools/task-output.js +3 -2
  318. package/dist/tools/task-output.js.map +1 -1
  319. package/dist/tools/task-send.d.ts +1 -1
  320. package/dist/tools/task-send.js +15 -1
  321. package/dist/tools/task-send.js.map +1 -1
  322. package/dist/tools/tool-tiers.d.ts +2 -2
  323. package/dist/tools/tool-tiers.js +3 -2
  324. package/dist/tools/tool-tiers.js.map +1 -1
  325. package/dist/tools/truncate.d.ts +21 -0
  326. package/dist/tools/truncate.js +187 -0
  327. package/dist/tools/truncate.js.map +1 -1
  328. package/dist/tools/ui-adopt.js +2 -0
  329. package/dist/tools/ui-adopt.js.map +1 -1
  330. package/dist/tools/write.js +4 -3
  331. package/dist/tools/write.js.map +1 -1
  332. package/dist/ui/App.d.ts +0 -4
  333. package/dist/ui/App.js +5 -28
  334. package/dist/ui/App.js.map +1 -1
  335. package/dist/ui/components/ActivityIndicator.js +1 -0
  336. package/dist/ui/components/ActivityIndicator.js.map +1 -1
  337. package/dist/ui/components/Footer.js +1 -1
  338. package/dist/ui/components/Footer.js.map +1 -1
  339. package/dist/ui/hooks/useAgentLoop.d.ts +1 -8
  340. package/dist/ui/hooks/useAgentLoop.js +1 -119
  341. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  342. package/dist/ui/render.d.ts +2 -4
  343. package/dist/ui/render.js +3 -2
  344. package/dist/ui/render.js.map +1 -1
  345. package/dist/utils/git.d.ts +77 -0
  346. package/dist/utils/git.js +285 -21
  347. package/dist/utils/git.js.map +1 -1
  348. package/dist/utils/github-ci.js +2 -1
  349. package/dist/utils/github-ci.js.map +1 -1
  350. package/dist/utils/github.js +11 -9
  351. package/dist/utils/github.js.map +1 -1
  352. package/dist/utils/image.d.ts +14 -0
  353. package/dist/utils/image.js +16 -0
  354. package/dist/utils/image.js.map +1 -1
  355. package/dist/utils/process.d.ts +20 -0
  356. package/dist/utils/process.js +98 -0
  357. package/dist/utils/process.js.map +1 -1
  358. package/dist/utils/text.d.ts +12 -0
  359. package/dist/utils/text.js +11 -0
  360. package/dist/utils/text.js.map +1 -1
  361. package/package.json +6 -6
  362. package/assets/motion/skills/mixkit-split-text-617/SKILL.md +0 -115
  363. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-480.json +0 -1
  364. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-494.json +0 -1
  365. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-5.json +0 -1
  366. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-508.json +0 -1
  367. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6525.json +0 -1
  368. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6539.json +0 -1
  369. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6647.json +0 -1
  370. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6663.json +0 -1
  371. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6677.json +0 -1
  372. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6691.json +0 -1
  373. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6706.json +0 -1
  374. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6722.json +0 -1
  375. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6736.json +0 -1
  376. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6750.json +0 -1
  377. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6764.json +0 -1
  378. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6780.json +0 -1
  379. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6794.json +0 -1
  380. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6810.json +0 -1
  381. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6823.json +0 -1
  382. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6872.json +0 -1
  383. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-6936.json +0 -1
  384. package/assets/motion/skills/mixkit-split-text-617/data/compositions/comp-76.json +0 -1
  385. package/assets/motion/skills/mixkit-split-text-617/data/manifest.json +0 -495
  386. package/assets/motion/skills/mixkit-split-text-617/references/RECONSTRUCTION.md +0 -201
  387. package/assets/motion/skills/mixkit-split-text-617/references/VERIFICATION.md +0 -107
  388. package/assets/motion/skills/mixkit-split-text-617/tools/inspect_motion.py +0 -130
  389. package/assets/motion/skills/video-qa/SKILL.md +0 -66
  390. package/dist/core/ideal-review-subagent.d.ts +0 -42
  391. package/dist/core/ideal-review-subagent.js +0 -95
  392. package/dist/core/ideal-review-subagent.js.map +0 -1
  393. package/dist/core/ideal-review.d.ts +0 -82
  394. package/dist/core/ideal-review.js +0 -242
  395. package/dist/core/ideal-review.js.map +0 -1
  396. package/dist/motion-agent/motion-check-tool.d.ts +0 -21
  397. package/dist/motion-agent/motion-check-tool.js +0 -206
  398. package/dist/motion-agent/motion-check-tool.js.map +0 -1
@@ -0,0 +1,206 @@
1
+ # Build sheet
2
+
3
+ Everything needed to write a composition with the move kit and to score it,
4
+ in one place. It is the complete public surface: you do not need to open
5
+ `moves.js`, `score-synth.mjs` or any helper's `--help` to use them.
6
+
7
+ ## Move kit (`window.GGMotionKit`)
8
+
9
+ Install with `<node> "<motion bin>/library.mjs" kit <project>`, load
10
+ `assets/kit/moves.js` after GSAP, then `const kit = window.GGMotionKit;`.
11
+ Every move adds tweens to `tl` from time `at` and returns the time of its key
12
+ moment, so the next move can start from it. Options are all optional; the
13
+ value after `=` is the default.
14
+
15
+ ### Arrivals
16
+
17
+ | Call | Options | Returns |
18
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
19
+ | `liftWords(tl, el, at, o)` | `stagger=0.07`, `spring="snappy"`, `duration`, `from=115` (start yPercent) | when the last word has mostly risen |
20
+ | `dropLetters(tl, el, at, o)` | `height=260`, `fall=0.38`, `stagger=0.05`, `squash=0.24`, `spring="bouncy"` | the last landing |
21
+ | `reveal(tl, el, at, o)` | `from="bottom"` (top, bottom, left, right), `duration=0.8`, `ease="snap"` | end |
22
+ | `typewrite(tl, el, at, o)` | `text` (default the element's text), `cps=22`, `jitter=0.4`, `seed=11`, `caret="▍"` or `false`, `caretHold=0` | when typing ends |
23
+ | `tick(tl, path, at, o)` | `duration=0.34`, `ease="snap"` (an SVG path) | end |
24
+ | `pop(tl, el, at, o)` | `from=0.3` (start scale), `spring="bouncy"` | when it reads as arrived |
25
+ | `stamp(tl, el, at, o)` | `duration=0.2`, `rotate=-4`, `from=2.4` | the contact |
26
+
27
+ ### Handoffs
28
+
29
+ | Call | Options | Returns |
30
+ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------- |
31
+ | `reshape(tl, el, at, to, o)` | `to` is `{ x, y, w, h, r }` or an element; `duration=0.85`, `ease="travel"`, or `spring` | when the change reads |
32
+ | `openFrom(tl, stage, at, o)` | `x`, `y` (default the centre), `width=1920`, `height=1080`, `from=0`, `duration=0.9`, `ease="travel"` | end |
33
+ | `diveThrough(tl, layer, at, o)` | `x=960`, `y=540`, `zoom=16`, `duration=1`, `ease="drop"`, `next` (element shown at the end) | end |
34
+ | `converge(tl, els, at, target, o)` | `target` is `{ x, y }`; `duration=0.85`, `stagger=0.05`, `bow=0.28`, `shrink=0.12`, `seed=5`, `ease="drop"`, `space` | the last arrival |
35
+
36
+ `converge` and `hop` own the element's transform: wrap an element to also
37
+ pop or move it.
38
+
39
+ **What each move animates**, so two moves on one element never fight:
40
+ `liftWords` yPercent of its word spans; `dropLetters` y, scaleX, scaleY and
41
+ opacity of its letters; `reveal` and `openFrom` clip-path; `tick`
42
+ stroke-dashoffset; `pop` scale and opacity; `stamp` scale, rotation and
43
+ opacity; `reshape` left, top, width, height and border-radius (position the
44
+ element absolutely); `diveThrough` the layer's scale and the `next`
45
+ element's visibility; `knock` rotation; `impact` the shake layer's x and
46
+ rotation; `converge`, `hop` and `cursorPath` write `style.transform`
47
+ directly. `typewrite` changes only the text.
48
+
49
+ ### Contact
50
+
51
+ | Call | Options | Returns |
52
+ | ----------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------- |
53
+ | `hop(tl, el, at, o)` | `height=140`, `duration=0.5` (air time), `squash=0.2` | the landing |
54
+ | `impact(tl, at, o)` | `shake` (a layer, not the camera world), `amount=16`, `duration=0.6`, `split: [left, right]`, `spread=140` | `at` |
55
+ | `knock(tl, els, at, o)` | `push=48`, `gap=0.11`, `tilt=7`, `axis="x"` or `"y"` | the last contact |
56
+
57
+ ### Camera
58
+
59
+ `const cam = kit.camera(tl, world, keys, o)` drives `world`, a layer holding
60
+ the whole scene in world pixels. It returns `{ plan, at(t), toScreen(t, x, y) }`.
61
+ Make `world` an absolutely positioned element at left 0, top 0 (any size;
62
+ place scenes inside it at their world coordinates). The camera owns its
63
+ transform and sets its transform-origin to 0 0: never animate `world`
64
+ yourself; move things inside it. A key's `x, y` is the world point shown at
65
+ the centre of the frame, so `{ x: 960, y: 540, zoom: 1 }` shows the first
66
+ 1920 × 1080 of the world unchanged.
67
+
68
+ - **Keys**: `[{ x, y, zoom=1, rotate=0 }, { at, x, y, zoom, rotate, move, duration }, ...]`.
69
+ The first key is the start. `move` is a curve name (`whip` by default,
70
+ `glide` for slow pushes, `cut` for a jump); `duration=0.9`.
71
+ - **Options**: `width=1920`, `height=1080`, `duration` (default the last move),
72
+ `lead` (seconds each move starts early), `handheld: { amp=6, rotate=0.2, rate=0.5, seed=7 }`,
73
+ `rests: [[from, to], ...]` (exactly still there), `shakes: [{ at, amount=14, decay=9 }]`,
74
+ `layers: [{ el, depth }]` (0 pinned, 0.5 far, 1 the world, above 1 near).
75
+ - Pure helpers: `cameraAt(plan, t, o)`, `atDepth(cam, depth)`, `toScreen(cam, x, y)`.
76
+
77
+ ### Deep zoom, light, texture
78
+
79
+ | Call | Options | Returns |
80
+ | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
81
+ | `deepZoom(tl, world, at, o)` | `anchor={x,y}` (world point, default the centre), `from=1`, `to=100` (any factor, up to about 1000), `screenFrom`, `screenTo` (where the anchor sits on screen; default the centre), `duration=3`, `ease="glide"`, `width`, `height` | end |
82
+ | `lightGround(tl, el, at, o)` | `rise=0.9`, `hold=0.6`, `drain=0.9`, `x`, `y` (default below the frame), `reach=1.15`, `color` (an `r, g, b` string), `ease="glide"`; on a canvas it paints, on other elements it sets `--light`, `--light-r`, `--light-x`, `--light-y` (with units) | the flood |
83
+ | `rings(tl, el, at, o)` | `count=4`, `duration=1.2`, `stagger=0.14`, `x`, `y` (default the centre), `ease="snap"`; reveals `el` (the next scene) through expanding rings | fully shown |
84
+ | `silk(tl, canvas, at, duration, o)` | `colors` (two or more hex), `seed=1`, `speed=0.08`, `scale=2.2`, `warp=1.2`, `cols=64`, `rows` | end |
85
+ | `belt(tl, items, at, o)` | `speed=240` (px/s), `stop` (timeline time it comes to rest), `spacing=360`, `axis="x"`, `direction=-1`, `rampIn=0.6`, `rampOut=0.9`, `origin`, `wrap` | `{ stop, at(t), clock(t) }` |
86
+ | `brushStroke(tl, canvas, at, o)` | `path` (SVG path) or `points`, `width=28`, `bristles=48`, `dryness=0.65`, `color`, `duration=0.8`, `seed=3`, `ease` | when the brush lifts |
87
+ | `grain(el, o)` | `amount=0.05`, `seed=9`, `size=128`; a fixed overlay so dark gradients do not band; identical on every frame | the tile's data URL |
88
+
89
+ ### Print look (riso, screen print)
90
+
91
+ | Call | Options | Returns |
92
+ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
93
+ | `printInk(el, o)` | `offset={x:0,y:0}` (fixed misregistration), `cell=7` (halftone spacing px), `angle=15`, `amount=0.86` (ink coverage), `rough=0.18`, `seed=3`; sets multiply blending and a halftone mask, so overlapping inks overprint | the tile's data URL |
94
+ | `misregister(tl, layers, at, o)` | `distance=26` px (or `from: [{x,y}, ...]`, one per layer), `seed=11`, `spring="soft"` or `ease` with `duration=0.8`, `apart=false` (true drifts apart instead of settling) | when the inks settle |
95
+ | `paperTexture(el, o)` | `size=256`, `amount=0.06`, `tint="#fdf8ee"`, `fibres=160`, `seed=5`; identical on every frame | the tile's data URL |
96
+
97
+ Give each ink its own layer (one flat colour per layer, e.g. fluorescent pink
98
+ and blue), lay them over paper, and let them settle into register on the beat.
99
+ `printInk` uses the element's `mask-image` and `translate`. Pure helpers:
100
+ `halftoneTile`, `misregisterAt`, `paperTile`.
101
+
102
+ `deepZoom` owns `world`'s transform like the camera does: a dive or pull-out
103
+ keeps its anchor exactly where it is keyed on screen at any depth. Pure
104
+ helpers: `deepZoomAt`, `lightLevel`, `ringsAt`, `silkField`, `beltAt`,
105
+ `grainTile`.
106
+
107
+ ### Cursor
108
+
109
+ `const { end, presses } = kit.cursorPath(tl, cursor, at, stops, o)`. Stops are
110
+ `{ x, y }` or `{ el }`, each with optional `click: true`, `hold=0.15` and
111
+ `duration`. Options: `speed=1500` (px/s), `press=0.09`, `release=0.26`,
112
+ `bow=0.12`, `tip=[6, 4]` (the hotspot), `space`. Script each pressed state and
113
+ its sound from `presses`.
114
+
115
+ ### Sound
116
+
117
+ `kit.cue(tl, at, sfx, { gain=1, x, pan, send, name })` marks a sound where the
118
+ event happens. `x` is the object's screen x and pans with it; `pan` (-1..1)
119
+ overrides it; `send` (0..1) is its distance. Then run
120
+ `<node> "<motion bin>/cues.mjs" <project>`.
121
+
122
+ ### Timing and helpers
123
+
124
+ - **Springs** (`spring` options): `snappy`, `bouncy`, `soft`, `heavy`, `whip`.
125
+ `kit.springEase(name)` gives a GSAP ease; `kit.settleTime(name)` gives its length.
126
+ - **Curves** (`ease` and `move`): `snap`, `drop`, `glide`, `travel`, `whip`,
127
+ `settle`, `bounce`, `firm`, `cut`.
128
+ - `drive(tl, at, duration, draw)`: calls `draw(localTime)` every frame, seeks
129
+ included; draw anything (counters, canvas, SVG) as a pure function of time.
130
+ - `split(el, "words" | "chars", { mask })` returns spans; `centerOf(el, space)`
131
+ and `rectOf(el, space)` measure layout without transforms; `rng(seed)` and
132
+ `noise(seed, t)` are seeded.
133
+
134
+ ## Score (`score.json` for `score-synth.mjs`)
135
+
136
+ Run `<node> "<motion bin>/score-synth.mjs" score.json assets/audio`. It writes
137
+ `music.wav`, `sfx.wav` and `tempo-map.json` (beats, bars, hits, merges,
138
+ balance) in under a second.
139
+
140
+ ```json
141
+ {
142
+ "bpm": 84,
143
+ "duration": 24,
144
+ "seed": 3,
145
+ "style": "lofi",
146
+ "key": "F",
147
+ "scale": "major",
148
+ "chords": ["Fmaj7", "Em7", "Dm7", "Cmaj7"],
149
+ "sections": [
150
+ { "name": "intro", "from": 0, "energy": 0.3 },
151
+ { "name": "groove", "from": 2.9, "energy": 0.7 }
152
+ ],
153
+ "hits": [
154
+ { "t": 3.0, "sfx": "tap" },
155
+ { "beat": 8, "sfx": "chime" },
156
+ { "bar": 4, "sfx": "impact" }
157
+ ],
158
+ "cues": "cues.json",
159
+ "room": "room",
160
+ "duck": 0.55,
161
+ "ending": "resolve",
162
+ "air": true,
163
+ "music": true
164
+ }
165
+ ```
166
+
167
+ - **bpm** 40–220; **duration** in seconds; **seed** any integer.
168
+ - **style**: `pulse` (four on the floor), `cinematic` (swells and low hits),
169
+ `minimal` (sparse keys), `lofi` (swung eighths, dusty keys, round bass,
170
+ soft kit, vinyl and tape wobble).
171
+ - **key** and **scale** (`major` or `minor`) pick default chords; `chords`
172
+ overrides them.
173
+ - **sections**: energy 0–1 brings parts in. In `lofi`: keys and vinyl alone
174
+ below 0.25, kick and snare from 0.25, hats from 0.4, the full kit from 0.5.
175
+ - **hits**: `t` (seconds), `beat` or `bar`, `sfx`, optional `gain` (0–2),
176
+ `pan`, `send`, `name`. Sounds: `tap`, `press`, `knock`, `chime`, `thud`,
177
+ `plip`, `paper`, `breath`, `click`, `tick`, `snap`, `pop`, `glitch`,
178
+ `whoosh`, `whoosh-short`, `riser`, `swell`, `impact`, `sub-drop`, `sting`,
179
+ `shimmer`, `typing`.
180
+ - **cues**: the file `cues.mjs` exported; its hits and camera air join these.
181
+ - **room**: `none`, `booth`, `room`, `hall`. **duck**: music level under the
182
+ heaviest hit (1 = none). **ending**: `resolve` or `cut`. **air**: camera air
183
+ on or off. **music**: false for effects only.
184
+
185
+ ## Licensed or supplied music
186
+
187
+ To cut a track the user supplies to the picture instead of synthesising one:
188
+ `<node> "<motion bin>/music-fit.mjs" <track> --duration <s> [--land <trackTime>@<filmTime>] [--out assets/audio]`.
189
+ It finds the tempo and downbeats, cuts whole bars on downbeats with short
190
+ crossfades so the length is exact, lands the chosen downbeat (`--land`, snapped
191
+ to the nearest one) on a film time, and writes `music.wav` plus
192
+ `music-fit.json` with the downbeats in film time. Put hits on those downbeats.
193
+ Constant tempo and 4/4 only.
194
+
195
+ ## Tall frame (1080 × 1920)
196
+
197
+ Fill the frame and go big. The feeds cover only a bar over the top 138 px, a
198
+ caption over the bottom 422 px and buttons over the right 179 px from y 840
199
+ down; keep words out from under those.
200
+
201
+ ## Render
202
+
203
+ | Step | Command |
204
+ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
205
+ | Final with blur | `<node> "<motion bin>/motion-blur.mjs" <project> renders/<name>-v1.mp4` (the one render, at feed loudness; run it in the background) |
206
+ | Stills | `<node> "<motion bin>/hyperframes.mjs" snapshot <project> --at 1,4,8,12 --describe false` (several at once) |
@@ -15,7 +15,7 @@ For GSAP:
15
15
  - **Do not** call `tl.play()` for render-critical motion.
16
16
  - **Do not** create empty tweens only to set duration; use `data-duration` on the clip instead.
17
17
 
18
- Use the adjacent `gsap.md`, `gsap-timeline-and-labels.md` and `gsap-easing-and-stagger.md` for GSAP mechanics. These technical references do not override the selected recipe's geometry, timing or allowed input changes.
18
+ Use the adjacent `gsap.md`, `gsap-timeline-and-labels.md` and `gsap-easing-and-stagger.md` for GSAP mechanics. These technical references do not choose the design.
19
19
 
20
20
  ## Determinism Rules
21
21
 
@@ -41,9 +41,9 @@ Build the visible end-state in static HTML and CSS first, then animate from/to t
41
41
  - **The root composition's total duration (render length / frame count) is fixed at compile time**, read once from the static root `data-duration` before scripts run, like `data-width` / `data-height`. A script or `--variables` value that rewrites the root `data-duration` afterward is ignored. To vary render length per output, author the root `data-duration` directly. (A _clip's_ own `data-duration` is re-read from the live DOM, so scripts/variables can still drive clip lengths. Only when the root omits `data-duration` does the renderer probe the live DOM / timeline for total length.)
42
42
  - Scene containers should fill the scene with `width: 100%; height: 100%; box-sizing: border-box`.
43
43
  - Use padding, flex, grid, and `max-width` for layout. Avoid positioning main content with hardcoded `top`/`left` offsets when a layout container can do it.
44
- - Preserve the recipe's positioning model. Absolute layers are appropriate when reproducing authored source geometry; generic layout preferences must not alter it.
44
+ - Absolute layers are appropriate for deliberately placed design elements; keep one positioning model per scene.
45
45
  - Prefer transforms and opacity for animation.
46
- - Keep text inside its intended container. Only use wrapping, resizing or `window.__hyperframes.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })` when the recipe permits that fit policy; otherwise resolve the input conflict.
46
+ - Keep text inside its intended container. Wrap, resize or use `window.__hyperframes.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })` deliberately; never let text clip silently.
47
47
  - For text measurement without DOM reflow, use `window.__hyperframes.pretext`. Measure off a canvas instead of writing into the page and reading it back, so nothing reflows: `pretext.prepare(text, font)` then `pretext.layout(prepared, maxWidth, lineHeight)` → `{ lineCount, height }`. `prepare` does the font measurement; everything downstream of a prepared string is arithmetic and cheap enough to run per frame. `fitTextFontSize` is built on it.
48
48
  - `layout` gives you height, not width. To size a container to its text (shrinkwrap), use `pretext.prepareWithSegments(text, font)` and then `pretext.measureNaturalWidth(prepared)` for the single-line width, or `pretext.measureLineStats(prepared, maxWidth)` for `{ lineCount, maxLineWidth }`.
49
49
  - `font` is a CSS font shorthand string, e.g. `"700 90px Inter"`.
@@ -11,14 +11,14 @@ Each has `.in`, `.out`, `.inOut` variants.
11
11
  | `power1.out`, `power2.out` | Gentle motion for secondary elements (a caption fade, a small shift). NOT the entrance default. |
12
12
  | `power3.out` (house default), `power4.out` | The standard long-tail settle. Entrances, title cards, hero reveals. |
13
13
  | `sine.inOut` | Long, slow, calm motion. Crossfades, ambient drift. |
14
- | `back.out(1.7)` | Overshoot then settle. RARE — explicitly-playful register only, never a default. |
15
- | `elastic.out(1, 0.3)` | Springy bounce. Same playful-only rule; prefer a baked spring (see Spring Eases below). |
14
+ | `back.out(1.7)` | Overshoot then settle. A chosen register (playful, physical), never a default. |
15
+ | `elastic.out(1, 0.3)` | Springy bounce. Same register rule; prefer a baked spring (see Spring Eases below). |
16
16
  | `expo.inOut` | Snappy, dramatic. Quick transitions between hero scenes. |
17
17
  | `none` (linear) | Camera moves with timed counterpoint, mechanical motion. |
18
18
 
19
19
  Pick `.out` for entrances, `.in` for exits, `.inOut` for symmetric moves and continuous motion.
20
20
 
21
- **Smooth beats bouncy** — the motion doctrine (`rules/spring-pop-entrance.md`, the workflows' `motion-language.md`): entrances default to `power3.out` or the baked critically-damped spring (see Spring Eases below); overshoot eases (`back` / `elastic` / `bounce`) are a rare, explicitly-playful register, never the house style.
21
+ **Smooth by default, bounce by choice**: entrances default to `power3.out` or the baked critically-damped spring (see Spring Eases below); overshoot eases (`back` / `elastic` / `bounce`, or an underdamped spring) are a register the brief chooses for playful or physical work, never the house style.
22
22
 
23
23
  ## Easing Vocabulary (character & mood)
24
24
 
@@ -26,18 +26,18 @@ Easings are tone of voice: a video that only whispers is boring; one that varies
26
26
 
27
27
  The full palette by character (each family has `.in`, `.out`, `.inOut` variants):
28
28
 
29
- | Family | Character | Typical use |
30
- | -------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
31
- | `power1`–`power4` | Gentle (1) to aggressive (4) acceleration curves | General purpose. **power3 is the house workhorse**; power2 for gentle secondary motion, power4 for dramatic snaps |
32
- | `back(N)` | Overshoot then settle. N controls how far past the target (1=subtle, 4=wild) | RARE — explicitly-playful register only, never a default. Keep N ≤ 2; prefer a baked spring at ζ 0.6–0.7 (physical settle, see Spring Eases) |
33
- | `elastic(amp, freq)` | Spring bounce. amp=magnitude, freq=oscillation speed | RARE — same playful-only rule; the baked spring (below) is the physical version |
34
- | `bounce` | Ball-drop bouncing | RARE — physical-comedy register only (something literally dropping) |
35
- | `expo` | Extreme acceleration curve (much steeper than power4) | Premium/luxury reveals, dramatic entrances |
36
- | `sine` | Smooth, organic, no hard edges | Ambient float, breathing, Ken Burns, anything that loops. `.inOut` for yoyo motion |
37
- | `circ` | Circular acceleration (starts very fast, ends very gentle or vice versa) | Camera moves, scene transitions, orbital motion |
38
- | `steps(N)` | Discrete N-step jumps, no interpolation | Typing effects, cursor blink, counter ticks, retro/digital aesthetics |
29
+ | Family | Character | Typical use |
30
+ | -------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
31
+ | `power1`–`power4` | Gentle (1) to aggressive (4) acceleration curves | General purpose. **power3 is the house workhorse**; power2 for gentle secondary motion, power4 for dramatic snaps |
32
+ | `back(N)` | Overshoot then settle. N controls how far past the target (1=subtle, 4=wild) | Chosen register only (playful, physical), never a default. Keep N ≤ 2; prefer a baked spring at ζ 0.6–0.7 (physical settle, see Spring Eases) |
33
+ | `elastic(amp, freq)` | Spring bounce. amp=magnitude, freq=oscillation speed | Same register rule; the baked spring (below) is the physical version |
34
+ | `bounce` | Ball-drop bouncing | Physical-comedy register only (something literally dropping) |
35
+ | `expo` | Extreme acceleration curve (much steeper than power4) | Premium/luxury reveals, dramatic entrances |
36
+ | `sine` | Smooth, organic, no hard edges | Ambient float, breathing, Nolan Burns, anything that loops. `.inOut` for yoyo motion |
37
+ | `circ` | Circular acceleration (starts very fast, ends very gentle or vice versa) | Camera moves, scene transitions, orbital motion |
38
+ | `steps(N)` | Discrete N-step jumps, no interpolation | Typing effects, cursor blink, counter ticks, retro/digital aesthetics |
39
39
 
40
- **Mood mapping:** Match easing character to the beat's emotional content. Smooth/organic easings (`sine`, `power1`) feel contemplative and drifting. Aggressive deceleration (`power4.out`, `expo.out`) feels snappy and confident. Spring overshoot (`back.out`) feels bouncy and physical — but bouncy is a register, not an emphasis tool; reach for it only on explicitly-playful beats. The storyboard's mood description should guide which character fits — not a formula.
40
+ **Mood mapping:** Match easing character to the beat's emotional content. Smooth/organic easings (`sine`, `power1`) feel contemplative and drifting. Aggressive deceleration (`power4.out`, `expo.out`) feels snappy and confident. Spring overshoot (`back.out`) feels bouncy and physical — but bouncy is a register, not an emphasis tool; reach for it only when the brief's register is playful or physical. The video's register should guide which character fits — not a formula.
41
41
 
42
42
  ## Defaults
43
43
 
@@ -58,7 +58,7 @@ Setting defaults at timeline scope is preferred — it documents the motion lang
58
58
 
59
59
  ## Spring Eases (baked physics, seek-safe)
60
60
 
61
- The "iOS feel" is a **damped spring's velocity curve**, not a bounce: a fast launch into a long asymptotic settle. Well-made system animations are critically damped or close to it — they barely overshoot, or don't at all. `power3.out` / `expo.out` approximate that curve; when you want the exact one — or a _physical_ overshoot for the rare playful register — bake the spring's closed-form solution into a function ease.
61
+ The "iOS feel" is a **damped spring's velocity curve**, not a bounce: a fast launch into a long asymptotic settle. Well-made system animations are critically damped or close to it — they barely overshoot, or don't at all. `power3.out` / `expo.out` approximate that curve; when you want the exact one — or a _physical_ overshoot for a playful register — bake the spring's closed-form solution into a function ease.
62
62
 
63
63
  Why not a real-time spring library: an interactive spring is a stateful integrator (velocity accumulates frame to frame), which cannot be seeked deterministically — you'd have to simulate frames 0…N−1 to render frame N. The closed form below is a **pure function of progress** — no state, nothing to desync, seek-safe by construction. This is also why interaction-lib spring solvers are banned in compositions.
64
64
 
@@ -67,7 +67,7 @@ Why not a real-time spring library: an interactive spring is a stateful integrat
67
67
  // response ≈ seconds one oscillation would take (0.3–0.6 for entrances)
68
68
  // dampingFraction 1.0 = critically damped — smooth settle, NO overshoot (house default)
69
69
  // 0.80–0.85 ≈ the iOS system register — ~1–1.5% overshoot, felt not seen
70
- // 0.60–0.70 = explicitly playful — ~5–10% overshoot (rare; replaces back.out)
70
+ // 0.60–0.70 = playful register — ~5–10% overshoot (by choice; replaces back.out)
71
71
  function springEase({ response = 0.5, dampingFraction = 1 } = {}) {
72
72
  const w = (2 * Math.PI) / response; // undamped natural frequency
73
73
  const z = dampingFraction;
@@ -116,24 +116,24 @@ tl.fromTo(
116
116
  );
117
117
  ```
118
118
 
119
- | dampingFraction | overshoot | register |
120
- | ----------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
121
- | **1.0 (default)** | none (monotone) | The house settle — the exact curve `power3.out` approximates. Product / enterprise / serious tone. |
122
- | 0.80–0.85 | ~1–1.5% | "Alive, not bouncy" — the iOS system default register. The overshoot is felt, not seen. |
123
- | 0.60–0.70 | ~5–10% | Explicitly-playful ONLY (same rule as `back.out`, which this replaces — a spring's second-order settle reads physical where `back` reads cartoon). |
124
- | < 0.55 | > 12% | Don't. Cartoon-wobble territory. |
119
+ | dampingFraction | overshoot | register |
120
+ | ----------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
121
+ | **1.0 (default)** | none (monotone) | The house settle — the exact curve `power3.out` approximates. Product / enterprise / serious tone. |
122
+ | 0.80–0.85 | ~1–1.5% | "Alive, not bouncy" — the iOS system default register. The overshoot is felt, not seen. |
123
+ | 0.60–0.70 | ~5–10% | Playful register, by choice (same rule as `back.out`, which this replaces — a spring's second-order settle reads physical where `back` reads cartoon). |
124
+ | < 0.55 | > 12% | Don't. Cartoon-wobble territory. |
125
125
 
126
- | response | duration (ζ=1) | feel |
127
- | --------- | -------------- | ------------------------------------------------------------ |
128
- | 0.25–0.35 | 0.37–0.51s | tight snap — chips, small UI |
129
- | 0.35–0.50 | 0.51–0.74s | standard entrance |
130
- | 0.50–0.70 | 0.74–1.03s | weighted hero landing — check the `t ≤ 0.5s` visibility rule |
126
+ | response | duration (ζ=1) | feel |
127
+ | --------- | -------------- | ------------------------------------------------------------------------------------------------------------------- |
128
+ | 0.25–0.35 | 0.37–0.51s | tight snap — chips, small UI |
129
+ | 0.35–0.50 | 0.51–0.74s | standard entrance |
130
+ | 0.50–0.70 | 0.74–1.03s | weighted hero landing — when the shot opens on it, start it early so the subject is seen within about half a second |
131
131
 
132
132
  Craft notes:
133
133
 
134
134
  - **ζ=1 vs `power3.out`**: the true spring front-loads harder (~67% vs ~58% travelled at quarter-time) and settles on a longer asymptotic tail; max shape difference ~11%. That long tail is the "premium" read — use it when the settle IS the shot (a wordmark landing, a final lockup).
135
135
  - **At ζ<1, overshooting curves go on transforms only** — never on `opacity` (it would push past 1) or color. Split opacity onto its own `power2.out` tween at the same timeline position.
136
- - **Doctrine unchanged**: ζ below ~0.8 is still the rare, explicitly-playful exception (`rules/spring-pop-entrance.md`). The default of this section is ζ=1 — real spring physics is not a license for bounce.
136
+ - **Default unchanged**: ζ below ~0.8 is a register the brief chooses, never a default. The default of this section is ζ=1 — real spring physics is not a license for bounce.
137
137
 
138
138
  ## Stagger
139
139
 
@@ -56,13 +56,13 @@ For transforms, autoAlpha, clearProps, and SVG specifics see `./gsap-transforms-
56
56
 
57
57
  ## Animated properties
58
58
 
59
- Prefer these efficient targets when they preserve the recipe's behaviour:
59
+ Prefer these efficient targets when they achieve the intended motion:
60
60
 
61
61
  - **Compositor-cheap**: `opacity`, `x`, `y`, `scale`, `scaleX`, `scaleY`, `rotation`, `rotationX`, `rotationY`, `skewX`, `skewY`, `transformOrigin`
62
62
  - **Visual fills**: `color`, `backgroundColor`, `borderColor`, `borderRadius`
63
63
  - **CSS variables**: `"--hue": 180` etc.
64
64
  - **Media `volume`** (on `<audio>` / `<video>`): do not tween it for fades or ducking; use the `data-automation` volume lane (see `data-attributes.md`). A lane wins over a tween on the same element.
65
- - **DOM text `innerText`** (for numeric counters): tween it directly, e.g. `tl.to(el, { innerText: 100, snap: { innerText: 1 } })` — `snap` keeps it integer; the GSAP inspector recognizes it as a counter. Use a deterministic proxy value with `onUpdate` for locale formatting or suffix logic when the selected recipe needs it.
65
+ - **DOM text `innerText`** (for numeric counters): tween it directly, e.g. `tl.to(el, { innerText: 100, snap: { innerText: 1 } })` — `snap` keeps it integer; the GSAP inspector recognizes it as a counter. Use a deterministic proxy value with `onUpdate` for locale formatting or suffix logic when the design needs it.
66
66
 
67
67
  **Avoid** (use the transform alias instead):
68
68
 
@@ -80,7 +80,7 @@ Prefer these efficient targets when they preserve the recipe's behaviour:
80
80
  - `./gsap-timeline-and-labels.md` — timeline creation, position parameter (`+=`, `<`, `>`), labels, nesting, sub-comp `fromTo` preference, playback control.
81
81
  - `./gsap-easing-and-stagger.md` — easing families, stagger objects, function-based values, `gsap.matchMedia()`, `gsap.defaults()`.
82
82
  - `./gsap-transforms-and-perf.md` — transform aliases, autoAlpha, `quickTo`, `will-change`, performance rules.
83
- - The selected recipe defines effects and motion mechanisms; these API examples are not additional creative instructions.
83
+ - The video's plan defines effects and motion; these API examples are not additional creative instructions.
84
84
 
85
85
  ## Best Practices
86
86
 
@@ -1,8 +1,7 @@
1
1
  # GG runtime inputs and assets
2
2
 
3
- This is implementation support, not a creative workflow. The selected recipe
4
- controls choreography and permitted adaptations. Bind approved text, fonts,
5
- colours, logos and media without adding a second look-selection process.
3
+ This is implementation support, not a creative workflow. Bind approved text,
4
+ fonts, colours, logos and media without adding a second look-selection process.
6
5
 
7
6
  `hf` in these references is shorthand for the exact bundled launcher command
8
7
  in the system prompt; expand it, never run bare `hf` or `npx hyperframes`.
@@ -14,13 +13,13 @@ package installs, cloud rendering or publishing without explicit permission.
14
13
  - Keep original captures/uploads in `sources/`; use local `assets/` for the
15
14
  files consumed by the composition. Never overwrite originals or finished renders.
16
15
  - A reusable kit lives at `brand-kits/<slug>/Motion.md` in the Motion workspace.
17
- Keep it read-only for ordinary video work. Record the selected kit and permitted
18
- bindings in `frame.md`; preserve legacy briefs rather than duplicating plans.
19
- - The recipe defines fit/crop/in-point policies. Record approved choices. A
20
- different asset aspect ratio or title length does not authorize new choreography.
21
- - Root output duration is a static composition contract. If a permitted input
22
- changes duration, update the authored root explicitly; a runtime variable
23
- cannot silently change the compiled video length.
16
+ Keep it read-only for ordinary video work; preserve legacy briefs rather than
17
+ duplicating plans.
18
+ - A longer title or a different aspect ratio calls for a deliberate layout adjustment, not a silent
19
+ crop.
20
+ - Root output duration is a static composition contract. If an input changes
21
+ the duration, update the authored root explicitly; a runtime variable cannot
22
+ silently change the compiled video length.
24
23
 
25
24
  ## Existing helpers (only when needed)
26
25
 
@@ -37,16 +36,22 @@ Inspect helper help for less common operations; do not guess options. Fonts,
37
36
  Three.js and library assets remain available offline, but their existence does
38
37
  not require using them. Respect actual licenses and required brand typography.
39
38
 
39
+ `fonts.mjs add` returns `head`: a `<style>` block of `@font-face` rules with
40
+ paths from the project folder. Paste it into the composition `<head>`.
41
+ `hf check` only recognises fonts declared in the page, so linking
42
+ `assets/fonts/fonts.css` instead renders fine but is reported as missing fonts.
43
+
44
+ GSAP loads from the pinned CDN script in
45
+ [minimal-composition](minimal-composition.md). There is no local copy in the
46
+ bundle; do not search for one or copy one from another project.
47
+
40
48
  Shared music and SFX are at `../../assets/music/` and `../../assets/sfx/` relative
41
49
  to this document. Upstream metadata can retain historical `skills/brag/` paths;
42
50
  resolve its filenames under these shared asset roots, not the removed skill.
43
51
  Those provenance notes are not instructions to invoke an old workflow.
44
52
  Preserve credits, cue maps and SFX analysis. Copy only used
45
- assets into the video project. The selected recipe or user determines whether
53
+ assets into the video project. The plan or user determines whether
46
54
  sound belongs in the video; do not automatically add music or hits.
47
55
 
48
- Use `motion_check` once on the current render as specified by `video-qa`; it
49
- runs the media helpers and returns images for this agent to inspect. Do not
50
- repeat its checks as a separate checklist. Request permission before
51
- installing missing FFmpeg/browser software; a detector setup failure does not
52
- justify skipping validation. Never upload user files to resolve a local blocker.
56
+ Request permission before installing missing FFmpeg/browser software. Never
57
+ upload user files to resolve a local blocker.
@@ -1,6 +1,6 @@
1
1
  # lint, check, snapshot
2
2
 
3
- Motion's `motion_check` tool already runs `check`, including lint, runtime, layout and contrast, and returns rendered images. Do not run the commands below as additional delivery gates. Use them only for targeted debugging of a concrete failure. `snapshot` captures still frames and zoomed crops; `validate`, `inspect` and `layout` are deprecated because `check` covers them.
3
+ Motion does not run these as delivery gates. Use them only for targeted debugging of a concrete failure. `snapshot` captures still frames and zoomed crops; `validate`, `inspect` and `layout` are deprecated because `check` covers them.
4
4
 
5
5
  ## Discipline (motion-heavy work)
6
6
 
@@ -9,7 +9,7 @@ For a concrete problem during authoring or editing:
9
9
  - Use `lint` for a static-code failure or `check --snapshots` for runtime/layout evidence, not both by default.
10
10
  - Look at the returned images before changing the animation: a diagnostic must not become an alternative art direction.
11
11
  - Treat layout errors as defects unless a snapshot proves the layering is intentional, in which case mark it with `data-layout-allow-overflow` / `data-layout-allow-overlap` / `data-layout-allow-occlusion` / `data-layout-allow-caption-zone` (caption band only).
12
- - Existing meaningful motion assertions may remain, but GG does not require a new `*.motion.json` sidecar for every video. Use rendered-pixel checks and the `video-qa` evidence process for liveness, especially for canvas/WebGL. No detector or screenshot proves playback was watched.
12
+ - Existing meaningful motion assertions may remain, but EZ does not require a new `*.motion.json` sidecar for every video. Use stills of the render for liveness, especially for canvas/WebGL. No detector or screenshot proves playback was watched.
13
13
 
14
14
  ## lint
15
15
 
@@ -68,7 +68,7 @@ hf check --frame-check # media (img/svg/video/canvas) out-of-frame detection
68
68
 
69
69
  `--caption-zone` takes fractional band geometry (`x0/y0/x1/y1` required, 0-1 fractions of the composition's own canvas, portrait included) with optional `severity` and comma-separated `seek` fractions; it flags a text element's DOM box (`getBoundingClientRect`) that overlaps the band. Waive intentional lower-third copy with `data-layout-allow-caption-zone` on the element or its nearest wrapper (see Escape hatches). `--frame-check` reports media elements breaching the canvas beyond `max(120px, 6% of the min canvas dimension)`.
70
70
 
71
- **Fixing contrast errors** — thresholds are 4.5:1 for normal text, 3:1 for large text (24px+, or 19px+ bold). The finding's `suggestedColor` already picks the nearest compliant color in the right direction (brighten on dark backgrounds, darken on light); apply an allowed correction, or resolve a conflict with locked source/brand colours before changing them. Recheck the changed output through `motion_check`; do not duplicate the full diagnostic checklist.
71
+ **Fixing contrast errors** — thresholds are 4.5:1 for normal text, 3:1 for large text (24px+, or 19px+ bold). The finding's `suggestedColor` already picks the nearest compliant color in the right direction (brighten on dark backgrounds, darken on light); apply an allowed correction, or resolve a conflict with locked source/brand colours before changing them. Look at a still of the changed moment; do not run the full diagnostic checklist.
72
72
 
73
73
  ## Motion verification (`*.motion.json` sidecar)
74
74
 
@@ -67,3 +67,9 @@ What the runtime actually requires:
67
67
  Everything else in the skeleton is ordinary HTML and CSS: the `#root` box, `.clip` positioning, and fonts are yours to choose.
68
68
 
69
69
  This pattern is **standalone** (top-level `index.html`) — no `<template>` wrapper around the root. For sub-compositions (files loaded by `data-composition-src`), see `sub-compositions.md`.
70
+
71
+ ## Vertical (9:16)
72
+
73
+ For phone-first video, set the viewport meta to `width=1080, height=1920`, give the root `data-width="1080"` and `data-height="1920"`, and render with the matching size (`--resolution portrait`). Everything else stays the same.
74
+
75
+ Size type against the frame's width, not its height: a 96 px headline that suits a 1920 px-wide frame takes over half the width of a 1080 px one, so check that the longest word fits. When the video will play in a feed (Instagram, TikTok, YouTube Shorts), keep words out from under the apps' own bar, caption and buttons: on 1080×1920, the top 138 px, the bottom 422 px and the right 179 px from y 840 down.
@@ -57,7 +57,7 @@ Failure modes:
57
57
 
58
58
  | Code | Meaning |
59
59
  | -------------------------- | -------------------------------------------------------------------------- |
60
- | `preview-not-running` | Start Studio first with `hf preview --background`. |
60
+ | `preview-not-running` | Start Studio first with `hf preview --background`. |
61
61
  | `ambiguous-preview-server` | Multiple matching Studio servers are open; rerun with one listed `--port`. |
62
62
  | `preview-port-mismatch` | The requested `--port` is not one of the matching Studio servers. |
63
63
  | `no-selection` | Studio is open, but the user has not selected an element yet. |
@@ -99,7 +99,7 @@ Validation runs before any server boots, so an invalid value exits cleanly witho
99
99
 
100
100
  ## render
101
101
 
102
- > A clear video request authorizes a new, versioned local render. Preview is available when useful, not a mandatory approval checkpoint. Ask only for unresolved inputs, material choices or permission to overwrite an existing export; check the result once through `motion_check`.
102
+ > A clear video request authorizes a new, versioned local render. Preview is available when useful, not a mandatory approval checkpoint. Ask only for unresolved inputs, material choices or permission to overwrite an existing export. The final render screens itself for harmful flashing.
103
103
 
104
104
  ```bash
105
105
  hf render # standard MP4 from cwd
@@ -153,4 +153,4 @@ hf render --docker # byte-identical
153
153
  Keep renders and diagnostics local. Feedback submission, issue filing, publishing
154
154
  and cloud rendering are not automatic completion steps. They require explicit
155
155
  user authorization; do not send source files, private assets or logs upstream.
156
- Use GG's `reveal.mjs` to select the delivered local file.
156
+ Use EZ's `reveal.mjs` to select the delivered local file.
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: app-walkthrough
3
+ description: Job skill for showing how an app or product is used, step by step, on rebuilt real screens. Adds walkthrough questions, the screen-rebuild method, moves and pitfalls. Load once, before asking.
4
+ ---
5
+
6
+ # App walkthrough
7
+
8
+ A walkthrough is the product in use: open it, do the task, get the
9
+ result. Build it as the `motion` skill describes; this page adds what is
10
+ specific to walkthroughs.
11
+
12
+ ## Ask (on the motion skill's single card)
13
+
14
+ - "Which task should the video walk through?" Offer the two or three tasks the
15
+ prompt or screenshots suggest, plus "Let EZ Motion choose".
16
+ - "Where will people mostly watch this?" (from the `motion` skill).
17
+ - "Should it have music?" (from the `motion` skill).
18
+ - "Which idea should we go with?" Pitches below, recommended marked, plus "Let
19
+ EZ Motion choose".
20
+
21
+ Without screenshots, end with one plain line: "Send me a screenshot of each
22
+ step of that task, in order. Phone photos of the screen are fine." Do not ask
23
+ for a shot list.
24
+
25
+ ## Rebuild the screens
26
+
27
+ Rebuild each screen as HTML at the screenshot's own size, with its states
28
+ scripted, its text big enough to read, one close-up per step and a cursor that
29
+ presses. Start from the `screen-replica-steps` piece. Hide account names,
30
+ emails and anything private. Data on screen comes from
31
+ their screenshots or files, never invented.
32
+
33
+ ## Ideas that suit walkthroughs
34
+
35
+ - **Follow the hand.** One continuous camera that rides the cursor from step to
36
+ step; each click opens the next framing.
37
+ - **The request becomes the result.** The thing the user types or picks grows
38
+ into what the app gives back.
39
+ - **The app's own transition.** Use the app's real sheet, drawer or page
40
+ animation as the handoff between steps.
41
+ - **Before the tap, after the tap.** Each step is a held "before" frame, one
42
+ press, and the change it causes.
43
+
44
+ ## Beats that work
45
+
46
+ - Open on the moment that matters most (the result), then rewind to how it is
47
+ done, or open straight on the first step with the cursor already moving.
48
+ - One step per beat, with a close-up on the control being used.
49
+ - Hold still on the result long enough to read it. That is the rest.
50
+ - End on the app's name or icon and where to get it.
51
+
52
+ ## Moves
53
+
54
+ `kit.cursorPath` with press and release; `kit.camera` following the cursor;
55
+ `kit.typewrite` for typed input; `kit.tick` for completed steps;
56
+ `kit.reshape` from the pressed control into the result. Pieces:
57
+ `screen-replica-steps`, `request-to-result`, `cursor-click`, `phone-frame`,
58
+ `browser-window`, `camera-rig`.
59
+
60
+ ## Pitfalls
61
+
62
+ - Screenshots placed flat and slid around. Rebuild them.
63
+ - Whole screens shown small: text unreadable at phone size.
64
+ - The cursor teleporting, or changes happening without a click.
65
+ - Steps of equal length with no rest on the result.
66
+ - Made-up names, numbers or results.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: before-after
3
+ description: Job skill for a before-and-after video, showing life without the product, then with it. Adds before/after questions, idea patterns, moves and pitfalls. Load once, before asking.
4
+ ---
5
+
6
+ # Before and after
7
+
8
+ The viewer should feel the difference, not read it. Build it as the `motion`
9
+ skill describes; this page adds what is specific to comparisons.
10
+
11
+ ## Ask (on the motion skill's single card)
12
+
13
+ - "What's the annoying part of life without it?" Offer two or three guesses
14
+ from the prompt, plus "Let EZ Motion choose".
15
+ - "Where will people mostly watch this?" (from the `motion` skill).
16
+ - "Should it have music?" (from the `motion` skill).
17
+ - "Which idea should we go with?" Pitches below, plus "Let EZ Motion choose".
18
+
19
+ ## Ideas that suit comparisons
20
+
21
+ - **The same task, twice, side by side.** Both halves start together; the
22
+ "before" side keeps getting interrupted while the "after" side simply
23
+ finishes. Then the losing half falls away.
24
+ - **One drawing, broken and whole.** A shape or line is drawn twice: broken up
25
+ by the problem on one side, unbroken on the other. The whole one becomes the
26
+ logo.
27
+ - **Rewind.** Play the messy version, rewind it in one motion, and play it
28
+ again with the product.
29
+
30
+ The comparison must use one measure the viewer can see (time, steps, mess),
31
+ shown on both sides in the same way.
32
+
33
+ ## Beats that work
34
+
35
+ - Set up both sides in one frame so the comparison is fair.
36
+ - Let the problem build, quickening, on the "before" side.
37
+ - A held breath when the "after" side finishes: a real, still rest.
38
+ - The winning side's result carries into the name.
39
+
40
+ ## Moves
41
+
42
+ `kit.impact` for interruptions; `kit.camera` with a local shake on one side
43
+ only; `kit.openFrom` from the finished result; `kit.converge` into the logo.
44
+ Pieces: `before-after-split`, `open-from-subject`, `gather-to-logo`,
45
+ `camera-rig`.
46
+
47
+ ## Pitfalls
48
+
49
+ - Two separate scenes, before then after, with a cut between. Show them
50
+ together, or carry one into the other.
51
+ - An unfair comparison: different tasks or different measures on each side.
52
+ - Captions that state the difference instead of showing it.
53
+ - Invented statistics about the improvement.