mcpField
S
story-generator

story-generator

github.com/dmccreary创意与媒体10956 次安装1 天前更新
代码仓库

关于 story-generator

这项 skill 为使用 MkDocs Material 构建的教材创作科学、数学和技术领域人物故事或虚构案例漫画,并支持自定义分格、图像提示词及通过文生图 API 生成图片。

主要功能

  1. 01创作结构化漫画叙事
  2. 02用 --panels N 设置分格数
  3. 03提供叙事文本和图像提示词
  4. 04生成封面与分格图片
  5. 05创建贴合教材主题的故事创意

适用场景

  1. 01为教材添加历史人物故事
  2. 02通过虚构案例讲解概念
  3. 03根据教材主题生成故事创意

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dmccreary/ibook-skills --skill story-generator

安装后在 Claude Code 中输入/story-generator确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
index-template.md
scripts/
fix-references.py
generate-images.py
uncomment-images.sh
verify-images.py

详细介绍

故事生成器

此技能可为使用 MkDocs Material 构建的智能教材,创作关于科学、数学和技术领域重要贡献者的完整图像小说叙事,以及虚构的案例研究故事。默认故事长度为 12 个分格加封面(共 13 张图片),但分格数量可配置:较简单的故事可以用 6–8 个分格讲述,综合性故事则可以扩展到 16 个分格。每个分格下方都包含一段叙事文字,并在可折叠的 <details> 块中提供详细的图像生成提示词。

自 2026-04 技能更新以来,此技能还可以通过多种文生图 API(包括 Google Gemini 和 OpenAI gpt-image-1),以原生 16:9(1344×768)格式自动生成每个分格的图片(1 张封面 + N 个分格)。生成高质量且文字位置准确的图片,目前每张约需 $0.039(因此,默认 13 张图片的故事约为 $0.51,6 个分格的故事约为 $0.27)。请参阅下文的“步骤 3.5:生成图片”。

--panels N 参数

此技能接受可选的 --panels N 参数,用于控制故事中的编号分格数量。封面图片始终单独生成,因此一个故事共有 N + 1 张图片。

  • 默认值: --panels 12(经典图像小说叙事弧)
  • 建议范围: 4 到 16
  • 少于 4 个: 叙事弧没有足够空间展开;请考虑是否真的需要讲述一个故事
  • 多于 16 个: 读者需要关注的图片太多;请拆分成两个故事

如何选择 N:

故事类型建议的 N
单一技巧,仅呈现前后对比6
线性发现过程(审计 → 修复 → 结果)7–8
谜团 + 揭晓 + 多步骤修复9
完整的历史人物生平叙事弧12(默认值)
多章节综合内容或总结蒙太奇14–16

用户如何调用:

用户会输入类似这样的内容:

/story-generator The Cache That Wasn't --panels 8

收到用户调用中的 --panels N 后,应将 N 视为整个工作流中统一使用的分格数量。如果没有提供 --panels 参数,则默认为 12。

无需修改脚本即可实现的原因:

generate-images.py 和 verify-images.py 都会统计 index.md 中 <details>...Image Prompt...</details> 块的数量,以确定要生成或验证多少张图片。它们不会将 12 写死。你在 index.md 中设置的分格数量,就是脚本将生成和验证的数量——无需在脚本端传入标志。

何时使用此技能

在以下情况下使用此技能:

  • 用户要求创作一部关于科学家、数学家、工程师或其他历史人物的新图像小说
  • 为任何智能教材的“故事 / 历史”章节添加故事
  • 创作包含嵌入式图像提示词的教育叙事内容
  • 用户提到关于历史人物的“故事”“图像小说”或“叙事”
  • 用户说“给我一些图像小说故事的创意” — 触发“故事创意生成器”工作流(见下文)

故事创意生成器

当用户说**“给我一些图像小说故事的创意”时,应生成一份精心策划的迷你图像小说创意列表,内容应贴合当前教材的学科主题。将结果保存到 docs/stories/story-ideas.md。每个创意都应包含一个建议的分格数量**(通常为 6 到 12),并根据故事的自然结构来选择——请参阅上文的“分格数量”指导。不要一律默认为 12;紧凑的 6–8 格故事往往比臃肿的 12 格故事更出色。

工作流
步骤 1:分析教材主题

阅读以下文件,了解教材的主题、受众和核心主题:

  1. docs/course-description.md — 课程标题、简介、目标受众和学习目标
  2. mkdocs.yml — 网站名称和导航结构,提供更多背景信息
  3. docs/learning-graph/learning-graph.csv(如果存在)— 概念列表和分类类别

提取:

  • 学科领域(例如,知识论、几何、函数、生物学)
  • 目标受众(例如,IB 学生、AP 学生、9 至 12 年级学生)
  • 课程简介和学习图中的核心主题和概念
步骤 2:生成故事创意

创建 15–20 个与教材主题相关的故事创意。每个故事创意都应是一个迷你图像小说概念,并建议包含 6 到 12 格画面(综合或总结性故事可多达 16 格)。

