> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apiyi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Seedance 2.0 동영상 에이전트 스킬

> 세 가지 Seedance 2.0 모델(mini / fast / standard)을 하나의 바로 사용 가능한 에이전트 스킬로 묶습니다 — Codex, OpenClaw, Claude Code 또는 다른 코딩 에이전트에 그대로 넣고 한 문장만으로 텍스트-투-비디오, 이미지-투-비디오, 참조 이미지 비디오를 생성할 수 있으며; 스크립트가 비동기 작업을 폴링하고 완료된 클립을 자동으로 다운로드합니다.

<Note>
  이 페이지는 **바로 사용할 수 있는 Agent Skill**을 제공합니다. 의존성 없는 스크립트 하나로 Seedance 2.0의 세 가지 모델(`mini` / `fast` / 표준)을 모두 지원하며, `--model`로 전환합니다. 사용 중인 어떤 코딩 에이전트에든 넣으면 한 문장만으로 동영상을 생성하며 — 전체는 파일 두 개뿐입니다. 또한 이 사이트의 **첫 번째 동영상 모델 스킬**이기도 합니다: 이미지와 달리 동영상 생성은 비동기 작업이며, 스크립트는 이미 제출 → 폴링 → 다운로드 전체 흐름을 래핑합니다.
</Note>

## 스킬이 하는 일

하나의 결합된 스킬입니다. 스크립트는 **어떤 이미지를 전달하는지와 그 역할**에 따라 생성 모드를 선택합니다.

<CardGroup cols={3}>
  <Card title="텍스트에서 동영상" icon="clapperboard">
    프롬프트만 전달하면 → 기본적으로 오디오가 동기화된 완전히 새로운 동영상이 생성됩니다(대사, 음향 효과, 앰비언스).
  </Card>

  <Card title="이미지에서 동영상" icon="image-play">
    첫 프레임 이미지를 전달하면 정지 이미지를 애니메이션으로 만들 수 있으며, 마지막 프레임 이미지를 추가하면 첫 프레임에서 마지막 프레임까지 자연스럽게 전환할 수 있습니다.
  </Card>

  <Card title="레퍼런스에서 동영상" icon="layers">
    최대 9장의 레퍼런스 이미지를 전달하면 → 캐릭터, 오브젝트, 스타일을 유지하는 새 영상이 생성됩니다.
  </Card>
</CardGroup>

## 어떤 모델을 선택해야 하나요

세 모델은 **호출 방식이 정확히 같습니다**. 다만 해상도 상한, 속도, 가격이 다릅니다. 스크립트가 `--model`별 차이를 처리합니다:

| 모델 (`--model`) | 모델 ID                             | 최대 해상도    | 속도 (720p/5s, 측정값)    | 720p/5s 정가 (0.18x) | 할인 그룹 (2026-09-07까지)           | 가장 적합한 용도                   |
| -------------- | --------------------------------- | --------- | -------------------- | ------------------ | ------------------------------ | --------------------------- |
| `mini` (기본값)   | `doubao-seedance-2-0-mini-260615` | 720p      | **가장 빠름, 약 87–170초** | \$0.4508           | `SD2Mini` 0.10x → **\$0.2504** | 고빈도 에이전트 사용, 대량 처리, 빠른 미리보기 |
| `fast`         | `doubao-seedance-2-0-fast-260128` | 720p      | 약 100–290초           | \$0.7253           | `SD2Fast` 0.15x → **\$0.6044** | 품질/비용의 중간 지점                |
| `std`          | `doubao-seedance-2-0-260128`      | **1080p** | 약 100–290초           | \$0.9074           | 없음 (`SeeDance2` 0.18x)         | 1080p, 최고 품질                |

<Tip>
  일반적인 기준으로는 **일상적인 사용과 에이전트 시나리오에서는 기본 `mini`를 유지**하고, **1080p나 최고 품질이 필요하면** → `--model std`를 사용하면 됩니다. 모든 화면비는 해상도 단계 내에서 동일한 비용이 적용되며, 재생 시간은 초 단위로 선형 과금되고, 프레임 레이트는 24fps로 고정됩니다. 할인 그룹 `SD2Mini` / `SD2Fast`는 \*\*2026년 9월 7일 23:59 (UTC+8)\*\*까지 운영되며, 그 이후에도 그룹은 계속 온라인 상태로 유지되고 요율 배수는 0.18x로 돌아갑니다. 자세한 내용은 [개요 페이지의 그룹 노트](/ko/api-capabilities/seedance2/overview)를 참조하십시오.
