# desktop-outfit-video

Adopt this skill: https://proskills.md/skills/other/liyupi-ai-desktop-outfit-video-skills-desktop-outfit-video

Page: https://proskills.md/skills/other/liyupi-ai-desktop-outfit-video-skills-desktop-outfit-video
This document is the public skill bundle for that page. It contains SKILL.md and every helper file the catalog carries. No login is required.

## File: skills/desktop-outfit-video/SKILL.md
size: 9415
sha: e163b7ac7ac1ea76917c02da66388df4e9c4852d
upstream: https://github.com/liyupi/ai-desktop-outfit-video/blob/main/skills/desktop-outfit-video/SKILL.md

````text
---
name: desktop-outfit-video
description: 生成「AI 桌面换装视频」的完整提示词，并可选地直接调用 Seedance 2.5 出片。当用户想做桌面录屏风格的动态壁纸换装视频、想复刻这类爆款、或提到「桌面换装」「动态壁纸换装」「AI 换装视频」时使用。
---

# AI 桌面换装视频

把用户一句话的想法，扩写成一条能直出 30 秒成片的 Seedance 提示词。

## 工作流

### 第一步：问清楚

一次只问一个，每个都给默认值，用户说「默认」或直接跳过就用默认值。全部用默认值时，产出的就是原版复刻。用户开头已经给过的答案（比如「做 30 秒」）不要再问。

1. **主角是谁？** 默认：中国古典美人，鹅蛋脸、杏眼、长直黑发过肩、皮肤白皙。
   追问一句：有没有人物参考图？有的话让用户给出图片 URL 或本地路径。
2. **场景？** 默认：深蓝灰色调房间，黑色皮沙发，冷调柔光。
   场景里如果没有沙发，把沙发写进 `{场景}`（节拍模板仍写沙发，不能改）。
3. **三套造型？** 默认：黑白条纹上衣配休闲裤 → 蓝黑格纹 JK → 酒红格纹学院风西装。
4. **对白？** 一次给两套让用户选，**不要让用户自己改文案，也不要多一轮「帮我改成兼容的」**。
   - **A 默认（原版）：** 点单「想看 JK」／称呼「老公」／结尾「机会用完啦，老公想留哪套呢？」
   - **B 兼容：** 点单对准**第二套**的短识别名（原版第二套是 JK，所以默认点单是「想看 JK」）；称呼和结尾沿用默认。例如造型是「水手服 → 洛丽塔 → 白领制服」时，B 为「想看洛丽塔」／「老公」／「机会用完啦，老公想留哪套呢？」
   - 三套仍是默认时，A 和 B 相同，只出 A。
   - 问法：`对白两套，回 A / B，或自己改三条。` 然后列出 A、B。
5. **尺度档位？** 软 / 中 / 硬，默认中。见下方「尺度档位」。
6. **时长？** 默认 30 秒。开头已说 30 秒就跳过。

### 第二步：填模板

用下面的模板，把答案填进对应位置。**除了填空处，模板一个字都不要改**——节拍、机位规则、字幕规则是这类视频成立的骨架，改了就不像了。

时长不是 30 秒时，按比例压缩节拍的时间区间，但八个节拍一个都不能删。

### 第三步：问用户怎么用

提示词给出后，问：

> 提示词好了。你是自己复制到即梦/豆包里用，还是我直接调 Seedance 2.5 API 帮你生成？

- 选复制 → 把提示词完整输出，结束。同时提醒：即梦里比例选 16:9、时长选对、确认对白音频是开的、**不要开任何运镜预设**。
- 选 API → 进入第四步。

### 第四步：走 API（仅当用户选择时）