多样性要求——涵盖以下所有类别:

  1. 历史人物 — 与教材主题直接相关的科学家、数学家、工程师、发明家和哲学家
  2. 多元创新者 — 来自代表性不足群体的人士(女性、有色人种、全球南方贡献者),他们对该领域作出了重要贡献
  3. 科学与教条的冲突 — 人们运用证据和理性挑战宗教教条、政治正统观念或机构阻力的故事
  4. 揭露错误信息 — 人们运用科学和批判性思维,通过揭露危险谬误让世界变得更好的故事(例如,Rachel Carson 的 Silent Spring 揭露 DDT 的危害,Ignaz Semmelweis 倡导洗手)
  5. 无名英雄 — 贡献鲜为人知、却奠定了重要基础的人士
  6. 当代人物 — 当今仍在世或近期活跃、推动该领域发展的人士

每个故事创意需提供:

  • 标题 — 引人入胜且简洁的标题(例如,“寂静的春天——Rachel Carson 对抗 DDT”)
  • 主角 — 全名、出生/逝世年份、国家(虚构案例故事则提供背景设定)
  • 主题 — 核心叙事主题(例如,“挑战行业的勇气”“屡遭拒绝仍坚持不懈”)
  • 与教材的联系 — 说明故事如何关联教材中的特定概念或章节
  • 画格数 — 建议画格数(6–16 格),并用一句话说明选择该长度的理由。请参考画格数指南:单一技巧故事用 6 格,线性发现故事用 8 格,谜题加解决方案故事用 9 格,完整人生历程故事用 12 格,综合蒙太奇故事用 14–16 格。用户在调用此技能时可以通过 --panels N 覆盖此设置。
  • 故事梗概 — 用 2–3 句话描述贯穿建议画格的故事情节
  • 故事的启发之处 — 用 1 句话说明年轻读者为何会产生共鸣
步骤 3:设置格式并保存

使用以下格式将故事创意保存到 docs/stories/story-ideas.md:

# Story Ideas for {Book Title}

These mini-graphic novel ideas are designed to inspire young
readers by connecting the subject matter of this textbook to
the real people who shaped the field. Each story can be
generated using the `/story-generator` skill, with the
suggested panel count or your own override via `--panels N`.

## Selection Criteria

Stories were selected for:

- **Relevance** — direct connection to the textbook's key concepts
- **Diversity** — range of backgrounds, cultures, genders, and time periods
- **Inspiration** — themes that resonate with the target audience
- **Drama** — compelling narrative arcs with conflict and resolution

## Story Ideas

### 1. {Title}

| | |
|---|---|
| **Subject** | {Full Name} ({birth}–{death}), {country} |
| **Theme** | {Central narrative theme} |
| **Connection** | {How it connects to specific textbook concepts} |
| **Panels** | **{N}** — {one-line rationale for that length} |

{2-3 sentence synopsis}

*Why this inspires:* {1 sentence}

---

### 2. {Title}

...

## How to Generate a Story

To turn any of these ideas into a full graphic novel with
generated images, use:

> /story-generator {Story Title} --panels {N}

Provide the subject's name (and optionally `--panels N` to
override the suggested count) and the skill will handle the
rest — writing the narrative, creating image prompts, and
optionally generating all panel images via multiple
text-to-image APIs (Google Gemini, OpenAI gpt-image-1, or
others). Current cost for high-quality images with accurate
text placement is
approximately **$0.039 per image**, so $0.039 × (N + 1) per
story — about $0.27 for 6 panels, $0.51 for 12 panels.
步骤 4:更新导航

在 mkdocs.yml 的 Stories 部分添加故事创意页面:

- Stories:
    - Overview: stories/index.md
    - Story Ideas: stories/story-ideas.md
    # ... individual stories follow
示例:知识理论

对于一本知识理论教材,故事创意可能包括:

  1. "寂静的春天" — Rachel Carson 奋力揭露 DDT 的危害(科学与行业误导信息之争)
  2. "星际信使" — Galileo 的望远镜,以及他与地心说教条的斗争
  3. "洗去死亡" — Ignaz Semmelweis 倡导洗手,却遭到医学界拒绝
  4. "破解秘密" — Rosalind Franklin 对 DNA 进行 X 射线晶体学研究,却未获署名
  5. "提灯女士" — Florence Nightingale 运用统计证据改革军队医院
  6. "用图像思考" — Temple Grandin 通过神经多样性的感知重新设计动物处理方式
  7. "疫苗先驱" — Edward Jenner 的天花疫苗克服了公众的恐惧和迷信
  8. "绘制霍乱地图" — John Snow 的数据可视化证明了疾病通过水传播
  9. "大胆的假设" — Alfred Wegener 的大陆漂移理论遭到数十年拒绝,最终得到证实
  10. "隐藏人物" — Katherine Johnson 的计算帮助宇航员进入太空,尽管她面临种族障碍

每个故事都遵循一致的结构,旨在吸引青少年和年轻读者:

