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.
- package/README.en.md +4 -3
- package/README.md +5 -4
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -0
- package/package.json +2 -2
- package/skills/embedded-captions/SKILL.md +28 -3
- package/skills/embedded-captions/references/aesthetic-principles.md +2 -3
- package/skills/embedded-captions/references/rail.md +1 -1
- package/skills/embedded-captions/scripts/check-occlusion.cjs +4 -1
- package/skills/embedded-captions/scripts/check-overflow.cjs +1 -0
- package/skills/embedded-captions/scripts/check-rail-climax.cjs +5 -1
- package/skills/embedded-captions/scripts/fixtures/heroless/theme.json +11 -0
- package/skills/embedded-captions/scripts/hf-cli.cjs +33 -0
- package/skills/embedded-captions/scripts/make-theme.cjs +95 -57
- package/skills/embedded-captions/scripts/make-theme.test.mjs +131 -0
- package/skills/embedded-captions/scripts/matte.cjs +1 -13
- package/skills/embedded-captions/scripts/measure-layout.cjs +2 -1
- package/skills/embedded-captions/scripts/preview-frames.cjs +39 -11
- package/skills/embedded-captions/scripts/preview-frames.test.mjs +24 -0
- package/skills/embedded-captions/scripts/render-and-composite.sh +8 -52
- package/skills/embedded-captions/scripts/safe-zones.cjs +4 -1
- package/skills/embedded-captions/scripts/transcribe.cjs +5 -14
- package/skills/embedded-captions/scripts/transcribe.test.mjs +41 -0
- package/skills/faceless-explainer/SKILL.md +20 -16
- package/skills/faceless-explainer/references/story-design.md +1 -1
- package/skills/faceless-explainer/scripts/assemble-index.mjs +6 -4
- package/skills/faceless-explainer/scripts/assemble-index.test.mjs +57 -2
- package/skills/faceless-explainer/scripts/audio.mjs +2 -0
- package/skills/faceless-explainer/scripts/build-frame.mjs +6 -3
- package/skills/faceless-explainer/scripts/captions.mjs +7 -4
- package/skills/faceless-explainer/scripts/frame-packets.mjs +4 -4
- package/skills/faceless-explainer/scripts/lib/bgm-volume.mjs +4 -0
- package/skills/faceless-explainer/scripts/lib/captured-fonts.mjs +58 -0
- package/skills/{hyperframes-core → faceless-explainer}/scripts/lib/frame-packets-core.mjs +5 -23
- package/skills/faceless-explainer/scripts/lib/storyboard.mjs +1 -1
- package/skills/faceless-explainer/scripts/lib/transitions.json +3 -3
- package/skills/faceless-explainer/scripts/transitions.mjs +1 -0
- package/skills/faceless-explainer/scripts/transitions.test.mjs +2 -0
- package/skills/faceless-explainer/sub-agents/frame-worker.md +1 -1
- package/skills/figma/SKILL.md +2 -0
- package/skills/general-video/SKILL.md +13 -11
- package/skills/general-video/scripts/frame-packets.mjs +4 -4
- package/skills/general-video/scripts/lib/frame-packets-core.mjs +194 -0
- package/skills/general-video/sub-agents/frame-worker.md +1 -1
- package/skills/hyperframes/SKILL.md +40 -30
- package/skills/{hyperframes-core → hyperframes}/references/brief-contract.md +15 -15
- package/skills/{hyperframes-core → hyperframes}/references/brief-format.md +8 -8
- package/skills/hyperframes/references/capability-menu.md +2 -2
- package/skills/{hyperframes-core → hyperframes}/references/frame-worker-core.md +1 -1
- package/skills/hyperframes/references/intent-interview.md +16 -16
- package/skills/hyperframes/references/plugin-installation.md +43 -0
- package/skills/{hyperframes-core → hyperframes}/references/production-loop.md +11 -11
- package/skills/hyperframes/references/review-loop.md +37 -0
- package/skills/hyperframes/references/route-briefs.md +1 -1
- package/skills/hyperframes/references/routes/motion-graphics.md +1 -1
- package/skills/{hyperframes-core → hyperframes}/references/script-format.md +3 -3
- package/skills/hyperframes/references/skill-lifecycle.md +2 -0
- package/skills/{hyperframes-core → hyperframes}/references/storyboard-format.md +3 -34
- package/skills/hyperframes/scripts/lib/frame-packets-core.mjs +194 -0
- package/skills/hyperframes/scripts/plugin-cli.mjs +88 -0
- package/skills/hyperframes/scripts/plugin-cli.test.mjs +117 -0
- package/skills/hyperframes-animation/SKILL.md +5 -1
- package/skills/hyperframes-animation/adapters/gsap.md +1 -1
- package/skills/hyperframes-animation/adapters/lottie.md +15 -2
- package/skills/hyperframes-animation/adapters/three.md +14 -0
- package/skills/hyperframes-animation/blueprints/titlecard-reveal.md +1 -1
- package/skills/hyperframes-animation/references/motion-blur.md +133 -0
- package/skills/hyperframes-animation/rules/cursor-click-ripple.md +1 -1
- package/skills/hyperframes-animation/rules/dynamic-content-sequencing.md +1 -1
- package/skills/hyperframes-animation/rules/hacker-flip-3d.md +1 -1
- package/skills/hyperframes-animation/rules/kinetic-beat-slam.md +2 -2
- package/skills/hyperframes-animation/rules/motion-blur-streak.md +1 -1
- package/skills/hyperframes-animation/rules/vertical-spring-ticker.md +1 -1
- package/skills/hyperframes-animation/scripts/package-loader.mjs +47 -16
- package/skills/hyperframes-animation/scripts/package-loader.test.mjs +52 -0
- package/skills/hyperframes-animation/techniques.md +1 -1
- package/skills/hyperframes-animation/transitions/TRANSITION-REGISTRY.md +3 -3
- package/skills/hyperframes-animation/transitions/css-push.md +4 -4
- package/skills/hyperframes-audio/SKILL.md +30 -22
- package/skills/hyperframes-audio/scripts/carve.mjs +6 -3
- package/skills/hyperframes-audio/scripts/carve.test.mjs +16 -1
- package/skills/hyperframes-cli/SKILL.md +44 -35
- package/skills/hyperframes-cli/references/init-and-scaffold.md +8 -6
- package/skills/hyperframes-cli/references/lint-validate-inspect.md +3 -3
- package/skills/hyperframes-cli/references/preview-render.md +35 -32
- package/skills/hyperframes-cli/references/upgrade-info-misc.md +50 -1
- package/skills/hyperframes-core/SKILL.md +30 -24
- package/skills/hyperframes-core/references/composition-patterns.md +3 -42
- package/skills/hyperframes-core/references/creator-editing-recipes.md +131 -7
- package/skills/hyperframes-core/references/data-attributes.md +11 -11
- package/skills/hyperframes-core/references/determinism-rules.md +2 -19
- package/skills/hyperframes-core/references/full-screen-motion.md +0 -9
- package/skills/hyperframes-core/references/minimal-composition.md +2 -2
- package/skills/hyperframes-core/references/sub-compositions.md +3 -66
- package/skills/hyperframes-core/references/tailwind.md +1 -20
- package/skills/hyperframes-core/references/tracks-and-clips.md +2 -6
- package/skills/hyperframes-core/references/variables-and-media.md +3 -3
- package/skills/hyperframes-creative/SKILL.md +2 -0
- package/skills/hyperframes-creative/references/house-style.md +15 -15
- package/skills/hyperframes-creative/references/story-spine.md +3 -1
- package/skills/hyperframes-creative/references/storyboard-recipe.md +57 -0
- package/skills/hyperframes-creative/references/typography.md +1 -1
- package/skills/hyperframes-creative/scripts/package-loader.mjs +47 -16
- package/skills/hyperframes-creative/scripts/package-loader.test.mjs +52 -0
- package/skills/hyperframes-keyframes/SKILL.md +4 -2
- package/skills/hyperframes-registry/SKILL.md +3 -1
- package/skills/hyperframes-registry/references/contributing.md +8 -2
- package/skills/hyperframes-registry/references/discovery.md +20 -34
- package/skills/hyperframes-studio/SKILL.md +77 -0
- package/skills/media-use/SKILL.md +14 -12
- package/skills/media-use/audio/references/captions/authoring.md +4 -0
- package/skills/media-use/audio/references/remove-background.md +1 -1
- package/skills/media-use/audio/references/tts-to-captions.md +11 -2
- package/skills/media-use/audio/references/tts.md +84 -6
- package/skills/media-use/audio/scripts/audio.mjs +15 -6
- package/skills/media-use/audio/scripts/gemini-pipeline.test.mjs +113 -0
- package/skills/media-use/audio/scripts/lib/audio-meta.mjs +39 -0
- package/skills/media-use/audio/scripts/lib/audio-meta.test.mjs +136 -0
- package/skills/media-use/audio/scripts/lib/bgm-volume.mjs +4 -0
- package/skills/media-use/audio/scripts/lib/bgm.mjs +2 -6
- package/skills/media-use/audio/scripts/lib/gemini-auth.mjs +43 -0
- package/skills/media-use/audio/scripts/lib/gemini-auth.py +52 -0
- package/skills/media-use/audio/scripts/lib/gemini-auth.test.mjs +86 -0
- package/skills/media-use/audio/scripts/lib/gemini-auth_test.py +90 -0
- package/skills/media-use/audio/scripts/lib/gemini-tts.mjs +122 -0
- package/skills/media-use/audio/scripts/lib/gemini-tts.test.mjs +243 -0
- package/skills/media-use/audio/scripts/lib/heygen.mjs +2 -1
- package/skills/media-use/audio/scripts/lib/tts.mjs +15 -3
- package/skills/media-use/audio/scripts/wait-bgm.mjs +8 -4
- package/skills/media-use/audio/scripts/wait-bgm.test.mjs +65 -0
- package/skills/media-use/references/audio.md +3 -2
- package/skills/media-use/references/grading.md +7 -7
- package/skills/media-use/references/media-treatment-recipes.md +1 -1
- package/skills/media-use/references/memory.md +2 -2
- package/skills/media-use/references/meta.md +2 -2
- package/skills/media-use/references/operations.md +15 -13
- package/skills/media-use/references/resolve.md +22 -11
- package/skills/media-use/references/setup-providers.md +11 -11
- package/skills/media-use/scripts/audio-duck.mjs +19 -27
- package/skills/media-use/scripts/compatibility.test.mjs +96 -0
- package/skills/media-use/scripts/lib/config-lock.mjs +45 -0
- package/skills/media-use/scripts/lib/duck.mjs +16 -10
- package/skills/media-use/scripts/lib/media-fetch.mjs +85 -0
- package/skills/media-use/scripts/lib/media-home.mjs +20 -0
- package/skills/media-use/scripts/lib/npx-sync.mjs +28 -2
- package/skills/media-use/scripts/lib/prefs-store.mjs +2 -2
- package/skills/media-use/scripts/lib/recipe-store.mjs +2 -2
- package/skills/media-use/scripts/lib/telemetry.mjs +29 -41
- package/skills/media-use/scripts/lib/transcriptCutFade.mjs +21 -0
- package/skills/media-use/scripts/prefs.mjs +1 -1
- package/skills/media-use/scripts/recipe.mjs +1 -1
- package/skills/media-use/scripts/resolve-plugin.test.mjs +62 -0
- package/skills/media-use/scripts/resolve.mjs +27 -1267
- package/skills/media-use/scripts/transcribe.mjs +39 -25
- package/skills/media-use/scripts/transcribe.test.mjs +112 -0
- package/skills/media-use/scripts/transcript-cut.mjs +39 -8
- package/skills/media-use/scripts/transcript-cut.test.mjs +117 -0
- package/skills/motion-graphics/SKILL.md +3 -1
- package/skills/motion-graphics/agents/builder.md +1 -0
- package/skills/motion-graphics/agents/director.md +2 -1
- package/skills/motion-graphics/catalog-map.md +25 -13
- package/skills/motion-graphics/categories/charts/module.md +2 -1
- package/skills/motion-graphics/categories/lower-thirds/module.md +4 -0
- package/skills/motion-graphics/categories/news/module.md +1 -1
- package/skills/motion-graphics/references/motion-vocabulary.md +4 -0
- package/skills/music-to-video/SKILL.md +8 -6
- package/skills/music-to-video/references/montage.md +3 -6
- package/skills/music-to-video/references/motion-primitives/3d-card-flip/index.html +10 -111
- package/skills/music-to-video/references/motion-primitives/3d-card-flip/scene.html +119 -0
- package/skills/music-to-video/references/motion-primitives/bg-flow-field/index.html +11 -284
- package/skills/music-to-video/references/motion-primitives/bg-flow-field/scene.html +294 -0
- package/skills/music-to-video/references/motion-primitives/binary-decrypt/index.html +10 -76
- package/skills/music-to-video/references/motion-primitives/binary-decrypt/scene.html +85 -0
- package/skills/music-to-video/references/motion-primitives/blur-resolve/index.html +10 -52
- package/skills/music-to-video/references/motion-primitives/blur-resolve/scene.html +60 -0
- package/skills/music-to-video/references/motion-primitives/braam-punch/index.html +10 -92
- package/skills/music-to-video/references/motion-primitives/braam-punch/scene.html +100 -0
- package/skills/music-to-video/references/motion-primitives/chromatic-split/index.html +10 -103
- package/skills/music-to-video/references/motion-primitives/chromatic-split/scene.html +111 -0
- package/skills/music-to-video/references/motion-primitives/chrome-sweep/index.html +10 -60
- package/skills/music-to-video/references/motion-primitives/chrome-sweep/scene.html +68 -0
- package/skills/music-to-video/references/motion-primitives/counting-punch/index.html +10 -110
- package/skills/music-to-video/references/motion-primitives/counting-punch/scene.html +119 -0
- package/skills/music-to-video/references/motion-primitives/crash-zoom-in/index.html +10 -112
- package/skills/music-to-video/references/motion-primitives/crash-zoom-in/scene.html +120 -0
- package/skills/music-to-video/references/motion-primitives/datamosh-smear/index.html +10 -121
- package/skills/music-to-video/references/motion-primitives/datamosh-smear/scene.html +131 -0
- package/skills/music-to-video/references/motion-primitives/directional-fill/index.html +10 -90
- package/skills/music-to-video/references/motion-primitives/directional-fill/scene.html +103 -0
- package/skills/music-to-video/references/motion-primitives/dolly-zoom/index.html +10 -94
- package/skills/music-to-video/references/motion-primitives/dolly-zoom/scene.html +102 -0
- package/skills/music-to-video/references/motion-primitives/electric-arc/index.html +10 -100
- package/skills/music-to-video/references/motion-primitives/electric-arc/scene.html +105 -0
- package/skills/music-to-video/references/motion-primitives/flash-cut/index.html +10 -89
- package/skills/music-to-video/references/motion-primitives/flash-cut/scene.html +97 -0
- package/skills/music-to-video/references/motion-primitives/gooey-metaball/index.html +10 -197
- package/skills/music-to-video/references/motion-primitives/gooey-metaball/scene.html +206 -0
- package/skills/music-to-video/references/motion-primitives/hard-cut/index.html +10 -74
- package/skills/music-to-video/references/motion-primitives/hard-cut/scene.html +82 -0
- package/skills/music-to-video/references/motion-primitives/hypercut-whip/index.html +10 -36
- package/skills/music-to-video/references/motion-primitives/hypercut-whip/scene.html +44 -0
- package/skills/music-to-video/references/motion-primitives/iris-open/index.html +10 -61
- package/skills/music-to-video/references/motion-primitives/iris-open/scene.html +69 -0
- package/skills/music-to-video/references/motion-primitives/kinetic-letter-in/index.html +10 -55
- package/skills/music-to-video/references/motion-primitives/kinetic-letter-in/scene.html +64 -0
- package/skills/music-to-video/references/motion-primitives/liquid-morph/index.html +10 -88
- package/skills/music-to-video/references/motion-primitives/liquid-morph/scene.html +96 -0
- package/skills/music-to-video/references/motion-primitives/mask-reveal/index.html +10 -66
- package/skills/music-to-video/references/motion-primitives/mask-reveal/scene.html +74 -0
- package/skills/music-to-video/references/motion-primitives/mosaic-pack/index.html +10 -81
- package/skills/music-to-video/references/motion-primitives/mosaic-pack/scene.html +89 -0
- package/skills/music-to-video/references/motion-primitives/neon-flicker/index.html +10 -65
- package/skills/music-to-video/references/motion-primitives/neon-flicker/scene.html +73 -0
- package/skills/music-to-video/references/motion-primitives/outline-to-fill/index.html +10 -74
- package/skills/music-to-video/references/motion-primitives/outline-to-fill/scene.html +82 -0
- package/skills/music-to-video/references/motion-primitives/palette-flip/index.html +10 -89
- package/skills/music-to-video/references/motion-primitives/palette-flip/scene.html +97 -0
- package/skills/music-to-video/references/motion-primitives/particle-burst/index.html +10 -98
- package/skills/music-to-video/references/motion-primitives/particle-burst/scene.html +106 -0
- package/skills/music-to-video/references/motion-primitives/pixel-dissolve/index.html +10 -78
- package/skills/music-to-video/references/motion-primitives/pixel-dissolve/scene.html +86 -0
- package/skills/music-to-video/references/motion-primitives/radial-burst-lines/index.html +10 -117
- package/skills/music-to-video/references/motion-primitives/radial-burst-lines/scene.html +130 -0
- package/skills/music-to-video/references/motion-primitives/screen-shake/index.html +10 -70
- package/skills/music-to-video/references/motion-primitives/screen-shake/scene.html +78 -0
- package/skills/music-to-video/references/motion-primitives/slot-machine-reveal/index.html +10 -87
- package/skills/music-to-video/references/motion-primitives/slot-machine-reveal/scene.html +100 -0
- package/skills/music-to-video/references/motion-primitives/spotlight-sweep/index.html +10 -94
- package/skills/music-to-video/references/motion-primitives/spotlight-sweep/scene.html +102 -0
- package/skills/music-to-video/references/motion-primitives/staggered-exit/index.html +10 -74
- package/skills/music-to-video/references/motion-primitives/staggered-exit/scene.html +82 -0
- package/skills/music-to-video/references/motion-primitives/text-spectral-rays/index.html +11 -271
- package/skills/music-to-video/references/motion-primitives/text-spectral-rays/scene.html +280 -0
- package/skills/music-to-video/references/motion-primitives/text-wave-distort/index.html +10 -92
- package/skills/music-to-video/references/motion-primitives/text-wave-distort/scene.html +106 -0
- package/skills/music-to-video/references/motion-primitives/tile-mosaic/index.html +10 -101
- package/skills/music-to-video/references/motion-primitives/tile-mosaic/scene.html +109 -0
- package/skills/music-to-video/references/motion-primitives/typewriter-reveal/index.html +10 -79
- package/skills/music-to-video/references/motion-primitives/typewriter-reveal/scene.html +91 -0
- package/skills/music-to-video/references/motion-primitives/word-grid-burst/index.html +10 -83
- package/skills/music-to-video/references/motion-primitives/word-grid-burst/scene.html +96 -0
- package/skills/music-to-video/references/planning.md +2 -2
- package/skills/music-to-video/scripts/lib/storyboard.mjs +1 -1
- package/skills/music-to-video/sub-agents/frame-worker.md +2 -2
- package/skills/pr-to-video/SKILL.md +20 -16
- package/skills/pr-to-video/references/code-vocabulary.md +14 -12
- package/skills/pr-to-video/references/story-design.md +1 -1
- package/skills/pr-to-video/scripts/assemble-index.mjs +6 -4
- package/skills/pr-to-video/scripts/assemble-index.test.mjs +57 -2
- package/skills/pr-to-video/scripts/audio.mjs +2 -0
- package/skills/pr-to-video/scripts/build-frame.mjs +6 -3
- package/skills/pr-to-video/scripts/captions.mjs +7 -4
- package/skills/pr-to-video/scripts/captions.test.mjs +41 -0
- package/skills/pr-to-video/scripts/frame-packets.mjs +4 -4
- package/skills/pr-to-video/scripts/lib/bgm-volume.mjs +4 -0
- package/skills/pr-to-video/scripts/lib/captured-fonts.mjs +58 -0
- package/skills/pr-to-video/scripts/lib/frame-packets-core.mjs +194 -0
- package/skills/pr-to-video/scripts/lib/storyboard.mjs +1 -1
- package/skills/pr-to-video/scripts/lib/transitions.json +3 -3
- package/skills/pr-to-video/scripts/transitions.mjs +7 -5
- package/skills/pr-to-video/sub-agents/frame-worker.md +1 -1
- package/skills/product-launch-video/SKILL.md +20 -16
- package/skills/product-launch-video/references/story-design.md +1 -1
- package/skills/product-launch-video/scripts/assemble-index.mjs +6 -4
- package/skills/product-launch-video/scripts/assemble-index.test.mjs +57 -2
- package/skills/product-launch-video/scripts/audio.mjs +2 -0
- package/skills/product-launch-video/scripts/audio.test.mjs +16 -0
- package/skills/product-launch-video/scripts/build-frame-subsets.test.mjs +152 -0
- package/skills/product-launch-video/scripts/build-frame.mjs +6 -3
- package/skills/product-launch-video/scripts/captions.mjs +7 -4
- package/skills/product-launch-video/scripts/frame-packets.mjs +4 -4
- package/skills/product-launch-video/scripts/lib/bgm-volume.mjs +4 -0
- package/skills/product-launch-video/scripts/lib/captured-fonts.mjs +58 -0
- package/skills/product-launch-video/scripts/lib/frame-packets-core.mjs +194 -0
- package/skills/product-launch-video/scripts/lib/storyboard.mjs +1 -1
- package/skills/product-launch-video/scripts/lib/transitions.json +3 -3
- package/skills/product-launch-video/scripts/transitions.mjs +7 -5
- package/skills/product-launch-video/scripts/transitions.test.mjs +68 -0
- package/skills/product-launch-video/sub-agents/frame-worker.md +1 -1
- package/skills/remotion-to-hyperframes/SKILL.md +7 -4
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/expected.json +5 -5
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/compositions/title.html +31 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/index.html +10 -25
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/README.md +8 -8
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/expected.json +9 -9
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-1.html +35 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-2.html +35 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/compositions/scene-3.html +36 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/index.html +28 -71
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/expected.json +3 -3
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-1.html +52 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-2.html +99 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/compositions/scene-3.html +55 -0
- package/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/index.html +13 -212
- package/skills/remotion-to-hyperframes/references/api-map.md +16 -16
- package/skills/remotion-to-hyperframes/references/limitations.md +7 -7
- package/skills/remotion-to-hyperframes/references/lottie.md +5 -7
- package/skills/remotion-to-hyperframes/references/media.md +3 -3
- package/skills/remotion-to-hyperframes/references/parameters.md +5 -0
- package/skills/remotion-to-hyperframes/references/sequencing.md +71 -18
- package/skills/slideshow/SKILL.md +4 -1
- package/skills/slideshow/references/standalone-harness.md +0 -3
- package/skills/talking-head-recut/SKILL.md +10 -1
- package/skills/hyperframes-core/references/review-loop.md +0 -41
- package/skills/media-use/scripts/lib/adopt.mjs +0 -128
- package/skills/media-use/scripts/lib/adopt.test.mjs +0 -95
- package/skills/media-use/scripts/lib/bgm-provider.mjs +0 -20
- package/skills/media-use/scripts/lib/brand-provider.mjs +0 -59
- package/skills/media-use/scripts/lib/bundled-sfx-provider.mjs +0 -108
- package/skills/media-use/scripts/lib/bundled-sfx-provider.test.mjs +0 -85
- package/skills/media-use/scripts/lib/cache.mjs +0 -150
- package/skills/media-use/scripts/lib/candidates.mjs +0 -91
- package/skills/media-use/scripts/lib/candidates.test.mjs +0 -155
- package/skills/media-use/scripts/lib/codex-provider.mjs +0 -161
- package/skills/media-use/scripts/lib/codex-provider.test.mjs +0 -34
- package/skills/media-use/scripts/lib/coverage.test.mjs +0 -117
- package/skills/media-use/scripts/lib/cube-build.mjs +0 -181
- package/skills/media-use/scripts/lib/cube-build.test.mjs +0 -80
- package/skills/media-use/scripts/lib/cube-validate.mjs +0 -198
- package/skills/media-use/scripts/lib/cube-validate.test.mjs +0 -125
- package/skills/media-use/scripts/lib/cutlist.test.mjs +0 -148
- package/skills/media-use/scripts/lib/duck.test.mjs +0 -118
- package/skills/media-use/scripts/lib/error-diffusion.test.mjs +0 -102
- package/skills/media-use/scripts/lib/freeze.mjs +0 -70
- package/skills/media-use/scripts/lib/freeze.test.mjs +0 -46
- package/skills/media-use/scripts/lib/grade-analyzer.mjs +0 -264
- package/skills/media-use/scripts/lib/grade-analyzer.test.mjs +0 -285
- package/skills/media-use/scripts/lib/heygen-cli.mjs +0 -191
- package/skills/media-use/scripts/lib/heygen-cli.test.mjs +0 -301
- package/skills/media-use/scripts/lib/heygen-search.mjs +0 -45
- package/skills/media-use/scripts/lib/heygen-search.test.mjs +0 -49
- package/skills/media-use/scripts/lib/heygen-video-provider.mjs +0 -127
- package/skills/media-use/scripts/lib/heygen-video-provider.test.mjs +0 -344
- package/skills/media-use/scripts/lib/image-provider.mjs +0 -44
- package/skills/media-use/scripts/lib/local-models.mjs +0 -318
- package/skills/media-use/scripts/lib/local-models.test.mjs +0 -220
- package/skills/media-use/scripts/lib/local-run.mjs +0 -78
- package/skills/media-use/scripts/lib/local-run.test.mjs +0 -121
- package/skills/media-use/scripts/lib/logo-provider.mjs +0 -222
- package/skills/media-use/scripts/lib/logo-provider.test.mjs +0 -137
- package/skills/media-use/scripts/lib/ltx-video-provider.mjs +0 -94
- package/skills/media-use/scripts/lib/ltx-video-provider.test.mjs +0 -316
- package/skills/media-use/scripts/lib/lut-preset-provider.mjs +0 -266
- package/skills/media-use/scripts/lib/lut-preset-provider.test.mjs +0 -176
- package/skills/media-use/scripts/lib/manifest.test.mjs +0 -388
- package/skills/media-use/scripts/lib/match.mjs +0 -47
- package/skills/media-use/scripts/lib/mflux-provider.mjs +0 -128
- package/skills/media-use/scripts/lib/mflux-provider.test.mjs +0 -174
- package/skills/media-use/scripts/lib/misses.mjs +0 -49
- package/skills/media-use/scripts/lib/misses.test.mjs +0 -78
- package/skills/media-use/scripts/lib/npx-sync.test.mjs +0 -50
- package/skills/media-use/scripts/lib/parakeet-words.test.mjs +0 -44
- package/skills/media-use/scripts/lib/prefs-store.test.mjs +0 -189
- package/skills/media-use/scripts/lib/probe.mjs +0 -39
- package/skills/media-use/scripts/lib/probe.test.mjs +0 -31
- package/skills/media-use/scripts/lib/providers.mjs +0 -5
- package/skills/media-use/scripts/lib/recipe-store.test.mjs +0 -367
- package/skills/media-use/scripts/lib/registry.mjs +0 -218
- package/skills/media-use/scripts/lib/registry.test.mjs +0 -261
- package/skills/media-use/scripts/lib/search.mjs +0 -24
- package/skills/media-use/scripts/lib/search.test.mjs +0 -32
- package/skills/media-use/scripts/lib/sfx-provider.mjs +0 -23
- package/skills/media-use/scripts/lib/specs.mjs +0 -132
- package/skills/media-use/scripts/lib/specs.test.mjs +0 -157
- package/skills/media-use/scripts/lib/stats.mjs +0 -117
- package/skills/media-use/scripts/lib/stats.test.mjs +0 -165
- package/skills/media-use/scripts/lib/telemetry.test.mjs +0 -373
- package/skills/media-use/scripts/lib/tts-local-provider.mjs +0 -92
- package/skills/media-use/scripts/lib/tts-local-provider.test.mjs +0 -72
- package/skills/media-use/scripts/lib/usage.mjs +0 -57
- package/skills/media-use/scripts/lib/usage.test.mjs +0 -54
- package/skills/media-use/scripts/lib/voice-provider.mjs +0 -57
- package/skills/media-use/scripts/lib/voice-provider.test.mjs +0 -46
- package/skills/media-use/scripts/resolve.test.mjs +0 -1120
- /package/skills/{hyperframes-core → hyperframes}/references/subagent-dispatch.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Composition Patterns
|
|
2
2
|
|
|
3
|
-
How to architect a project
|
|
3
|
+
How to architect a project: the `index.html` orchestrator at scale, and the common sub-composition archetypes. Pair with `minimal-composition.md` (single-file shape) and `sub-compositions.md` (mechanics of a sub-comp file).
|
|
4
4
|
|
|
5
5
|
## Two Architectures
|
|
6
6
|
|
|
@@ -13,27 +13,6 @@ How to architect a project — when to inline everything in one HTML, when to sp
|
|
|
13
13
|
|
|
14
14
|
Both architectures use the same runtime contract — `data-*` attributes + `window.__timelines[id]`. The choice is structural, not behavioral.
|
|
15
15
|
|
|
16
|
-
### Pick monolithic when
|
|
17
|
-
|
|
18
|
-
- The whole video is one continuous scene with no hard cuts.
|
|
19
|
-
- Scenes share heavy state (one canvas/WebGL context spanning the whole video, a single SVG that morphs across all beats).
|
|
20
|
-
- Total scope is small (~200–400 lines of markup + script).
|
|
21
|
-
- No scene is reused across projects.
|
|
22
|
-
|
|
23
|
-
### Pick modular when
|
|
24
|
-
|
|
25
|
-
- The video has clear scene cuts — each scene is its own segment of the timeline.
|
|
26
|
-
- Some scenes are large (>100 lines of markup or significant scripted animation).
|
|
27
|
-
- A scene is reusable (kinetic intro, end-card logo lockup, a transition).
|
|
28
|
-
- The video has a continuous audio track over multiple visual segments. Keep audio at the root, visual segments as sub-comps.
|
|
29
|
-
- You want to author/iterate on scenes in isolation (preview a single sub-comp file directly).
|
|
30
|
-
|
|
31
|
-
### Refactor between them
|
|
32
|
-
|
|
33
|
-
Conversion is mechanical and reversible. To lift a monolithic scene into a sub-comp: wrap the scene's markup + scoped CSS + its slice of the parent timeline into a `<template>`, save as `compositions/<scene>.html`, replace the inline content in `index.html` with a slot `<div data-composition-src="compositions/<scene>.html">`, and have the sub-comp register its own timeline at `window.__timelines["<scene>"]`. The parent timeline shrinks accordingly.
|
|
34
|
-
|
|
35
|
-
If a monolithic project is approaching three or more scene cuts, prefer modularizing _before_ adding the next scene. Mixed projects where some scenes are inline and siblings are in `compositions/` are the hardest to maintain.
|
|
36
|
-
|
|
37
16
|
## Modular Orchestrator Pattern
|
|
38
17
|
|
|
39
18
|
When using sub-compositions, `index.html` should be **thin**. Its job is to declare slots, lay them out in time, mount the audio track, and register a (usually empty) root timeline. All scene animation lives inside the sub-comps.
|
|
@@ -51,8 +30,8 @@ When using sub-compositions, `index.html` should be **thin**. Its job is to decl
|
|
|
51
30
|
}
|
|
52
31
|
#root {
|
|
53
32
|
position: relative;
|
|
54
|
-
width:
|
|
55
|
-
height:
|
|
33
|
+
width: 100%;
|
|
34
|
+
height: 100%;
|
|
56
35
|
overflow: hidden;
|
|
57
36
|
}
|
|
58
37
|
/* Sub-comp slots stretch to fill the root. */
|
|
@@ -110,7 +89,6 @@ When using sub-compositions, `index.html` should be **thin**. Its job is to decl
|
|
|
110
89
|
</div>
|
|
111
90
|
|
|
112
91
|
<script>
|
|
113
|
-
window.__timelines = window.__timelines || {};
|
|
114
92
|
window.__timelines["root"] = gsap.timeline({ paused: true });
|
|
115
93
|
</script>
|
|
116
94
|
</body>
|
|
@@ -162,7 +140,6 @@ The reason to reach for it: a sub-comp timeline **cannot** drive host elements (
|
|
|
162
140
|
|
|
163
141
|
<script>
|
|
164
142
|
// MAIN timeline drives the host video. Global time: scene starts at 20.
|
|
165
|
-
window.__timelines = window.__timelines || {};
|
|
166
143
|
const main = window.__timelines["main"];
|
|
167
144
|
main.fromTo(
|
|
168
145
|
"#final-video",
|
|
@@ -182,7 +159,6 @@ The reason to reach for it: a sub-comp timeline **cannot** drive host elements (
|
|
|
182
159
|
style="position:absolute; inset:0; pointer-events:none;"
|
|
183
160
|
>
|
|
184
161
|
<script>
|
|
185
|
-
window.__timelines = window.__timelines || {};
|
|
186
162
|
const tl = gsap.timeline({ paused: true });
|
|
187
163
|
// animate ONLY this sub-comp's own elements here (labels, frame, overlays)
|
|
188
164
|
window.__timelines["final-anim"] = tl;
|
|
@@ -216,7 +192,6 @@ When several beat-level scenes share continuous state — a chat thread that gro
|
|
|
216
192
|
<div class="phase" id="phase-b">…</div>
|
|
217
193
|
<div class="phase" id="phase-c">…</div>
|
|
218
194
|
<script>
|
|
219
|
-
window.__timelines = window.__timelines || {};
|
|
220
195
|
const tl = gsap.timeline({ paused: true });
|
|
221
196
|
tl.set("#phase-a", { opacity: 1 }, 0);
|
|
222
197
|
tl.to("#phase-a", { opacity: 0, duration: 0.4 }, 3.0);
|
|
@@ -247,17 +222,3 @@ Audio always lives at the host (`index.html`) as a root-level `<audio>` so playb
|
|
|
247
222
|
| Audio at root | `data-track-index` well above visual tracks | `10` while visuals use `1` |
|
|
248
223
|
|
|
249
224
|
The `-template` suffix on `<template>` is conventional but not required — the runtime extracts contents from whichever `<template>` is in `<body>`, regardless of id. The prefix on inner element ids is the only safeguard against id collisions when multiple sub-comps are mounted into the same host page at once.
|
|
250
|
-
|
|
251
|
-
## Editing Existing Projects
|
|
252
|
-
|
|
253
|
-
Before adding or modifying scenes, identify which architecture is in use:
|
|
254
|
-
|
|
255
|
-
```bash
|
|
256
|
-
ls compositions/ 2>/dev/null && echo "modular" || echo "monolithic"
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
- In a **monolithic** project, add new scenes as inline `<section class="clip">` elements with a deliberate `data-start` and a sensible `data-track-index`, and extend the existing single timeline.
|
|
260
|
-
- In a **modular** project, match the pattern: add a new file under `compositions/`, add a slot in `index.html`, keep the root timeline thin. Do **not** start inlining new scenes into `index.html` when sibling scenes are sub-comps — the inconsistency is the worst of both worlds.
|
|
261
|
-
- If a monolithic project needs a third or fourth scene cut, lift each scene into a sub-comp before adding more. The conversion is mechanical (see "Refactor between them" above).
|
|
262
|
-
|
|
263
|
-
When picking the slot's `data-start`/`data-duration`, prefer continuing the existing sequencing convention (adjoining starts, deliberate overlaps for cross-fades). Don't introduce a new track index unless you actually need parallel visual layers — most sequential-scene projects use exactly one visual track.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Use these copyable contracts after `tracks-and-clips.md`. Global math: **consumed source = timeline duration × rate**; **natural timeline duration = remaining source / rate**.
|
|
4
4
|
|
|
5
|
+
Before any edit, run `npx hyperframes timeline` (add `--json` for a machine-readable list) to see the project's tracks and clips instead of reading the HTML.
|
|
6
|
+
|
|
5
7
|
These recipes keep sound on a separate `<audio>` element with the `<video>` muted, which is the pattern to reach for when picture and sound are cut independently. An unmuted `<video>` that declares `data-has-audio="true"` is also mixed, so a separate track is a choice, not a requirement.
|
|
6
8
|
|
|
7
9
|
**Every `<video>` and `<audio>` below carries an `id`, and that is not cosmetic**: `lint` errors with `media_missing_id` on timed media without one, and an id-less `<audio>` is never picked up by the mixer, so the render comes out silent. Keep the ids when you copy a recipe.
|
|
@@ -47,7 +49,7 @@ These recipes keep sound on a separate `<audio>` element with the `<video>` mute
|
|
|
47
49
|
></audio>
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
Timeline math: B starts at A start + duration. Source math: each range starts at `data-media-start`; consumed source = timeline duration × rate. Audio follows: duplicate matching `<audio>` ranges/timing. Owner: `/hyperframes-core`. Limit: adjacent windows only; author the two windows edge to edge.
|
|
52
|
+
Timeline math: B starts at A start + duration. Source math: each range starts at `data-media-start`; consumed source = timeline duration × rate. Audio follows: duplicate matching `<audio>` ranges/timing. Owner: `/hyperframes-core`. Limit: adjacent windows only; author the two windows edge to edge. Same-track overlap is valid; both clips paint in CSS order.
|
|
51
53
|
|
|
52
54
|
## Trim in/out
|
|
53
55
|
|
|
@@ -227,7 +229,7 @@ Timeline math: the still owns its hold duration. Source math: final-source frame
|
|
|
227
229
|
></video>
|
|
228
230
|
```
|
|
229
231
|
|
|
230
|
-
Timeline math: duration is authored timeline time. Source math: consumed source = timeline duration × rate; natural timeline duration = remaining source / rate. Audio follows: matching separate audio track uses the same constant rate. Owner: `/hyperframes-core`. Limit: normalized 0.1..
|
|
232
|
+
Timeline math: duration is authored timeline time. Source math: consumed source = timeline duration × rate; natural timeline duration = remaining source / rate. Audio follows: matching separate audio track uses the same constant rate. Owner: `/hyperframes-core`. Limit: normalized 0.1..10. For a speed ramp put a `rate` lane in `data-automation`, e.g. `{"version":1,"lanes":[{"target":"rate","points":[{"t":0,"v":1},{"t":2,"v":4}]}]}`; it wins over the constant.
|
|
231
233
|
|
|
232
234
|
## Zoom / punch
|
|
233
235
|
|
|
@@ -314,11 +316,10 @@ Timeline math: overlap placed clips for the 0.5s handoff. Source math: each clip
|
|
|
314
316
|
></audio>
|
|
315
317
|
<script>
|
|
316
318
|
const tl = gsap.timeline({ paused: true });
|
|
317
|
-
tl.set("#b-visual", {
|
|
318
|
-
.to("#a-visual", {
|
|
319
|
-
.to("#b-visual", {
|
|
320
|
-
window.__timelines =
|
|
321
|
-
window.__timelines.main = tl;
|
|
319
|
+
tl.set("#b-visual", { opacity: 0 }, 0)
|
|
320
|
+
.to("#a-visual", { opacity: 0, duration: 0.5 }, 2.5)
|
|
321
|
+
.to("#b-visual", { opacity: 1, duration: 0.5 }, 2.5);
|
|
322
|
+
window.__timelines["main"] = tl;
|
|
322
323
|
</script>
|
|
323
324
|
```
|
|
324
325
|
|
|
@@ -339,6 +340,8 @@ Timeline math: distinct tracks overlap by 0.5s with opposing opacity envelopes.
|
|
|
339
340
|
|
|
340
341
|
Timeline math: lane `t` is clip-local authored time: fade-in 0–1, duck down 2–2.2, hold 2.2–3, duck up 3–3.2, fade-out 4–5. Source math: source selection still uses core attributes. Audio follows: the explicit down-hold-up envelope affects this separate audio track. Owner: `/hyperframes-audio`. Limit: automation is not source retiming.
|
|
341
342
|
|
|
343
|
+
**One rule for volume over time: use the lane.** `lint` accepts a timeline tween on `volume` too, but when a track has both, the lane wins and the tween is ignored (`audio_volume_double_automation`). Never add a lane to a track that already has a `volume` tween, and never add a tween to a track that has a lane; edit the one that exists. To ramp 0.1 to 0.5 over ten seconds, write `{"t":0,"v":0.1},{"t":10,"v":0.5}`. `t` is seconds from the clip's own start, so a ramp past `data-duration` never finishes: check the clip's length before choosing the times. `data-volume` stays as the static level of the clip and combines with nothing else you author here.
|
|
344
|
+
|
|
342
345
|
## Audio alignment
|
|
343
346
|
|
|
344
347
|
```html
|
|
@@ -365,3 +368,124 @@ Timeline math: lane `t` is clip-local authored time: fade-in 0–1, duck down 2
|
|
|
365
368
|
```
|
|
366
369
|
|
|
367
370
|
Timeline math: picture and sound share start/duration. Source math: both consume four source seconds. Audio follows: identical timing, range, and rate on the separate audio track. Owner: `/hyperframes-core` + `/hyperframes-audio`. Limit: no waveform auto-sync or drift correction.
|
|
371
|
+
|
|
372
|
+
## Align a sound to an on-screen event
|
|
373
|
+
|
|
374
|
+
```html
|
|
375
|
+
<audio
|
|
376
|
+
id="sfx-click-3"
|
|
377
|
+
src="click.mp3"
|
|
378
|
+
data-start="7.48"
|
|
379
|
+
data-duration="0.07"
|
|
380
|
+
data-track-index="103"
|
|
381
|
+
data-volume="0.85"
|
|
382
|
+
></audio>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Timeline math: an audio element in the root composition has `data-start` in absolute root time; audio inside a scene file uses scene-local time and the host's `data-start` is added for you. An event inside a sub-composition happens at the host's `data-start` plus the event's local time in that sub-composition's own timeline, so `data-start = host start + local time`. Move only the audio's `data-start`; leave the picture alone. Source math: if the sound's transient is not at the file's first sample, subtract that lead-in from `data-start` (or trim it with `data-media-start`). Audio follows: nothing links audio to picture, so re-derive after every retime of the host. Owner: `/hyperframes-core`. Limit: no waveform auto-sync; for a beat grid use `hyperframes beats` and place each start on a beat time.
|
|
386
|
+
|
|
387
|
+
## Copy a group of clips to another time
|
|
388
|
+
|
|
389
|
+
```html
|
|
390
|
+
<audio
|
|
391
|
+
id="sfx-click-0"
|
|
392
|
+
src="click.mp3"
|
|
393
|
+
data-start="1.6"
|
|
394
|
+
data-duration="0.07"
|
|
395
|
+
data-track-index="100"
|
|
396
|
+
></audio>
|
|
397
|
+
<audio
|
|
398
|
+
id="sfx-type-0"
|
|
399
|
+
src="typenew.mp3"
|
|
400
|
+
data-start="7.8"
|
|
401
|
+
data-duration="0.57"
|
|
402
|
+
data-track-index="109"
|
|
403
|
+
></audio>
|
|
404
|
+
<audio
|
|
405
|
+
id="sfx-click-0-copy"
|
|
406
|
+
src="click.mp3"
|
|
407
|
+
data-start="41.6"
|
|
408
|
+
data-duration="0.07"
|
|
409
|
+
data-track-index="186"
|
|
410
|
+
></audio>
|
|
411
|
+
<audio
|
|
412
|
+
id="sfx-type-0-copy"
|
|
413
|
+
src="typenew.mp3"
|
|
414
|
+
data-start="47.8"
|
|
415
|
+
data-duration="0.57"
|
|
416
|
+
data-track-index="187"
|
|
417
|
+
></audio>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Timeline math: pick the clips first and say which ones you picked (by id) if the request does not match the file exactly; then add one `delta` to every member's `data-start`, so relative spacing is preserved (here `delta = 40`). Give each copy a new unique `id` and the next unused `data-track-index`; keep `src`, `data-duration`, `data-media-start`, `data-volume` and any `data-automation` as they are. Leave the originals untouched. Check the copies still end inside the composition's duration. Owner: `/hyperframes-core`. Limit: copies of a `<video>` or a sub-composition host follow the same rule, and a copied sub-composition needs its own host `id`.
|
|
421
|
+
|
|
422
|
+
## Add media (image, video, audio)
|
|
423
|
+
|
|
424
|
+
Write what Studio writes when a person drops a file on the timeline, so an agent-added clip behaves the same as a dropped one; the one difference is that video and audio need no `data-duration`. Studio's source of truth is `DEFAULT_TIMELINE_ASSET_DURATION` in `packages/studio/src/utils/studioHelpers.ts` and `buildTimelineAssetInsertHtml` in `packages/studio/src/utils/timelineAssetDrop.ts`; a test keeps this section equal to them.
|
|
425
|
+
|
|
426
|
+
- **Image: `data-duration` is optional and defaults to 3 seconds**, the same as a dropped image, because a still has no length of its own. Write it only for another length. A test keeps the 3 equal to the default in code.
|
|
427
|
+
- **Video and audio: `data-start` is enough.** The length comes from the media itself. An authored `data-duration` shorter than the file is a trim, never a requirement; leave it out unless the request asks for a shorter clip.
|
|
428
|
+
- **Start: the playhead or the requested time, never a silent `0`.** Studio's asset-panel Add uses the playhead time on track `0`; a drop uses the drop point.
|
|
429
|
+
- Give every clip `id`, `class="clip"`, `data-start` and `data-track-index`. Video is `muted playsinline`; audio carries `data-volume="1"`.
|
|
430
|
+
- Then make sure the root composition's `data-duration` is at least the clip's end (`data-start` plus its length: 3 for an image unless you set another, the media's length for video and audio): Studio raises a declared root duration to cover the new clip, so an agent must too, or the clip lies past the end and never plays.
|
|
431
|
+
- **Images and video fill the whole frame**: absolutely positioned at `left: 0; top: 0`, `width` and `height` equal to the composition's `data-width` and `data-height`, `object-fit: contain`. Studio does not know a dropped file's natural size, so it does not centre a smaller one.
|
|
432
|
+
- `z-index` is the number of top-level clips already in that file plus one (at least `1`); later clips stack above earlier ones.
|
|
433
|
+
- Several files dropped together share the drop's track and run end to end.
|
|
434
|
+
|
|
435
|
+
```html
|
|
436
|
+
<img
|
|
437
|
+
id="photo"
|
|
438
|
+
class="clip"
|
|
439
|
+
src="assets/photo.png"
|
|
440
|
+
data-start="4"
|
|
441
|
+
data-track-index="1"
|
|
442
|
+
style="position: absolute; left: 0px; top: 0px; width: 1920px; height: 1080px; object-fit: contain; z-index: 2"
|
|
443
|
+
/>
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
```html
|
|
447
|
+
<video
|
|
448
|
+
id="broll"
|
|
449
|
+
class="clip"
|
|
450
|
+
src="assets/broll.mp4"
|
|
451
|
+
data-start="4"
|
|
452
|
+
data-track-index="2"
|
|
453
|
+
muted
|
|
454
|
+
playsinline
|
|
455
|
+
style="position: absolute; left: 0px; top: 0px; width: 1920px; height: 1080px; object-fit: contain; z-index: 3"
|
|
456
|
+
></video>
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
```html
|
|
460
|
+
<audio
|
|
461
|
+
id="whoosh"
|
|
462
|
+
class="clip"
|
|
463
|
+
src="assets/whoosh.mp3"
|
|
464
|
+
data-start="4"
|
|
465
|
+
data-track-index="3"
|
|
466
|
+
data-volume="1"
|
|
467
|
+
></audio>
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Inside a sub-composition file, `data-start` is scene-local (see `## Align a sound to an on-screen event`). Owner: `/hyperframes-core`.
|
|
471
|
+
|
|
472
|
+
## Swap a media file
|
|
473
|
+
|
|
474
|
+
```html
|
|
475
|
+
<video
|
|
476
|
+
id="hero"
|
|
477
|
+
src="assets/product-v2.mp4"
|
|
478
|
+
data-start="2"
|
|
479
|
+
data-duration="4"
|
|
480
|
+
data-media-start="0"
|
|
481
|
+
data-track-index="0"
|
|
482
|
+
muted
|
|
483
|
+
playsinline
|
|
484
|
+
></video>
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Timeline math: change only `src`. Source math: reset `data-media-start` to the offset you want in the NEW file, and set `data-duration` no longer than the new file's remaining length (probe it with `ffprobe`). Audio follows: a separate `<audio>` that pointed at the old file needs the same `src` swap. Keep `id`, `data-start`, `data-track-index` and any `data-automation` so nothing else moves. Run `lint`: `audio_src_not_found` and `media_src_kind_mismatch` catch a wrong path or kind. Owner: `/hyperframes-core`. Limit: a still swapped for a video (or the reverse) is a tag change, not a swap.
|
|
488
|
+
|
|
489
|
+
## Split a section and change its speed
|
|
490
|
+
|
|
491
|
+
Timeline math: a section that is a sub-composition or a group of clips has no `data-playback-rate` of its own to set; split it by giving each half its own host or clips and shift everything after the cut by the length change. New length of a part = old length / rate. Every later `data-start` (clips, audio, root-timeline tweens) moves by the same delta. Source math: `<video>` and `<audio>` parts use `data-playback-rate` (0.1 to 10, constant) per the constant-speed recipe above, with matching audio. A speed ramp (a rate that changes within one clip) is a `rate` lane in `data-automation` on the `<video>`/`<audio>`; see `docs/reference/speed-ramps`. Say which you did.
|
|
@@ -14,7 +14,7 @@ Every renderable composition needs one root element:
|
|
|
14
14
|
| `data-fps` | No | Optional frame rate hint. CLI render flags can override output fps. |
|
|
15
15
|
| `data-composition-variables` | No | JSON array of variable declarations (on `<html>`). See `variables-and-media.md`. |
|
|
16
16
|
|
|
17
|
-
\*`data-duration` is optional whenever the runtime can auto-infer duration: a registered GSAP timeline, a finite CSS animation, a finite WAAPI `element.animate()`,
|
|
17
|
+
\*`data-duration` is optional whenever the runtime can auto-infer duration: a registered GSAP timeline, a finite CSS animation, a finite WAAPI `element.animate()`, a registered Lottie animation, or timed clips (the root then ends at its latest clip end, and lint only warns `root_composition_duration_derived`). It is **required** for Three.js (no auto-inference), for infinite/unbounded CSS or WAAPI animations, and for any composition with no GSAP timeline, no animation signal and no timed clip with a length. `npx hyperframes lint` enforces this (`root_composition_missing_duration_source`). Per-runtime inference lives in `hyperframes-animation/adapters/`.
|
|
18
18
|
|
|
19
19
|
The root should be `position: relative`, have explicit pixel dimensions, and hide overflow unless intentionally composing outside the frame.
|
|
20
20
|
|
|
@@ -22,19 +22,19 @@ The root should be `position: relative`, have explicit pixel dimensions, and hid
|
|
|
22
22
|
|
|
23
23
|
**`data-start` is what makes an element a clip.** The runtime collects `[data-start]` and drives visibility off that attribute, so any element carrying it is timed.
|
|
24
24
|
|
|
25
|
-
`class="clip"` is a **convention, not a requirement**: the runtime never reads it. Keep writing it
|
|
25
|
+
`class="clip"` is a **convention, not a requirement**: the runtime never reads it. Keep writing it: drop it and the full-frame box collapses unless you supply that layout yourself, Studio uses it as an edit hint, and `lint` warns (`timed_element_missing_clip_class`) when a timed element lacks it. Omit it on `<video>` and `<audio>`.
|
|
26
26
|
|
|
27
27
|
**Nesting is allowed.** A timed element inside a wrapper is still timed, and a timed ancestor clamps its descendants: a child cannot be visible while its timed ancestor is hidden. Direct children of the root get automatic layout (see "Root-level clips get automatic layout" below); nested ones do not, so give them their own positioning.
|
|
28
28
|
|
|
29
|
-
| Attribute | Required
|
|
30
|
-
| ------------------ |
|
|
31
|
-
| `id` | Yes on `<video>`/`<audio>`, else recommended
|
|
32
|
-
| `data-start` | Yes
|
|
33
|
-
| `data-duration` | Required for `div
|
|
34
|
-
| `data-track-index` | No
|
|
35
|
-
| `data-media-start` | No
|
|
36
|
-
| `data-volume` | No
|
|
37
|
-
| `data-has-audio` | No (`<video>` only)
|
|
29
|
+
| Attribute | Required | Meaning |
|
|
30
|
+
| ------------------ | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| `id` | Yes on `<video>`/`<audio>`, else recommended | `lint` errors with `media_missing_id` on media without one, and an id-less `<audio>` is never mixed, so the render is **silent**. Elsewhere it is a warning (`studio_missing_editable_id`): Studio needs a stable edit target, and timeline targets reference it. |
|
|
32
|
+
| `data-start` | Yes | Start time in seconds, or a supported clip-time reference. This attribute is what marks the element as timed. |
|
|
33
|
+
| `data-duration` | Required for `div` and sub-compositions | Duration in seconds. An `img` with `data-start` defaults to 3 s; video/audio default to the source length (less the playback offset, over the rate) once known; an authored value trims. Without any resolvable duration the element has no end and stays visible for the rest of the composition. |
|
|
34
|
+
| `data-track-index` | No | Studio timeline lane, display only. The render never reads it, and clips on one track may overlap in time. Absent, the parser defaults it and Studio lays out one lane per clip. Two `<audio>` elements on the same index that overlap in time raise a `lint` warning. |
|
|
35
|
+
| `data-media-start` | No | Offset into the media source, in seconds. |
|
|
36
|
+
| `data-volume` | No | Static audio gain, default `1` (0 dB). `0` is silence and values above `1` boost, up to `3.98` (+12 dB) — Studio's fader writes this. For fades and ducking, use the `data-automation` volume lane (see `creator-editing-recipes.md`). |
|
|
37
|
+
| `data-has-audio` | No (`<video>` only) | `"true"` to declare the video carries an audio track when auto-detection would miss it. |
|
|
38
38
|
|
|
39
39
|
**The visibility window is half-open: `[start, start + duration)`.** A clip shows while `start ≤ t < start + duration` and is hidden at exactly `t = start + duration`. Land an animation's resolved end state slightly **before** `data-duration`, not on it, or its last frame is never rendered. Two clips can therefore be authored back to back (`b.start === a.start + a.duration`) with no overlapping frame.
|
|
40
40
|
|
|
@@ -15,18 +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 `hyperframes-animation` skill for tween syntax, position parameters, eases, and performance rules.
|
|
19
|
-
|
|
20
|
-
### Duration Contract For Non-GSAP Runtimes
|
|
21
|
-
|
|
22
|
-
The render engine needs a positive total duration before it will capture a single frame — without one, capture fails outright with "Composition has zero duration." A GSAP timeline supplies this automatically. CSS, WAAPI, and Lottie compositions have no timeline object, so the runtime infers duration itself:
|
|
23
|
-
|
|
24
|
-
- **CSS**: longest `animation-delay` + `animation-duration` × finite `animation-iteration-count` across animated elements (offset by each element's `data-start`). `animation-iteration-count: infinite` cannot be inferred.
|
|
25
|
-
- **WAAPI**: longest `element.animate()` effect's `getComputedTiming().endTime`. Infinite `iterations` cannot be inferred.
|
|
26
|
-
- **Lottie**: the registered animation's native length (`totalFrames / frameRate`, or the dotLottie player's own `duration`) — always finite regardless of `loop`.
|
|
27
|
-
- **Three.js**: **not inferable**. The `three` adapter only forwards time via `hf-seek` — it has no `AnimationClip`/`AnimationMixer` inspection.
|
|
28
|
-
|
|
29
|
-
`data-duration` on the root `[data-composition-id]` element is therefore optional whenever every non-GSAP animation on the page is finite (CSS/WAAPI with finite iteration counts, or Lottie). It is **required** when: the composition has an infinite/unbounded CSS or WAAPI animation, the composition uses Three.js, or there is no GSAP timeline and no animation signal at all for any adapter to discover. `npx hyperframes lint` enforces exactly this (`root_composition_missing_duration_source`) — see the runtime/adapter-specific docs under `hyperframes-animation/adapters/` for the full contract per runtime.
|
|
18
|
+
Use the `hyperframes-animation` skill for tween syntax, position parameters, eases, and performance rules. Non-GSAP duration inference lives in `hyperframes-animation/adapters/`.
|
|
30
19
|
|
|
31
20
|
## Determinism Rules
|
|
32
21
|
|
|
@@ -40,7 +29,7 @@ Rendered frames must be reproducible from the requested time. Do **not** use any
|
|
|
40
29
|
|
|
41
30
|
Also avoid:
|
|
42
31
|
|
|
43
|
-
- Tweening `display
|
|
32
|
+
- Tweening `display`, raw `visibility`, or `autoAlpha` **on a clip element**: HyperFrames timing owns a clip's visibility, and `lint` rejects it (`gsap_animates_clip_element`). Fade with `opacity`, or tween a child wrapper. Do not tween `class="clip"`.
|
|
44
33
|
- There is no fixed allowlist of animatable properties. `lint` enforces a **denylist**, so `filter`, `clipPath`, `strokeDashoffset`, `width`, `height` and similar are all legitimate targets. Prefer transforms and opacity where you have the choice, for performance rather than correctness. The per-runtime detail lives in `hyperframes-animation/adapters/`.
|
|
45
34
|
- Animating the same property on the same element from multiple timelines at the same time — GSAP's overwrite behavior is order-dependent and can flip between renders.
|
|
46
35
|
|
|
@@ -62,9 +51,3 @@ Build the visible end-state in static HTML and CSS first, then animate from/to t
|
|
|
62
51
|
- **Do not** use `<br>` in body text. Forced breaks ignore the actual rendered font width and produce an extra break when the line already wraps naturally, causing overlap. Let text wrap via `max-width`. Exception: short display titles where each word is deliberately on its own line.
|
|
63
52
|
- **Transformed elements must be block-level + sized.** `transform`/`scaleX`/`scaleY` is a no-op on an inline `<span>`, and scaling an auto-width (0px) element shows nothing → invisible bars/fills. Give them `display: block`/`inline-block`/flex-item **and** a real `width`/`height` (e.g. `width: 100%` inside a sized parent). _(Silent — automated gates may miss it.)_
|
|
64
53
|
- **Absolutely-positioned decoratives that pulse or overshoot** (`yoyo` scale, `back.out`) need clearance at their **peak** size and must not straddle an `overflow: hidden` edge — else they overlap a neighbor or get clipped. Position for the largest frame, not the resting one. _(silent.)_
|
|
65
|
-
|
|
66
|
-
## Why This Matters
|
|
67
|
-
|
|
68
|
-
The renderer takes a time value and produces a pixel buffer. There is no notion of "playback" — every frame is a fresh seek. Any state that depends on having reached this frame _through_ a prior frame (timers, accumulated state, event-driven animations) will desync when the renderer samples out of order or in parallel.
|
|
69
|
-
|
|
70
|
-
If you find yourself reaching for `setTimeout`, `requestAnimationFrame`, or `addEventListener` to drive a visual, rebuild it as a tween on the timeline instead.
|
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
For full-frame motion (continuous backgrounds, color washes, full-bleed visual states that span multiple clips), prefer a **shared background layer + transparent timed content layers** over stacked opaque scene backgrounds.
|
|
4
4
|
|
|
5
|
-
## Why
|
|
6
|
-
|
|
7
|
-
Stacking opaque scene divs means every scene change has to repaint the entire frame, every cross-scene visual continuity has to be faked, and every "global" state (a hue shift, a vignette, a film grain) has to be duplicated on every scene. A shared background layer driven by the seekable timeline gives you one continuous visual surface and makes scenes themselves cheap and transparent.
|
|
8
|
-
|
|
9
5
|
## Pattern
|
|
10
6
|
|
|
11
7
|
```html
|
|
@@ -48,7 +44,6 @@ Stacking opaque scene divs means every scene change has to repaint the entire fr
|
|
|
48
44
|
</div>
|
|
49
45
|
|
|
50
46
|
<script>
|
|
51
|
-
window.__timelines = window.__timelines || {};
|
|
52
47
|
const tl = gsap.timeline({ paused: true });
|
|
53
48
|
|
|
54
49
|
// Drive the shared background from the seekable timeline.
|
|
@@ -70,7 +65,3 @@ Stacking opaque scene divs means every scene change has to repaint the entire fr
|
|
|
70
65
|
- **Drive global state from the shared layer.** Hue shifts, vignettes, grain, film-look filters — animate them once on the shared layer, not per-scene.
|
|
71
66
|
- **Do not animate visibility on `.clip` elements.** HyperFrames already shows/hides clips based on `data-start` and `data-duration`. Animating `display` / `visibility` on the clip itself races with the framework's own show/hide. Animate a _child wrapper_ inside the clip instead.
|
|
72
67
|
- **Verify intentional overflow with snapshots.** Before adding `data-layout-allow-overflow` to silence an inspect warning, run `npx hyperframes snapshot` and confirm the overflow is what you want.
|
|
73
|
-
|
|
74
|
-
## When Not to Use This Pattern
|
|
75
|
-
|
|
76
|
-
If scenes really are visually disjoint — hard cuts between distinct color worlds with no continuity — the stacked-opaque pattern is fine. The shared-background pattern is for compositions where the background **is part of the motion language**, not just backdrop.
|
|
@@ -48,8 +48,7 @@ So `<template>` is not just a wrapper — it is the **transport container**. If
|
|
|
48
48
|
<template>
|
|
49
49
|
<!-- EVERYTHING the runtime needs goes here: styles, markup, scripts -->
|
|
50
50
|
<style>
|
|
51
|
-
/* Root: style by #root, never a class.
|
|
52
|
-
data-composition-id, so a class on the root stops matching — see Pitfall 3.) */
|
|
51
|
+
/* Root: style by #root, never a class. lint: subcomposition_root_styled_by_class. See Pitfall 3. */
|
|
53
52
|
#root {
|
|
54
53
|
position: absolute;
|
|
55
54
|
inset: 0;
|
|
@@ -63,7 +62,6 @@ So `<template>` is not just a wrapper — it is the **transport container**. If
|
|
|
63
62
|
</div>
|
|
64
63
|
|
|
65
64
|
<script>
|
|
66
|
-
window.__timelines = window.__timelines || {};
|
|
67
65
|
const tl = gsap.timeline({ paused: true });
|
|
68
66
|
// ... build timeline ...
|
|
69
67
|
window.__timelines["data-chart"] = tl;
|
|
@@ -77,7 +75,7 @@ Contrast with **standalone** compositions, which put the root directly in `<body
|
|
|
77
75
|
|
|
78
76
|
## Common pitfalls that pass static checks but break at render
|
|
79
77
|
|
|
80
|
-
Static file checks cannot prove the **cross-file mount contract**. These failures appear only when the runtime mounts the sub-composition.
|
|
78
|
+
Static file checks cannot prove the **cross-file mount contract**. These failures appear only when the runtime mounts the sub-composition.
|
|
81
79
|
|
|
82
80
|
### Pitfall 1 — `<style>` in `<head>` instead of inside `<template>`
|
|
83
81
|
|
|
@@ -137,68 +135,7 @@ Static file checks cannot prove the **cross-file mount contract**. These failure
|
|
|
137
135
|
|
|
138
136
|
### Pitfall 3 — Styling the root by a class instead of `#root`
|
|
139
137
|
|
|
140
|
-
|
|
141
|
-
<!-- ❌ WRONG — class on the root, stylesheet keyed off it -->
|
|
142
|
-
<template>
|
|
143
|
-
<style>
|
|
144
|
-
.frame {
|
|
145
|
-
position: absolute;
|
|
146
|
-
inset: 0;
|
|
147
|
-
background: #faf9f5;
|
|
148
|
-
}
|
|
149
|
-
.frame .title {
|
|
150
|
-
font-size: 120px;
|
|
151
|
-
}
|
|
152
|
-
</style>
|
|
153
|
-
<div id="root" class="frame" data-composition-id="03-scene" ...>
|
|
154
|
-
<div class="title">…</div>
|
|
155
|
-
</div>
|
|
156
|
-
</template>
|
|
157
|
-
|
|
158
|
-
<!-- ✅ RIGHT — root styled by #root, descendants by plain selectors -->
|
|
159
|
-
<template>
|
|
160
|
-
<style>
|
|
161
|
-
#root {
|
|
162
|
-
position: absolute;
|
|
163
|
-
inset: 0;
|
|
164
|
-
background: #faf9f5;
|
|
165
|
-
}
|
|
166
|
-
.title {
|
|
167
|
-
font-size: 120px;
|
|
168
|
-
}
|
|
169
|
-
</style>
|
|
170
|
-
<div id="root" data-composition-id="03-scene" ...>
|
|
171
|
-
<div class="title">…</div>
|
|
172
|
-
</div>
|
|
173
|
-
</template>
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Why this happens:** when sub-compositions are inlined into one composited render, the compiler **scopes each file's CSS to its own `data-composition-id`** so scenes can't leak styles into each other: every rule `S` becomes `[data-composition-id="<id>"] S` (a _descendant_ selector). A rule whose leftmost selector is the **root's own class** (`.frame`) therefore becomes `[data-composition-id="<id>"] .frame`, which cannot match the scoped element itself. `#root` is special-cased by the scoper and keeps matching the root; plain descendant selectors (`.title`) match normally. The per-scene class namespace is also just redundant, since the `data-composition-id` scope already isolates each scene's styles.
|
|
177
|
-
|
|
178
|
-
**What actually happens today:** the render no longer drops these rules. Since #1886 the producer preserves the authored root as a `data-hf-inner-root` wrapper _inside_ the scoped element, so a class on the root still matches as a descendant and preview and render agree. The regression is pinned by `packages/producer/tests/sub-comp-class-selector/`.
|
|
179
|
-
|
|
180
|
-
**So why still use `#root`?** Because `lint` rejects the class form outright (`subcomposition_root_styled_by_class`, **error**), and it is the pattern the registry blocks model (e.g. `apple-money-count`). Treat this as a lint constraint you must satisfy, not as a render bug you are avoiding. If you inherited a composition that styles its root by class, it renders correctly; you still have to convert it to `#root` to get a green `lint`.
|
|
181
|
-
|
|
182
|
-
### Verification checklist before render
|
|
183
|
-
|
|
184
|
-
```bash
|
|
185
|
-
# For every sub-composition file in compositions/:
|
|
186
|
-
# 1) <style> + <script> + main markup all live INSIDE <template>
|
|
187
|
-
grep -n "<style\|<script\|<template" compositions/<scene>.html
|
|
188
|
-
# → first <style>/<script>/<div data-composition-id> should be AFTER <template>, before </template>
|
|
189
|
-
|
|
190
|
-
# 2) host data-composition-id == internal data-composition-id == window.__timelines key
|
|
191
|
-
grep "data-composition-id" index.html
|
|
192
|
-
grep "data-composition-id\|__timelines\[" compositions/<scene>.html
|
|
193
|
-
# → all three strings must match exactly per scene
|
|
194
|
-
|
|
195
|
-
# 3) the root is styled by #root, not by a class on the data-composition-id element
|
|
196
|
-
grep -n 'data-composition-id=' compositions/<scene>.html
|
|
197
|
-
# → that element should NOT also carry a class="…" that the <style> keys off
|
|
198
|
-
# (e.g. `.frame { … }`); scoping drops it. Style the root via #root. See Pitfall 3.
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
For the runtime end-to-end check (a fast `snapshot` pass + per-scene frame eyeball), see the **Visual smoke test** step in `hyperframes-cli`'s Minimum Completion Gate — that is the only gate that catches these three pitfalls.
|
|
138
|
+
`lint` still errors (`subcomposition_root_styled_by_class`) if a sub-composition styles the host root's own class. Style the root with `#root`.
|
|
202
139
|
|
|
203
140
|
## What HyperFrames Does With the Sub-Composition
|
|
204
141
|
|
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
HyperFrames `init --tailwind` uses the Tailwind browser runtime pinned by the scaffold. Treat it as Tailwind v4, not Studio's Tailwind v3 setup.
|
|
4
4
|
|
|
5
|
-
## When To Use
|
|
6
|
-
|
|
7
|
-
- The project was scaffolded with `npx hyperframes init --tailwind`.
|
|
8
|
-
- `index.html` contains `window.__tailwindReady`.
|
|
9
|
-
- The task asks for Tailwind utility classes, `@theme`, custom utilities, or v3-to-v4 fixes in a composition.
|
|
10
|
-
- Rendered frames have missing Tailwind styles or frame-0 flashes.
|
|
11
|
-
|
|
12
5
|
## Version Contract
|
|
13
6
|
|
|
14
7
|
- **Pinned: `@tailwindcss/browser@4.2.4`** (source of truth: `packages/cli/src/commands/init.ts` `TAILWIND_BROWSER_VERSION`).
|
|
@@ -44,7 +37,7 @@ Avoid v3-only patterns in browser-runtime compositions:
|
|
|
44
37
|
|
|
45
38
|
Do not add `tailwind.config.js` only for composition colors, fonts, spacing, or utilities. Use `@theme` and `@utility`.
|
|
46
39
|
|
|
47
|
-
|
|
40
|
+
**`@config` / `@plugin` abort the browser compile.** The pinned `@tailwindcss/browser` build does not support JS config or plugins. Theme and utilities stay in a `text/tailwindcss` block.
|
|
48
41
|
|
|
49
42
|
## Composition Pattern
|
|
50
43
|
|
|
@@ -109,15 +102,3 @@ npx hyperframes check
|
|
|
109
102
|
# Render proof — frame 0 must NOT flash unstyled content. Preview alone can hide this.
|
|
110
103
|
npx hyperframes render . --workers 1 --quality draft --output tailwind-proof.mp4
|
|
111
104
|
```
|
|
112
|
-
|
|
113
|
-
## Quick Debug Checklist
|
|
114
|
-
|
|
115
|
-
When Tailwind styles don't apply in a render, check in order:
|
|
116
|
-
|
|
117
|
-
1. Project scaffolded with `npx hyperframes init --tailwind`?
|
|
118
|
-
2. `index.html` `<head>` has `<script src="…@tailwindcss/browser@4.2.4…">` (not `cdn.tailwindcss.com`)?
|
|
119
|
-
3. `window.__tailwindReady` Promise present in `<head>`?
|
|
120
|
-
4. No v3 directives (`@tailwind base/components/utilities`) in the file?
|
|
121
|
-
5. Tokens moved from `tailwind.config.js` to `@theme` (or `@config` reference for v3 migration)?
|
|
122
|
-
6. Every render-critical class appears as a complete static token (no `bg-${color}-500` style assembly)?
|
|
123
|
-
7. Re-run `npx hyperframes check`, then the render proof above.
|
|
@@ -10,7 +10,7 @@ A clip is any DOM element with `data-start` and, where required, `data-duration`
|
|
|
10
10
|
- **Sub-composition hosts** — `<div>` with `data-composition-src`. Always require `data-duration`.
|
|
11
11
|
- **Video clips** — `<video>` with `muted` and `playsinline`. Duration can default to media length.
|
|
12
12
|
- **Audio clips** — `<audio>`. Duration can default to media length.
|
|
13
|
-
- **Image clips** — `<img>`.
|
|
13
|
+
- **Image clips** — `<img>`. `data-duration` is optional and defaults to 3 seconds; write it only for another length.
|
|
14
14
|
|
|
15
15
|
Add `class="clip"` to authored visual clips. The runtime does not read it, but the scaffold's shared `.clip { position: absolute; inset: 0 }` rule is what gives a scene its full-frame box, Studio treats it as an edit hint, and `lint` warns without it.
|
|
16
16
|
|
|
@@ -28,11 +28,7 @@ The one place the value carries meaning: two `<audio>` elements that share a tra
|
|
|
28
28
|
|
|
29
29
|
## Picking a Track Index
|
|
30
30
|
|
|
31
|
-
Purely a readability choice for whoever opens the file in Studio. Common patterns
|
|
32
|
-
|
|
33
|
-
- **Track 0** — base video (e.g. an A-roll).
|
|
34
|
-
- **Track 1+** — visual scenes, overlays, captions.
|
|
35
|
-
- **Higher tracks (e.g. 10+)**: audio clips, separated from visual tracks.
|
|
31
|
+
Purely a readability choice for whoever opens the file in Studio. Common patterns, owned by `/hyperframes-studio` (one caption track, one element kind per track).
|
|
36
32
|
|
|
37
33
|
When adding a clip to an existing composition, set its `data-start`/`data-duration` against the clips around it. You do not need to hunt for a free lane, and you never need to renumber tracks after a retime.
|
|
38
34
|
|
|
@@ -58,11 +58,11 @@ document.getElementById("title").textContent = title;
|
|
|
58
58
|
### Two JSON Shapes (Easy to Confuse)
|
|
59
59
|
|
|
60
60
|
- `data-composition-variables` is an **array of declarations** (the schema): `[{id, type, label, default}, ...]`
|
|
61
|
-
- `--variables` and `data-variable-values` are **objects keyed by id** (the values): `{
|
|
61
|
+
- `--variables` and `data-variable-values` are **objects keyed by id** (the values): `{"title":"Q4","accent":"#fff"}`
|
|
62
62
|
|
|
63
63
|
## Media
|
|
64
64
|
|
|
65
|
-
**`<video>`/`<audio>` work at any nesting depth, including inside a sub-composition `<template>` or a wrapper `<div>`.** The runtime discovers media with a flat `document.querySelectorAll("video, audio")`, resolves each element's host composition via `element.closest("[data-composition-id]")`, and rebases its local `data-start` by the accumulated absolute start of every ancestor composition
|
|
65
|
+
**`<video>`/`<audio>` work at any nesting depth, including inside a sub-composition `<template>` or a wrapper `<div>`.** The runtime discovers media with a flat `document.querySelectorAll("video, audio")`, resolves each element's host composition via `element.closest("[data-composition-id]")`, and rebases its local `data-start` by the accumulated absolute start of every ancestor composition. A host at `2` with child media at `2` therefore starts that media at root time `4`, consistently in preview, snapshot, extraction, and render. Legacy projects that deliberately authored a media start in root time must mark that element with `data-hf-media-start-basis="global"`; never infer the basis from overlapping numbers. New compositions should always use scene-local `data-start`. If a panel renders blank after a render, capture a per-frame `snapshot` and treat it as render-blocking.
|
|
66
66
|
|
|
67
67
|
The one real constraint is about **timelines, not media placement**: a sub-composition timeline **cannot reach or animate host elements** — neither `document.querySelector("#host-id")` nor a gsap selector string (`tl.to("#host-id", …)`) resolves across the boundary; a sub-comp timeline only drives its own subtree. So if a media element lives at the host root, **its per-scene motion (scale/opacity/morph/tilt/breathing) must be authored on the MAIN timeline in `index.html`, at GLOBAL time** (scene-local time + the scene slot's `data-start`). Keeping the media inside the scene sub-comp instead lets that sub-comp's own timeline animate it with scene-local time. For 3D tilt without a perspective parent, use gsap `transformPerspective` on the element. See `composition-patterns.md` archetype B.
|
|
68
68
|
|
|
@@ -100,7 +100,7 @@ Video elements must be muted and inline. Audio must be a separate `<audio>` elem
|
|
|
100
100
|
- **Never** add `crossorigin` to `<video>`/`<audio>`. `lint` rejects it unconditionally (`media_crossorigin_breaks_preview`, error) because a media host without `Access-Control-Allow-Origin` then fails silently in preview while renders still work, hiding the bug. There is no suppression, so this holds even for the canvas/WebGL/WebAudio readback case.
|
|
101
101
|
- **Every `<audio>` needs an `id`.** The mixer selects `audio[id][src]`, so an id-less `<audio>` is never mixed and the render is **silent**. `lint` catches it as `media_missing_id`.
|
|
102
102
|
- Audio always lives on a separate `<audio>` element — even if its source file is the same as a `<video>`. The `<video>` is muted; the `<audio>` carries sound.
|
|
103
|
-
- For volume fades
|
|
103
|
+
- For volume fades and ducking, use the `data-automation` volume lane; the exact form is in `creator-editing-recipes.md`. `data-volume` is the static baseline. A timeline `volume` tween is ignored when a lane is present.
|
|
104
104
|
|
|
105
105
|
For media duration: `<video>` and `<audio>` can omit `data-duration` if the media's intrinsic length is known and you want the full clip. Otherwise provide `data-duration` explicitly.
|
|
106
106
|
|
|
@@ -3,6 +3,8 @@ name: hyperframes-creative
|
|
|
3
3
|
description: Non-animation creative direction for HyperFrames videos. Use for design spec (frame.md / design.md) handling, palettes, typography, narration, beat planning, audio-reactive visuals, composition patterns, and brand / style decisions. For atomic motion patterns and scene blueprints, use `hyperframes-animation`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
**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.
|
|
7
|
+
|
|
6
8
|
# HyperFrames Creative
|
|
7
9
|
|
|
8
10
|
Brand, pacing, style, narration, and composition direction. Use after the technical contract from `hyperframes-core` is in place.
|