character-avatar-play

Community@xinsong854/character-avatar-play
With improvements from @siosan
Community skill — not reviewed. It was shared by 安诺涅 and has not been checked by Neta. Read SKILL.md below before letting an agent use it.
Use it in Cohub

Paste this into your agent's chat — it fetches the skill and follows it.

Use the skill: character-avatar-play. Run `npx -y @neta-art/neta-search-cli@latest skills use @xinsong854/character-avatar-play --via site` and follow what it prints. Read its complete output, redirecting it to a temporary file first if necessary, and resolve relative paths from the skill directory it prints.
Install from a terminal
npx -y @neta-art/neta-search-cli@latest skills use @xinsong854/character-avatar-play
Summary

Turn a character from your world into a living avatar page that blinks, follows the cursor and breathes.

  • It reads your character's notes and artwork, then writes a sourced profile covering looks, personality, motives, relationships and way of speaking, for you to confirm.
  • The avatar blinks, its eyes follow your mouse, the head and hair accessories shift slightly, and it breathes with a gentle float.
  • If the artwork can't support eye animation (animals, masks, busy styles), it falls back to a gentle float, or to a still avatar.
  • You get a shareable avatar gallery page in Studio, with a switcher between characters, plus an avatar image file for each one.
  • Works best with a clear, front-facing character picture and a well-written character card; it never changes hair, outfit or signature items.
Improvements from other creators
  • Siosan@siosan1 adopted suggestion
SKILL.md
# 角色动态头像 · 玩法 Skill

**版本 0.1.2 · 试用版。** 安装到任意 Space 后,用户说一句话,Agent 读取该 Space 里目标角色的资料和立绘,整理成有出处的角色档案,经确认后制作角色头像页和头像文件。

安装本身不扫描、不联网、不发布。只有用户调用后才读取 Space 资料。

## 产物

- 一个登记好的 Studio 网页作品,目录由 `neta work init` 给出(新世界是 `works/webs/avatar-<slug>/`,老世界是 `works/web/`),浏览器入口在 `public/`(`index.html`、`app.js`、`live-rig.js`、`style.css`、`config.json`,以及每个角色的素材)。
- 每个角色的头像文件:`avatar.svg`(svg 模式)或 `avatar.png`,以及 `preview.png`。
- `work/avatar-play/<run>/`:来源索引、角色档案、制作报告、QA 截图。私有,不发布。

## 何时停下来问用户

1. 目标角色不明确。开场没有点出具体角色名,就算不明确:“这个世界里的角色”“这些角色”“全部”都算。做法见第 1 步末尾的检查点。
2. 同名、多版本,或设定冲突会改变外貌或身份。
3. 没有可用于识别外貌的图片。只有文字时,先请用户提供立绘;用户同意另行生成时,生成结果也要让用户确认后再进入本流程。
4. 要对世界之外公开分享(`cohub-apps`)。注意:登记并发布成 Studio 作品不属于这一条,它是每次交付都要做的,不用问。

其余空缺记为“未知”,不补写成事实。

## 流程

`SKILL` 为本技能目录(即 SKILL.md 所在目录),`SPACE_ROOT` 为目标 Space 的工作目录(通常是 `/workspace`)。

### 1. 取材(只读)

```bash
SKILL="${SKILL:?先设成本 SKILL.md 所在目录(skills use 打印的那个)}"
RUN="$SPACE_ROOT/work/avatar-play/$(date +%Y%m%d-%H%M%S)"; mkdir -p "$RUN"
node "$SKILL/tools/intake.mjs" scan --root "$SPACE_ROOT" --out "$RUN/source-index.json"
```

扫描只列出文件和候选人物,不代表已经读懂。用户指定其他资料目录时加 `--include 目录`。

**检查点 · 目标角色。** 开场没有点出具体角色名时(见“何时停下来问用户”第 1 条),扫描完就列出候选人物,每人一句理由,请用户圈定,然后结束这一轮。用户回答之前不建 `$RUN/avatar/` 目录、不裁图、不组装。不要替用户挑角色。开场已经点名的,跳过这个问题。

### 2. 读资料

