character-refs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

character-refs

character-refs

输入一段角色描述,输出一组角色参考图——角色从哪来都行:小说改编、自己编的故事、临时想到的一个人。一张正面全身锚点,其余每张都只参考这张锚点。 给视频模型(H3 / Wan / Seedance)当参考图使用,也给人看。
{baseDir}
= 本文件所在目录。脚本
{baseDir}/scripts/character-refs.mjs
,零依赖,
node
直接跑。
**这是仓库里唯一真出图的 skill。**其余 skill 只交提示词,因为出图那一刻才能决定模型和画风; 这个 skill 就是「那一刻」——模型在 Step 0 由用户选定,画风在建角色时选择(默认动漫,另有写实预设,也能挂自定义画风)。
Input a paragraph of character description, and output a set of character reference images — characters can come from anywhere: novel adaptations, original stories you made up, a person you thought of on the spot. One front-facing full-body anchor image, all other images only reference this anchor image. Can be used as reference images for video models (H3 / Wan / Seedance), and also for human viewing.
{baseDir}
= the directory where this file is located. The script
{baseDir}/scripts/character-refs.mjs
has zero dependencies and runs directly with
node
.
This is the only skill in the repository that actually generates images. All other skills only provide prompts, because the model and art style can only be decided at the moment of image generation; This skill is that "moment" — the model is selected by the user in Step 0, and the art style is selected when creating the character (default is anime, there are also realistic presets, and custom art styles can be attached).

核心规则(先读懂再动手)

Core Rules (Read carefully before starting)

  • **一组图只有一个根:正面全身锚点。**只有它是文生图,其余全是「锚点 + 一句改图指令」。 头发、脸、领口三类细节额外挂确认过的正脸大头照。图与图之间不再互相参考—— 所以任何一张出坏了,单独重出这一张就行,不会连锁。
  • 分档,默认出到第二档:
    档位内容什么时候出
    1正面全身(锚点)总是,第一张
    2(默认)正脸大头照、90° 侧面(面朝画面右侧)、背面默认就出齐
    3细节图(最多 8 张):用户点名的、角色最能认出来的地方;没有就用默认的头发 / 发饰、领口、袖口、鞋有配饰或服装局部的特写
    4(默认不出)45° 大头照(面朝画面左侧)用户明确要
    H3 实测:只给正面全身,服装和背影都对,但脸会走样;加一张大头照,脸最接近。所以默认出齐第二档。 只要锚点(比如先看看长相再说):
    gen <asset.json> --tier 1
    。
  • 模型不锁定:主图与派生图可以使用不同模型,重出单张也可以换模型。一致性来自「同一张锚点」, 不来自「同一个模型」(实测 Qwen 锚点 + GPT 派生、GPT 锚点 + Qwen 派生、同组混用都衔接得上)。 每张图记录自己的模型,同组混用只在报告里提醒。
  • 冻结的只有三样:锚点文件(sha256)、画风快照、文字描述指纹。任何一样变了, 依赖它的图标成「过期」——只标记,不删除,旧版本全部留着。

  • A set of images has only one root: the front-facing full-body anchor image. Only it is text-to-image generated; all others are "anchor image + one image editing instruction". Three types of details — hair, face, and neckline — additionally use a confirmed front-facing close-up portrait. Images do not reference each other — so if any one image turns out bad, just regenerate that single one, no chain reaction.
  • Tiered generation, default up to Tier 2:
    TierContentWhen to generate
    1Front-facing full-body (anchor)Always, first image
    2 (default)Front-facing close-up portrait, 90° side view (facing right side of the frame), back viewGenerated by default
    3Detail shots (max 8): features specified by the user, the most recognizable parts of the character; if none, use default hair/hair accessories, neckline, cuffs, shoesWhen there are accessories or close-ups of clothing parts
    4 (not generated by default)45° close-up portrait (facing left side of the frame)When explicitly requested by the user
    H3 actual test: with only front-facing full-body image, clothing and back view are correct, but the face will be distorted; adding a close-up portrait makes the face most accurate. That's why Tier 2 is generated by default. If you only want the anchor image (e.g. check the appearance first):
    gen <asset.json> --tier 1
    .
  • No model lock-in: The main image and derived images can use different models, and you can also switch models when regenerating a single image. Consistency comes from "the same anchor image", not from "the same model" (actual tests show Qwen anchor + GPT derived, GPT anchor + Qwen derived, and mixed use in the same set all work well). Each image records its own model, and mixed model use in the same set is only reminded in the report.
  • Only three things are frozen: anchor image file (sha256), art style snapshot, text description fingerprint. If any of them changes, images that depend on it are marked as "expired" — only marked, not deleted, all old versions are kept.