必备组成部分
  1. YAML Frontmatter — 标题、描述、Open Graph 图片路径
  2. 封面图 — 在 <details> 块中附带详细的生成提示词
  3. 叙事提示词 — 整个故事的背景信息
  4. 序章 — 以引人入胜的方式介绍主人公的重要性
  5. 独立的人物介绍 — 在叙事中首次提及每位具名人物之前,先以叙事文字介绍他们
  6. 12 个分镜 — 每个分镜都包含叙事文本、图片占位符和图片提示词
  7. 尾声 — 经验教训表格(挑战 / 应对方式 / 给当今的启示)
  8. 行动号召 — 联系读者的鼓舞人心的信息
  9. 引言 — 主人公的 2-3 条令人难忘的引言
  10. 参考资料 — 5 个真实可用的 URL(前 3 个来自 Wikipedia,其余来自二手资料)。切勿使用 (PLACEHOLDER)。

完整结构的模板位于 references/index-template.md。

YAML Frontmatter

使用 Open Graph 协议进行社交媒体分享:

---
title: <Catchy Title> - <Subject Name>'s <Theme>
description: A graphic-novel story of how <brief description>...
image: /stories/{story-dir-name}/cover.png
og:image: /stories/{story-dir-name}/cover.png
twitter:image: /stories/{story-dir-name}/cover.png
social:
   cards: false
---

其中 {story-dir-name} 是 kebab-case 格式的目录名称。

长度指南:

  • 标题:最多 60-70 个字符(标题过长会在社交媒体上被截断)
  • 描述:155-200 个字符(1-2 个简洁有力的句子)
图片提示词要求

每条图片提示词都必须指定:

  • 每条提示词正文都以分镜标识行开头:
    • 封面:(This is the Cover Image. Do not include this label in the image.)
    • 分镜:(This is Panel N. Do not include the panel number in the image.),其中 N 是分镜编号
  • 横向宽屏 16:9 格式(generate-images.py 脚本会通过 API 配置传入该格式——提示词中的文字是重复说明,但无害)
  • 符合时代背景的艺术风格(见下方的艺术风格参考表)
  • 具体人物的外貌特征和服装
  • 包含年份和地点的具体场景
  • 色彩搭配指导
  • 情感基调和氛围
  • 每条提示词至少包含 6 个具体的视觉细节,以指导生成并避免产出泛泛的图像
  • 以此句结尾:Generate the image immediately without asking clarifying questions.

generate-images.py 脚本会直接从故事的 index.md 中解析 <details><summary>Image Prompt</summary>...</details> 块,因此块结构至关重要——不要更改 HTML 结构。

工作流

有些故事讲述历史人物,有些则围绕虚构场景或概念展开。两者的工作流相同,但研究和写作过程略有不同。

步骤 1:收集信息并规划故事

动笔前,确定:

  • 主题人物的全名及生卒年份
  • 所属国家和历史时期
  • 重要发现、贡献或人生经历
  • 核心主题(例如“在失败中坚持不懈”或“看见他人未能察觉之事”)
  • 适合该时代的艺术风格
  • 3–5 个关键人生经历(虚构故事则为故事节点),用于构成 N 个分镜(默认 N=12)。每 2–3 个分镜安排一个故事节点——6 格故事通常有 3 个节点,12 格故事通常有 4–6 个节点。如果指定了 --panels N,此处使用该 N 值。
步骤 2:创建故事目录
mkdir -p docs/stories/{story-dir-name-in-kebab-case}

目录名使用 kebab-case(小写字母,以连字符分隔):ada-lovelace、rene-descartes、marie-curie。切勿使用空格或下划线。

步骤 3:编写故事

根据 references/index-template.md 中的模板创建 docs/stories/{story-dir-name}/index.md。

主要约定:

  • N 个编号分镜加 1 张封面图 = 共 N + 1 张图片(默认 N = 12,可用 --panels N 覆盖)
  • 分镜从 panel-01 到 panel-NN 连续编号,不得缺号或多号
  • 每行分镜标识都应使用“panel X of N”格式,并填入该故事实际的 N 值(例如,6 格故事中的“panel 3 of 8”就是错误的——每个提示词中的分母都必须等于分镜总数)
  • 所有图片引用均使用 .png 扩展名
  • 分镜图片提示词需用 <details><summary>Image Prompt</summary>...</details> 块包裹
  • 封面图片提示词需用 <details><summary>Cover Image Prompt</summary>...</details> 块包裹
  • 每段提示词正文都以分镜标识行开头(参见“图片提示词要求”)
  • 叙事段落放在每个分镜图片下方(而非 <details> 块内)
  • 每个故事都应独立成篇。在叙事正文中首次提及每个具名角色之前,先添加一个简短句子,说明角色的全名及其通俗易懂的身份或与故事的关系。每个故事中都要重新介绍反复出现的角色。封面信息、标题、图片提示词、说明文字、角色设定表和之前的故事均不计入。具名吉祥物或向导也应在叙事中首次提及前以相同方式介绍。
  • 参考资料:提供 5 个真实 URL,绝不可使用 (PLACEHOLDER)——参见下方“参考资料指南”一节

references/index-template.md 中的模板展示了标准的 12 格布局。 对于更短或更长的故事,遵循相同的逐格模式,并在第 N 格结束。不要为了凑足 12 格而填充无关内容——紧凑的 6 格故事胜过冗长的 12 格故事。

第 3.5 步:生成图像(可选但推荐)

编写完 Markdown 后,使用 scripts/generate-images.py 自动生成 N + 1 张分镜图。该脚本会根据 index.md 中的 <details>...Image Prompt...</details> 区块自动检测分镜数量,因此无需向脚本传递 --panels N——Markdown 中写了多少就会生成多少。

