character-drink-play

Verified@xinsong854/character-drink-play-2
With improvements from @siosan
Use it in Cohub

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

Use the skill: character-drink-play. Run `npx -y @neta-art/neta-search-cli@latest skills use @xinsong854/character-drink-play-2 --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.
Use in Neta Studio Open it in Neta Studio and see what people made with it.
Install from a terminal
npx -y @neta-art/neta-search-cli@latest skills use @xinsong854/character-drink-play-2
Summary

Turn a character in your world into a signature drink, shown on a 3D stand you can spin by dragging.

  • Pick a character and get one custom drink designed from their look, personality, history and favorite colors, with each design choice explained.
  • You get a web page with the drink on a display stand. Drag to rotate it 360° and switch between several drinks.
  • Two recipes: a fantasy recipe that fits your world, and a real-life version using only edible, easy-to-find ingredients. You can ask for either or both.
  • Details like a slowly spinning or floating decoration appear only if they truly suit the character. Otherwise nothing moves.
  • Works best with characters that have a portrait and written notes: a striking palette, a signature object, a clear personality.
Improvements from other creators

This version: thanks to @siosan.

  • Siosan@siosan1 adopted suggestion · in this version
SKILL.md
# 角色特调饮品 · Skill

**版本 0.1.2 · 试用版。** 安装到任意 Space 后,用户说一句话,Agent 读取该 Space 里目标角色的资料,为每位角色设计一杯饮品,并制作展台网页、设计说明与配方。

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

## 产物

- 一个登记好的 Studio 网页作品,目录 `works/webs/drink-<slug>/`(老世界是 `works/web/`),浏览器入口在 `public/`:展台网页。`procedural` 路线只需要 `config.json`;`glb` 路线另有 `characters/<id>/drink.glb`。
- 设计说明:每杯一份,列出每个设计件的依据(事实 / 推断 / 创作)、配方和动态清单。
- `work/drink-play/<run>/`:来源索引、角色档案、Blender 工程与烘焙中间件、QA 截图、报告。私有,不发布。

## 何时停下来问用户

这一节是“停不停”的唯一依据,流程里不再另设确认关卡。

**制作前必须知道的决定:**

- 目标角色明确。开场没有点出具体角色名就算不明确(“这个世界里的角色”“全部”都算),要先列候选名单。
- 路线(`procedural` / `glb`)。
- 配方类型(`concept` / `real-world` / `both`)。

**默认值(用户没提就用它,不为此停下):** 路线 `procedural`,除非用户提到 Blender、GLB 或烘焙;配方类型 `both`;动态为零。液面波纹开关、甜度、可选装饰这类用户没问的细节,按设计自行决定,在交付里列为可调。

**必须停下的情况:**

1. 上面的必须决定有一项没有,且没有默认值可用。
2. 同名、多版本,或设定冲突会改变饮品的主意象。
3. 角色的核心符号或禁忌不清楚,无法决定主色与主意象。
4. 配方涉及危险物质、药物、毒物,或世界观里不可食用的东西要求做成“现实配方”。此时改为概念配方,或替换为可食用原料。
5. 要对世界之外公开分享(`cohub-apps`)。注意:登记并发布成 Studio 作品不属于这一条,它是每次交付都要做的,不用问。

要停时,把缺的项在**一条消息**里问完,在写 pack、跑 Blender 或 `work init` 之前结束这一轮,等用户回话。以上都不成立就不停,直接做到交付。

## 流程

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

### 1. 取材(只读)

```bash
SKILL="${SKILL:?先设成本 SKILL.md 所在目录(skills use 打印的那个)}"
RUN="$SPACE_ROOT/work/drink-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"
```

扫描只列出文件和候选人物,不代表已经读懂。读完角色正文和立绘后再进入下一步。

- 从立绘取配色(主色 2–3 个)和标志物。每个色样记录取自哪张图、哪个区域。
- 资料里没有的饮食喜好写“未知”。不能由饮品设计倒推角色喜好。
- 小说、EPUB、长设定集优先用已安装的 `book-to-world`(Full 档)整理,再核对回角色。见 `references/space-intake.md`。

### 2. 角色档案与设计映射

按 `templates/dossier.example.json` 写 `$RUN/dossier.json`,每条事实标注 `basis`(`explicit` / `visual` / `inferred`)与 `visibility`(`public` / `private` / `undecided`),并给出证据。

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

设计映射写在 `$RUN/design/<id>.md`,方法见 `references/design-mapping.md`。每个设计件都要回答三件事:为什么是这个角色、外观是什么、用什么工艺实现。

### 3. 路线与配方

| 路线 | 条件 | 产物 |
|---|---|---|
| `procedural` | 默认。不需要 Blender,几何由 `scene` 配置实时生成 | 可拖动展台 |
| `glb` | 有 Blender 4.2 或 4.5 LTS,并需要烘焙质感 | 烘焙 GLB + 展台 |

没有 WebGL 时只能交付静态截图,并明确写“未提供可拖动 3D 展台”。

配方分三类,必须标明:

- `concept`:世界观概念配方,不暗示可以饮用。
- `real-world`:现实可调制版本,所有原料可食用、可获得,不含药物或危险操作。
- `both`:两者都给,分开书写。

### 4. 方案

按“何时停下来问用户”判断:有必须停下的情况,就把缺的项和暂定方案一起发出,结束这一轮;否则把方案摘要写在消息里,接着制作、QA、发布,不停。

方案包括:角色、饮品名、五个槽位的设计与依据、配方类型、动态清单(默认为零)、用了哪些默认值、不会做的事。

### 5. 制作

- pack 的 `locale` 写用户开场的语言(内置 `zh`、`en`;其他语言在 pack 的 `ui` 里给出全部界面文字,键名见 `tools/ui-strings.mjs`)。pack 标题、饮品名、tagline、设计说明、配方、表现范围都用这个语言写;角色名等专名保留原样。展台的按钮、状态、页脚由构建器按 `locale` 填入。
- `procedural`:按 `templates/pack.example.json` 写 `scene`(容器剖面、三色液体、装饰、动态)。
- `glb`:把 `templates/build_drink.py` 复制到 `$RUN/drink/<id>/build/`,按设计改造骨架。骨架里的占位件(底座、插饰、闪光)按设计保留或删除,不能留下没有依据的默认元素。运行方法见 `references/BLENDER.md` 与 `references/BAKE.md`。

### 6. 组装

先登记作品目录(只写一个 `meta.json`,状态为制作中),再把展台组装进去。不要自己挑 `works/` 下的目录名,也不要手写 `meta.json`。`--title` 用用户的语言写,和 pack 的 `locale` 一致:

```bash
cd "$SPACE_ROOT"
WORK=$(node /mods/neta/neta work init web works/web/drink-<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/drink-<slug>,老世界是 works/web/drink-<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`,之后重新 QA、重新发布。构建器只复制 pack 明确列出的素材,并校验 GLB 文件头、拒绝越界路径、外部 URL 与像档案的 JSON。

### 7. QA

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

- 页面无控制台错误、无 404;每杯都能切换;拖动与复位正常。
- 动态元素按设计运行,且默认关闭的动态不出现。
- 设计说明只显示 public 依据;公开目录里没有档案字段。
- 页面可见文字和作品标题都是用户的语言:英文用户的页面里没有连续 4 个及以上的中日韩文字(`--check-only` 的 `warnings` 会列出来)。
- glb 路线:`glb_check.py` 通过,材质没有丢贴图。
- 窄屏可以操作,截图与设计说明一致。

### 8. 交付

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` 才算发布成功。失败时按报错修(例如 `world_slug_required` 要先给世界设 slug),不要退回去交文件卡。
- 只发布 `public/`。档案、来源索引、`project-state.json`、`revisions/` 都不会进作品。
- 用 `interaction-components` 交一张**作品卡**:`{"type": "work", "workId": "<作品目录名,即 drink-<slug>>"}`。不要交 `world-file` 文件卡,也不要贴 `index.html` 路径。
- 发布成 Studio 作品和"对世界之外公开分享"是两回事。前者每次都做;后者要用户明确同意,再用 `cohub-apps`。
- 交付说明:设计说明(含依据)、配方、动态清单、用了哪些默认值(可调)、未验证项。交付说明和作品卡的 fallback / presentation 文字都按下面“回话语言”一条写。

## 硬规则

- **回话语言。** 看用户开场用的语言,之后每一条回话都用它写:方案、进度、交付说明(设计、配方、动态清单、未验证项)以及作品卡文字。专名和用户给的原话保留原样。
- 每杯从零设计。只读本角色的资料与本杯的设计文档,不沿用其他角色的符号、配方或动态。
- 装饰要能回答“为什么是这个角色”。只为风格服务的装饰要标明是创作。
- 动态元素默认为零。只有角色意象里真的会动的东西才能开启,并引用 public 事实。
- 现实配方的原料必须可食用,不给出危险操作。

## 已知边界

- 现实配方只是参考。具体调制的安全性由用户自行确认。
- `glb` 路线依赖 Blender。本包已在 Blender 4.2.1 上验证构建与烘焙;其它版本需先跑冒烟。
- `glb` 路线在 0.1 版只渲染烘焙模型、玻璃与液面,`scene.json` 中的闪光、指针、漂浮物尚未接入网页。
- `procedural` 路线的动态只支持 `spin` 与 `float` 两种运动。
- 0.1 版只用合成角色跑通了 procedural 与 glb 两条路线(组装、浏览器渲染、烘焙、GLB 检查)。对本 Space 的真实角色只做了扫描,没有做过完整制作与验收。

## 首次使用

在 Blender 路线前先确认版本与烘焙冒烟:`BLENDER_BIN -b --version`,并按 `references/BAKE.md` 跑低分辨率烘焙(`256 4`)。

## 文件

- `tools/intake.mjs`:扫描 Space、校验角色档案
- `tools/create-project.mjs`:由档案与 pack 组装展台项目
- `tools/shot.mjs`:无头浏览器截图与页面状态检查
- `runtime/`:展台网页(`index.html`、`app.js`、`style.css`、`vendor/` 里的 three.js r186 模块)
- `templates/`:`build_drink.py`(建模骨架)、`bake_export.py`(烘焙导出)、`qa/glb_check.py`(材质检查)、档案与 pack 示例
- `references/`:取材、设计映射、Blender、烘焙、QA