Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
28 KiB
| name | description | arguments | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ai-animation | Use when creating AI-powered animations and videos — nano-banana keyframes → Kling/Luma/Veo video generation via fal.ai → web-ready output. Full pipeline from concept to scroll-driven animation or video embed. Triggers on "AI animation", "animate image", "AI video", "Kling", "image to video", "анимируй", "сделай видео из картинки". |
|
AI Animation Pipeline
nano-banana (keyframes) → fal.ai (video gen) → FFmpeg (web-ready) → scroll/embed Prices verified 2026-03-13 [E1-fal.ai API docs]
Pipeline Overview
Concept / Prompt
│
├─→ [1. Keyframes] nano-banana → reference images (poses, angles, scenes)
│
├─→ [2. Animate] fal.ai → Kling / Luma / Veo → MP4 video
│
├─→ [3. Process] FFmpeg → frame sequence / optimized video / GIF
│
└─→ [4. Integrate] scroll-animation / video embed / motion-design
Model Selection Matrix [E1-fal.ai docs]
| Use Case | Model | Endpoint | Cost/sec | Duration | Why |
|---|---|---|---|---|---|
| Product reveal | Kling v3 Pro | fal-ai/kling-video/v3/pro/image-to-video |
$0.112 (no audio) / $0.168 (audio) | 3-15s | Best motion, multi-prompt, elements |
| Hero loop | Luma Ray 2 | fal-ai/luma-dream-machine/ray-2/image-to-video |
$0.10/sec @540p | 5s, 9s | loop: true, start+end keyframes |
| Cinematic | Veo 3 | fal-ai/veo3 |
$0.20 (no audio) / $0.40 (audio) | 4-8s | Best quality + audio, 1080p |
| Cinematic (fast) | Veo 3 Fast | fal-ai/veo3/fast/image-to-video |
$0.10 (no audio) / $0.15 (audio) | 4-8s | 50% cheaper I2V |
| Bulk/cheap | LTX 2.0 | fal-ai/ltx-2/text-to-video/fast |
$0.04 @1080p | 6-20s | Cheapest, up to 4K, extend/retake |
| Stylized | PixVerse v4.5 | fal-ai/pixverse/v4.5/image-to-video |
$0.03-0.08/sec | 5-8s | anime/3d/clay/comic/cyberpunk + camera presets |
Quick Decision
- Loop for hero section? → Luma Ray 2 (loop: true)
- Animate a product/design comp? → Kling v3 Pro
- Maximum quality, budget OK? → Veo 3
- Need 10+ videos cheap? → LTX 2.0
- Specific art style? → PixVerse v4.5
Step 1: Generate Keyframes (nano-banana)
Generate reference images that will be animated into video.
Best Practices for Animation Keyframes
# Product floating in space — good for Kling rotation
nano-banana "premium wireless headphones floating on dark background, studio lighting, centered composition, clean edges" -s 2K -a 16:9 -o keyframe-product
# Scene for cinematic animation — good for Veo/Kling
nano-banana "cyberpunk street at golden hour, rain puddles, neon reflections, cinematic composition" -s 2K -a 16:9 -o keyframe-scene
# Character pose — good for Kling motion
nano-banana "3D character mascot robot waving, isometric view, white background, Pixar style" -s 1K -a 1:1 -o keyframe-character
# Hero background — good for Luma loop
nano-banana "abstract flowing liquid metal, iridescent purple and gold, macro photography" -s 2K -a 16:9 -o keyframe-hero
# Transparent asset for animation
nano-banana "floating crystal sphere with inner glow" -t -s 1K -o keyframe-crystal
nano-banana → fal.ai Upload Workflow
nano-banana outputs local PNG files. To use as input for fal.ai video models:
import fal_client
# Option A: Upload to fal CDN (recommended for large files)
image_url = fal_client.upload_file("keyframe-product.png") # → https://fal.media/files/...
# Option B: Encode as data URI (inline, faster for small files, no CDN hop)
image_data = fal_client.encode_file("keyframe-product.png")
# Then use in any video model
result = fal_client.run("fal-ai/kling-video/v3/pro/image-to-video", arguments={
"start_image_url": image_url, # or image_data
"prompt": "the headphones slowly rotate",
"duration": "5"
})
Optimal nano-banana settings per video model:
| Video Model | nano-banana Size | Aspect | Notes |
|---|---|---|---|
| Kling v3 Pro | -s 2K |
-a 16:9 or -a 9:16 or -a 1:1 |
Match aspect_ratio param |
| Luma Ray 2 | -s 2K |
-a 16:9 or any of 6 ratios |
540p output, 2K input still better |
| Veo 3 | -s 2K |
-a 16:9 or -a 9:16 only |
Must be 720p+ and <8MB |
| LTX 2.0 | -s 2K |
-a 16:9 |
Flexible, handles most inputs |
| PixVerse v4.5 | -s 2K |
match target | Resolution matches input |
Keyframe Prompting Rules
- Clean edges — AI video models struggle with busy/cluttered compositions
- Centered subject — off-center subjects may drift during animation
- Consistent lighting — dramatic lighting gives video models more to work with
- Simple backgrounds — solid/gradient backgrounds → cleaner motion
- Describe potential motion — "floating", "flowing", "spinning" primes the composition
- 16:9 for video — match the target video aspect ratio in the keyframe
- High resolution — use
-s 2Kminimum, video models downsample better than upscale
Step 2: Animate via fal.ai
Prerequisites
pip install fal-client
export FAL_KEY="your-key"
fal_client SDK Patterns (Python)
import fal_client
# SYNC — blocks until done (simplest, for single generations)
result = fal_client.run("fal-ai/veo3", arguments={...})
video_url = result["video"]["url"]
# ASYNC — non-blocking
import asyncio
async def generate():
result = await fal_client.run_async("fal-ai/veo3", arguments={...})
return result["video"]["url"]
# QUEUE with progress tracking — best for long jobs
async def generate_with_progress():
handler = await fal_client.submit_async("fal-ai/veo3", arguments={...})
logs_index = 0
async for event in handler.iter_events(with_logs=True):
if isinstance(event, fal_client.Queued):
print(f"Queue position: {event.position}")
elif isinstance(event, (fal_client.InProgress, fal_client.Completed)):
for log in event.logs[logs_index:]:
print(log["message"])
logs_index = len(event.logs)
result = await handler.get()
return result["video"]["url"]
# FILE UPLOAD — local file → fal CDN URL
url = fal_client.upload_file("local-image.png") # returns https://fal.media/files/...
data_uri = fal_client.encode_file("local-image.png") # inline data URI, no upload
REST API Pattern (curl)
# Sync (blocks until done, timeout risk for long generations)
curl -X POST "https://fal.run/{endpoint}" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "...", ...}'
# Queue submit (non-blocking, recommended)
REQUEST_ID=$(curl -s -X POST "https://queue.fal.run/{endpoint}" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "...", ...}' | jq -r '.request_id')
# Check status
curl -s "https://queue.fal.run/{endpoint}/requests/$REQUEST_ID/status" \
-H "Authorization: Key $FAL_KEY"
# Get result
curl -s "https://queue.fal.run/{endpoint}/requests/$REQUEST_ID" \
-H "Authorization: Key $FAL_KEY"
# Webhook (fire and forget)
curl -X POST "https://queue.fal.run/{endpoint}" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-H "X-Fal-Webhook-Url: https://your-server.com/webhook" \
-d '{"prompt": "..."}'
Kling v3 Pro — Image to Video [E1-verified]
Best for: product reveals, design comp animation, character motion, multi-shot sequences.
import fal_client
result = fal_client.run(
"fal-ai/kling-video/v3/pro/image-to-video",
arguments={
"prompt": "the headphones slowly rotate 360 degrees, studio lighting, smooth motion",
"start_image_url": "https://...keyframe-product.png",
"duration": "5", # "3" to "15" seconds (string)
"aspect_ratio": "16:9", # 16:9, 9:16, 1:1
"generate_audio": False, # True adds $0.056/sec
}
)
video_url = result["video"]["url"]
print(f"Video: {video_url}")
// Node.js
import { fal } from "@fal-ai/client";
const result = await fal.subscribe("fal-ai/kling-video/v3/pro/image-to-video", {
input: {
prompt: "the headphones slowly rotate 360 degrees",
start_image_url: "https://...keyframe.png",
duration: "5",
aspect_ratio: "16:9",
generate_audio: false,
},
logs: true,
onQueueUpdate: (update) => {
if (update.status === "IN_PROGRESS") {
update.logs.map((log) => log.message).forEach(console.log);
}
},
});
Parameters:
| Param | Values | Default | Notes |
|---|---|---|---|
prompt |
string | — | Describe MOTION, not scene. Mutually exclusive with multi_prompt |
start_image_url |
URL | required | Source keyframe (not image_url) |
end_image_url |
URL | — | End frame for interpolation |
duration |
"3"-"15" |
"5" |
String, per-second increments |
aspect_ratio |
16:9, 9:16, 1:1 |
16:9 |
|
generate_audio |
bool | true |
Native audio (Chinese/English) |
negative_prompt |
string | "blur, distort, and low quality" |
|
cfg_scale |
float | 0.5 |
Prompt adherence strength |
multi_prompt |
array | — | Multi-shot: [{"prompt": "...", "duration": "5"}, ...] |
elements |
array | — | Character/object consistency via reference images |
Cost [E1]:
- No audio: $0.112/sec → 5s = $0.56, 10s = $1.12
- With audio: $0.168/sec → 5s = $0.84, 10s = $1.68
- With voice control: $0.196/sec
Multi-shot example:
result = fal_client.run("fal-ai/kling-video/v3/pro/image-to-video", arguments={
"start_image_url": "https://...keyframe.png",
"multi_prompt": [
{"prompt": "camera orbits around the product slowly", "duration": "5"},
{"prompt": "zoom in to the detail panel", "duration": "5"}
],
"generate_audio": False,
})
curl:
curl -X POST "https://fal.run/fal-ai/kling-video/v3/pro/image-to-video" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{"start_image_url": "https://...keyframe.png", "prompt": "rotate slowly", "duration": "5", "generate_audio": false}'
Prompting for motion:
- Describe WHAT MOVES: "the camera slowly orbits around the product"
- NOT the scene:
"beautiful product on dark background" - Be specific: "rotate 90 degrees clockwise" > "rotate"
- Keep it simple: one primary motion per clip
Luma Ray 2 — Looping Hero Videos [E1-verified]
Best for: hero section backgrounds, ambient loops, living textures, start→end interpolation.
result = fal_client.run(
"fal-ai/luma-dream-machine/ray-2/image-to-video",
arguments={
"prompt": "gentle flowing motion, seamless loop",
"image_url": "https://...keyframe-hero.png",
"loop": True, # seamless loop!
"resolution": "540p", # 540p, 720p (2x), 1080p (4x)
"duration": "5s", # "5s" or "9s"
"aspect_ratio": "16:9",
}
)
video_url = result["video"]["url"]
Key features:
loop: True→ seamless loops for<video loop autoplay>hero sectionsend_image_url→ interpolate between start and end keyframes (морфинг!)
Start→End keyframe example:
result = fal_client.run("fal-ai/luma-dream-machine/ray-2/image-to-video", arguments={
"prompt": "smooth transformation between the two states",
"image_url": "https://...keyframe-start.png",
"end_image_url": "https://...keyframe-end.png",
"duration": "5s",
"aspect_ratio": "16:9",
})
Parameters:
| Param | Values | Default | Notes |
|---|---|---|---|
prompt |
string | required | Min 3, max 5000 chars |
image_url |
URL | required | Start frame |
end_image_url |
URL | — | End frame (interpolation) |
loop |
bool | false |
End blended with beginning |
duration |
"5s", "9s" |
"5s" |
9s costs 2x |
resolution |
"540p", "720p", "1080p" |
"540p" |
720p=2x, 1080p=4x cost |
aspect_ratio |
16:9, 9:16, 4:3, 3:4, 21:9, 9:21 |
"16:9" |
Cost [E1]:
| Resolution | 5s | 9s |
|---|---|---|
| 540p | $0.50 | $1.00 |
| 720p | $1.00 | $2.00 |
| 1080p | $2.00 | $4.00 |
curl:
curl -X POST "https://fal.run/fal-ai/luma-dream-machine/ray-2/image-to-video" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "gentle flowing motion, seamless loop", "image_url": "https://...hero.png", "loop": true, "resolution": "540p", "duration": "5s"}'
Veo 3 — Maximum Quality [E1-verified]
Best for: cinematic hero videos, with audio. Two variants: standard and fast.
# Standard — best quality
result = fal_client.run(
"fal-ai/veo3",
arguments={
"prompt": "cinematic reveal of headphones, dramatic lighting, camera dollies in slowly",
"image_url": "https://...keyframe.png", # optional for text-to-video
"duration": "8s", # "4s", "6s", "8s"
"resolution": "1080p", # "720p", "1080p"
"aspect_ratio": "16:9", # "16:9", "9:16"
"generate_audio": True, # unique: audio generation
}
)
video_url = result["video"]["url"]
# Fast I2V — 50% cheaper for image-to-video
result = fal_client.run(
"fal-ai/veo3/fast/image-to-video",
arguments={
"prompt": "camera slowly orbits the product",
"image_url": "https://...keyframe.png",
"duration": "8s",
"generate_audio": False,
}
)
Unique: Veo 3 generates audio with the video. safety_tolerance 1-6 (1=strict, 6=permissive). auto_fix auto-rewrites failing prompts. seed for reproducibility.
Cost [E1]:
| Variant | No audio | With audio |
|---|---|---|
| Standard | $0.20/sec | $0.40/sec |
| Fast I2V | $0.10/sec | $0.15/sec |
8s standard with audio = $3.20. 8s fast I2V no audio = $0.80.
Image input constraints (Veo 3): Max 8MB, must be 720p+, formats: PNG/JPEG/WebP. Aspect must be 16:9 or 9:16.
curl (fast I2V):
curl -X POST "https://fal.run/fal-ai/veo3/fast/image-to-video" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "gentle camera movement, ambient sounds", "image_url": "https://...keyframe.png", "duration": "8s", "generate_audio": true}'
LTX 2.0 Fast — Budget Option [E1-verified]
Best for: bulk generation, prototyping, long videos up to 20s, up to 4K.
# Text-to-video
result = fal_client.run(
"fal-ai/ltx-2/text-to-video/fast",
arguments={
"prompt": "flowing abstract particles, dark background",
"duration": 6, # 6, 8, 10, 12, 14, 16, 18, 20 seconds
"resolution": "1080p", # "1080p", "1440p", "2160p"
"fps": 25, # 25 or 50
"generate_audio": True,
}
)
# Image-to-video
result = fal_client.run(
"fal-ai/ltx-2/image-to-video/fast",
arguments={
"prompt": "gentle camera movement revealing details",
"image_url": "https://...keyframe.png",
"duration": 6,
"resolution": "1080p",
}
)
# Extend existing video
result = fal_client.run(
"fal-ai/ltx-2/extend-video",
arguments={
"video_url": "https://...existing.mp4",
"prompt": "continue the motion smoothly",
"duration": 5, # max 20s total
"mode": "end", # "start" or "end"
}
)
Cost [E1]: $0.04/sec @1080p, $0.08/sec @1440p, $0.16/sec @2160p 6s @1080p = $0.24. 5x cheaper than Kling (no audio).
Extra endpoints: extend-video (extend existing), retake-video (regenerate segment), audio-to-video (audio→video).
PixVerse v4.5 — Stylized [E1-verified]
Best for: 3D render, cyberpunk, anime, clay, comic styles. Has camera presets.
result = fal_client.run(
"fal-ai/pixverse/v4.5/image-to-video",
arguments={
"prompt": "cyberpunk city comes alive, neon signs flicker",
"image_url": "https://...keyframe.png",
"style": "cyberpunk", # anime, 3d_animation, clay, comic, cyberpunk
"camera_movement": "smooth_zoom_in", # see list below
"resolution": "720p", # 360p, 540p, 720p, 1080p
"duration": "5", # "5" or "8" (8s = 2x cost, 1080p = 5s only)
}
)
Camera presets: horizontal_left, horizontal_right, vertical_up, vertical_down, zoom_in, zoom_out, crane_up, quickly_zoom_in, quickly_zoom_out, smooth_zoom_in, camera_rotation, robo_arm, super_dolly_out, whip_pan, hitchcock, left_follow, right_follow, pan_left, pan_right, fix_bg
Cost [E1]:
| Resolution | 5s | 8s (2x) |
|---|---|---|
| 360p/540p | $0.15 | $0.30 |
| 720p | $0.20 | $0.40 |
| 1080p | $0.40 | — (5s only) |
Step 3: Process for Web (FFmpeg)
Download Generated Video
# Download from fal.ai URL
curl -o generated.mp4 "VIDEO_URL_FROM_FAL"
Route A: Frame Sequence (for scroll animations)
Use when the video will be played via GSAP ScrollTrigger or canvas scroll.
# Extract frames at 30fps, 1920x1080
mkdir -p frames/desktop
ffmpeg -i generated.mp4 -vf "fps=30,scale=1920:1080" frames/desktop/frame_%04d.png
# Convert to WebP
for f in frames/desktop/*.png; do
cwebp -q 80 "$f" -o "${f%.png}.webp"
rm "$f"
done
# Mobile version (fewer frames, smaller)
mkdir -p frames/mobile
ffmpeg -i generated.mp4 -vf "fps=15,scale=960:540" frames/mobile/frame_%04d.png
for f in frames/mobile/*.png; do
cwebp -q 80 "$f" -o "${f%.png}.webp"
rm "$f"
done
→ Then use scroll-animation skill for GSAP ScrollTrigger canvas playback.
Route B: Optimized Video (for autoplay/embed)
Use for hero video backgrounds, embedded players.
# Web-optimized MP4 (H.264 for max compat)
ffmpeg -i generated.mp4 \
-c:v libx264 -preset slow -crf 23 \
-c:a aac -b:a 128k \
-movflags +faststart \
-vf "scale=1920:1080" \
hero-video.mp4
# WebM (VP9, smaller, modern browsers)
ffmpeg -i generated.mp4 \
-c:v libvpx-vp9 -crf 30 -b:v 2M \
-c:a libopus -b:a 128k \
-vf "scale=1920:1080" \
hero-video.webm
# AV1 (smallest, newer browsers)
ffmpeg -i generated.mp4 \
-c:v libaom-av1 -crf 30 -b:v 0 \
-c:a libopus -b:a 128k \
-vf "scale=1920:1080" \
hero-video.av1.mp4
Route C: Scrub-Optimized Video (for scroll-driven playback)
# Every frame is keyframe = instant seeking
ffmpeg -i generated.mp4 \
-c:v libx264 -preset slow -crf 23 \
-g 1 -an -movflags +faststart \
-vf "scale=1920:1080" \
scrub-video.mp4
Route D: Looping GIF (for social/email)
# High quality GIF with palette optimization
ffmpeg -i generated.mp4 \
-vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-loop 0 output.gif
Step 4: Integrate into Web
Hero Video Background
<section class="hero">
<video autoplay loop muted playsinline class="hero-video">
<source src="hero-video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08">
<source src="hero-video.webm" type="video/webm">
<source src="hero-video.mp4" type="video/mp4">
</video>
<div class="hero-content">
<h1>Product Name</h1>
</div>
</section>
<style>
.hero { position: relative; height: 100vh; overflow: hidden; }
.hero-video {
position: absolute; inset: 0;
width: 100%; height: 100%;
object-fit: cover;
}
.hero-content {
position: relative; z-index: 1;
display: grid; place-items: center;
height: 100%;
}
</style>
Scroll-Driven Frame Sequence
→ Invoke scroll-animation skill with the frame sequence from Step 3A.
Reduced Motion Fallback
<picture>
<source srcset="keyframe-hero.avif" type="image/avif">
<source srcset="keyframe-hero.webp" type="image/webp">
<img src="keyframe-hero.jpg" alt="Hero" class="hero-fallback">
</picture>
<style>
.hero-video { display: block; }
.hero-fallback { display: none; }
@media (prefers-reduced-motion: reduce) {
.hero-video { display: none; }
.hero-fallback { display: block; }
}
</style>
Cost Calculator [E1-verified]
Per-Video Costs (no audio, cheapest resolution)
| Model | 5s | 10s | With keyframe ($0.07) |
|---|---|---|---|
| Kling v3 Pro (no audio) | $0.56 | $1.12 | $0.63 / $1.19 |
| Kling v3 Pro (audio) | $0.84 | $1.68 | $0.91 / $1.75 |
| Luma Ray 2 @540p | $0.50 | — | $0.57 |
| Luma Ray 2 @1080p | $2.00 | — | $2.07 |
| Veo 3 Standard (no audio) | $1.00 | — | $1.07 |
| Veo 3 Fast I2V (no audio) | $0.50 | — | $0.57 |
| LTX 2.0 @1080p | $0.20 | $0.40 | $0.27 / $0.47 |
| PixVerse v4.5 @720p | $0.20 | — | $0.27 |
Landing Page Budget Estimates
| Scenario | Videos | Model | Est. Cost |
|---|---|---|---|
| 1 hero loop @540p | 1 | Luma | ~$0.57 |
| Product reveal 10s | 1 | Kling no audio | ~$1.19 |
| Product + hero | 2 | Kling + Luma | ~$1.20 |
| Full cinematic page | 3-5 | Mixed | ~$2-5 |
| Bulk content (10 clips) | 10 | LTX 2.0 | ~$2.70 |
| Max quality (Veo 3 audio) | 3 | Veo 3 Standard | ~$10+ |
Before Running — API Cost Guard
- Check fal.ai dashboard balance
- Calculate exact cost:
duration × cost_per_sec + keyframe_cost - Generate ONE test clip first
- Review quality before batch
- Tell user total cost before proceeding
Full Pipeline Examples
Example 1: Apple-Style Product Scroll
# 1. Keyframe
nano-banana "premium smart watch floating on dark background, studio rim lighting, centered" -s 2K -a 16:9 -o watch-keyframe
# 2. Animate (product rotation)
python3 -c "
import fal_client
result = fal_client.run('fal-ai/kling-video/v3/pro/image-to-video', arguments={
'prompt': 'the watch slowly rotates 360 degrees, camera orbits smoothly, dramatic lighting',
'start_image_url': 'file://watch-keyframe.png',
'duration': '10',
'aspect_ratio': '16:9',
'generate_audio': False,
})
print(result['video']['url'])
"
# 3. Download & extract frames
curl -o watch-rotation.mp4 "VIDEO_URL"
mkdir -p public/frames/watch/desktop public/frames/watch/mobile
ffmpeg -i watch-rotation.mp4 -vf "fps=30,scale=1920:1080" public/frames/watch/desktop/frame_%04d.png
ffmpeg -i watch-rotation.mp4 -vf "fps=15,scale=960:540" public/frames/watch/mobile/frame_%04d.png
# Convert to WebP
for dir in public/frames/watch/desktop public/frames/watch/mobile; do
for f in "$dir"/*.png; do cwebp -q 80 "$f" -o "${f%.png}.webp" && rm "$f"; done
done
# 4. → Use scroll-animation skill for GSAP canvas playback
Cost: ~$0.07 (keyframe) + $1.12 (Kling 10s no audio) = $1.19
Example 2: Hero Background Loop
# 1. Keyframe
nano-banana "abstract flowing liquid metal, iridescent, macro photography, dark background" -s 2K -a 16:9 -o hero-bg
# 2. Animate (seamless loop)
python3 -c "
import fal_client
result = fal_client.run('fal-ai/luma-dream-machine/ray-2/image-to-video', arguments={
'prompt': 'gentle flowing motion, metallic liquid ripples, seamless loop',
'image_url': 'file://hero-bg.png',
'loop': True,
'aspect_ratio': '16:9'
})
print(result['video']['url'])
"
# 3. Optimize for web autoplay
curl -o hero-loop-raw.mp4 "VIDEO_URL"
ffmpeg -i hero-loop-raw.mp4 -c:v libx264 -preset slow -crf 23 -an -movflags +faststart hero-loop.mp4
ffmpeg -i hero-loop-raw.mp4 -c:v libvpx-vp9 -crf 30 -b:v 2M -an hero-loop.webm
Cost: ~$0.07 + $0.50 = $0.57
Example 3: Bulk Content Videos (Budget)
# 1. Generate 5 keyframes
for i in 1 2 3 4 5; do
nano-banana "feature illustration $i, minimal, clean" -s 1K -a 16:9 -o "feature-$i"
done
# 2. Animate all with LTX (cheapest)
python3 << 'EOF'
import fal_client
prompts = [
"gentle zoom in, subtle particle effects",
"slow pan right revealing details",
"elements float upward gently",
"soft glow pulses outward",
"camera slowly pulls back"
]
for i, prompt in enumerate(prompts, 1):
result = fal_client.run("fal-ai/ltx-2/text-to-video/fast", arguments={
"prompt": prompt,
"image_url": f"file://feature-{i}.png",
"duration": 5,
"aspect_ratio": "16:9"
})
print(f"Feature {i}: {result['video']['url']}")
EOF
Cost: 5 × ($0.07 + $0.20) = $1.35 for 5 videos
Prompting Guide for Video Models
Motion Prompts (DO)
- "slowly rotates 360 degrees clockwise"
- "camera dollies in from medium to close-up"
- "gentle floating up and down motion"
- "particles drift outward from center"
- "liquid flows from left to right"
- "zoom in on the detail, rack focus"
Motion Prompts (DON'T)
"beautiful product"(describes scene, not motion)"4K cinematic masterpiece"(quality tags don't help)"the scene transforms into a different scene"(too complex)"person walks, talks, and dances"(too many actions)
Rules
- One motion per clip — don't combine rotate + zoom + pan
- Describe the camera — "camera orbits", "dolly in", "static wide"
- Describe speed — "slowly", "gently", "dramatically fast"
- 5s for simple motion, 10s for complex reveals
- Match prompt to model — Kling handles product/object motion best, Luma handles ambient/organic best
Integration with Other Skills
| Skill | Role | When |
|---|---|---|
nano-banana |
Generate keyframe images | Step 1 |
video-gen |
Process video → frame sequence | Step 3A |
scroll-animation |
GSAP ScrollTrigger playback | Step 4 (scroll) |
motion-design |
Page transitions + micro-interactions | Step 4 (ambient) |
web-assets |
Optimize final video/frames | Step 3 (all routes) |
landing-page |
Full page orchestration | When recipe needs video |
3d-scene |
Three.js alternative to AI video | When real 3D needed |
nano-banana via fal.ai API (Alternative to CLI)
If the nano-banana CLI is not available, use the fal.ai endpoint directly:
import fal_client
# Generate keyframe via fal.ai nano-banana (Gemini image gen)
result = fal_client.run("fal-ai/nano-banana", arguments={
"prompt": "premium smart watch on dark background, studio rim lighting, centered, clean edges",
"num_images": 1,
"aspect_ratio": "16:9", # 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 4:5, 5:4, 21:9
"output_format": "png", # png, jpeg, webp
"safety_tolerance": 4, # 1 (strict) to 6 (permissive)
})
keyframe_url = result["images"][0]["url"]
# Cost: $0.039 per image
# Now chain directly into video generation (no upload needed — already a URL!)
video_result = fal_client.run("fal-ai/kling-video/v3/pro/image-to-video", arguments={
"start_image_url": keyframe_url, # direct URL from nano-banana
"prompt": "watch slowly rotates 360 degrees, studio lighting",
"duration": "5",
"generate_audio": False,
})
video_url = video_result["video"]["url"]
Key advantage: nano-banana output is already a fal.ai URL, so it chains directly into any video model without upload. Total cost for keyframe + 5s Kling video: $0.039 + $0.56 = $0.60.
# curl version
KEYFRAME_URL=$(curl -s -X POST "https://fal.run/fal-ai/nano-banana" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "premium watch on dark bg, studio lighting, centered", "aspect_ratio": "16:9"}' \
| jq -r '.images[0].url')
curl -X POST "https://queue.fal.run/fal-ai/kling-video/v3/pro/image-to-video" \
-H "Authorization: Key $FAL_KEY" \
-H "Content-Type: application/json" \
-d "{\"start_image_url\": \"$KEYFRAME_URL\", \"prompt\": \"watch rotates slowly\", \"duration\": \"5\", \"generate_audio\": false}"
Workflow Summary
- Define goal — what animation, where on page, what triggers it?
- Pick model — use selection matrix above
- Cost estimate — calculate and tell user BEFORE generating
- Generate keyframe — nano-banana with animation-friendly composition
- Animate — fal.ai with focused motion prompt
- Review — watch output, iterate prompt if needed (budget 2-3 attempts)
- Process — choose route: frame sequence / video / scrub / GIF
- Integrate — embed with scroll-animation, video tag, or motion-design
- Fallback — static keyframe for prefers-reduced-motion