前置条件:

  1. Python 包:

    pip install google-genai
    
  2. API 密钥——前往 https://aistudio.google.com/apikey 免费获取,然后:

    export GEMINI_API_KEY="your-key-here"
    

    如需持久保存,请将其添加到 ~/.zshrc 或 ~/.bashrc。免费套餐无需信用卡,也无需计费账户。

首次运行——先验证封面图,再消耗额度生成另外 12 张图:

python3 ~/.claude/skills/story-generator/scripts/generate-images.py \
    docs/stories/{story-dir-name} --first-only

这只会生成封面,通过 sips 验证其是否为 16:9,并在宽高比不正确时自动中止。请目视检查封面——它是否符合你想要的艺术风格和构图?如果符合,就继续完整运行。

完整运行:

python3 ~/.claude/skills/story-generator/scripts/generate-images.py \
    docs/stories/{story-dir-name}

这会以原生 1344×768(16:9)生成全部 N + 1 张图像(封面 + N 张分镜图)。在 10 RPM 速率限制下,预计耗时约为 6 × (N + 1) 秒——默认的 12 格故事约需 90 秒,6 格故事约需 45 秒。每张图像生成后都会立即验证。

常用标志:

标志用途
--first-only只生成封面图(检查宽高比和风格)
--skip-existing跳过 PNG 文件已存在的图像(可安全重试)
--rpm N覆盖默认的 10 RPM 速率限制(在配额更高的付费套餐中使用)
--aspect-ratio W:H覆盖默认值 16:9。支持:21:9、16:9、4:3、3:2、1:1、9:16、3:4、2:3、5:4、4:5

脚本生成的内容:

  • docs/stories/{story-dir-name}/cover.png 和 panel-01.png 至 panel-12.png 中的 PNG 文件
  • 每个故事对应的 Markdown 日志 logs/{story-dir-name}-{YYYY-MM-DD}.md,包含运行元数据、汇总统计、逐图表格和提示词摘录
  • 每张图像都会在 logs/image-generation-usage.jsonl 中追加一条 JSONL 审计记录(时间戳、令牌数、计算费用)

如果图像生成失败:

脚本会捕获安全过滤器导致的失败和 API 异常,记录原因(包括 finish_reason 和安全评级),然后继续生成下一张图像。失败的图像会被跳过,不会导致流程中止。运行完成后,使用 --skip-existing 重新运行,只重试失败的图像。有关如何弱化触发安全过滤器的提示词,请参阅下文的“安全过滤器模式”一节。

第 4 步:验证图像

生成完成后,运行验证脚本,确认每张图像都存在且宽高比正确:

python3 ~/.claude/skills/story-generator/scripts/verify-images.py \
    docs/stories/{story-dir-name}

这是只读审计——只进行检查,不会修改任何内容。退出代码 0 表示没有问题,1 表示发现问题。尤其适用于:

  • 发现旧版 Antigravity 工作流遗留的正方形图像
  • 验证部分运行后 13 张分镜图是否都已生成
  • 提交前钩子
第 5 步:添加到导航

编辑 mkdocs.yml,按主题人物的出生年份按时间顺序添加故事:

- Stories:
    - Overview: stories/index.md
    - <Subject Name> - <Title>: stories/<subject-name>/index.md

时间顺序示例(请根据你的项目调整):

  • 阿基米德(公元前 287 年)
  • 伽利略(1564 年)
  • 笛卡尔(1596 年)
  • 牛顿(1643 年)
  • 欧拉(1707 年)
  • 傅里叶(1768 年)
  • 法拉第(1791 年)
  • 洛夫莱斯(1815 年)
  • 麦克斯韦(1831 年)
  • 特斯拉(1856 年)
  • 玛丽·居里(1867 年)
  • 爱因斯坦(1879 年)
  • 诺特(1882 年)
  • 拉马努金(1887 年)
  • 图灵(1912 年)
第 6 步:在故事索引中添加网格卡片

编辑 docs/stories/index.md,使用 MkDocs Material 网格格式添加卡片:

- **[<Story Title>](<subject-name>/index.md)**

    ![<Subject Name>](./<subject-name>/cover.png)
    <2-4 sentence compelling description emphasizing the story's theme>
第 7 步:复用其他教材中的故事

如果某个故事已经存在于另一个智能教材项目中(例如,在生态学教材中复用认识论故事),应链接到源教材已发布网站上的故事,而不是复制一份。每个故事约有 170 行 Markdown 和 13 张生成的图片(1 张封面 + 12 张分镜)——在不同教材中重复复制这些内容只会增加不必要的体量,没有任何价值。

策略:只复制封面图片,并链接到外部故事。

# Copy ONLY the cover image from the source project into the current project
mkdir -p docs/stories/<subject-name>
cp /path/to/other-textbook/docs/stories/<subject-name>/cover.png \
   docs/stories/<subject-name>/cover.png

封面图片必须保存在本地,这样在开发期间运行 mkdocs serve 时才能正常显示。不要使用外部图片 URL——它们无法在本地显示,还会造成对其他网站的依赖。