</Tip>

## 어떤 에이전트가 사용할 수 있습니까

<Info>
  스킬은 본질적으로 **하나의 폴더**입니다: 에이전트가 읽을 노트(`SKILL.md`)와 작업을 수행하는 스크립트로 이루어집니다. 따라서 **로컬 파일을 읽고 셸 명령을 실행할 수 있는 코딩 에이전트라면 무엇이든 사용할 수 있습니다** — **Codex, OpenClaw, hermes-agent, Claude Code** 등입니다.

  필요한 것은 단 하나입니다. 에이전트를 실행하는 머신(사용자의 노트북이나 서버)에 **Python 3**와 **인터넷 연결**이 있어야 합니다(스크립트가 `api.apiyi.com`를 직접 호출합니다). 이 스크립트는 Python 표준 라이브러리만 사용하므로 **`pip install`할 것은 아무것도 없습니다**.
</Info>

## 3단계로 설정하기

### ① 폴더를 만들고 파일을 붙여 넣습니다

스킬 폴더를 만들고 아래의 두 파일을 넣습니다(전체 내용은 다음 두 섹션에 있습니다):

```
seedance2/
├── SKILL.md
├── scripts/
│   └── seedance_video.py
└── .env          # created in step ②, holds your key
```

### ② 그 옆에 키를 넣습니다

`seedance2/.env`에 **APIYI API 키**를 입력합니다(`api.apiyi.com` 콘솔에서 하나 생성하십시오. **토큰에는 반드시 `SeeDance2` 그룹이 활성화되어 있어야 합니다** — 또는 할인된 `SD2Mini` / `SD2Fast` — 종량제 과금 기준):

```bash theme={null}
APIYI_API_KEY=sk-your-api-key
```

스크립트는 이 `.env`에서 키를 자동으로 읽습니다 — **추가 설정이나 환경 변수는 필요하지 않습니다**.

<Warning>
  `.env`에는 비밀 키가 들어 있습니다. 스킬이 프로젝트 저장소 안에서 공유된다면, **`.env`를 `.gitignore`에 추가하고 절대 커밋하지 마십시오**.
</Warning>

### ③ 에이전트에게 전달합니다

* **스킬 자동 검색이 가능한 에이전트**(예: Claude Code): 전체 `seedance2/` 폴더를 해당 스킬 디렉터리에 넣습니다 — 개인 `~/.claude/skills/` 또는 프로젝트 수준 `.claude/skills/`(저장소와 공유됨).
* **다른 에이전트**: 각자의 스킬/플러그인 규칙을 따르십시오. 아니면 가장 간단하게는 — **에이전트에게 “이 폴더의 SKILL.md를 읽고 따르라”고 지시하십시오**.