Step 0 — 初次设置(每台机器一次)

Step 0 — Initial Setup (once per machine)

bash
node {baseDir}/scripts/character-refs.mjs config --show
输出末尾写「还缺:……」就要问用户这三件事,一次问完:
  1. 主图(锚点)使用哪个模型:
    • qwen
      —— Qwen Image 2.1,走自己的 ComfyUI 服务器。快(每张 25–45 秒)、尺寸精确、不吃订阅额度。 需要
      COMFY_URL
      (可选
      COMFY_USER
      /
      COMFY_PASS
      ),放环境变量或一个 .env 文件
    • codex
      —— codex 内置出图(GPT)。不要 API key,但吃 ChatGPT 订阅额度(Plus 约 25 张会触顶,几小时后恢复),每张 80–160 秒
    • openai
      —— OpenAI Images API,默认
      gpt-image-2
      。按量计费,要
      OPENAI_API_KEY
      ;也能指到兼容接口(
      --openai-base-url
      )
    • custom:<名字>
      —— 用户自己的出图命令,见
      references/models.md
  2. 派生图使用哪个模型:默认与主图相同。可以分开(比如锚点 GPT、派生 Qwen)
  3. 出完锚点要不要停下来等人确认:推荐
    yes
    ——锚点是全组的根,它不对后面全白出。 选
    no
    则自动放行,报告里标「未经人工确认」;没过检查门的锚点不会自动放行,要人看过再
    confirm
    或重出
bash
node {baseDir}/scripts/character-refs.mjs config --model qwen --confirm-anchor yes --qwen-env-file <.env 路径>
bash
node {baseDir}/scripts/character-refs.mjs config --show
If the output ends with "Missing: ...", you need to ask the user these three things, ask all at once:
  1. Which model to use for the main image (anchor):
    • qwen
      — Qwen Image 2.1, runs on your own ComfyUI server. Fast (25–45 seconds per image), precise dimensions, does not consume subscription quota. Requires
      COMFY_URL
      (optional
      COMFY_USER
      /
      COMFY_PASS
      ), placed in environment variables or a .env file
    • codex
      — codex built-in image generation (GPT). No API key required, but consumes ChatGPT subscription quota (Plus plan hits limit at ~25 images, recovers after a few hours), 80–160 seconds per image
    • openai
      — OpenAI Images API, default
      gpt-image-2
      . Pay-as-you-go, requires
      OPENAI_API_KEY
      ; can also point to compatible endpoints (
      --openai-base-url
      )
    • custom:<name>
      — user's own image generation command, see
      references/models.md
  2. Which model to use for derived images: Defaults to the same as the main image. Can be set separately (e.g. GPT for anchor, Qwen for derived images)
  3. Whether to stop and wait for human confirmation after generating the anchor: Recommended
    yes
    — the anchor is the root of the entire set, if it's wrong all subsequent images are wasted. Selecting
    no
    will auto-approve, marked as "not manually confirmed" in the report; anchors that fail the check gate will not be auto-approved, they require human review then
    confirm
    or regeneration.
bash
node {baseDir}/scripts/character-refs.mjs config --model qwen --confirm-anchor yes --qwen-env-file <.env path>

分开设置:--anchor-model codex --derive-model qwen

