work-making-of

Officialneta-search/work-making-of
Use it in Cohub

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

Use the skill: work-making-of. Run `npx -y @neta-art/neta-search-cli@latest skills use neta-search/work-making-of --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 neta-search/work-making-of
Summary

Turn your creation process into a video that shows the conversation, the drafts, and what changed.

  • Works from your chat history: each line you typed appears on screen, then the images or versions it generated fall onto a board.
  • Shows what went wrong and how you fixed it: rejected drafts marked with ✗, new versions side by side with old ones, zoomed in to see the difference.
  • Two formats: video works become a card-pulling reveal (flip 3 cards per round, circle the problem, show the final cut at the end). Web apps get a board with comparisons and a playable demo.
  • Works best when the chat is still in the world and the work went through visible changes: early drafts that didn't work, revisions, multiple published versions.
  • Delivers a finished video and a poster showing every step laid out. No new images generated; it only uses what you already made.
SKILL.md
# 作品创作过程片(Work Replay)

## 开工规矩(先读,两条路都适用)

**不问,直接做。** 不弹问卷、不跑 questionnaire skill、不用文字摆 A/B/C 让用户挑。片长、讲几轮、用什么当「原话」,都按本文件和 guide 自己定,交付时一句话说明你是怎么定的。

**唯一可以停下来问的情况**:用户点名的作品,在这个世界里(加上用户给的链接)既找不到作品本身,也找不到它的任何产物。这时用一句话问作品名或 Chat 链接,然后结束这一轮;不拉素材、不渲染。

**找不到原话时,按顺序往下取,不要问:**
1. 生成它的 Chat 在 → 用用户原话(正常流程)。
2. Chat 不在、拉不到,但产物在(作品记录 `works/<id>.json` 里的 `content` 就是生成提示词,`pull-assets.py` 会自动带上;旧格式世界是 `artifacts/media/*.json` 里的 `prompt`;或作品发布过版本)→ 每一拍打出**这件产物自己的生成提示词**:一字不改,太长只能用……截断;用「手写一拍」(`guide/story-json.md`)写 `say`,`who` 写「生成提示词」,不冒充用户原话。按创建时间排;有 V1→V2 改版照常做对比。
3. 连提示词也没有的产物(世界创建时导入的素材、上传的图)→ 用它自己的标题(作品名、素材名)当这一拍的字,`who` 写「素材」,按创建时间排。
4. 始终做**用户点名的那件作品**。不换成世界里别的作品,也不为了「有过程可讲」先把作品重做一遍。

走了 2 或 3 时,交付时说一句:「这件作品的对话不在这个世界里,片子里打出来的是每件产物真正的生成提示词 / 标题。」

**片子语言跟用户走**:用户用什么语言跟你说话,片子上的字就用什么语言——英文用户(例如开场句是英文)就全片英文。开工命令带 `--lang en`(`gacha-start.sh` / `gacha-draft.py` / `draft.py`),gacha.json / story.json 里会写好 `"lang": "en"`,渲染器的界面字(牌库、按键、星级、卡背、印章、画板件数、时间……)随之换成英文;你写的标题、轮名、提示、字幕、标签、片尾也全用英文。**原话照原样,不翻译**。check / build 在 `lang: en` 时见到你写的字里有汉字会直接拦下。

**明确不做**:
- 不重做、改写、重新发布原作品——过程片只讲已经发生过的事
- 不删开工前就有的文件(包括原作品目录里的文件),只在自己的 `$P` 目录里写东西
- 不改世界设定(`world/WORLD.md` 的 frontmatter,不跑 `neta config set`;旧格式世界是 `manifest.worldConfig`)
- 不为凑画面生成新图

**交付用交接卡**:照 interaction-components skill 的 Link 写法发卡,正文里不要再贴同一个链接。成片一张卡、总览图一张卡;`target` 用 `{"type":"external-url","url":"<publish.sh 打印的 ✓ 那个地址>"}`,`presentation.name` 写「《作品名》· 创作过程片」/「《作品名》· 总览图」。只用这一轮工具真打印出来的地址,不要自己拼。

## 先分路(第一件事)

| 作品是什么 | 走哪条 | 读什么 |
|---|---|---|
| **一段一段生成的视频**(Chat 里助手发的是 mp4) | **抽卡版** | `guide/gacha.md`,照 9 步做;范例 `examples/video-gacha*/` |
| 网页、游戏、互动作品、工具 | 画板版 | 本文件下面的「步骤」+ `guide/fun.md` |

抽卡版是最新、用户确认过的做法;下面「画板版」的内容**不适用于视频作品**。

## 抽卡版速查(细节、完成标志都在 `guide/gacha.md`)

**怎么判断**:作品是一段一段**生成的视频**(Chat 里助手发的是 mp4),就走抽卡;网页 / 游戏 / 工具走下面的画板流程。

抽卡版 = 每生成一次视频算抽一张牌,3 轮 × 3 张翻牌 + 结尾完整放成片,90~130 秒。命令一览(细节和完成标志在 gacha.md):

```bash
bash $SK/scripts/gacha-start.sh <spaceId> <sessionId> $P --lang en|zh   # 1~4 环境 + 拉每一抽 + 起草 gacha.json + 圈框总图(2 分钟)
#                                                                 5 读 src/takes.json 的文字 + 1~2 张看片图,整份写好 gacha.json
python3 $SK/scripts/gacha-ring.py $P --set "13:box=…" --set …   #   读 rings 总图,一条命令改完不对的框
python3 $SK/scripts/gacha-check.py $P                           # 6 检查,⚠ 也改完
bash $SK/scripts/gacha.sh $P ; bash $SK/scripts/gacha.sh $P --status   # 8 后台渲染(3~4 分钟,自动出总览图)
```
目标:10 分钟内出片。

最容易犯的错:
1. **框和原话对不上**:每个圈写 `hl`(原话里的原样片段),不圈自己看出来的问题;`t` 从 segs 起点算;先看冻结帧再量框;声音类问题不圈
2. **原话截断或改字**(check 会拦)
3. **片尾讲成制作账**:片尾只放「一句话讲作品 +《作品名》」,「抽了几次」只在开头规则卡里说
4. **结尾成片太碎**:收下的段从头放到尾(默认 `full`),不要拼 12 秒剪辑
5. **不要做快进**:没进 3 轮的抽直接不出现
6. **节奏太快**:用户两次说过太快
7. **片子语言和用户不一致**:英文用户却出了满屏「生成牌库 / 再抽一手 / 稀有」——开工没带 `--lang en`


---

# 画板版(网页 / 游戏 / 工具)

**观众看完要感觉到**:这个作品是一句一句话聊出来的,中间卡住过、来回改过,作品本身一直在变,最后真的成了、能玩。

**最容易做坏的方式**:平铺。一拍落一批图,一拍又落一批,镜头一直很远,每张图都看不清,也看不出改了什么。这样的片子是流水账。

所以这个 skill 有两层:
- **画板层**:东西越堆越多(落下、✗、✓、件数涨)。这是“量”。
- **屏幕层**:盖在画板上,让人**看清楚**——特写、改前改后对比、作品试玩、章节卡。这是“质”。

`$SK` = 本文件所在目录。用到时再读:
- `$SK/guide/fun.md`:**编排**(镜头怎么配、三幕怎么分、节奏)和怎么挑好玩的拍。写 story.json 之前必读
- `$SK/guide/gacha.md`:**视频作品走这条**——把「每生成一次视频」做成抽一张牌,3 轮 + 成片收尾
- `$SK/guide/story-json.md`:story.json 每个字段
- `$SK/guide/style.md`:配色和字体怎么跟着作品走

## 核心:每一拍 = 一句原话 + 这句话真正生成的产物 + 一个镜头

工具会查每件产物是**哪一轮对话生成的**,作品的每个版本是**哪一轮发布的**。所以一拍只要写:

```json
{"turn": "#4.8", "title": "样稿", "reject": "#4.7"}
```

输入框打出 #4.8 这句原话 → 落下这一轮生成的图 → #4.7 那一批打 ✗ → **自动把 #4.7 和 #4.8 并排放大对比** → 如果这一轮发布了新版本,画框和右上角小窗自动换成新版本。

镜头大多是自动的(见 fun.md):重做了被否掉的东西 → 自动对比;落下一大批 → 自动挑 3 张特写;作品有版本 → 自动跟着换。你要做的是**分幕、挑试玩的时刻、把平的几拍并成连发**。

---

## 步骤

### 第 0 步 · 环境 + 看一遍演示(第一次用时做,3 分钟)

下面所有命令里的 `$SK` 都是**这份 SKILL.md 所在的目录**:用 `skills use` 拿到的就是它打印的那个目录(从 picker 来的在 `/tmp/neta-skills/…` 下),装在世界里的才是 `/workspace/.agents/skills/work-making-of`。不要写死成后者。

```bash
SK="<skill-dir>"   # 换成这份 SKILL.md 所在的目录(skills use 打印的那个目录)
bash $SK/scripts/doctor.sh
bash $SK/scripts/new.sh /workspace/_demo --demo
node $SK/tools/build-story.js /workspace/_demo && bash $SK/scripts/pv.sh /workspace/_demo
```
对照 `/workspace/_demo/board/story.json` 看 `/workspace/_demo/out/pv-*.jpg`:倒叙开场、章节卡、对比、连发、作品小窗、试玩、结尾对比,全在里面。

**完成标志**:doctor 打印“环境就绪”;build 打印“✓ 没有警告”。

### 第 1 步 · 建项目,拉素材和版本

找到作品所在的 space id(`cohub://spaces/<id>`,或 `cohub spaces ls --json` 按名字找)。作品跨了几个 space 就用逗号连起来。