이것으로 끝입니다 — 예시는 [사용 방법](#how-to-use-it)을 참고하십시오.

## SKILL.md

아래의 전체 내용을 담은 `seedance2/SKILL.md`를 생성합니다(`description`에는 “무엇을 하는지 + 언제 사용해야 하는지”가 적혀 있으며, 에이전트가 이를 자동으로 트리거하는 데 사용합니다):

````markdown theme={null}
---
name: seedance2
description: Generate videos via APIYI's Seedance 2.0 (doubao-seedance-2-0 series) models — text-to-video, image-to-video (first/last frame), and reference-image-to-video, with synced audio by default. Use this when the user asks to create, generate, or animate a video clip.
allowed-tools: Bash(python3 *)
---

# Seedance 2.0 Video Skill

Generate videos through the APIYI platform using Seedance 2.0 (`doubao-seedance-2-0` series). Defaults to the fastest and cheapest mini model, with synced audio built in.

## Key configuration

The script auto-reads `APIYI_API_KEY` from a `.env` file in the skill folder (an environment variable of the same name also works).
If it reports "API key not found", ask the user to add a line `APIYI_API_KEY=sk-xxx` to `.env`;
the token must have the `SeeDance2` (or discounted `SD2Mini` / `SD2Fast`) group enabled with pay-as-you-go billing.

## Usage (important: generation takes 2-5 minutes)

Video generation is an **async task**: the script submits the task and polls until done, so one call usually takes 2-5 minutes in total.
**Run it with a long command timeout (600+ seconds) or in the background** — do not use a default 2-minute timeout, or the script gets killed before the video is ready.

```bash
# 텍스트를 동영상으로 생성(기본 mini / 720p / 5 s / 오디오 포함)
python3 ${CLAUDE_SKILL_DIR}/scripts/seedance_video.py "초원에서 나비를 쫓는 주황색 고양이, 느린 트래킹 샷, 자연광" -o cat.mp4

# 이미지를 동영상으로 생성(첫 프레임 — 정지 이미지를 애니메이션화)
python3 ${CLAUDE_SKILL_DIR}/scripts/seedance_video.py "카메라가 천천히 앞으로 이동하고, 빛이 흐릅니다" -i photo.jpg -o animated.mp4

# 첫 프레임에서 마지막 프레임으로의 전환
python3 ${CLAUDE_SKILL_DIR}/scripts/seedance_video.py "첫 프레임에서 마지막 프레임으로 부드럽게 전환" -i first.png --last-frame last.png -o morph.mp4

# 참조 이미지를 동영상으로 생성(참조한 캐릭터/스타일을 유지, 최대 9장)
python3 ${CLAUDE_SKILL_DIR}/scripts/seedance_video.py "참조 이미지의 캐릭터가 눈밭을 가로질러 달립니다" --ref-image role.png -o run.mp4

# 고화질: 표준 모델 + 1080p + 10 s
python3 ${CLAUDE_SKILL_DIR}/scripts/seedance_video.py "가을 계곡 위를 지나는 드론 샷, 시네마틱" --model std --resolution 1080p --duration 10 -o valley.mp4
```

Parameters:

- 1st positional argument: the prompt (required). Describing scene + camera motion + mood works best.
- `--model`: `mini` (default, fastest and cheapest) / `fast` / `std` (the only one supporting 1080p).
- `--resolution`: `480p` / `720p` (default) / `1080p` (std only).
- `--ratio`: `adaptive` (default) / `16:9` / `4:3` / `1:1` / `3:4` / `9:16` / `21:9`; all ratios cost the same within a tier.
- `--duration`: integer seconds 4-15, default 5; `-1` lets the model decide. Longer costs more.
- `--no-audio`: disable synced audio (on by default).
- `-i / --image`: first-frame image (local path / URL / `asset://` asset ID); passing it switches to image-to-video. Combine with `--last-frame` for first/last-frame mode.
- `--ref-image`: reference image, repeatable up to 9, mutually exclusive with `-i`.
- `-o / --out`: output file name, default `output.mp4`.

## Clip count and cost (important)

- **One call produces exactly 1 video** — there is no batch flag. If the user wants several, run sequential calls and warn about cost first.
- Video bills by tokens and is far pricier than images (about \$0.45-0.91 list per 720p/5s clip; longer or sharper costs more).
  Unless the user explicitly asks, **keep the defaults mini / 720p / 5s** — never bump duration, resolution, or switch to std on your own.

## Output location (important)

- With a **bare file name** for `-o` (like `cat.mp4`), the video goes to the **`seedance-output/` folder in the project root**.
- With a **path containing directories**, it saves to that path (relative paths resolve against the current working directory).
- Never write videos to `/tmp`, scratchpads, or other temp folders — the user won't find them.
- The returned video URL expires in 24 hours; the script already downloads the file locally — the local file is the deliverable.

## When done

The script prints the saved path, file size, elapsed time, and billed tokens — report the path back to the user verbatim.
If it reports a failure (including content-moderation rejections), relay the error as-is and do not retry the same prompt.
On "no available channel for this model", ask the user to check the token's group includes `SeeDance2` / `SD2Mini` / `SD2Fast`.
````

<Tip>
  `name`는 소문자와 하이픈만 사용해야 합니다. 슬래시 명령을 사용하는 에이전트에서는 폴더 이름이 명령입니다 — `seedance2`가 `/seedance2`를 제공합니다. `${CLAUDE_SKILL_DIR}`는 Claude Code의 skill-directory 변수입니다. 다른 에이전트에서는 스크립트의 실제 경로를 사용하면 됩니다.
</Tip>

## scripts/seedance\_video.py

`seedance2/scripts/seedance_video.py`을 만드세요 — 순수 Python 표준 라이브러리만 사용하며, 이 사이트의 [동영상 생성 API 레퍼런스](/ko/api-capabilities/seedance2/video-generation)와 동일한 요청 코드를 사용하고, 동작이 검증되었습니다:

```python theme={null}
#!/usr/bin/env python3
"""Generate videos via APIYI's Seedance 2.0 (text / image / reference-image to video). Pure stdlib, zero dependencies."""
import argparse
import base64
import json
import os
import shutil
import sys
import time
import urllib.error
import urllib.request

# Line-buffer stdout even when redirected, so agents can tail progress from the background
sys.stdout.reconfigure(line_buffering=True)

TASKS_URL = "https://api.apiyi.com/seedance/api/v3/contents/generations/tasks"

# Short name -> full model ID
MODELS = {
    "mini": "doubao-seedance-2-0-mini-260615",
    "fast": "doubao-seedance-2-0-fast-260128",
    "std": "doubao-seedance-2-0-260128",
}
# Resolution caps per model (mini/fast reject 1080p upstream with 400; fail fast client-side)
MODEL_CAPS = {
    "mini": ("480p", "720p"),
    "fast": ("480p", "720p"),
    "std": ("480p", "720p", "1080p"),
}
RATIOS = ("adaptive", "16:9", "4:3", "1:1", "3:4", "9:16", "21:9")
MAX_REF_IMAGES = 9

# Generation is async: wait a bit before the first poll; 720p/5s takes ~90-170s in practice
POLL_FIRST_DELAY = 25
POLL_INTERVAL = 15
POLL_TIMEOUT = 15 * 60


def load_api_key():
    """Prefer the environment variable; otherwise look for .env in the script dir and its parent."""
    key = os.environ.get("APIYI_API_KEY")
    if key:
        return key
    here = os.path.dirname(os.path.abspath(__file__))
    for d in (here, os.path.dirname(here)):
        env_path = os.path.join(d, ".env")
        if os.path.exists(env_path):
            with open(env_path, encoding="utf-8") as f:
                for line in f:
                    line = line.strip()
                    if line.startswith("APIYI_API_KEY") and "=" in line:
                        return line.split("=", 1)[1].strip().strip('"').strip("'")
    return None


def project_root():
    """Walk up from the script location to the first dir containing .git or .claude; else use cwd."""
    d = os.path.dirname(os.path.abspath(__file__))
    while True:
        if os.path.isdir(os.path.join(d, ".git")) or os.path.isdir(os.path.join(d, ".claude")):
            return d
        parent = os.path.dirname(d)
        if parent == d:
            return os.getcwd()
        d = parent


def resolve_path(out):
    """Bare file name -> save under <project root>/seedance-output/ so it's easy to find; else use the given path."""
    if os.path.dirname(out):
        return os.path.abspath(out)
    out_dir = os.path.join(project_root(), "seedance-output")
    os.makedirs(out_dir, exist_ok=True)
    return os.path.join(out_dir, out)


def image_source(src):
    """Image inputs: pass URLs / asset:// / data: through as-is; encode local files as base64 data URIs."""
    if src.startswith(("http://", "https://", "asset://", "data:")):
        return src
    if not os.path.exists(src):
        sys.exit(f"Image file not found: {src}")
    ext = src.lower().rsplit(".", 1)[-1]
    mime = {"png": "image/png", "webp": "image/webp"}.get(ext, "image/jpeg")
    with open(src, "rb") as f:
        return f"data:{mime};base64,{base64.b64encode(f.read()).decode()}"


def api_request(url, api_key, body=None):
    """The gateway labels responses content-encoding: gzip without compressing them — Accept-Encoding: identity is required."""
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
        "Accept-Encoding": "identity",
    }
    data = json.dumps(body).encode() if body is not None else None
    req = urllib.request.Request(url, data=data, headers=headers,
                                 method="POST" if body is not None else "GET")
    try:
        with urllib.request.urlopen(req, timeout=60) as r:
            return json.loads(r.read())
    except urllib.error.HTTPError as e:
        raise RuntimeError(f"Request failed HTTP {e.code}: {e.read().decode(errors='replace')[:800]}")


def download(url, path):
    """Download the result video: it's a signed URL — do NOT send the Authorization header."""
    req = urllib.request.Request(url)
    with urllib.request.urlopen(req, timeout=300) as r, open(path, "wb") as f:
        shutil.copyfileobj(r, f)
    return os.path.getsize(path)


def build_content(args):
    content = [{"type": "text", "text": args.prompt}]
    if args.image:
        content.append({"type": "image_url",
                        "image_url": {"url": image_source(args.image)},
                        "role": "first_frame"})
        if args.last_frame:
            content.append({"type": "image_url",
                            "image_url": {"url": image_source(args.last_frame)},
                            "role": "last_frame"})
    for src in args.ref_image:
        content.append({"type": "image_url",
                        "image_url": {"url": image_source(src)},
                        "role": "reference_image"})
    return content


def main():
    api_key = load_api_key()
    if not api_key:
        sys.exit("API key not found: add a line APIYI_API_KEY=sk-xxx to .env in the skill folder"
                 " (the token must have the SeeDance2 / SD2Mini / SD2Fast group enabled)")

    parser = argparse.ArgumentParser(description="Seedance 2.0 video generation")
    parser.add_argument("prompt", help="prompt (scene + camera motion + mood)")
    parser.add_argument("--model", default="mini", choices=sorted(MODELS),
                        help="mini=fastest & cheapest (default) / fast / std (only one with 1080p)")
    parser.add_argument("--resolution", default="720p", choices=("480p", "720p", "1080p"),
                        help="resolution, default 720p")
    parser.add_argument("--ratio", default="adaptive", choices=RATIOS,
                        help="aspect ratio, default adaptive (same price across ratios per tier)")
    parser.add_argument("--duration", type=int, default=5,
                        help="duration 4-15 integer seconds, or -1 to let the model decide; default 5")
    parser.add_argument("--no-audio", action="store_true",
                        help="disable synced audio (on by default)")
    parser.add_argument("--seed", type=int, default=None, help="random seed, for reproducibility")
    parser.add_argument("-i", "--image", help="first-frame image (local path / URL / asset://); enables image-to-video")
    parser.add_argument("--last-frame", help="last-frame image, used together with -i")
    parser.add_argument("--ref-image", action="append", default=[],
                        help=f"reference image (repeatable, up to {MAX_REF_IMAGES}); mutually exclusive with -i")
    parser.add_argument("-o", "--out", default="output.mp4", help="output file name")
    args = parser.parse_args()

    if args.image and args.ref_image:
        sys.exit("First-frame mode (-i) and reference mode (--ref-image) are mutually exclusive.")
    if args.last_frame and not args.image:
        sys.exit("--last-frame must be used together with -i (first-frame image).")
    if len(args.ref_image) > MAX_REF_IMAGES:
        sys.exit(f"At most {MAX_REF_IMAGES} reference images.")
    if args.duration != -1 and not 4 <= args.duration <= 15:
        sys.exit("Duration must be an integer of 4-15 seconds, or -1 for smart duration.")
    if args.resolution not in MODEL_CAPS[args.model]:
        sys.exit(f"{args.model} supports up to {MODEL_CAPS[args.model][-1]}; "
                 f"use --model std for 1080p.")

    body = {
        "model": MODELS[args.model],
        "content": build_content(args),
        "resolution": args.resolution,
        "ratio": args.ratio,
        "duration": args.duration,
    }
    if args.no_audio:
        body["generate_audio"] = False
    if args.seed is not None:
        body["seed"] = args.seed

    try:
        task = api_request(TASKS_URL, api_key, body)
    except (RuntimeError, OSError) as e:
        sys.exit(f"Submission failed: {e}")
    task_id = task.get("id")
    if not task_id:
        sys.exit(f"Submission failed, response: {json.dumps(task, ensure_ascii=False)[:500]}")
    print(f"Task submitted task_id={task_id}; generation usually takes 2-5 minutes, polling...")

    t0 = time.time()
    time.sleep(POLL_FIRST_DELAY)
    while True:
        try:
            task = api_request(f"{TASKS_URL}/{task_id}", api_key)
        except (RuntimeError, OSError) as e:  # network hiccups don't stop the poll loop
            print(f"  poll error (continuing): {e}")
            time.sleep(POLL_INTERVAL)
            continue
        status = task.get("status", "unknown")
        elapsed = round(time.time() - t0)
        print(f"  [{elapsed:>4}s] status={status}")
        if status in ("succeeded", "failed", "expired"):
            break
        if time.time() - t0 > POLL_TIMEOUT:
            sys.exit(f"Polling timed out ({POLL_TIMEOUT}s). The task is still server-side; query it later:\n"
                     f"  GET {TASKS_URL}/{task_id}")
        time.sleep(POLL_INTERVAL)

    if status != "succeeded":
        err = task.get("error") or task
        sys.exit(f"Generation failed (status={status}): {json.dumps(err, ensure_ascii=False)[:500]}")

    video_url = (task.get("content") or {}).get("video_url")
    if not video_url:
        sys.exit(f"Task succeeded but no video URL returned: {json.dumps(task, ensure_ascii=False)[:500]}")

    path = resolve_path(args.out)
    size = download(video_url, path)
    tokens = (task.get("usage") or {}).get("completion_tokens", "?")
    print(f"Video saved to {path} ({size / 1e6:.1f} MB, {round(time.time() - t0)}s elapsed, "
          f"billed {tokens} tokens)")


if __name__ == "__main__":
    main()
```

## 모델 전환 방법

모델을 전환하는 것은 **그냥 `--model`**, 세 가지 값입니다:

```text theme={null}
... seedance_video.py "prompt"                                    # default mini (fastest & cheapest)
... seedance_video.py "prompt" --model fast                       # fast edition
... seedance_video.py "prompt" --model std --resolution 1080p     # standard - the only 1080p model
```

<Info>
  **토큰의 그룹이 호출할 수 있는 모델을 결정합니다**: 일반 `SeeDance2` 그룹(0.18x)은 세 가지를 모두 실행합니다. 할인 그룹은 **단일 모델 전용 레인**입니다 — `SD2Mini`(0.10x)는 `mini`만 지원하고, `SD2Fast`(0.15x)는 `fast`만 지원하며, 할인 토큰으로 다른 모델을 호출하면 “이 모델에 사용할 수 있는 채널이 없습니다”가 반환됩니다. 하나의 키로 세 모델 모두를 사용하려면 `SeeDance2` 토큰이 가장 간단합니다. 사용량이 충분해지면 전용 할인 토큰을 발급하세요 — [개요 페이지의 그룹 참고 사항](/ko/api-capabilities/seedance2/overview)을 참조하세요.
</Info>

## 2\~5분 대기 예상(중요)

동영상 생성은 **비동기 작업**입니다 — 이미지 기능과의 가장 큰 차이점입니다:

* 스크립트가 전체 흐름을 처리합니다: 제출 → 15초마다 폴링 → 성공 시 mp4를 자동 다운로드합니다. **720p/5초 클립은 처음부터 끝까지 약 2\~3분이 걸립니다**; 1080p이거나 길이가 더 길면 더 오래 걸립니다.
* **명령에 충분히 긴 타임아웃(600초 이상)을 주거나 백그라운드에서 실행하십시오** — 많은 에이전트가 기본 2분 후, 동영상이 준비되기 전에 명령을 종료합니다. `SKILL.md`에 이 내용이 적혀 있으며, 백그라운드 실행을 지원하는 에이전트(예: Claude Code)는 이를 자동으로 처리합니다.
* 폴링이 15분 후에도 타임아웃되면 작업은 여전히 서버 측 대기열에 남아 있습니다. 스크립트는 `task_id`와 조회 명령을 출력하므로 나중에 가져올 수 있습니다. **돈은 낭비되지 않습니다** — Seedance 2.0은 제출 시 미리 과금하고 완료 시 차액을 환불하며, 거절된 제출(HTTP 400)은 절대 과금되지 않습니다.

## 한 문장이 어떻게 동영상을 생성하는가

자주 나오는 질문입니다: 저는 명령을 한 번도 입력하지 않았는데 — 어떻게 「고양이 동영상을 만들어 줘」가 클립을 생성했습니까?

방법은 이렇습니다: 시작 시 에이전트는 각 skill의 `description`를 해당 `SKILL.md`에서 **읽습니다**(이 skill이 무엇을 하며 언제 사용해야 하는지를 설명하는 짧은 메타데이터입니다). 여러분의 요청이 그 설명과 **일치하면**(예: 「동영상을 생성/만들기」, 「이 이미지를 애니메이션화하기」), 에이전트는 **스스로 해당 skill을 호출하기로 결정하고**, 전체 `SKILL.md`를 읽은 뒤 스크립트를 실행합니다 — 여러분은 명령을 외울 필요가 없습니다.

에이전트의 추측에 의존하고 싶지 않다면, **완전한 제어**를 위해 아래의 **명시적 호출**을 사용하면 됩니다.

## 사용하는 방법

### 자연어(암시적 트리거)

설치한 후에는 에이전트에 말하기만 하면 됩니다:

| 입력 문구                       | 스킬 동작                                                 |
| --------------------------- | ----------------------------------------------------- |
| "잔디 위를 달리는 고양이의 동영상을 만들어 줘" | 기본값 `mini` / 720p / 5 s, 오디오가 포함된 mp4 1개              |
| "이 포스터를 모션 동영상으로 바꿔 줘"      | `-i poster.png`이 추가되며, 첫 프레임 이미지-투-비디오                |
| "10초 분량의 1080p 드론 샷"        | `--model std --resolution 1080p --duration 10`이 추가됩니다 |
| "이 캐릭터 이미지를 파쿠르 클립에 사용해 줘"  | 참조 이미지와 함께 `--ref-image`이 추가됩니다                       |
| "배경음 없이"                    | `--no-audio`이 추가됩니다                                   |

### 명시적 호출(더 많은 제어)

* **슬래시 명령을 사용하는 에이전트**(예: Claude Code):

  ```text theme={null}
  /seedance2 Drone shot over an autumn valley, golden forest, cinematic --duration 8 --ratio 16:9
  ```

* **모든 에이전트 / 스크립트를 직접 실행하라고 지시하는 방식**(가장 범용적):

  ```text theme={null}
  Run python3 seedance2/scripts/seedance_video.py "Drone shot over an autumn valley, cinematic" --duration 8
  ```

## 생성된 동영상이 저장되는 위치

* `-o`에 **디렉터리가 없는 파일명**을 지정한 경우(예: `-o cat.mp4`), 동영상은 프로젝트 루트에 자동 생성되는 **`seedance-output/` 폴더**에 저장되며, 프로젝트 내부에 바로 들어갑니다.
* 프로젝트 루트는 스크립트에서 위로 올라가며 찾은 `.git` 또는 `.claude`를 포함하는 첫 번째 디렉터리입니다. **에이전트가 어디서 실행되든 동영상은 프로젝트 안에 남아 있으며, 임시 폴더에 묻혀 사라지지 않습니다.**
* 완료 시 스크립트는 전체 절대 경로가 포함된 한 줄과 함께 파일 크기, 경과 시간, 청구된 tokens를 출력합니다. 예: `Video saved to /Users/you/project/seedance-output/cat.mp4 (3.8 MB, 132s elapsed, billed 108900 tokens)`.
* 반환된 동영상 URL은 **24시간 후 만료**되므로, 스크립트가 항상 먼저 다운로드합니다. **로컬 mp4가 결과물입니다.** URL을 결과로 유지해서는 안 됩니다.
* **디렉터리를 포함한 경로**를 지정한 경우(예: `-o videos/cat.mp4` 또는 절대 경로), `seedance-output/`를 건너뛰고 지정한 위치에 정확히 저장됩니다.

## 관련 문서

* [Seedance 2.0 개요](/ko/api-capabilities/seedance2/overview) (모델, 가격, 그룹)
* [동영상 생성 API 레퍼런스](/ko/api-capabilities/seedance2/video-generation) (전체 매개변수 및 엔드포인트)
* [자산 참조 동영상 생성](/ko/api-capabilities/seedance2/asset-reference) (캐릭터 일관성, `asset://` 자산)
* [GPT-Image-2 시리즈 에이전트 스킬](/ko/api-capabilities/gpt-image-2/skills) (이미지 측 대응 항목)
* [Nano Banana Pro 에이전트 스킬](/ko/api-capabilities/nano-banana-image/skills)