- 读世界观(manifest 的 worldConfig)和每位目标角色的完整正文,包括结构化内容、标签与引用。
- 搜索姓名与别名,补充小说、关系与经历。长文件分段读完,记录未读范围。
- 小说、EPUB、长设定集优先用已安装的 `book-to-world`(Full 档)整理,再把结果核对回角色。见 `references/space-intake.md`。
- 每一张用于外貌的图片都要实际查看,记下用途和是否为用户认可版本。

### 3. 写角色档案

按 `templates/dossier.example.json` 写 `$RUN/dossier.json`。每条事实都要标注:

- `basis`:`explicit`(原文或用户明说)/ `visual`(看图所得的可见外观)/ `inferred`(有依据的推断,需标注)。
- `visibility`:`public` / `private` / `undecided`。只有 `public` 会进入网页。
- `evidence`:来源 id 与定位(行号、页码、图像区域)。

```bash
node "$SKILL/tools/intake.mjs" validate --dossier "$RUN/dossier.json"
```

这只检查结构与证据引用,不证明事实正确,也不证明覆盖完整。

### 4. 设计映射与模式

按 `templates/pack.example.json` 写 `$RUN/pack.json`:

- `design`:每一项引用 `factIds`,并标明 `basis`(`explicit` / `visual` / `inferred` / `creative`)。引用的事实必须是 `public`。`factIds` 和 `basis` 只留在 `$RUN/pack.json`,构建器写 `public/config.json` 时只保留 `title` 与 `detail`。
- `mode`:按素材选择,见下表。
- `behavior`:只能落在安全范围内(`tiltDeg` 0–4,`breathPx` 0–3,`breathSec` 1–20)。

| 模式 | 条件 | 产物 | 动效 |
|---|---|---|---|
| `live` | 眼睛可拆层(眼白、虹膜、睫毛、闭眼帧),头部区域可测量 | 网页(WebGL 形变)+ SVG + PNG | 视线跟随、头部与发饰视差、眨眼、呼吸 |
| `svg` | 眼睛可拆层,只需要独立头像文件 | 独立 SVG(无 JS)+ PNG | SMIL 眨眼 |
| `parallax` | 不适合拆眼(动物、面具、无眼、画风复杂) | 网页 + PNG | 轻微浮动与呼吸,不眨眼 |
| `static` | 只要静态头像 | 网页 + PNG | 无 |

降级顺序:`live` → `svg` → `parallax` → `static`。每次降级都要写进交付说明。

### 5. 确认

展示角色清单、每人模式与降级原因、将进入网页的设计说明,以及不会做的事。**方案是这一轮的最后内容,发出后结束这一轮,等用户回话**,同一轮里不开始第 6 步。

- 开场写得再详细(点了角色、给了立绘、说了动效)也不算确认。
- 只有用户明确说“不用确认,直接做”才能跳过,并在报告里记下。
- 同时还要问目标角色(第 1 步检查点)时,可以在同一次停下里一起问,附上暂定方案;否则等用户选定角色后再确认方案。

### 6. 制作

- `parallax` / `static`:从认可的立绘裁出正方形(原图像素,不放大补细节),输出 `avatar.png` 与 `preview.png`。
- `live` / `svg`:按 `references/template-guide.md` 量取眼部参数,运行两个构建模板,再用 `scripts/` 里的工具做对照与帧检查。
- 每个角色使用独立目录 `$RUN/avatar/<id>/`,互不影响。

### 7. 组装

先登记作品目录(只写一个 `meta.json`,状态为制作中),再把头像册组装进去。不要自己挑 `works/` 下的目录名,也不要手写 `meta.json`。作品标题用用户的语言:

```bash
cd "$SPACE_ROOT"
WORK=$(node /mods/neta/neta work init web works/web/avatar-<slug> --entry public/index.html --title "<作品标题>" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const j=s.split("\n").filter(l=>l.startsWith("{")).map(l=>JSON.parse(l)).find(j=>j.data&&j.data.workDir);if(!j){console.error(s);process.exit(1)}console.log(j.data.workDir)})')
echo "$WORK"   # 新世界是 works/webs/avatar-<slug>,老世界是 works/web/avatar-<slug>;以命令给出的为准
node "$SKILL/tools/create-project.mjs" --check-only --pack "$RUN/pack.json" \
  --dossier "$RUN/dossier.json" --source-root "$RUN"
node "$SKILL/tools/create-project.mjs" --pack "$RUN/pack.json" \
  --dossier "$RUN/dossier.json" --source-root "$RUN" --out "$WORK"
```