```bash
P=/workspace/<作品英文名>-making-of          # 必须在 /workspace 下
bash $SK/scripts/new.sh $P
bash $SK/scripts/pull.sh <spaceId> $P                  # 先不带目录:列出哪些目录放着产物
bash $SK/scripts/pull.sh <spaceId> $P <目录1> <目录2>   # 带上挑好的目录(几分钟)
python3 $SK/scripts/pull-versions.py <spaceId> $P      # 作品发布过的每个版本(几分钟)
```

- 挑目录:要**生成过程中产出的**(`world/media/studio/works`,旧格式世界是 `artifacts/media`;生成图的 `assets/`、`images/`、验收截图 `qa/`)。作品代码里打包的素材目录不要
- `world/media/studio/` 下的文件:`pull-assets.py` 会按 `manifest.json` 的作品索引读每条作品记录,用记录里的 `createdAt` 当时间、`content` 当生成提示词。迁移过来的世界里,这些文件的修改时间全是迁移那一刻,不能拿来排序
- `pull-versions.py`:作品发布成 App 才有版本。它会列出所有 App,自动挑版本最多的当“主作品”(不对就在命令最后写 slug)。场景/地图之类单独发布的 App 加 `--also slug1 slug2` 当普通产物。看一眼 `$P/out/versions.jpg`:**每一版都应该是作品画面,不是加载页、不是白屏**。截坏了的删掉 `board/hd/ver_v<N>.jpg` 重跑
- 没发布过 App:没有版本也能做,作品画面靠 `frame.flip` 翻验收截图

