- 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"]
# arcads-claude-code
> Skill by [ara.so](https://ara.so) — Claude Code Skills collection.
## What it does
`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:
- **Video models**: Seedance 2.0, Sora 2, Veo 3.1, Kling 3.0, Grok Video, OmniHuman, Audio-driven
- **Image models**: Nano Banana 2/Pro/Edit, ChatGPT Image 2
- **Static ad library**: 37 validated Meta image-ad templates
- **Multi-step pipelines**: Pixar-style animated ads, claymation ads, YouTube thumbnails, caption workflows
Built for AI agents in Claude Code and Cursor to handle API calls, polling, prompt engineering, file organization, and cost confirmation.
## Installation
### 1. Clone and setup
```bash
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](https://app.arcads.ai/settings/api))
- Save it to `.env` (never committed)
- Verify API connection
- Create `MASTER_CONTEXT.md` workspace file
### 2. Install dependencies (optional, based on workflows)
Basic video/image generation requires only **Python 3.10+**. Multi-step pipelines need:
```bash
# 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:
```bash
apt install ffmpeg jq nodejs python3 python3-pip
```
### 3. Environment variables
`.env` file structure:
```bash
ARCADS_API_KEY=your_api_key_here
```
Never hardcode keys — always use `os.environ['ARCADS_API_KEY']`.
## Core API patterns
### Authentication
All requests require `Authorization: Bearer $ARCADS_API_KEY` header.
```python
import os
import requests
BASE_URL = "https://api.arcads.ai"
headers = {
"Authorization": f"Bearer {os.environ['ARCADS_API_KEY']}",
"Content-Type": "application/json"
}
```
### Polling workflow
Most video/image generation is asynchronous:
1. POST to generate endpoint → receive `jobId`
2. Poll GET `/v1/job/{jobId}` until `status: "completed"`
3. Extract `outputUrl` or `imageUrl`
```python
import 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")
```
## Video generation
### Seedance 2.0 (flagship model)
**Key features**: 4–15s clips, native audio, image-to-video, video-to-video, reference images, multiple shot styles.
#### Text-to-video with dialogue
```python
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"
)
```
#### Image-to-video (product reveal)
```python
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 formula
- `seedance-2-premium-reveal.md` — Dark void product reveal
- `seedance-2-product-hero.md` — Elemental effects (water, mist)
- `seedance-2-studio-lookbook.md` — Editorial multi-shot
- `seedance-2-feature-walkthrough.md` — Fast-paced demo
### Sora 2
**Text-to-video, up to 20s.**
```python
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):
```python
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'])
```
### Veo 3.1 (start-frame animation)
**Primary use case**: Animate static UGC stills with natural motion + dialogue.
```python
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.
### Kling 3.0 (b-roll / scene)
```python
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'])
```
### Grok Video
```python
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'])
```
### OmniHuman / Audio-driven
```python
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'])
```
## Image generation
### Nano Banana (photoreal / lifestyle)
**Models**: `nano-banana-2` (default), `nano-banana` (Pro — tighter identity lock), `nano-banana-edit` (inpainting).
#### Basic generation
```python
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'])
```
#### With reference images (character consistency)
```python
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'])
```
#### Create AI influencer (10-image character sheet)
```python
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 = [
عرض على GitHub