dsh-hyperframes 0.3.2 → 0.4.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 (375) hide show
  1. package/README.en.md +4 -3
  2. package/README.md +5 -4
  3. package/lib/index.d.ts +1 -1
  4. package/lib/index.js +1 -0
  5. package/package.json +2 -2
  6. package/skills/embedded-captions/SKILL.md +28 -3
  7. package/skills/embedded-captions/references/aesthetic-principles.md +2 -3
  8. package/skills/embedded-captions/references/rail.md +1 -1
  9. package/skills/embedded-captions/scripts/check-occlusion.cjs +4 -1
  10. package/skills/embedded-captions/scripts/check-overflow.cjs +1 -0
  11. package/skills/embedded-captions/scripts/check-rail-climax.cjs +5 -1
  12. package/skills/embedded-captions/scripts/fixtures/heroless/theme.json +11 -0
  13. package/skills/embedded-captions/scripts/hf-cli.cjs +33 -0
  14. package/skills/embedded-captions/scripts/make-theme.cjs +95 -57
  15. package/skills/embedded-captions/scripts/make-theme.test.mjs +131 -0
  16. package/skills/embedded-captions/scripts/matte.cjs +1 -13
  17. package/skills/embedded-captions/scripts/measure-layout.cjs +2 -1
  18. package/skills/embedded-captions/scripts/preview-frames.cjs +39 -11
  19. package/skills/embedded-captions/scripts/preview-frames.test.mjs +24 -0
  20. package/skills/embedded-captions/scripts/render-and-composite.sh +8 -52
  21. package/skills/embedded-captions/scripts/safe-zones.cjs +4 -1
  22. package/skills/embedded-captions/scripts/transcribe.cjs +5 -14
  23. package/skills/embedded-captions/scripts/transcribe.test.mjs +41 -0
  24. package/skills/faceless-explainer/SKILL.md +20 -16
  25. package/skills/faceless-explainer/references/story-design.md +1 -1
  26. package/skills/faceless-explainer/scripts/assemble-index.mjs +6 -4
  27. package/skills/faceless-explainer/scripts/assemble-index.test.mjs +57 -2
  28. package/skills/faceless-explainer/scripts/audio.mjs +2 -0
  29. package/skills/faceless-explainer/scripts/build-frame.mjs +6 -3
  30. package/skills/faceless-explainer/scripts/captions.mjs +7 -4
  31. package/skills/faceless-explainer/scripts/frame-packets.mjs +4 -4
  32. package/skills/faceless-explainer/scripts/lib/bgm-volume.mjs +4 -0
  33. package/skills/faceless-explainer/scripts/lib/captured-fonts.mjs +58 -0
  34. package/skills/{hyperframes-core → faceless-explainer}/scripts/lib/frame-packets-core.mjs +5 -23
  35. package/skills/faceless-explainer/scripts/lib/storyboard.mjs +1 -1
  36. package/skills/faceless-explainer/scripts/lib/transitions.json +3 -3
  37. package/skills/faceless-explainer/scripts/transitions.mjs +1 -0
  38. package/skills/faceless-explainer/scripts/transitions.test.mjs +2 -0
  39. package/skills/faceless-explainer/sub-agents/frame-worker.md +1 -1
  40. package/skills/figma/SKILL.md +2 -0
  41. package/skills/general-video/SKILL.md +13 -11
  42. package/skills/general-video/scripts/frame-packets.mjs +4 -4
  43. package/skills/general-video/scripts/lib/frame-packets-core.mjs +194 -0
  44. package/skills/general-video/sub-agents/frame-worker.md +1 -1
  45. package/skills/hyperframes/SKILL.md +40 -30
  46. package/skills/{hyperframes-core → hyperframes}/references/brief-contract.md +15 -15
  47. package/skills/{hyperframes-core → hyperframes}/references/brief-format.md +8 -8
  48. package/skills/hyperframes/references/capability-menu.md +2 -2
  49. package/skills/{hyperframes-core → hyperframes}/references/frame-worker-core.md +1 -1
  50. package/skills/hyperframes/references/intent-interview.md +16 -16
  51. package/skills/hyperframes/references/plugin-installation.md +43 -0
  52. package/skills/{hyperframes-core → hyperframes}/references/production-loop.md +11 -11
  53. package/skills/hyperframes/references/review-loop.md +37 -0
  54. package/skills/hyperframes/references/route-briefs.md +1 -1
  55. package/skills/hyperframes/references/routes/motion-graphics.md +1 -1
  56. package/skills/{hyperframes-core → hyperframes}/references/script-format.md +3 -3
  57. package/skills/hyperframes/references/skill-lifecycle.md +2 -0
  58. package/skills/{hyperframes-core → hyperframes}/references/storyboard-format.md +3 -34
  59. package/skills/hyperframes/scripts/lib/frame-packets-core.mjs +194 -0
  60. package/skills/hyperframes/scripts/plugin-cli.mjs +88 -0
  61. package/skills/hyperframes/scripts/plugin-cli.test.mjs +117 -0
  62. package/skills/hyperframes-animation/SKILL.md +5 -1
  63. package/skills/hyperframes-animation/adapters/gsap.md +1 -1
  64. package/skills/hyperframes-animation/adapters/lottie.md +15 -2
  65. package/skills/hyperframes-animation/adapters/three.md +14 -0
  66. package/skills/hyperframes-animation/blueprints/titlecard-reveal.md +1 -1
  67. package/skills/hyperframes-animation/references/motion-blur.md +133 -0
  68. package/skills/hyperframes-animation/rules/cursor-click-ripple.md +1 -1
  69. package/skills/hyperframes-animation/rules/dynamic-content-sequencing.md +1 -1
  70. package/skills/hyperframes-animation/rules/hacker-flip-3d.md +1 -1
  71. package/skills/hyperframes-animation/rules/kinetic-beat-slam.md +2 -2
  72. package/skills/hyperframes-animation/rules/motion-blur-streak.md +1 -1
  73. package/skills/hyperframes-animation/rules/vertical-spring-ticker.md +1 -1
  74. package/skills/hyperframes-animation/scripts/package-loader.mjs +47 -16
  75. package/skills/hyperframes-animation/scripts/package-loader.test.mjs +52 -0
  76. package/skills/hyperframes-animation/techniques.md +1 -1
  77. package/skills/hyperframes-animation/transitions/TRANSITION-REGISTRY.md +3 -3
  78. package/skills/hyperframes-animation/transitions/css-push.md +4 -4
  79. package/skills/hyperframes-audio/SKILL.md +30 -22
  80. package/skills/hyperframes-audio/scripts/carve.mjs +6 -3
  81. package/skills/hyperframes-audio/scripts/carve.test.mjs +16 -1
  82. package/skills/hyperframes-cli/SKILL.md +44 -35
  83. package/skills/hyperframes-cli/references/init-and-scaffold.md +8 -6
  84. package/skills/hyperframes-cli/references/lint-validate-inspect.md +3 -3
  85. package/skills/hyperframes-cli/references/preview-render.md +35 -32
  86. package/skills/hyperframes-cli/references/upgrade-info-misc.md +50 -1
  87. package/skills/hyperframes-core/SKILL.md +30 -24
  88. package/skills/hyperframes-core/references/composition-patterns.md +3 -42
  89. package/skills/hyperframes-core/references/creator-editing-recipes.md +131 -7
  90. package/skills/hyperframes-core/references/data-attributes.md +11 -11
  91. package/skills/hyperframes-core/references/determinism-rules.md +2 -19
  92. package/skills/hyperframes-core/references/full-screen-motion.md +0 -9
  93. package/skills/hyperframes-core/references/minimal-composition.md +2 -2
  94. package/skills/hyperframes-core/references/sub-compositions.md +3 -66
  95. package/skills/hyperframes-core/references/tailwind.md +1 -20
  96. package/skills/hyperframes-core/references/tracks-and-clips.md +2 -6
  97. package/skills/hyperframes-core/references/variables-and-media.md +3 -3
  98. package/skills/hyperframes-creative/SKILL.md +2 -0
  99. package/skills/hyperframes-creative/references/house-style.md +15 -15
  100. package/skills/hyperframes-creative/references/story-spine.md +3 -1
  101. package/skills/hyperframes-creative/references/storyboard-recipe.md +57 -0
  102. package/skills/hyperframes-creative/references/typography.md +1 -1
  103. package/skills/hyperframes-creative/scripts/package-loader.mjs +47 -16
  104. package/skills/hyperframes-creative/scripts/package-loader.test.mjs +52 -0
  105. package/skills/hyperframes-keyframes/SKILL.md +4 -2
  106. package/skills/hyperframes-registry/SKILL.md +3 -1
  107. package/skills/hyperframes-registry/references/contributing.md +8 -2
  108. package/skills/hyperframes-registry/references/discovery.md +20 -34
  109. package/skills/hyperframes-studio/SKILL.md +77 -0
  110. package/skills/media-use/SKILL.md +14 -12
  111. package/skills/media-use/audio/references/captions/authoring.md +4 -0
  112. package/skills/media-use/audio/references/remove-background.md +1 -1
  113. package/skills/media-use/audio/references/tts-to-captions.md +11 -2
  114. package/skills/media-use/audio/references/tts.md +84 -6
  115. package/skills/media-use/audio/scripts/audio.mjs +15 -6
  116. package/skills/media-use/audio/scripts/gemini-pipeline.test.mjs +113 -0
  117. package/skills/media-use/audio/scripts/lib/audio-meta.mjs +39 -0
  118. package/skills/media-use/audio/scripts/lib/audio-meta.test.mjs +136 -0
  119. package/skills/media-use/audio/scripts/lib/bgm-volume.mjs +4 -0
  120. package/skills/media-use/audio/scripts/lib/bgm.mjs +2 -6
  121. package/skills/media-use/audio/scripts/lib/gemini-auth.mjs +43 -0
  122. package/skills/media-use/audio/scripts/lib/gemini-auth.py +52 -0
  123. package/skills/media-use/audio/scripts/lib/gemini-auth.test.mjs +86 -0
  124. package/skills/media-use/audio/scripts/lib/gemini-auth_test.py +90 -0
  125. package/skills/media-use/audio/scripts/lib/gemini-tts.mjs +122 -0
  126. package/skills/media-use/audio/scripts/lib/gemini-tts.test.mjs +243 -0
  127. package/skills/media-use/audio/scripts/lib/heygen.mjs +2 -1
  128. package/skills/media-use/audio/scripts/lib/tts.mjs +15 -3
  129. package/skills/media-use/audio/scripts/wait-bgm.mjs +8 -4
  130. package/skills/media-use/audio/scripts/wait-bgm.test.mjs +65 -0
  131. package/skills/media-use/references/audio.md +3 -2
  132. package/skills/media-use/references/grading.md +7 -7
  133. package/skills/media-use/references/media-treatment-recipes.md +1 -1
  134. package/skills/media-use/references/memory.md +2 -2
  135. package/skills/media-use/references/meta.md +2 -2
  136. package/skills/media-use/references/operations.md +15 -13
  137. package/skills/media-use/references/resolve.md +22 -11
  138. package/skills/media-use/references/setup-providers.md +11 -11
  139. package/skills/media-use/scripts/audio-duck.mjs +19 -27
  140. package/skills/media-use/scripts/compatibility.test.mjs +96 -0
  141. package/skills/media-use/scripts/lib/config-lock.mjs +45 -0
  142. package/skills/media-use/scripts/lib/duck.mjs +16 -10
  143. package/skills/media-use/scripts/lib/media-fetch.mjs +85 -0
  144. package/skills/media-use/scripts/lib/media-home.mjs +20 -0
  145. package/skills/media-use/scripts/lib/npx-sync.mjs +28 -2
  146. package/skills/media-use/scripts/lib/prefs-store.mjs +2 -2
  147. package/skills/media-use/scripts/lib/recipe-store.mjs +2 -2
  148. package/skills/media-use/scripts/lib/telemetry.mjs +29 -41
  149. package/skills/media-use/scripts/lib/transcriptCutFade.mjs +21 -0
  150. package/skills/media-use/scripts/prefs.mjs +1 -1
  151. package/skills/media-use/scripts/recipe.mjs +1 -1
  152. package/skills/media-use/scripts/resolve-plugin.test.mjs +62 -0
  153. package/skills/media-use/scripts/resolve.mjs +27 -1267
  154. package/skills/media-use/scripts/transcribe.mjs +39 -25
  155. package/skills/media-use/scripts/transcribe.test.mjs +112 -0
  156. package/skills/media-use/scripts/transcript-cut.mjs +39 -8
  157. package/skills/media-use/scripts/transcript-cut.test.mjs +117 -0
  158. package/skills/motion-graphics/SKILL.md +3 -1
  159. package/skills/motion-graphics/agents/builder.md +1 -0
  160. package/skills/motion-graphics/agents/director.md +2 -1
  161. package/skills/motion-graphics/catalog-map.md +25 -13
  162. package/skills/motion-graphics/categories/charts/module.md +2 -1
  163. package/skills/motion-graphics/categories/lower-thirds/module.md +4 -0
  164. package/skills/motion-graphics/categories/news/module.md +1 -1
  165. package/skills/motion-graphics/references/motion-vocabulary.md +4 -0
  166. package/skills/music-to-video/SKILL.md +8 -6
  167. package/skills/music-to-video/references/montage.md +3 -6
  168. package/skills/music-to-video/references/motion-primitives/3d-card-flip/index.html +10 -111
  169. package/skills/music-to-video/references/motion-primitives/3d-card-flip/scene.html +119 -0
  170. package/skills/music-to-video/references/motion-primitives/bg-flow-field/index.html +11 -284
  171. package/skills/music-to-video/references/motion-primitives/bg-flow-field/scene.html +294 -0
  172. package/skills/music-to-video/references/motion-primitives/binary-decrypt/index.html +10 -76
  173. package/skills/music-to-video/references/motion-primitives/binary-decrypt/scene.html +85 -0
  174. package/skills/music-to-video/references/motion-primitives/blur-resolve/index.html +10 -52
  175. package/skills/music-to-video/references/motion-primitives/blur-resolve/scene.html +60 -0
  176. package/skills/music-to-video/references/motion-primitives/braam-punch/index.html +10 -92
  177. package/skills/music-to-video/references/motion-primitives/braam-punch/scene.html +100 -0
  178. package/skills/music-to-video/references/motion-primitives/chromatic-split/index.html +10 -103
  179. package/skills/music-to-video/references/motion-primitives/chromatic-split/scene.html +111 -0
  180. package/skills/music-to-video/references/motion-primitives/chrome-sweep/index.html +10 -60
  181. package/skills/music-to-video/references/motion-primitives/chrome-sweep/scene.html +68 -0
  182. package/skills/music-to-video/references/motion-primitives/counting-punch/index.html +10 -110
  183. package/skills/music-to-video/references/motion-primitives/counting-punch/scene.html +119 -0
  184. package/skills/music-to-video/references/motion-primitives/crash-zoom-in/index.html +10 -112
  185. package/skills/music-to-video/references/motion-primitives/crash-zoom-in/scene.html +120 -0
  186. package/skills/music-to-video/references/motion-primitives/datamosh-smear/index.html +10 -121
  187. package/skills/music-to-video/references/motion-primitives/datamosh-smear/scene.html +131 -0
  188. package/skills/music-to-video/references/motion-primitives/directional-fill/index.html +10 -90
  189. package/skills/music-to-video/references/motion-primitives/directional-fill/scene.html +103 -0
  190. package/skills/music-to-video/references/motion-primitives/dolly-zoom/index.html +10 -94
  191. package/skills/music-to-video/references/motion-primitives/dolly-zoom/scene.html +102 -0
  192. package/skills/music-to-video/references/motion-primitives/electric-arc/index.html +10 -100
  193. package/skills/music-to-video/references/motion-primitives/electric-arc/scene.html +105 -0
  194. package/skills/music-to-video/references/motion-primitives/flash-cut/index.html +10 -89
  195. package/skills/music-to-video/references/motion-primitives/flash-cut/scene.html +97 -0
  196. package/skills/music-to-video/references/motion-primitives/gooey-metaball/index.html +10 -197
  197. package/skills/music-to-video/references/motion-primitives/gooey-metaball/scene.html +206 -0
  198. package/skills/music-to-video/references/motion-primitives/hard-cut/index.html +10 -74
  199. package/skills/music-to-video/references/motion-primitives/hard-cut/scene.html +82 -0
  200. package/skills/music-to-video/references/motion-primitives/hypercut-whip/index.html +10 -36
  201. package/skills/music-to-video/references/motion-primitives/hypercut-whip/scene.html +44 -0
  202. package/skills/music-to-video/references/motion-primitives/iris-open/index.html +10 -61
  203. package/skills/music-to-video/references/motion-primitives/iris-open/scene.html +69 -0
  204. package/skills/music-to-video/references/motion-primitives/kinetic-letter-in/index.html +10 -55
  205. package/skills/music-to-video/references/motion-primitives/kinetic-letter-in/scene.html +64 -0
  206. package/skills/music-to-video/references/motion-primitives/liquid-morph/index.html +10 -88
  207. package/skills/music-to-video/references/motion-primitives/liquid-morph/scene.html +96 -0
  208. package/skills/music-to-video/references/motion-primitives/mask-reveal/index.html +10 -66
  209. package/skills/music-to-video/references/motion-primitives/mask-reveal/scene.html +74 -0
  210. package/skills/music-to-video/references/motion-primitives/mosaic-pack/index.html +10 -81
  211. package/skills/music-to-video/references/motion-primitives/mosaic-pack/scene.html +89 -0
  212. package/skills/music-to-video/references/motion-primitives/neon-flicker/index.html +10 -65
  213. package/skills/music-to-video/references/motion-primitives/neon-flicker/scene.html +73 -0
  214. package/skills/music-to-video/references/motion-primitives/outline-to-fill/index.html +10 -74
  215. package/skills/music-to-video/references/motion-primitives/outline-to-fill/scene.html +82 -0
  216. package/skills/music-to-video/references/motion-primitives/palette-flip/index.html +10 -89
  217. package/skills/music-to-video/references/motion-primitives/palette-flip/scene.html +97 -0
  218. package/skills/music-to-video/references/motion-primitives/particle-burst/index.html +10 -98
  219. package/skills/music-to-video/references/motion-primitives/particle-burst/scene.html +106 -0
  220. package/skills/music-to-video/references/motion-primitives/pixel-dissolve/index.html +10 -78
  221. package/skills/music-to-video/references/motion-primitives/pixel-dissolve/scene.html +86 -0
  222. package/skills/music-to-video/references/motion-primitives/radial-burst-lines/index.html +10 -117
  223. package/skills/music-to-video/references/motion-primitives/radial-burst-lines/scene.html +130 -0
  224. package/skills/music-to-video/references/motion-primitives/screen-shake/index.html +10 -70
  225. package/skills/music-to-video/references/motion-primitives/screen-shake/scene.html +78 -0
  226. package/skills/music-to-video/references/motion-primitives/slot-machine-reveal/index.html +10 -87
  227. package/skills/music-to-video/references/motion-primitives/slot-machine-reveal/scene.html +100 -0
  228. package/skills/music-to-video/references/motion-primitives/spotlight-sweep/index.html +10 -94
  229. package/skills/music-to-video/references/motion-primitives/spotlight-sweep/scene.html +102 -0
  230. package/skills/music-to-video/references/motion-primitives/staggered-exit/index.html +10 -74
  231. package/skills/music-to-video/references/motion-primitives/staggered-exit/scene.html +82 -0
  232. package/skills/music-to-video/references/motion-primitives/text-spectral-rays/index.html +11 -271
  233. package/skills/music-to-video/references/motion-primitives/text-spectral-rays/scene.html +280 -0
  234. package/skills/music-to-video/references/motion-primitives/text-wave-distort/index.html +10 -92
  235. package/skills/music-to-video/references/motion-primitives/text-wave-distort/scene.html +106 -0
  236. package/skills/music-to-video/references/motion-primitives/tile-mosaic/index.html +10 -101
  237. package/skills/music-to-video/references/motion-primitives/tile-mosaic/scene.html +109 -0
  238. package/skills/music-to-video/references/motion-primitives/typewriter-reveal/index.html +10 -79
  239. package/skills/music-to-video/references/motion-primitives/typewriter-reveal/scene.html +91 -0
  240. package/skills/music-to-video/references/motion-primitives/word-grid-burst/index.html +10 -83
  241. package/skills/music-to-video/references/motion-primitives/word-grid-burst/scene.html +96 -0
  242. package/skills/music-to-video/references/planning.md +2 -2
  243. package/skills/music-to-video/scripts/lib/storyboard.mjs +1 -1
  244. package/skills/music-to-video/sub-agents/frame-worker.md +2 -2
  245. package/skills/pr-to-video/SKILL.md +20 -16
  246. package/skills/pr-to-video/references/code-vocabulary.md +14 -12
  247. package/skills/pr-to-video/references/story-design.md +1 -1
  248. package/skills/pr-to-video/scripts/assemble-index.mjs +6 -4
  249. package/skills/pr-to-video/scripts/assemble-index.test.mjs +57 -2
  250. package/skills/pr-to-video/scripts/audio.mjs +2 -0
  251. package/skills/pr-to-video/scripts/build-frame.mjs +6 -3
  252. package/skills/pr-to-video/scripts/captions.mjs +7 -4
  253. package/skills/pr-to-video/scripts/captions.test.mjs +41 -0
  254. package/skills/pr-to-video/scripts/frame-packets.mjs +4 -4
  255. package/skills/pr-to-video/scripts/lib/bgm-volume.mjs +4 -0
  256. package/skills/pr-to-video/scripts/lib/captured-fonts.mjs +58 -0
  257. package/skills/pr-to-video/scripts/lib/frame-packets-core.mjs +194 -0
  258. package/skills/pr-to-video/scripts/lib/storyboard.mjs +1 -1
  259. package/skills/pr-to-video/scripts/lib/transitions.json +3 -3
  260. package/skills/pr-to-video/scripts/transitions.mjs +7 -5
  261. package/skills/pr-to-video/sub-agents/frame-worker.md +1 -1
  262. package/skills/product-launch-video/SKILL.md +20 -16
  263. package/skills/product-launch-video/references/story-design.md +1 -1
  264. package/skills/product-launch-video/scripts/assemble-index.mjs +6 -4
  265. package/skills/product-launch-video/scripts/assemble-index.test.mjs +57 -2
  266. package/skills/product-launch-video/scripts/audio.mjs +2 -0
  267. package/skills/product-launch-video/scripts/audio.test.mjs +16 -0
  268. package/skills/product-launch-video/scripts/build-frame-subsets.test.mjs +152 -0
  269. package/skills/product-launch-video/scripts/build-frame.mjs +6 -3
  270. package/skills/product-launch-video/scripts/captions.mjs +7 -4
  271. package/skills/product-launch-video/scripts/frame-packets.mjs +4 -4
  272. package/skills/product-launch-video/scripts/lib/bgm-volume.mjs +4 -0
  273. package/skills/product-launch-video/scripts/lib/captured-fonts.mjs +58 -0
  274. package/skills/product-launch-video/scripts/lib/frame-packets-core.mjs +194 -0
  275. package/skills/product-launch-video/scripts/lib/storyboard.mjs +1 -1
  276. package/skills/product-launch-video/scripts/lib/transitions.json +3 -3
  277. package/skills/product-launch-video/scripts/transitions.mjs +7 -5
  278. package/skills/product-launch-video/scripts/transitions.test.mjs +68 -0
  279. package/skills/product-launch-video/sub-agents/frame-worker.md +1 -1
  280. package/skills/remotion-to-hyperframes/SKILL.md +7 -4
  281. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/expected.json +5 -5
  282. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/compositions/title.html +31 -0
  283. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/index.html +10 -25
  284. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/README.md +8 -8
  285. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/expected.json +9 -9
  286. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-1.html +35 -0
  287. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-2.html +35 -0
  288. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-3.html +36 -0
  289. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/index.html +28 -71
  290. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/expected.json +3 -3
  291. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-1.html +52 -0
  292. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-2.html +99 -0
  293. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-3.html +55 -0
  294. package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/index.html +13 -212
  295. package/skills/remotion-to-hyperframes/references/api-map.md +16 -16
  296. package/skills/remotion-to-hyperframes/references/limitations.md +7 -7
  297. package/skills/remotion-to-hyperframes/references/lottie.md +5 -7
  298. package/skills/remotion-to-hyperframes/references/media.md +3 -3
  299. package/skills/remotion-to-hyperframes/references/parameters.md +5 -0
  300. package/skills/remotion-to-hyperframes/references/sequencing.md +71 -18
  301. package/skills/slideshow/SKILL.md +4 -1
  302. package/skills/slideshow/references/standalone-harness.md +0 -3
  303. package/skills/talking-head-recut/SKILL.md +10 -1
  304. package/skills/hyperframes-core/references/review-loop.md +0 -41
  305. package/skills/media-use/scripts/lib/adopt.mjs +0 -128
  306. package/skills/media-use/scripts/lib/adopt.test.mjs +0 -95
  307. package/skills/media-use/scripts/lib/bgm-provider.mjs +0 -20
  308. package/skills/media-use/scripts/lib/brand-provider.mjs +0 -59
  309. package/skills/media-use/scripts/lib/bundled-sfx-provider.mjs +0 -108
  310. package/skills/media-use/scripts/lib/bundled-sfx-provider.test.mjs +0 -85
  311. package/skills/media-use/scripts/lib/cache.mjs +0 -150
  312. package/skills/media-use/scripts/lib/candidates.mjs +0 -91
  313. package/skills/media-use/scripts/lib/candidates.test.mjs +0 -155
  314. package/skills/media-use/scripts/lib/codex-provider.mjs +0 -161
  315. package/skills/media-use/scripts/lib/codex-provider.test.mjs +0 -34
  316. package/skills/media-use/scripts/lib/coverage.test.mjs +0 -117
  317. package/skills/media-use/scripts/lib/cube-build.mjs +0 -181
  318. package/skills/media-use/scripts/lib/cube-build.test.mjs +0 -80
  319. package/skills/media-use/scripts/lib/cube-validate.mjs +0 -198
  320. package/skills/media-use/scripts/lib/cube-validate.test.mjs +0 -125
  321. package/skills/media-use/scripts/lib/cutlist.test.mjs +0 -148
  322. package/skills/media-use/scripts/lib/duck.test.mjs +0 -118
  323. package/skills/media-use/scripts/lib/error-diffusion.test.mjs +0 -102
  324. package/skills/media-use/scripts/lib/freeze.mjs +0 -70
  325. package/skills/media-use/scripts/lib/freeze.test.mjs +0 -46
  326. package/skills/media-use/scripts/lib/grade-analyzer.mjs +0 -264
  327. package/skills/media-use/scripts/lib/grade-analyzer.test.mjs +0 -285
  328. package/skills/media-use/scripts/lib/heygen-cli.mjs +0 -191
  329. package/skills/media-use/scripts/lib/heygen-cli.test.mjs +0 -301
  330. package/skills/media-use/scripts/lib/heygen-search.mjs +0 -45
  331. package/skills/media-use/scripts/lib/heygen-search.test.mjs +0 -49
  332. package/skills/media-use/scripts/lib/heygen-video-provider.mjs +0 -127
  333. package/skills/media-use/scripts/lib/heygen-video-provider.test.mjs +0 -344
  334. package/skills/media-use/scripts/lib/image-provider.mjs +0 -44
  335. package/skills/media-use/scripts/lib/local-models.mjs +0 -318
  336. package/skills/media-use/scripts/lib/local-models.test.mjs +0 -220
  337. package/skills/media-use/scripts/lib/local-run.mjs +0 -78
  338. package/skills/media-use/scripts/lib/local-run.test.mjs +0 -121
  339. package/skills/media-use/scripts/lib/logo-provider.mjs +0 -222
  340. package/skills/media-use/scripts/lib/logo-provider.test.mjs +0 -137
  341. package/skills/media-use/scripts/lib/ltx-video-provider.mjs +0 -94
  342. package/skills/media-use/scripts/lib/ltx-video-provider.test.mjs +0 -316
  343. package/skills/media-use/scripts/lib/lut-preset-provider.mjs +0 -266
  344. package/skills/media-use/scripts/lib/lut-preset-provider.test.mjs +0 -176
  345. package/skills/media-use/scripts/lib/manifest.test.mjs +0 -388
  346. package/skills/media-use/scripts/lib/match.mjs +0 -47
  347. package/skills/media-use/scripts/lib/mflux-provider.mjs +0 -128
  348. package/skills/media-use/scripts/lib/mflux-provider.test.mjs +0 -174
  349. package/skills/media-use/scripts/lib/misses.mjs +0 -49
  350. package/skills/media-use/scripts/lib/misses.test.mjs +0 -78
  351. package/skills/media-use/scripts/lib/npx-sync.test.mjs +0 -50
  352. package/skills/media-use/scripts/lib/parakeet-words.test.mjs +0 -44
  353. package/skills/media-use/scripts/lib/prefs-store.test.mjs +0 -189
  354. package/skills/media-use/scripts/lib/probe.mjs +0 -39
  355. package/skills/media-use/scripts/lib/probe.test.mjs +0 -31
  356. package/skills/media-use/scripts/lib/providers.mjs +0 -5
  357. package/skills/media-use/scripts/lib/recipe-store.test.mjs +0 -367
  358. package/skills/media-use/scripts/lib/registry.mjs +0 -218
  359. package/skills/media-use/scripts/lib/registry.test.mjs +0 -261
  360. package/skills/media-use/scripts/lib/search.mjs +0 -24
  361. package/skills/media-use/scripts/lib/search.test.mjs +0 -32
  362. package/skills/media-use/scripts/lib/sfx-provider.mjs +0 -23
  363. package/skills/media-use/scripts/lib/specs.mjs +0 -132
  364. package/skills/media-use/scripts/lib/specs.test.mjs +0 -157
  365. package/skills/media-use/scripts/lib/stats.mjs +0 -117
  366. package/skills/media-use/scripts/lib/stats.test.mjs +0 -165
  367. package/skills/media-use/scripts/lib/telemetry.test.mjs +0 -373
  368. package/skills/media-use/scripts/lib/tts-local-provider.mjs +0 -92
  369. package/skills/media-use/scripts/lib/tts-local-provider.test.mjs +0 -72
  370. package/skills/media-use/scripts/lib/usage.mjs +0 -57
  371. package/skills/media-use/scripts/lib/usage.test.mjs +0 -54
  372. package/skills/media-use/scripts/lib/voice-provider.mjs +0 -57
  373. package/skills/media-use/scripts/lib/voice-provider.test.mjs +0 -46
  374. package/skills/media-use/scripts/resolve.test.mjs +0 -1120
  375. /package/skills/{hyperframes-core → hyperframes}/references/subagent-dispatch.md +0 -0