Separate settings: --anchor-model codex --derive-model qwen


配置写在 `{baseDir}/config.local.json`(不进版本控制,重新安装不会覆盖)。以后默认一直使用它,
用户说「换成 xx」就重新跑 `config`。**不要把 .env 里的密码或 key 打印出来**,`config --show` 已经打码。
Configuration is written to `{baseDir}/config.local.json` (not under version control, will not be overwritten by reinstallation). It will be used by default afterwards,
if the user says "switch to xx", re-run `config`. **Do not print passwords or keys from .env**, `config --show` already masks them.

Step 1 — 一次性输入

Step 1 — One-time Input

用户一段话描述角色就够了,不要一项一项问。你(模型)来拆:
bash
node {baseDir}/scripts/character-refs.mjs intake-template
照模板把描述拆进各字段,写到
<工作目录>/<角色名>-intake.json
。规则(详见
references/intake.md
):
  • lang
    填用户说话的语言(中文
    zh
    、英文
    en
    、日文
    ja
    内置)。确认表和报告都用这个语言; 其他语言先运行
    ui-template <lang>
    ,把打印出的英文文案逐项翻译,整块放进 intake 的
    ui
    字段
  • 用户说了的标
    stated
    ,你推出来的标
    inferred
    ,按惯例补的标
    default
    ——如实标,确认表靠它提醒用户看哪几项
  • 年龄、性别、年代推不出来就问用户,只有这三样不许自己编;其余一律自己补,不要追问
  • en
    进提示词:永远英文、不写角色名、不写画风词;
    text
    给人看,用
    lang
    的语言写(旧输入写的
    zh
    照样认)
  • 服装分
    top
    /
    bottom
    ——大头照只用上装,带上下装模型就会把镜头拉远
  • 细节图按角色挑:用户点名的优先,没点名挑最能认出这个角色的地方,默认四槽位兜底;脸上的特征不出细节图(大头照已经看得清)。详见
    references/intake.md
bash
node {baseDir}/scripts/character-refs.mjs intake-check <intake.json>
有问题按报错改到通过。通过后它打印确认表,原样给用户看,推断和默认的项带标记。 用户确认(或改完再确认)之后才往下走。
The user only needs to describe the character in one paragraph, don't ask item by item. You (the model) split it:
bash
node {baseDir}/scripts/character-refs.mjs intake-template
Split the description into various fields according to the template, and write to
<working directory>/<character-name>-intake.json
. Rules (see
references/intake.md
for details):
  • lang
    fills in the language the user speaks (Chinese
    zh
    , English
    en
    , Japanese
    ja
    are built-in). Both the confirmation form and report use this language; For other languages, first run
    ui-template <lang>
    , translate the printed English text item by item, and put the whole block into the
    ui
    field of the intake file
  • Content stated by the user is marked
    stated
    , content you infer is marked
    inferred
    , content supplemented by convention is marked
    default
    — mark truthfully, the confirmation form relies on this to remind the user which items to check
  • If you can't infer age, gender, or era, ask the user — only these three things are not allowed to be made up; all others are supplemented by yourself, don't ask follow-up questions
  • en
    field goes into prompts: always English, no character name, no art style words;
    text
    is for human reading, written in the
    lang
    language (old inputs written in
    zh
    are still recognized)
  • Clothing is split into
    top
    /
    bottom
    — close-up portraits only use the top, if both top and bottom are included the model will pull the camera back
  • Select detail shots based on the character: user-specified features take priority, if none, select the most recognizable parts of the character, with four default slots as fallback; facial features do not get detail shots (they are already clear in close-up portraits). See
    references/intake.md
    for details.
bash
node {baseDir}/scripts/character-refs.mjs intake-check <intake.json>
If there are issues, fix them according to the error messages until it passes. After passing, it prints a confirmation form, show it to the user as-is, with inferred and default items marked. Only proceed after the user confirms (or confirms after modifications).

Step 2 — 建资产

Step 2 — Create Asset

