| name | arcads-ai-video-generator |
| description | Create AI marketing videos and static Meta image ads using the Arcads API with Seedance 2.0, Sora 2, Veo 3.1, Kling, Nano Banana, ChatGPT Image, and 37 static ad templates |
| triggers | ["generate an AI video ad","create a UGC video with Seedance","make a product reveal video","generate AI influencer images","create static Meta image ads","build a Pixar-style animated ad","animate a still image with Veo","generate YouTube thumbnails"] |
Arcads AI Video Generator
Skill by ara.so โ Claude Code Skills collection.
Create AI marketing videos and images using the Arcads API. Supports the full creative stack: Seedance 2.0 (flagship video), Sora 2, Veo 3.1, Kling 3.0, Grok Video, Nano Banana 2/Pro/Edit, ChatGPT Image 2, OmniHuman, Audio-driven models, plus a 37-template static Meta image-ad library and multi-step pipelines for Pixar-style and claymation animated ads.
Installation
git clone https://github.com/krusemediallc/arcads-claude-code.git
cd arcads-claude-code
./scripts/setup.sh
The setup script will:
- Prompt for your Arcads API key (get it at app.arcads.ai/settings/api)
- Save credentials to
.env
- Verify API connection
- Create
MASTER_CONTEXT.md workspace file
Prerequisites
| Tool | Required for | Install |
|---|
| Python 3.10+ | Core API operations | brew install python@3.12 |
ffmpeg | Video stitching, chroma-key | brew install ffmpeg |
jq | JSON parsing in bash scripts | brew install jq |
| Node.js | Caption burn-in (hyperframes) | brew install node |
whisper | Caption transcription | pip install openai-whisper |
Environment Setup
Create .env in the project root:
ARCADS_API_KEY=your_api_key_here
Core API Patterns
Video Generation (Seedance 2.0)
Endpoint: POST https://api.arcads.ai/v1/seedance2/video
import requests
import os
import time
API_KEY = os.getenv('ARCADS_API_KEY')
BASE_URL = 'https://api.arcads.ai'
def generate_seedance_video(prompt, duration=12):
"""Generate a Seedance 2.0 video."""
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
payload = {
'prompt': prompt,
'duration': duration,
'shotStyle': 'ugc-selfie'
}
response = requests.post(
f'{BASE_URL}/v1/seedance2/video',
headers=headers,
json=payload
)
job = response.json()
job_id = job['id']
while True:
status_response = requests.get(
f'{BASE_URL}/v1/jobs/{job_id}',
headers=headers
)
status = status_response.json()
if status['status'] == 'completed':
return status['videoUrl']
elif status['status'] == 'failed':
raise Exception(f"Generation failed: {status.get('error')}")
time.sleep(5)
video_url = generate_seedance_video(
prompt="""
[SCENE: NATURAL KITCHEN LIGHTING]
Medium shot, slight handheld motion.
Woman, early 30s, messy bun, casual tank top.
Holding [PRODUCT] at chest level, genuine smile.
[DIALOGUE]
"Okay so I used to buy [COMPETITOR] every month but then I found THISโ"
*lifts product slightly, direct eye contact*
"โand honestly? I'm never going back."
[VISUAL BEATS]
0-3s: Establishing shot, product reveal
3-7s: Close on face during key claim
7-12s: Pull back, casual product demo gesture
""",
duration=12
)
print(f"Video ready: {video_url}")
Seedance 2.0 Prompt Formulas
Five battle-tested formulas ship with the skill:
1. UGC Selfie-Style Review
[SCENE: NATURAL KITCHEN LIGHTING]
Medium shot, slight handheld motion.
Woman, early 30s, messy bun, casual tank top.
Holding [PRODUCT] at chest level, genuine smile.
[DIALOGUE]
"Okay so I used to buy [COMPETITOR] every month..."
[VISUAL BEATS]
0-3s: Establishing shot
3-7s: Close on face
7-12s: Product demo gesture
2. Premium Product Reveal (No Person)
[SCENE: DARK VOID]
No human. Product only.
Black background, dramatic side lighting.
[TEXT OVERLAYS]
Beat 1 (0-3s): "Most [CATEGORY] products..."
Beat 2 (3-6s): "[PRODUCT] is different."
Beat 3 (6-9s): Hero rotation + key feature callout
[CAMERA]
Slow push-in, 360ยฐ rotation at beat 3
3. Product Hero with Elements
[SCENE: ELEMENTAL SHOWCASE]
Product suspended mid-frame.
Water splash from below, mist rising.
Slow rotation (15ยฐ/sec).
[VISUAL FX]
0-2s: Water splash entry
2-5s: Mist buildup
5-8s: Light rays piercing mist
8-12s: Hero rotation + feature close-up
Image Generation (Nano Banana)
Endpoint: POST https://api.arcads.ai/v1/nano-banana/image
import base64
def generate_nano_banana_image(prompt, reference_image_path=None, model='nano-banana-2'):
"""Generate a Nano Banana image with optional reference."""
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
payload = {
'prompt': prompt,
'model': model,
'aspectRatio': '9:16'
}
if reference_image_path:
with open(reference_image_path, 'rb') as f:
img_base64 = base64.b64encode(f.read()).decode('utf-8')
payload['refImageAsBase64'] = img_base64
response = requests.post(
f'{BASE_URL}/v1/nano-banana/image',
headers=headers,
json=payload
)
job = response.json()
job_id = job['id']
while True:
status_response = requests.get(
f'{BASE_URL}/v1/jobs/{job_id}',
headers=headers
)
status = status_response.json()
if status['status'] == 'completed':
return status['imageUrl']
elif status['status'] == 'failed':
raise Exception(f"Generation failed: {status.get('error')}")
time.sleep(3)
image_url = generate_nano_banana_image(
prompt="""
iPhone selfie camera, natural bedroom lighting.
Woman, 22, freckles, golden hour glow.
Holding [PRODUCT] at chest level, genuine smile.
Messy hair, no makeup, casual tank top.
Slight camera shake, realistic skin texture.
Background: unmade bed, string lights, plants.
""",
reference_image_path='references/influencers/sofia_hero.jpg'
)
Veo 3.1 (Start-Frame Animation)
Endpoint: POST https://api.arcads.ai/v1/veo3/video
def animate_with_veo(start_frame_path, prompt, duration=8):
"""Animate a still image with Veo 3.1."""
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
with open(start_frame_path, 'rb') as f:
img_base64 = base64.b64encode(f.read()).decode('utf-8')
payload = {
'prompt': prompt,
'startFrame': img_base64,
'duration': duration,
'dialogue': 'I switched to this product and never looked back'
}
response = requests.post(
f'{BASE_URL}/v1/veo3/video',
headers=headers,
json=payload
)
job = response.json()
return poll_job(job['id'])
def poll_job(job_id):
"""Generic job polling."""
headers = {'Authorization': f'Bearer {API_KEY}'}
while True:
response = requests.get(
f'{BASE_URL}/v1/jobs/{job_id}',
headers=headers
)
status = response.json()
if status['status'] == 'completed':
return status.get('videoUrl') or status.get('imageUrl')
elif status['status'] == 'failed':
raise Exception(f"Job failed: {status.get('error')}")
time.sleep(5)
Sora 2 Video Generation
Endpoint: POST https://api.arcads.ai/v1/sora2/video
def generate_sora_video(prompt, duration=16, reference_image_path=None):
"""Generate a Sora 2 video (up to 20s)."""
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
payload = {
'prompt': prompt,
'duration': duration
}
if reference_image_path:
with open(reference_image_path, 'rb') as f:
img_base64 = base64.b64encode(f.read()).decode('utf-8')
payload['styleReference'] = img_base64
response = requests.post(
f'{BASE_URL}/v1/sora2/video',
headers=headers,
json=payload
)
return poll_job(response.json()['id'])
video_url = generate_sora_video(
prompt="""
Cozy coffee shop interior, warm afternoon light.
Camera tracks across table as woman opens laptop.
Smooth dolly shot, shallow depth of field.
Steam rising from coffee mug in foreground.
Natural color grading, 24fps cinematic feel.
""",
duration=16
)
B-Roll / Scene Generation (Kling 3.0)
Endpoint: POST https://api.arcads.ai/v1/b-roll or POST https://api.arcads.ai/v1/scene
def generate_broll(prompt, duration=5):
"""Generate b-roll footage with Kling 3.0."""
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
payload = {
'prompt': prompt,
'duration': duration
}
response = requests.post(
f'{BASE_URL}/v1/b-roll',
headers=headers,
json=payload
)
return poll_job(response.json()['id'])
broll_url = generate_broll(
prompt="""
Close-up of coffee beans being poured into grinder.
Slow motion, 120fps.
Natural light from window, wooden countertop.
Shallow focus on falling beans.
"""
)
Static Meta Image Ad Library
The repo includes 37 validated prompt templates for static Meta image ads. Two primary generators:
ChatGPT Image 2 (Typography/UI-Heavy)
Best for: Apple Notes lists, editorial layouts, comparison tables, UI mockups, text-heavy designs
def generate_chatgpt_image_ad(template_name, product_details):
"""Generate static ad using ChatGPT Image 2."""
template_path = f'shared/skills/image-ad-prompting/library/{template_name}.md'
with open(template_path, 'r') as f:
template = f.read()
prompt = template.format(**product_details)
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
payload = {
'prompt': prompt,
'model': 'gpt-image-2',
'aspectRatio': '4:5'
}
response = requests.post(
f'{BASE_URL}/v1/chatgpt-image/generate',
headers=headers,
json=payload
)
return poll_job(response.json()['id'])
image_url = generate_chatgpt_image_ad(
template_name='apple-notes-list',
product_details={
'product_name': 'FocusFlow',
'category': 'productivity app',
'benefits': [
'Blocks distractions automatically',
'AI suggests optimal focus times',
'Syncs across all devices'
],
'cta': 'Download free today'
}
)
Nano Banana (Photoreal/Lifestyle)
Best for: Lifestyle product shots, before/after, founder letters with portraits, real-world settings
def generate_nano_banana_ad(template_name, product_details, reference_images=None):
"""Generate static ad using Nano Banana."""
template_path = f'shared/skills/image-ad-prompting/library/{template_name}.md'
with open(template_path, 'r') as f:
template = f.read()
prompt = template.format(**product_details)
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
payload = {
'prompt': prompt,
'model': 'nano-banana-2',
'aspectRatio': '4:5'
}
if reference_images:
ref_images_b64 = []
for img_path in reference_images:
with open(img_path, 'rb') as f:
ref_images_b64.append(base64.b64encode(f.read()).decode('utf-8'))
payload['referenceImages'] = ref_images_b64
response = requests.post(
f'{BASE_URL}/v1/nano-banana/image',
headers=headers,
json=payload
)
return poll_job(response.json()['id'])
Available Templates (37 total)
Key templates in the library:
apple-notes-list โ Simple checklist aesthetic
forbes-editorial โ Magazine hero layout
comparison-table โ Side-by-side feature grid
fake-google-search โ Search results UI mockup
sticky-note-flatlay โ Scattered notes on desk
imessage-screenshot โ Text conversation mockup
chatgpt-conversation โ AI chat interface
weather-forecast-ui โ Weather app parody
dating-app-card โ Swipe-style card layout
billboard-mockup โ Outdoor advertising placement
museum-exhibit โ Art gallery presentation
scratch-off-ticket โ Lottery/game aesthetic
See shared/skills/image-ad-prompting/OVERVIEW.md for full template list and compatibility matrix.
Multi-Step Pipelines
Pixar-Style 3D Animated Ad
Creates an 8-beat story arc with anthropomorphized characters, stitched into a final video with captions.
Workflow:
- Define character sheet (mascot design)
- Generate storyboard stills (ChatGPT Image 2)
- Animate each beat (Seedance 2.0 i2v)
- Stitch segments (ffmpeg)
- Burn captions (HyperFrames)
./shared/skills/pixar-style-ad/pipeline.sh \
--product "EcoBottle" \
--duration 60 \
--output output/pixar-ad.mp4
Python API approach:
def create_pixar_ad(product_name, story_beats):
"""Generate a Pixar-style animated ad."""
character_prompt = f"""
3D Pixar style mascot for {product_name}.
Anthropomorphized product with expressive face.
Big eyes, friendly smile, rounded shapes.
Soft lighting, vibrant colors, clean geometry.
T-pose reference, white background.
"""
character_img = generate_chatgpt_image(character_prompt)
storyboard_frames = []
prev_frame = character_img
for beat in story_beats:
frame_prompt = f"""
{beat['scene_description']}
Character from reference image.
Pixar 3D render style, consistent lighting.
"""
frame_url = generate_chatgpt_image(
prompt=frame_prompt,
reference_images=[prev_frame]
)
storyboard_frames.append(frame_url)
prev_frame = frame_url
video_segments = []
for i, frame in enumerate(storyboard_frames):
video_url = animate_with_seedance_i2v(
start_frame=frame,
duration=story_beats[i]['duration'],
motion_prompt=story_beats[i]['motion']
)
video_segments.append(video_url)
final_video = stitch_videos(video_segments)
return final_video
def animate_with_seedance_i2v(start_frame, duration, motion_prompt):
"""Animate a still frame with Seedance 2.0 image-to-video."""
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
import requests as req
img_data = req.get(start_frame).content
img_base64 = base64.b64encode(img_data).decode('utf-8')
payload = {
'startFrame': img_base64,
'motionPrompt': motion_prompt,
'duration': duration
}
response = requests.post(
f'{BASE_URL}/v1/seedance2/video',
headers=headers,
json=payload
)
return poll_job(response.json()['id'])
pixar_ad = create_pixar_ad(
product_name='EcoBottle',
story_beats=[
{
'scene_description': 'Mascot looking sad at pile of plastic waste',
'duration': 6,
'motion': 'Subtle head turn, eyes downcast'
},
{
'scene_description': 'Mascot has idea, lightbulb appears',
'duration': 4,
'motion': 'Excited jump, arms raised'
},
{
'scene_description': 'Mascot presents EcoBottle to camera',
'duration': 8,
'motion': 'Slow rotation of bottle, proud smile'
}
]
)
AI Influencer Creation (10-Image Character Sheet)
Generates a consistent AI influencer with multiple angles for reuse.
def create_ai_influencer(description):
"""Create a 10-image character sheet for an AI influencer."""
hero_prompt = f"""
Front-facing portrait, iPhone selfie camera.
{description}
Natural lighting, genuine smile.
9:16 aspect ratio, eye-level camera.
Realistic skin texture, no AI smoothing.
"""
hero_url = generate_nano_banana_image(
prompt=hero_prompt,
model='nano-banana'
)
print(f"Hero generated: {hero_url}")
print("Review and approve before generating additional angles...")
input("Press Enter when approved...")
angles = [
('3/4 view, slight smile, looking slightly left', 3),
('Profile view, side lighting', 3),
('Close-up of face, neutral expression', 2),
('Full body shot, standing pose', 1),
('Laughing expression, candid moment', 2),
('Serious expression, professional', 2)
]
character_sheet = [hero_url]
for angle_desc, count in angles:
for _ in range(count):
angle_prompt = f"""
{description}
{angle_desc}
Match character from reference image exactly.
Same lighting style, same person.
"""
img_url = generate_nano_banana_image(
prompt=angle_prompt,
reference_image_path=download_temp(hero_url),
model='nano-banana'
)
character_sheet.append(img_url)
save_character_sheet('sofia', character_sheet)
return character_sheet
influencer = create_ai_influencer(
description="""
Woman, 24 years old, warm smile.
Light freckles, wavy brown hair.
College student aesthetic.
Natural makeup, approachable energy.
"""
)
Caption Burn-In Workflow
Add captions to any finished video using Whisper + HyperFrames.
./shared/skills/caption-video/burn_captions.sh \
--input output/video.mp4 \
--output output/video_captioned.mp4 \
--style "viral"
Python implementation:
import whisper
import subprocess
import json
def burn_captions(video_path, output_path, style='viral'):
"""Add captions to video using Whisper + HyperFrames."""
model = whisper.load_model("medium.en")
result = model.transcribe(video_path, word_timestamps=True)
phrases = group_into_phrases(result['segments'])
caption_json = generate_hyperframes_config(phrases, style)
with open('captions_config.json', 'w') as f:
json.dump(caption_json, f)
subprocess.run([
'npx', 'hyperframes',
'--input', video_path,
'--config', 'captions_config.json',
'--output', output_path
])
return output_path
def group_into_phrases(segments, max_words=4):
"""Group word-level timestamps into reading phrases."""
phrases = []
current_phrase = []
for segment in segments:
for word in segment.get('words', []):
current_phrase.append(word)
if len(current_phrase) >= max_words or word['word'].endswith(('.', '!', '?')):
phrases.append({
'text': ' '.join([w['word'] for w in current_phrase]),
'start': current_phrase[0]['start'],
'end': current_phrase[-1]['end']
})
current_phrase = []
return phrases
def generate_hyperframes_config(phrases, style):
"""Generate HyperFrames caption configuration."""
styles = {
'viral': {
'font': 'Montserrat-ExtraBold',
'fontSize': 72,
'color': '#FFFFFF',
'stroke': '#000000',
'strokeWidth': 6,
'position': 'center'
},
'minimal': {
'font': 'Helvetica-Neue',
'fontSize': 48,
'color': '#FFFFFF',
'stroke': 'none',
'position': 'bottom'
}
}
return {
'captions': phrases,
'style': styles.get(style, styles['viral'])
}
Configuration
API Base URL
Default: https://api.arcads.ai
Override via environment variable:
export ARCADS_API_BASE_URL=https://custom-endpoint.com
Model Selection
SEEDANCE_2 = 'seedance-2'
SORA_2 = 'sora-2'
VEO_3_1 = 'veo-3.1'
KLING_3 = 'kling-3.0'
GROK_VIDEO = 'grok-video'
NANO_BANANA_2 = 'nano-banana-2'
NANO_BANANA_PRO = 'nano-banana'
NANO_BANANA_EDIT = 'nano-banana-edit'
CHATGPT_IMAGE_2 = 'gpt-image-2'
Aspect Ratios
ASPECT_RATIOS = {
'vertical': '9:16',
'square': '1:1',
'meta-image': '4:5',
'landscape': '16:9'
}
Duration Limits
DURATION_LIMITS = {
'seedance-2': (4, 15),
'sora-2': (1, 20),
'veo-3.1': (4, 15),
'kling-3.0': (1, 10),
'grok-video': (1, 10)
}
Common Patterns
Pattern: UGC Workflow (Still โ Video)
def ugc_workflow(influencer_ref, product_ref, script):
"""Complete UGC workflow: still generation โ video animation."""
still_prompt = f"""
iPhone selfie camera, natural bedroom lighting.
{influencer_ref['description']}
Holding product at chest level, genuine smile.
Messy hair, casual tank top.
Background: unmade bed, string lights.
"""
still_url = generate_nano_banana_image(
prompt=still_prompt,
reference_image_path=influencer_ref['hero_path']
)
print(f"Still generated: {still_url}")
input("Review and approve...")
video_url = animate_with_veo(
start_frame_path=download_temp(still_url),
prompt=f"""
Natural head and hand movement.
Maintains eye contact with camera.
Slight smile, authentic energy.
Product stays in frame throughout.
""",
duration=12
)
return video_url
Pattern: Batch Generation
def batch_generate_variations(base_prompt, variations, model='nano-banana-2'):
"""Generate multiple variations in parallel."""
import concurrent.futures
def generate_variation(variation):
full_prompt = f"{base_prompt}\n\nVariation: {variation}"
return generate_nano_banana_image(full_prompt, model=model)
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
urls = list(executor.map(generate_variation, variations))
return urls
thumbnails = batch_generate_variations(
base_prompt="""
YouTube thumbnail, 16:9 aspect ratio.
Man, 30s, excited expression, peace sign.
Product held in other hand.
Bold text overlay: "THIS CHANGED EVERYTHING"
High contrast, vibrant colors.
""",
variations=[
'Blue background, indoor studio lighting',
'Yellow background, warm tone',
'Outdoor natural light, green background',
'Split-screen comparison layout',
'Close-up face, product in foreground',
'Full body shot, product placement emphasized'
]
)
Pattern: Cost Estimation
COST_TABLE = {
'seedance-2': 0.25,
'sora-2': 0.30,
'veo-3.1': 0.20,
'kling-3.0': 0.15,
'nano-banana-2': 0.08,
'nano-banana': 0.12,
'gpt-image-2': 0.10
}
def estimate_cost(model, duration=None, image_count=None):
"""Estimate generation cost."""
unit_cost = COST_TABLE.get(model, 0)
if duration:
return unit_cost * duration
elif image_count:
return unit_cost * image_count
return unit_cost
cost = estimate_cost('seedance-2', duration=12)
print(f"Estimated cost: ${cost:.2f}")
user_input = input(f"Proceed with generation? (${cost:.2f}) [y/N]: ")