故事标题链接应指向源教材网站上的已发布 URL:

- **[<Story Title>](https://dmccreary.github.io/<source-book>/stories/<subject-name>/)**

    ![<Subject Name>](./<subject-name>/cover.png)
    <2-4 sentence compelling description>

在交叉链接故事的网格上方添加读者提示,避免学生跳转到其他网站时感到困惑。提示只需添加一次,放在网格前面——不要放在每张卡片上:

*Clicking a card below will take you to the <Source Book Name> site, where the
full story and all 12 panel images are hosted. Use your browser's back button
to return here. We link rather than duplicate because each story includes 13
generated images — copying them across textbooks would add unnecessary bulk
without adding value.*

不要将完整的故事 Markdown 或 12 张分镜图片复制到当前项目中。只需在本地复制封面图片。

参考资料指南

在初稿中填写有效的真实 URL。不要使用 (PLACEHOLDER)。

每个故事都遵循标准的 5 条参考资料模式:

#来源用途
1Wikipedia:<人物传记>完整的传记文章
2Wikipedia:<主要贡献>此人的代表性发现或作品
3Wikipedia:<相关概念或作品>第二个主题链接(例如,与此人相关的发明、以其命名的方程、重要论文)
4MacTutor(数学家)、Nobel Prize(获奖者)、NASA(任务科学家)或同等机构的传记稳定的学术历史资料来源
5Encyclopaedia Britannica 或 Stanford Encyclopedia of Philosophy精选的参考概览

示例——Ada Lovelace:

## References

1. [Wikipedia: Ada Lovelace](https://en.wikipedia.org/wiki/Ada_Lovelace) - Biography of the English mathematician often called the first programmer
2. [Wikipedia: Analytical Engine](https://en.wikipedia.org/wiki/Analytical_Engine) - Babbage's proposed mechanical general-purpose computer
3. [Wikipedia: Note G](https://en.wikipedia.org/wiki/Note_G) - Lovelace's note describing the first published algorithm
4. [MacTutor: Augusta Ada King, Countess of Lovelace](https://mathshistory.st-andrews.ac.uk/Biographies/Lovelace/) - University of St Andrews history of mathematics archive
5. [Encyclopaedia Britannica: Ada Lovelace](https://www.britannica.com/biography/Ada-Lovelace) - Overview of Lovelace's life and contributions to computing
修复带有 PLACEHOLDER URL 的旧故事

部分在 2026-04 技能更新前生成的故事仍包含 (PLACEHOLDER) 参考资料 URL。若要批量清理,请将 scripts/fix-references.py 复制到项目的 src/ 目录,编辑顶部的 REFS 字典,列出故事及其精选 URL,然后运行脚本:

cp ~/.claude/skills/story-generator/scripts/fix-references.py src/stories/
# Edit src/stories/fix-references.py to fill in the REFS dict
python3 src/stories/fix-references.py

该脚本会重写所列每个故事的 index.md 中从 ## References 标题到文件末尾的所有内容。可以安全地重复运行。

此脚本有意不设计为通用脚本——精选优质参考资料需要作出判断,而且每个项目需要的来源略有不同。维护一份项目本地的自定义副本才是正确做法。

安全过滤器模式

Gemini 2.5 Flash Image 会拒绝触发其安全分类器的提示词。响应中会显示 finish_reason=FinishReason.IMAGE_SAFETY,脚本会记录该信息,并继续处理下一张图像,不会崩溃。

已知触发因素:

  • 明确的纳粹图像(卐字标志、纳粹旗帜、党卫军制服)
  • 血腥暴力、伤口或血液
  • 裸露或色情内容
  • 未成年人处于明确令人痛苦的场景中
  • 描绘真实人物遭到杀害或折磨

弱化模式 —— 重写提示词,在保留情绪分量的同时移除触发因素:

原文(会触发过滤器)弱化后(通常有效)
"建筑上挂着纳粹旗帜""有光秃树木的灰色空街道"
"信上的卐字印章""信上的普通火漆印章"
"因纳粹法律被迫离开""准备离开德国"
"地板上的血迹""地板上的一件破损物品"
"被行刑队处决""他空荡荡的办公桌和翻倒的椅子"

案例研究——Emmy Noether 第 10 幅分镜(2026-04-05): 原始提示词明确提到了“远处建筑上挂着纳粹旗帜”和“盖有卐字印章的解雇信”。Gemini 以 IMAGE_SAFETY 拒绝生成。将提示词弱化为“有光秃树木的灰色空街道”和“盖有普通火漆印章的政府解雇信”后,下一次尝试便成功生成了干净的图像。被迫流亡的历史意义得以保留,明确的象征符号则已移除。

提示词被拦截时的工作流:

  1. 脚本记录失败并继续运行,不会崩溃
  2. 在故事的 index.md 中编辑有问题的提示词,弱化触发词
  3. 重新运行:python3 generate-images.py docs/stories/<name> --skip-existing
  4. 只会重新生成之前失败的分镜;其他分镜都会跳过
  5. 提交弱化后的提示词,确保今后重新生成时能一次成功

成本分析

Gemini 2.5 Flash Image 定价(经核实,2026 年初):

  • 输入文本 Token:每 100 万个 $0.30
  • 输出图像 Token:每 100 万个 $30.00
  • 固定费率:每张图像 1,290 个输出 Token = 付费层级下 每张图像 $0.039

免费层级(注意——请参阅下方警告):

  • 每天 500 个请求(RPD)
  • 每分钟 10 个请求(RPM)
  • 每分钟约 250,000 个 Token(TPM)
  • 宣称无需信用卡,无需结算账号

警告:“免费层级”可能不支持图像生成(截至 2026 年 4 月)。 在 2026-04-06 测试时,新创建的 Google AI Studio 免费层级项目调用 gemini-2.5-flash-preview-image 时返回 RESOURCE_EXHAUSTED,并显示 limit: 0。这意味着免费层级项目的图像生成模型配额为零——这不是速率限制或临时上限,而是硬性零配额。只有启用了第 1 层后付费结算(需要信用卡)的项目才能成功生成图像。免费层级可能可用于纯文本 Gemini 调用,但似乎无法用于图像生成。这与下方早先的文档以及 Gemini 文档相矛盾。如果 Google 恢复免费层级的图像生成功能,可以移除此警告。

成本预测(仅限付费层级——目前免费层级无法用于图像):

每个故事的成本随分格数量线性增长:N 格故事的费用为 $0.039 × (N + 1)。

范围图像数付费层级费用
6 格故事(1 张封面 + 6 格)7~$0.27
8 格故事(1 张封面 + 8 格)9~$0.35
默认 12 格故事(1 张封面 + 12 格)13$0.51
16 格故事(1 张封面 + 16 格)17~$0.66
一本 14 个故事的教科书(全部为默认 12 格)182~$7.10
一本 14 个故事的教科书(混合篇幅:平均 8 格)~126~$4.91
一本 16 个故事的教科书(全部为默认 12 格)208~$8.07

支出上限警告: Google AI Studio 的第 1 层后付费项目可设置每月支出上限(默认值因项目而异)。上限生效可能最多延迟 10 分钟,因此超支几个百分点的情况可能发生。请在 https://aistudio.google.com/spend 监控支出。上限会在每月 1 日(PST)重置。如果运行过程中达到上限,脚本会记录每次失败并继续运行——提高上限后,使用 --skip-existing 重新运行。

建议: 每个故事按 $0.039 × (N + 1) 预留预算——默认 12 格篇幅的故事约需 $0.50,紧凑的 6 格故事则不到 $0.30。一本由默认篇幅故事组成的 14 个故事的教科书约需 $7;每个故事平均 8 格的混合篇幅教科书约需 $5。请将支出上限设为至少达到预期的月度总支出,并留出少量缓冲,以应对超支。

备选模型(适用于高产量制作)

如果持续超过每个项目每天 500 张图像,也有更便宜的选项,但质量各有差异:

模型提供方每张图像的大致费用备注
FLUX.1 [schnell]Fal / Replicate$0.003便宜 13 倍,质量不错,不支持原生 16:9 配置
FLUX.1 [dev]Fal / Replicate$0.025中等价位,质量出色
SD 3.5 MediumStability AI~$0.035与 Gemini 相当
gpt-image-1 (low)OpenAI$0.011便宜 3 倍,质量较低,宽高比选项有限
Local SDXL / FLUX可自托管 GPU~免费需要 16 GB 以上 VRAM 和配置时间

客观评估: 对于此技能面向的使用规模,Gemini 2.5 Flash Image 仍是性价比最高的选择。只有每个项目每天超过 500 张图像时,备选方案才值得考虑,而现实中的教科书工作流都不会达到这个规模。

已知问题

免费版不支持图像生成(截至 2026 年 4 月)

新创建的 Google AI Studio 免费版项目对 gemini-2.5-flash-preview-image 的配额为 零。API 会返回 RESOURCE_EXHAUSTED,并显示 limit: 0——这不是速率限制,而是配额确实为零。我们于 2026-04-06 在两个独立的免费版项目中验证了这一点。只有启用了 Tier 1 Postpay 计费(需要信用卡)的项目才能生成图像。这似乎与生成函数教科书时的情况不同。如果你在新项目中看到 limit: 0 错误,解决方法是在 https://aistudio.google.com/billing 启用计费,而不是等待或重试。

消费上限可能会在不提示的情况下阻止生成

Google AI Studio 中的 Tier 1 Postpay 项目可以设置每月消费上限。达到上限后,所有 API 调用都会返回 RESOURCE_EXHAUSTED,并显示消息“Your project has exceeded its spending cap.”。generate-images.py 脚本会记录此错误并继续运行(非致命),但不会生成任何图像。上限生效最多可能延迟 10 分钟,因此超出几个百分点属于正常情况。请在 https://aistudio.google.com/spend 监控并调整上限。上限会在每月 1 日(PST)重置。

Antigravity 的 generate_image 工具未提供 aspect_ratio

Google Antigravity IDE 内置了一个 generate_image 工具,其架构仅接受 Prompt、ImageName、ImagePaths 和工具元数据。它不提供 aspect_ratio 或 size,因此生成的图像默认都是 1:1 正方形。**请勿使用 Antigravity 的 generate_image 生成图像小说分格。**请改用 scripts/generate-images.py(此技能)——它通过 google-genai 直接调用 Gemini,并传入 ImageConfig(aspect_ratio="16:9")。

在提示词中写“16:9 横向电影构图”等变通方法不起作用——Gemini 会遵循 ImageConfig.aspect_ratio,但最多只会把提示词中的宽高比提示视为风格建议。

值得反馈:Antigravity 团队应提供 Gemini 支持的全部 10 种宽高比(21:9、16:9、4:3、3:2、1:1、9:16、3:4、2:3、5:4、4:5),并最好支持 response_modalities 和透明 PNG 选项。

各分格间角色面部的一致性

Gemini 2.5 Flash Image 能在使用相似提示词进行多次生成时保持风格连续性(艺术风格、配色、氛围),但无法让同一角色的面部特征完全一致。第 3 格中的 Marie Curie 在风格上会与第 5 格中的 Marie Curie 相似,但两者不会完全相同。对于分格按顺序阅读、并在下方配有旁白的教育类图像小说,这通常可以接受。对于要求角色面部像素级一致的专业作品,可考虑 Flux Kontext、使用参考图像的 Imagen 4,或经过微调的角色 LoRA。这不在此技能的范围内。

仅使用第一段图像内容

如果 Gemini 在单个响应中返回多段图像内容(虽然少见,但有可能),脚本只会保存第一段。不支持多图像响应。

按时代划分的艺术风格参考

时代建议的艺术风格
古代(公元 500 年以前)古典地中海风格,马赛克风格
文艺复兴(1400-1600)意大利文艺复兴风格,暖色光线
启蒙时代(1600-1800)巴洛克风格,荷兰黄金时代风格
拿破仑帝国时期(1795-1815)帝国时期法国学院派绘画
维多利亚时代(1800-1900)前拉斐尔派风格,工业风格
镀金时代(1870-1900)新艺术风格,美国工业风格
早期现代(1900-1950)装饰艺术、现代主义、包豪斯风格(适用于魏玛时期的德国)
二战时期(1939-1945)20 世纪 40 年代黑色电影风格,低饱和橄榄绿/卡其色
世纪中叶(1950-1980)原子时代风格,线条简洁,贝尔实验室现代主义风格
太空时代(1957-1975)NASA 技术插画,宇宙蓝色调
当代(1980 年至今)融入时代元素的写实风格

写作指南

目标受众
  • 大多数智能教科书项目面向中学生(9—12 年级,14—18 岁)
  • 根据项目调整阅读难度——这项技能支持面向年龄较小或较大的受众,只需改变叙述语气,无需改变结构
叙事风格
  • 使用主动语态和生动的描述
  • 让每个故事都能独立成篇:在叙述中使用人物简称之前,先介绍每位具名人物的全名和身份
  • 在符合历史背景的情况下加入对话
  • 兼顾戏剧性与教育内容的准确性
  • 突出发现背后的人物故事
  • 展现挣扎、失败和坚持
  • 将历史事件与现代技术或当代意义联系起来
主题发展

选择一个能引起目标受众共鸣的核心主题:

  • 克服质疑者和怀疑者的阻挠
  • 在失败中坚持
  • 自学与好奇心
  • 反抗歧视
  • 看见他人看不到的事物
  • 成功后依然保持谦逊
  • 让不可见之物变得可见
历史准确性
  • 调查关键日期、事件和人物关系
  • 在图像提示词中使用符合历史的细节(服装、建筑、技术、排版)
  • 在 Narrative Prompt 区块中注明任何创作性改编
  • 尽可能收录可核实的引语

脚本

generate-images.py(主要脚本)

通过 Gemini API 生成所有分镜图片。请参阅上文的“步骤 3.5:生成图片”。

verify-images.py

只读审查工具——检查所有预期分镜图片是否存在、宽高比是否正确,以及是否达到最小文件大小。用法:

python3 ~/.claude/skills/story-generator/scripts/verify-images.py \
    docs/stories/{story-dir-name}
fix-references.py(旧版修复工具)

用于追溯替换旧故事中的 (PLACEHOLDER) 参考链接。不适用于新故事——新故事应在初稿中使用真实链接。请参阅上文的“参考资料指南”部分。

uncomment-images.sh(备用工作流)

对于推迟生成图片的工作流:Markdown 中的图片引用会包在 HTML 注释(``)中,以避免显示损坏的图片图标;待以任何方式生成 PNG 后,此脚本会取消注释。

用法:

~/.claude/skills/story-generator/scripts/uncomment-images.sh \
    docs/stories/{story-dir-name}/index.md

适用情况:

  • 你想立即发布 Markdown,之后再通过批处理作业生成图片
  • 你使用的图片生成工具不是 generate-images.py
  • 你正在从旧版工作流迁移

不适用情况:

  • 你使用 generate-images.py——它会直接将 PNG 写入 index.md 中引用的文件名,因此无需取消注释

检查清单

完成一个故事后,请验证:

内容:

  • 已创建故事目录:docs/stories/<name>/
  • index.md 包含完整叙述和全部 N + 1 条图像提示词(封面 + N 个分镜,其中 N 与 --panels 参数一致,或默认为 12)
  • 分镜按 panel-01 到 panel-NN 连续编号,没有遗漏
  • 每一行“panel X of N”标识都使用本故事的实际 N(而不是遗留的 12)
  • 所有图像引用都使用 .png 扩展名(绝不使用 .jpg 或 .md)
  • YAML 前置内容包含标题、描述以及 og/twitter 图像路径
  • N 个编号分镜的结构一致(图像 + 提示词 + 叙述)
  • 每位具名角色都在首次出现在叙述中之前,以全名和通俗易懂的身份介绍;无需借助此前的故事、图像提示词或角色设定表即可理解其身份
  • 尾声包含“挑战 / 回应 / 教训”表格
  • 包含 2-3 条相关人物引言(虚构故事则为角色引言)
  • 参考资料部分包含 5 个真实有效的网址,前 3 个来自 Wikipedia,且不含 (PLACEHOLDER) 字符串

图像生成(如果使用 generate-images.py):

  • 已在环境中设置 GEMINI_API_KEY
  • 已完成 pip install google-genai
  • 已运行 generate-images.py --first-only,并确认封面原生比例为 16:9(1344×768)
  • 已完整运行 generate-images.py,没有致命错误
  • 故事目录中存在全部 N + 1 个 PNG 文件
  • verify-images.py 以代码 0 退出
  • 存在每个故事对应的日志:logs/{story-name}-{YYYY-MM-DD}.md
  • 已更新 JSONL 使用情况日志:logs/image-generation-usage.jsonl

集成:

  • 已按出生年份的时间顺序添加到 mkdocs.yml 导航中
  • 已将网格卡片添加到 docs/stories/index.md
  • 已提交任何安全过滤器的放宽调整,避免未来重新生成时出现回归
  • 任何图像提示词中都不含真实品牌名、产品名或商标(叙述文字中可以出现品牌)

附录:从 IB 函数教材中吸取的经验(2026-04-05)

2026-04 技能更新源于一个真实项目:在 /Users/dan/Documents/ws/functions 制作一本包含 16 个故事的教材。完整的案例研究见 /Users/dan/Documents/ws/functions/logs/stories.md。以下是总结的关键经验:

  1. 旧工作流生成的是方形图片。 故事是通过 Antigravity IDE Agent 的 generate_image 工具生成的,该工具不提供 aspect_ratio 参数,默认比例为 1:1。解决方法是将方图放大到 1280×1280,然后居中裁剪为 1280×720——垂直内容损失约 44%。解决方案是绕过 Antigravity,直接通过 google-genai 调用 Gemini;现在 scripts/generate-images.py 就是这样做的。

  2. 免费层确实免费。 (2026-04-06 更正。) 最初的函数教材(208 张图片)可能是在免费层图像生成可用期间生成的,但截至 2026 年 4 月,新建的免费层项目对 gemini-2.5-flash-preview-image 返回 limit: 0。只有 Tier 1 Postpay 项目(需要信用卡)才能生成图片。一本包含 14 个故事的教材(知识论,182 张图片)在 Tier 1 Postpay 上的费用约为 $11。目前,免费层无法用于图像生成。预算约为每个故事 $0.50。

  3. 安全过滤器不常触发,但会造成影响。 在生成的 208 张图片中,恰有 1 张被直接拦截(Emmy Noether 第 10 格,因为包含明确的纳粹图像),另有 1 张被暂时拦截(Mirzakhani 第 10 格,未作任何更改,重试后即通过)。脚本现在能妥善处理这两种情况,上文也记录了适用于 Noether 类内容的弱化处理方式。

  4. 占位符引用是个陷阱。 最初发布的全部 16 个故事都带有早期版本技能留下的 (PLACEHOLDER) URL。事后修复这些引用需要编写 fix-references.py 脚本。新故事的初稿应当包含真实 URL——本技能现在已明确说明这一点。

  5. 每次运行都记录审计日志,值得多写几行代码。 JSONL 审计日志捕捉到了一个原本难以察觉的细节:无论提示词多复杂,每张图片的输出计费都恰好是 1,290 个 token。这证实了已公布的定价模式,也让用户确信大规模使用时的成本预测会准确。

  6. 以目前的价格,角色面部一致性尚未解决。 参见上文“已知问题”。用户不应期待角色在 12 格中做到像素级一致——以当前每张图片 $0.039 的技术水平,只能让角色在风格上保持一致,但每个角色仍各不相同。对于大规模制作教育类图像小说,这是可以接受的取舍;对于专业商业出版,则不可接受。

  7. 免费层不再支持图像生成(2026-04-06)。 在制作知识论教材期间,Tier 1 Postpay 生成了 78 张图片,之后触及 $10 的支出上限。尝试新建免费层项目以继续生成时发现,所有免费层项目的 gemini-2.5-flash-preview-image 的 limit 都为 0。这与上文第 2 条经验相矛盾;第 2 条来自函数项目,该项目可能是在免费层图像生成可用期间生成的。技能文档已更新,提醒用户图像生成需要付费结算。预算约为每个故事 $0.50,整本教材约为 $7–8。

如果你今后要更新此技能,请阅读函数项目中的 logs/stories.md,了解完整的会话记录,以及当前设计背后的所有决策。

评论

支持 Markdown