@koda-sl/baker-cli 0.39.29 → 0.66.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1754 -7
- package/canvas/avocado-tutorial.json +89 -0
- package/canvas/hello-world-composition/index.html +83 -0
- package/canvas/hello-world-composition/meta.json +41 -0
- package/canvas/hello-world-overlay.json +37 -0
- package/canvas/phone-scroll-composition/index.html +141 -0
- package/canvas/phone-scroll-composition/meta.json +39 -0
- package/canvas/tiktok-captions-composition/index.html +126 -0
- package/canvas/tiktok-captions-composition/meta.json +46 -0
- package/canvas/video-overlay-composition/index.html +239 -0
- package/canvas/video-overlay-composition/meta.json +29 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/ads/meta/creatives.js +1 -1
- package/dist/commands/canvas/catalog.d.ts +2 -0
- package/dist/commands/canvas/catalog.d.ts.map +1 -0
- package/dist/commands/canvas/catalog.js +13 -0
- package/dist/commands/canvas/catalog.js.map +1 -0
- package/dist/commands/canvas/index.d.ts +2 -0
- package/dist/commands/canvas/index.d.ts.map +1 -0
- package/dist/commands/canvas/index.js +32 -0
- package/dist/commands/canvas/index.js.map +1 -0
- package/dist/commands/canvas/inspect.d.ts +16 -0
- package/dist/commands/canvas/inspect.d.ts.map +1 -0
- package/dist/commands/canvas/inspect.js +115 -0
- package/dist/commands/canvas/inspect.js.map +1 -0
- package/dist/commands/canvas/run.d.ts +24 -0
- package/dist/commands/canvas/run.d.ts.map +1 -0
- package/dist/commands/canvas/run.js +56 -0
- package/dist/commands/canvas/run.js.map +1 -0
- package/dist/commands/canvas/scaffold-static-ad.d.ts +40 -0
- package/dist/commands/canvas/scaffold-static-ad.d.ts.map +1 -0
- package/dist/commands/canvas/scaffold-static-ad.js +265 -0
- package/dist/commands/canvas/scaffold-static-ad.js.map +1 -0
- package/dist/commands/canvas/scaffold-video.d.ts +44 -0
- package/dist/commands/canvas/scaffold-video.d.ts.map +1 -0
- package/dist/commands/canvas/scaffold-video.js +235 -0
- package/dist/commands/canvas/scaffold-video.js.map +1 -0
- package/dist/commands/canvas/validate.d.ts +8 -0
- package/dist/commands/canvas/validate.d.ts.map +1 -0
- package/dist/commands/canvas/validate.js +37 -0
- package/dist/commands/canvas/validate.js.map +1 -0
- package/dist/commands/images/find.d.ts +1 -1
- package/dist/commands/images/find.d.ts.map +1 -1
- package/dist/commands/images/find.js +12 -3
- package/dist/commands/images/find.js.map +1 -1
- package/dist/commands/images/google.d.ts +1 -1
- package/dist/commands/images/google.d.ts.map +1 -1
- package/dist/commands/images/google.js +12 -3
- package/dist/commands/images/google.js.map +1 -1
- package/dist/commands/images/stock.d.ts +1 -1
- package/dist/commands/images/stock.d.ts.map +1 -1
- package/dist/commands/images/stock.js +7 -3
- package/dist/commands/images/stock.js.map +1 -1
- package/dist/engine/client/backend-client.d.ts +50 -0
- package/dist/engine/client/backend-client.d.ts.map +1 -0
- package/dist/engine/client/backend-client.js +20 -0
- package/dist/engine/client/backend-client.js.map +1 -0
- package/dist/engine/client/env.d.ts +7 -0
- package/dist/engine/client/env.d.ts.map +1 -0
- package/dist/engine/client/env.js +18 -0
- package/dist/engine/client/env.js.map +1 -0
- package/dist/engine/client/http.d.ts +56 -0
- package/dist/engine/client/http.d.ts.map +1 -0
- package/dist/engine/client/http.js +168 -0
- package/dist/engine/client/http.js.map +1 -0
- package/dist/engine/engine/cache-key.d.ts +19 -0
- package/dist/engine/engine/cache-key.d.ts.map +1 -0
- package/dist/engine/engine/cache-key.js +33 -0
- package/dist/engine/engine/cache-key.js.map +1 -0
- package/dist/engine/engine/canonical.d.ts +14 -0
- package/dist/engine/engine/canonical.d.ts.map +1 -0
- package/dist/engine/engine/canonical.js +53 -0
- package/dist/engine/engine/canonical.js.map +1 -0
- package/dist/engine/engine/composition-hash.d.ts +14 -0
- package/dist/engine/engine/composition-hash.d.ts.map +1 -0
- package/dist/engine/engine/composition-hash.js +51 -0
- package/dist/engine/engine/composition-hash.js.map +1 -0
- package/dist/engine/engine/composition-meta.d.ts +77 -0
- package/dist/engine/engine/composition-meta.d.ts.map +1 -0
- package/dist/engine/engine/composition-meta.js +199 -0
- package/dist/engine/engine/composition-meta.js.map +1 -0
- package/dist/engine/engine/context.d.ts +16 -0
- package/dist/engine/engine/context.d.ts.map +1 -0
- package/dist/engine/engine/context.js +2 -0
- package/dist/engine/engine/context.js.map +1 -0
- package/dist/engine/engine/define.d.ts +69 -0
- package/dist/engine/engine/define.d.ts.map +1 -0
- package/dist/engine/engine/define.js +9 -0
- package/dist/engine/engine/define.js.map +1 -0
- package/dist/engine/engine/didyoumean.d.ts +2 -0
- package/dist/engine/engine/didyoumean.d.ts.map +1 -0
- package/dist/engine/engine/didyoumean.js +58 -0
- package/dist/engine/engine/didyoumean.js.map +1 -0
- package/dist/engine/engine/errors.d.ts +41 -0
- package/dist/engine/engine/errors.d.ts.map +1 -0
- package/dist/engine/engine/errors.js +45 -0
- package/dist/engine/engine/errors.js.map +1 -0
- package/dist/engine/engine/executor.d.ts +72 -0
- package/dist/engine/engine/executor.d.ts.map +1 -0
- package/dist/engine/engine/executor.js +445 -0
- package/dist/engine/engine/executor.js.map +1 -0
- package/dist/engine/engine/refs.d.ts +12 -0
- package/dist/engine/engine/refs.d.ts.map +1 -0
- package/dist/engine/engine/refs.js +48 -0
- package/dist/engine/engine/refs.js.map +1 -0
- package/dist/engine/engine/registry.d.ts +11 -0
- package/dist/engine/engine/registry.d.ts.map +1 -0
- package/dist/engine/engine/registry.js +26 -0
- package/dist/engine/engine/registry.js.map +1 -0
- package/dist/engine/engine/scheduler.d.ts +10 -0
- package/dist/engine/engine/scheduler.d.ts.map +1 -0
- package/dist/engine/engine/scheduler.js +89 -0
- package/dist/engine/engine/scheduler.js.map +1 -0
- package/dist/engine/engine/validator.d.ts +31 -0
- package/dist/engine/engine/validator.d.ts.map +1 -0
- package/dist/engine/engine/validator.js +501 -0
- package/dist/engine/engine/validator.js.map +1 -0
- package/dist/engine/index.d.ts +33 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +104 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/lib/ulid.d.ts +3 -0
- package/dist/engine/lib/ulid.d.ts.map +1 -0
- package/dist/engine/lib/ulid.js +36 -0
- package/dist/engine/lib/ulid.js.map +1 -0
- package/dist/engine/models/canvas-ad-params.test.d.ts +2 -0
- package/dist/engine/models/canvas-ad-params.test.d.ts.map +1 -0
- package/dist/engine/models/canvas-ad-params.test.js +60 -0
- package/dist/engine/models/canvas-ad-params.test.js.map +1 -0
- package/dist/engine/models/registry.d.ts +63 -0
- package/dist/engine/models/registry.d.ts.map +1 -0
- package/dist/engine/models/registry.js +432 -0
- package/dist/engine/models/registry.js.map +1 -0
- package/dist/engine/models/validateParams.d.ts +38 -0
- package/dist/engine/models/validateParams.d.ts.map +1 -0
- package/dist/engine/models/validateParams.js +166 -0
- package/dist/engine/models/validateParams.js.map +1 -0
- package/dist/engine/nodes/ingest.d.ts +113 -0
- package/dist/engine/nodes/ingest.d.ts.map +1 -0
- package/dist/engine/nodes/ingest.js +555 -0
- package/dist/engine/nodes/ingest.js.map +1 -0
- package/dist/engine/nodes/ingest.svg.test.d.ts +2 -0
- package/dist/engine/nodes/ingest.svg.test.d.ts.map +1 -0
- package/dist/engine/nodes/ingest.svg.test.js +30 -0
- package/dist/engine/nodes/ingest.svg.test.js.map +1 -0
- package/dist/engine/nodes/local/audioTimeline.d.ts +82 -0
- package/dist/engine/nodes/local/audioTimeline.d.ts.map +1 -0
- package/dist/engine/nodes/local/audioTimeline.js +97 -0
- package/dist/engine/nodes/local/audioTimeline.js.map +1 -0
- package/dist/engine/nodes/local/ffmpeg.d.ts +56 -0
- package/dist/engine/nodes/local/ffmpeg.d.ts.map +1 -0
- package/dist/engine/nodes/local/ffmpeg.js +50 -0
- package/dist/engine/nodes/local/ffmpeg.js.map +1 -0
- package/dist/engine/nodes/local/fontSpecimen.d.ts +50 -0
- package/dist/engine/nodes/local/fontSpecimen.d.ts.map +1 -0
- package/dist/engine/nodes/local/fontSpecimen.js +198 -0
- package/dist/engine/nodes/local/fontSpecimen.js.map +1 -0
- package/dist/engine/nodes/local/hyperframe-snapshot.d.ts +116 -0
- package/dist/engine/nodes/local/hyperframe-snapshot.d.ts.map +1 -0
- package/dist/engine/nodes/local/hyperframe-snapshot.js +230 -0
- package/dist/engine/nodes/local/hyperframe-snapshot.js.map +1 -0
- package/dist/engine/nodes/local/hyperframe.d.ts +123 -0
- package/dist/engine/nodes/local/hyperframe.d.ts.map +1 -0
- package/dist/engine/nodes/local/hyperframe.js +367 -0
- package/dist/engine/nodes/local/hyperframe.js.map +1 -0
- package/dist/engine/nodes/local/imagemagick.d.ts +56 -0
- package/dist/engine/nodes/local/imagemagick.d.ts.map +1 -0
- package/dist/engine/nodes/local/imagemagick.js +71 -0
- package/dist/engine/nodes/local/imagemagick.js.map +1 -0
- package/dist/engine/nodes/local/lib/assets.d.ts +20 -0
- package/dist/engine/nodes/local/lib/assets.d.ts.map +1 -0
- package/dist/engine/nodes/local/lib/assets.js +40 -0
- package/dist/engine/nodes/local/lib/assets.js.map +1 -0
- package/dist/engine/nodes/local/lib/cli-runner.d.ts +78 -0
- package/dist/engine/nodes/local/lib/cli-runner.d.ts.map +1 -0
- package/dist/engine/nodes/local/lib/cli-runner.js +254 -0
- package/dist/engine/nodes/local/lib/cli-runner.js.map +1 -0
- package/dist/engine/nodes/local/lib/ffmpeg.d.ts +23 -0
- package/dist/engine/nodes/local/lib/ffmpeg.d.ts.map +1 -0
- package/dist/engine/nodes/local/lib/ffmpeg.js +75 -0
- package/dist/engine/nodes/local/lib/ffmpeg.js.map +1 -0
- package/dist/engine/nodes/local/lib/hyperframe-errors.d.ts +2 -0
- package/dist/engine/nodes/local/lib/hyperframe-errors.d.ts.map +1 -0
- package/dist/engine/nodes/local/lib/hyperframe-errors.js +47 -0
- package/dist/engine/nodes/local/lib/hyperframe-errors.js.map +1 -0
- package/dist/engine/nodes/local/lib/templating.d.ts +22 -0
- package/dist/engine/nodes/local/lib/templating.d.ts.map +1 -0
- package/dist/engine/nodes/local/lib/templating.js +85 -0
- package/dist/engine/nodes/local/lib/templating.js.map +1 -0
- package/dist/engine/nodes/local/text.d.ts +6 -0
- package/dist/engine/nodes/local/text.d.ts.map +1 -0
- package/dist/engine/nodes/local/text.js +15 -0
- package/dist/engine/nodes/local/text.js.map +1 -0
- package/dist/engine/nodes/remote/delegate.d.ts +25 -0
- package/dist/engine/nodes/remote/delegate.d.ts.map +1 -0
- package/dist/engine/nodes/remote/delegate.js +160 -0
- package/dist/engine/nodes/remote/delegate.js.map +1 -0
- package/dist/engine/nodes/remote/dialogue.d.ts +34 -0
- package/dist/engine/nodes/remote/dialogue.d.ts.map +1 -0
- package/dist/engine/nodes/remote/dialogue.js +54 -0
- package/dist/engine/nodes/remote/dialogue.js.map +1 -0
- package/dist/engine/nodes/remote/image.d.ts +42 -0
- package/dist/engine/nodes/remote/image.d.ts.map +1 -0
- package/dist/engine/nodes/remote/image.js +43 -0
- package/dist/engine/nodes/remote/image.js.map +1 -0
- package/dist/engine/nodes/remote/imageAspectAdapt.d.ts +30 -0
- package/dist/engine/nodes/remote/imageAspectAdapt.d.ts.map +1 -0
- package/dist/engine/nodes/remote/imageAspectAdapt.js +42 -0
- package/dist/engine/nodes/remote/imageAspectAdapt.js.map +1 -0
- package/dist/engine/nodes/remote/imageBackgroundRemove.d.ts +39 -0
- package/dist/engine/nodes/remote/imageBackgroundRemove.d.ts.map +1 -0
- package/dist/engine/nodes/remote/imageBackgroundRemove.js +37 -0
- package/dist/engine/nodes/remote/imageBackgroundRemove.js.map +1 -0
- package/dist/engine/nodes/remote/imageDescribe.d.ts +29 -0
- package/dist/engine/nodes/remote/imageDescribe.d.ts.map +1 -0
- package/dist/engine/nodes/remote/imageDescribe.js +25 -0
- package/dist/engine/nodes/remote/imageDescribe.js.map +1 -0
- package/dist/engine/nodes/remote/imageReferenceSheet.d.ts +34 -0
- package/dist/engine/nodes/remote/imageReferenceSheet.d.ts.map +1 -0
- package/dist/engine/nodes/remote/imageReferenceSheet.js +38 -0
- package/dist/engine/nodes/remote/imageReferenceSheet.js.map +1 -0
- package/dist/engine/nodes/remote/imageSearch.d.ts +18 -0
- package/dist/engine/nodes/remote/imageSearch.d.ts.map +1 -0
- package/dist/engine/nodes/remote/imageSearch.js +22 -0
- package/dist/engine/nodes/remote/imageSearch.js.map +1 -0
- package/dist/engine/nodes/remote/imageSelect.d.ts +39 -0
- package/dist/engine/nodes/remote/imageSelect.d.ts.map +1 -0
- package/dist/engine/nodes/remote/imageSelect.js +45 -0
- package/dist/engine/nodes/remote/imageSelect.js.map +1 -0
- package/dist/engine/nodes/remote/music.d.ts +45 -0
- package/dist/engine/nodes/remote/music.d.ts.map +1 -0
- package/dist/engine/nodes/remote/music.js +73 -0
- package/dist/engine/nodes/remote/music.js.map +1 -0
- package/dist/engine/nodes/remote/soundEffect.d.ts +21 -0
- package/dist/engine/nodes/remote/soundEffect.d.ts.map +1 -0
- package/dist/engine/nodes/remote/soundEffect.js +41 -0
- package/dist/engine/nodes/remote/soundEffect.js.map +1 -0
- package/dist/engine/nodes/remote/textGenerate.d.ts +21 -0
- package/dist/engine/nodes/remote/textGenerate.d.ts.map +1 -0
- package/dist/engine/nodes/remote/textGenerate.js +27 -0
- package/dist/engine/nodes/remote/textGenerate.js.map +1 -0
- package/dist/engine/nodes/remote/tts.d.ts +45 -0
- package/dist/engine/nodes/remote/tts.d.ts.map +1 -0
- package/dist/engine/nodes/remote/tts.js +66 -0
- package/dist/engine/nodes/remote/tts.js.map +1 -0
- package/dist/engine/nodes/remote/video.d.ts +58 -0
- package/dist/engine/nodes/remote/video.d.ts.map +1 -0
- package/dist/engine/nodes/remote/video.js +44 -0
- package/dist/engine/nodes/remote/video.js.map +1 -0
- package/dist/engine/nodes/remote/videoBackgroundRemove.d.ts +30 -0
- package/dist/engine/nodes/remote/videoBackgroundRemove.d.ts.map +1 -0
- package/dist/engine/nodes/remote/videoBackgroundRemove.js +29 -0
- package/dist/engine/nodes/remote/videoBackgroundRemove.js.map +1 -0
- package/dist/engine/nodes/remote/videoDeconstruct.d.ts +61 -0
- package/dist/engine/nodes/remote/videoDeconstruct.d.ts.map +1 -0
- package/dist/engine/nodes/remote/videoDeconstruct.js +40 -0
- package/dist/engine/nodes/remote/videoDeconstruct.js.map +1 -0
- package/dist/engine/nodes/remote/videoLipsync.d.ts +37 -0
- package/dist/engine/nodes/remote/videoLipsync.d.ts.map +1 -0
- package/dist/engine/nodes/remote/videoLipsync.js +26 -0
- package/dist/engine/nodes/remote/videoLipsync.js.map +1 -0
- package/dist/engine/nodes/remote/videoTranscribe.d.ts +116 -0
- package/dist/engine/nodes/remote/videoTranscribe.d.ts.map +1 -0
- package/dist/engine/nodes/remote/videoTranscribe.js +123 -0
- package/dist/engine/nodes/remote/videoTranscribe.js.map +1 -0
- package/dist/engine/nodes/remote/voiceSelect.d.ts +28 -0
- package/dist/engine/nodes/remote/voiceSelect.d.ts.map +1 -0
- package/dist/engine/nodes/remote/voiceSelect.js +25 -0
- package/dist/engine/nodes/remote/voiceSelect.js.map +1 -0
- package/dist/engine/scaffold/staticAd.d.ts +44 -0
- package/dist/engine/scaffold/staticAd.d.ts.map +1 -0
- package/dist/engine/scaffold/staticAd.js +243 -0
- package/dist/engine/scaffold/staticAd.js.map +1 -0
- package/dist/engine/scaffold/video.d.ts +56 -0
- package/dist/engine/scaffold/video.d.ts.map +1 -0
- package/dist/engine/scaffold/video.js +709 -0
- package/dist/engine/scaffold/video.js.map +1 -0
- package/dist/engine/schema/canvas.d.ts +41 -0
- package/dist/engine/schema/canvas.d.ts.map +1 -0
- package/dist/engine/schema/canvas.js +67 -0
- package/dist/engine/schema/canvas.js.map +1 -0
- package/dist/engine/schema/catalog.d.ts +25 -0
- package/dist/engine/schema/catalog.d.ts.map +1 -0
- package/dist/engine/schema/catalog.js +48 -0
- package/dist/engine/schema/catalog.js.map +1 -0
- package/dist/engine/schema/primitives.d.ts +6 -0
- package/dist/engine/schema/primitives.d.ts.map +1 -0
- package/dist/engine/schema/primitives.js +4 -0
- package/dist/engine/schema/primitives.js.map +1 -0
- package/dist/engine/schema/prompts.d.ts +4 -0
- package/dist/engine/schema/prompts.d.ts.map +1 -0
- package/dist/engine/schema/prompts.js +23 -0
- package/dist/engine/schema/prompts.js.map +1 -0
- package/dist/engine/schema/refs.d.ts +113 -0
- package/dist/engine/schema/refs.d.ts.map +1 -0
- package/dist/engine/schema/refs.js +35 -0
- package/dist/engine/schema/refs.js.map +1 -0
- package/dist/engine/storage/asset-store.d.ts +48 -0
- package/dist/engine/storage/asset-store.d.ts.map +1 -0
- package/dist/engine/storage/asset-store.js +166 -0
- package/dist/engine/storage/asset-store.js.map +1 -0
- package/dist/engine/storage/cache-store.d.ts +21 -0
- package/dist/engine/storage/cache-store.d.ts.map +1 -0
- package/dist/engine/storage/cache-store.js +31 -0
- package/dist/engine/storage/cache-store.js.map +1 -0
- package/dist/engine/storage/output-writer.d.ts +18 -0
- package/dist/engine/storage/output-writer.d.ts.map +1 -0
- package/dist/engine/storage/output-writer.js +52 -0
- package/dist/engine/storage/output-writer.js.map +1 -0
- package/dist/engine/storage/sha256.d.ts +2 -0
- package/dist/engine/storage/sha256.d.ts.map +1 -0
- package/dist/engine/storage/sha256.js +7 -0
- package/dist/engine/storage/sha256.js.map +1 -0
- package/package.json +15 -3
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "baker-canvas/1",
|
|
3
|
+
"metadata": {
|
|
4
|
+
"name": "Avocado cutting tutorial with captions",
|
|
5
|
+
"description": "Generate a persona, first/last frames, video with Veo 3.1, transcribe, and burn TikTok-style captions."
|
|
6
|
+
},
|
|
7
|
+
"nodes": [
|
|
8
|
+
{
|
|
9
|
+
"id": "persona",
|
|
10
|
+
"type": "image_generate",
|
|
11
|
+
"params": {
|
|
12
|
+
"model": "google/gemini-3-pro-image-preview",
|
|
13
|
+
"prompt": "Portrait photo of a friendly young woman with natural makeup, wearing a casual white t-shirt, standing in a bright modern kitchen with white countertops and natural daylight from a large window. Warm smile, looking at camera, iPhone selfie style, 9:16 vertical framing.",
|
|
14
|
+
"aspect_ratio": "9:16",
|
|
15
|
+
"image_size": "1K"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "first_frame",
|
|
20
|
+
"type": "image_generate",
|
|
21
|
+
"inputs": {
|
|
22
|
+
"image": "$ref:persona.images#0"
|
|
23
|
+
},
|
|
24
|
+
"params": {
|
|
25
|
+
"model": "google/gemini-3-pro-image-preview",
|
|
26
|
+
"prompt": "Same woman from the reference image, now holding up a whole ripe avocado in her right hand, smiling at the camera in a bright modern kitchen. A wooden cutting board and chef knife are visible on the countertop. iPhone vertical selfie-style, natural daylight, 9:16.",
|
|
27
|
+
"aspect_ratio": "9:16",
|
|
28
|
+
"image_size": "1K"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "last_frame",
|
|
33
|
+
"type": "image_generate",
|
|
34
|
+
"inputs": {
|
|
35
|
+
"image": "$ref:persona.images#0"
|
|
36
|
+
},
|
|
37
|
+
"params": {
|
|
38
|
+
"model": "google/gemini-3-pro-image-preview",
|
|
39
|
+
"prompt": "Same woman from the reference image, proudly showing the camera two perfectly cut avocado halves on a wooden cutting board, the pit removed, bright modern kitchen, satisfied smile, iPhone vertical selfie-style, natural daylight, 9:16.",
|
|
40
|
+
"aspect_ratio": "9:16",
|
|
41
|
+
"image_size": "1K"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "video",
|
|
46
|
+
"type": "video_generate",
|
|
47
|
+
"inputs": {
|
|
48
|
+
"first_frame": "$ref:first_frame.images#0",
|
|
49
|
+
"last_frame": "$ref:last_frame.images#0"
|
|
50
|
+
},
|
|
51
|
+
"params": {
|
|
52
|
+
"model": "google/veo-3.1",
|
|
53
|
+
"prompt": "iPhone vertical selfie-style video of the woman cutting an avocado. She places the avocado on the wooden cutting board, slices it in half lengthwise with a chef knife, twists the halves apart revealing the pit, removes the pit, and scoops the flesh out with a spoon. She narrates casually: 'OK so first you want to cut it right down the middle, then twist it like this, pop the pit out, and just scoop!' Natural daylight, handheld iPhone movement, casual friendly vibe like an Instagram reel.",
|
|
54
|
+
"duration": 8,
|
|
55
|
+
"aspect_ratio": "9:16",
|
|
56
|
+
"resolution": "1080p",
|
|
57
|
+
"generate_audio": true,
|
|
58
|
+
"person_generation": "allow_all"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "transcribe",
|
|
63
|
+
"type": "video_transcribe",
|
|
64
|
+
"inputs": {
|
|
65
|
+
"video": "$ref:video.video"
|
|
66
|
+
},
|
|
67
|
+
"params": {}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "captioned",
|
|
71
|
+
"type": "hyperframe_render",
|
|
72
|
+
"inputs": {
|
|
73
|
+
"background": "$ref:video.video",
|
|
74
|
+
"transcript": "$ref:transcribe.transcript"
|
|
75
|
+
},
|
|
76
|
+
"params": {
|
|
77
|
+
"composition": "./packages/cli/canvas/tiktok-captions-composition",
|
|
78
|
+
"words_per_group": 3,
|
|
79
|
+
"font_size": 72,
|
|
80
|
+
"text_color": "#ffffff",
|
|
81
|
+
"highlight_color": "#FFD700"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"output": {
|
|
86
|
+
"node": "captioned",
|
|
87
|
+
"output": "video"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=1080, height=1920" />
|
|
6
|
+
<script src="./gsap.min.js"></script>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
html, body {
|
|
10
|
+
width: 1080px;
|
|
11
|
+
height: 1920px;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
background: #000;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.bg-image {
|
|
17
|
+
position: absolute;
|
|
18
|
+
inset: 0;
|
|
19
|
+
width: 100%;
|
|
20
|
+
height: 100%;
|
|
21
|
+
object-fit: cover;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.scrim {
|
|
25
|
+
position: absolute;
|
|
26
|
+
inset: 0;
|
|
27
|
+
background: rgba(0, 0, 0, {{scrim_opacity}});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.text-container {
|
|
31
|
+
position: absolute;
|
|
32
|
+
inset: 0;
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
padding: 80px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.text {
|
|
40
|
+
font-family: 'Arial Black', 'Impact', sans-serif;
|
|
41
|
+
font-size: {{font_size}}px;
|
|
42
|
+
font-weight: 900;
|
|
43
|
+
color: {{text_color}};
|
|
44
|
+
text-align: center;
|
|
45
|
+
text-wrap: balance;
|
|
46
|
+
line-height: 1.1;
|
|
47
|
+
text-transform: uppercase;
|
|
48
|
+
letter-spacing: 4px;
|
|
49
|
+
text-shadow:
|
|
50
|
+
3px 3px 0 rgba(0,0,0,0.8),
|
|
51
|
+
-1px -1px 0 rgba(0,0,0,0.8),
|
|
52
|
+
1px -1px 0 rgba(0,0,0,0.8),
|
|
53
|
+
-1px 1px 0 rgba(0,0,0,0.8),
|
|
54
|
+
0 4px 12px rgba(0,0,0,0.5);
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
57
|
+
</head>
|
|
58
|
+
<body>
|
|
59
|
+
<div
|
|
60
|
+
id="root"
|
|
61
|
+
data-composition-id="main"
|
|
62
|
+
data-start="0"
|
|
63
|
+
data-duration="{{duration}}"
|
|
64
|
+
data-width="1080"
|
|
65
|
+
data-height="1920"
|
|
66
|
+
>
|
|
67
|
+
<img class="bg-image" src="background.png" alt="" />
|
|
68
|
+
<div class="scrim"></div>
|
|
69
|
+
<div class="text-container">
|
|
70
|
+
<div class="text">{{text}}</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<script>
|
|
75
|
+
(() => {
|
|
76
|
+
var tl = gsap.timeline({ paused: true });
|
|
77
|
+
tl.to({}, { duration: 0.01 }, 0);
|
|
78
|
+
window.__timelines = window.__timelines || {};
|
|
79
|
+
window.__timelines.main = tl;
|
|
80
|
+
})();
|
|
81
|
+
</script>
|
|
82
|
+
</body>
|
|
83
|
+
</html>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "hello-world-overlay",
|
|
3
|
+
"title": "Bold text overlay on a background image",
|
|
4
|
+
"description": "Renders large centered text on top of a full-bleed background image with a dark scrim for legibility.",
|
|
5
|
+
"width": 1080,
|
|
6
|
+
"height": 1920,
|
|
7
|
+
"fps": 30,
|
|
8
|
+
"default_duration": 1,
|
|
9
|
+
"inputs": {
|
|
10
|
+
"background": {
|
|
11
|
+
"kind": "image",
|
|
12
|
+
"required": true,
|
|
13
|
+
"staged_as": "background.png",
|
|
14
|
+
"description": "Full-bleed background image."
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"params": {
|
|
18
|
+
"text": {
|
|
19
|
+
"kind": "string",
|
|
20
|
+
"required": true,
|
|
21
|
+
"description": "The text to render on top of the image."
|
|
22
|
+
},
|
|
23
|
+
"font_size": {
|
|
24
|
+
"kind": "integer",
|
|
25
|
+
"min": 24,
|
|
26
|
+
"max": 300,
|
|
27
|
+
"default": 128
|
|
28
|
+
},
|
|
29
|
+
"text_color": {
|
|
30
|
+
"kind": "color",
|
|
31
|
+
"default": "#ffffff"
|
|
32
|
+
},
|
|
33
|
+
"scrim_opacity": {
|
|
34
|
+
"kind": "number",
|
|
35
|
+
"min": 0,
|
|
36
|
+
"max": 1,
|
|
37
|
+
"default": 0.3,
|
|
38
|
+
"description": "Dark overlay opacity behind the text for legibility."
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "baker-canvas/1",
|
|
3
|
+
"metadata": {
|
|
4
|
+
"name": "Hello World overlay",
|
|
5
|
+
"description": "Generate an image of a person, then render HELLO WORLD!! on top via a custom HTML composition."
|
|
6
|
+
},
|
|
7
|
+
"nodes": [
|
|
8
|
+
{
|
|
9
|
+
"id": "person_image",
|
|
10
|
+
"type": "image_generate",
|
|
11
|
+
"params": {
|
|
12
|
+
"model": "google/gemini-3.5-flash",
|
|
13
|
+
"prompt": "Portrait photo of a friendly person smiling, standing outdoors in a city park with soft golden-hour sunlight, 9:16 framing, natural colors.",
|
|
14
|
+
"aspect_ratio": "9:16",
|
|
15
|
+
"image_size": "1K"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "overlay",
|
|
20
|
+
"type": "hyperframe_snapshot",
|
|
21
|
+
"inputs": {
|
|
22
|
+
"background": "$ref:person_image.images#0"
|
|
23
|
+
},
|
|
24
|
+
"params": {
|
|
25
|
+
"composition": "./packages/cli/canvas/hello-world-composition",
|
|
26
|
+
"text": "HELLO WORLD!!",
|
|
27
|
+
"font_size": 128,
|
|
28
|
+
"text_color": "#ffffff",
|
|
29
|
+
"scrim_opacity": 0.3
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"output": {
|
|
34
|
+
"node": "overlay",
|
|
35
|
+
"output": "image"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=720, height=1280" />
|
|
6
|
+
<script src="./gsap.min.js"></script>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
html, body {
|
|
10
|
+
width: 720px;
|
|
11
|
+
height: 1280px;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
background: {{background_color}};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.viewport {
|
|
17
|
+
position: absolute;
|
|
18
|
+
inset: 0;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.screenshot {
|
|
23
|
+
position: absolute;
|
|
24
|
+
top: 0;
|
|
25
|
+
left: 50%;
|
|
26
|
+
transform: translate(-50%, 0);
|
|
27
|
+
width: 720px;
|
|
28
|
+
height: auto;
|
|
29
|
+
display: block;
|
|
30
|
+
will-change: transform;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.tap {
|
|
34
|
+
position: absolute;
|
|
35
|
+
width: 80px;
|
|
36
|
+
height: 80px;
|
|
37
|
+
margin-left: -40px;
|
|
38
|
+
margin-top: -40px;
|
|
39
|
+
border: 4px solid {{tap_color}};
|
|
40
|
+
border-radius: 50%;
|
|
41
|
+
opacity: 0;
|
|
42
|
+
pointer-events: none;
|
|
43
|
+
box-shadow: 0 0 12px rgba(0, 0, 0, 0.35);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.tap.long-press {
|
|
47
|
+
border-width: 6px;
|
|
48
|
+
}
|
|
49
|
+
</style>
|
|
50
|
+
</head>
|
|
51
|
+
<body>
|
|
52
|
+
<div
|
|
53
|
+
id="root"
|
|
54
|
+
data-composition-id="main"
|
|
55
|
+
data-start="0"
|
|
56
|
+
data-duration="{{duration}}"
|
|
57
|
+
data-width="720"
|
|
58
|
+
data-height="1280"
|
|
59
|
+
>
|
|
60
|
+
<div class="viewport">
|
|
61
|
+
<img id="screenshot" class="screenshot" src="screenshot.png" alt="" />
|
|
62
|
+
</div>
|
|
63
|
+
<div id="taps"></div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<script>
|
|
67
|
+
(() => {
|
|
68
|
+
const TIMELINE = {{timeline}};
|
|
69
|
+
const TAPS = {{taps}};
|
|
70
|
+
const DURATION = parseFloat('{{duration}}');
|
|
71
|
+
|
|
72
|
+
const screenshot = document.getElementById('screenshot');
|
|
73
|
+
const tapsContainer = document.getElementById('taps');
|
|
74
|
+
|
|
75
|
+
// Build the GSAP timeline. Each keyframe describes a destination y at
|
|
76
|
+
// a specific time t, with an ease covering the segment from the
|
|
77
|
+
// previous keyframe to this one. The first keyframe acts as the
|
|
78
|
+
// starting position (instant set).
|
|
79
|
+
const tl = gsap.timeline({ paused: true });
|
|
80
|
+
|
|
81
|
+
if (!Array.isArray(TIMELINE) || TIMELINE.length === 0) {
|
|
82
|
+
// No timeline: leave the image at y=0 for the full duration.
|
|
83
|
+
gsap.set(screenshot, { y: 0 });
|
|
84
|
+
} else {
|
|
85
|
+
const sorted = [...TIMELINE].sort((a, b) => (a.at || 0) - (b.at || 0));
|
|
86
|
+
const first = sorted[0];
|
|
87
|
+
gsap.set(screenshot, { y: -(first.y || 0) });
|
|
88
|
+
|
|
89
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
90
|
+
const prev = sorted[i - 1];
|
|
91
|
+
const cur = sorted[i];
|
|
92
|
+
const segmentDuration = Math.max(0, (cur.at || 0) - (prev.at || 0));
|
|
93
|
+
const ease = typeof cur.ease === 'string' && cur.ease.length > 0 ? cur.ease : 'none';
|
|
94
|
+
tl.to(
|
|
95
|
+
screenshot,
|
|
96
|
+
{
|
|
97
|
+
y: -(cur.y || 0),
|
|
98
|
+
duration: segmentDuration,
|
|
99
|
+
ease,
|
|
100
|
+
},
|
|
101
|
+
prev.at || 0,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Render tap overlays. Each tap is a 0.5s ripple: fade in, scale up,
|
|
107
|
+
// fade out. Position is x/y on the viewport (percent strings or
|
|
108
|
+
// explicit px values).
|
|
109
|
+
if (Array.isArray(TAPS)) {
|
|
110
|
+
TAPS.forEach((tap, idx) => {
|
|
111
|
+
if (typeof tap !== 'object' || tap === null) return;
|
|
112
|
+
const el = document.createElement('div');
|
|
113
|
+
el.className = 'tap' + (tap.kind === 'long-press' ? ' long-press' : '');
|
|
114
|
+
el.id = 'tap_' + idx;
|
|
115
|
+
el.style.left = String(tap.x ?? '50%');
|
|
116
|
+
el.style.top = String(tap.y ?? '50%');
|
|
117
|
+
tapsContainer.appendChild(el);
|
|
118
|
+
|
|
119
|
+
const at = Number(tap.at ?? 0);
|
|
120
|
+
const ringDuration = tap.kind === 'long-press' ? 0.9 : 0.5;
|
|
121
|
+
tl.fromTo(
|
|
122
|
+
el,
|
|
123
|
+
{ opacity: 0.9, scale: 0.4 },
|
|
124
|
+
{ opacity: 0, scale: 1.6, duration: ringDuration, ease: 'power2.out' },
|
|
125
|
+
at,
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Anchor the timeline to the full requested duration so trailing
|
|
131
|
+
// pauses (after the last keyframe) render correctly.
|
|
132
|
+
if (DURATION > 0) {
|
|
133
|
+
tl.to({}, { duration: 0.01 }, Math.max(0, DURATION - 0.01));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
window.__timelines = window.__timelines || {};
|
|
137
|
+
window.__timelines.main = tl;
|
|
138
|
+
})();
|
|
139
|
+
</script>
|
|
140
|
+
</body>
|
|
141
|
+
</html>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "phone-scroll",
|
|
3
|
+
"title": "Non-linear app scroll for green-screen compositing",
|
|
4
|
+
"description": "Renders a tall app screenshot inside a phone-aspect viewport and animates its vertical scroll along a keyframed timeline (with eased pauses, direction changes, and optional tap-pulse overlays). Output is intended to feed into ffmpeg chromakey_overlay as the `app` input.",
|
|
5
|
+
"width": 720,
|
|
6
|
+
"height": 1280,
|
|
7
|
+
"fps": 30,
|
|
8
|
+
"default_duration": 8,
|
|
9
|
+
"inputs": {
|
|
10
|
+
"image": {
|
|
11
|
+
"kind": "image",
|
|
12
|
+
"required": true,
|
|
13
|
+
"staged_as": "screenshot.png",
|
|
14
|
+
"description": "Tall app screenshot to scroll through. Should be at least as wide as the viewport (720px); excess width is cropped centred."
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"params": {
|
|
18
|
+
"timeline": {
|
|
19
|
+
"kind": "json",
|
|
20
|
+
"required": true,
|
|
21
|
+
"description": "Array of keyframes: [{at: seconds, y: pixels, ease?: gsap-ease-name, label?: string}]. y is the translateY (negative scrolls up through long content). Direction changes are just keyframes going the other way. For a constant pan, pass two keyframes with ease:'none'."
|
|
22
|
+
},
|
|
23
|
+
"taps": {
|
|
24
|
+
"kind": "json",
|
|
25
|
+
"default": [],
|
|
26
|
+
"description": "Optional array of tap-pulse overlays: [{at: seconds, x: 'NN%'|'NNpx', y: 'NN%'|'NNpx', kind?: 'tap'|'long-press'}]. Renders a 0.5s ripple at the position."
|
|
27
|
+
},
|
|
28
|
+
"background_color": {
|
|
29
|
+
"kind": "color",
|
|
30
|
+
"default": "#000000",
|
|
31
|
+
"description": "Fill color around the scrolled image (visible if the image is shorter than the viewport)."
|
|
32
|
+
},
|
|
33
|
+
"tap_color": {
|
|
34
|
+
"kind": "color",
|
|
35
|
+
"default": "#ffffff",
|
|
36
|
+
"description": "Stroke color for tap-pulse overlays."
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=1080, height=1920" />
|
|
6
|
+
<script src="./gsap.min.js"></script>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
html, body {
|
|
10
|
+
width: 1080px;
|
|
11
|
+
height: 1920px;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
background: #000;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
video#bg {
|
|
17
|
+
position: absolute;
|
|
18
|
+
inset: 0;
|
|
19
|
+
width: 100%;
|
|
20
|
+
height: 100%;
|
|
21
|
+
object-fit: cover;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.caption-container {
|
|
25
|
+
position: absolute;
|
|
26
|
+
bottom: 320px;
|
|
27
|
+
left: 0;
|
|
28
|
+
right: 0;
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
padding: 0 60px;
|
|
33
|
+
pointer-events: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.caption-group {
|
|
37
|
+
position: absolute;
|
|
38
|
+
font-family: 'Arial Black', 'Helvetica Neue', sans-serif;
|
|
39
|
+
font-size: {{font_size}}px;
|
|
40
|
+
font-weight: 900;
|
|
41
|
+
color: {{text_color}};
|
|
42
|
+
text-align: center;
|
|
43
|
+
text-transform: uppercase;
|
|
44
|
+
line-height: 1.2;
|
|
45
|
+
text-shadow:
|
|
46
|
+
2px 2px 0 rgba(0,0,0,0.9),
|
|
47
|
+
-2px -2px 0 rgba(0,0,0,0.9),
|
|
48
|
+
2px -2px 0 rgba(0,0,0,0.9),
|
|
49
|
+
-2px 2px 0 rgba(0,0,0,0.9),
|
|
50
|
+
0 4px 8px rgba(0,0,0,0.6);
|
|
51
|
+
visibility: hidden;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.caption-group .active-word {
|
|
55
|
+
color: {{highlight_color}};
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
58
|
+
</head>
|
|
59
|
+
<body>
|
|
60
|
+
<div
|
|
61
|
+
id="root"
|
|
62
|
+
data-composition-id="main"
|
|
63
|
+
data-start="0"
|
|
64
|
+
data-duration="{{duration}}"
|
|
65
|
+
data-width="1080"
|
|
66
|
+
data-height="1920"
|
|
67
|
+
>
|
|
68
|
+
<video id="bg" src="background.mp4" muted></video>
|
|
69
|
+
<div class="caption-container" id="captions"></div>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<script>
|
|
73
|
+
(async () => {
|
|
74
|
+
const WORDS_PER_GROUP = {{words_per_group}};
|
|
75
|
+
const resp = await fetch('./transcript.json');
|
|
76
|
+
const transcript = await resp.json();
|
|
77
|
+
const container = document.getElementById('captions');
|
|
78
|
+
const tl = gsap.timeline({ paused: true });
|
|
79
|
+
|
|
80
|
+
const groups = [];
|
|
81
|
+
for (let i = 0; i < transcript.length; i += WORDS_PER_GROUP) {
|
|
82
|
+
groups.push(transcript.slice(i, i + WORDS_PER_GROUP));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
groups.forEach((group, gi) => {
|
|
86
|
+
const el = document.createElement('div');
|
|
87
|
+
el.className = 'caption-group';
|
|
88
|
+
el.id = 'cg_' + gi;
|
|
89
|
+
|
|
90
|
+
group.forEach((word, wi) => {
|
|
91
|
+
const span = document.createElement('span');
|
|
92
|
+
span.id = 'w_' + gi + '_' + wi;
|
|
93
|
+
span.textContent = word.text + ' ';
|
|
94
|
+
el.appendChild(span);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
container.appendChild(el);
|
|
98
|
+
|
|
99
|
+
const groupStart = group[0].start;
|
|
100
|
+
const groupEnd = group[group.length - 1].end;
|
|
101
|
+
|
|
102
|
+
gsap.set(el, { visibility: 'hidden' });
|
|
103
|
+
tl.set(el, { visibility: 'visible' }, groupStart);
|
|
104
|
+
|
|
105
|
+
group.forEach((word, wi) => {
|
|
106
|
+
const span = document.getElementById('w_' + gi + '_' + wi);
|
|
107
|
+
tl.set(span, { className: '+=active-word' }, word.start);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
tl.fromTo(el,
|
|
111
|
+
{ scale: 0.8, opacity: 0 },
|
|
112
|
+
{ scale: 1, opacity: 1, duration: 0.1, ease: 'back.out(1.5)' },
|
|
113
|
+
groupStart
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
tl.set(el, { visibility: 'hidden' }, groupEnd + 0.05);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
tl.to({}, { duration: 0.01 }, parseFloat('{{duration}}') - 0.01);
|
|
120
|
+
|
|
121
|
+
window.__timelines = window.__timelines || {};
|
|
122
|
+
window.__timelines.main = tl;
|
|
123
|
+
})();
|
|
124
|
+
</script>
|
|
125
|
+
</body>
|
|
126
|
+
</html>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tiktok-captions",
|
|
3
|
+
"title": "TikTok-style word-by-word captions over video",
|
|
4
|
+
"description": "Renders animated word-by-word captions centered on screen over a background video. Expects a JSON transcript from video_transcribe.",
|
|
5
|
+
"width": 1080,
|
|
6
|
+
"height": 1920,
|
|
7
|
+
"fps": 30,
|
|
8
|
+
"default_duration": 8,
|
|
9
|
+
"inputs": {
|
|
10
|
+
"background": {
|
|
11
|
+
"kind": "video",
|
|
12
|
+
"required": true,
|
|
13
|
+
"staged_as": "background.mp4",
|
|
14
|
+
"description": "The video to overlay captions on."
|
|
15
|
+
},
|
|
16
|
+
"transcript": {
|
|
17
|
+
"kind": "json",
|
|
18
|
+
"required": true,
|
|
19
|
+
"staged_as": "transcript.json",
|
|
20
|
+
"description": "Word-level transcript JSON from video_transcribe: [{text, start, end}, ...]"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"params": {
|
|
24
|
+
"words_per_group": {
|
|
25
|
+
"kind": "integer",
|
|
26
|
+
"min": 1,
|
|
27
|
+
"max": 8,
|
|
28
|
+
"default": 3,
|
|
29
|
+
"description": "How many words to show at once."
|
|
30
|
+
},
|
|
31
|
+
"font_size": {
|
|
32
|
+
"kind": "integer",
|
|
33
|
+
"min": 24,
|
|
34
|
+
"max": 200,
|
|
35
|
+
"default": 72
|
|
36
|
+
},
|
|
37
|
+
"text_color": {
|
|
38
|
+
"kind": "color",
|
|
39
|
+
"default": "#ffffff"
|
|
40
|
+
},
|
|
41
|
+
"highlight_color": {
|
|
42
|
+
"kind": "color",
|
|
43
|
+
"default": "#FFD700"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|