bash
node {baseDir}/scripts/character-refs.mjs new <intake.json> --out <输出目录> [--look 画风]
建出
<输出目录>/<角色名>/asset.json
。画风层此时整份快照进资产,之后改预设不影响已有角色。
画风:用户说了就按用户说的选择,没说就是动漫。同一部剧的角色全部使用同一个画风。
预设
--look
认的名字
动漫(默认)
动漫
卡通
anime
cartoon
二次元
アニメ
写实照片
写实
realistic
photo
真人
looks
列出全部预设。用户要别的画风(国风、美漫……):
look-template <最接近的预设> > my-look.json
,改
style
(介质、线条)、
clean
(背景与光,必须保留白底)、
neg
(反向词——换成画出来的画风要把
anime
illustration
从反向词里拿掉), 画出来的画风把
medium
写成
drawn
,然后
--look my-look.json
。自定义画风没有实测,先出锚点看效果。
已经建好的角色要换画风:
bash
node {baseDir}/scripts/character-refs.mjs restyle <asset.json> --look 动漫
换完所有已有的图(连锚点)都标过期,旧图保留,从锚点开始重出。
bash
node {baseDir}/scripts/character-refs.mjs new <intake.json> --out <output directory> [--look art style]
Creates
<output directory>/<character-name>/asset.json
. The entire art style layer is snapshotted into the asset at this point, subsequent preset changes will not affect existing characters. Art style: Select according to user's request if specified, default is anime. Characters from the same work all use the same art style.
PresetNames recognized by
--look
Anime (default)
动漫
卡通
anime
cartoon
二次元
アニメ
Realistic photo
写实
realistic
photo
真人
looks
lists all presets. If the user wants another art style (Chinese style, American comics...): run
look-template <closest preset> > my-look.json
, modify
style
(medium, lines),
clean
(background and lighting, white background must be retained),
neg
(negative prompts — when switching to a drawn art style, remove
anime
illustration
from negative prompts), for drawn art styles set
medium
to
drawn
, then use
--look my-look.json
. Custom art styles have not been actually tested, generate the anchor image first to check the effect. To change the art style of an already created character:
bash
node {baseDir}/scripts/character-refs.mjs restyle <asset.json> --look anime
After changing, all existing images (including the anchor) are marked as expired, old images are kept, and regeneration starts from the anchor.

Step 3 — 出默认的第二档

Step 3 — Generate Default Tier 2

bash
node {baseDir}/scripts/character-refs.mjs gen <asset.json>
不给视图和档位,就是补齐第一、二档里还没出的、已过期的图。
配置了确认:这条命令只出锚点就停下。把图给用户看(报告或直接打开 PNG),用户说可以再
bash
node {baseDir}/scripts/character-refs.mjs confirm <asset.json>
node {baseDir}/scripts/character-refs.mjs gen <asset.json>      # 同一条命令,接着出大头照、侧面、背面
不满意就再跑一次
gen <asset.json> front-full
(出 v2,可
--seed
换种子、
--model
换模型), 或者回 Step 1 改描述。**锚点没确认,派生图会被拒。**配置为不确认时,一条命令出齐四张。
bash
node {baseDir}/scripts/character-refs.mjs gen <asset.json>
Without specifying views or tiers, this command fills in all ungenerated and expired images in Tier 1 and Tier 2. If confirmation is configured: this command stops after generating only the anchor image. Show the image to the user (via report or directly opening the PNG), and after the user approves, run:
bash
node {baseDir}/scripts/character-refs.mjs confirm <asset.json>
node {baseDir}/scripts/character-refs.mjs gen <asset.json>      # Same command, continues to generate close-up portrait, side view, back view
If not satisfied, run
gen <asset.json> front-full
again (generates v2, can use
--seed
to change seed,
--model
to change model), or go back to Step 1 to modify the description. If the anchor is not confirmed, derived images will be rejected. When confirmation is disabled, one command generates all four images.

Step 4 — 按需升档