- `--out` 必须是 `work init` 刚建的目录(里面只有 `meta.json`)。重做时不要再 `work init`:`WORK` 用已有的作品目录,加 `--update`,旧版本会保存到 `revisions/`,之后重新 QA、重新发布。
- 构建器只复制 pack 明确列出的素材,并拒绝:含脚本的 SVG、外部 URL、像档案的 JSON、越出目录的路径。

### 8. QA

按 `references/QA.md` 执行。最低要求:

- 页面无控制台错误,没有 404,每个角色都能切换。
- `live`/`svg`:闭眼帧与半闭帧在正常显示尺寸下看过,无漏光、无接缝、视线方向正确。
- 所有模式:窄屏可用;静态备份存在;公开目录里没有档案字段(包括 `basis`、`factIds`、`evidence`)。
- 发布后:Studio 里有这件作品卡,能打开。
- 报告写清楚测了什么、没测什么。

### 9. 交付

QA 通过后,把 `public/` 发布成 Studio 作品。**只组装出网页、没有登记发布,算没交付**:用户在 Studio 里看不到作品卡,打不开也分享不了。

```bash
cd "$SPACE_ROOT"
node /mods/neta/neta work publish web "$WORK" --from "$WORK/public"
```

- 输出 `"ok":true`、`meta.json` 里 `status` 变成 `ready` 才算发布成功。把命令给出的作品 id 记进报告。失败时按报错修(例如 `world_slug_required` 要先给世界设 slug),不要退回去交文件卡。
- 只发布 `public/`。档案、来源索引、`project-state.json`、`revisions/` 都不会进作品。
- 交付消息里用 `interaction-components` 交一张**作品卡**:`{"type": "work", "workId": "<发布命令给出的作品 id>"}`,名称用作品标题,封面用作品缩略图。主交付不能是指向 `public/index.html` 的 `world-file` 文件卡;`avatar.svg` / `avatar.png` 的下载可以作为次要的文件链接附上。
- 发布成 Studio 作品和“对世界之外公开分享”是两回事。前者每次都做;后者要用户明确同意,再用 `cohub-apps`。
- 交付内容:作品卡、每人的头像文件、模式与降级说明、已知风险、未验证项。

## 硬规则

- 不改变身份特征(发色、发饰、脸型、标志物、服装)。需要改动时要有依据,并让用户确认。
- 性格只驱动克制的动作节奏(视线停留、眨眼频率、头部跟随),不做“冷酷=不眨眼”这类硬套。
- 动效幅度按显示尺寸量过,不凭感觉。
- 私人和未确定资料不进入 `public/`。来源索引与档案留在 `work/`。

## 已知边界

- 不是通用 Live2D 绑定。拆眼、测量和闭眼帧需要人工与图像工具配合,耗时取决于图片。
- 原图没画出来的背面、被遮挡部位不会凭空生成,头部转动幅度有限。
- SVG 无 JS,只能眨眼;视线跟随只在网页的 `live` 模式中存在。
- 没有 WebGL 的环境只显示静态备份。
- 0.1 版只用合成素材跑通了完整流程(组装、三种模式的浏览器加载、眨眼帧)。对本 Space 的真实角色只做了扫描,没有做过真实角色的完整制作与验收。

## 首次使用

先运行 `bash "$SKILL/scripts/selftest.sh"`,应输出 `ALL OK`。

## 文件

- `tools/intake.mjs`:扫描 Space、校验角色档案(`scan`、`validate`)
- `tools/create-project.mjs`:由档案与 pack 组装网页项目(`--check-only`、`--update`)
- `tools/shot.mjs`:无头浏览器截图与页面状态检查
- `runtime/`:头像册网页(`index.html`、`app.js`、`live-rig.js`、`style.css`)
- `scripts/`:配准、帧检查、SVG 检查与自检(`selftest.sh`)
- `templates/`:眼部与 SVG 构建模板、配置示例、档案与 pack 示例、SVG 骨架
- `references/`:取材、模板使用、诊断度量、动效与 live 版、QA、空间取材说明