@mevdragon/vidfarm-devcli 0.13.0 → 0.15.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/.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/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/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/vidfarm-media/SKILL.md +85 -0
- package/.agents/skills/vidfarm-media/references/tts.md +54 -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/SKILL.director.md +60 -4
- package/SKILL.platform.md +7 -2
- package/demo/dist/app.css +1 -1
- package/demo/dist/app.js +485 -86
- package/dist/src/account-pages-legacy.js +9 -14
- package/dist/src/app.js +659 -159
- package/dist/src/cli.js +618 -17
- package/dist/src/composition-runtime.js +286 -6
- package/dist/src/devcli/composition-edit.js +176 -8
- package/dist/src/devcli/doctor.js +192 -0
- package/dist/src/devcli/hyperframes-cli.js +118 -0
- package/dist/src/devcli/skills.js +476 -0
- package/dist/src/devcli/stills.js +249 -0
- package/dist/src/devcli/transitions.js +205 -0
- package/dist/src/editor-chat.js +260 -4
- package/dist/src/frontend/template-editor-chat.js +6 -5
- package/dist/src/homepage.js +2 -48
- package/dist/src/hyperframes/composition.js +188 -7
- package/dist/src/services/composition-lint.js +199 -0
- package/dist/src/services/hyperframes.js +127 -28
- package/dist/src/services/serverless-records.js +7 -0
- package/dist/src/template-editor-shell.js +87 -48
- package/package.json +2 -1
- package/public/assets/page-runtime-client-app.js +31 -31
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Typographic moves — a palette, not a cage
|
|
2
|
+
|
|
3
|
+
`cinematic-cream` template locks DNA only (font-family, motion, color
|
|
4
|
+
palette defaults). It does NOT enforce slot structure. The agent writes
|
|
5
|
+
each caption group's typography from scratch via the plan.json `css`
|
|
6
|
+
field.
|
|
7
|
+
|
|
8
|
+
This doc is a **palette** of tried combinations — pick what fits the
|
|
9
|
+
scene, invent new ones, skip these if the content demands. These are
|
|
10
|
+
recommendations, not rules.
|
|
11
|
+
|
|
12
|
+
## Size vs text length — DO THIS BEFORE PICKING SIZE
|
|
13
|
+
|
|
14
|
+
Bigger is NOT better if the word doesn't fit the frame width. Every time
|
|
15
|
+
you pick a font-size, sanity-check against word length:
|
|
16
|
+
|
|
17
|
+
**Rough rule for Inter 900 uppercase at -0.03em tracking:**
|
|
18
|
+
`max_font_px ≈ frame_width / (longest_word_chars × 0.72)`
|
|
19
|
+
|
|
20
|
+
The 0.72 multiplier is intentionally conservative — it targets the text
|
|
21
|
+
filling ~90% of the frame width so there's a small side margin. If you
|
|
22
|
+
want edge-to-edge, drop to 0.65, but you lose a bit of safety margin.
|
|
23
|
+
|
|
24
|
+
720px portrait:
|
|
25
|
+
|
|
26
|
+
- 3-char word (15%): max ~330px (a single big number like "15%")
|
|
27
|
+
- 5-char word (TAKE): max ~200px
|
|
28
|
+
- 7-char word (AUGMENT / QUANTUM / MATTERS): max ~143px
|
|
29
|
+
- 10-char word (CREATIVITY): max ~100px
|
|
30
|
+
- 13-char word (UNPRECEDENTED): max ~77px
|
|
31
|
+
|
|
32
|
+
1920px landscape:
|
|
33
|
+
|
|
34
|
+
- 7-char word: max ~380px
|
|
35
|
+
- 10-char word: max ~267px
|
|
36
|
+
|
|
37
|
+
For italic/upright 500-700 it's slightly narrower — increase max by ~10%.
|
|
38
|
+
|
|
39
|
+
**If you want the word bigger than it fits:**
|
|
40
|
+
|
|
41
|
+
- Split into multiple words per group (natural wrap), OR
|
|
42
|
+
- Add explicit `<br>` between syllables, OR
|
|
43
|
+
- Drop letter-spacing to -0.05em, OR
|
|
44
|
+
- Accept that the matte will cut part of it (Vogue-cover embed effect —
|
|
45
|
+
only works when the cut area is exactly where the subject is)
|
|
46
|
+
|
|
47
|
+
Never let the text OVERFLOW the frame edge — that's not cinematic, that's
|
|
48
|
+
just broken. Use the heuristic.
|
|
49
|
+
|
|
50
|
+
## Sizing discipline (frame-height-relative)
|
|
51
|
+
|
|
52
|
+
Portrait 9:16 (720×1290) and landscape 16:9 (1920×1080) have very
|
|
53
|
+
different comfort ranges. Use `calc(<pct> * var(--h))` for responsive:
|
|
54
|
+
|
|
55
|
+
| Feel | % of frame height | Example calc |
|
|
56
|
+
| ---------------------- | ----------------- | ----------------------- |
|
|
57
|
+
| Whisper / label | 4-6% | `calc(0.05 * var(--h))` |
|
|
58
|
+
| Soft opener | 6-9% | `calc(0.07 * var(--h))` |
|
|
59
|
+
| Narrative body | 9-14% | `calc(0.11 * var(--h))` |
|
|
60
|
+
| Emphasis | 14-22% | `calc(0.18 * var(--h))` |
|
|
61
|
+
| Climax / monumental | 22-35% | `calc(0.28 * var(--h))` |
|
|
62
|
+
| Title-bigger-than-face | 40%+ | `calc(0.48 * var(--h))` |
|
|
63
|
+
|
|
64
|
+
Use absolute px only when a specific scale needs to look identical
|
|
65
|
+
across frame sizes (rare). Prefer `calc` + `var(--h)`.
|
|
66
|
+
|
|
67
|
+
## Named moves — pick per group
|
|
68
|
+
|
|
69
|
+
**Italic contemplative opener** (memory-wall cap-1 lineage):
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
font-style: italic;
|
|
74
|
+
letter-spacing: -0.01em;
|
|
75
|
+
font-size: calc(0.075 * var(--h));
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Italic continuation / dreamier continuation** (cap-2 lineage):
|
|
79
|
+
|
|
80
|
+
```css
|
|
81
|
+
font-weight: 500;
|
|
82
|
+
font-style: italic;
|
|
83
|
+
letter-spacing: -0.005em;
|
|
84
|
+
font-size: calc(0.065 * var(--h));
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Upright pivot / statement** (cap-3 lineage — "but suddenly"):
|
|
88
|
+
|
|
89
|
+
```css
|
|
90
|
+
font-weight: 700;
|
|
91
|
+
letter-spacing: -0.015em;
|
|
92
|
+
font-size: calc(0.07 * var(--h));
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Uppercase climax / monumental** (cap-4 lineage — "EVERYTHING IS SHARP AGAIN"):
|
|
96
|
+
|
|
97
|
+
```css
|
|
98
|
+
font-weight: 900;
|
|
99
|
+
text-transform: uppercase;
|
|
100
|
+
letter-spacing: -0.03em;
|
|
101
|
+
line-height: 0.95;
|
|
102
|
+
font-size: calc(0.18 * var(--h));
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Chapter card / full-frame Adam Curtis manifesto**:
|
|
106
|
+
|
|
107
|
+
```css
|
|
108
|
+
font-weight: 700;
|
|
109
|
+
text-transform: uppercase;
|
|
110
|
+
letter-spacing: -0.015em;
|
|
111
|
+
line-height: 0.9;
|
|
112
|
+
font-size: calc(0.14 * var(--h));
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**News chyron / broadcast label** (small, locked):
|
|
116
|
+
|
|
117
|
+
```css
|
|
118
|
+
font-weight: 500;
|
|
119
|
+
letter-spacing: 0.02em;
|
|
120
|
+
font-size: calc(0.038 * var(--h));
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Tiny side note / caption-on-surface**:
|
|
124
|
+
|
|
125
|
+
```css
|
|
126
|
+
font-weight: 400;
|
|
127
|
+
font-style: italic;
|
|
128
|
+
font-size: calc(0.045 * var(--h));
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Vogue-masthead monumental**:
|
|
132
|
+
|
|
133
|
+
```css
|
|
134
|
+
font-weight: 900;
|
|
135
|
+
text-transform: uppercase;
|
|
136
|
+
letter-spacing: -0.04em;
|
|
137
|
+
line-height: 0.85;
|
|
138
|
+
font-size: calc(0.32 * var(--h));
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Narrative arcs (suggestions, not required)
|
|
142
|
+
|
|
143
|
+
**Poem arc** — memory-wall canonical: italic opener → italic continuation
|
|
144
|
+
→ upright pivot → uppercase climax. Four steps.
|
|
145
|
+
|
|
146
|
+
**Question-answer arc**: italic question small → uppercase answer big.
|
|
147
|
+
Two steps.
|
|
148
|
+
|
|
149
|
+
**List-of-three arc**: three equal-weight narration segments, one
|
|
150
|
+
climactic uppercase. Four steps.
|
|
151
|
+
|
|
152
|
+
**Single-statement arc**: one monumental uppercase held long. One step.
|
|
153
|
+
|
|
154
|
+
**Whisper-hook arc** (short-form): tiny italic hook → massive uppercase
|
|
155
|
+
reveal. Two steps.
|
|
156
|
+
|
|
157
|
+
The **number** of groups comes from the **content**. A 25s Pausch talk
|
|
158
|
+
has ~8 beats. A 7s TikTok hook has 2-3 beats. Don't force 4 or 5 or 7 —
|
|
159
|
+
read the transcript and mark breath-groups.
|
|
160
|
+
|
|
161
|
+
## Position + layer vocabulary
|
|
162
|
+
|
|
163
|
+
**Position** is where the caption lives in frame. Use:
|
|
164
|
+
|
|
165
|
+
- `top / left / right / bottom` (percentages or px) for anchor
|
|
166
|
+
- `transform: translateX/Y` for fine offsets
|
|
167
|
+
- `text-align: center / left / right` for alignment
|
|
168
|
+
|
|
169
|
+
**Layer** per group:
|
|
170
|
+
|
|
171
|
+
- `bg` (default) — behind subject. Matte occludes. Cinematic embed. Works
|
|
172
|
+
on clean zones (sky, walls) OR intentionally crosses subject for the
|
|
173
|
+
Vogue-masthead effect.
|
|
174
|
+
- `fg` — on top of subject. Announcement. Use for climax breakthroughs or
|
|
175
|
+
when bg would be 100% occluded by body.
|
|
176
|
+
|
|
177
|
+
**Tone** per group:
|
|
178
|
+
|
|
179
|
+
- `soft` — gentle per-word opacity+y drift (0.45s power2.out). Use for
|
|
180
|
+
introspective, dreamy, or narrative content.
|
|
181
|
+
- `present` — snappy per-word opacity+y+scale pop (0.22s power3.out). Use
|
|
182
|
+
for emphatic or declarative beats.
|
|
183
|
+
|
|
184
|
+
## Anti-patterns the DNA protects against
|
|
185
|
+
|
|
186
|
+
The DNA defaults prevent most ugly outcomes. But avoid in per-group CSS:
|
|
187
|
+
|
|
188
|
+
- Multiple different `font-family` within one video (DNA is one family)
|
|
189
|
+
- Multiple saturated colors (one accent at most; DNA defaults cream or
|
|
190
|
+
deep warm)
|
|
191
|
+
- `letter-spacing` above ±0.05em unless there's a specific reason
|
|
192
|
+
- `font-weight` 300 or below — too light for screen
|
|
193
|
+
- `font-style: italic` on emphasis — italic is for lyricism, not stress
|
|
194
|
+
|
|
195
|
+
## When cinematic-cream is wrong
|
|
196
|
+
|
|
197
|
+
This DNA assumes mid-to-dark backgrounds (luminance 60-180). For:
|
|
198
|
+
|
|
199
|
+
- Bright white studios → cinematic-cream's cream + `screen` washes out, and the DNA is
|
|
200
|
+
**locked** (you cannot recolour it) → use **Standard mode** (opaque rail) instead
|
|
201
|
+
- Documentary formal → Standard mode (documentary-dignified direction; see references/direction-catalog.md §1)
|
|
202
|
+
- Energetic vlog hooks → future `kinetic-vlog` DNA (not yet shipped)
|
|
203
|
+
|
|
204
|
+
## Example: memory-wall original, expressed in freeform
|
|
205
|
+
|
|
206
|
+
Same output as the canonical memory-wall.html, but using slot-free plan:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"template": "cinematic-cream",
|
|
211
|
+
"caption_layer": "bg",
|
|
212
|
+
"groups": [
|
|
213
|
+
{
|
|
214
|
+
"id": "cg-0",
|
|
215
|
+
"tone": "soft",
|
|
216
|
+
"in": 0.2,
|
|
217
|
+
"out": 4.85,
|
|
218
|
+
"css": "top: 14%; right: 6%; left: auto; text-align: right; font-size: calc(0.09 * var(--h)); font-weight: 600; font-style: italic; letter-spacing: -0.01em;",
|
|
219
|
+
"words": [
|
|
220
|
+
{ "text": "Some", "start": 0.24, "end": 0.44 },
|
|
221
|
+
{ "text": "memories", "start": 0.48, "end": 0.82 },
|
|
222
|
+
{ "text": "feel", "start": 0.92, "end": 1.14 },
|
|
223
|
+
{ "text": "soft", "start": 1.2, "end": 1.64 }
|
|
224
|
+
]
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"id": "cg-1",
|
|
228
|
+
"tone": "soft",
|
|
229
|
+
"in": 2.55,
|
|
230
|
+
"out": 4.85,
|
|
231
|
+
"css": "top: 26%; right: 10%; left: auto; text-align: right; font-size: calc(0.075 * var(--h)); font-weight: 500; font-style: italic;",
|
|
232
|
+
"words": [
|
|
233
|
+
{ "text": "like", "start": 2.66, "end": 2.78 },
|
|
234
|
+
{ "text": "old", "start": 2.88, "end": 3.02 },
|
|
235
|
+
{ "text": "film", "start": 3.16, "end": 3.46 }
|
|
236
|
+
]
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"id": "cg-2",
|
|
240
|
+
"tone": "present",
|
|
241
|
+
"in": 4.9,
|
|
242
|
+
"out": 8.04,
|
|
243
|
+
"css": "top: 18%; right: 6%; left: auto; text-align: right; font-size: calc(0.085 * var(--h)); font-weight: 700;",
|
|
244
|
+
"words": [
|
|
245
|
+
{ "text": "but", "start": 5.04, "end": 5.18 },
|
|
246
|
+
{ "text": "suddenly", "start": 5.24, "end": 5.76 }
|
|
247
|
+
]
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"id": "cg-3",
|
|
251
|
+
"tone": "present",
|
|
252
|
+
"in": 6.7,
|
|
253
|
+
"out": 8.04,
|
|
254
|
+
"css": "top: 32%; right: 6%; left: auto; text-align: right; font-size: calc(0.11 * var(--h)); font-weight: 900; text-transform: uppercase; letter-spacing: -0.03em; line-height: 0.95;",
|
|
255
|
+
"words": [
|
|
256
|
+
{ "text": "everything", "start": 6.82, "end": 7.14 },
|
|
257
|
+
{ "text": "is", "start": 7.18, "end": 7.28 },
|
|
258
|
+
{ "text": "sharp", "start": 7.32, "end": 7.52 },
|
|
259
|
+
{ "text": "again", "start": 7.58, "end": 7.92 }
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Same visual, no slot constraint. Each group owns its typography.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Typography Presets
|
|
2
|
+
|
|
3
|
+
Five named styles corresponding to the `cap-*` CSS classes. Pick one per caption group in `plan.json` based on the line's semantic role.
|
|
4
|
+
|
|
5
|
+
| style | CSS | Use when |
|
|
6
|
+
| -------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| `intro` | 66px italic 500 | First line, filler ("You know…", "So…"), contemplative openings. Low visual weight. |
|
|
8
|
+
| `phrase` | 78px upright 600 | Main statement clauses. Default for most lines. |
|
|
9
|
+
| `emph` | 92px upright 800 | Lines with emotional peak or key achievement ("I've achieved incredible things"). |
|
|
10
|
+
| `dream` | 82px italic 700 | Aspirational / "was dreaming of…" style lines. Italic signals memory/imagination. |
|
|
11
|
+
| `crown` | 140px upright 900 uppercase | **Only for the climax line.** Used in center-stage `crown-plane`. Maximum one per composition — ideally the last caption. |
|
|
12
|
+
|
|
13
|
+
## Tone field
|
|
14
|
+
|
|
15
|
+
Independent of style, each group has `tone`: `soft` or `present`.
|
|
16
|
+
|
|
17
|
+
- **soft** — gentle fade + 8px y-drift entrance, `power2.out` ease. Feels floaty, nostalgic. Use for memory, intro, dream.
|
|
18
|
+
- **present** — snappy 6px y + 1.04 scale pop, `power3.out`, transformOrigin center. Feels assertive, in-the-moment. Use for emphasis and crown.
|
|
19
|
+
|
|
20
|
+
## Picking automatically
|
|
21
|
+
|
|
22
|
+
Scan each group's words:
|
|
23
|
+
|
|
24
|
+
1. Does it contain superlatives (incredible, best, only, never, always) or brand/proper nouns? → `emph` + `present`
|
|
25
|
+
2. Does it start with discourse markers (you know, so, well, look) or is it short (≤3 words)? → `intro` + `soft`
|
|
26
|
+
3. Does it reference dreams, hopes, memory, past tense verbs like "was dreaming"? → `dream` + `soft`
|
|
27
|
+
4. Is it the final sentence-clinching line and feels like a title/headline? → `crown` + `present` (only one per video)
|
|
28
|
+
5. Otherwise → `phrase` + (match the group's neighbors' tone; default `soft`)
|
|
29
|
+
|
|
30
|
+
## Font-size scales with column width
|
|
31
|
+
|
|
32
|
+
The `.cap-*` defaults in each template are tuned for a **~560px column** (the original champion composition). When the caption plane is wider than that, the fonts feel underweight — too much negative space around text. Scale up accordingly.
|
|
33
|
+
|
|
34
|
+
| Plane width | intro | phrase | emph | dream | crown (centered, full-frame) | crown (clean-zone only) |
|
|
35
|
+
| ------------------- | ----- | ------ | ---- | ----- | ---------------------------- | ----------------------- |
|
|
36
|
+
| 460-580 px (tight) | 66 | 78 | 92 | 82 | 140 | n/a |
|
|
37
|
+
| 600-760 px (medium) | 78 | 108 | 128 | 100 | 220 | 118 |
|
|
38
|
+
| 780+ px (wide) | 90 | 128 | 150 | 116 | 260 | 140 |
|
|
39
|
+
|
|
40
|
+
Notes:
|
|
41
|
+
|
|
42
|
+
- Crown sizes assume landscape (1920×1080). For portrait 1080×1920, divide all crown sizes by 1.5.
|
|
43
|
+
- "full-frame crown" = centered, designed to span `0.8+ × frame_width` and cross the subject's body. Use only when [layout-heuristics.md § Crown placement](layout-heuristics.md) conditions pass.
|
|
44
|
+
- "clean-zone only crown" = crown positioned inside one clean zone, smaller font, tail letters lightly touch subject. Fallback when centered crown would eat too much.
|
|
45
|
+
|
|
46
|
+
Also: if a plane's `rotateY` is non-trivial (say > 8°), effective visible width shrinks. Scale fonts up ~10% to compensate.
|
|
47
|
+
|
|
48
|
+
## What NOT to do
|
|
49
|
+
|
|
50
|
+
- Don't use more than **one crown** per render. The whole point is that it's a singular payoff.
|
|
51
|
+
- Don't use `emph` on more than ~30% of groups. Emphasis loses meaning when everything is emphasized.
|
|
52
|
+
- Don't pick `intro` for the main content just because the words are short. "I won" (2 words) is `emph` or `crown`, not `intro`.
|
|
53
|
+
- Don't mix `soft` and `present` alternately for no reason. Tone should follow the story arc: soft opening → present build → emph peak → (optional crown climax).
|
|
54
|
+
|
|
55
|
+
## When scene luminance affects color choice
|
|
56
|
+
|
|
57
|
+
The default color is warm bone-white (`#fff5df`). Adjust in the template CSS:
|
|
58
|
+
|
|
59
|
+
- Wall is mostly warm wood / tan → keep default, or shift cooler `#e8f0ff`
|
|
60
|
+
- Wall is cool blue / tech-lab → push warmer `#fff0c0`
|
|
61
|
+
- Wall has strong primary color → desaturate default, luminance first
|
|
62
|
+
|
|
63
|
+
These adjustments happen in the HTML template, not plan.json. If you repeatedly need different palettes, make new template variants.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* audio-envelope.cjs — extract a per-50ms RMS loudness envelope from the source audio.
|
|
4
|
+
*
|
|
5
|
+
* node audio-envelope.cjs <project-dir> → <project>/envelope.json
|
|
6
|
+
*
|
|
7
|
+
* { hop: 0.05, rms: [linear 0..1 per hop] }
|
|
8
|
+
*
|
|
9
|
+
* Used by lib-dna.cjs to couple the hero's entrance amplitude to how hard the word was
|
|
10
|
+
* actually SPOKEN (percentile of the hero window's loudness within the clip). ffmpeg
|
|
11
|
+
* astats over fixed windows — deterministic, no network, no Python.
|
|
12
|
+
*/
|
|
13
|
+
const path = require("path");
|
|
14
|
+
const fs = require("fs");
|
|
15
|
+
const cp = require("child_process");
|
|
16
|
+
|
|
17
|
+
const HOP = 0.05;
|
|
18
|
+
|
|
19
|
+
function findSource(project) {
|
|
20
|
+
for (const c of ["source.mp4"].concat(
|
|
21
|
+
fs
|
|
22
|
+
.readdirSync(project)
|
|
23
|
+
.filter(
|
|
24
|
+
(f) =>
|
|
25
|
+
/\.(mp4|mov|webm|mkv|m4v|wav|m4a|mp3)$/i.test(f) &&
|
|
26
|
+
!/^(final|bg_plus_caps|fg_caps|rail|index)/.test(f),
|
|
27
|
+
),
|
|
28
|
+
)) {
|
|
29
|
+
const p = path.join(project, c);
|
|
30
|
+
if (fs.existsSync(p)) return p;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function main() {
|
|
36
|
+
const project = path.resolve(process.argv[2] || "");
|
|
37
|
+
if (!process.argv[2]) {
|
|
38
|
+
console.error("usage: audio-envelope.cjs <project-dir>");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
const src = findSource(project);
|
|
42
|
+
if (!src) {
|
|
43
|
+
console.error("[envelope] no source media found");
|
|
44
|
+
process.exit(2);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// asetnsamples groups audio into fixed windows; astats prints RMS per window
|
|
48
|
+
const sr = 16000,
|
|
49
|
+
n = Math.round(sr * HOP);
|
|
50
|
+
let out;
|
|
51
|
+
try {
|
|
52
|
+
// resample INSIDE the filter chain — an output-option -ar applies after the
|
|
53
|
+
// filtergraph, which would make each window n/<input-rate> seconds instead of HOP
|
|
54
|
+
out = cp.execFileSync(
|
|
55
|
+
"ffmpeg",
|
|
56
|
+
[
|
|
57
|
+
"-v",
|
|
58
|
+
"info",
|
|
59
|
+
"-i",
|
|
60
|
+
src,
|
|
61
|
+
"-map",
|
|
62
|
+
"a:0",
|
|
63
|
+
"-af",
|
|
64
|
+
`aresample=${sr},aformat=channel_layouts=mono,asetnsamples=n=${n}:p=0,astats=metadata=1:reset=1,ametadata=mode=print:key=lavfi.astats.Overall.RMS_level:file=-`,
|
|
65
|
+
"-f",
|
|
66
|
+
"null",
|
|
67
|
+
"-",
|
|
68
|
+
],
|
|
69
|
+
{ encoding: "utf8", maxBuffer: 64 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] },
|
|
70
|
+
);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
// ffmpeg writes the metadata to stdout before exiting; some containers still exit 0 — re-throw only if nothing parsed
|
|
73
|
+
out = (e.stdout || "") + "";
|
|
74
|
+
if (!out.includes("RMS_level")) {
|
|
75
|
+
console.error(`[envelope] ffmpeg failed: ${e.message}`);
|
|
76
|
+
process.exit(2);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const rmsDb = [];
|
|
80
|
+
for (const line of String(out).split("\n")) {
|
|
81
|
+
const m = line.match(/lavfi\.astats\.Overall\.RMS_level=(-?[\d.]+|-inf)/);
|
|
82
|
+
if (m) rmsDb.push(m[1] === "-inf" ? -90 : Math.max(-90, parseFloat(m[1])));
|
|
83
|
+
}
|
|
84
|
+
if (!rmsDb.length) {
|
|
85
|
+
console.error("[envelope] no RMS windows parsed");
|
|
86
|
+
process.exit(2);
|
|
87
|
+
}
|
|
88
|
+
const rms = rmsDb.map((db) => +Math.pow(10, db / 20).toFixed(5)); // linear 0..1
|
|
89
|
+
fs.writeFileSync(path.join(project, "envelope.json"), JSON.stringify({ hop: HOP, rms }));
|
|
90
|
+
const peakAt = rms.indexOf(Math.max(...rms)) * HOP;
|
|
91
|
+
console.log(
|
|
92
|
+
`[envelope] ${rms.length} windows @ ${HOP}s → envelope.json (loudest beat ~${peakAt.toFixed(2)}s)`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
main();
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* check-occlusion.cjs — pixel-perfect occlusion gate (Node port of check-occlusion-v2.py).
|
|
3
|
+
* Runs measure-layout.cjs (real Chromium DOM rects), reads the subject-matte alpha via sharp,
|
|
4
|
+
* computes per-word / per-cap occlusion. No Python.
|
|
5
|
+
* node check-occlusion.cjs <project-dir> [--strict] [--word-fail F] [--word-warn F] [--cap-fail F] [--remeasure]
|
|
6
|
+
*/
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const os = require("os");
|
|
10
|
+
const cp = require("child_process");
|
|
11
|
+
|
|
12
|
+
function hfResolve(pkg) {
|
|
13
|
+
const roots = [
|
|
14
|
+
process.env.HYPERFRAMES_ROOT,
|
|
15
|
+
path.resolve(__dirname, "..", "..", ".."),
|
|
16
|
+
path.join(os.homedir(), "Downloads", "hyperframes"),
|
|
17
|
+
].filter(Boolean);
|
|
18
|
+
for (const root of roots) {
|
|
19
|
+
const cands = [path.join(root, "node_modules", pkg)];
|
|
20
|
+
const bun = path.join(root, "node_modules", ".bun");
|
|
21
|
+
try {
|
|
22
|
+
if (fs.existsSync(bun))
|
|
23
|
+
for (const d of fs.readdirSync(bun))
|
|
24
|
+
if (d.startsWith(pkg + "@")) cands.push(path.join(bun, d, "node_modules", pkg));
|
|
25
|
+
} catch {}
|
|
26
|
+
for (const c of cands) {
|
|
27
|
+
try {
|
|
28
|
+
if (fs.existsSync(c)) return require(c);
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
console.error(`[v2] cannot find ${pkg} — set HYPERFRAMES_ROOT`);
|
|
33
|
+
process.exit(3);
|
|
34
|
+
}
|
|
35
|
+
const sharp = hfResolve("sharp");
|
|
36
|
+
|
|
37
|
+
function ensureLayoutMeasured(project, force) {
|
|
38
|
+
const lp = path.join(project, "_layout.json"),
|
|
39
|
+
idx = path.join(project, "index.html");
|
|
40
|
+
let stale = force || !fs.existsSync(lp);
|
|
41
|
+
if (!stale && fs.existsSync(idx) && fs.statSync(idx).mtimeMs > fs.statSync(lp).mtimeMs)
|
|
42
|
+
stale = true;
|
|
43
|
+
if (stale)
|
|
44
|
+
cp.execFileSync("node", [path.join(__dirname, "measure-layout.cjs"), project], {
|
|
45
|
+
stdio: "inherit",
|
|
46
|
+
});
|
|
47
|
+
return JSON.parse(fs.readFileSync(lp, "utf8"));
|
|
48
|
+
}
|
|
49
|
+
async function loadAlphaMask(png) {
|
|
50
|
+
if (!fs.existsSync(png)) return null;
|
|
51
|
+
const { data, info } = await sharp(png)
|
|
52
|
+
.ensureAlpha()
|
|
53
|
+
.extractChannel(3)
|
|
54
|
+
.raw()
|
|
55
|
+
.toBuffer({ resolveWithObject: true });
|
|
56
|
+
return { data, W: info.width, H: info.height };
|
|
57
|
+
}
|
|
58
|
+
function occlusionForRect(m, x, y, w, h) {
|
|
59
|
+
if (!m) return 0;
|
|
60
|
+
const x0 = Math.max(0, Math.round(x)),
|
|
61
|
+
y0 = Math.max(0, Math.round(y));
|
|
62
|
+
const x1 = Math.min(m.W, Math.round(x + w)),
|
|
63
|
+
y1 = Math.min(m.H, Math.round(y + h));
|
|
64
|
+
if (x1 <= x0 || y1 <= y0) return 0;
|
|
65
|
+
let cnt = 0,
|
|
66
|
+
tot = 0;
|
|
67
|
+
for (let yy = y0; yy < y1; yy++) {
|
|
68
|
+
const row = yy * m.W;
|
|
69
|
+
for (let xx = x0; xx < x1; xx++) {
|
|
70
|
+
tot++;
|
|
71
|
+
if (m.data[row + xx] > 128) cnt++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return tot ? cnt / tot : 0;
|
|
75
|
+
}
|
|
76
|
+
function argf(name, d) {
|
|
77
|
+
const i = process.argv.indexOf(name);
|
|
78
|
+
return i >= 0 ? parseFloat(process.argv[i + 1]) : d;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function main() {
|
|
82
|
+
const project = path.resolve(process.argv[2] || "");
|
|
83
|
+
if (!process.argv[2]) {
|
|
84
|
+
console.error("usage: check-occlusion.cjs <project-dir> [--strict]");
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
const strict = process.argv.includes("--strict");
|
|
88
|
+
const wordFail = argf("--word-fail", 0.65),
|
|
89
|
+
wordWarn = argf("--word-warn", 0.35),
|
|
90
|
+
capFail = argf("--cap-fail", 0.5);
|
|
91
|
+
const layout = ensureLayoutMeasured(project, process.argv.includes("--remeasure"));
|
|
92
|
+
const framesDir = path.join(project, "frames_fg");
|
|
93
|
+
if (!fs.existsSync(framesDir)) {
|
|
94
|
+
console.error(`[v2] missing ${framesDir}`);
|
|
95
|
+
process.exit(2);
|
|
96
|
+
}
|
|
97
|
+
const planPath = path.join(project, "plan.json");
|
|
98
|
+
const plan = fs.existsSync(planPath) ? JSON.parse(fs.readFileSync(planPath, "utf8")) : {};
|
|
99
|
+
const planLayer = plan.caption_layer || "bg";
|
|
100
|
+
// Hero groups (the ONE big promoted word) are SUPPOSED to sit ON the subject — for them
|
|
101
|
+
// occlusion is a TARGET (~30–55%), not "minimize". Collect their ids for the advisory below.
|
|
102
|
+
const heroIds = new Set();
|
|
103
|
+
const heroIn = {};
|
|
104
|
+
for (const g of plan.groups || [])
|
|
105
|
+
if (g && (g.hero === true || /^(hero|crown)$/i.test(g.plane || ""))) {
|
|
106
|
+
heroIds.add(g.id);
|
|
107
|
+
heroIn[g.id] = g.in;
|
|
108
|
+
}
|
|
109
|
+
if (plan.crown_group && plan.crown_group.id) {
|
|
110
|
+
heroIds.add(plan.crown_group.id);
|
|
111
|
+
heroIn[plan.crown_group.id] = plan.crown_group.in;
|
|
112
|
+
}
|
|
113
|
+
const M = 2; // frame-edge tolerance (px) — matches check-overflow.cjs
|
|
114
|
+
const frameW = layout.width,
|
|
115
|
+
frameH = layout.height;
|
|
116
|
+
|
|
117
|
+
const capStats = {};
|
|
118
|
+
for (const sample of layout.samples) {
|
|
119
|
+
const png = path.join(framesDir, `f_${String(sample.frame_idx).padStart(4, "0")}.png`);
|
|
120
|
+
const mask = await loadAlphaMask(png);
|
|
121
|
+
if (!mask) continue;
|
|
122
|
+
for (const cap of sample.caps) {
|
|
123
|
+
const entry = (capStats[cap.id] ||= { layer: cap.layer || planLayer, samples: [] });
|
|
124
|
+
const wordsData = [];
|
|
125
|
+
for (const w of cap.words || []) {
|
|
126
|
+
if ((w.opacity ?? 1) < 0.3) continue;
|
|
127
|
+
wordsData.push({ text: w.text, occlusion: occlusionForRect(mask, w.x, w.y, w.w, w.h) });
|
|
128
|
+
// Frame-edge overflow — clipped SETTLED text is always wrong; a hero's first
|
|
129
|
+
// 0.5s is its entrance TRANSIENT (slam over-scale, streak fly-in pass through
|
|
130
|
+
// off-frame states by design) — judge overflow on the hold, not mid-flight.
|
|
131
|
+
if (heroIds.has(cap.id) && heroIn[cap.id] != null && sample.t < heroIn[cap.id] + 0.5)
|
|
132
|
+
continue;
|
|
133
|
+
const off = {
|
|
134
|
+
left: Math.max(0, Math.round(-w.x - M)),
|
|
135
|
+
right: Math.max(0, Math.round(w.x + w.w - frameW - M)),
|
|
136
|
+
top: Math.max(0, Math.round(-w.y - M)),
|
|
137
|
+
bottom: Math.max(0, Math.round(w.y + w.h - frameH - M)),
|
|
138
|
+
};
|
|
139
|
+
const score = off.left + off.right + off.top + off.bottom;
|
|
140
|
+
if (score > 0 && (!entry.overflow || score > entry.overflow.score))
|
|
141
|
+
entry.overflow = { text: w.text, off, score, t: sample.t };
|
|
142
|
+
}
|
|
143
|
+
const capOccl = occlusionForRect(
|
|
144
|
+
mask,
|
|
145
|
+
cap.cap_bbox.x,
|
|
146
|
+
cap.cap_bbox.y,
|
|
147
|
+
cap.cap_bbox.w,
|
|
148
|
+
cap.cap_bbox.h,
|
|
149
|
+
);
|
|
150
|
+
entry.samples.push({
|
|
151
|
+
t: sample.t,
|
|
152
|
+
cap_occl: capOccl,
|
|
153
|
+
cap_bbox: cap.cap_bbox,
|
|
154
|
+
words: wordsData,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const failures = [];
|
|
160
|
+
console.log(
|
|
161
|
+
`[v2] ${path.basename(project)} word-fail≥${(wordFail * 100).toFixed(0)}% cap-fail≥${(capFail * 100).toFixed(0)}%`,
|
|
162
|
+
);
|
|
163
|
+
for (const [gid, entry] of Object.entries(capStats)) {
|
|
164
|
+
// Frame-edge overflow applies to every layer (fg too). The skill allows the
|
|
165
|
+
// climax a few-px graze on the first/last letter, so only a clear glyph clip
|
|
166
|
+
// (>8px past an edge) is a hard FAIL; a sub-glyph graze is a WARN.
|
|
167
|
+
if (entry.overflow) {
|
|
168
|
+
const o = entry.overflow;
|
|
169
|
+
const maxOff = Math.max(o.off.left, o.off.right, o.off.top, o.off.bottom);
|
|
170
|
+
const sides = Object.entries(o.off)
|
|
171
|
+
.filter(([, v]) => v > 0)
|
|
172
|
+
.map(([s, v]) => `${s} ${v}px`)
|
|
173
|
+
.join(", ");
|
|
174
|
+
const hard = maxOff >= 8;
|
|
175
|
+
console.log(
|
|
176
|
+
` ${gid} [overflow${hard ? "" : "-warn"}] "${o.text}" off-frame: ${sides} (@${o.t}s)` +
|
|
177
|
+
(hard ? " — cropped text is always wrong" : " (graze — within climax tolerance)"),
|
|
178
|
+
);
|
|
179
|
+
if (hard && !failures.includes(gid)) failures.push(gid);
|
|
180
|
+
}
|
|
181
|
+
if (entry.layer === "fg") {
|
|
182
|
+
console.log(` ${gid} fg (occlusion skipped — fg renders above matte)`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const capOccls = entry.samples.map((s) => s.cap_occl);
|
|
186
|
+
const avgCap = capOccls.length ? capOccls.reduce((a, b) => a + b, 0) / capOccls.length : 0;
|
|
187
|
+
const peakCap = capOccls.length ? Math.max(...capOccls) : 0;
|
|
188
|
+
const wordPeaks = {};
|
|
189
|
+
for (const s of entry.samples)
|
|
190
|
+
for (const wd of s.words)
|
|
191
|
+
wordPeaks[wd.text] = Math.max(wordPeaks[wd.text] || 0, wd.occlusion);
|
|
192
|
+
const oblit = Object.entries(wordPeaks).filter(([, p]) => p >= wordFail);
|
|
193
|
+
const warn = Object.entries(wordPeaks).filter(([, p]) => p >= wordWarn && p < wordFail);
|
|
194
|
+
let status = "OK";
|
|
195
|
+
// HERO caps WANT occlusion (~30–55% is the embed); the generic cap threshold would
|
|
196
|
+
// fail a working hero. Heroes fail only past the feasibility ceiling (68%).
|
|
197
|
+
const capLimit = heroIds.has(gid) ? Math.max(capFail, 0.68) : capFail;
|
|
198
|
+
if (oblit.length || peakCap >= capLimit) {
|
|
199
|
+
status = "FAIL";
|
|
200
|
+
failures.push(gid);
|
|
201
|
+
} else if (warn.length) status = "WARN";
|
|
202
|
+
let s = "";
|
|
203
|
+
if (oblit.length)
|
|
204
|
+
s =
|
|
205
|
+
oblit
|
|
206
|
+
.slice(0, 5)
|
|
207
|
+
.map(([t, p]) => `${t}(${(p * 100).toFixed(0)}%)`)
|
|
208
|
+
.join(" ") + (oblit.length > 5 ? ` …+${oblit.length - 5}` : "");
|
|
209
|
+
else if (warn.length)
|
|
210
|
+
s =
|
|
211
|
+
"[warn] " +
|
|
212
|
+
warn
|
|
213
|
+
.slice(0, 3)
|
|
214
|
+
.map(([t, p]) => `${t}(${(p * 100).toFixed(0)}%)`)
|
|
215
|
+
.join(" ");
|
|
216
|
+
console.log(
|
|
217
|
+
` ${gid} ${entry.layer} avg ${(avgCap * 100).toFixed(0)}% peak ${(peakCap * 100).toFixed(0)}% ${status} ${s}`,
|
|
218
|
+
);
|
|
219
|
+
// HERO target-occlusion advisory (not a failure): a hero should sit ON the subject
|
|
220
|
+
// (~30–55%). If it barely grazes, it reads as a small floating word, not an embed.
|
|
221
|
+
if (heroIds.has(gid) && peakCap < 0.15) {
|
|
222
|
+
// METRIC HONESTY: this advisory uses CAP-AREA occlusion, which saturates ~15%
|
|
223
|
+
// for a width-filled hero over a narrow subject (the 30–55% figure elsewhere is
|
|
224
|
+
// the safe-zones BAND metric — different denominator). If the hero already owns
|
|
225
|
+
// the width, "center it + make it BIG" is unactionable — stay quiet.
|
|
226
|
+
const widest = Math.max(...entry.samples.map((sm) => (sm.cap_bbox && sm.cap_bbox.w) || 0), 0);
|
|
227
|
+
if (widest >= frameW * 0.8) {
|
|
228
|
+
console.log(
|
|
229
|
+
` ${gid} [hero-ok] peak ${(peakCap * 100).toFixed(0)}% cap-area — width-saturated hero over a narrow subject; cap-area can't reach the band target (this is the geometry, not a layout fault).`,
|
|
230
|
+
);
|
|
231
|
+
} else {
|
|
232
|
+
console.log(
|
|
233
|
+
` ${gid} [hero-weak] peak ${(peakCap * 100).toFixed(0)}% — hero barely crosses the subject; it should sit ON the subject (~30–55% by the safe-zones BAND metric = the embed effect). Center it (safe-zones heroAnchor) + make it BIG; don't park it in a clean margin.`,
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (failures.length) {
|
|
239
|
+
const uniq = [...new Set(failures)];
|
|
240
|
+
console.error(`\n[v2] ${uniq.length} cap(s) FAIL: ${uniq.join(", ")}`);
|
|
241
|
+
console.error(
|
|
242
|
+
" → occlusion: set that cap's layer to fg, OR shrink/reposition; overflow: shrink/reposition (fg won't help)",
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
process.exit(strict && failures.length ? 2 : 0);
|
|
246
|
+
}
|
|
247
|
+
main().catch((e) => {
|
|
248
|
+
console.error("[v2]", e.message);
|
|
249
|
+
process.exit(1);
|
|
250
|
+
});
|