Step 4 — Upgrade Tier as Needed

bash
node {baseDir}/scripts/character-refs.mjs gen <asset.json> --tier 3 --reason "E03 有发饰和领口特写"
--reason
写为什么升档,记进资产。也可以只出某几张:
gen <asset.json> detail-hair detail-neck
。
bash
node {baseDir}/scripts/character-refs.mjs gen <asset.json> --tier 3 --reason "E03 has hair accessory and neckline close-ups"
--reason
records why the tier is upgraded, and is stored in the asset. You can also generate only specific images:
gen <asset.json> detail-hair detail-neck
.

Step 5 — 检查与重出

Step 5 — Check and Regenerate

bash
node {baseDir}/scripts/character-refs.mjs check <asset.json>
每张图过代码门(尺寸 300–5760、宽高比 0.4–2.5、比例对得上、≤20MB、背景够白),再看过期。 **有问题 exit 1。**门没过或过期的,单独重出那一张:
bash
node {baseDir}/scripts/character-refs.mjs gen <asset.json> detail-neck --model codex
门里「背景够白」对全身图查四边,对大头照只查上边和两侧上半段(身体本来就顶到下边),细节图跳过并明说。 门查不了长相、角度、取景——出完一定要看图,这几项靠眼睛。
bash
node {baseDir}/scripts/character-refs.mjs check <asset.json>
Each image passes through a code gate (dimensions 300–5760, aspect ratio 0.4–2.5, correct proportions, ≤20MB, background is white enough), then checks for expiration. Exits with code 1 if there are issues. For images that fail the gate or are expired, regenerate that single image:
bash
node {baseDir}/scripts/character-refs.mjs gen <asset.json> detail-neck --model codex
For the "background is white enough" check in the gate: for full-body images, check all four edges; for close-up portraits, only check the top edge and upper half of both sides (the body naturally reaches the bottom); for detail shots, this check is skipped and explicitly stated. The gate cannot check appearance, angle, or framing — you must look at the images after generation, these items rely on human eyes.

Step 6 — 报告

Step 6 — Report

bash
node {baseDir}/scripts/character-refs.mjs render <asset.json>... --out <输出目录>/character-refs.html
多个角色可以一起出。语言默认取资产的
lang
,临时换加
--lang en
;非内置语言没带
ui
时,用
--ui <文件>
传自译文案, 缺文案会直接报错,不出半中半英的报告。界面文案换语言,角色描述保持原文。 第一档只有一张卡片;第二档起是设定图版面(左大头照,右上正面 / 侧面 / 背面,右下细节条), 默认不显示细节图,页面上一键切换。过期的图标红框,页面顶部有图例说明,鼠标移到红框图上能看到原因;混用模型会提醒。
bash
node {baseDir}/scripts/character-refs.mjs render <asset.json>... --out <output directory>/character-refs.html
Multiple characters can be generated together. The language defaults to the asset's
lang
, add
--lang en
to temporarily change it; for non-built-in languages without
ui
, use
--ui <file>
to pass self-translated text, missing text will directly throw an error, no half-Chinese half-English reports will be generated. Interface text changes with language, character descriptions remain in original language. Tier 1 has only one card; from Tier 2 onwards it's a concept art layout (close-up portrait on the left, front/side/back views on the top right, detail bar on the bottom right), detail shots are not shown by default, can be toggled with one click on the page. Expired images are marked with red borders, there is a legend at the top of the page, and the reason can be seen when hovering over red-bordered images; mixed model use is also reminded.

Step 7 — 汇报

Step 7 — Report Back

一句话:出了哪几张、使用的哪个模型、报告路径。门没过或过期的点名。没看过图不要说「效果很好」。

In one sentence: state which images were generated, which model was used, and the report path. Name any images that failed the gate or are expired. Do not say "the effect is great" if you haven't looked at the images.

落地结构

Output Structure