**完成标志**:pull.sh 打印“✓ 拉齐了”,配对里「猜」不多;有版本的话 `src/versions.txt` 每版都对上了原话。

### 第 2 步 · 自动起草(已经编排好)

```bash
python3 $SK/scripts/draft.py $P --lang en|zh        # 用户说英文就 en
```
它挑 12~14 拍,并且已经:配好 ✗、分好三幕、连着平铺的拍并成 `montage`、关键版本加了 `"try": true`。打印最后一行是录试玩的命令。

然后**你自己读一遍** `$P/out/beats-1.jpg`(每行:左边原话,右边这句话生成的图)和 `src/turns.txt`,按 `guide/fun.md` 改。不用发给用户确认,直接往下做。

### 第 3 步 · 填占位、写字幕

**作品里有视频**(生成的视频、作品本身就是视频):拍法不一样,**少看挑选过程,多放片子本身**——每一场戏几句话快速连发,然后全屏放用户点头的那一版最好看的 5 秒(`play`,带原声)。先读 fun.md 第 3.5 节。命令:
```bash
python3 $SK/scripts/cut-videos.py $P                       # 切帧 + 原声;读看片图 out/videos-*.jpg
python3 $SK/scripts/find-highlights.py $P <要放的视频id …>  # 挑最好看的几秒;读 out/highlights-*.jpg 核对
python3 $SK/scripts/cut-videos.py $P                       # 写好 play 以后再跑一次:要全屏放的自动切成 24 帧
```

