一键导入
arcads-claude-code
Create AI marketing videos and images using Arcads API — Seedance, Sora, Veo, Kling, Nano Banana, ChatGPT Image, and multi-step ad pipelines
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Create AI marketing videos and images using Arcads API — Seedance, Sora, Veo, Kling, Nano Banana, ChatGPT Image, and multi-step ad pipelines
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Generate AI marketing videos and static image ads using the Arcads API with skills for Seedance 2.0, Sora 2, Veo 3.1, Kling 3.0, Nano Banana, and 37 Meta ad templates
Create AI marketing videos and images using Arcads API with Seedance 2.0, Sora 2, Veo 3.1, Kling 3.0, Nano Banana, and 37 static Meta ad templates
Generate AI marketing videos and images using Arcads creative stack (Seedance 2.0, Sora 2, Veo 3.1, Kling, Nano Banana, ChatGPT Image) from Claude Code or Cursor
Generate AI marketing videos and static image ads using Arcads external API with Seedance 2.0, Sora 2, Veo 3.1, Kling, Nano Banana, and 37-template Meta image library
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
Deploy and manage the Seagull 2.0 custom personality configuration for Claude Code
| name | arcads-claude-code |
| description | Create AI marketing videos and images using Arcads API — Seedance, Sora, Veo, Kling, Nano Banana, ChatGPT Image, and multi-step ad pipelines |
| triggers | ["generate an AI video ad","create a UGC video with Seedance","make a Nano Banana product image","build a Pixar-style animated ad","create static Meta image ads","animate this still with Veo","generate YouTube thumbnails","make a claymation ad campaign"] |
Skill by ara.so — Claude Code Skills collection.
arcads-claude-code is a comprehensive skill pack for generating AI marketing videos and images through the Arcads API. It supports the full Arcads creative stack:
Built for AI agents in Claude Code and Cursor to handle API calls, polling, prompt engineering, file organization, and cost confirmation.
git clone https://github.com/krusemediallc/arcads-claude-code.git
cd arcads-claude-code
./scripts/setup.sh
The setup script will:
.env (never committed)MASTER_CONTEXT.md workspace fileBasic video/image generation requires only Python 3.10+. Multi-step pipelines need:
# macOS
brew install ffmpeg jq node
# Python packages for specific workflows
pip install openai-whisper # Caption transcription
pip install -r shared/skills/meta-ad-builder/scripts/requirements.txt # Meta publishing
Linux:
apt install ffmpeg jq nodejs python3 python3-pip
.env file structure:
ARCADS_API_KEY=your_api_key_here
Never hardcode keys — always use os.environ['ARCADS_API_KEY'].
All requests require Authorization: Bearer $ARCADS_API_KEY header.
import os
import requests
BASE_URL = "https://api.arcads.ai"
headers = {
"Authorization": f"Bearer {os.environ['ARCADS_API_KEY']}",
"Content-Type": "application/json"
}
Most video/image generation is asynchronous:
jobId/v1/job/{jobId} until status: "completed"outputUrl or imageUrlimport time
def poll_job(job_id, timeout=600):
"""Poll Arcads job until completion."""
start = time.time()
while time.time() - start < timeout:
resp = requests.get(
f"{BASE_URL}/v1/job/{job_id}",
headers=headers
)
data = resp.json()
if data['status'] == 'completed':
return data
elif data['status'] == 'failed':
raise Exception(f"Job failed: {data.get('error')}")
time.sleep(5)
raise TimeoutError(f"Job {job_id} timeout after {timeout}s")
Key features: 4–15s clips, native audio, image-to-video, video-to-video, reference images, multiple shot styles.
def generate_seedance_ugc(prompt, duration=12):
"""Generate UGC-style Seedance video."""
payload = {
"prompt": prompt,
"duration": duration,
"model": "seedance-2.0",
"aspectRatio": "9:16",
"dialogue": "I stopped buying [competitor] after I found this"
}
resp = requests.post(
f"{BASE_URL}/v1/seedance/generate",
headers=headers,
json=payload
)
job_id = resp.json()['jobId']
result = poll_job(job_id)
return result['outputUrl']
# Usage
video_url = generate_seedance_ugc(
"Woman in kitchen, natural lighting, holding product bottle, iPhone selfie aesthetic"
)
import base64
def seedance_image_to_video(image_path, prompt, duration=8):
"""Animate static image with Seedance."""
with open(image_path, 'rb') as f:
image_b64 = base64.b64encode(f.read()).decode()
payload = {
"prompt": prompt,
"duration": duration,
"startFrame": image_b64,
"aspectRatio": "1:1"
}
resp = requests.post(
f"{BASE_URL}/v1/seedance/generate",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
Prompt formulas (see skills/arcads-external-api/prompting/prompt-library/):
seedance-2-ugc.md — 9-layer UGC selfie formulaseedance-2-premium-reveal.md — Dark void product revealseedance-2-product-hero.md — Elemental effects (water, mist)seedance-2-studio-lookbook.md — Editorial multi-shotseedance-2-feature-walkthrough.md — Fast-paced demoText-to-video, up to 20s.
def generate_sora(prompt, duration=16, reference_image=None):
"""Generate Sora 2 video."""
payload = {
"prompt": prompt,
"duration": duration,
"aspectRatio": "16:9"
}
if reference_image:
with open(reference_image, 'rb') as f:
payload['referenceImage'] = base64.b64encode(f.read()).decode()
resp = requests.post(
f"{BASE_URL}/v1/sora2/generate",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
Sora 2 remix (restyle existing video):
def sora_remix(video_path, new_prompt):
"""Remix existing video with new style."""
with open(video_path, 'rb') as f:
video_b64 = base64.b64encode(f.read()).decode()
payload = {
"videoAsBase64": video_b64,
"prompt": new_prompt
}
resp = requests.post(
f"{BASE_URL}/v1/sora2/remix/video",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
Primary use case: Animate static UGC stills with natural motion + dialogue.
def veo_animate_still(image_path, prompt, dialogue, duration=8):
"""Animate static image with Veo 3.1."""
with open(image_path, 'rb') as f:
start_frame = base64.b64encode(f.read()).decode()
payload = {
"prompt": prompt,
"startFrame": start_frame,
"dialogue": dialogue,
"duration": duration,
"aspectRatio": "9:16"
}
resp = requests.post(
f"{BASE_URL}/v1/veo/generate",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
MANDATORY dialogue gate: Agent must confirm dialogue separately before generating.
def generate_kling_broll(scene_description, duration=5):
"""Generate b-roll clip with Kling 3.0."""
payload = {
"prompt": scene_description,
"duration": duration,
"type": "b-roll"
}
resp = requests.post(
f"{BASE_URL}/v1/b-roll",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
def generate_kling_scene(environment, duration=8):
"""Generate scene with Kling 3.0."""
payload = {
"prompt": environment,
"duration": duration
}
resp = requests.post(
f"{BASE_URL}/v1/scene",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
def generate_grok(prompt, duration=10):
"""Generate Grok video."""
payload = {
"model": "grok-video",
"prompt": prompt,
"duration": duration
}
resp = requests.post(
f"{BASE_URL}/v2/videos/generate",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
def generate_omnihuman(avatar_description, script):
"""Generate talking avatar."""
payload = {
"avatar": avatar_description,
"script": script
}
resp = requests.post(
f"{BASE_URL}/v1/omnihuman",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
def generate_audio_driven(video_path, audio_path):
"""Lip-sync video to audio file."""
with open(video_path, 'rb') as f:
video_b64 = base64.b64encode(f.read()).decode()
with open(audio_path, 'rb') as f:
audio_b64 = base64.b64encode(f.read()).decode()
payload = {
"videoAsBase64": video_b64,
"audioAsBase64": audio_b64
}
resp = requests.post(
f"{BASE_URL}/v1/audio-driven",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
Models: nano-banana-2 (default), nano-banana (Pro — tighter identity lock), nano-banana-edit (inpainting).
def generate_nano_banana(prompt, model="nano-banana-2", aspect_ratio="1:1"):
"""Generate Nano Banana image."""
payload = {
"prompt": prompt,
"model": model,
"aspectRatio": aspect_ratio
}
resp = requests.post(
f"{BASE_URL}/v1/nano-banana/generate",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
def generate_with_references(prompt, reference_paths, model="nano-banana-2"):
"""Generate with multiple reference images for character lock."""
references = []
for path in reference_paths:
with open(path, 'rb') as f:
references.append(base64.b64encode(f.read()).decode())
payload = {
"prompt": prompt,
"model": model,
"referenceImages": references,
"aspectRatio": "9:16"
}
resp = requests.post(
f"{BASE_URL}/v1/nano-banana/generate",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
def create_influencer_sheet(description, output_dir="references/influencers/"):
"""Generate 10-image character sheet."""
import os
os.makedirs(output_dir, exist_ok=True)
# Step 1: Hero portrait
hero_prompt = f"{description}, front-facing portrait, neutral expression, soft natural lighting"
hero_result = generate_nano_banana(hero_prompt, aspect_ratio="1:1")
hero_path = f"{output_dir}hero.png"
download_image(hero_result['imageUrl'], hero_path)
# Step 2: 9 additional angles
angles = [
"3/4 view left", "3/4 view right", "profile left", "profile right",
"close-up face", "full body", "laughing expression", "serious expression",
"over-the-shoulder"
]
for i, angle in enumerate(angles, 1):
prompt = f"{description}, {angle}, same person, consistent features"
result = generate_with_references(prompt, [hero_path])
download_image(result['imageUrl'], f"{output_dir}angle_{i:02d}.png")
return output_dir
def download_image(url, path):
"""Helper to download image."""
resp = requests.get(url)
with open(path, 'wb') as f:
f.write(resp.content)
def generate_ugc_selfie(influencer_ref, product_ref, setting):
"""Generate UGC selfie with influencer + product."""
refs = [influencer_ref, product_ref]
# Add aesthetic references
ugc_aesthetic_dir = "references/aesthetics/ugc-selfie/"
for ref_file in os.listdir(ugc_aesthetic_dir):
refs.append(f"{ugc_aesthetic_dir}{ref_file}")
prompt = f"""
iPhone selfie, {setting}, natural lighting, slightly grainy,
person holding product visible in frame, authentic candid moment,
skin texture visible, minor lens distortion, informal composition
"""
return generate_with_references(prompt, refs, model="nano-banana")
def generate_chatgpt_image(prompt, aspect_ratio="1:1"):
"""Generate ChatGPT Image 2."""
payload = {
"prompt": prompt,
"aspectRatio": aspect_ratio
}
resp = requests.post(
f"{BASE_URL}/v1/chatgpt-image/generate",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
chatgpt-image-ad (Apple Notes, fake Slack, comparison tables, ChatGPT conversation)nano-banana-image-ad (founder letter with portrait, product flat-lay, editorial hero)image-ad-clonedef generate_apple_notes_ad(product_name, benefits_list):
"""Apple Notes template — 8-12 bullet points."""
prompt = f"""
iOS Apple Notes app screenshot style:
- Title: "{product_name}" in San Francisco font
- Yellow header background (#FFD60A)
- Clean white note background
- Numbered list (emoji + text):
{chr(10).join(f" {i+1}. {benefit}" for i, benefit in enumerate(benefits_list))}
- Timestamp "Just now" bottom right
- Authentic iOS UI chrome (back button, share icon)
- Screenshot aspect ratio
"""
return generate_chatgpt_image(prompt, aspect_ratio="9:16")
def generate_forbes_editorial_ad(product_ref, headline, subhead):
"""Forbes editorial hero template."""
with open(product_ref, 'rb') as f:
ref_b64 = base64.b64encode(f.read()).decode()
prompt = f"""
Forbes magazine editorial layout:
- Hero product image (centered, premium lighting)
- Forbes logo top left
- Headline: "{headline}" (Freight Big Pro, 48pt)
- Subheadline: "{subhead}" (Untitled Sans, 18pt)
- Clean white background, minimal typography, luxury aesthetic
- Article byline and date bottom
"""
payload = {
"prompt": prompt,
"referenceImages": [ref_b64],
"aspectRatio": "4:5"
}
resp = requests.post(
f"{BASE_URL}/v1/nano-banana/generate",
headers=headers,
json=payload
)
return poll_job(resp.json()['jobId'])
def clone_ad_as_template(source_image_path, backend="chatgpt-image"):
"""Reverse-engineer existing ad into library template."""
# Phase 1: Visual analysis
with open(source_image_path, 'rb') as f:
image_b64 = base64.b64encode(f.read()).decode()
# Use vision API to extract structure
analysis = analyze_ad_structure(image_b64)
# Phase 2: Template construction
template_name = input("Template name (kebab-case): ")
template_dir = f"shared/skills/image-ad-prompting/templates/{template_name}/"
os.makedirs(template_dir, exist_ok=True)
# Write template files
with open(f"{template_dir}prompt.md", 'w') as f:
f.write(analysis['prompt_formula'])
with open(f"{template_dir}metadata.json", 'w') as f:
json.dump({
"backend": backend,
"aspectRatios": analysis['supported_ratios'],
"category": analysis['category']
}, f, indent=2)
# Phase 3: Test generation
test_result = generate_from_template(template_name, backend)
return template_dir
Read shared/skills/image-ad-prompting/OVERVIEW.md first for full workflow and aspect-ratio compatibility matrix.
Requirements: ffmpeg, jq, npx hyperframes, whisper
# Orchestrate from bash
./shared/skills/pixar-style-ad/scripts/generate.sh
Python workflow:
def generate_pixar_ad(product_name, story_beats):
"""
Generate Pixar-style animated ad.
Args:
product_name: Product name
story_beats: List of 8 story beat descriptions
"""
output_dir = f"output/pixar-ads/{product_name.lower().replace(' ', '-')}/"
os.makedirs(output_dir, exist_ok=True)
# Step 1: Cast sheet (mascot design)
mascot_prompt = f"""
Pixar-style 3D character sheet: {product_name} mascot,
anthropomorphized, large expressive eyes, rounded friendly shapes,
soft studio lighting, white backdrop, turnaround views
"""
cast_result = generate_chatgpt_image(mascot_prompt, "1:1")
cast_path = f"{output_dir}cast_sheet.png"
download_image(cast_result['imageUrl'], cast_path)
# Step 2: Storyboard stills (8 beats, sequential reference)
stills = []
prev_frame = None
for i, beat in enumerate(story_beats):
refs = [cast_path]
if prev_frame:
refs.append(prev_frame)
# Max 5 referenceImages
refs = refs[:5]
prompt = f"Pixar 3D render: {beat}, same character from cast sheet, consistent style"
with open(cast_path, 'rb') as f:
cast_b64 = base64.b64encode(f.read()).decode()
ref_data = [cast_b64]
if prev_frame:
with open(prev_frame, 'rb') as f:
ref_data.append(base64.b64encode(f.read()).decode())
payload = {
"prompt": prompt,
"referenceImages": ref_data,
"aspectRatio": "16:9"
}
resp = requests.post(
f"{BASE_URL}/v1/chatgpt-image/generate",
headers=headers,
json=payload
)
result = poll_job(resp.json()['jobId'])
still_path = f"{output_dir}beat_{i+1:02d}.png"
download_image(result['imageUrl'], still_path)
stills.append(still_path)
prev_frame = still_path
# Step 3: Image-to-video per beat (Seedance 2.0)
clips = []
for i, still_path in enumerate(stills):
video_result = seedance_image_to_video(
still_path,
prompt=f"Subtle animation, character movement, Pixar style",
duration=3
)
clip_path = f"{output_dir}clip_{i+1:02d}.mp4"
download_video(video_result['outputUrl'], clip_path)
clips.append(clip_path)
# Step 4: Stitch with ffmpeg
final_path = f"{output_dir}final_stitched.mp4"
stitch_videos(clips, final_path)
# Step 5: Burn captions (optional)
captioned_path = f"{output_dir}final_captioned.mp4"
burn_captions(final_path, captioned_path)
return captioned_path
def stitch_videos(clip_paths, output_path):
"""Stitch multiple clips with ffmpeg."""
import subprocess
concat_file = "/tmp/concat_list.txt"
with open(concat_file, 'w') as f:
for path in clip_paths:
f.write(f"file '{os.path.abspath(path)}'\n")
subprocess.run([
"ffmpeg", "-f", "concat", "-safe", "0",
"-i", concat_file, "-c", "copy", output_path
], check=True)
def burn_captions(video_path, output_path):
"""Transcribe and burn captions with HyperFrames."""
import subprocess
# Transcribe with Whisper
import whisper
model = whisper.load_model("medium.en")
result = model.transcribe(video_path)
# Write SRT
srt_path = "/tmp/captions.srt"
write_srt(result['segments'], srt_path)
# Burn with HyperFrames
subprocess.run([
"npx", "hyperframes", "burn",
"--input", video_path,
"--srt", srt_path,
"--output", output_path,
"--style", "bold",
"--color", "yellow"
], check=True)
def write_srt(segments, output_path):
"""Convert Whisper segments to SRT format."""
with open(output_path, 'w') as f:
for i, seg in enumerate(segments, 1):
start = format_timestamp(seg['start'])
end = format_timestamp(seg['end'])
text = seg['text'].strip()
f.write(f"{i}\n{start} --> {end}\n{text}\n\n")
def format_timestamp(seconds):
"""Format seconds to SRT timestamp."""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
millis = int((seconds % 1) * 1000)
return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"
Same backbone as Pixar with clay textures and narrator-driven script.
def generate_claymation_ad(product_name, narrator_script):
"""Generate claymation ad (60-115s)."""
# 8-beat story arc from narrator script
beats = split_into_beats(narrator_script, num_beats=8)
# Cast sheet: plasticine characters
cast_prompt = f"""
Claymation character sheet: {product_name} mascot,
sculpted plasticine texture, visible fingerprints,
simple shapes, Aardman style, white backdrop
"""
# ... similar workflow to Pixar
# Stitch with optional stop-motion judder
subprocess.run([
"ffmpeg", "-i", "stitched.mp4",
"-vf", "fps=12,fps=24", # Stop-motion effect
"final_claymation.mp4"
])
def generate_youtube_thumbnails(face_refs, product_ref, formula="peace-sign"):
"""
Generate YouTube thumbnail batch.
Formulas: peace-sign, comparison, terminal, reaction, before-after
"""
formulas = {
"peace-sign": "Person doing peace sign, product visible, bold text overlay",
"comparison": "Split screen: Real vs AI, contrasting colors, VS text",
"terminal": "Code terminal aesthetic, matrix green, tech vibes",
"reaction": "Shocked expression, mouth open, surprised eyes, product reveal",
"before-after": "Vertical split: before (dull) | after (vibrant)"
}
prompt = f"""
YouTube thumbnail, 16:9 aspect ratio:
- {formulas[formula]}
- High contrast, bold colors (red/yellow/green)
- Large readable text (Arial Black, 72pt+)
- Person's face takes 40% of frame (likeness lock from references)
- Product visible in hand or foreground
- Slight lens distortion (wide-angle effect)
- Vibrant saturation boost
"""
# Batch generate 6 variations
refs = face_refs + [product_ref]
results = []
for i in range(6):
result = generate_with_references(
f"{prompt}\nVariation {i+1}: minor composition shift",
refs,
model="nano-banana"
)
results.append(result)
return results
Your personal workspace file for campaign state:
# Current Campaign: [Product Name]
## Active AI Influencers
- **Sofia** — 22, college student, freckles, golden-hour kitchen
- References: `references/influencers/sofia/`
- Used in: UGC batch 2024-01-15
## Product Assets
- Hero shot: `assets/products/bottle_hero.png`
- Lifestyle: `assets/products/in_use_kitchen.png`
## Active Prompts
- Seedance UGC: [link to prompt-library/seedance-2-ugc.md]
- Static ad: Apple Notes template
## Cost Tracking
- Seedance 2.0: $0.50/video (12s)
- Nano Banana 2: $0.10/image
- Sora 2: $1.20/video (16s)
## Notes
- Veo 3.1 requires explicit dialogue confirmation
- Nano Banana Pro locks identity better for influencer sheets
skills/arcads-external-api/prompting/prompt-library/
├── seedance-2-ugc.md # 9-layer UGC formula
├── seedance-2-premium-reveal.md # Dark void product
├── seedance-2-product-hero.md # Elemental effects
├── seedance-2-studio-lookbook.md # Editorial multi-shot
└── seedance-2-feature-walkthrough.md # Demo cuts
shared/skills/image-ad-prompting/templates/
├── apple-notes/
│ ├── prompt.md
│ └── metadata.json
├── forbes-editorial/
├── comparison-table/
├── fake-slack-thread/
├── chatgpt-conversation/
├── iphone-message/
└── ... (37 total)
def maintain_character_consistency(influencer_name, new_scene):
"""Use influencer reference library for consistent character."""
ref_dir = f"references/influencers/{influencer_name}/"
# Load all reference angles
refs = [f"{ref_dir}{f}" for f in os.listdir(ref_dir) if f.endswith('.png')]
# Use hero + 4 most relevant angles (max 5 refs)
primary_refs = [f"{ref_dir}hero.png"] + refs[1:5]
result = generate_with_references(
f"Same person from references, {new_scene}, consistent features and style",
primary_refs,
model="nano-banana" # Pro model for tighter identity lock
)
return result
def estimate_cost(job_type, count):
"""Estimate cost before batch generation."""
pricing = {
"seedance-2.0": {"12s": 0.50, "8s": 0.35, "15s": 0.65},
"sora-2": {"16s": 1.20, "20s": 1.50},
"veo-3.1": {"8s": 0.80},
"nano-banana-2": 0.10,
"nano-banana": 0.15, # Pro
"chatgpt-image-2": 0.08
}
unit_cost = pricing.get