@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
package/dist/src/editor-chat.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { tool } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { lintCompositionHtml } from "./services/composition-lint.js";
|
|
1
4
|
export const EDITOR_CHAT_PROVIDER_PRIORITY = [
|
|
2
5
|
"openai",
|
|
3
6
|
"gemini",
|
|
@@ -64,7 +67,7 @@ export function buildTemplateEditorChatSystemPrompt(input) {
|
|
|
64
67
|
"If the user asks for each output to have its own chat thread, call frontend_action with action=create_thread for each tracer before or alongside the corresponding POST request.",
|
|
65
68
|
"If multiple tracers are available, mention which tracer you are using when it matters.",
|
|
66
69
|
"If the user asks to add, remove, switch tracers, or create a separate chat thread for a tracer, use the frontend_action tool so the page state updates directly.",
|
|
67
|
-
"If the user asks to add, remove, retime, reposition, resize, restyle, swap media, tag, note, group, ungroup, duplicate, or split layers on the composition timeline, call the editor_action tool. Supported action_type values are add_layer, remove_layer, set_layer_timing, set_layer_visual, set_layer_style, set_layer_media, set_layer_text, set_layer_identity, duplicate_layer, split_layer, group_layers, ungroup_layers, generate_layer, replace_composition_html, export_composition, and
|
|
70
|
+
"If the user asks to add, remove, retime, reposition, resize, restyle, swap media, tag, note, group, ungroup, duplicate, or split layers on the composition timeline, call the editor_action tool. Supported action_type values are add_layer, remove_layer, set_layer_timing, set_layer_visual, set_layer_style, set_layer_media, set_layer_text, set_layer_identity, duplicate_layer, split_layer, group_layers, ungroup_layers, generate_layer, replace_composition_html, export_composition, set_captions, and set_transitions.",
|
|
68
71
|
"If the user asks to export, render, publish, or produce the final MP4 for this composition (phrases like 'export it', 'render this', 'kick off the export', 'make the mp4'), call editor_action with action_type=export_composition and a brief explanation. This is the same action as the editor's Export button — it queues the composition on production AWS Lambda. Do NOT try to hit any /api/v1/compositions/:id/export route via http_request for this; use the editor_action tool. After calling export_composition, tell the user the export has started and that the finished MP4 URL will appear once the render succeeds; do not fabricate a URL or claim success until a later turn shows last_export_url populated in editor_context.",
|
|
69
72
|
"The editor_context block includes last_export_url, last_export_title, last_export_status, and last_export_render_id when a render has succeeded in this session. Treat last_export_url as the current 'finished Export MP4' for this composition. If the user asks to approve, package, share, or schedule the exported video without providing an explicit URL, use last_export_url as the primary MP4 media (kind=video, role=primary) for POST /api/v1/approved/posts. If last_export_url is null, tell the user to Export first (or offer to call editor_action with action_type=export_composition on their behalf) instead of guessing a URL.",
|
|
70
73
|
"Each layer in editor_context includes element_id (data-hf-id), optional slug (data-hf-slug), and optional note (data-hf-note). layer_key on any editor_action may be EITHER the element_id or the slug — prefer the slug when the user (or a viral DNA blurb) refers to a layer by its human name like 'the hero_image'. Use set_layer_identity to add/change a layer's slug or note. Slugs are the stable AI-friendly handle: when planning viral DNA notes, reference the element by its slug (e.g., 'raise the {{hero_image}} to full canvas at 4s') so future turns can resolve it deterministically.",
|
|
@@ -79,7 +82,7 @@ export function buildTemplateEditorChatSystemPrompt(input) {
|
|
|
79
82
|
"When placing generated character media on the timeline, prefer generate_layer (it applies the placement rules for you): to drop the character into a blank moment use intent='fill_gap' with start/duration on a timeline_gaps span; to swap them into an existing scene use intent='replace_layer' with replace_layer_key (its timing and full-canvas geometry are copied automatically). Always set aspect_ratio to the canvas (e.g. 9:16 for vertical) so the clip fills the frame. Only when you already have a finished media URL should you fall back to add_layer with explicit collision-free start/duration and full-canvas geometry (x=0, y=0, width=100, height=100) for a timeline-proxy/full-canvas replacement.",
|
|
80
83
|
"Use set_layer_visual for geometry (x, y, width, height in %, plus font_size and border_radius in px). Use set_layer_style for text/color styling (color, background, background_style plain|outline|highlight-solid|highlight-translucent, font_family, font_weight, italic, underline, text_align, border_radius, font_size). Use set_layer_media to swap src, volume, muted, playback_start, or object_fit on media layers. Use set_layer_timing for start, duration, track index, playback_start.",
|
|
81
84
|
"KEN BURNS / ANIMATE STILL IMAGES: every still-image layer supports a built-in Ken Burns effect — a slow pan or zoom that spans the clip's full duration in both the preview and the final render. Apply it with editor_action set_layer_media and the ken_burns field (presets: zoom-in, zoom-out, pan-left, pan-right, pan-up, pan-down, zoom-in-left, zoom-in-right; 'none' removes it), optionally ken_burns_intensity (0.04-0.5, default 0.18; ~0.1 subtle, ~0.3 dramatic). When the user says 'animate the images', 'make the photos move', 'ken burns', or similar, apply a preset to EVERY still-image layer in one pass (one set_layer_media call per layer), varying presets across adjacent clips — e.g. zoom-in, then pan-left, then zoom-out — so consecutive stills don't repeat the same motion. Zoom presets suit subjects centered in frame (products, faces); pan presets suit wide scenery or tall screenshots. You can also seed ken_burns directly on add_layer (kind=image) or generate_layer (media_type=image) so freshly placed stills arrive already animated. It only applies to image layers — never set it on video, text, or audio.",
|
|
82
|
-
"SCENE TRANSITIONS: every visual clip supports
|
|
85
|
+
"SCENE TRANSITIONS: every visual clip supports first-class transitions — an ENTRANCE at its start (transition: the clip animates IN over the previous clip on its track, which is automatically held on screen beneath it for the transition window) and an EXIT at its end (transition_out: the clip animates AWAY over its last transition_out_duration seconds), in both the preview and the final render. Entrance presets: crossfade, fade-black, fade-white, flash, smoke, blur, slide-left/right/up/down, whip-left/right, wipe-left/right/up/down, zoom-in, zoom-out, circle-open. Exit presets: fade, fade-black, fade-white, flash, smoke, blur, slide-left/right/up/down, wipe-left/right/up/down, zoom-in, zoom-out, circle-close. 'none' removes either. PREFER the bulk verb: when the user says 'add transitions', 'smooth out the cuts', 'crossfade between scenes', or similar, ONE editor_action action_type=set_transitions call does the whole timeline — transition = the junction preset applied at every cut (every scene clip except each track's first), optional transition_duration, optional transition_intro (first clip's entrance, e.g. fade-black to open from black), optional transition_outro (last clip's exit, e.g. fade-black to end on black) with transition_out_duration. For a SINGLE cut, set transition with set_layer_media ON THE INCOMING CLIP (the clip AFTER the cut, never the one before it); for a single clip's exit (before a gap, or a deliberate dip-to-black) set transition_out on the OUTGOING clip. Match the preset to the template's energy: crossfade/fade-black/fade-white/blur read calm and cinematic, smoke reads dreamy, slide/wipe read energetic (vary directions across cuts), whip/flash read fast-paced social, zoom/circle read punchy and meme-y; keep ONE family per video unless asked otherwise. You can also seed transition/transition_out directly on add_layer or generate_layer so a newly placed scene arrives with its motion. Transitions belong on video/image scene clips — never on audio; on text overlays prefer them only when the user asks. Timing is handled for you — never move clip starts or durations to 'make room' for a transition. Transitions also appear as clickable chips at every cut on the editor timeline, so tell users they can fine-tune from there too.",
|
|
83
86
|
"ANIMATED CAPTIONS (word-by-word, TikTok/CapCut style): the composition supports first-class animated captions — caption layers whose words animate one at a time in both the preview and the final render. Available preset looks (caption_style): spotlight (active word gets a rounded highlight pill on bold outlined text — the classic Hormozi/CapCut look), karaoke (words fill with a color as they are spoken and stay lit), word-pop (one word at a time, punchy scale-in), stack-up (words fade/rise in and accumulate), neon (active word pulses with a glow), bounce (active word bounces). When the user asks to 'add captions', 'add animated captions', 'add subtitles', or similar, pick the cue source by where the speech lives: (a) narration that needs TRANSCRIBING — a TTS voiceover layer, replaced audio, or when word-accurate karaoke timing matters — call the captions primitive: POST /api/v1/primitives/audio/captions with body { tracer, payload: { source_url: <the narration audio/video URL from editor_context>, style } }; the finished job's result carries captions (the cue array) and set_captions_action (fully-formed editor_action arguments) — apply them verbatim with editor_action action_type=set_captions. Real word timestamps need an OpenAI key (tried first; gemini/openrouter degrade to estimated word windows). (b) speech that is the SOURCE VIDEO's own audio on an already-decomposed fork — video_context already has the transcript's timestamped segments, so skip the job and call editor_action action_type=set_captions directly with captions=[{text, start, duration, words?}] cues derived from those segments — split segment text into pages of 3-5 words, keep each cue inside its segment's time window, and pass word timings when the transcript provides them (otherwise omit words and the editor estimates). Pick caption_style to match the template's voice (composition_context), or spotlight by default; override colors with caption_active_color / caption_highlight_color / color / background / background_style, and caption_uppercase for shouty formats. set_captions REPLACES all existing animated caption layers in one call — use it for 'restyle all the captions' too (same cues, new style) when cue text/timing is already in editor_context (each caption layer's text and caption_animation are listed there). For a single cue, set_layer_style with caption_* fields restyles just that layer, set_layer_text rewrites its words (timings re-estimate), and caption_animation='none' flattens it back to static text. Never hand-build word-by-word captions out of many add_layer text layers — always use set_captions. There is also a ONE-STEP server route, POST /api/v1/compositions/:forkId/captions { audio_url?|text?, style?, ... }, which transcribes the fork's own narration and writes the caption layers into the working composition server-side — use it ONLY for headless/automation flows, never while this editor session is open (the editor's next auto-save would overwrite the server-side change; in the editor always mutate through editor_action set_captions).",
|
|
84
87
|
"Use duplicate_layer to clone an existing layer; supply layer_key for the source, and optionally start/duration/track/label on the duplicate. Use split_layer with layer_key and split_time to cut at a moment in the timeline. Use group_layers with layer_keys (>=2) and optional group_label; ungroup_layers with layer_keys of any grouped members.",
|
|
85
88
|
"Prefer one editor_action call per mutation. For a multi-layer composition, sequence calls: generate or fetch each asset, then add or edit each layer with its own editor_action call. Chain edits by reusing the layer_key you assigned during add_layer.",
|
|
@@ -89,9 +92,12 @@ export function buildTemplateEditorChatSystemPrompt(input) {
|
|
|
89
92
|
"When you simply want to change a layer's media without moving it, prefer set_layer_media (kind must match: video↔video, image↔image, audio↔audio) — it keeps the same node, id, track, and geometry.",
|
|
90
93
|
"CONTEXT AVAILABLE FOR USE — this composition can expose TWO video sources plus a text/scene context: (1) the ORIGINAL video — the raw uploaded source, with any baked-in subtitles/captions; (2) the DECOMPOSED video — a processed, caption-free copy Vidfarm produces asynchronously (subtitles removed) that the composition timeline renders from; and (3) the decomposed video context (transcript + per-scene visual descriptions + viral DNA) available via the video_context tool. The original and the decomposed video are NOT the same URL, and you should not carry both URLs in default context. When the user asks to reuse, re-render, or feed the composition's video into a primitive route (image extract, ai video edit, media/dedupe, video trim, video probe, etc.), call GET /api/v1/compositions/:forkId/remove-video-captions FIRST to read { status, original_source_url, mirrored_url } and pick correctly — here original_source_url is the ORIGINAL video and mirrored_url is the DECOMPOSED video: prefer the DECOMPOSED video (mirrored_url) when status=\"done\" and the downstream call should be caption-free (thumbnails, style references, re-cut hooks); prefer the ORIGINAL video (original_source_url) when the user explicitly wants the raw upload (branded intros, provenance, when captions are the subject matter). If status is \"pending\" and the user is not blocked on subtitle removal, use the ORIGINAL video and mention that the decomposed (caption-free) video is still processing. If status is \"none\" or \"failed\", there is no decomposed video yet — use the ORIGINAL video only. Do not call POST /remove-video-captions-poll unless the user explicitly asks to advance the subtitle-removal job. To strip burned-in captions from any OTHER video URL (not this fork's decompose flow), use the POST /api/v1/primitives/videos/remove-captions primitive instead.",
|
|
91
94
|
"The OPTIONAL video_context tool returns this fork's decomposed video context: the source video's verbatim audio transcript (full text plus timestamped segments), a literal visual description of every scene, per-scene transcript excerpts, and viral DNA. Call it with the fork id from editor_context whenever the user asks what the source video says or shows, when writing/translating captions, hooks, or dubs that must match the spoken audio, or when you need scene-by-scene grounding before planning timeline edits. It is read-only and non-billing, so prefer it over guessing from frames or memory. If it returns status=\"none\", the fork was never smart-decomposed — offer to run POST /api/v1/compositions/:forkId/auto-decompose first. The same data is available via GET /api/v1/compositions/:forkId/video-context.json through http_request (useful for other forks).",
|
|
95
|
+
"KNOWLEDGE ON DEMAND (load_skill): deeper authoring knowledge ships as vidfarm skill packs you can read mid-conversation with the load_skill tool — the composition HTML contract (hyperframes-core), motion/animation craft and transition doctrine (hyperframes-animation), seek-safe keyframe patterns (hyperframes-keyframes), creative direction/palettes/typography (hyperframes-creative), caption identities (embedded-captions), media/audio resolution (vidfarm-media), and end-to-end workflow playbooks (product-launch-video, faceless-explainer, website-to-video, general-video, motion-graphics, slideshow, talking-head-recut). Call load_skill with the pack name to read its SKILL.md; it lists reference files you can then load by relative path (e.g. file='references/step-4-vo.md'). Use it when a request needs craft beyond the built-in preset vocabulary — designing a whole composition via replace_composition_html, picking motion or transition language for a style, or following a named workflow. Load only what the task needs, never bulk-load packs, and never paste large skill content back to the user.",
|
|
96
|
+
"replace_composition_html is validated before it reaches the editor: when the HTML violates the composition contract (missing data-composition-id, invalid clip timing, same-track overlaps, unknown preset names, media without src) the tool result comes back with rejected=true and lint_errors, and NOTHING is applied — fix the reported issues and call it again. lint_warnings are advisory and the action still applies (e.g. <script> tags survive local renders but are stripped on cloud/web saves — keep web-editor compositions declarative).",
|
|
92
97
|
"TEMPLATE FORMAT — MATCH IT WHEN WRITING TEXT: the COMPOSITION BRIEF (stable template context in the system prompt) carries composition_context — WHAT THIS TEMPLATE IS: its format/genre and narrative arc (trend_tagline, hook, retention, payoff, preserve, avoid). ALWAYS read it before writing or adjusting ANY captions, text layers, or on-screen copy, and make your copy fit the template's format and voice — do NOT default to generic product/app ad copy. The format dictates the caption style: a text-message / DM / iMessage conversation template's captions must read like short back-and-forth chat messages between people (in-character, conversational), a 'story time' / talking-head template reads like first-person spoken narration, a listicle reads like punchy numbered items, a fake-news / headline template reads like a news chyron, etc. `preserve` usually names format cues that must stay (e.g. the messaging-bubble layout); `avoid` names what to keep out. When the template's format is a conversation, skit, or roleplay, keep the captions in that voice and only weave the product in the way that format allows (subtly, in-dialogue) rather than replacing the messages with feature bullets. If the brief's composition_context is thin or you are unsure what the video actually shows, call video_context (scene visual descriptions + transcript) to ground the format BEFORE writing captions.",
|
|
93
|
-
"MY FILES: the user has a personal file library ('My Files') of uploaded assets — videos (mp4/mov/webm), images (png/jpg/jpeg/gif/webp/svg), audio (mp3/wav/m4a/aac), and documents (pdf/md/txt/csv) — organized into virtual folders. Use the browse_files tool to explore AND write it: call action=list (optionally with folder_path) to see what files and folders exist, action=read with a file_id (copied from a prior list) to fetch one file,
|
|
94
|
-
"SAVING CONTEXT TO MY FILES: browse_files action=write persists durable, reusable context the user (and future chats/agents) can read back. write
|
|
98
|
+
"MY FILES: the user has a personal file library ('My Files') of uploaded assets — videos (mp4/mov/webm), images (png/jpg/jpeg/gif/webp/svg), audio (mp3/wav/m4a/aac), and documents (pdf/md/txt/csv) — organized into virtual folders. Use the browse_files tool to explore AND write it: call action=list (optionally with folder_path) to see what files and folders exist, action=search with a plain-language query to find files by MEANING (keyword + vector match over every file's name, folder, and metadata notes — prefer it over paging list when the library is large or the user references an asset vaguely), action=read with a file_id (copied from a prior list/search) to fetch one file, action=write with file_name + content (or source_url) to SAVE a file, and action=annotate with file_id + notes to attach metadata notes to any existing file. When the user references their own footage, brand assets, logos, music, a brief, or a script ('use my product photo', 'the video I uploaded', 'my brand logo', 'the script in my files'), browse_files search or list first to find it rather than asking them to re-upload or paste a URL. For text files (md/txt/csv/srt/vtt/json), read returns the full text_content inline so you can read a brief or script directly. For images/video/audio/pdf, read returns only a durable view_url — use that URL as media: drop it into the timeline via editor_action add_layer/set_layer_media, or pass it into primitive routes (images/edit source_image_url, videos/generate input_references, videos/download). Never invent file ids or view URLs — always list or search to discover the real ones first.",
|
|
99
|
+
"SAVING CONTEXT TO MY FILES: browse_files action=write persists durable, reusable context the user (and future chats/agents) can read back. write saves text files (md/txt/csv/json/srt/vtt) via content, and IMPORTS media into the library via source_url (a durable URL from a finished primitive job or existing asset) — use source_url to persist a generated asset the user will want again (a character sprite card, a recurring background, a logo variant) instead of leaving it stranded in a job result. Use write to capture the Getting Started artifacts as Markdown: a product About.md (basic offer/product context) or a deeper Interview.md, plus awareness-levels.md, persuasive-angles.md, and ad-hooks.md distilled from the matching brainstorm outputs. When a brainstorm job returns strategy the user wants to keep, offer to save it (or save it) as the corresponding .md so it is not lost when the chat ends. Namescope every write under the right product/offer folder (see MY FILES IS MULTI-OFFER) — e.g. folder_path='acme-skincare', file_name='About.md'. Pass notes on write (or annotate afterwards) for any asset worth finding again: notes describe what the file is, who/what it depicts, and when to use it, and they are vector-embedded so action=search finds the file by meaning in future sessions. Before overwriting an existing file of the same name in the same folder, confirm with the user (writing the same name replaces it).",
|
|
100
|
+
"CHARACTER CONSISTENCY: when the user has a recurring character — a mascot, spokesperson, avatar, or product character that should look the same across videos — persist the character to My Files so every future generation can reference it, namescoped under the offer's folder (e.g. 'acme-skincare/characters/zara/'): (1) about_character.md — name, role, personality, physical description (face, build, wardrobe, colors), voice/tone, and do/don'ts, saved via write with content; (2) character_sprite_card.png — ONE reference-sheet image showing the character consistently (full body front/side/back plus a face close-up, neutral background). If the user has no sprite card, offer to generate one with POST /api/v1/primitives/images/generate (image gen is cheap; pass their best character photos as prompt_attachments if they exist, and ask the image for a 'character reference sheet / sprite card' layout), then save the finished job's URL into My Files via write with source_url + file_name='character_sprite_card.png'. Annotate BOTH files with notes naming the character so browse_files search finds them from any phrasing ('our mascot', 'the fox character'). From then on, character consistency = always pass the sprite card's view_url as the reference input on generation: prompt_attachments for images/generate and images/edit reference_attachments, input_references for videos/generate (or generate_layer's prompt_attachments/input_references), and pull wording from about_character.md into the prompt. Before generating ANY recurring character, search My Files for an existing sprite card first — never regenerate a character from memory when a reference exists.",
|
|
95
101
|
"GETTING STARTED / ONBOARDING: only run this flow when the user signals they don't know where to start (e.g. 'getting started', 'I don't know where to begin', 'help me set up') — if they already know what they want, just do that; never force onboarding. When they do want it, walk them through, saving each artifact to My Files (browse_files write, namescoped to their product/offer folder) as you go: (1) capture product/offer context — a quick About.md, or a fuller Interview.md if they want depth (use /brainstorm/coldstart to drive the interview questions); (2) figure out customer awareness level (Eugene Schwartz) — if unknown, note that ads for every level should be tested — via /brainstorm/awareness_stages, and save awareness-levels.md; (3) persuasive angles via /brainstorm/angles → persuasive-angles.md; (4) hooks via /brainstorm/hooks → ad-hooks.md; (5) ask whether they have brand assets (logos/mascots/themes — suggest a /brand-assets folder, e.g. /brand-assets/logo.png) or product demos / screen recordings (suggest a /product-demos folder), and browse_files list to see if they already uploaded any; (6) ask roughly what they want to spend per video and map it to the cost spectrum (see COST AWARENESS) so you know which approach to default to and whether AI video generation is on the table; (7) recommend templates that fit their offer by searching the catalog (GET /discover/feed?q=<offer>) and reading each result's promotions/keywords/summary, then offer to fork and modify the best fit to their offer. Users can skip straight to any step — e.g. 'just find me a good template for X' should jump to step 7 without the full interview.",
|
|
96
102
|
"COST AWARENESS: video cost spans a wide spectrum and the APPROACH sets the price — always default to the cheapest approach that meets the user's goal and make the tradeoff explicit. Bands: (a) FREE — reuse an already-decomposed template, swap captions/images/existing MP4s (from My Files, the user's computer, or a web search), and render on a local `vidfarm serve` box (in-process, no charge); (b) ~$0.001-$0.03 — same reuse but cloud render (~$0.01-$0.10); (c) ~$1 — AI-generate a few scenes for specificity; (d) $10+ — heavy AI generation (many/long AI clips, custom characters). Reusing existing footage or footage the user films is cheapest; AI-generating characters/scenes is most expensive. IMAGE generation is cheap — use it freely without asking. AI VIDEO generation is expensive — ASK the user's permission before generating video (/videos/generate or the generate_layer video path), and prefer reuse/local/image options unless they've okayed the spend or budget. Decompose (auto-decompose smart) is a one-time ~$0.10 per NEW source — prefer forking already-decomposed catalog templates to avoid it. Surface cost whenever the user asks about it, when a budget was set, or before kicking off an expensive video-gen job.",
|
|
97
103
|
"TEMPLATE / INSPIRATION DISCOVERY: when the user asks which templates, formats, or source videos suit a product or offer ('which templates are best to promote my weight loss app?', 'find me formats for a SaaS free trial', 'what should I use for my restaurant?'), search the catalog with http_request. Call GET /discover/feed?q=<their offer in their own words>&limit=20 to get ranked TEMPLATES, and GET /api/v1/videos?q=<offer>&limit=20 to get ranked source INSPIRATIONS. Each result carries decompose-derived metadata — `promotions` (the offer/product categories that format can sell), `keywords`, and a `summary`/`viralDna` blurb — so read those to judge fit, then recommend the best 3-6 with a one-line reason each (name the promotion or hook that matches their offer) and include their templateId/editor link. The q match is a coarse keyword prefilter, so also reason semantically over promotions/keywords/summary rather than trusting rank order blindly, and if a query returns nothing, retry with broader or synonym terms (e.g. 'fitness', 'transformation', 'before after' for a weight-loss app) before saying there are no matches. These are read-only, non-billing GETs — prefer them over guessing template ids from memory.",
|
|
@@ -450,4 +456,254 @@ export function compactEditorChatModelMessages(messages) {
|
|
|
450
456
|
...recentMessages
|
|
451
457
|
];
|
|
452
458
|
}
|
|
459
|
+
// ——— Skill packs the load_skill chat tool can fetch on demand. Served from
|
|
460
|
+
// GET /skill/:name (SKILL.md) and GET /skill-pack/:name/files/<path>
|
|
461
|
+
// (reference files), vendored under .agents/skills. Keep this list in sync
|
|
462
|
+
// with the packs actually vendored in the repo.
|
|
463
|
+
export const EDITOR_CHAT_SKILL_PACKS = [
|
|
464
|
+
{ name: "vidfarm-director", summary: "the full director playbook (REST + devcli flows)" },
|
|
465
|
+
{ name: "hyperframes", summary: "workflow router for the HyperFrames skill suite" },
|
|
466
|
+
{ name: "hyperframes-cli", summary: "HyperFrames CLI dev loop (init/lint/validate/inspect/snapshot/render)" },
|
|
467
|
+
{ name: "hyperframes-core", summary: "composition HTML contract: data-* timing attrs, tracks, clips, determinism rules" },
|
|
468
|
+
{ name: "hyperframes-animation", summary: "motion rules catalog, scene blueprints, transition doctrine, runtime adapters" },
|
|
469
|
+
{ name: "hyperframes-keyframes", summary: "seek-safe keyframe/CSS animation patterns" },
|
|
470
|
+
{ name: "hyperframes-creative", summary: "design specs, palettes, typography, house style, narration craft" },
|
|
471
|
+
{ name: "vidfarm-media", summary: "narration TTS/STT, BGM/SFX/media resolution through vidfarm primitives" },
|
|
472
|
+
{ name: "embedded-captions", summary: "caption identity catalog + subject-occlusion caption pipeline" },
|
|
473
|
+
{ name: "talking-head-recut", summary: "timed graphic overlay cards on existing footage" },
|
|
474
|
+
{ name: "product-launch-video", summary: "product/launch promo workflow (time-coded shot sequences)" },
|
|
475
|
+
{ name: "faceless-explainer", summary: "text-to-faceless-explainer workflow" },
|
|
476
|
+
{ name: "website-to-video", summary: "website capture to video workflow" },
|
|
477
|
+
{ name: "general-video", summary: "general multi-scene composition workflow" },
|
|
478
|
+
{ name: "motion-graphics", summary: "short motion-graphic workflow with category modules" },
|
|
479
|
+
{ name: "slideshow", summary: "interactive slideshow/deck composition contract" }
|
|
480
|
+
];
|
|
481
|
+
export const EDITOR_CHAT_SKILL_FILE_MAX_CHARS = 24_000;
|
|
482
|
+
// ——— Stream guardrails shared by the in-process chat (src/app.ts) and the
|
|
483
|
+
// deployed Lambda copy (infra/lambda/editor-chat.ts). One implementation so
|
|
484
|
+
// the two stream loops cannot drift.
|
|
485
|
+
export const EDITOR_CHAT_JOB_ID_PATTERN = /\bjob_[a-z0-9]+\b/gi;
|
|
486
|
+
const HTTP_TOOL_CLAIM_PATTERN = /\b(?:http_request|REST API call|API call|GET\s+https?:\/\/|POST\s+https?:\/\/|GET\s+\/api\/|POST\s+\/api\/)/i;
|
|
487
|
+
export function collectJobIdsFromUnknown(value, output = new Set()) {
|
|
488
|
+
if (typeof value === "string") {
|
|
489
|
+
for (const match of value.matchAll(EDITOR_CHAT_JOB_ID_PATTERN)) {
|
|
490
|
+
output.add(match[0]);
|
|
491
|
+
}
|
|
492
|
+
return output;
|
|
493
|
+
}
|
|
494
|
+
if (Array.isArray(value)) {
|
|
495
|
+
for (const entry of value) {
|
|
496
|
+
collectJobIdsFromUnknown(entry, output);
|
|
497
|
+
}
|
|
498
|
+
return output;
|
|
499
|
+
}
|
|
500
|
+
if (value && typeof value === "object") {
|
|
501
|
+
for (const entry of Object.values(value)) {
|
|
502
|
+
collectJobIdsFromUnknown(entry, output);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return output;
|
|
506
|
+
}
|
|
507
|
+
export function collectVerifiedHttpJobIds(toolResult) {
|
|
508
|
+
if (!toolResult || typeof toolResult !== "object") {
|
|
509
|
+
return new Set();
|
|
510
|
+
}
|
|
511
|
+
const record = toolResult;
|
|
512
|
+
return collectJobIdsFromUnknown(record.response?.body ?? record.result?.body);
|
|
513
|
+
}
|
|
514
|
+
export function readAsyncJobHandoff(output) {
|
|
515
|
+
if (!output || typeof output !== "object") {
|
|
516
|
+
return null;
|
|
517
|
+
}
|
|
518
|
+
const record = output;
|
|
519
|
+
const body = record.response?.body;
|
|
520
|
+
if (!body || typeof body !== "object") {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
const job = body;
|
|
524
|
+
if (typeof job.job_id !== "string" || typeof job.status !== "string") {
|
|
525
|
+
return null;
|
|
526
|
+
}
|
|
527
|
+
if (job.status === "succeeded" || job.status === "failed" || job.status === "cancelled") {
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
jobId: job.job_id,
|
|
532
|
+
tracer: typeof job.tracer === "string" ? job.tracer : null,
|
|
533
|
+
status: job.status,
|
|
534
|
+
isNewQueuedJob: record.request?.method === "POST" && record.response?.status === 202
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
export function buildAsyncJobHandoffText(input) {
|
|
538
|
+
// "Render …" wording is load-bearing: template-editor-chat.tsx emits the
|
|
539
|
+
// identical strings client-side and dedupes with a substring check, so any
|
|
540
|
+
// wording change here double-prints every queued-job handoff.
|
|
541
|
+
if (!input.isNewQueuedJob) {
|
|
542
|
+
return `Render \`${input.jobId}\` is ${input.status}.`;
|
|
543
|
+
}
|
|
544
|
+
return [
|
|
545
|
+
`Started render \`${input.jobId}\`${input.tracer ? ` with tracer \`${input.tracer}\`` : ""}.`,
|
|
546
|
+
"If it takes a while, ask for an update later and I can check it for you."
|
|
547
|
+
].join("\n\n");
|
|
548
|
+
}
|
|
549
|
+
export function buildEditorChatGuardrailNotice(input) {
|
|
550
|
+
const mentionedJobIds = collectJobIdsFromUnknown(input.assistantText);
|
|
551
|
+
const unverifiedJobIds = [...mentionedJobIds].filter((jobId) => !input.verifiedJobIds.has(jobId));
|
|
552
|
+
const notices = [];
|
|
553
|
+
if (input.redactedJobIds.size) {
|
|
554
|
+
notices.push("Guardrail: I withheld unverified job ID text because it did not come from a visible HTTP response card.");
|
|
555
|
+
}
|
|
556
|
+
else if (unverifiedJobIds.length) {
|
|
557
|
+
notices.push("Guardrail: I mentioned an unverified job ID. Ignore it unless it appears in a visible HTTP response card.");
|
|
558
|
+
}
|
|
559
|
+
if (!input.hasHttpRequestResult && HTTP_TOOL_CLAIM_PATTERN.test(input.assistantText)) {
|
|
560
|
+
notices.push("Guardrail: no `http_request` tool result was recorded for this response, so any claimed REST/API call should be treated as not executed.");
|
|
561
|
+
}
|
|
562
|
+
return notices.length ? `\n\n${notices.join("\n\n")}` : "";
|
|
563
|
+
}
|
|
564
|
+
export function redactUnverifiedJobIds(input) {
|
|
565
|
+
return input.text.replace(EDITOR_CHAT_JOB_ID_PATTERN, (jobId) => {
|
|
566
|
+
if (input.verifiedJobIds.has(jobId)) {
|
|
567
|
+
return jobId;
|
|
568
|
+
}
|
|
569
|
+
input.redactedJobIds.add(jobId);
|
|
570
|
+
return "[unverified job id]";
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
const SKILL_PACK_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
574
|
+
const SKILL_PACK_TEXT_FILE_RE = /\.(md|txt|json|ya?ml|mjs|cjs|js|html|css|srt|vtt|sh)$/i;
|
|
575
|
+
// Shared implementation behind the load_skill chat tool (registered in both
|
|
576
|
+
// src/app.ts and infra/lambda/editor-chat.ts). Fetches vendored skill-pack
|
|
577
|
+
// content from the vidfarm host's public /skill + /skill-pack routes.
|
|
578
|
+
export async function loadEditorChatSkillContent(input) {
|
|
579
|
+
const skill = input.skill.trim().toLowerCase().replace(/^\//, "");
|
|
580
|
+
if (!SKILL_PACK_NAME_RE.test(skill)) {
|
|
581
|
+
return { skill: input.skill, error: "Invalid skill pack name." };
|
|
582
|
+
}
|
|
583
|
+
const knownPack = EDITOR_CHAT_SKILL_PACKS.some((pack) => pack.name === skill);
|
|
584
|
+
const file = (input.file ?? "").trim().replace(/^\.?\//, "");
|
|
585
|
+
if (file && (file.includes("..") || !SKILL_PACK_TEXT_FILE_RE.test(file))) {
|
|
586
|
+
return { skill, file, error: "file must be a text file path inside the pack (no '..'; markdown/scripts/data files only)." };
|
|
587
|
+
}
|
|
588
|
+
const base = input.publicBaseUrl.replace(/\/$/, "");
|
|
589
|
+
const url = file
|
|
590
|
+
? `${base}/skill-pack/${encodeURIComponent(skill)}/files/${file.split("/").map(encodeURIComponent).join("/")}`
|
|
591
|
+
: `${base}/skill/${encodeURIComponent(skill)}`;
|
|
592
|
+
const timeoutController = new AbortController();
|
|
593
|
+
const timeoutId = setTimeout(() => {
|
|
594
|
+
timeoutController.abort(new Error("Skill fetch timed out after 30 seconds."));
|
|
595
|
+
}, 30_000);
|
|
596
|
+
try {
|
|
597
|
+
const signal = input.abortSignal
|
|
598
|
+
? AbortSignal.any([input.abortSignal, timeoutController.signal])
|
|
599
|
+
: timeoutController.signal;
|
|
600
|
+
const response = await fetch(url, { method: "GET", signal });
|
|
601
|
+
if (!response.ok) {
|
|
602
|
+
return {
|
|
603
|
+
explanation: input.explanation ?? null,
|
|
604
|
+
skill,
|
|
605
|
+
file: file || null,
|
|
606
|
+
status: response.status,
|
|
607
|
+
error: `Skill content unavailable (${response.status}).${knownPack ? "" : " Unknown pack — the tool description lists the available packs."}`
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
const raw = await response.text();
|
|
611
|
+
const truncated = raw.length > EDITOR_CHAT_SKILL_FILE_MAX_CHARS;
|
|
612
|
+
return {
|
|
613
|
+
explanation: input.explanation ?? null,
|
|
614
|
+
skill,
|
|
615
|
+
file: file || "SKILL.md",
|
|
616
|
+
truncated,
|
|
617
|
+
content: truncated
|
|
618
|
+
? `${raw.slice(0, EDITOR_CHAT_SKILL_FILE_MAX_CHARS)}\n\n[truncated — load a specific reference file for the rest]`
|
|
619
|
+
: raw
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
return {
|
|
624
|
+
explanation: input.explanation ?? null,
|
|
625
|
+
skill,
|
|
626
|
+
file: file || null,
|
|
627
|
+
error: error instanceof Error ? error.message : "Skill fetch failed."
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
finally {
|
|
631
|
+
clearTimeout(timeoutId);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
// ——— load_skill tool factory + replace_composition_html lint gate, shared by
|
|
635
|
+
// both chat copies (src/app.ts and infra/lambda/editor-chat.ts) so the tool
|
|
636
|
+
// description, schema, and gating semantics cannot drift between deployments.
|
|
637
|
+
export function createLoadSkillTool(input) {
|
|
638
|
+
return tool({
|
|
639
|
+
description: `OPTIONAL knowledge fetch: load a vidfarm skill pack document on demand instead of guessing at authoring craft. Available packs: ${EDITOR_CHAT_SKILL_PACKS.map((pack) => `${pack.name} — ${pack.summary}`).join("; ")}. Call with just skill=<name> to read the pack's SKILL.md (it lists the pack's reference files), then load a specific reference with file=<relative path> (e.g. 'references/step-4-vo.md', 'rules-index.md'). Text files only; long files are truncated. Read-only and non-billing. Load only what the current task needs.`,
|
|
640
|
+
inputSchema: z.object({
|
|
641
|
+
skill: z.string().min(1).describe("Skill pack name, e.g. 'hyperframes-animation'."),
|
|
642
|
+
file: z.string().optional().describe("Optional text file path inside the pack. Omit to fetch SKILL.md."),
|
|
643
|
+
explanation: z.string().optional().describe("Short reason for loading this knowledge.")
|
|
644
|
+
}),
|
|
645
|
+
execute: async ({ skill, file, explanation }) => loadEditorChatSkillContent({
|
|
646
|
+
skill,
|
|
647
|
+
file,
|
|
648
|
+
explanation,
|
|
649
|
+
publicBaseUrl: input.publicBaseUrl,
|
|
650
|
+
abortSignal: input.abortSignal
|
|
651
|
+
})
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
// Lint gate for editor_action's replace_composition_html escape hatch. Returns
|
|
655
|
+
// the tool result to send INSTEAD of the echoed args, or null to pass through.
|
|
656
|
+
// A rejected result omits action_type, so the browser's extractEditorAction
|
|
657
|
+
// never applies it — rejected payloads are inert by construction.
|
|
658
|
+
export function lintReplaceCompositionAction(args) {
|
|
659
|
+
if (args.action_type !== "replace_composition_html") {
|
|
660
|
+
return null;
|
|
661
|
+
}
|
|
662
|
+
const lint = lintCompositionHtml(typeof args.composition_html === "string" ? args.composition_html : "");
|
|
663
|
+
if (!lint.ok) {
|
|
664
|
+
return {
|
|
665
|
+
rejected: true,
|
|
666
|
+
reason: "composition_html failed validation and was NOT applied. Fix the lint_errors and call replace_composition_html again.",
|
|
667
|
+
lint_errors: lint.errors,
|
|
668
|
+
lint_warnings: lint.warnings,
|
|
669
|
+
explanation: args.explanation
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
if (lint.warnings.length) {
|
|
673
|
+
return { ...args, lint_warnings: lint.warnings };
|
|
674
|
+
}
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
// Streaming wrapper around redactUnverifiedJobIds: ai-sdk text deltas split at
|
|
678
|
+
// arbitrary byte boundaries, so a verified id like job_abc123 can arrive as
|
|
679
|
+
// "…job_ab" + "c123…" — redacting each chunk independently mangles the leading
|
|
680
|
+
// fragment. Hold back a trailing potential id fragment until the next delta
|
|
681
|
+
// (or flush) completes it.
|
|
682
|
+
export function createStreamingJobIdRedactor(input) {
|
|
683
|
+
let carry = "";
|
|
684
|
+
const TRAILING_FRAGMENT = /\bjob_[a-z0-9]*$/i;
|
|
685
|
+
const MAX_CARRY_CHARS = 64;
|
|
686
|
+
const redact = (text) => redactUnverifiedJobIds({
|
|
687
|
+
text,
|
|
688
|
+
verifiedJobIds: input.verifiedJobIds,
|
|
689
|
+
redactedJobIds: input.redactedJobIds
|
|
690
|
+
});
|
|
691
|
+
return {
|
|
692
|
+
push(text) {
|
|
693
|
+
let combined = carry + text;
|
|
694
|
+
carry = "";
|
|
695
|
+
const match = combined.match(TRAILING_FRAGMENT);
|
|
696
|
+
if (match && match[0].length <= MAX_CARRY_CHARS) {
|
|
697
|
+
carry = match[0];
|
|
698
|
+
combined = combined.slice(0, combined.length - carry.length);
|
|
699
|
+
}
|
|
700
|
+
return combined ? redact(combined) : "";
|
|
701
|
+
},
|
|
702
|
+
flush() {
|
|
703
|
+
const rest = carry;
|
|
704
|
+
carry = "";
|
|
705
|
+
return rest ? redact(rest) : "";
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
}
|
|
453
709
|
//# sourceMappingURL=editor-chat.js.map
|
|
@@ -2272,6 +2272,7 @@ export function TemplateEditorChat({ boot }) {
|
|
|
2272
2272
|
const [hasHydrated, setHasHydrated] = useState(false);
|
|
2273
2273
|
const [isDropTarget, setIsDropTarget] = useState(false);
|
|
2274
2274
|
const [isMobileChatOpen, setIsMobileChatOpen] = useState(false);
|
|
2275
|
+
const [isMobileChatExpanded, setIsMobileChatExpanded] = useState(false);
|
|
2275
2276
|
const [showHistoryPanel, setShowHistoryPanel] = useState(false);
|
|
2276
2277
|
const [showBranchesPanel, setShowBranchesPanel] = useState(false);
|
|
2277
2278
|
const [branches, setBranches] = useState(null);
|
|
@@ -4123,20 +4124,20 @@ export function TemplateEditorChat({ boot }) {
|
|
|
4123
4124
|
setLastError(null);
|
|
4124
4125
|
setOpenThreadMenu(null);
|
|
4125
4126
|
setShowHistoryPanel(false);
|
|
4126
|
-
if (isBrainstormSurface) {
|
|
4127
|
-
setIsMobileChatOpen(false);
|
|
4128
|
-
}
|
|
4129
4127
|
}, children: [_jsx("span", { className: "vf-editor-chat-thread-chip-title", children: thread.title }), thread.tracers.length ? (_jsxs("span", { className: "vf-editor-chat-thread-chip-tracers", children: [thread.tracers.slice(0, 2).join(", "), thread.tracers.length > 2 ? ` +${thread.tracers.length - 2}` : ""] })) : null] }), _jsx("div", { className: "vf-editor-chat-thread-menu-wrap", children: _jsx("button", { type: "button", className: "vf-editor-chat-thread-chip-menu", "aria-label": `Actions for ${thread.title}`, onClick: (event) => {
|
|
4130
4128
|
event.stopPropagation();
|
|
4131
4129
|
toggleThreadMenu(thread.id, event.currentTarget);
|
|
4132
4130
|
}, children: "..." }) })] }, thread.id))) : (_jsx("div", { className: "vf-editor-chat-thread-empty", children: "Start a chat to create your first conversation thread." })) }));
|
|
4133
|
-
return (_jsxs("div", { className: "vf-editor-chat-shell", "data-mobile-open": isMobileChatOpen ? "true" : "false", "data-
|
|
4131
|
+
return (_jsxs("div", { className: "vf-editor-chat-shell", "data-mobile-open": isMobileChatOpen ? "true" : "false", "data-mobile-expanded": isMobileChatExpanded ? "true" : "false", "data-layout": isBrainstormSurface ? "brainstorm" : "default", children: [_jsx("button", { type: "button", className: "vf-editor-chat-mobile-fab", "aria-label": "Open chat", "aria-expanded": isMobileChatOpen, onClick: () => {
|
|
4132
|
+
setIsMobileChatExpanded(false);
|
|
4133
|
+
setIsMobileChatOpen(true);
|
|
4134
|
+
}, children: _jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M20 11.5a7.5 7.5 0 0 1-9.8 7.1L4 20l1.5-5.3A7.5 7.5 0 1 1 20 11.5Z" }) }) }), lastError ? (_jsx("div", { className: "vf-editor-chat-error", role: "status", children: lastError })) : null, _jsxs("div", { className: `${isBrainstormSurface ? "vf-editor-chat-body vf-editor-chat-brainstorm-layout" : "vf-editor-chat-body"}${showPersistentSidebar ? " has-sidebar" : ""}`, "data-history-open": showHistoryPanel || showBranchesPanel ? "true" : "false", children: [showPersistentSidebar ? (_jsxs("aside", { className: "vf-editor-chat-history-pane", children: [_jsx("div", { className: "vf-editor-chat-history-header", children: _jsxs("div", { className: "vf-editor-chat-history-header-main", children: [_jsxs("a", { className: "vf-editor-chat-back-button", href: "/discover", "aria-label": "Back to Discover", children: [_jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.9", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "m12 4-6 6 6 6" }) }), "Discover"] }), _jsx("div", { className: "vf-editor-chat-history-kicker", children: "Chat history" })] }) }), _jsx("button", { type: "button", className: "vf-editor-chat-new-thread vf-editor-chat-new-thread-sidebar", onClick: createNewThreadFromClick, children: "New chat" }), threadListContent] })) : null, _jsxs("div", { className: "vf-editor-chat-thread", children: [_jsxs("div", { className: "vf-editor-chat-header", children: [_jsxs("div", { className: "vf-editor-chat-header-row", children: [_jsx("a", { className: "vf-editor-chat-back-button vf-editor-chat-back-button--header", href: "/discover", "aria-label": "Back to Discover", children: _jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.9", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "m12 4-6 6 6 6" }) }) }), _jsx("button", { type: "button", className: "vf-editor-chat-history-icon", "aria-label": showHistoryPanel ? "Back to chat" : "Open chat history", "aria-pressed": showHistoryPanel, onClick: () => {
|
|
4134
4135
|
setShowHistoryPanel((prev) => !prev);
|
|
4135
4136
|
setShowBranchesPanel(false);
|
|
4136
4137
|
}, children: showHistoryPanel ? (_jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.9", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "m12 4-6 6 6 6" }) })) : (_jsxs("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "10", cy: "10", r: "7.2" }), _jsx("path", { d: "M10 6v4l2.6 1.6" })] })) }), _jsx("button", { type: "button", className: "vf-editor-chat-history-icon vf-editor-chat-branches-icon", "aria-label": showBranchesPanel ? "Back to chat" : "Open template forks", "aria-pressed": showBranchesPanel, onClick: () => {
|
|
4137
4138
|
setShowBranchesPanel((prev) => !prev);
|
|
4138
4139
|
setShowHistoryPanel(false);
|
|
4139
|
-
}, children: showBranchesPanel ? (_jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.9", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "m12 4-6 6 6 6" }) })) : (_jsxs("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "5.5", cy: "4.5", r: "1.9" }), _jsx("circle", { cx: "5.5", cy: "15.5", r: "1.9" }), _jsx("circle", { cx: "14.5", cy: "8", r: "1.9" }), _jsx("path", { d: "M5.5 6.4v7.2" }), _jsx("path", { d: "M5.5 13.6c0-3.2 2.4-3.6 4.4-3.9 2-.3 4.6-.5 4.6-3.7" })] })) }), _jsxs("div", { className: "vf-editor-chat-header-titles", children: [_jsx("div", { className: "vf-editor-chat-header-title", children: "Vidfarm" }), _jsx("div", { className: "vf-editor-chat-header-subtitle", children: showHistoryPanel ? "Chat history" : showBranchesPanel ? "Template forks" : boot.template.templateTitle })] }), _jsx("button", { type: "button", className: "vf-editor-chat-new-thread", onClick: createNewThreadFromClick, children: "New chat" }), _jsx("button", { type: "button", className: "vf-editor-chat-minimize", "aria-label": "Minimize chat", onClick: () => setIsMobileChatOpen(false), children: "\u00D7" })] }), openThreadMenu && openThreadMenuThread ? createPortal(_jsxs("div", { className: "vf-editor-chat-thread-menu", role: "menu", style: {
|
|
4140
|
+
}, children: showBranchesPanel ? (_jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.9", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "m12 4-6 6 6 6" }) })) : (_jsxs("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "5.5", cy: "4.5", r: "1.9" }), _jsx("circle", { cx: "5.5", cy: "15.5", r: "1.9" }), _jsx("circle", { cx: "14.5", cy: "8", r: "1.9" }), _jsx("path", { d: "M5.5 6.4v7.2" }), _jsx("path", { d: "M5.5 13.6c0-3.2 2.4-3.6 4.4-3.9 2-.3 4.6-.5 4.6-3.7" })] })) }), _jsxs("div", { className: "vf-editor-chat-header-titles", children: [_jsx("div", { className: "vf-editor-chat-header-title", children: "Vidfarm" }), _jsx("div", { className: "vf-editor-chat-header-subtitle", children: showHistoryPanel ? "Chat history" : showBranchesPanel ? "Template forks" : boot.template.templateTitle })] }), _jsx("button", { type: "button", className: "vf-editor-chat-new-thread", onClick: createNewThreadFromClick, children: "New chat" }), _jsx("button", { type: "button", className: "vf-editor-chat-expand", "aria-label": isMobileChatExpanded ? "Shrink chat" : "Expand chat", "aria-pressed": isMobileChatExpanded, onClick: () => setIsMobileChatExpanded((prev) => !prev), children: isMobileChatExpanded ? (_jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", focusable: "false", children: [_jsx("path", { d: "M16.5 8.5h-5v-5" }), _jsx("path", { d: "M11.5 8.5 17 3" }), _jsx("path", { d: "M3.5 11.5h5v5" }), _jsx("path", { d: "M8.5 11.5 3 17" })] })) : (_jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", focusable: "false", children: [_jsx("path", { d: "M11.5 3.5h5v5" }), _jsx("path", { d: "M16.5 3.5 11 9" }), _jsx("path", { d: "M8.5 16.5h-5v-5" }), _jsx("path", { d: "M3.5 16.5 9 11" })] })) }), _jsx("button", { type: "button", className: "vf-editor-chat-minimize", "aria-label": "Minimize chat", onClick: () => setIsMobileChatOpen(false), children: "\u00D7" })] }), openThreadMenu && openThreadMenuThread ? createPortal(_jsxs("div", { className: "vf-editor-chat-thread-menu", role: "menu", style: {
|
|
4140
4141
|
top: openThreadMenu.top,
|
|
4141
4142
|
left: openThreadMenu.left
|
|
4142
4143
|
}, onClick: (event) => event.stopPropagation(), children: [_jsx("button", { type: "button", onClick: () => copyThreadId(openThreadMenuThread.id), children: "Copy Chat ID" }), _jsx("button", { type: "button", onClick: () => editThreadTracers(openThreadMenuThread.id), children: "Edit tracers" }), _jsx("button", { type: "button", onClick: () => removeThreadFromView(openThreadMenuThread.id), children: "Remove from view" }), _jsx("button", { type: "button", onClick: () => archiveThread(openThreadMenuThread.id), children: "Archive thread" }), _jsx("button", { type: "button", "data-danger": "true", onClick: () => deleteThread(openThreadMenuThread.id), children: "Delete" })] }), document.body) : null] }), _jsx("div", { className: "vf-editor-chat-viewport", ref: viewportRef, children: showHistoryPanel ? (_jsx("div", { className: "vf-editor-chat-history-panel", children: threadListContent })) : showBranchesPanel ? (_jsxs("div", { className: "vf-editor-chat-history-panel vf-editor-chat-branches-panel", children: [_jsxs("div", { className: "vf-editor-chat-branches-header", children: [_jsxs("div", { className: "vf-editor-chat-branches-header-main", children: [_jsx("div", { className: "vf-editor-chat-branches-kicker", children: "Forks" }), _jsxs("div", { className: "vf-editor-chat-branches-title", children: [branches?.length ?? 0, " fork", (branches?.length ?? 0) === 1 ? "" : "s", " of this template"] })] }), _jsx("button", { type: "button", className: "vf-editor-chat-branches-refresh", onClick: () => { void loadBranches({ force: true }); }, disabled: branchesLoading, "aria-label": "Refresh forks", children: branchesLoading ? "Loading…" : "Refresh" })] }), branchesError ? (_jsx("div", { className: "vf-editor-chat-thread-empty", role: "status", children: branchesError })) : branchesLoading && !branches ? (_jsx("div", { className: "vf-editor-chat-thread-empty", children: "Loading forks\u2026" })) : branches && branches.length ? (_jsx("div", { className: "vf-editor-chat-thread-list", children: branches.map((fork) => {
|
package/dist/src/homepage.js
CHANGED
|
@@ -956,54 +956,8 @@ export function renderHomepage(input) {
|
|
|
956
956
|
display: none !important;
|
|
957
957
|
}
|
|
958
958
|
|
|
959
|
-
/*
|
|
960
|
-
|
|
961
|
-
(closed by default, full-screen thread only while open). These
|
|
962
|
-
override the [data-layout="brainstorm"] rules in the shared shell
|
|
963
|
-
styles, which load before this block. */
|
|
964
|
-
.discover-frame .vf-editor-chat-shell[data-layout="brainstorm"] {
|
|
965
|
-
pointer-events: none;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
.discover-frame .vf-editor-chat-shell[data-layout="brainstorm"][data-mobile-open="true"] {
|
|
969
|
-
pointer-events: auto;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
.discover-frame .vf-editor-chat-shell[data-layout="brainstorm"] .vf-editor-chat-mobile-fab {
|
|
973
|
-
display: inline-flex;
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
.discover-frame .vf-editor-chat-shell[data-layout="brainstorm"][data-mobile-open="true"] .vf-editor-chat-mobile-fab {
|
|
977
|
-
opacity: 0;
|
|
978
|
-
transform: scale(0.86);
|
|
979
|
-
pointer-events: none;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
.discover-frame .vf-editor-chat-shell[data-layout="brainstorm"] .vf-editor-chat-thread {
|
|
983
|
-
position: fixed;
|
|
984
|
-
inset: 0;
|
|
985
|
-
z-index: 1;
|
|
986
|
-
display: none;
|
|
987
|
-
width: 100%;
|
|
988
|
-
height: 100svh;
|
|
989
|
-
border-radius: 0;
|
|
990
|
-
pointer-events: auto;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
.discover-frame .vf-editor-chat-shell[data-layout="brainstorm"][data-mobile-open="true"] .vf-editor-chat-thread {
|
|
994
|
-
display: grid;
|
|
995
|
-
grid-template-rows: auto minmax(0, 1fr) auto;
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
.discover-frame .vf-editor-chat-shell[data-layout="brainstorm"] .vf-editor-chat-minimize {
|
|
999
|
-
display: inline-flex;
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
/* Already on Discover — the /chat back-to-Discover header link would
|
|
1003
|
-
point at the current page. */
|
|
1004
|
-
.discover-frame .vf-editor-chat-shell[data-layout="brainstorm"] .vf-editor-chat-back-button--header {
|
|
1005
|
-
display: none;
|
|
1006
|
-
}
|
|
959
|
+
/* The shared shell styles now default brainstorm surfaces to the
|
|
960
|
+
FAB + popup dock, so Discover needs no chat overrides here. */
|
|
1007
961
|
|
|
1008
962
|
/* iOS zooms the page when focusing sub-16px inputs; modals must not
|
|
1009
963
|
trigger that. */
|