@officexapp/vidfarm-devcli 0.21.10
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/.agents/skills/dollarplatoon-skill/SKILL.md +1227 -0
- package/.agents/skills/editor-capabilities/SKILL.md +182 -0
- package/.agents/skills/editor-capabilities/references/re-theme-walkthrough.md +58 -0
- package/.agents/skills/embedded-captions/CATALOG.md +93 -0
- package/.agents/skills/embedded-captions/SKILL.md +286 -0
- package/.agents/skills/embedded-captions/assets/brand/CDPR-fankit-terms.txt +35 -0
- package/.agents/skills/embedded-captions/assets/brand/cyberpunk-widths.json +115 -0
- package/.agents/skills/embedded-captions/assets/fonts/char-widths.json +2211 -0
- package/.agents/skills/embedded-captions/assets/strokefonts/HersheyScript1.svg +242 -0
- package/.agents/skills/embedded-captions/assets/strokefonts/HersheyScriptMed.svg +242 -0
- package/.agents/skills/embedded-captions/dna/README.md +148 -0
- package/.agents/skills/embedded-captions/dna/chrome.json +68 -0
- package/.agents/skills/embedded-captions/dna/cream.json +69 -0
- package/.agents/skills/embedded-captions/dna/documentary.json +62 -0
- package/.agents/skills/embedded-captions/dna/editorial.json +70 -0
- package/.agents/skills/embedded-captions/dna/glitch.json +82 -0
- package/.agents/skills/embedded-captions/dna/ink.json +65 -0
- package/.agents/skills/embedded-captions/dna/keynote.json +62 -0
- package/.agents/skills/embedded-captions/dna/loud.json +75 -0
- package/.agents/skills/embedded-captions/dna/neon.json +58 -0
- package/.agents/skills/embedded-captions/dna/velocity.json +89 -0
- package/.agents/skills/embedded-captions/modes/cinematic/README.md +48 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/champion/spec.md +98 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/champion/template.html +188 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/memory-wall/spec.md +134 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/memory-wall/template.html +179 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/portrait-header/spec.md +81 -0
- package/.agents/skills/embedded-captions/modes/cinematic/_archive/portrait-header/template.html +170 -0
- package/.agents/skills/embedded-captions/modes/cinematic/cinematic-cream/spec.md +16 -0
- package/.agents/skills/embedded-captions/modes/cinematic/cinematic-cream/template.html +226 -0
- package/.agents/skills/embedded-captions/modes/cinematic/engine.html +355 -0
- package/.agents/skills/embedded-captions/modes/standard/_anatomy.md +233 -0
- package/.agents/skills/embedded-captions/modes/standard/_motion.md +192 -0
- package/.agents/skills/embedded-captions/modes/standard/fonts/build-fonts-css.cjs +97 -0
- package/.agents/skills/embedded-captions/references/aesthetic-principles.md +168 -0
- package/.agents/skills/embedded-captions/references/anti-patterns.md +188 -0
- package/.agents/skills/embedded-captions/references/bespoke-vs-presets.md +178 -0
- package/.agents/skills/embedded-captions/references/caption-grouping.md +130 -0
- package/.agents/skills/embedded-captions/references/composition-craft.md +522 -0
- package/.agents/skills/embedded-captions/references/direction-catalog.md +138 -0
- package/.agents/skills/embedded-captions/references/example-renders/champion.html +371 -0
- package/.agents/skills/embedded-captions/references/example-renders/memory-wall.html +334 -0
- package/.agents/skills/embedded-captions/references/failure-modes.md +145 -0
- package/.agents/skills/embedded-captions/references/layout-heuristics.md +238 -0
- package/.agents/skills/embedded-captions/references/motion-vocabulary.md +148 -0
- package/.agents/skills/embedded-captions/references/rail.md +68 -0
- package/.agents/skills/embedded-captions/references/reference-bar.md +47 -0
- package/.agents/skills/embedded-captions/references/scene-types.md +94 -0
- package/.agents/skills/embedded-captions/references/test-set.md +66 -0
- package/.agents/skills/embedded-captions/references/typographic-moves.md +266 -0
- package/.agents/skills/embedded-captions/references/typography-presets.md +63 -0
- package/.agents/skills/embedded-captions/scripts/audio-envelope.cjs +95 -0
- package/.agents/skills/embedded-captions/scripts/check-occlusion.cjs +250 -0
- package/.agents/skills/embedded-captions/scripts/check-overflow.cjs +194 -0
- package/.agents/skills/embedded-captions/scripts/check-rail-climax.cjs +233 -0
- package/.agents/skills/embedded-captions/scripts/check-timing.cjs +173 -0
- package/.agents/skills/embedded-captions/scripts/fill-timings.cjs +124 -0
- package/.agents/skills/embedded-captions/scripts/fit-fonts.cjs +158 -0
- package/.agents/skills/embedded-captions/scripts/gen-stroke-path.py +46 -0
- package/.agents/skills/embedded-captions/scripts/inject-fonts.cjs +169 -0
- package/.agents/skills/embedded-captions/scripts/lib-dna.cjs +201 -0
- package/.agents/skills/embedded-captions/scripts/make-cinematic.cjs +1205 -0
- package/.agents/skills/embedded-captions/scripts/make-composition.cjs +404 -0
- package/.agents/skills/embedded-captions/scripts/make-theme.cjs +8781 -0
- package/.agents/skills/embedded-captions/scripts/matte.cjs +294 -0
- package/.agents/skills/embedded-captions/scripts/measure-layout.cjs +293 -0
- package/.agents/skills/embedded-captions/scripts/prepare.sh +39 -0
- package/.agents/skills/embedded-captions/scripts/preview-frames.cjs +268 -0
- package/.agents/skills/embedded-captions/scripts/render-and-composite.sh +509 -0
- package/.agents/skills/embedded-captions/scripts/render-theme.sh +34 -0
- package/.agents/skills/embedded-captions/scripts/safe-zones.cjs +813 -0
- package/.agents/skills/embedded-captions/scripts/transcribe.cjs +349 -0
- package/.agents/skills/embedded-captions/themes/PORTING.md +49 -0
- package/.agents/skills/embedded-captions/themes/README.md +244 -0
- package/.agents/skills/embedded-captions/themes/anchor.json +27 -0
- package/.agents/skills/embedded-captions/themes/arcade.json +51 -0
- package/.agents/skills/embedded-captions/themes/aurora.json +41 -0
- package/.agents/skills/embedded-captions/themes/biolume.json +35 -0
- package/.agents/skills/embedded-captions/themes/brush.json +74 -0
- package/.agents/skills/embedded-captions/themes/chalkboard.json +52 -0
- package/.agents/skills/embedded-captions/themes/dossier.json +56 -0
- package/.agents/skills/embedded-captions/themes/graffiti.json +62 -0
- package/.agents/skills/embedded-captions/themes/hologram.json +41 -0
- package/.agents/skills/embedded-captions/themes/inkwater.json +43 -0
- package/.agents/skills/embedded-captions/themes/laser.json +46 -0
- package/.agents/skills/embedded-captions/themes/lastpage.json +33 -0
- package/.agents/skills/embedded-captions/themes/neonsign.json +53 -0
- package/.agents/skills/embedded-captions/themes/nightcity.json +56 -0
- package/.agents/skills/embedded-captions/themes/ordnance.json +54 -0
- package/.agents/skills/embedded-captions/themes/papercut.json +37 -0
- package/.agents/skills/embedded-captions/themes/popup.json +46 -0
- package/.agents/skills/embedded-captions/themes/ransom.json +62 -0
- package/.agents/skills/embedded-captions/themes/scoreboard.json +54 -0
- package/.agents/skills/embedded-captions/themes/spectrum.json +46 -0
- package/.agents/skills/embedded-captions/themes/stardust.json +29 -0
- package/.agents/skills/embedded-captions/themes/stomp.json +43 -0
- package/.agents/skills/embedded-captions/themes/terminal.json +49 -0
- package/.agents/skills/embedded-captions/themes/thunder.json +44 -0
- package/.agents/skills/embedded-captions/themes/transit.json +44 -0
- package/.agents/skills/embedded-captions/themes/vhs.json +47 -0
- package/.agents/skills/faceless-explainer/SKILL.md +209 -0
- package/.agents/skills/faceless-explainer/references/cut-catalog.md +215 -0
- package/.agents/skills/faceless-explainer/references/motion-language.md +156 -0
- package/.agents/skills/faceless-explainer/references/story-design.md +248 -0
- package/.agents/skills/faceless-explainer/references/visual-design.md +146 -0
- package/.agents/skills/faceless-explainer/scripts/assemble-index.mjs +570 -0
- package/.agents/skills/faceless-explainer/scripts/audio.mjs +260 -0
- package/.agents/skills/faceless-explainer/scripts/build-frame.mjs +536 -0
- package/.agents/skills/faceless-explainer/scripts/captions.mjs +508 -0
- package/.agents/skills/faceless-explainer/scripts/lib/assets.mjs +55 -0
- package/.agents/skills/faceless-explainer/scripts/lib/dimensions.mjs +45 -0
- package/.agents/skills/faceless-explainer/scripts/lib/storyboard.mjs +249 -0
- package/.agents/skills/faceless-explainer/scripts/lib/tokens.mjs +204 -0
- package/.agents/skills/faceless-explainer/scripts/lib/transition-registry.mjs +38 -0
- package/.agents/skills/faceless-explainer/scripts/lib/transitions.json +71 -0
- package/.agents/skills/faceless-explainer/scripts/transitions.mjs +320 -0
- package/.agents/skills/faceless-explainer/sub-agents/frame-worker.md +75 -0
- package/.agents/skills/farmville-saas-ux/SKILL.md +156 -0
- package/.agents/skills/farmville-saas-ux/assets/starter.html +294 -0
- package/.agents/skills/farmville-saas-ux/references/components.md +340 -0
- package/.agents/skills/farmville-saas-ux/references/porting-guide.md +121 -0
- package/.agents/skills/farmville-saas-ux/references/tokens.md +271 -0
- package/.agents/skills/flockposter/LICENSE +17 -0
- package/.agents/skills/flockposter/README.md +72 -0
- package/.agents/skills/flockposter/SKILL.md +562 -0
- package/.agents/skills/flockposter/examples/cli-instagram-reel.sh +21 -0
- package/.agents/skills/flockposter/examples/cli-multi-platform.json +69 -0
- package/.agents/skills/flockposter/examples/cli-tiktok-upload-only.sh +22 -0
- package/.agents/skills/flockposter/examples/cli-x-thread.sh +17 -0
- package/.agents/skills/flockposter/examples/cli-youtube-short.sh +21 -0
- package/.agents/skills/flockposter/examples/public-api-instagram-reel.json +28 -0
- package/.agents/skills/general-video/SKILL.md +143 -0
- package/.agents/skills/hyperframes/SKILL.md +160 -0
- package/.agents/skills/hyperframes-animation/SKILL.md +84 -0
- package/.agents/skills/hyperframes-animation/adapters/animate-text.md +64 -0
- package/.agents/skills/hyperframes-animation/adapters/animejs.md +114 -0
- package/.agents/skills/hyperframes-animation/adapters/css-animations.md +143 -0
- package/.agents/skills/hyperframes-animation/adapters/gsap-easing-and-stagger.md +118 -0
- package/.agents/skills/hyperframes-animation/adapters/gsap-timeline-and-labels.md +96 -0
- package/.agents/skills/hyperframes-animation/adapters/gsap-transforms-and-perf.md +96 -0
- package/.agents/skills/hyperframes-animation/adapters/gsap.md +105 -0
- package/.agents/skills/hyperframes-animation/adapters/html-in-canvas-patterns.md +507 -0
- package/.agents/skills/hyperframes-animation/adapters/lottie.md +117 -0
- package/.agents/skills/hyperframes-animation/adapters/three.md +131 -0
- package/.agents/skills/hyperframes-animation/adapters/typegpu.md +178 -0
- package/.agents/skills/hyperframes-animation/adapters/waapi.md +101 -0
- package/.agents/skills/hyperframes-animation/blueprints/comparison-split.md +27 -0
- package/.agents/skills/hyperframes-animation/blueprints/constellation-hub.md +44 -0
- package/.agents/skills/hyperframes-animation/blueprints/cta-morph-press.md +28 -0
- package/.agents/skills/hyperframes-animation/blueprints/cursor-ui-demo.md +57 -0
- package/.agents/skills/hyperframes-animation/blueprints/dataviz-countup.md +46 -0
- package/.agents/skills/hyperframes-animation/blueprints/device-surface-showcase.md +53 -0
- package/.agents/skills/hyperframes-animation/blueprints/grid-card-assemble.md +66 -0
- package/.agents/skills/hyperframes-animation/blueprints/kinetic-type-beats.md +78 -0
- package/.agents/skills/hyperframes-animation/blueprints/logo-assemble-lockup.md +69 -0
- package/.agents/skills/hyperframes-animation/blueprints/overwhelm-surround.md +28 -0
- package/.agents/skills/hyperframes-animation/blueprints/spatial-pan-stations.md +37 -0
- package/.agents/skills/hyperframes-animation/blueprints/ticker-takeover.md +29 -0
- package/.agents/skills/hyperframes-animation/blueprints/titlecard-reveal.md +42 -0
- package/.agents/skills/hyperframes-animation/blueprints/typewriter-reveal.md +51 -0
- package/.agents/skills/hyperframes-animation/blueprints/video-text-pivot.md +30 -0
- package/.agents/skills/hyperframes-animation/blueprints-index.md +146 -0
- package/.agents/skills/hyperframes-animation/examples/assets/avatars/02.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/assets/brands/github.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/assets/brands/nvidia.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/assets/brands/visa.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/assets/brands/zoominfo.avif +0 -0
- package/.agents/skills/hyperframes-animation/examples/brand-reveal-assemble-zoom.html +382 -0
- package/.agents/skills/hyperframes-animation/examples/comparison-split-cards.html +649 -0
- package/.agents/skills/hyperframes-animation/examples/concept-demo-decode-pan.html +520 -0
- package/.agents/skills/hyperframes-animation/examples/cta-morph-press.html +468 -0
- package/.agents/skills/hyperframes-animation/examples/cta-orbit-collapse.html +1298 -0
- package/.agents/skills/hyperframes-animation/examples/demo-page-scroll-spotlight.html +759 -0
- package/.agents/skills/hyperframes-animation/examples/hook-counter-burst.html +729 -0
- package/.agents/skills/hyperframes-animation/examples/messaging-multi-phrase.html +352 -0
- package/.agents/skills/hyperframes-animation/examples/metric-video-text-pivot.html +779 -0
- package/.agents/skills/hyperframes-animation/examples/problem-mockup-overwhelm.html +1374 -0
- package/.agents/skills/hyperframes-animation/examples/proof-logo-chain.html +861 -0
- package/.agents/skills/hyperframes-animation/examples/takeover-ticker-displace.html +347 -0
- package/.agents/skills/hyperframes-animation/examples/workflow-approve-press.html +606 -0
- package/.agents/skills/hyperframes-animation/rules/3d-page-scroll.md +227 -0
- package/.agents/skills/hyperframes-animation/rules/3d-text-depth-layers.md +297 -0
- package/.agents/skills/hyperframes-animation/rules/ai-tracking-box.md +382 -0
- package/.agents/skills/hyperframes-animation/rules/ambient-glow-bloom.md +305 -0
- package/.agents/skills/hyperframes-animation/rules/asr-keyword-glow.md +286 -0
- package/.agents/skills/hyperframes-animation/rules/avatar-cloud-network.md +371 -0
- package/.agents/skills/hyperframes-animation/rules/camera-cursor-tracking.md +246 -0
- package/.agents/skills/hyperframes-animation/rules/card-morph-anchor.md +267 -0
- package/.agents/skills/hyperframes-animation/rules/center-outward-expansion.md +227 -0
- package/.agents/skills/hyperframes-animation/rules/context-sensitive-cursor.md +257 -0
- package/.agents/skills/hyperframes-animation/rules/coordinate-target-zoom.md +332 -0
- package/.agents/skills/hyperframes-animation/rules/counting-dynamic-scale.md +283 -0
- package/.agents/skills/hyperframes-animation/rules/css-marker-patterns.md +373 -0
- package/.agents/skills/hyperframes-animation/rules/cursor-click-ripple.md +262 -0
- package/.agents/skills/hyperframes-animation/rules/depth-of-field-blur.md +313 -0
- package/.agents/skills/hyperframes-animation/rules/depth-scatter-assemble.md +303 -0
- package/.agents/skills/hyperframes-animation/rules/discrete-text-sequence.md +273 -0
- package/.agents/skills/hyperframes-animation/rules/dynamic-content-sequencing.md +307 -0
- package/.agents/skills/hyperframes-animation/rules/gsap-effects.md +299 -0
- package/.agents/skills/hyperframes-animation/rules/hacker-flip-3d.md +223 -0
- package/.agents/skills/hyperframes-animation/rules/kinetic-beat-slam.md +183 -0
- package/.agents/skills/hyperframes-animation/rules/motion-blur-streak.md +328 -0
- package/.agents/skills/hyperframes-animation/rules/multi-phase-camera.md +273 -0
- package/.agents/skills/hyperframes-animation/rules/orbit-3d-entry.md +301 -0
- package/.agents/skills/hyperframes-animation/rules/physics-press-reaction.md +350 -0
- package/.agents/skills/hyperframes-animation/rules/press-release-spring.md +296 -0
- package/.agents/skills/hyperframes-animation/rules/reactive-displacement.md +277 -0
- package/.agents/skills/hyperframes-animation/rules/scale-swap-transition.md +298 -0
- package/.agents/skills/hyperframes-animation/rules/sine-wave-loop.md +278 -0
- package/.agents/skills/hyperframes-animation/rules/split-tilt-cards.md +277 -0
- package/.agents/skills/hyperframes-animation/rules/spring-pop-entrance.md +273 -0
- package/.agents/skills/hyperframes-animation/rules/stat-bars-and-fills.md +156 -0
- package/.agents/skills/hyperframes-animation/rules/svg-icon-enrichment.md +329 -0
- package/.agents/skills/hyperframes-animation/rules/svg-path-draw.md +274 -0
- package/.agents/skills/hyperframes-animation/rules/vertical-spring-ticker.md +239 -0
- package/.agents/skills/hyperframes-animation/rules/viewport-change.md +349 -0
- package/.agents/skills/hyperframes-animation/rules-index.md +86 -0
- package/.agents/skills/hyperframes-animation/scripts/animation-map.mjs +606 -0
- package/.agents/skills/hyperframes-animation/scripts/package-loader.mjs +288 -0
- package/.agents/skills/hyperframes-animation/scripts/package-loader.test.mjs +62 -0
- package/.agents/skills/hyperframes-animation/techniques.md +507 -0
- package/.agents/skills/hyperframes-animation/transitions/TRANSITION-REGISTRY.md +167 -0
- package/.agents/skills/hyperframes-animation/transitions/catalog.md +127 -0
- package/.agents/skills/hyperframes-animation/transitions/css-3d.md +12 -0
- package/.agents/skills/hyperframes-animation/transitions/css-blur.md +51 -0
- package/.agents/skills/hyperframes-animation/transitions/css-cover.md +43 -0
- package/.agents/skills/hyperframes-animation/transitions/css-destruction.md +95 -0
- package/.agents/skills/hyperframes-animation/transitions/css-dissolve.md +66 -0
- package/.agents/skills/hyperframes-animation/transitions/css-distortion.md +45 -0
- package/.agents/skills/hyperframes-animation/transitions/css-grid.md +10 -0
- package/.agents/skills/hyperframes-animation/transitions/css-light.md +49 -0
- package/.agents/skills/hyperframes-animation/transitions/css-mechanical.md +30 -0
- package/.agents/skills/hyperframes-animation/transitions/css-other.md +25 -0
- package/.agents/skills/hyperframes-animation/transitions/css-push.md +41 -0
- package/.agents/skills/hyperframes-animation/transitions/css-radial.md +37 -0
- package/.agents/skills/hyperframes-animation/transitions/css-scale.md +24 -0
- package/.agents/skills/hyperframes-animation/transitions/overview.md +153 -0
- package/.agents/skills/hyperframes-cli/SKILL.md +113 -0
- package/.agents/skills/hyperframes-cli/references/doctor-browser.md +45 -0
- package/.agents/skills/hyperframes-cli/references/init-and-scaffold.md +55 -0
- package/.agents/skills/hyperframes-cli/references/lambda.md +132 -0
- package/.agents/skills/hyperframes-cli/references/lint-validate-inspect.md +121 -0
- package/.agents/skills/hyperframes-cli/references/preview-render.md +149 -0
- package/.agents/skills/hyperframes-cli/references/upgrade-info-misc.md +75 -0
- package/.agents/skills/hyperframes-core/SKILL.md +78 -0
- package/.agents/skills/hyperframes-core/references/composition-patterns.md +263 -0
- package/.agents/skills/hyperframes-core/references/data-attributes.md +70 -0
- package/.agents/skills/hyperframes-core/references/determinism-rules.md +68 -0
- package/.agents/skills/hyperframes-core/references/full-screen-motion.md +62 -0
- package/.agents/skills/hyperframes-core/references/minimal-composition.md +66 -0
- package/.agents/skills/hyperframes-core/references/script-format.md +49 -0
- package/.agents/skills/hyperframes-core/references/storyboard-format.md +95 -0
- package/.agents/skills/hyperframes-core/references/sub-compositions.md +237 -0
- package/.agents/skills/hyperframes-core/references/subagent-dispatch.md +41 -0
- package/.agents/skills/hyperframes-core/references/tailwind.md +125 -0
- package/.agents/skills/hyperframes-core/references/tracks-and-clips.md +76 -0
- package/.agents/skills/hyperframes-core/references/variables-and-media.md +90 -0
- package/.agents/skills/hyperframes-creative/SKILL.md +70 -0
- package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/FRAME.md +289 -0
- package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/caption-skin.html +221 -0
- package/.agents/skills/hyperframes-creative/frame-presets/biennale-yellow/frame-showcase.html +1214 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blockframe/FRAME.md +275 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blockframe/caption-skin.html +224 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blockframe/frame-showcase.html +1347 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/FRAME.md +307 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/caption-skin.html +223 -0
- package/.agents/skills/hyperframes-creative/frame-presets/blue-professional/frame-showcase.html +1372 -0
- package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/FRAME.md +275 -0
- package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/caption-skin.html +230 -0
- package/.agents/skills/hyperframes-creative/frame-presets/bold-poster/frame-showcase.html +1140 -0
- package/.agents/skills/hyperframes-creative/frame-presets/broadside/FRAME.md +284 -0
- package/.agents/skills/hyperframes-creative/frame-presets/broadside/caption-skin.html +225 -0
- package/.agents/skills/hyperframes-creative/frame-presets/broadside/frame-showcase.html +1166 -0
- package/.agents/skills/hyperframes-creative/frame-presets/capsule/FRAME.md +284 -0
- package/.agents/skills/hyperframes-creative/frame-presets/capsule/caption-skin.html +224 -0
- package/.agents/skills/hyperframes-creative/frame-presets/capsule/frame-showcase.html +1465 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cartesian/FRAME.md +278 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cartesian/caption-skin.html +222 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cartesian/frame-showcase.html +1263 -0
- package/.agents/skills/hyperframes-creative/frame-presets/claude/FRAME.md +277 -0
- package/.agents/skills/hyperframes-creative/frame-presets/claude/caption-skin.html +224 -0
- package/.agents/skills/hyperframes-creative/frame-presets/claude/frame-showcase.html +1439 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/FRAME.md +265 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/caption-skin.html +238 -0
- package/.agents/skills/hyperframes-creative/frame-presets/cobalt-grid/frame-showcase.html +1468 -0
- package/.agents/skills/hyperframes-creative/frame-presets/coral/FRAME.md +314 -0
- package/.agents/skills/hyperframes-creative/frame-presets/coral/caption-skin.html +226 -0
- package/.agents/skills/hyperframes-creative/frame-presets/coral/frame-showcase.html +1268 -0
- package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/FRAME.md +333 -0
- package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/caption-skin.html +227 -0
- package/.agents/skills/hyperframes-creative/frame-presets/creative-mode/frame-showcase.html +1330 -0
- package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/FRAME.md +274 -0
- package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/caption-skin.html +230 -0
- package/.agents/skills/hyperframes-creative/frame-presets/daisy-days/frame-showcase.html +1444 -0
- package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/FRAME.md +265 -0
- package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/caption-skin.html +223 -0
- package/.agents/skills/hyperframes-creative/frame-presets/editorial-forest/frame-showcase.html +1273 -0
- package/.agents/skills/hyperframes-creative/palettes/bold-energetic.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/clean-corporate.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/dark-premium.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/jewel-rich.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/monochrome.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/nature-earth.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/neon-electric.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/pastel-soft.md +14 -0
- package/.agents/skills/hyperframes-creative/palettes/warm-editorial.md +14 -0
- package/.agents/skills/hyperframes-creative/references/audio-reactive.md +76 -0
- package/.agents/skills/hyperframes-creative/references/beat-direction.md +164 -0
- package/.agents/skills/hyperframes-creative/references/composition-patterns.md +199 -0
- package/.agents/skills/hyperframes-creative/references/data-in-motion.md +19 -0
- package/.agents/skills/hyperframes-creative/references/design-adherence.md +19 -0
- package/.agents/skills/hyperframes-creative/references/design-picker.md +123 -0
- package/.agents/skills/hyperframes-creative/references/design-spec.md +55 -0
- package/.agents/skills/hyperframes-creative/references/house-style.md +73 -0
- package/.agents/skills/hyperframes-creative/references/motion-principles.md +150 -0
- package/.agents/skills/hyperframes-creative/references/narration.md +92 -0
- package/.agents/skills/hyperframes-creative/references/prompt-expansion.md +68 -0
- package/.agents/skills/hyperframes-creative/references/typography.md +218 -0
- package/.agents/skills/hyperframes-creative/references/video-composition.md +63 -0
- package/.agents/skills/hyperframes-creative/references/visual-styles.md +457 -0
- package/.agents/skills/hyperframes-creative/scripts/contrast-report.mjs +353 -0
- package/.agents/skills/hyperframes-creative/scripts/extract-audio-data.py +188 -0
- package/.agents/skills/hyperframes-creative/scripts/package-loader.mjs +288 -0
- package/.agents/skills/hyperframes-creative/scripts/package-loader.test.mjs +62 -0
- package/.agents/skills/hyperframes-creative/templates/design-picker.html +1432 -0
- package/.agents/skills/hyperframes-keyframes/SKILL.md +237 -0
- package/.agents/skills/hyperframes-keyframes/agents/openai.yaml +4 -0
- package/.agents/skills/hyperframes-keyframes/references/keyframe-patterns.md +106 -0
- package/.agents/skills/motion-graphics/SKILL.md +172 -0
- package/.agents/skills/motion-graphics/agents/builder.md +40 -0
- package/.agents/skills/motion-graphics/agents/director.md +53 -0
- package/.agents/skills/motion-graphics/agents/finalize.md +17 -0
- package/.agents/skills/motion-graphics/catalog-map.md +40 -0
- package/.agents/skills/motion-graphics/categories/asset-fusion/module.md +37 -0
- package/.agents/skills/motion-graphics/categories/charts/module.md +21 -0
- package/.agents/skills/motion-graphics/categories/kinetic-type/module.md +19 -0
- package/.agents/skills/motion-graphics/categories/logo-reveal/module.md +17 -0
- package/.agents/skills/motion-graphics/categories/lower-thirds/module.md +16 -0
- package/.agents/skills/motion-graphics/categories/maps/bake-basemap.mjs +273 -0
- package/.agents/skills/motion-graphics/categories/maps/module.md +61 -0
- package/.agents/skills/motion-graphics/categories/news/module.md +56 -0
- package/.agents/skills/motion-graphics/categories/stat/module.md +21 -0
- package/.agents/skills/motion-graphics/categories/tweet/module.md +16 -0
- package/.agents/skills/motion-graphics/categories/webpage/module.md +21 -0
- package/.agents/skills/motion-graphics/grounding/PROTOCOL.md +64 -0
- package/.agents/skills/motion-graphics/grounding/locate.mjs +227 -0
- package/.agents/skills/motion-graphics/phases/source/guide.md +21 -0
- package/.agents/skills/motion-graphics/references/builder-contract.md +38 -0
- package/.agents/skills/motion-graphics/references/motion-vocabulary.md +43 -0
- package/.agents/skills/motion-graphics/references/shot-plan-ir.md +54 -0
- package/.agents/skills/motion-graphics/samples/asset-fusion/_ref-circle-highlight.html +306 -0
- package/.agents/skills/music/SKILL.md +416 -0
- package/.agents/skills/music/references/api_reference.md +519 -0
- package/.agents/skills/music/references/installation.md +65 -0
- package/.agents/skills/product-launch-video/SKILL.md +208 -0
- package/.agents/skills/product-launch-video/references/cut-catalog.md +220 -0
- package/.agents/skills/product-launch-video/references/motion-language.md +156 -0
- package/.agents/skills/product-launch-video/references/story-design.md +373 -0
- package/.agents/skills/product-launch-video/references/visual-design.md +126 -0
- package/.agents/skills/product-launch-video/scripts/assemble-index.mjs +570 -0
- package/.agents/skills/product-launch-video/scripts/audio.mjs +260 -0
- package/.agents/skills/product-launch-video/scripts/build-frame.mjs +536 -0
- package/.agents/skills/product-launch-video/scripts/captions.mjs +508 -0
- package/.agents/skills/product-launch-video/scripts/lib/assets.mjs +55 -0
- package/.agents/skills/product-launch-video/scripts/lib/dimensions.mjs +45 -0
- package/.agents/skills/product-launch-video/scripts/lib/pad-frame-duration.mjs +36 -0
- package/.agents/skills/product-launch-video/scripts/lib/pad-frame-duration.test.mjs +76 -0
- package/.agents/skills/product-launch-video/scripts/lib/storyboard.mjs +249 -0
- package/.agents/skills/product-launch-video/scripts/lib/tokens.mjs +204 -0
- package/.agents/skills/product-launch-video/scripts/lib/transition-registry.mjs +38 -0
- package/.agents/skills/product-launch-video/scripts/lib/transitions.json +71 -0
- package/.agents/skills/product-launch-video/scripts/stage-assets.mjs +39 -0
- package/.agents/skills/product-launch-video/scripts/transitions.mjs +327 -0
- package/.agents/skills/product-launch-video/sub-agents/frame-worker.md +75 -0
- package/.agents/skills/slideshow/SKILL.md +550 -0
- package/.agents/skills/slideshow/references/standalone-harness.md +1020 -0
- package/.agents/skills/talking-head-recut/NOTICE.md +39 -0
- package/.agents/skills/talking-head-recut/SKILL.md +1195 -0
- package/.agents/skills/talking-head-recut/assets/vendor/gsap.min.js +10 -0
- package/.agents/skills/talking-head-recut/references/DESIGN_INDEX.md +145 -0
- package/.agents/skills/talking-head-recut/references/frames/clean.html +92 -0
- package/.agents/skills/talking-head-recut/references/frames/hairline.html +171 -0
- package/.agents/skills/talking-head-recut/references/frames/polaroid.html +131 -0
- package/.agents/skills/talking-head-recut/references/layouts/overlay.html +164 -0
- package/.agents/skills/talking-head-recut/references/layouts/pip.html +143 -0
- package/.agents/skills/talking-head-recut/references/layouts/split.html +121 -0
- package/.agents/skills/talking-head-recut/references/layouts/stack.html +109 -0
- package/.agents/skills/talking-head-recut/references/styles/academic.html +172 -0
- package/.agents/skills/talking-head-recut/references/styles/audit.html +170 -0
- package/.agents/skills/talking-head-recut/references/styles/editorial.html +189 -0
- package/.agents/skills/talking-head-recut/references/styles/geom.html +181 -0
- package/.agents/skills/talking-head-recut/references/styles/minimal.html +130 -0
- package/.agents/skills/talking-head-recut/references/styles/spotlight.html +142 -0
- package/.agents/skills/talking-head-recut/references/styles/swiss.html +188 -0
- package/.agents/skills/talking-head-recut/references/styles/terminal.html +196 -0
- package/.agents/skills/talking-head-recut/references/styles/whiteboard.html +170 -0
- package/.agents/skills/talking-head-recut/references/styles/xhs.html +206 -0
- package/.agents/skills/text-to-speech/SKILL.md +226 -0
- package/.agents/skills/text-to-speech/references/installation.md +90 -0
- package/.agents/skills/text-to-speech/references/streaming.md +307 -0
- package/.agents/skills/text-to-speech/references/voice-settings.md +115 -0
- package/.agents/skills/vidfarm-director/SKILL.md +179 -0
- package/.agents/skills/vidfarm-director/recipes/find-and-fork-template.md +16 -0
- package/.agents/skills/vidfarm-director/recipes/local-edit-render-approve.md +13 -0
- package/.agents/skills/vidfarm-director/recipes/onboard-a-new-director.md +13 -0
- package/.agents/skills/vidfarm-director/recipes/retheme-template.md +17 -0
- package/.agents/skills/vidfarm-director/references/assets-and-sourcing.md +117 -0
- package/.agents/skills/vidfarm-director/references/automation-and-local-dev.md +276 -0
- package/.agents/skills/vidfarm-director/references/core-workflows.md +301 -0
- package/.agents/skills/vidfarm-director/references/editor-workflows.md +367 -0
- package/.agents/skills/vidfarm-director/references/onboarding.md +28 -0
- package/.agents/skills/vidfarm-director/references/primitives.md +307 -0
- package/.agents/skills/vidfarm-director/references/rest-api.md +84 -0
- package/.agents/skills/vidfarm-media/SKILL.md +158 -0
- package/.agents/skills/vidfarm-media/references/tts.md +111 -0
- package/.agents/skills/vidfarm-media/scripts/audio.mjs +628 -0
- package/.agents/skills/vidfarm-media/scripts/wait-bgm.mjs +31 -0
- package/.agents/skills/website-to-video/SKILL.md +145 -0
- package/.agents/skills/website-to-video/assets/sfx/CREDITS.md +35 -0
- package/.agents/skills/website-to-video/assets/sfx/manifest.json +97 -0
- package/.agents/skills/website-to-video/references/beat-builder-guide.md +263 -0
- package/.agents/skills/website-to-video/references/capabilities.md +713 -0
- package/.agents/skills/website-to-video/references/step-0-capture.md +55 -0
- package/.agents/skills/website-to-video/references/step-1-design.md +333 -0
- package/.agents/skills/website-to-video/references/step-2-brief.md +178 -0
- package/.agents/skills/website-to-video/references/step-3-storyboard.md +572 -0
- package/.agents/skills/website-to-video/references/step-4-vo.md +225 -0
- package/.agents/skills/website-to-video/references/step-5-build.md +483 -0
- package/.agents/skills/website-to-video/references/step-6-validate.md +341 -0
- package/.agents/skills/website-to-video/scripts/w2h-verify.mjs +759 -0
- package/README.md +97 -0
- package/SKILL.director.md +1644 -0
- package/SKILL.md +83 -0
- package/demo/README.md +28 -0
- package/demo/dist/app.css +1 -0
- package/demo/dist/app.js +968 -0
- package/demo/dist/chunks/chunk-3OT2D42H.js +1 -0
- package/demo/dist/chunks/chunk-DXB73IDG.js +1 -0
- package/demo/dist/chunks/domEditingLayers-AT7G6F4L-ZTHJHB7R.js +1 -0
- package/demo/dist/chunks/hyperframes-player-7HKH6NSO.js +459 -0
- package/demo/dist/chunks/lib-XAQ37YOE.js +1 -0
- package/demo/dist/chunks/src-TJ2QYA4U.js +207 -0
- package/demo/dist/favicon.ico +0 -0
- package/demo/dist/icons/timeline/audio.svg +7 -0
- package/demo/dist/icons/timeline/captions.svg +5 -0
- package/demo/dist/icons/timeline/composition.svg +12 -0
- package/demo/dist/icons/timeline/image.svg +18 -0
- package/demo/dist/icons/timeline/music.svg +10 -0
- package/demo/dist/icons/timeline/text.svg +3 -0
- package/demo/dist/index.html +16 -0
- package/dist/src/cli.js +7258 -0
- package/dist/src/devcli/auth-store.js +67 -0
- package/dist/src/devcli/captions.js +310 -0
- package/dist/src/devcli/clip-store.js +368 -0
- package/dist/src/devcli/clips.js +1138 -0
- package/dist/src/devcli/composition-edit.js +1292 -0
- package/dist/src/devcli/cost-mode.js +149 -0
- package/dist/src/devcli/doctor.js +192 -0
- package/dist/src/devcli/hyperframes-cli.js +118 -0
- package/dist/src/devcli/local-backend.js +167 -0
- package/dist/src/devcli/local-frontend-server.js +681 -0
- package/dist/src/devcli/local-render.js +136 -0
- package/dist/src/devcli/skills.js +476 -0
- package/dist/src/devcli/speech.js +178 -0
- package/dist/src/devcli/stills.js +249 -0
- package/dist/src/devcli/telemetry.js +236 -0
- package/dist/src/devcli/timeline-edit.js +490 -0
- package/dist/src/devcli/transitions.js +205 -0
- package/dist/src/hyperframes/composition.js +780 -0
- package/dist/src/lib/crypto.js +45 -0
- package/dist/src/lib/dev-log.js +54 -0
- package/dist/src/lib/display-name.js +11 -0
- package/dist/src/lib/ids.js +24 -0
- package/dist/src/lib/images.js +19 -0
- package/dist/src/lib/json.js +15 -0
- package/dist/src/lib/package-root.js +47 -0
- package/dist/src/lib/render-media-prep.js +293 -0
- package/dist/src/lib/template-paths.js +28 -0
- package/dist/src/lib/time.js +7 -0
- package/dist/src/lib/url-clean.js +85 -0
- package/dist/src/services/captions.js +123 -0
- package/dist/src/services/clip-curation/cost.js +116 -0
- package/dist/src/services/clip-curation/ffmpeg.js +352 -0
- package/dist/src/services/clip-curation/gemini.js +418 -0
- package/dist/src/services/clip-curation/hunt.js +470 -0
- package/dist/src/services/clip-curation/index.js +19 -0
- package/dist/src/services/clip-curation/local-agent.js +248 -0
- package/dist/src/services/clip-curation/media-select.js +152 -0
- package/dist/src/services/clip-curation/presets.js +20 -0
- package/dist/src/services/clip-curation/presets.v1.json +59 -0
- package/dist/src/services/clip-curation/query.js +167 -0
- package/dist/src/services/clip-curation/refine.js +165 -0
- package/dist/src/services/clip-curation/scan.js +189 -0
- package/dist/src/services/clip-curation/source-naming.js +131 -0
- package/dist/src/services/clip-curation/taxonomy.js +73 -0
- package/dist/src/services/clip-curation/taxonomy.v1.json +102 -0
- package/dist/src/services/clip-curation/types.js +7 -0
- package/dist/src/services/composition-lint.js +199 -0
- package/dist/src/services/provider-errors.js +128 -0
- package/dist/src/services/speech.js +629 -0
- package/package.json +154 -0
- package/public/assets/discover-client-app.js +1 -0
- package/public/assets/favicon.ico +0 -0
- package/public/assets/file-directory-app.js +89 -0
- package/public/assets/homepage-app.js +54 -0
- package/public/assets/homepage-client-app.js +80 -0
- package/public/assets/landing-page-client-app.js +87 -0
- package/public/assets/logo-vidfarm.png +0 -0
- package/public/assets/page-runtime-client-app.js +94 -0
- package/public/assets/placeholders/scene-placeholder.png +0 -0
- package/public/serve-shells/editor.html +3146 -0
- package/public/serve-shells/library-files.html +3450 -0
- package/public/serve-shells/library-raws.html +4404 -0
- package/public/serve-shells/tools-clipper.html +3991 -0
- package/public/serve-shells/tools-image.html +5584 -0
- package/public/serve-shells/tools-video.html +4404 -0
|
@@ -0,0 +1,780 @@
|
|
|
1
|
+
export const KEN_BURNS_PRESETS = [
|
|
2
|
+
"zoom-in",
|
|
3
|
+
"zoom-out",
|
|
4
|
+
"pan-left",
|
|
5
|
+
"pan-right",
|
|
6
|
+
"pan-up",
|
|
7
|
+
"pan-down",
|
|
8
|
+
"zoom-in-left",
|
|
9
|
+
"zoom-in-right"
|
|
10
|
+
];
|
|
11
|
+
// Ken Burns is stored declaratively: the still-image layer element (the <img>
|
|
12
|
+
// that carries data-start) also carries data-kenburns="<preset>" plus optional
|
|
13
|
+
// inline vars (--vf-kb-amount / --vf-kb-origin / --vf-kb-dur). The animation
|
|
14
|
+
// runs directly on that <img> via CSS transform, so the ONE element that owns
|
|
15
|
+
// the timeline (data-start/duration) is also the one that animates — which is
|
|
16
|
+
// exactly what the render's per-frame CSS-animation adapter keys off (it seeks
|
|
17
|
+
// each animation by time-minus-that-element's-data-start). No wrapper, so every
|
|
18
|
+
// existing "image layer is an <img>" invariant in the editor and timeline holds.
|
|
19
|
+
// This static stylesheet supplies the keyframes; any surface that toggles the
|
|
20
|
+
// attribute (builder, editor, chat agent, devcli) gets identical motion in the
|
|
21
|
+
// preview runtime and both render pipelines. The marker comment is the
|
|
22
|
+
// idempotency key for serve/publish-time injection into stored HTML.
|
|
23
|
+
export const KEN_BURNS_STYLE_MARKER = "__VF_KENBURNS_V1__";
|
|
24
|
+
export const KEN_BURNS_CSS = `/*${KEN_BURNS_STYLE_MARKER}*/
|
|
25
|
+
@keyframes vf-kb-zoom-in { from { transform: translate(0%, 0%) scale(1); } to { transform: translate(0%, 0%) scale(calc(1 + var(--vf-kb-amount, 0.18))); } }
|
|
26
|
+
@keyframes vf-kb-zoom-out { from { transform: translate(0%, 0%) scale(calc(1 + var(--vf-kb-amount, 0.18))); } to { transform: translate(0%, 0%) scale(1); } }
|
|
27
|
+
@keyframes vf-kb-pan-left { from { transform: translate(calc(var(--vf-kb-amount, 0.18) * 45%), 0%) scale(calc(1 + var(--vf-kb-amount, 0.18))); } to { transform: translate(calc(var(--vf-kb-amount, 0.18) * -45%), 0%) scale(calc(1 + var(--vf-kb-amount, 0.18))); } }
|
|
28
|
+
@keyframes vf-kb-pan-right { from { transform: translate(calc(var(--vf-kb-amount, 0.18) * -45%), 0%) scale(calc(1 + var(--vf-kb-amount, 0.18))); } to { transform: translate(calc(var(--vf-kb-amount, 0.18) * 45%), 0%) scale(calc(1 + var(--vf-kb-amount, 0.18))); } }
|
|
29
|
+
@keyframes vf-kb-pan-up { from { transform: translate(0%, calc(var(--vf-kb-amount, 0.18) * 45%)) scale(calc(1 + var(--vf-kb-amount, 0.18))); } to { transform: translate(0%, calc(var(--vf-kb-amount, 0.18) * -45%)) scale(calc(1 + var(--vf-kb-amount, 0.18))); } }
|
|
30
|
+
@keyframes vf-kb-pan-down { from { transform: translate(0%, calc(var(--vf-kb-amount, 0.18) * -45%)) scale(calc(1 + var(--vf-kb-amount, 0.18))); } to { transform: translate(0%, calc(var(--vf-kb-amount, 0.18) * 45%)) scale(calc(1 + var(--vf-kb-amount, 0.18))); } }
|
|
31
|
+
@keyframes vf-kb-zoom-in-left { from { transform: translate(0%, 0%) scale(1); } to { transform: translate(calc(var(--vf-kb-amount, 0.18) * -45%), 0%) scale(calc(1 + var(--vf-kb-amount, 0.18))); } }
|
|
32
|
+
@keyframes vf-kb-zoom-in-right { from { transform: translate(0%, 0%) scale(1); } to { transform: translate(calc(var(--vf-kb-amount, 0.18) * 45%), 0%) scale(calc(1 + var(--vf-kb-amount, 0.18))); } }
|
|
33
|
+
[data-kenburns] {
|
|
34
|
+
transform-origin: var(--vf-kb-origin, 50% 50%);
|
|
35
|
+
animation-duration: var(--vf-kb-dur, 5s);
|
|
36
|
+
animation-timing-function: var(--vf-kb-ease, linear);
|
|
37
|
+
animation-fill-mode: both;
|
|
38
|
+
animation-play-state: paused;
|
|
39
|
+
will-change: transform;
|
|
40
|
+
backface-visibility: hidden;
|
|
41
|
+
}
|
|
42
|
+
[data-kenburns="zoom-in"] { animation-name: vf-kb-zoom-in; }
|
|
43
|
+
[data-kenburns="zoom-out"] { animation-name: vf-kb-zoom-out; }
|
|
44
|
+
[data-kenburns="pan-left"] { animation-name: vf-kb-pan-left; }
|
|
45
|
+
[data-kenburns="pan-right"] { animation-name: vf-kb-pan-right; }
|
|
46
|
+
[data-kenburns="pan-up"] { animation-name: vf-kb-pan-up; }
|
|
47
|
+
[data-kenburns="pan-down"] { animation-name: vf-kb-pan-down; }
|
|
48
|
+
[data-kenburns="zoom-in-left"] { animation-name: vf-kb-zoom-in-left; }
|
|
49
|
+
[data-kenburns="zoom-in-right"] { animation-name: vf-kb-zoom-in-right; }
|
|
50
|
+
`;
|
|
51
|
+
// Serializes a Ken Burns config into the inline CSS custom properties the
|
|
52
|
+
// stylesheet reads. Kept next to the CSS so presets and vars never drift.
|
|
53
|
+
export function kenBurnsInlineVars(kenBurns, durationSeconds) {
|
|
54
|
+
const vars = [];
|
|
55
|
+
if (durationSeconds !== undefined && Number.isFinite(durationSeconds) && durationSeconds > 0) {
|
|
56
|
+
vars.push(`--vf-kb-dur:${Number(durationSeconds.toFixed(3))}s`);
|
|
57
|
+
}
|
|
58
|
+
if (kenBurns.intensity !== undefined)
|
|
59
|
+
vars.push(`--vf-kb-amount:${Number(kenBurns.intensity.toFixed(4))}`);
|
|
60
|
+
if (kenBurns.origin)
|
|
61
|
+
vars.push(`--vf-kb-origin:${kenBurns.origin}`);
|
|
62
|
+
return vars.join(";");
|
|
63
|
+
}
|
|
64
|
+
export function normalizeKenBurns(value) {
|
|
65
|
+
if (!value)
|
|
66
|
+
return null;
|
|
67
|
+
const raw = typeof value === "string" ? { preset: value } : value;
|
|
68
|
+
if (!KEN_BURNS_PRESETS.includes(raw.preset))
|
|
69
|
+
return null;
|
|
70
|
+
const intensity = Number(raw.intensity);
|
|
71
|
+
const origin = typeof raw.origin === "string" && raw.origin.trim() ? raw.origin.trim() : undefined;
|
|
72
|
+
return {
|
|
73
|
+
preset: raw.preset,
|
|
74
|
+
intensity: Number.isFinite(intensity) ? Math.max(0.04, Math.min(0.5, intensity)) : undefined,
|
|
75
|
+
origin
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Scene transitions. Same declarative contract as Ken Burns: the INCOMING
|
|
80
|
+
// clip (the element that owns data-start) carries data-transition="<preset>"
|
|
81
|
+
// plus data-transition-duration and the inline --vf-tr-dur var, and a static
|
|
82
|
+
// vf-tr-* keyframe animates the clip IN over its first data-transition-duration
|
|
83
|
+
// seconds. Both preview runtimes and the render producer's CSS adapter scrub
|
|
84
|
+
// the animation by (time - data-start), so the motion is identical everywhere.
|
|
85
|
+
//
|
|
86
|
+
// The one thing CSS cannot express is the OUTGOING clip staying on screen
|
|
87
|
+
// beneath the incoming one: stored compositions keep scenes butt-cut (A ends
|
|
88
|
+
// exactly where B starts) so timeline edits and agent edits stay trivial. The
|
|
89
|
+
// preview runtime extends the previous same-track clip's active window live,
|
|
90
|
+
// and normalizePublishHtml materializes the same overlap into data-duration at
|
|
91
|
+
// publish/render time (recorded in data-transition-hold for idempotency),
|
|
92
|
+
// because the render engine derives visibility strictly from data-start/
|
|
93
|
+
// data-duration. Presets animate opacity / clip-path / standalone translate /
|
|
94
|
+
// scale — never `transform` — so they compose with a Ken Burns transform on
|
|
95
|
+
// the same element. Keyframes deliberately omit the `to` state so the
|
|
96
|
+
// animation settles into the element's own inline styles instead of
|
|
97
|
+
// clobbering a custom opacity.
|
|
98
|
+
export const TRANSITION_PRESETS = [
|
|
99
|
+
"crossfade",
|
|
100
|
+
"fade-black",
|
|
101
|
+
"fade-white",
|
|
102
|
+
"flash",
|
|
103
|
+
"smoke",
|
|
104
|
+
"blur",
|
|
105
|
+
"slide-left",
|
|
106
|
+
"slide-right",
|
|
107
|
+
"slide-up",
|
|
108
|
+
"slide-down",
|
|
109
|
+
"whip-left",
|
|
110
|
+
"whip-right",
|
|
111
|
+
"wipe-left",
|
|
112
|
+
"wipe-right",
|
|
113
|
+
"wipe-up",
|
|
114
|
+
"wipe-down",
|
|
115
|
+
"zoom-in",
|
|
116
|
+
"zoom-out",
|
|
117
|
+
"circle-open"
|
|
118
|
+
];
|
|
119
|
+
// Exit transitions: the clip animates AWAY over its last data-transition-out-
|
|
120
|
+
// duration seconds. Same declarative contract as the entrance presets; the
|
|
121
|
+
// keyframes omit the `from` state so the animation departs from the element's
|
|
122
|
+
// own inline styles, and the inline --vf-tr-out-delay var (clip duration minus
|
|
123
|
+
// out duration) positions the animation window at the clip's tail so the
|
|
124
|
+
// time-based scrub in the producer and preview runtimes needs no extra logic.
|
|
125
|
+
export const TRANSITION_OUT_PRESETS = [
|
|
126
|
+
"fade",
|
|
127
|
+
"fade-black",
|
|
128
|
+
"fade-white",
|
|
129
|
+
"flash",
|
|
130
|
+
"smoke",
|
|
131
|
+
"blur",
|
|
132
|
+
"slide-left",
|
|
133
|
+
"slide-right",
|
|
134
|
+
"slide-up",
|
|
135
|
+
"slide-down",
|
|
136
|
+
"wipe-left",
|
|
137
|
+
"wipe-right",
|
|
138
|
+
"wipe-up",
|
|
139
|
+
"wipe-down",
|
|
140
|
+
"zoom-in",
|
|
141
|
+
"zoom-out",
|
|
142
|
+
"circle-close"
|
|
143
|
+
];
|
|
144
|
+
export const TRANSITION_DEFAULT_DURATION = 0.5;
|
|
145
|
+
export const TRANSITION_MIN_DURATION = 0.1;
|
|
146
|
+
export const TRANSITION_MAX_DURATION = 2.5;
|
|
147
|
+
// Two butt-cut clips can drift by a few ms through timeline edits; treat ends
|
|
148
|
+
// within this window as adjacent when granting the outgoing clip's hold.
|
|
149
|
+
export const TRANSITION_ADJACENCY_EPSILON = 0.05;
|
|
150
|
+
// V2: entrance AND exit animations compose on one element via cascading custom
|
|
151
|
+
// properties (--vf-tr-in-name / --vf-tr-out-name) feeding a two-slot animation
|
|
152
|
+
// list — per-preset attribute selectors can't merge two animation-names, vars
|
|
153
|
+
// can. The [data-kenburns] combo rules below fix a V1 latent clash where Ken
|
|
154
|
+
// Burns and a transition on the same <img> fought over animation-name (equal
|
|
155
|
+
// specificity, last stylesheet won); the (0,2,0) combo selectors prepend the
|
|
156
|
+
// vf-kb animation to the list instead.
|
|
157
|
+
export const TRANSITION_STYLE_MARKER = "__VF_TRANSITIONS_V2__";
|
|
158
|
+
// The exact V1 block previous builds baked into stored compositions. Injectors
|
|
159
|
+
// string-replace this with the current TRANSITION_CSS so old drafts/publishes
|
|
160
|
+
// upgrade in place instead of accumulating duplicate style blocks.
|
|
161
|
+
export const LEGACY_TRANSITION_CSS_V1 = `/*__VF_TRANSITIONS_V1__*/
|
|
162
|
+
@keyframes vf-tr-crossfade { from { opacity: 0; } }
|
|
163
|
+
@keyframes vf-tr-fade-black { 0% { opacity: 0; filter: brightness(0); } 35% { opacity: 1; filter: brightness(0); } }
|
|
164
|
+
@keyframes vf-tr-slide-left { from { translate: 100% 0; } }
|
|
165
|
+
@keyframes vf-tr-slide-right { from { translate: -100% 0; } }
|
|
166
|
+
@keyframes vf-tr-slide-up { from { translate: 0 100%; } }
|
|
167
|
+
@keyframes vf-tr-slide-down { from { translate: 0 -100%; } }
|
|
168
|
+
@keyframes vf-tr-wipe-left { from { clip-path: inset(0 0 0 100%); } to { clip-path: inset(0 0 0 0); } }
|
|
169
|
+
@keyframes vf-tr-wipe-right { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
|
|
170
|
+
@keyframes vf-tr-wipe-up { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
|
|
171
|
+
@keyframes vf-tr-wipe-down { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
|
|
172
|
+
@keyframes vf-tr-zoom-in { from { opacity: 0; scale: 1.18; } }
|
|
173
|
+
@keyframes vf-tr-zoom-out { from { opacity: 0; scale: 0.82; } }
|
|
174
|
+
@keyframes vf-tr-circle-open { from { clip-path: circle(0% at 50% 50%); } to { clip-path: circle(75% at 50% 50%); } }
|
|
175
|
+
[data-transition] {
|
|
176
|
+
animation-duration: var(--vf-tr-dur, 0.5s);
|
|
177
|
+
animation-timing-function: var(--vf-tr-ease, ease-in-out);
|
|
178
|
+
animation-fill-mode: both;
|
|
179
|
+
animation-play-state: paused;
|
|
180
|
+
}
|
|
181
|
+
[data-transition="crossfade"] { animation-name: vf-tr-crossfade; }
|
|
182
|
+
[data-transition="fade-black"] { animation-name: vf-tr-fade-black; }
|
|
183
|
+
[data-transition="slide-left"] { animation-name: vf-tr-slide-left; }
|
|
184
|
+
[data-transition="slide-right"] { animation-name: vf-tr-slide-right; }
|
|
185
|
+
[data-transition="slide-up"] { animation-name: vf-tr-slide-up; }
|
|
186
|
+
[data-transition="slide-down"] { animation-name: vf-tr-slide-down; }
|
|
187
|
+
[data-transition="wipe-left"] { animation-name: vf-tr-wipe-left; }
|
|
188
|
+
[data-transition="wipe-right"] { animation-name: vf-tr-wipe-right; }
|
|
189
|
+
[data-transition="wipe-up"] { animation-name: vf-tr-wipe-up; }
|
|
190
|
+
[data-transition="wipe-down"] { animation-name: vf-tr-wipe-down; }
|
|
191
|
+
[data-transition="zoom-in"] { animation-name: vf-tr-zoom-in; }
|
|
192
|
+
[data-transition="zoom-out"] { animation-name: vf-tr-zoom-out; }
|
|
193
|
+
[data-transition="circle-open"] { animation-name: vf-tr-circle-open; }
|
|
194
|
+
`;
|
|
195
|
+
export const TRANSITION_CSS = `/*${TRANSITION_STYLE_MARKER}*/
|
|
196
|
+
@keyframes vf-tr-crossfade { from { opacity: 0; } }
|
|
197
|
+
@keyframes vf-tr-fade-black { 0% { opacity: 0; filter: brightness(0); } 35% { opacity: 1; filter: brightness(0); } }
|
|
198
|
+
@keyframes vf-tr-fade-white { 0% { opacity: 0; filter: saturate(0.55) brightness(3); } 45% { opacity: 1; filter: saturate(0.7) brightness(2.1); } }
|
|
199
|
+
@keyframes vf-tr-flash { 0% { filter: saturate(0.3) brightness(5); } 55% { filter: saturate(0.9) brightness(1.6); } }
|
|
200
|
+
@keyframes vf-tr-smoke { 0% { opacity: 0; filter: blur(26px) saturate(0.65) brightness(1.55); } 55% { opacity: 1; } }
|
|
201
|
+
@keyframes vf-tr-blur { from { opacity: 0; filter: blur(16px); } }
|
|
202
|
+
@keyframes vf-tr-slide-left { from { translate: 100% 0; } }
|
|
203
|
+
@keyframes vf-tr-slide-right { from { translate: -100% 0; } }
|
|
204
|
+
@keyframes vf-tr-slide-up { from { translate: 0 100%; } }
|
|
205
|
+
@keyframes vf-tr-slide-down { from { translate: 0 -100%; } }
|
|
206
|
+
@keyframes vf-tr-whip-left { 0% { translate: 110% 0; filter: blur(14px); } 60% { filter: blur(5px); } }
|
|
207
|
+
@keyframes vf-tr-whip-right { 0% { translate: -110% 0; filter: blur(14px); } 60% { filter: blur(5px); } }
|
|
208
|
+
@keyframes vf-tr-wipe-left { from { clip-path: inset(0 0 0 100%); } to { clip-path: inset(0 0 0 0); } }
|
|
209
|
+
@keyframes vf-tr-wipe-right { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
|
|
210
|
+
@keyframes vf-tr-wipe-up { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
|
|
211
|
+
@keyframes vf-tr-wipe-down { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
|
|
212
|
+
@keyframes vf-tr-zoom-in { from { opacity: 0; scale: 1.18; } }
|
|
213
|
+
@keyframes vf-tr-zoom-out { from { opacity: 0; scale: 0.82; } }
|
|
214
|
+
@keyframes vf-tr-circle-open { from { clip-path: circle(0% at 50% 50%); } to { clip-path: circle(75% at 50% 50%); } }
|
|
215
|
+
@keyframes vf-tr-out-fade { to { opacity: 0; } }
|
|
216
|
+
@keyframes vf-tr-out-fade-black { to { filter: brightness(0); } }
|
|
217
|
+
@keyframes vf-tr-out-fade-white { to { filter: saturate(0.35) brightness(6); } }
|
|
218
|
+
@keyframes vf-tr-out-flash { 65% { filter: brightness(1); } 100% { filter: saturate(0.3) brightness(5); } }
|
|
219
|
+
@keyframes vf-tr-out-smoke { to { opacity: 0; filter: blur(24px) saturate(0.7) brightness(1.5); } }
|
|
220
|
+
@keyframes vf-tr-out-blur { to { opacity: 0; filter: blur(16px); } }
|
|
221
|
+
@keyframes vf-tr-out-slide-left { to { translate: -100% 0; } }
|
|
222
|
+
@keyframes vf-tr-out-slide-right { to { translate: 100% 0; } }
|
|
223
|
+
@keyframes vf-tr-out-slide-up { to { translate: 0 -100%; } }
|
|
224
|
+
@keyframes vf-tr-out-slide-down { to { translate: 0 100%; } }
|
|
225
|
+
@keyframes vf-tr-out-wipe-left { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(0 100% 0 0); } }
|
|
226
|
+
@keyframes vf-tr-out-wipe-right { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(0 0 0 100%); } }
|
|
227
|
+
@keyframes vf-tr-out-wipe-up { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(0 0 100% 0); } }
|
|
228
|
+
@keyframes vf-tr-out-wipe-down { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(100% 0 0 0); } }
|
|
229
|
+
@keyframes vf-tr-out-zoom-in { to { opacity: 0; scale: 1.18; } }
|
|
230
|
+
@keyframes vf-tr-out-zoom-out { to { opacity: 0; scale: 0.82; } }
|
|
231
|
+
@keyframes vf-tr-out-circle-close { from { clip-path: circle(75% at 50% 50%); } to { clip-path: circle(0% at 50% 50%); } }
|
|
232
|
+
[data-transition], [data-transition-out] {
|
|
233
|
+
animation-name: var(--vf-tr-in-name, none), var(--vf-tr-out-name, none);
|
|
234
|
+
animation-duration: var(--vf-tr-dur, 0.5s), var(--vf-tr-out-dur, 0.5s);
|
|
235
|
+
animation-delay: 0s, var(--vf-tr-out-delay, 0s);
|
|
236
|
+
animation-timing-function: var(--vf-tr-ease, ease-in-out), var(--vf-tr-out-ease, ease-in-out);
|
|
237
|
+
animation-fill-mode: both, both;
|
|
238
|
+
animation-play-state: paused, paused;
|
|
239
|
+
}
|
|
240
|
+
[data-kenburns][data-transition], [data-kenburns][data-transition-out] {
|
|
241
|
+
animation-name: var(--vf-kb-name, none), var(--vf-tr-in-name, none), var(--vf-tr-out-name, none);
|
|
242
|
+
animation-duration: var(--vf-kb-dur, 5s), var(--vf-tr-dur, 0.5s), var(--vf-tr-out-dur, 0.5s);
|
|
243
|
+
animation-delay: 0s, 0s, var(--vf-tr-out-delay, 0s);
|
|
244
|
+
animation-timing-function: var(--vf-kb-ease, linear), var(--vf-tr-ease, ease-in-out), var(--vf-tr-out-ease, ease-in-out);
|
|
245
|
+
animation-fill-mode: both, both, both;
|
|
246
|
+
animation-play-state: paused, paused, paused;
|
|
247
|
+
}
|
|
248
|
+
[data-kenburns="zoom-in"] { --vf-kb-name: vf-kb-zoom-in; }
|
|
249
|
+
[data-kenburns="zoom-out"] { --vf-kb-name: vf-kb-zoom-out; }
|
|
250
|
+
[data-kenburns="pan-left"] { --vf-kb-name: vf-kb-pan-left; }
|
|
251
|
+
[data-kenburns="pan-right"] { --vf-kb-name: vf-kb-pan-right; }
|
|
252
|
+
[data-kenburns="pan-up"] { --vf-kb-name: vf-kb-pan-up; }
|
|
253
|
+
[data-kenburns="pan-down"] { --vf-kb-name: vf-kb-pan-down; }
|
|
254
|
+
[data-kenburns="zoom-in-left"] { --vf-kb-name: vf-kb-zoom-in-left; }
|
|
255
|
+
[data-kenburns="zoom-in-right"] { --vf-kb-name: vf-kb-zoom-in-right; }
|
|
256
|
+
[data-transition="crossfade"] { --vf-tr-in-name: vf-tr-crossfade; }
|
|
257
|
+
[data-transition="fade-black"] { --vf-tr-in-name: vf-tr-fade-black; }
|
|
258
|
+
[data-transition="fade-white"] { --vf-tr-in-name: vf-tr-fade-white; }
|
|
259
|
+
[data-transition="flash"] { --vf-tr-in-name: vf-tr-flash; --vf-tr-ease: cubic-bezier(0.3, 0, 0.55, 1); }
|
|
260
|
+
[data-transition="smoke"] { --vf-tr-in-name: vf-tr-smoke; --vf-tr-ease: cubic-bezier(0.25, 0.4, 0.3, 1); }
|
|
261
|
+
[data-transition="blur"] { --vf-tr-in-name: vf-tr-blur; }
|
|
262
|
+
[data-transition="slide-left"] { --vf-tr-in-name: vf-tr-slide-left; --vf-tr-ease: cubic-bezier(0.22, 1, 0.36, 1); }
|
|
263
|
+
[data-transition="slide-right"] { --vf-tr-in-name: vf-tr-slide-right; --vf-tr-ease: cubic-bezier(0.22, 1, 0.36, 1); }
|
|
264
|
+
[data-transition="slide-up"] { --vf-tr-in-name: vf-tr-slide-up; --vf-tr-ease: cubic-bezier(0.22, 1, 0.36, 1); }
|
|
265
|
+
[data-transition="slide-down"] { --vf-tr-in-name: vf-tr-slide-down; --vf-tr-ease: cubic-bezier(0.22, 1, 0.36, 1); }
|
|
266
|
+
[data-transition="whip-left"] { --vf-tr-in-name: vf-tr-whip-left; --vf-tr-ease: cubic-bezier(0.16, 1, 0.3, 1); }
|
|
267
|
+
[data-transition="whip-right"] { --vf-tr-in-name: vf-tr-whip-right; --vf-tr-ease: cubic-bezier(0.16, 1, 0.3, 1); }
|
|
268
|
+
[data-transition="wipe-left"] { --vf-tr-in-name: vf-tr-wipe-left; --vf-tr-ease: cubic-bezier(0.45, 0.05, 0.35, 0.95); }
|
|
269
|
+
[data-transition="wipe-right"] { --vf-tr-in-name: vf-tr-wipe-right; --vf-tr-ease: cubic-bezier(0.45, 0.05, 0.35, 0.95); }
|
|
270
|
+
[data-transition="wipe-up"] { --vf-tr-in-name: vf-tr-wipe-up; --vf-tr-ease: cubic-bezier(0.45, 0.05, 0.35, 0.95); }
|
|
271
|
+
[data-transition="wipe-down"] { --vf-tr-in-name: vf-tr-wipe-down; --vf-tr-ease: cubic-bezier(0.45, 0.05, 0.35, 0.95); }
|
|
272
|
+
[data-transition="zoom-in"] { --vf-tr-in-name: vf-tr-zoom-in; --vf-tr-ease: cubic-bezier(0.16, 1, 0.3, 1); }
|
|
273
|
+
[data-transition="zoom-out"] { --vf-tr-in-name: vf-tr-zoom-out; --vf-tr-ease: cubic-bezier(0.16, 1, 0.3, 1); }
|
|
274
|
+
[data-transition="circle-open"] { --vf-tr-in-name: vf-tr-circle-open; --vf-tr-ease: cubic-bezier(0.3, 0.6, 0.3, 1); }
|
|
275
|
+
[data-transition-out="fade"] { --vf-tr-out-name: vf-tr-out-fade; }
|
|
276
|
+
[data-transition-out="fade-black"] { --vf-tr-out-name: vf-tr-out-fade-black; }
|
|
277
|
+
[data-transition-out="fade-white"] { --vf-tr-out-name: vf-tr-out-fade-white; }
|
|
278
|
+
[data-transition-out="flash"] { --vf-tr-out-name: vf-tr-out-flash; --vf-tr-out-ease: cubic-bezier(0.45, 0, 0.7, 0.4); }
|
|
279
|
+
[data-transition-out="smoke"] { --vf-tr-out-name: vf-tr-out-smoke; --vf-tr-out-ease: cubic-bezier(0.7, 0, 0.75, 0.6); }
|
|
280
|
+
[data-transition-out="blur"] { --vf-tr-out-name: vf-tr-out-blur; }
|
|
281
|
+
[data-transition-out="slide-left"] { --vf-tr-out-name: vf-tr-out-slide-left; --vf-tr-out-ease: cubic-bezier(0.55, 0.06, 0.68, 0.19); }
|
|
282
|
+
[data-transition-out="slide-right"] { --vf-tr-out-name: vf-tr-out-slide-right; --vf-tr-out-ease: cubic-bezier(0.55, 0.06, 0.68, 0.19); }
|
|
283
|
+
[data-transition-out="slide-up"] { --vf-tr-out-name: vf-tr-out-slide-up; --vf-tr-out-ease: cubic-bezier(0.55, 0.06, 0.68, 0.19); }
|
|
284
|
+
[data-transition-out="slide-down"] { --vf-tr-out-name: vf-tr-out-slide-down; --vf-tr-out-ease: cubic-bezier(0.55, 0.06, 0.68, 0.19); }
|
|
285
|
+
[data-transition-out="wipe-left"] { --vf-tr-out-name: vf-tr-out-wipe-left; --vf-tr-out-ease: cubic-bezier(0.45, 0.05, 0.35, 0.95); }
|
|
286
|
+
[data-transition-out="wipe-right"] { --vf-tr-out-name: vf-tr-out-wipe-right; --vf-tr-out-ease: cubic-bezier(0.45, 0.05, 0.35, 0.95); }
|
|
287
|
+
[data-transition-out="wipe-up"] { --vf-tr-out-name: vf-tr-out-wipe-up; --vf-tr-out-ease: cubic-bezier(0.45, 0.05, 0.35, 0.95); }
|
|
288
|
+
[data-transition-out="wipe-down"] { --vf-tr-out-name: vf-tr-out-wipe-down; --vf-tr-out-ease: cubic-bezier(0.45, 0.05, 0.35, 0.95); }
|
|
289
|
+
[data-transition-out="zoom-in"] { --vf-tr-out-name: vf-tr-out-zoom-in; --vf-tr-out-ease: cubic-bezier(0.5, 0, 0.75, 0.4); }
|
|
290
|
+
[data-transition-out="zoom-out"] { --vf-tr-out-name: vf-tr-out-zoom-out; --vf-tr-out-ease: cubic-bezier(0.5, 0, 0.75, 0.4); }
|
|
291
|
+
[data-transition-out="circle-close"] { --vf-tr-out-name: vf-tr-out-circle-close; --vf-tr-out-ease: cubic-bezier(0.6, 0, 0.7, 0.4); }
|
|
292
|
+
`;
|
|
293
|
+
export function clampTransitionDuration(value) {
|
|
294
|
+
const next = Number(value);
|
|
295
|
+
if (!Number.isFinite(next) || next <= 0)
|
|
296
|
+
return TRANSITION_DEFAULT_DURATION;
|
|
297
|
+
return Math.max(TRANSITION_MIN_DURATION, Math.min(TRANSITION_MAX_DURATION, next));
|
|
298
|
+
}
|
|
299
|
+
// Seconds into the clip at which its exit animation must start so it finishes
|
|
300
|
+
// exactly at the clip's end. Written as the inline --vf-tr-out-delay var.
|
|
301
|
+
export function transitionOutDelaySeconds(layerDurationSeconds, outDurationSeconds) {
|
|
302
|
+
const layerDuration = Number(layerDurationSeconds);
|
|
303
|
+
const outDuration = Number(outDurationSeconds);
|
|
304
|
+
if (!Number.isFinite(layerDuration) || !Number.isFinite(outDuration))
|
|
305
|
+
return 0;
|
|
306
|
+
return Math.max(0, Number((layerDuration - outDuration).toFixed(3)));
|
|
307
|
+
}
|
|
308
|
+
export function normalizeTransition(value) {
|
|
309
|
+
if (!value)
|
|
310
|
+
return null;
|
|
311
|
+
const raw = typeof value === "string" ? { preset: value } : value;
|
|
312
|
+
if (!TRANSITION_PRESETS.includes(raw.preset))
|
|
313
|
+
return null;
|
|
314
|
+
return {
|
|
315
|
+
preset: raw.preset,
|
|
316
|
+
duration: raw.duration !== undefined ? clampTransitionDuration(raw.duration) : undefined
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
export function normalizeTransitionOut(value) {
|
|
320
|
+
if (!value)
|
|
321
|
+
return null;
|
|
322
|
+
const raw = typeof value === "string" ? { preset: value } : value;
|
|
323
|
+
if (!TRANSITION_OUT_PRESETS.includes(raw.preset))
|
|
324
|
+
return null;
|
|
325
|
+
return {
|
|
326
|
+
preset: raw.preset,
|
|
327
|
+
duration: raw.duration !== undefined ? clampTransitionDuration(raw.duration) : undefined
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
// Upgrades stored composition HTML that still carries the V1 transition
|
|
331
|
+
// stylesheet: exact-replaces the legacy block with the current one. If the V1
|
|
332
|
+
// marker is present but the block has drifted, callers' normal marker-guarded
|
|
333
|
+
// injection appends the V2 block AFTER it, which also wins (equal-specificity
|
|
334
|
+
// rules, later source order) — this replace just avoids duplicate blocks in
|
|
335
|
+
// the common case.
|
|
336
|
+
export function upgradeLegacyTransitionCss(html) {
|
|
337
|
+
if (!html || html.includes(TRANSITION_STYLE_MARKER) || !html.includes("__VF_TRANSITIONS_V1__"))
|
|
338
|
+
return html;
|
|
339
|
+
return html.split(LEGACY_TRANSITION_CSS_V1).join(TRANSITION_CSS);
|
|
340
|
+
}
|
|
341
|
+
// ---------------------------------------------------------------------------
|
|
342
|
+
// Animated captions. Same declarative contract as Ken Burns: the caption layer
|
|
343
|
+
// <div> (the element that owns data-start/data-duration) carries
|
|
344
|
+
// data-caption-animation="<preset>" plus per-cue CSS vars, and each word is a
|
|
345
|
+
// <span data-cap-word> whose inline animation-delay/animation-duration encode
|
|
346
|
+
// that word's window RELATIVE TO THE LAYER START. The render producer's CSS
|
|
347
|
+
// adapter seeks every animation to (frameTime - ancestor data-start), and both
|
|
348
|
+
// preview runtimes scrub the same way, so word-level motion is deterministic
|
|
349
|
+
// and identical across preview and export. Everything is pure HTML+CSS so it
|
|
350
|
+
// survives sanitizeCompositionHtml. Word timings also round-trip through
|
|
351
|
+
// data-word-start/data-word-end so editors can re-derive them without parsing
|
|
352
|
+
// CSS.
|
|
353
|
+
export const CAPTION_ANIMATIONS = [
|
|
354
|
+
"highlight-pop",
|
|
355
|
+
"karaoke-fill",
|
|
356
|
+
"word-pop",
|
|
357
|
+
"cumulative-reveal",
|
|
358
|
+
"glow-pulse",
|
|
359
|
+
"bounce-wave"
|
|
360
|
+
];
|
|
361
|
+
export const CAPTION_STYLE_MARKER = "__VF_CAPTIONS_V1__";
|
|
362
|
+
export const CAPTION_ANIM_CSS = `/*${CAPTION_STYLE_MARKER}*/
|
|
363
|
+
[data-caption-animation] [data-cap-word] {
|
|
364
|
+
display:inline-block;
|
|
365
|
+
animation-play-state:paused;
|
|
366
|
+
animation-timing-function:ease-out;
|
|
367
|
+
animation-fill-mode:none;
|
|
368
|
+
will-change:transform,opacity;
|
|
369
|
+
}
|
|
370
|
+
[data-caption-uppercase="1"] { text-transform:uppercase; }
|
|
371
|
+
@keyframes vf-cap-highlight { 14%, 100% { background-color:var(--vf-cap-hl, #7C3AED); color:var(--vf-cap-active, #FFFFFF); transform:scale(1.06); } }
|
|
372
|
+
[data-caption-animation="highlight-pop"] [data-cap-word] { animation-name:vf-cap-highlight; padding:0.08em 0.18em; margin:-0.08em -0.05em; border-radius:0.3em; }
|
|
373
|
+
@keyframes vf-cap-karaoke { to { color:var(--vf-cap-active, #FFE14D); } }
|
|
374
|
+
[data-caption-animation="karaoke-fill"] [data-cap-word] { animation-name:vf-cap-karaoke; animation-fill-mode:forwards; animation-timing-function:linear; }
|
|
375
|
+
@keyframes vf-cap-word-pop { 0% { opacity:0; transform:scale(0.45); } 22% { opacity:1; transform:scale(1.14); } 38%, 100% { opacity:1; transform:scale(1); } }
|
|
376
|
+
[data-caption-animation="word-pop"] [data-vf-text-inline] { display:grid; place-items:center; }
|
|
377
|
+
[data-caption-animation="word-pop"] [data-cap-word] { animation-name:vf-cap-word-pop; opacity:0; grid-area:1 / 1; }
|
|
378
|
+
@keyframes vf-cap-reveal { from { opacity:0; transform:translateY(0.4em); } 40%, 100% { opacity:1; transform:none; } }
|
|
379
|
+
[data-caption-animation="cumulative-reveal"] [data-cap-word] { animation-name:vf-cap-reveal; animation-fill-mode:forwards; opacity:0; }
|
|
380
|
+
@keyframes vf-cap-glow { 20%, 80% { color:var(--vf-cap-active, #9BFF57); text-shadow:0 0 0.14em var(--vf-cap-active, #9BFF57), 0 0 0.5em var(--vf-cap-active, #9BFF57); transform:scale(1.04); } }
|
|
381
|
+
[data-caption-animation="glow-pulse"] [data-cap-word] { animation-name:vf-cap-glow; }
|
|
382
|
+
@keyframes vf-cap-bounce { 25% { transform:translateY(-0.22em) scale(1.08); } 55% { transform:translateY(0.05em); } 75% { transform:none; } }
|
|
383
|
+
[data-caption-animation="bounce-wave"] [data-cap-word] { animation-name:vf-cap-bounce; }
|
|
384
|
+
`;
|
|
385
|
+
export const CAPTION_STYLE_PRESETS = [
|
|
386
|
+
{
|
|
387
|
+
id: "spotlight",
|
|
388
|
+
label: "Spotlight",
|
|
389
|
+
animation: "highlight-pop",
|
|
390
|
+
color: "#ffffff",
|
|
391
|
+
background: "#000000",
|
|
392
|
+
textBackgroundStyle: "outline",
|
|
393
|
+
highlightColor: "#7C3AED",
|
|
394
|
+
activeColor: "#ffffff",
|
|
395
|
+
fontWeight: 800,
|
|
396
|
+
uppercase: true
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
id: "karaoke",
|
|
400
|
+
label: "Karaoke",
|
|
401
|
+
animation: "karaoke-fill",
|
|
402
|
+
color: "#ffffff",
|
|
403
|
+
background: "#000000",
|
|
404
|
+
textBackgroundStyle: "outline",
|
|
405
|
+
activeColor: "#FFE14D",
|
|
406
|
+
fontWeight: 800
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
id: "word-pop",
|
|
410
|
+
label: "Word Pop",
|
|
411
|
+
animation: "word-pop",
|
|
412
|
+
color: "#ffffff",
|
|
413
|
+
background: "#000000",
|
|
414
|
+
textBackgroundStyle: "outline",
|
|
415
|
+
fontWeight: 900,
|
|
416
|
+
uppercase: true
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
id: "stack-up",
|
|
420
|
+
label: "Stack Up",
|
|
421
|
+
animation: "cumulative-reveal",
|
|
422
|
+
color: "#ffffff",
|
|
423
|
+
background: "#000000",
|
|
424
|
+
textBackgroundStyle: "highlight-translucent",
|
|
425
|
+
fontWeight: 700
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
id: "neon",
|
|
429
|
+
label: "Neon Glow",
|
|
430
|
+
animation: "glow-pulse",
|
|
431
|
+
color: "#eafff1",
|
|
432
|
+
background: "#04140a",
|
|
433
|
+
textBackgroundStyle: "plain",
|
|
434
|
+
activeColor: "#9BFF57",
|
|
435
|
+
fontWeight: 800,
|
|
436
|
+
uppercase: true
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
id: "bounce",
|
|
440
|
+
label: "Bounce",
|
|
441
|
+
animation: "bounce-wave",
|
|
442
|
+
color: "#FFE14D",
|
|
443
|
+
background: "#000000",
|
|
444
|
+
textBackgroundStyle: "outline",
|
|
445
|
+
activeColor: "#FFE14D",
|
|
446
|
+
fontWeight: 900,
|
|
447
|
+
uppercase: true
|
|
448
|
+
}
|
|
449
|
+
];
|
|
450
|
+
export function captionStylePresetById(id) {
|
|
451
|
+
if (!id)
|
|
452
|
+
return null;
|
|
453
|
+
const clean = String(id).trim().toLowerCase();
|
|
454
|
+
return CAPTION_STYLE_PRESETS.find((preset) => preset.id === clean) || null;
|
|
455
|
+
}
|
|
456
|
+
export function normalizeCaptionConfig(value) {
|
|
457
|
+
if (!value)
|
|
458
|
+
return null;
|
|
459
|
+
const raw = typeof value === "string" ? { animation: value } : value;
|
|
460
|
+
if (!CAPTION_ANIMATIONS.includes(raw.animation))
|
|
461
|
+
return null;
|
|
462
|
+
const words = Array.isArray(raw.words)
|
|
463
|
+
? raw.words
|
|
464
|
+
.map((word) => ({
|
|
465
|
+
text: String(word?.text ?? "").trim(),
|
|
466
|
+
start: Math.max(0, Number(word?.start) || 0),
|
|
467
|
+
end: Math.max(0, Number(word?.end) || 0)
|
|
468
|
+
}))
|
|
469
|
+
.filter((word) => word.text && word.end > word.start)
|
|
470
|
+
: undefined;
|
|
471
|
+
return {
|
|
472
|
+
animation: raw.animation,
|
|
473
|
+
words: words && words.length ? words : undefined,
|
|
474
|
+
activeColor: typeof raw.activeColor === "string" && raw.activeColor.trim() ? raw.activeColor.trim() : undefined,
|
|
475
|
+
highlightColor: typeof raw.highlightColor === "string" && raw.highlightColor.trim() ? raw.highlightColor.trim() : undefined,
|
|
476
|
+
uppercase: raw.uppercase === true ? true : undefined
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
// Char-weighted word windows across a cue when the transcript has no
|
|
480
|
+
// word-level timings (Gemini segments, hand-typed text). Leaves a hair of
|
|
481
|
+
// silence between words so pop/highlight transitions read as discrete.
|
|
482
|
+
export function estimateCaptionWords(text, durationSeconds) {
|
|
483
|
+
const tokens = String(text || "").trim().split(/\s+/).filter(Boolean);
|
|
484
|
+
const duration = Number.isFinite(durationSeconds) && durationSeconds > 0 ? durationSeconds : tokens.length * 0.32;
|
|
485
|
+
if (!tokens.length)
|
|
486
|
+
return [];
|
|
487
|
+
const weights = tokens.map((token) => Math.max(2, token.length) + 1.5);
|
|
488
|
+
const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
|
|
489
|
+
const words = [];
|
|
490
|
+
let cursor = 0;
|
|
491
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
492
|
+
const span = (weights[index] / totalWeight) * duration;
|
|
493
|
+
const gap = Math.min(0.03, span * 0.1);
|
|
494
|
+
words.push({
|
|
495
|
+
text: tokens[index],
|
|
496
|
+
start: Number(cursor.toFixed(3)),
|
|
497
|
+
end: Number(Math.max(cursor + 0.05, cursor + span - gap).toFixed(3))
|
|
498
|
+
});
|
|
499
|
+
cursor += span;
|
|
500
|
+
}
|
|
501
|
+
return words;
|
|
502
|
+
}
|
|
503
|
+
export function captionInlineVars(config) {
|
|
504
|
+
const vars = [];
|
|
505
|
+
if (config.activeColor)
|
|
506
|
+
vars.push(`--vf-cap-active:${config.activeColor}`);
|
|
507
|
+
if (config.highlightColor)
|
|
508
|
+
vars.push(`--vf-cap-hl:${config.highlightColor}`);
|
|
509
|
+
return vars.join(";");
|
|
510
|
+
}
|
|
511
|
+
export function buildHyperframeCompositionHtml(input) {
|
|
512
|
+
const duration = positiveNumber(input.duration, inferDuration(input.layers));
|
|
513
|
+
const width = positiveInteger(input.width, 720);
|
|
514
|
+
const height = positiveInteger(input.height, 1280);
|
|
515
|
+
const background = input.backgroundColor || "#050604";
|
|
516
|
+
const fontImport = input.fontImportCss ?? "@import url(\"https://fonts.googleapis.com/css2?family=Abel&family=Montserrat:wght@600;700;800;900&family=Source+Code+Pro:wght@700&family=TikTok+Sans:wght@400;600;700;800;900&display=swap\");";
|
|
517
|
+
const layers = input.layers.map(renderLayer).join("\n ");
|
|
518
|
+
return `<!doctype html>
|
|
519
|
+
<html>
|
|
520
|
+
<head>
|
|
521
|
+
<meta charset="UTF-8" />
|
|
522
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
523
|
+
<style>
|
|
524
|
+
${fontImport}
|
|
525
|
+
html, body { width:100%; height:100%; margin:0; overflow:hidden; background:${background}; }
|
|
526
|
+
[data-composition-id] { position:relative; width:100vw; height:100vh; overflow:hidden; background:${background}; }
|
|
527
|
+
audio { display:none; }
|
|
528
|
+
${KEN_BURNS_CSS}
|
|
529
|
+
${CAPTION_ANIM_CSS}
|
|
530
|
+
${TRANSITION_CSS}
|
|
531
|
+
${input.css ?? ""}
|
|
532
|
+
</style>
|
|
533
|
+
</head>
|
|
534
|
+
<body>
|
|
535
|
+
<div data-composition-id="${escapeAttr(input.compositionId)}" data-source-folder="${escapeAttr(input.sourceFolder || "")}" data-width="${width}" data-height="${height}" data-duration="${num(duration)}">
|
|
536
|
+
${layers}
|
|
537
|
+
</div>
|
|
538
|
+
</body>
|
|
539
|
+
</html>
|
|
540
|
+
`;
|
|
541
|
+
}
|
|
542
|
+
export function inferDuration(layers) {
|
|
543
|
+
return layers.reduce((max, layer) => Math.max(max, positiveNumber(layer.start, 0) + positiveNumber(layer.duration, 0)), 0);
|
|
544
|
+
}
|
|
545
|
+
export function assertHyperframeTimeline(layers) {
|
|
546
|
+
const timedLayers = layers.filter((layer) => positiveNumber(layer.duration, 0) > 0);
|
|
547
|
+
for (const layer of timedLayers) {
|
|
548
|
+
if (!layer.id.trim())
|
|
549
|
+
throw new Error("HyperFrame layer id is required.");
|
|
550
|
+
if (positiveNumber(layer.start, -1) < 0)
|
|
551
|
+
throw new Error(`HyperFrame layer ${layer.id} has a negative start.`);
|
|
552
|
+
if (positiveNumber(layer.duration, 0) <= 0)
|
|
553
|
+
throw new Error(`HyperFrame layer ${layer.id} must have a positive duration.`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
// Public single-layer serializer so out-of-band builders (devcli composition
|
|
557
|
+
// edits) emit byte-identical layer markup to the composition builder.
|
|
558
|
+
export function renderHyperframeLayerHtml(layer) {
|
|
559
|
+
return renderLayer(layer);
|
|
560
|
+
}
|
|
561
|
+
// Alpha-capable media formats (mirror of the SPA editor's srcSupportsAlpha).
|
|
562
|
+
// A cut-out or watermark delivered in one of these can carry real
|
|
563
|
+
// transparency, so the layer is flagged data-transparent and never gets an
|
|
564
|
+
// opaque backdrop painted behind it.
|
|
565
|
+
const ALPHA_IMAGE_EXT = /\.(png|webp|gif|avif)(\?|#|$)/i;
|
|
566
|
+
const ALPHA_VIDEO_EXT = /\.(webm|mov)(\?|#|$)/i;
|
|
567
|
+
export function srcSupportsAlpha(kind, src) {
|
|
568
|
+
const clean = (src ?? "").trim();
|
|
569
|
+
if (!clean)
|
|
570
|
+
return false;
|
|
571
|
+
return kind === "image" ? ALPHA_IMAGE_EXT.test(clean) : ALPHA_VIDEO_EXT.test(clean);
|
|
572
|
+
}
|
|
573
|
+
function renderLayer(layer) {
|
|
574
|
+
const attrs = timedAttrs(layer);
|
|
575
|
+
const style = layerStyle(layer);
|
|
576
|
+
if (layer.kind === "video") {
|
|
577
|
+
const loop = layer.loop ? ` loop data-loop="true"` : "";
|
|
578
|
+
const alpha = srcSupportsAlpha("video", layer.src) ? ` data-transparent="true"` : "";
|
|
579
|
+
// Imported/added video keeps its native audio unless the caller explicitly
|
|
580
|
+
// mutes it (muted:true) — a persisted muted attribute silences the clip in
|
|
581
|
+
// BOTH preview unmute and the final render.
|
|
582
|
+
return `<video ${attrs}${loop}${alpha} src="${escapeAttr(layer.src || "")}" ${layer.muted === true ? "muted " : ""}playsinline preload="auto" style="${escapeAttr(style)}"></video>`;
|
|
583
|
+
}
|
|
584
|
+
if (layer.kind === "audio") {
|
|
585
|
+
return `<audio ${attrs} src="${escapeAttr(layer.src || "")}" data-timeline-role="music" data-volume="${num(positiveNumber(layer.volume, 1))}" preload="metadata"></audio>`;
|
|
586
|
+
}
|
|
587
|
+
if (layer.kind === "image") {
|
|
588
|
+
const kenBurns = normalizeKenBurns(layer.kenBurns);
|
|
589
|
+
if (kenBurns) {
|
|
590
|
+
// The animation lives directly on the <img> — the same node that carries
|
|
591
|
+
// data-start — so the render's CSS adapter seeks it by (frameTime -
|
|
592
|
+
// data-start) and it plays across exactly the clip's span.
|
|
593
|
+
const vars = kenBurnsInlineVars(kenBurns, positiveNumber(layer.duration, 0));
|
|
594
|
+
const kbStyle = vars ? `${style};${vars}` : style;
|
|
595
|
+
return `<img class="clip" ${attrs} data-kenburns="${escapeAttr(kenBurns.preset)}" src="${escapeAttr(layer.src || "")}" alt="" style="${escapeAttr(kbStyle)}" />`;
|
|
596
|
+
}
|
|
597
|
+
return `<img class="clip" ${attrs} src="${escapeAttr(layer.src || "")}" alt="" style="${escapeAttr(style)}" />`;
|
|
598
|
+
}
|
|
599
|
+
if (layer.kind === "html") {
|
|
600
|
+
return `<div class="clip" ${attrs} style="${escapeAttr(style)}">${layer.html || ""}</div>`;
|
|
601
|
+
}
|
|
602
|
+
const text = layer.text ?? layer.label ?? "";
|
|
603
|
+
const inlineStyle = textInlineCss(layer.textBackgroundStyle || "plain", layer.color || "#ffffff", layer.background || "#000000", layer.fontFamily || "TikTok Sans", positiveInteger(layer.fontWeight, 700));
|
|
604
|
+
const linesStyle = [
|
|
605
|
+
"display:block",
|
|
606
|
+
"max-width:100%",
|
|
607
|
+
"text-align:inherit",
|
|
608
|
+
`line-height:${positiveNumber(layer.lineHeight, 1.18)}`,
|
|
609
|
+
"white-space:pre-wrap",
|
|
610
|
+
"overflow:visible"
|
|
611
|
+
].join(";");
|
|
612
|
+
const captionConfig = layer.kind === "caption" || layer.kind === "text" ? normalizeCaptionConfig(layer.captionAnimation) : null;
|
|
613
|
+
if (captionConfig) {
|
|
614
|
+
const words = captionConfig.words ?? estimateCaptionWords(text, positiveNumber(layer.duration, 0));
|
|
615
|
+
if (words.length) {
|
|
616
|
+
const vars = captionInlineVars(captionConfig);
|
|
617
|
+
// text-transform must be INLINE: layerStyle already writes an inline
|
|
618
|
+
// text-transform:none, which would beat the [data-caption-uppercase]
|
|
619
|
+
// stylesheet rule. The attribute stays for round-trip state reads.
|
|
620
|
+
// overflow:visible (overriding layerStyle's hidden) because caption text
|
|
621
|
+
// wrapping past the cue box must never clip mid-glyph.
|
|
622
|
+
const upper = captionConfig.uppercase ? ";text-transform:uppercase" : "";
|
|
623
|
+
const divStyle = `${style}${vars ? `;${vars}` : ""}${upper};overflow:visible`;
|
|
624
|
+
const captionAttrs = `${attrs} data-caption-animation="${escapeAttr(captionConfig.animation)}"${captionConfig.uppercase ? " data-caption-uppercase=\"1\"" : ""}`;
|
|
625
|
+
return `<div class="clip" ${captionAttrs} style="${escapeAttr(divStyle)}"><span data-vf-text-lines="true" style="${escapeAttr(linesStyle)}"><span data-vf-text-inline="true" style="${escapeAttr(inlineStyle)}">${captionWordSpansHtml(words)}</span></span></div>`;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return `<div class="clip" ${attrs} style="${escapeAttr(style)}"><span data-vf-text-lines="true" style="${escapeAttr(linesStyle)}"><span data-vf-text-inline="true" style="${escapeAttr(inlineStyle)}">${escapeHtml(text)}</span></span></div>`;
|
|
629
|
+
}
|
|
630
|
+
// Serializes word windows into the <span data-cap-word> run that the caption
|
|
631
|
+
// stylesheet animates. Delay/duration are the word window relative to the
|
|
632
|
+
// layer start — the ONLY timing source the render adapter needs; the
|
|
633
|
+
// data-word-* attrs exist so editing surfaces can re-derive timings without
|
|
634
|
+
// parsing CSS.
|
|
635
|
+
export function captionWordSpansHtml(words) {
|
|
636
|
+
return words
|
|
637
|
+
.map((word) => {
|
|
638
|
+
const start = Math.max(0, positiveNumber(word.start, 0));
|
|
639
|
+
const end = Math.max(start + 0.05, positiveNumber(word.end, start + 0.05));
|
|
640
|
+
const wordStyle = `animation-delay:${num(start)}s;animation-duration:${num(end - start)}s`;
|
|
641
|
+
return `<span data-cap-word="true" data-word-start="${num(start)}" data-word-end="${num(end)}" style="${wordStyle}">${escapeHtml(word.text)}</span>`;
|
|
642
|
+
})
|
|
643
|
+
.join(" ");
|
|
644
|
+
}
|
|
645
|
+
function timedAttrs(layer) {
|
|
646
|
+
const attrs = [
|
|
647
|
+
`id="${escapeAttr(layer.id)}"`,
|
|
648
|
+
`data-hf-id="${escapeAttr(layer.id)}"`,
|
|
649
|
+
`data-layer-mode="${escapeAttr(layer.mode || "publish")}"`,
|
|
650
|
+
`data-layer-kind="${escapeAttr(layer.kind)}"`,
|
|
651
|
+
`data-viral-note="${escapeAttr(layer.viralAlignment || "")}"`,
|
|
652
|
+
`data-start="${num(positiveNumber(layer.start, 0))}"`,
|
|
653
|
+
`data-duration="${num(positiveNumber(layer.duration, 0))}"`,
|
|
654
|
+
`data-track-index="${positiveInteger(layer.track, 0)}"`,
|
|
655
|
+
`data-label="${escapeAttr(layer.label || layer.id)}"`
|
|
656
|
+
];
|
|
657
|
+
if (layer.mediaStart !== undefined || layer.playbackStart !== undefined) {
|
|
658
|
+
const mediaStart = positiveNumber(layer.playbackStart ?? layer.mediaStart, 0);
|
|
659
|
+
attrs.push(`data-media-start="${num(mediaStart)}"`, `data-playback-start="${num(mediaStart)}"`);
|
|
660
|
+
}
|
|
661
|
+
if (layer.kind !== "audio") {
|
|
662
|
+
const transition = normalizeTransition(layer.transition);
|
|
663
|
+
if (transition) {
|
|
664
|
+
attrs.push(`data-transition="${escapeAttr(transition.preset)}"`, `data-transition-duration="${num(clampTransitionDuration(transition.duration ?? TRANSITION_DEFAULT_DURATION))}"`);
|
|
665
|
+
}
|
|
666
|
+
const transitionOut = normalizeTransitionOut(layer.transitionOut);
|
|
667
|
+
if (transitionOut) {
|
|
668
|
+
attrs.push(`data-transition-out="${escapeAttr(transitionOut.preset)}"`, `data-transition-out-duration="${num(clampTransitionDuration(transitionOut.duration ?? TRANSITION_DEFAULT_DURATION))}"`);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (["caption", "text", "shape", "html"].includes(layer.kind)) {
|
|
672
|
+
attrs.push(`data-text-background-style="${escapeAttr(layer.textBackgroundStyle || "plain")}"`, `data-text-background-color="${escapeAttr(layer.background || "#000000")}"`, `data-font-family="${escapeAttr(layer.fontFamily || "TikTok Sans")}"`);
|
|
673
|
+
}
|
|
674
|
+
return attrs.join(" ");
|
|
675
|
+
}
|
|
676
|
+
function layerStyle(layer) {
|
|
677
|
+
const styles = [
|
|
678
|
+
"position:absolute",
|
|
679
|
+
`left:${positiveNumber(layer.x, 0)}%`,
|
|
680
|
+
`top:${positiveNumber(layer.y, 0)}%`,
|
|
681
|
+
`width:${positiveNumber(layer.width, 100)}%`,
|
|
682
|
+
`height:${positiveNumber(layer.height, 100)}%`,
|
|
683
|
+
`z-index:${positiveInteger(layer.z, 0)}`,
|
|
684
|
+
`opacity:${positiveNumber(layer.opacity, 1)}`,
|
|
685
|
+
`border-radius:${positiveInteger(layer.radius, 0)}px`,
|
|
686
|
+
"overflow:hidden"
|
|
687
|
+
];
|
|
688
|
+
if (layer.kind === "video" || layer.kind === "image") {
|
|
689
|
+
styles.push(`object-fit:${layer.fit || "cover"}`);
|
|
690
|
+
}
|
|
691
|
+
if (layer.kind !== "audio") {
|
|
692
|
+
// data-transition picks the keyframes; the inline var supplies the span so
|
|
693
|
+
// the animation covers exactly the transition window.
|
|
694
|
+
const transition = normalizeTransition(layer.transition);
|
|
695
|
+
if (transition) {
|
|
696
|
+
styles.push(`--vf-tr-dur:${num(clampTransitionDuration(transition.duration ?? TRANSITION_DEFAULT_DURATION))}s`);
|
|
697
|
+
}
|
|
698
|
+
// Exit transitions additionally need the delay var so the animation window
|
|
699
|
+
// sits at the clip's tail (duration − out duration).
|
|
700
|
+
const transitionOut = normalizeTransitionOut(layer.transitionOut);
|
|
701
|
+
if (transitionOut) {
|
|
702
|
+
const outDur = clampTransitionDuration(transitionOut.duration ?? TRANSITION_DEFAULT_DURATION);
|
|
703
|
+
styles.push(`--vf-tr-out-dur:${num(outDur)}s`, `--vf-tr-out-delay:${num(transitionOutDelaySeconds(positiveNumber(layer.duration, 0), outDur))}s`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (["caption", "text", "shape", "html"].includes(layer.kind)) {
|
|
707
|
+
const fontFamily = layer.fontFamily || "TikTok Sans";
|
|
708
|
+
styles.push("display:flex", "align-items:center", "justify-content:center", "padding:3px", `font-family:${fontCssFamily(fontFamily)}, 'TikTok Sans', Montserrat, Abel, sans-serif`, `font-weight:${positiveInteger(layer.fontWeight, 700)}`, `line-height:${positiveNumber(layer.lineHeight, 1.18)}`, "text-align:center", "text-transform:none", `font-size:${positiveInteger(layer.fontSize, 32)}px`, `color:${layer.color || "#ffffff"}`, layer.kind === "shape" && layer.textBackgroundStyle === "panel"
|
|
709
|
+
? `background:${layer.background || "transparent"}`
|
|
710
|
+
: "background:transparent");
|
|
711
|
+
}
|
|
712
|
+
for (const [property, value] of Object.entries(layer.style || {})) {
|
|
713
|
+
styles.push(`${property}:${value}`);
|
|
714
|
+
}
|
|
715
|
+
return styles.join(";");
|
|
716
|
+
}
|
|
717
|
+
function textInlineCss(style, color, background, fontFamily, fontWeight) {
|
|
718
|
+
const styles = [
|
|
719
|
+
"display:inline",
|
|
720
|
+
"box-decoration-break:clone",
|
|
721
|
+
"-webkit-box-decoration-break:clone",
|
|
722
|
+
"line-height:inherit"
|
|
723
|
+
];
|
|
724
|
+
if (style === "plain" || style === "panel") {
|
|
725
|
+
styles.push("padding:0", "border-radius:0", "background:transparent", "text-shadow:none", "-webkit-text-stroke:0 transparent");
|
|
726
|
+
}
|
|
727
|
+
else if (style === "outline") {
|
|
728
|
+
styles.push("padding:0", "border-radius:0", "background:transparent", `text-shadow:2px 0 ${background},-2px 0 ${background},0 2px ${background},0 -2px ${background},1.5px 1.5px ${background},-1.5px 1.5px ${background},1.5px -1.5px ${background},-1.5px -1.5px ${background}`, `-webkit-text-stroke:1.5px ${background}`, "paint-order:stroke fill");
|
|
729
|
+
}
|
|
730
|
+
else if (style === "highlight-solid") {
|
|
731
|
+
styles.push("padding:0.07em 0.46em 0.09em", "border-radius:0.32em", `background:${background}`, "text-shadow:none", "-webkit-text-stroke:0 transparent");
|
|
732
|
+
}
|
|
733
|
+
else if (style === "highlight-translucent") {
|
|
734
|
+
styles.push("padding:0.07em 0.46em 0.09em", "border-radius:0.32em", `background:${rgbaFromColor(background, 0.34)}`, "text-shadow:none", "-webkit-text-stroke:0 transparent");
|
|
735
|
+
}
|
|
736
|
+
styles.push(`font-family:${fontCssFamily(fontFamily)}, 'TikTok Sans', sans-serif`);
|
|
737
|
+
styles.push(`font-weight:${fontWeight}`);
|
|
738
|
+
styles.push(`color:${color}`);
|
|
739
|
+
return styles.join(";");
|
|
740
|
+
}
|
|
741
|
+
function fontCssFamily(font) {
|
|
742
|
+
return font === "Georgia" ? "Georgia" : `'${font.replaceAll("'", "")}'`;
|
|
743
|
+
}
|
|
744
|
+
function rgbaFromColor(value, alpha) {
|
|
745
|
+
const clean = String(value || "").trim();
|
|
746
|
+
const hex = clean.startsWith("#") ? clean.slice(1) : "";
|
|
747
|
+
if (hex.length === 3 || hex.length === 6) {
|
|
748
|
+
const full = hex.length === 3 ? hex.split("").map((part) => part + part).join("") : hex;
|
|
749
|
+
const numeric = Number.parseInt(full, 16);
|
|
750
|
+
if (Number.isFinite(numeric)) {
|
|
751
|
+
const red = (numeric >> 16) & 255;
|
|
752
|
+
const green = (numeric >> 8) & 255;
|
|
753
|
+
const blue = numeric & 255;
|
|
754
|
+
return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
return clean.startsWith("rgba(") || clean.startsWith("rgb(") ? clean : `rgba(0, 0, 0, ${alpha})`;
|
|
758
|
+
}
|
|
759
|
+
function positiveNumber(value, fallback) {
|
|
760
|
+
const next = Number(value);
|
|
761
|
+
return Number.isFinite(next) && next >= 0 ? next : fallback;
|
|
762
|
+
}
|
|
763
|
+
function positiveInteger(value, fallback) {
|
|
764
|
+
const next = Math.round(Number(value));
|
|
765
|
+
return Number.isFinite(next) && next >= 0 ? next : fallback;
|
|
766
|
+
}
|
|
767
|
+
function num(value) {
|
|
768
|
+
return Number(Number(value || 0).toFixed(3)).toString();
|
|
769
|
+
}
|
|
770
|
+
function escapeHtml(value) {
|
|
771
|
+
return String(value ?? "")
|
|
772
|
+
.replaceAll("&", "&")
|
|
773
|
+
.replaceAll("<", "<")
|
|
774
|
+
.replaceAll(">", ">")
|
|
775
|
+
.replaceAll('"', """);
|
|
776
|
+
}
|
|
777
|
+
function escapeAttr(value) {
|
|
778
|
+
return escapeHtml(String(value ?? ""));
|
|
779
|
+
}
|
|
780
|
+
//# sourceMappingURL=composition.js.map
|