@@ -0,0 +1,133 @@
1
+ # Motion blur — shutter smear on any animated element
2
+
3
+ ## Read this part before you blur anything
4
+
5
+ Blur is not polish. It is the smear a real shutter leaves while the subject
6
+ crosses the frame, so it only reads as correct when the subject crosses enough
7
+ of the frame to have smeared. Applied to motion that was never fast enough, it
8
+ reads as a soft, cheap render: the eye sees mush where it expected an edge.
9
+
10
+ Do not blur:
11
+
12
+ | Case | Why | Do instead |
13
+ | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ----------------------------------- |
14
+ | Travel under about one element-width per frame | The copies pile up inside the element's own silhouette, so the result is a softer element, not a smear | Leave it sharp |
15
+ | A fade, a color change, a blur-in, a filter beat | Nothing reaches `transform`, so there is no trajectory to integrate and no smear to draw | Leave it sharp |
16
+ | Text meant to be read at that moment | A smeared word is an unreadable word, which is usually the opposite of the brief | Blur the approach, land sharp, hold |
17
+ | A slow drift, a parallax layer, a breathing loop | Below the half-pixel deadband it renders sharp anyway; above it, it looks like a mistake | Leave it sharp |
18
+ | The whole scene, or a container of many elements | Cost is the copies of an entire subtree, and a container that never moves smears nothing inside it | Point it at the element that moves |
19
+
20
+ Blur the beats that snap: a slam, a whip, a hard cut in position, a spin, a
21
+ scale punch. One to three of them in a composition, not every tween.
22
+
23
+ ## Two routes, and they are not interchangeable
24
+
25
+ | Route | What it is | Use when |
26
+ | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
27
+ | The `motion-blur` registry component | A DOM shutter synthesised in the page: N+1 additively blended copies of the element along its sampled trajectory | You want the smear visible in the preview, on selected elements, authored per element |
28
+ | The engine's `motionBlur` render option | The renderer integrates real sub-frame samples of the whole frame | You want every moving thing smeared, including canvas, video and transformed ancestors, and only in the final render |
29
+
30
+ The component smears what a `transform` can express, on the elements you mark.
31
+ The engine smears the frame. The component is the one an agent authors; the
32
+ engine option is a render-time decision and shows nothing in a preview.
33
+
34
+ ## The contract: one attribute
35
+
36
+ Paste the component's snippet into the composition, then mark the element:
37
+
38
+ ```html
39
+ <div id="root" data-composition-id="hero" data-duration="4" data-fps="30">
40
+ <div id="slam" data-hf-motion-blur></div>
41
+ <div id="title" data-hf-motion-blur='{"shutterAngle": 360}'></div>
42
+ </div>
43
+ ```
44
+
45
+ Nothing to call and no ordering to get right. A marked element is attached as
46
+ soon as its composition's timeline is registered, and the registry is also
47
+ polled for about eight seconds after load, so a composition that mounts
48
+ asynchronously is picked up too. An element takes the timeline registered under
49
+ the `data-composition-id` of its nearest ancestor carrying that attribute, so a
50
+ sub-composition's targets follow that sub-composition.
51
+
52
+ Empty attribute means defaults. Any other value must parse as a JSON object, so
53
+ it needs double quotes on the keys. A value that parses to something else,
54
+ `null` or a bare number, warns and is skipped rather than quietly taken as
55
+ defaults.
56
+
57
+ `attachMotionBlur(target, timeline, options)` is for an element created later
58
+ than that window. It has an ordering contract, after every tween so the
59
+ timeline's final duration is known, and getting it wrong is silent. For markup
60
+ that is already in the document, use the attribute.
61
+
62
+ ## Options
63
+
64
+ | Option | Default | Meaning |
65
+ | ----------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
66
+ | `shutterAngle` | 720 | Degrees of the frame interval the shutter is open. 720 is two frames, measured off a real After Effects export. 360 is one frame. 0 disables the smear |
67
+ | `shutterPhase` | -360 | Degrees the window start sits from the frame time. -360 centres the window on the frame |
68
+ | `samplesPerFrame` | 16 | Sub-intervals of the window, so this many plus one copies, each at 1 over this many opacity. Max 64 |
69
+ | `fps` | the `data-fps` of the target's own composition root, else 30 | Composition frame rate. Pass it explicitly when rendering with an fps override |
70
+
71
+ A key that is none of these four, and a value that is not a finite number, are
72
+ both refused by name rather than read as defaults. `{"shutterAngle": "720deg"}`
73
+ is a refusal, not a 720 degree shutter.
74
+
75
+ There is no axis, no strength and no radius. The smear is the trajectory,
76
+ integrated; its extent is speed times shutter time and is not a free parameter.
77
+ A template that passes `axis`, `blurMax` or `blurScale` carries an older fork of
78
+ this snippet and its options do nothing in the current one.
79
+
80
+ ## The failure modes are all silent
81
+
82
+ Every one of these renders a plausible-looking sharp element and reports
83
+ nothing except where noted:
84
+
85
+ | Symptom | Cause | Fix |
86
+ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
87
+ | Console warns that no composition registered a timeline for an element | The element is outside every `data-composition-id`, or that composition never registers a timeline | Put it inside the composition's root, or register the timeline |
88
+ | Console warns the attribute is not JSON | Single quotes, unquoted keys, a trailing comma | Double-quoted JSON, or an empty attribute for defaults |
89
+ | Console warns the attribute is not a JSON object | `null`, a bare number, a quoted string, an array | An object, or an empty attribute for defaults |
90
+ | Console warns the attribute names no such option | A misspelled key, for example `samplesperframe` | Use one of the four names above, case-sensitive |
91
+ | Console warns the attribute needs a number for an option | A quoted or unit-suffixed value, for example `"720deg"` | A bare JSON number |
92
+ | Console warns it cannot blur a target inside another target | Both an element and one of its ancestors carry the attribute | Mark one of them, the one that moves |
93
+ | Console warns one call cannot blur compositions at different frame rates | One `attachMotionBlur` call named elements in two compositions whose `data-fps` differ | One call per composition |
94
+ | Console warns a second timeline registered for an element | The same `data-composition-id` key was registered twice with different timelines; the copies still follow the first | Register once per composition |
95
+ | No smear, no warning | The beat animates `left`, `top`, `width` or `height`; the snippet reads the resolved `transform` | Animate `x`, `y`, `scale`, `rotation` |
96
+ | No smear on a container's children | The marked element does not move; its children do | Mark the elements that move |
97
+ | A smear that lags the element | A transformed ancestor is doing the moving | Move the element itself, or use the engine route |
98
+ | Blur only on the first frame, or never in a preview | The host never seeks the timeline | HyperFrames seeks every frame; a paused timeline nobody seeks shows nothing |
99
+ | A smear left behind in the old parent | The target was reparented after attaching; the group stays where it was inserted and is never moved | Do not reparent a blurred element. Animate `x`/`y` instead, or attach after the move |
100
+ | A selector stops matching after attaching | A copy keeps the element's classes, because a class rule is the only thing that can style a copy's pseudo-elements | Address the element by id or by reference, never by a class a copy also carries |
101
+
102
+ ## Cost
103
+
104
+ Each target costs N+1 copies of its whole subtree. Those are restyled on attach
105
+ and on resize, and re-transformed every frame, and the timeline is seeked N+1
106
+ times per frame to sample the trajectory. At the default 16 that is 17 copies
107
+ and 17 seeks per target per frame. Three marked elements is fine. Thirty is a
108
+ different render.
109
+
110
+ Drop `samplesPerFrame` before you drop the effect: 8 halves the cost and the
111
+ staircase is still smooth on a fast beat.
112
+
113
+ ## The numbers, so you can argue with them
114
+
115
+ The defaults are measured against a 1920x1080 30 fps After Effects export of
116
+ translating text, not chosen. In that export the outermost trailing copy sits
117
+ exactly at the previous frame's position and the outermost leading copy exactly
118
+ at the next frame's, with 8 evenly spaced copies between on each side: a window
119
+ of two frames, phase minus one frame, 16 sub-intervals. The staircase across a
120
+ stroke steps by 0.063 plus or minus 0.002 of the sharp text intensity, a flat
121
+ 1/16 per copy with no taper toward the window edges. Triangle weighting scores
122
+ 1.6 dB worse against the same export.
123
+
124
+ Per-beat PSNR against that reference, sharp render versus this component:
125
+ translate +3.38 dB, scale +0.62, rotate X +0.43, rotate Y +0.84, rotate Z
126
+ +1.15. A beat that only scales or only rotates smears, which the earlier
127
+ SVG-filter stage could not do.
128
+
129
+ ## See also
130
+
131
+ `../../registry/components/motion-blur/motion-blur.html` is the snippet and its
132
+ full header. `shutter-slam` is the same model as an installable component: the
133
+ After Effects reference case, six beats, elastic to the container.
@@ -89,7 +89,7 @@ tl.to(
89
89
  | RIPPLE_EASE | discrete choice | `power2.out` standard ping · `power3.out` sharper attack · `expo.out` strong distant pulse |
90
90
  | TARGET_X / TARGET_Y | layout-derived | must match the target's visual centroid — a 4 px miss reads as missing the button |
91
91
 
92
- Reference values: `../../examples/cta-orbit-collapse.html` — 0.5 s move on `back.out(1.3)`, click +0.2 s, press 0.08 s at 0.85/0.95, single ring to 5× over 0.7 s `power2.out`.
92
+ Reference values: `../examples/cta-orbit-collapse.html` — 0.5 s move on `back.out(1.3)`, click +0.2 s, press 0.08 s at 0.85/0.95, single ring to 5× over 0.7 s `power2.out`.
93
93
 
94
94
  ## Critical Constraints
95
95
 
@@ -134,7 +134,7 @@ Values: `HOLD_START` 0.8–1.2s; `DECAY` 0.75–0.88 (higher = longer runway bef
134
134
  | TAIL_PAD | 0.0–1.0s | quiet beat after the last entry; prefer 0 when the next composition owns the breath |
135
135
  | CONTENT N | 3–6 entries | <3 isn't a sequence; >6 drags (accelerating cadence relaxes this — see above) |
136
136
 
137
- Reference: `../../examples/messaging-multi-phrase.html`.
137
+ Reference: `../examples/messaging-multi-phrase.html`.
138
138
 
139
139
  ## Critical Constraints
140
140
 
@@ -108,7 +108,7 @@ charEls.forEach((el, i) => {
108
108
  | REVEAL_THRESHOLD | 0.5–0.7 | lower reveals too early (no tension); higher reads as a hard end-reveal |
109
109
  | FLICKER_RATE | 3–6 frames per glyph swap | <3 looks like noise; >6 looks like discrete typing |
110
110
 
111
- Reference: `../../examples/proof-logo-chain.html` (163px, 0.55s, 0.033s, 0.6).
111
+ Reference: `../examples/proof-logo-chain.html` (163px, 0.55s, 0.033s, 0.6).
112
112
 
113
113
  ## Critical Constraints
114
114
 
@@ -112,7 +112,7 @@ tl.to(
112
112
  ## Variations
113
113
 
114
114
  - **Entrance easing by attack character** — `power4.out` hard slam ⭐ default hit · `expo.out` hardest snap (side-snaps, whip-ins) · `back.out(2)` overshoot pop (accents only, not body words) · `circ.out` heavy rise with momentum. Use **at least 3 distinct easings** across the piece.
115
- - **Rhythm chrome alternatives** — a center beat bar or a `// label` monospace tag pulsing on-beat instead of the 5-tick metronome; mark any decorative that must survive a shader transition per `../../transitions/overview.md`.
115
+ - **Rhythm chrome alternatives** — a center beat bar or a `// label` monospace tag pulsing on-beat instead of the 5-tick metronome; mark any decorative that must survive a shader transition per `../transitions/overview.md`.
116
116
  - **Finale dressing** — stack + accent underline sweep ([css-marker-patterns](css-marker-patterns.md)); don't just leave the last phrase sitting.
117
117
 
118
118
  ## Values
@@ -129,7 +129,7 @@ tl.to(
129
129
  - **One beat array, not scattered offsets** — every element times off `BEATS[]` / `PULSE`; this is the single biggest lever for "rhythmic".
130
130
  - **Different entrance per phrase** — a reused `punchIn()` for all lines is the flat-but-competent tell. Vary the motion axis, reuse the ease _family_.
131
131
  - **Finale repeat math**: `repeat: Math.max(0, Math.floor(dur / cycle) - 1)` — `Math.ceil` overshoots `data-duration` and trips the `gsap_repeat_ceil_overshoot` lint rule; a negative repeat is read by GSAP as `-1` (infinite).
132
- - **No banned exit animations between scenes** — in a montage the _transition_ is the exit (`../../transitions/overview.md`); only a final scene may fade out.
132
+ - **No banned exit animations between scenes** — in a montage the _transition_ is the exit (`../transitions/overview.md`); only a final scene may fade out.
133
133
  - **Display font must be embedded** or it silently falls back at render — Anton / Bebas-as-literal are NOT embedded (`Bebas Neue` aliases to League Gothic; verify in `typography.md`).
134
134
 
135
135
  ## See also
@@ -12,7 +12,7 @@ Real motion blur isn't available to a seeked renderer (it integrates over shutte
12
12
  - **(A) Directional SVG blur** — inline `<feGaussianBlur stdDeviation="X 0">` (X on the motion axis, 0 across it), tweened via a proxy. Cleanest; a true directional smear.
13
13
  - **(B) Echo / ghost trail** — 2–4 duplicates at decreasing opacity, offset backward along the motion vector, collapsing into the lead as it settles. No filter cost; a stylized "speed-line" trail.
14
14
 
15
- **Entrances and mid-shot moves only — never a mid-composition exit.** A blurred element fleeing off-frame mid-composition reads as a glitch; a hard exit between scenes is the transition's job (`../../transitions/overview.md`). One sanctioned scope extension: the envelope may ride the **camera wrapper** during a travel leg — see the Camera-Travel Carve-Out.
15
+ **Entrances and mid-shot moves only — never a mid-composition exit.** A blurred element fleeing off-frame mid-composition reads as a glitch; a hard exit between scenes is the transition's job (`../transitions/overview.md`). One sanctioned scope extension: the envelope may ride the **camera wrapper** during a travel leg — see the Camera-Travel Carve-Out.
16
16
 
17
17
  ## How It Works
18
18
 
@@ -87,7 +87,7 @@ springs.forEach((spring, i) => {
87
87
  | STEP_SPACING | 0.3–0.5s | **≤ STEP_DUR** so springs overlap (additive); wider gaps read as a lazy linear scroll |
88
88
  | BOUNCE_FACTOR | 1.4–2.5 | 1.4 gentle click / 2.0 firm / 2.5+ casino spin-and-land for a climax step |
89
89
 
90
- Reference: `../../examples/proof-logo-chain.html` (204px, 1 step, 0.45s).
90
+ Reference: `../examples/proof-logo-chain.html` (204px, 1 step, 0.45s).
91
91
 
92
92
  ## Critical Constraints
93
93
 
@@ -12,7 +12,7 @@ import { spawnSync } from "node:child_process";
12
12
  import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
13
13
  import { createRequire } from "node:module";
14
14
  import { tmpdir } from "node:os";
15
- import { basename, delimiter, dirname, join, parse, resolve } from "node:path";
15
+ import { basename, delimiter, dirname, join, parse, resolve, win32 as win32Path } from "node:path";
16
16
  import { createInterface } from "node:readline/promises";
17
17
  import { fileURLToPath, pathToFileURL } from "node:url";
18
18
 
@@ -339,23 +339,54 @@ function ancestors(start) {
339
339
  return dirs;
340
340
  }
341
341
 
342
+ export function resolveNpmSpawnCommand(
343
+ args,
344
+ platform = process.platform,
345
+ env = process.env,
346
+ nodeExecPath = process.execPath,
347
+ pathExists = existsSync,
348
+ ) {
349
+ if (platform !== "win32") {
350
+ return { cmd: "npm", args, opts: { stdio: "inherit" } };
351
+ }
352
+
353
+ const bundledNpmCli = win32Path.join(
354
+ win32Path.dirname(nodeExecPath),
355
+ "node_modules",
356
+ "npm",
357
+ "bin",
358
+ "npm-cli.js",
359
+ );
360
+ const npmCli = [env.npm_execpath, bundledNpmCli].find(
361
+ (candidate) => candidate && pathExists(candidate),
362
+ );
363
+ if (!npmCli) return null;
364
+ return {
365
+ cmd: env.npm_node_execpath || nodeExecPath,
366
+ args: [npmCli, ...args],
367
+ opts: { stdio: "inherit", windowsHide: true },
368
+ };
369
+ }
370
+
342
371
  function bootstrapWithNpmInstall(packageNames) {
343
372
  const installRoot = mkdtempSync(join(tmpdir(), "hyperframes-skill-deps-"));
344
- const installResult = spawnSync(
345
- process.platform === "win32" ? "npm.cmd" : "npm",
346
- [
347
- "install",
348
- "--silent",
349
- "--no-audit",
350
- "--no-fund",
351
- "--ignore-scripts",
352
- "--no-save",
353
- "--prefix",
354
- installRoot,
355
- ...packageNames,
356
- ],
357
- { stdio: "inherit" },
358
- );
373
+ const npmArgs = [
374
+ "install",
375
+ "--silent",
376
+ "--no-audit",
377
+ "--no-fund",
378
+ "--ignore-scripts",
379
+ "--no-save",
380
+ "--prefix",
381
+ installRoot,
382
+ ...packageNames,
383
+ ];
384
+ const npmCommand = resolveNpmSpawnCommand(npmArgs);
385
+ if (!npmCommand) {
386
+ rmSync(installRoot, { recursive: true, force: true });
387
+ throw new Error("Could not locate npm-cli.js for dependency bootstrap on Windows.");
388
+ }
389
+ const installResult = spawnSync(npmCommand.cmd, npmCommand.args, npmCommand.opts);
359
390
 
360
391
  if (installResult.error) throw installResult.error;
361
392
  if (installResult.status !== 0) {
@@ -5,10 +5,62 @@ import { copyFileSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
5
5
  import { dirname, join } from "node:path";
6
6
  import { tmpdir } from "node:os";
7
7
  import { fileURLToPath } from "node:url";
8
+ import { resolveNpmSpawnCommand } from "./package-loader.mjs";
8
9
 
9
10
  const HERE = dirname(fileURLToPath(import.meta.url));
10
11
  const ENV = "HYPERFRAMES_SKILL_PKG_VERSION";
11
12
 
13
+ test("resolveNpmSpawnCommand routes Windows npm through node and npm-cli.js", () => {
14
+ const npmCli = "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js";
15
+ const node = "C:\\Program Files\\nodejs\\node.exe";
16
+ const resolved = resolveNpmSpawnCommand(
17
+ ["install", "@hyperframes/producer@0.7.55", "value & calc"],
18
+ "win32",
19
+ { npm_execpath: npmCli, npm_node_execpath: node },
20
+ node,
21
+ (path) => path === npmCli,
22
+ );
23
+
24
+ assert.deepEqual(resolved, {
25
+ cmd: node,
26
+ args: [npmCli, "install", "@hyperframes/producer@0.7.55", "value & calc"],
27
+ opts: { stdio: "inherit", windowsHide: true },
28
+ });
29
+ assert.equal(resolved.opts.shell, undefined);
30
+ });
31
+
32
+ test("resolveNpmSpawnCommand finds npm-cli.js beside node for direct Windows runs", () => {
33
+ const node = "C:\\Program Files\\nodejs\\node.exe";
34
+ const npmCli = "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js";
35
+ const resolved = resolveNpmSpawnCommand(
36
+ ["install", "@hyperframes/producer@0.7.55"],
37
+ "win32",
38
+ {},
39
+ node,
40
+ (path) => path === npmCli,
41
+ );
42
+
43
+ assert.equal(resolved?.cmd, node);
44
+ assert.deepEqual(resolved?.args, [npmCli, "install", "@hyperframes/producer@0.7.55"]);
45
+ });
46
+
47
+ test(
48
+ "resolveNpmSpawnCommand launches the installed npm CLI on Windows",
49
+ { skip: process.platform !== "win32" },
50
+ () => {
51
+ const resolved = resolveNpmSpawnCommand(["--version"]);
52
+ assert.ok(resolved);
53
+
54
+ const result = spawnSync(resolved.cmd, resolved.args, {
55
+ encoding: "utf8",
56
+ windowsHide: true,
57
+ });
58
+
59
+ assert.equal(result.status, 0, result.stderr);
60
+ assert.match(result.stdout.trim(), /^\d+\./);
61
+ },
62
+ );
63
+
12
64
  // (a) env override wins — no ancestor lookup, exact version echoed back.
13
65
  test("hyperframesPackageSpec: env override wins", async () => {
14
66
  const prev = process.env[ENV];
@@ -197,7 +197,7 @@ Vector animations that play inside a composition. Use for logos, character anima
197
197
  </script>
198
198
  ```
199
199
 
200
- `autoplay: false` + `loop: false` + `window.__hfLottie.push()` are mandatory — HyperFrames seeks each registered player to composition time, so anything left on `autoplay`/`loop` runs in wall-clock and renders non-deterministically. The adapter seeks absolute time (no modulo loop, no playback-rate scaling): bake repeating cycles or non-default speed into the Lottie asset or an explicit timeline, then verify the render. Full contract + `.lottie`/dotLottie variant: `adapters/lottie.md`.
200
+ `autoplay: false` + `window.__hfLottie.push()` are mandatory — HyperFrames seeks each registered player to composition time, so a player left on `autoplay` runs in wall-clock and renders non-deterministically. `loop: true` is seek-safe: the adapter wraps composition time into the animation's own length, so a short cycle repeats for the whole scene. There is no playback-rate scaling: bake non-default speed into the Lottie asset. Characters (walk cycles, mascots, gestures) and the full `.lottie`/dotLottie contract: `adapters/lottie.md`.
201
201
 
202
202
  ---
203
203
 
@@ -97,11 +97,11 @@ whitelist is a _scene-worker_ prompt rule only — it does not bind index.html).
97
97
  "note": "Directional. The injector picks __DX__/__DY__ from the direction and emits the horizontal OR vertical pair (not both).",
98
98
  "gsap_template_horizontal": [
99
99
  "tl.to(__OLD__, { x: __DX__, duration: __DUR__, ease: \"power3.inOut\" }, __T__);",
100
- "tl.fromTo(__NEW__, { x: __DXIN__, opacity: 1 }, { x: 0, duration: __DUR__, ease: \"power3.inOut\" }, __T__);"
100
+ "tl.fromTo(__NEW__, { x: __DXIN__, opacity: 1 }, { x: 0, opacity: 1, duration: __DUR__, ease: \"power3.inOut\" }, __T__);"
101
101
  ],
102
102
  "gsap_template_vertical": [
103
103
  "tl.to(__OLD__, { y: __DY__, duration: __DUR__, ease: \"power3.inOut\" }, __T__);",
104
- "tl.fromTo(__NEW__, { y: __DYIN__, opacity: 1 }, { y: 0, duration: __DUR__, ease: \"power3.inOut\" }, __T__);"
104
+ "tl.fromTo(__NEW__, { y: __DYIN__, opacity: 1 }, { y: 0, opacity: 1, duration: __DUR__, ease: \"power3.inOut\" }, __T__);"
105
105
  ]
106
106
  },
107
107
  {
@@ -128,7 +128,7 @@ whitelist is a _scene-worker_ prompt rule only — it does not bind index.html).
128
128
  "note": "Old compresses to a vertical line on the left edge; new expands from the right edge. Incoming starts off (scaleX 0) so its higher-track stacking is harmless.",
129
129
  "gsap_template": [
130
130
  "tl.to(__OLD__, { scaleX: 0, transformOrigin: \"left center\", duration: __DUR__, ease: \"power3.inOut\" }, __T__);",
131
- "tl.fromTo(__NEW__, { scaleX: 0, transformOrigin: \"right center\", opacity: 1 }, { scaleX: 1, transformOrigin: \"right center\", duration: __DUR__, ease: \"power3.inOut\" }, __T__);"
131
+ "tl.fromTo(__NEW__, { scaleX: 0, transformOrigin: \"right center\", opacity: 1 }, { scaleX: 1, transformOrigin: \"right center\", opacity: 1, duration: __DUR__, ease: \"power3.inOut\" }, __T__);"
132
132
  ]
133
133
  }
134
134
  ],
@@ -6,7 +6,7 @@ Both scenes move together — new pushes old out.
6
6
 
7
7
  ```js
8
8
  tl.to(old, { x: -1920, duration: 0.5, ease: "power3.inOut" }, T);
9
- tl.fromTo(new, { x: 1920, opacity: 1 }, { x: 0, duration: 0.5, ease: "power3.inOut" }, T);
9
+ tl.fromTo(new, { x: 1920, opacity: 1 }, { x: 0, opacity: 1, duration: 0.5, ease: "power3.inOut" }, T);
10
10
  ```
11
11
 
12
12
  ### Vertical Push
@@ -15,7 +15,7 @@ Same as push slide but vertical.
15
15
 
16
16
  ```js
17
17
  tl.to(old, { y: -1080, duration: 0.5, ease: "power3.inOut" }, T);
18
- tl.fromTo(new, { y: 1080, opacity: 1 }, { y: 0, duration: 0.5, ease: "power3.inOut" }, T);
18
+ tl.fromTo(new, { y: 1080, opacity: 1 }, { y: 0, opacity: 1, duration: 0.5, ease: "power3.inOut" }, T);
19
19
  ```
20
20
 
21
21
  ### Elastic Push
@@ -24,7 +24,7 @@ Push with overshoot bounce on the incoming scene.
24
24
 
25
25
  ```js
26
26
  tl.to(old, { x: -1920, duration: 0.5, ease: "power3.in" }, T);
27
- tl.fromTo(new, { x: 1920, opacity: 1 }, { x: 30, duration: 0.4, ease: "power4.out" }, T + 0.1);
27
+ tl.fromTo(new, { x: 1920, opacity: 1 }, { x: 30, opacity: 1, duration: 0.4, ease: "power4.out" }, T + 0.1);
28
28
  tl.to(new, { x: -15, duration: 0.15, ease: "sine.inOut" }, T + 0.5);
29
29
  tl.to(new, { x: 0, duration: 0.1, ease: "sine.out" }, T + 0.65);
30
30
  ```
@@ -36,6 +36,6 @@ Old compresses, new expands from opposite side.
36
36
  ```js
37
37
  tl.to(old, { scaleX: 0, transformOrigin: "left center", duration: 0.4, ease: "power3.inOut" }, T);
38
38
  tl.fromTo(new, { scaleX: 0, transformOrigin: "right center", opacity: 1 },
39
- { scaleX: 1, duration: 0.4, ease: "power3.inOut" }, T + 0.1);
39
+ { scaleX: 1, opacity: 1, duration: 0.4, ease: "power3.inOut" }, T + 0.1);
40
40
  tl.set(old, { opacity: 0 }, T + 0.5);
41
41
  ```
@@ -13,6 +13,8 @@ description: >
13
13
  `/hyperframes-core`.
14
14
  ---
15
15
 
16
+ **Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.
17
+
16
18
  # HyperFrames Audio
17
19
 
18
20
  A mix is a set of relationships, not a stack of processors. Two tracks that each
@@ -32,10 +34,11 @@ crossfade envelopes, track gain/track volume, volume and effect automation,
32
34
  ducking/voiceover carve, and the effect chain. `/media-use` owns sourcing,
33
35
  generation, and preprocessing.
34
36
 
35
- Constant `data-playback-rate` (`0.1..5`) is render-safe for picture and
37
+ Constant `data-playback-rate` (`0.1..10`) is render-safe for picture and
36
38
  pitch-preserved sound when matching audio/video elements use the same timing,
37
- source offset, and rate. Source speed ramps are not supported because there is
38
- no rate envelope; preprocess a derived synchronized asset. HyperFrames does not
39
+ source offset, and rate. A speed ramp is a `rate` lane in `data-automation`
40
+ (see `docs/reference/speed-ramps`); it wins over the constant and keeps pitch
41
+ in preview and render. HyperFrames does not
39
42
  provide automatic waveform sync or drift correction.
40
43
  For copyable cut/crossfade/retime recipes, use `/hyperframes-core` → `references/creator-editing-recipes.md`.
41
44
 
@@ -252,11 +255,7 @@ analysis time, so a clip added to the group later is covered without touching
252
255
  <audio id="vo-middle" data-audio-group="voiceover" …></audio>
253
256
  <audio id="vo-outro" data-audio-group="voiceover" …></audio>
254
257
 
255
- <audio
256
- id="music"
257
- data-fx-carve='{"enabled":true,"sources":["voiceover"],"strength":0.25}'
258
- …
259
- ></audio>
258
+ <audio id="music" data-fx-carve='{"enabled":true,"sources":["voiceover"],"strength":0.8}' …></audio>
260
259
  ```
261
260
 
262
261
  A `sources` list naming two or more plain clip ids instead of a group is caught
@@ -355,17 +354,26 @@ many bands, how wide, how far to favour intelligibility over raw voice energy,
355
354
  how far the level may drop, how far under the voice to aim. Those six move
356
355
  together in any real mix — a gentle carve is a shallow cut in few bands with
357
356
  little ducking, a hard one is deeper in more bands with more — so they are one
358
- relationship written once, in `carveProfile`. Default is `0.25` — a 6 dB dip in
359
- three bands with 6 dB of level room, audible without sounding like a hole. At
360
- `0.5` the dip reaches 10 dB, which is where a carve starts being heard as an
361
- effect rather than as room for the voice; above that is deliberate territory for
362
- a loud bed under a quiet voice. `0` is spectral only — one band, no level match
363
- at all.
364
-
365
- **Carve by default.** A bed playing under narration wants a carve; it is not a
366
- polish step to get to if there is time. Place both tracks, run the command below,
367
- listen. Skip it only when there is no narration for the music to sit under — a
368
- music video, a title card, a montage cut to the track.
357
+ relationship written once, in `carveProfile`. `carve.mjs` defaults to `0.8` —
358
+ six bands from 250 Hz to 2.5 kHz cut about 7 dB each and 15 dB at 1.6 kHz, with
359
+ 19 dB of level room — because a bed under narration has to get out of the way
360
+ first and be music second; `0.25` (a 6 dB dip in three bands, 6 dB of room) kept
361
+ the bed present but still let it fight the voice, and was judged too weak in
362
+ practice. At `0.5` the dip reaches 10 dB, which is where a carve starts being
363
+ heard as an effect rather than as room for the voice. Drop the strength when the
364
+ bed is the point and the voice is sparse. `0` is spectral only — one band, no
365
+ level match at all.
366
+
367
+ **Carve by default — required whenever music plays under a voice.** A bed
368
+ under any voice track (narration, avatar speech, interview, voiceover) gets a
369
+ carve as part of finishing the mix, not as a polish step to get to if there is
370
+ time. Place both tracks, run the command below (default strength `0.8`; add
371
+ `--bed` / `--voice` when detection picks wrong), confirm the written
372
+ `data-fx-carve`, `data-fx-chain` and `data-automation` with `npx hyperframes check`,
373
+ and only then render. A volume duck on its own is not a finished mix: it leaves
374
+ the voice and the bed fighting in the 1–3 kHz band and costs the bed all of its
375
+ presence for the whole voiceover. Skip the carve only when there is no voice for
376
+ the music to sit under — a music video, a title card, a montage cut to the track.
369
377
 
370
378
  **It always follows the voice.** There is no static mode: a fixed depth thins the
371
379
  bed through every pause, and once you have heard both there is no reason to want it.
@@ -399,9 +407,9 @@ dynamically at the default strength, and prints what it decided:
399
407
  ```
400
408
  bed music-bed (name looks like music)
401
409
  voice narration (only track left)
402
- carve strength 0.25 dynamic
403
- bands 400Hz -6dB q1.4, 1000Hz -3dB q1.4, 1600Hz -3.17dB q1.4
404
- level 216-point envelope, floor -6 dB
410
+ carve strength 0.8 dynamic
411
+ bands 250Hz -7.4dB q2.06, 400Hz -7.4dB q2.06, 630Hz -7.4dB q2.06, 1000Hz -7.4dB q2.06, 1600Hz -14.8dB q2.06, 2500Hz -7.4dB q2.06
412
+ level 273-point envelope, floor -19.2 dB
405
413
  ```
406
414
 
407
415
  Name the tracks with `--bed` / `--voice` (repeatable) when the automatic choice is
@@ -34,17 +34,20 @@ import { pathToFileURL } from "node:url";
34
34
  * bands and envelopes come out the same either way. */
35
35
  const SAMPLE_RATE = 48000;
36
36
 
37
+ /** Default carve strength. 0.25 kept the bed present but still fighting the voice. */
38
+ export const DEFAULT_STRENGTH = 0.8;
39
+
37
40
  const usage = `carve.mjs --comp <file.html> [--bed <elementId>] [--voice <elementId> ...]
38
41
  [--strength 0..1] [--dry-run] [--core <dir>]
39
42
 
40
43
  --bed id of the music track that gets carved (detected if omitted)
41
44
  --voice id of a voice to make room for; repeatable (detected if omitted)
42
- --strength how hard to carve, 0..1 (default 0.25)
45
+ --strength how hard to carve, 0..1 (default ${DEFAULT_STRENGTH})
43
46
  --dry-run report what it would write, touch nothing
44
47
  --core directory to resolve @hyperframes/core from (default: the comp's)`;
45
48
 
46
- function parseArgs(argv) {
47
- const args = { strength: 0.25, dryRun: false, voices: [] };
49
+ export function parseArgs(argv) {
50
+ const args = { strength: DEFAULT_STRENGTH, dryRun: false, voices: [] };
48
51
  for (let i = 0; i < argv.length; i += 1) {
49
52
  const flag = argv[i];
50
53
  const next = () => {
@@ -5,7 +5,13 @@ import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node
5
5
  import { tmpdir } from "node:os";
6
6
  import { dirname, join } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
- import { carveSources, groupSourceRefusal, loadCore } from "./carve.mjs";
8
+ import {
9
+ DEFAULT_STRENGTH,
10
+ carveSources,
11
+ groupSourceRefusal,
12
+ loadCore,
13
+ parseArgs,
14
+ } from "./carve.mjs";
9
15
 
10
16
  const SCRIPTS_DIR = dirname(fileURLToPath(import.meta.url));
11
17
 
@@ -237,3 +243,12 @@ test("members is required, so dropping it cannot silently restore the group form
237
243
  assert.throws(() => carveSources(voices, bed("bgm", "music")), TypeError);
238
244
  assert.throws(() => groupSourceRefusal(voices, bed("bgm", "music")), TypeError);
239
245
  });
246
+
247
+ test("the default strength is 0.8, and --strength still overrides it", () => {
248
+ // 0.25 left the bed audibly fighting the voice on narrated builds; a carve at
249
+ // the default has to already be a finished mix. Pinned so it cannot drift back
250
+ // unnoticed — core pins its own DEFAULT_CARVE the same way.
251
+ assert.equal(DEFAULT_STRENGTH, 0.8);
252
+ assert.equal(parseArgs(["--comp", "x.html"]).strength, 0.8);
253
+ assert.equal(parseArgs(["--comp", "x.html", "--strength", "0.25"]).strength, 0.25);
254
+ });