<输出目录>/
├── character-refs.html          ← render 产出
└── <角色名>/
    ├── asset.json               ← 角色描述 + 每张图的全部版本
    └── default/                 ← 造型(v1 只有 default 一套)
        ├── front-full.v1.png    ← 锚点
        ├── face-front.v1.png
        ├── face-front.v2.png    ← 重出不覆盖
        └── detail-hair.v1.png …
每张 PNG 里都写着标识(
角色/造型/视图/版本
)、模型、参考了哪几张,图被单独拷走也查得到来历。
asset.json
的结构见
references/schema.md
。
<output directory>/
├── character-refs.html          ← render output
└── <character name>/
    ├── asset.json               ← character description + all versions of each image
    └── default/                 ← outfit (v1 only has default set)
        ├── front-full.v1.png    ← anchor
        ├── face-front.v1.png
        ├── face-front.v2.png    ← regeneration does not overwrite
        └── detail-hair.v1.png …
Each PNG has embedded identifiers (
character/outfit/view/version
), model, and which images it references — even if the image is copied separately, its origin can be traced. See
references/schema.md
for the structure of
asset.json
.

边界

Limitations

  • 实测过的画风只有写实和动漫两种(都是 Qwen 跑四档);自定义画风效果取决于写法,先出锚点看
  • 细节图只收长在角色身上的(发饰、领口、袖口、鞋);道具归 novel-art
  • 已知短板:小疤痕容易画成新伤、双排扣这类大面积细节取景偏远、Qwen 的领口细节会把粗布画得像丝绒(换 codex 重出这一张)、Qwen 细节图里露出的皮肤会偏老(提示词已加年龄句,16 岁样例上有效,未大量验证)
  • openai
    适配器只使用本地假服务器验过请求格式,没有用真 key 跑过;第一次使用时先出一张锚点看看
  • 同一套提示词在 Qwen 和 GPT 上都实测过;自定义模型的效果取决于那个模型
  • Only two art styles have been actually tested: realistic and anime (both run all four tiers on Qwen); custom art style effects depend on the prompt writing, generate the anchor image first to check
  • Detail shots only include features on the character's body (hair accessories, neckline, cuffs, shoes); props belong to novel-art
  • Known shortcomings: small scars are easily drawn as fresh wounds, large-area details like double-breasted buttons have distant framing, Qwen's neckline details make coarse cloth look like velvet (regenerate that single image with codex), exposed skin in Qwen detail shots looks older (age sentences have been added to prompts, effective on 16-year-old samples, not extensively verified)
  • The
    openai
    adapter has only been tested for request format using a local fake server, has not been run with a real key; generate an anchor image first when using it for the first time
  • The same set of prompts has been actually tested on both Qwen and GPT; custom model effects depend on that model.

自测

Self-test

bash
node {baseDir}/scripts/selftest.mjs
230 项断言,不调模型、不花额度:PNG 标识读写、检查门、输入校验、多语言确认表与报告、画风预设与换画风、提示词、过期传导、出图适配器的请求格式(Qwen 与 GPT Image 使用本地假服务器)、 以及使用自定义命令跑通的完整流程。改完脚本先跑这个。
bash
node {baseDir}/scripts/selftest.mjs
230 assertions, no model calls, no quota consumption: PNG identifier read/write, check gate, input validation, multilingual confirmation forms and reports, art style presets and style switching, prompts, expiration propagation, request format of image generation adapters (Qwen and GPT Image use local fake servers), and the complete workflow run with custom commands. Run this after modifying the script.

自带样例

Built-in Examples

{baseDir}/examples/阿禾-描述.txt
是一段用户式的一句话描述(1920 年代江南采茶姑娘),
阿禾-intake.json
是拆好的输入,推断和默认的字段都标了。样例图不进版本控制,要看就使用自己的模型跑一遍。
{baseDir}/examples/阿禾-描述.txt
is a user-style one-paragraph description (1920s Jiangnan tea-picking girl),
阿禾-intake.json
is the parsed input, with inferred and default fields marked. Example images are not under version control, run it with your own model if you want to see them.