`story.json` 里所有 `<<…>>` 都要填(不填 build 会拦下):
1. `open.cap`:倒叙开场那一句(≤14 字,「这个游戏,是聊出来的。」)
2. `act`:三幕的名字,「第二幕 · 卡住了」,2~5 个字,说这一段的处境,不说做了什么
3. 每个 `title`:区块标题(「原片截图」「样稿」);`title` 顶部是片尾作品名 + 一句话;`frame.label`
4. 4~6 拍加 `cap` 字幕(写法见 fun.md)

### 第 4 步 · 录试玩

```bash
node $SK/tools/shoot.js --clips $P v12 v40          # draft.py 打印的那一行
```
它打开那一版,自动点「开始/进入/出牌」这类按钮,录 6 秒,记下每次点在哪(片子里的鼠标就照这个动)。**录完挑中间一帧看**:`ls $P/board/clips/v12/`,read 一张。点错了(点进设置、点了没反应)就写 `board/clips/v12.steps.json` 手动指定点哪里再录(格式见 `tools/shoot.js` 开头)。

没有版本的作品:`"try": {"stills": ["截图id1", "截图id2"]}` 用验收截图翻页代替。

### 第 5 步 · 检查、预览

```bash
node $SK/tools/build-story.js $P && bash $SK/scripts/pv.sh $P
```
build 打印每一拍「原话 → 画面变化」和警告,**有警告就改,直到“✓ 没有警告”**。警告里会写改法(连着几拍太平、没有对比、没有试玩、没分幕……)。

逐张看 `$P/out/pv-*.jpg`:
- [ ] 开头 3 秒是成品,然后倒带回空画板
- [ ] 每句原话发出去,画面上真的有东西落下或变化,而且**落下的图就是这句话要的东西**
- [ ] 至少 2 次对比:放大的两张图,一眼看得出差在哪
- [ ] 右上角小窗里的作品在变(有版本时);试玩窗口里真的在玩,鼠标点的地方对
- [ ] 没有连着 3 拍长得一样
- [ ] 结尾:第一版 → 最后一版扫过去,然后收进画框、实机、标题

### 第 6 步 · 结尾、声音、渲染、交付

- **实机**(结尾最好看):用 `$SK/tools/record.js` 录 5~8 秒,写 `ending.footage`(见 story-json.md)。有了它,倒叙开场也会用它。没录就用最后一版截图
- **BGM**:作品自己的音乐放成 `$P/audio/bgm.mp3`(单个 HTML 内嵌的用 `python3 $SK/tools/extract-audio.py <作品.html> $P/audio` 取)
- **配色**(可选):`$SK/guide/style.md`

