# Novel Characters

从小说或短故事里拆出角色表、人物画像、形象提示词、音色提示词， 其中形象提示词含一张角色设定图的完整版面指令（左半身像 + 右全身三视图 + 细节条）， 产出 JSON +...

- Repository: https://github.com/eternityspring/shuohao-skills (5850 stars)
- Category: Engineering
- License: Apache-2.0
- Last updated: 2026-10-26
- Runs scripts: yes, review before use

## Install

Claude Code: `npx skills add eternityspring/shuohao-skills --skill novel-characters -g -a claude-code -y`
Codex: `npx skills add eternityspring/shuohao-skills --skill novel-characters -g -a codex -y`
Cursor: `npx skills add eternityspring/shuohao-skills --skill novel-characters -g -a cursor -y`
Gemini CLI: `npx skills add eternityspring/shuohao-skills --skill novel-characters -g -a gemini-cli -y`

## Description

从小说或短故事里拆出角色表、人物画像、形象提示词、音色提示词， 其中形象提示词含一张角色设定图的完整版面指令（左半身像 + 右全身三视图 + 细节条）， 产出 JSON + Markdown + 可交互的 report.html。 报告语言可指定（--lang），默认中文，任意语言都支持；零依赖、零 API key、不出图。 Use when asked to 拆小说角色、分析人物、生成角色卡、character sheets from a novel。

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

## novel-characters

输入一篇小说/短故事，输出每个角色的：人物画像、形象提示词、音色提示词、角色设定图的版面指令。

**本 skill 不出图，只产提示词。**出图是下游的事, , 它要选模型、选画风、选画幅，那三件事在这里一个都答不了。

`{baseDir}` = 本文件所在目录。脚本 `{baseDir}/scripts/novel-characters.mjs`，零依赖，`node` 直接跑。

**运行环境**：Claude Code 和 codex 都能跑，没有差别, , 这条管线全是 node 脚本加模型读写，不碰任何本机可执行文件。

---

### Step 0, 确定报告语言

用户可以指定语言，比如「用英文」「--lang en」「日本語で」。**没说就是中文（`zh`）。**

这个 `lang` 会一路传下去：第二趟生成角色卡时决定人类可读字段用什么语言，`validate` 和 `render` 也都要带上。

**界面文案分两种情况：**

- `zh` / `en` / `ja`, , 内置，不用管
- **其他任何语言**, , 你要现场翻一份。跑

  ```bash
  node {baseDir}/scripts/novel-characters.mjs ui-template <lang>
  ```

  它打印一份英文骨架，把每个值翻译成目标语言，整块放进 `cast.json` 顶层的 `ui` 字段。渲染时会合并进内置表。

  **不给 `ui` 的话 `validate` 会直接报错**, , 否则报告会是「角色内容是法语、界面标签是英文」的半吊子状态。

支持的语言不受内置表限制，法语韩语西班牙语都能出完整报告。

### Step 1, 定位输入

用户给文件路径就直接用。直接粘正文的，**先落到一个临时 .txt**, , 后面校验「引文是否逐字」要拿原文比对，没有原文文件这步就没法做。

确定输出目录：用户指定就用；没指定就用原书同级目录。

**有 `outline.json`（novel-outline 的产出）就一起要过来，走 seed**, , 大纲是角色设定的上游，它的 `characters` 块已经定死了角色清单：

```bash
node {baseDir}/scripts/novel-characters.mjs seed <outline.json> > <workdir>/seed.json
```

搬过来的是大纲已经拍板的事实，留空的是这一层才该做的设计：

| outline 的字段 | seed 之后 |
| --- | --- |
| `id` | 原样保留成角色码, , 下游 script / storyboard 用它引用角色 |
| `name` | 角色表就照这份，**不再自己判断谁该进** |
| `tier` | 映射成 `importance`：`lead` → `protagonist`、`support` → `supporting`、`functional` → `minor` |
| `arc` | 直接落进 `persona.arc` |
| `role` / `from` | 进 `seedNote`, , 定位（女主 / 反派）与「由原著的谁合并而来」，扫原文时知道该收哪几条线的戏 |

留空待填：`aliases`（要读原文才知道）、`oneLiner`、`persona` 其余各项、`image`、`voice`。**seed 出来的是骨架不是成品**，直接跑 `validate` 会报一堆字段缺失，那是预期的, , 后面 Step 2, 6 就是来填它的。

两处口径要守住：

- **大纲定的分档不要推翻**。谁重要是改编阶段拍板的事，这一层只负责把定下来的人做深。真觉得分档不对，回去改大纲，别在这里悄悄改一个不一样的
- **主角组内部可以细分**。outline 的 `lead` 是「男女主 + 主反派」一整组，对应 `protagonist` 与 `major` 两档，seed 一律给 `protagonist`；照 `seedNote` 里的定位把主角之外的改成 `major`，这不算推翻分档

**没有 `outline.json` 也照常跑**，本 skill 不依赖它, , 跳过 seed，从 Step 2 开始自己从原文拆角色表。

### Step 2, 分块

```bash
node {baseDir}/scripts/novel-characters.mjs chunk <book.txt> <workdir>
```

打印 `{"chunks": N, ...}`。

The rest: https://github.com/eternityspring/shuohao-skills/blob/HEAD/skills/novel-characters/SKILL.md