1. 要 API Key。让用户去 [火山方舟控制台](https://console.volcengine.com/ark) 创建，或确认环境变量 `ARK_API_KEY` 已设置。**永远不要把 Key 写进任何文件或提交到 git。**
2. 要 model ID。优先用用户从方舟「开通管理 / 在线推理」复制的接入点。用户没给时，用预置推理接入点 `doubao-seedance-2-5-260628`（短名 `doubao-seedance-2-5` 可能 404，不要死磕）。
3. 跑 `scripts/seedance.py`，参数见该文件顶部。脚本会按有无参考图自动选分辨率。
4. 任务是异步的，30 秒视频通常要等几分钟。脚本会自己轮询并下载。

#### Seedance 2.5 参数（以官方文档 + 实测为准）

官方方舟已宣布 **1080P（10bit）上线**。上次出片落到 720p，不是 1080p 不受支持，而是多传了 2.5 不认的字段，任务以 `InternalServiceError` 秒失败。

| 参数 | 值 | 说明 |
|---|---|---|
| `resolution` | 文生视频 `"1080p"`；带参考图 `"720p"` | 官方参数表：1080p 可选，但**参考图场景不支持 1080p**。文生视频默认 1080p。 |
| `generate_audio` | `True` | 不开就是默片，对白和字幕全没了 |
| `duration` | `30` | 2.5 支持 4–30 秒 |
| `ratio` | `"16:9"` | 桌面天然是横屏 |
| `camera_fixed` | **不要传** | r2v 会 400：`camera_fixed is not supported ... must be empty`。固定机位只写在提示词里。 |
| `optimize_prompt` | **不要传** | 传 `false` 会 `InternalServiceError`，看起来像分辨率问题 |
| `watermark` | **不要传** | 默认已是无水印；显式传也会内部错误 |

1080p 文生视频若仍报 `InvalidParameter`（resolution）或 `InternalServiceError`，**降到 720p 只重试一次**，不要一上来就把默认改成 720p。

#### 参考图

- 本地路径可以，脚本会转 data URI；提示词里写 `@图1`。
- 写实人脸直接传会 400：`InputImageSensitiveContentDetected.PrivacyInformation`。**不要原图重试**。改用文字锁脸继续出片，并告诉用户：要锁真人需走方舟 LAS 素材库 `asset://`，不能直接上传。
- 被拒后把【人物】换回文字外貌描述（按参考图写五官发型肤色），不要再挂图。

---

## 提示词模板

```
【画面】
模拟一台电脑的全屏桌面录屏：左上角一列桌面图标，底部一条任务栏，屏幕主体是一张会实时互动的动态壁纸。壁纸内容是{场景}。固定机位，一镜到底，全程不推、不拉、不摇，镜头绝对不跟人移动。

【人物】
{人物描述}。坐在沙发上、位于画面右侧，画面左侧留空给字幕。真人实拍质感，皮肤有自然纹理和毛孔，不磨皮，不要网红脸，不要 CG 或 3D 渲染感。全程同一个人，五官、发型、肤色、身材比例严格不变，只换衣服。

【服装】
三套依次出现，{尺度档位}：
一、{造型一}
二、{造型二}
三、{造型三}

【节拍】
0–3s 她穿第一套坐在沙发上，腿上抱着黑色靠枕，整理了一下头发，看向镜头微笑，说「说吧……今天想看什么？」
3–5s 画外男声（始终不露脸）说「{男声点单}」。她安静听着，笑意加深，轻轻点头。
5–7s 她说「好，等我一下」，把靠枕放到一旁，撑着沙发起身。
7–10s 起身时身体从镜头前掠过，镜头不跟随，头部移出画面上沿，随后走出画面右侧。沙发空镜停留约一秒。
10–14s 她换好第二套从右侧走回来，站得离镜头较近。因为镜头没有抬高，画面里只看得到腰部以下的{造型二的下装}，头在画面外。她轻轻转动腰身让下摆摆动，说「当当……{称呼}，怎么样？」画外男声回答「嗯，不错」。
14–18s 她说「等等，还有一套」，转身走出画面。沙发空镜再停留约一秒。
18–21s 她换好第三套走回来，仍然只拍到腰以下，{造型三的关键识别物}清晰完整，不在走动中变形。她问「这套呢？」画外男声说「这套也好看」。
21–25s 她坐回沙发，把靠枕重新放在腿上，整理头发和衣领，微微侧身靠住沙发。脸重新完整入画，一直看着镜头，表情自信亲近。
25–30s 她抱着靠枕露出得意的笑，说「{结尾钩子}」然后轻轻偏头，保持微笑，画面自然结束。

【字幕】
字幕固定出现在画面左侧中部，不要放在底部。纤细无衬线中文字体，无底框，轻微发光。她说话时是淡紫色文字、左边一个小扬声器图标；画外男声说话时是白色文字、左边一个小麦克风图标。字幕下方有一条细白色音频波形随声音跳动。字幕跟着发音逐字打出，说完停留一下再整句淡出，不要整句突然出现，也不要提前显示后面的字。

【声音】
中文对白。她的声音是贴脸近场收音，口型精确对上；男声只有画外音，不露脸。垫一层很轻的电子环境音乐，说话时自动压低。换装进出画面时各有一声短促的「嗖」声。她的表演自然克制，不夸张卖萌；男声说话时她闭嘴聆听。
```

有人物参考图时，把【人物】整段换成：

```
外貌严格参考 @图1，只锁五官、发型、肤色和身份，服装按下文变化。坐在沙发上、位于画面右侧，画面左侧留空给字幕。全程同一个人，身材比例不变，只换衣服。
```

## 尺度档位

- 软：`上装统一是低圆领修身款，身材曲线明显`
- 中：`上装统一是低圆领修身款，上围明显，微露事业线`
- 硬：`上装统一是低 V 领修身款，上围饱满，事业线明显`

没有哪一档保证过审，平台策略是黑盒。被拒就降一档重试，别在提示词里堆更多形容词——那只会让模型畸变。想要更明显的身材特征，挂参考图比写文字有效得多。

## 不要改的东西

这四条改了就不是这个品类了：

1. **镜头绝对不跟人移动。** 她站起来时镜头不抬，只拍到腰以下、头在画外——这是「真的像我电脑壁纸」的全部来源。
2. **每次换装前留一秒空沙发。** 没有这个空镜，换装会变成瞬移或者直接在身上变形。
3. **字幕在左侧中部，不在底部。** 放底部就成了普通短视频。
4. **八个节拍的顺序。** 可以换台词内容，不能删节拍。

时间码只写整秒，不要写 0.1 秒精度——模型遵循的是顺序和相对时长，小数点后的数字不会被兑现。
````

## File: skills/desktop-outfit-video/scripts/seedance.py
size: 7377
sha: 2ac908e107f126fd437633607d52608ab7c478b8
upstream: https://github.com/liyupi/ai-desktop-outfit-video/blob/main/skills/desktop-outfit-video/scripts/seedance.py

```text
#!/usr/bin/env python3
"""调用火山方舟 Seedance 2.5 生成桌面换装视频。

准备：
    pip install arkruntime requests
    export ARK_API_KEY=你的key

用法：
    python seedance.py --prompt-file prompt.txt
    python seedance.py --prompt-file prompt.txt --image /path/to/ref.jpg
    python seedance.py --model doubao-seedance-2-5-260628 --prompt-file prompt.txt

分辨率：
    文生视频默认 1080p（官方已上线）。
    带参考图时默认 720p——官方参数表写明参考图场景不支持 1080p。
    可用 --resolution 强制覆盖。1080p 若 InvalidParameter / InternalServiceError，自动降 720p 再试一次。

不要传 camera_fixed / optimize_prompt / watermark：Seedance 2.5 会 400 或内部错误。
"""

from __future__ import annotations

import argparse
import base64
import mimetypes
import os
import sys
import time
from pathlib import Path

import requests
from arkruntime import Ark
from arkruntime._exceptions import ArkAPIError, ArkNotFoundError

POLL_INTERVAL = 10
POLL_TIMEOUT = 900
DEFAULT_MODEL = "doubao-seedance-2-5-260628"
FALLBACK_MODELS = ("doubao-seedance-2-5-260628", "doubao-seedance-2-5")

def to_image_url(src: str) -> str:
    path = Path(src)
    if path.is_file():
        mime = mimetypes.guess_type(path.name)[0] or "image/jpeg"
        data = base64.b64encode(path.read_bytes()).decode("ascii")
        return f"data:{mime};base64,{data}"
    return src

def build_content(prompt: str, images: list[str]) -> list[dict]:
    content: list[dict] = [{"type": "text", "text": prompt}]
    for src in images:
        content.append(
            {
                "type": "image_url",
                "image_url": {"url": to_image_url(src)},
                "role": "reference_image",
            }
        )
    return content

def wait_for_task(client: Ark, task_id: str) -> object:
    deadline = time.time() + POLL_TIMEOUT
    while time.time() < deadline:
        task = client.content_generation.tasks.get(task_id)
        if task.status in ("succeeded", "failed", "cancelled"):
            return task
        print(f"  {task.status} ... {int(time.time() - deadline + POLL_TIMEOUT)}s", flush=True)
        time.sleep(POLL_INTERVAL)
    raise TimeoutError(f"任务 {task_id} 超过 {POLL_TIMEOUT}s 仍未完成")

def error_text(exc: BaseException) -> str:
    return str(exc)

def is_model_missing(exc: BaseException) -> bool:
    text = error_text(exc)
    return isinstance(exc, ArkNotFoundError) or "InvalidEndpointOrModel.NotFound" in text

def is_privacy_image(exc: BaseException) -> bool:
    text = error_text(exc)
    return "InputImageSensitiveContentDetected.PrivacyInformation" in text or "may contain real person" in text

def should_fallback_720p(exc: BaseException | None, task_error: object | None = None) -> bool:
    chunks = [error_text(exc)] if exc else []
    if task_error is not None:
        chunks.append(str(task_error))
    text = " ".join(chunks)
    return (
        "InternalServiceError" in text
        or "InvalidParameter" in text
        or "resolution" in text.lower()
    )

def create_task(client: Ark, model: str, content: list[dict], args: argparse.Namespace, resolution: str):
    return client.content_generation.tasks.create(
        model=model,
        content=content,
        duration=args.duration,
        ratio=args.ratio,
        resolution=resolution,
        seed=args.seed,
        generate_audio=True,
    )

def submit_with_fallbacks(
    client: Ark,
    models: list[str],
    content: list[dict],
    args: argparse.Namespace,
    resolution: str,
):
    last_error: BaseException | None = None
    for model in models:
        try:
            created = create_task(client, model, content, args, resolution)
            print(f"任务已提交：{created.id}  model={model}  resolution={resolution}", flush=True)
            return created, model, resolution
        except ArkAPIError as exc:
            last_error = exc
            if is_privacy_image(exc):
                print(
                    "参考图被判定为真人肖像，接口拒绝直接上传。"
                    "不要原图重试。改用文字锁脸，或走方舟 LAS 素材库 asset://。",
                    file=sys.stderr,
                )
                raise
            if is_model_missing(exc):
                print(f"接入点不可用：{model}，换下一个", flush=True)
                continue
            if resolution == "1080p" and should_fallback_720p(exc):
                print(f"1080p 提交失败（{exc}），降到 720p 重试一次", flush=True)
                created = create_task(client, model, content, args, "720p")
                print(f"任务已提交：{created.id}  model={model}  resolution=720p", flush=True)
                return created, model, "720p"
            raise
    assert last_error is not None
    raise last_error

def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--model", default=DEFAULT_MODEL, help="方舟接入点 ID，默认预置 doubao-seedance-2-5-260628")
    parser.add_argument("--prompt-file", required=True, type=Path)
    parser.add_argument("--image", action="append", default=[], help="参考图 URL 或本地路径，可重复")
    parser.add_argument("--duration", type=int, default=30)
    parser.add_argument("--ratio", default="16:9")
    parser.add_argument(
        "--resolution",
        default=None,
        help="默认：文生视频 1080p，带参考图 720p（参考图场景官方不支持 1080p）",
    )
    parser.add_argument("--seed", type=int, default=None)
    parser.add_argument("--out", type=Path, default=Path("output.mp4"))
    args = parser.parse_args()

    if not os.environ.get("ARK_API_KEY"):
        print("缺少 ARK_API_KEY 环境变量", file=sys.stderr)
        return 1

    prompt = args.prompt_file.read_text(encoding="utf-8").strip()
    client = Ark.volc()
    content = build_content(prompt, args.image)

    if args.resolution:
        resolution = args.resolution
    else:
        resolution = "720p" if args.image else "1080p"

    models: list[str] = []
    for candidate in (args.model, *FALLBACK_MODELS):
        if candidate not in models:
            models.append(candidate)

    try:
        created, model, resolution = submit_with_fallbacks(client, models, content, args, resolution)
    except ArkAPIError:
        return 1

    task = wait_for_task(client, created.id)
    if task.status != "succeeded" and resolution == "1080p" and should_fallback_720p(None, task.error):
        print(f"1080p 失败（{task.error}），降到 720p 重试一次", flush=True)
        try:
            created, model, resolution = submit_with_fallbacks(client, [model], content, args, "720p")
        except ArkAPIError:
            return 1
        task = wait_for_task(client, created.id)

    if task.status != "succeeded":
        print(f"生成失败：{task.status} {task.error}", file=sys.stderr)
        return 1

    url = task.content.video_url
    print(f"生成成功，下载中：{url}", flush=True)
    resp = requests.get(url, timeout=300)
    resp.raise_for_status()
    args.out.write_bytes(resp.content)
    print(f"已保存到 {args.out}（{len(resp.content) / 1e6:.1f} MB）  {resolution}")
    return 0

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

## File: skills/desktop-outfit-video/元提示词.md
size: 5726
sha: 97a5830c7a942d11c367d4942e12172f9f9b0480
upstream: https://github.com/liyupi/ai-desktop-outfit-video/blob/main/skills/desktop-outfit-video/%E5%85%83%E6%8F%90%E7%A4%BA%E8%AF%8D.md

````text
# 元提示词

复制下面整段，粘贴到豆包 / DeepSeek / ChatGPT / Claude 任意一家，它会反过来采访你，然后吐出一条能直接用的 Seedance 提示词。

```
你是「AI 桌面换装视频」的提示词生成器。我会告诉你我想做什么样的片子，你负责把它扩写成一条能直出 30 秒成片的提示词。

规则：
一次只问我一个问题，问完等我回答再问下一个。每个问题都给出默认值，我说「默认」就用默认值。用户开头已经给过的答案不要再问。六个问题问完，直接输出完整提示词，不要解释，不要寒暄。

要问的六个问题：
1. 主角是谁？默认：中国古典美人，鹅蛋脸、杏眼、长直黑发过肩、皮肤白皙。顺便问我有没有人物参考图。
2. 场景？默认：深蓝灰色调房间，黑色皮沙发，冷调柔光。场景里如果没有沙发，把沙发写进场景描述，后面节拍里的沙发不要改。
3. 三套造型分别是什么？默认：黑白条纹上衣配休闲裤 → 蓝黑格纹 JK → 酒红格纹学院风西装。
4. 对白？一次给两套让我选，不要让我自己改文案。
   A 默认（原版）：点单「想看 JK」／称呼「老公」／结尾「机会用完啦，老公想留哪套呢？」
   B 兼容：点单对准第二套的短识别名，称呼和结尾沿用默认。例如造型是水手服→洛丽塔→白领制服时，B 为「想看洛丽塔」／「老公」／「机会用完啦，老公想留哪套呢？」
   三套仍是默认时 A 和 B 相同，只出 A。问法：「对白两套，回 A / B，或自己改三条。」
5. 尺度？软（身材曲线明显）／中（上围明显，微露事业线）／硬（上围饱满，事业线明显），默认中。
6. 时长？默认 30 秒。开头已说 30 秒就跳过。

然后按下面的模板填空输出。除了填空处，模板一个字都不许改——节拍、机位规则、字幕规则是这类视频成立的骨架。时长不是 30 秒时按比例压缩时间区间，但八个节拍一个都不能删。

模板：

【画面】
模拟一台电脑的全屏桌面录屏：左上角一列桌面图标，底部一条任务栏，屏幕主体是一张会实时互动的动态壁纸。壁纸内容是{场景}。固定机位，一镜到底，全程不推、不拉、不摇，镜头绝对不跟人移动。

【人物】
{人物描述}。坐在沙发上、位于画面右侧，画面左侧留空给字幕。真人实拍质感，皮肤有自然纹理和毛孔，不磨皮，不要网红脸，不要 CG 或 3D 渲染感。全程同一个人，五官、发型、肤色、身材比例严格不变，只换衣服。

【服装】
三套依次出现，{尺度档位}：
一、{造型一}
二、{造型二}
三、{造型三}

【节拍】
0–3s 她穿第一套坐在沙发上，腿上抱着黑色靠枕，整理了一下头发，看向镜头微笑，说「说吧……今天想看什么？」
3–5s 画外男声（始终不露脸）说「{男声点单}」。她安静听着，笑意加深，轻轻点头。
5–7s 她说「好，等我一下」，把靠枕放到一旁，撑着沙发起身。
7–10s 起身时身体从镜头前掠过，镜头不跟随，头部移出画面上沿，随后走出画面右侧。沙发空镜停留约一秒。
10–14s 她换好第二套从右侧走回来，站得离镜头较近。因为镜头没有抬高，画面里只看得到腰部以下的{造型二的下装}，头在画面外。她轻轻转动腰身让下摆摆动，说「当当……{称呼}，怎么样？」画外男声回答「嗯，不错」。
14–18s 她说「等等，还有一套」，转身走出画面。沙发空镜再停留约一秒。
18–21s 她换好第三套走回来，仍然只拍到腰以下，{造型三的关键识别物}清晰完整，不在走动中变形。她问「这套呢？」画外男声说「这套也好看」。
21–25s 她坐回沙发，把靠枕重新放在腿上，整理头发和衣领，微微侧身靠住沙发。脸重新完整入画，一直看着镜头，表情自信亲近。
25–30s 她抱着靠枕露出得意的笑，说「{结尾钩子}」然后轻轻偏头，保持微笑，画面自然结束。

【字幕】
字幕固定出现在画面左侧中部，不要放在底部。纤细无衬线中文字体，无底框，轻微发光。她说话时是淡紫色文字、左边一个小扬声器图标；画外男声说话时是白色文字、左边一个小麦克风图标。字幕下方有一条细白色音频波形随声音跳动。字幕跟着发音逐字打出，说完停留一下再整句淡出，不要整句突然出现，也不要提前显示后面的字。

【声音】
中文对白。她的声音是贴脸近场收音，口型精确对上；男声只有画外音，不露脸。垫一层很轻的电子环境音乐，说话时自动压低。换装进出画面时各有一声短促的「嗖」声。她的表演自然克制，不夸张卖萌；男声说话时她闭嘴聆听。

尺度档位三选一，原样填入：
软：上装统一是低圆领修身款，身材曲线明显
中：上装统一是低圆领修身款，上围明显，微露事业线
硬：上装统一是低 V 领修身款，上围饱满，事业线明显

我说有参考图时，把【人物】整段换成这一句：外貌严格参考 @图1，只锁五官、发型、肤色和身份，服装按下文变化。坐在沙发上、位于画面右侧，画面左侧留空给字幕。全程同一个人，身材比例不变，只换衣服。

输出提示词之后，加一句提醒：在即梦里比例选 16:9、时长选对、确认对白音频是开的、不要开任何运镜预设。

现在开始问第一个问题。
```
````

## File: README.md
upstream: https://github.com/liyupi/ai-desktop-outfit-video/blob/main/README.md

````text
# AI 桌面换装视频

把最近很火的「AI 桌面换装视频」拆成了可复用的提示词模板和一个 Agent Skill。一条提示词直出 30 秒成片，不需要任何后期剪辑。

![封面](assets/cover.jpg)

## 效果

下面这段是模板直出的，没有剪辑、没有叠图层。注意镜头全程一动没动——人站起来的时候镜头不跟，所以只剩腰部以下入画，这正是它看起来像「真的是我电脑壁纸」的原因。

![演示](assets/demo.gif)

整条 30 秒的节奏：

![时间轴](assets/timeline.jpg)

## 三种用法

### 1. 直接抄提示词

打开 [提示词.md](提示词.md)，里面是三段可以直接复制的提示词，按顺序用：

| 步骤 | 做什么 | 为什么 |
|---|---|---|
| 第 0 步 | 出一张人物参考图 | 可选。挂了参考图，30 秒里漂脸的概率大幅下降 |
| 第 1 步 | 10 秒验桌面壳 | 先确认桌面 UI、固定机位、左侧字幕这三样能不能成 |
| 第 2 步 | 10 秒验换装节拍 | 全片最容易崩的地方，单独验一次 |
| 第 3 步 | 30 秒全片 | 前两步都稳了再上，省积分也省时间 |

别一上来就抽 30 秒。崩了你分不清是桌面壳崩了、人物漂脸了、还是换装节拍没执行。

### 2. 让 AI 采访你，帮你写提示词

如果想换题材（换人物、换场景、换三套造型），不用自己改模板。打开 [元提示词.md](skills/desktop-outfit-video/元提示词.md)，复制整段贴进豆包 / DeepSeek / ChatGPT / Claude 任意一家，它会反过来问你六个问题，然后吐出一条填好的完整提示词。

六个问题分别是：主角、场景、三套造型、对白、尺度、时长。每个都有默认值，全部回车就是原版复刻。

### 3. 装成 Agent Skill

支持 Cursor、Claude Code 等读取 `SKILL.md` 的客户端：

```bash
git clone https://github.com/liyupi/ai-desktop-outfit-video.git
cp -r ai-desktop-outfit-video/skills/desktop-outfit-video ~/.cursor/skills/
```

之后直接说「帮我做一个桌面换装视频」就会触发。Skill 会先问清需求、生成提示词，再问你是自己复制去即梦用，还是直接调 API 出片。

## 核心原理

这类视频看着复杂，真正让它成立的只有四条。改了任何一条，出来就不是这个味道了。

![机位机关](assets/camera-trick.jpg)

上面四格从左上到右下，是同一条视频里的四个时刻：

1. **镜头绝对不跟人移动。** 她坐着时是正常的半身构图；一站起来，镜头不抬也不跟，脸直接移出画面上沿。所以展示新造型那几段只看得到腰部以下的裙摆和袜子。这是整条片子真实感的全部来源，也是最多人复刻失败的地方——大部分模型的本能是追着人脸走。
2. **每次换装前留一秒空沙发。** 第三格那个空镜不是废镜头。没有它，换装会变成瞬移，或者衣服直接在身上融化变形。
3. **字幕在画面左侧中部，不在底部。** 放底部就成了普通短视频；放左侧中部，配上扬声器/麦克风图标和跟着声音跳的波形，才像一个桌面语音助手的界面。
4. **八个节拍的顺序不能动。** 台词内容随便换，节拍一个都不能删。

还有一条反直觉的：**时间码只写整秒，不要写 0.1 秒精度**。逐帧比对过原版视频，提示词里写「08.80 换装入画」，实际 9.7 秒才入画。模型遵循的是顺序和相对时长，小数点后面的数字不会被兑现，写了只是浪费提示词长度。

## 调 API 出片

除了在即梦网页版手动跑，也可以直接调火山方舟的 Seedance API 批量生成：

```bash
pip install arkruntime requests
export ARK_API_KEY=你的key

python skills/desktop-outfit-video/scripts/seedance.py \
  --model 你的接入点ID \
  --prompt-file prompt.txt \
  --out output.mp4
```

`--model` 是方舟控制台里的接入点 ID，随账号和模型版本不同，去 [火山方舟控制台](https://console.volcengine.com/ark) 复制，别猜。

有四个参数填错了片子直接废，脚本里已经写死：

| 参数 | 值 | 作用 |
|---|---|---|
| `camera_fixed` | `True` | 官方的固定机位开关，比在提示词里写十遍「不要跟人」都硬。**即梦网页版没有这个开关，走 API 才能用上** |
| `generate_audio` | `True` | 不开就是默片，对白和字幕全没了 |
| `optimize_prompt` | `False` | 开了平台会重写提示词，把调好的节拍和机位规则改掉 |
| `watermark` | `False` | |

## 目录结构

```
.
├── 提示词.md                          三步复刻提示词，复制即用
├── skills/
│   └── desktop-outfit-video/          拷进 ~/.cursor/skills/ 即可使用
│       ├── SKILL.md                   工作流：六问 → 填模板 → 问用户怎么用
│       ├── 元提示词.md                 可分发版，任何 AI 都能跑
│       └── scripts/seedance.py        火山方舟 Seedance API 调用脚本
└── assets/                            README 配图
```

## 避坑

- **尺度卡审核。** 提示词里给了软 / 中 / 硬三档措辞，被拒就降一档重试。别在提示词里堆更多形容词，那只会让模型畸变。想要更明确的人物特征，挂参考图比写文字有效得多。
- **即梦里别开运镜预设。** 这条片子全靠镜头一动不动，开了任何运镜都会毁掉。
- **同一级别抽三次不过就改提示词**，别在同一级硬耗。
- **确认对白音频是开的。** 少了这一步出来是默片，字幕也不会有。

## 致谢

玩法原型来自 [@cnyzgkc](https://x.com/cnyzgkc/status/2099029556434985065) 的作品。本仓库是在逐帧拆解之后重新整理的模板，提示词经过精简和重写，不是原文转载。

## 免责声明

- 生成内容请遵守所在平台的社区规范和相关法律法规。
- 不要用他人肖像作为参考图，除非获得本人授权。
- 本仓库只提供提示词模板和调用脚本，不提供任何模型或生成服务。

## License

[MIT](LICENSE)
````