```bash
bash $SK/scripts/render.sh $P        # 后台渲染,5~10 分钟
bash $SK/scripts/status.sh $P        # 每 1~2 分钟看一次,直到“✓ 渲染完成”
bash $SK/scripts/publish.sh $P/out/film.mp4 <作品名>-making-of/film-v1.mp4
bash $SK/scripts/publish.sh $P/out/sheet-full.jpg <作品名>-making-of/sheet-v1.jpg
```
回复用户(不贴本地路径):成片和总览图各发一张交接卡(见上面「开工规矩 · 交付用交接卡」,正文不再贴链接);说明「画板摆法是片子重排的,原话、产物、版本都是真的、一一对应」;试玩是自动点的还是手动指定的;请用户试听(你听不到声音)。

---

## 铁律

1. **原话一字不改**,只能用……截断
2. **只放这句话真正生成的产物、真正发布过的版本**。不生成新图来凑;不把 A 句话的图安到 B 句话上
3. **每一拍都要有可见变化**
4. **看得清**:一拍落下一大批之后,要有特写或对比让人看清其中几张。全片不能只有“落下”这一种镜头
5. **一定要有翻车**,而且翻车要有对比:旧的 ✗ 和新的 ✓ 并排放大
6. **数字能数出来**。字幕里的数字,在画面上数得到
7. **别读大图**:只看 `out/` 里缩好的图

## 沙箱的坑

- 沙箱重启后 `/tmp/pp`(puppeteer)会丢:重跑 `doctor.sh`
- **不要 `pkill -f chrome` / `pkill -f node`**:同一个 workspace 里可能有别的会话在渲染,会一起被杀掉。只杀自己启动的进程(记下 PID)
- `link-assets.py` 的工具调用缓存在 `src/calls.json`;`pull-versions.py` 已截过的版本不重截(删 `board/hd/ver_v<N>.jpg` 才会重截)
- 任务中断了:看 `$P/board/summary.txt`、`$P/out/beats.txt` 就知道做到哪了
- **沙箱内存 4GB**:渲染类任务最多开 2~3 个进程,多了会被静默杀掉(进程突然消失、numpy/PIL 报没装);依赖由 `doctor.sh` 装到 `/workspace/.pylib/<Python 版本>`,别装 `--user`(重连会丢);沙箱换过 Python 版本,报 `_imaging` / numpy 导入错就重跑 `doctor.sh`
- 抽卡版 `gacha.sh` 起的是后台守护进程,自己补段、自己拼;`--status` 看进度。十几分钟没进展是出事了,不是算力慢

## 目录

```
SKILL.md
guide/      fun.md(编排 + 挑拍)  story-json.md(字段)  style.md(配色)  gacha.md(视频作品的抽卡版)
scripts/    doctor.sh  new.sh  gacha-start.sh / gacha-pull.py / gacha-draft.py / gacha-ring.py / gacha-check.py / gacha.sh(抽卡版:一键开工 / 拉 / 起草 / 圈框预览调框 / 检查 / 后台渲染)  pull.sh(拉齐素材)  pull-versions.py(作品版本)  cut-videos.py(视频切帧 + 原声 + 看片图)  find-highlights.py(视频挑最好看的几秒)  draft.py(起草+编排)  sheet.py(自查用的分镜图)
            pv.sh  render.sh  status.sh  publish.sh
            pull.sh 内部:find-dirs.py  pull-quotes.py  pull-assets.py  link-assets.py  find-moments.py
tools/      gacha/render.py(抽卡版渲染器,读 gacha.json)  build-story.js(检查)  shoot.js(版本截图 / 录试玩)  record.js(录实机)  preview.js  render.js  palette.py  extract-audio.py
tools/board/  画板引擎:board-engine.js(画板、镜头)  board-screens.js(屏幕层:特写/对比/章节/试玩/重抽/小窗/倒叙)  auto-story.js(读 story.json)
examples/   niulai/(真实项目)  advanced/(手写 story.js 的原版)
```