zenstory-ai/oh-story-claudecode검사 통과
SKILL DETAIL
story-long-write
zenstory-ai/oh-story-claudecode/story-long-write
长篇网文写作。从大纲到正文,辅助长篇网络小说的创作,包括世界观、人物、情节线管理。触发方式:/story-long-write、/写长篇、「帮我开书」「写大纲」「日更」「续写」「继续写」「修改第X章」「回炉」「重写第X章」。
설치 수 · 91출처 보기
Installation
npx skills add https://github.com/zenstory-ai/oh-story-claudecode --skill story-long-write
스킬 파일
SKILL.md
최근 동기화 · 2026. 8. 30.
references/anti-ai-writing.md›
# 去AI味完整指南
<!-- 同名副本×5 字节同步,改动后跑 scripts/check-shared-files.sh -->
> 识别AI写作指纹、系统性去AI三遍法、禁用词约束、改写范例库。用于正文写作后做去AI味自检和改写时查阅。
---
## 决策路由
| 你在做什么 | 查阅哪个模块 |
|-----------|-------------|
| 写完正文后做去AI自检 | 核心规则 -> AI写作模式检测 -> 质量维度检查 |
| 改写某段AI味重的文字 | 改写范例库 + 冲突对话改写范例 |
| 检查是否用了禁用词 | 禁用词与句式速查 -> AI高频词(模式1) |
| 系统性去除整章AI味 | 系统性去AI三遍法 |
| 检查章尾是否有总结升华 | AI写作指纹 -> 章末总结体 |
| 判断情绪描写是否告知式 | Show Don't Tell原则 + 去AI味补充技法 |
| 快速扫描全章质量 | 快速自检口诀 + 质量维度检查 |
## 指令语气
本文件以问题模式和高危清单为主。一级高危词优先检查;二级/语境敏感词按频率、语境和是否偷懒判断。遇到冲突时,保留创作意图与剧情功能优先于机械替换。
---
## AI写作指纹(必须避免)
### 高频AI用词
> 完整禁用词表见 [banned-words.md](banned-words.md)
**补充类目**(`banned-words.md` 未覆盖的高阶替换):
| 类别 | 替代原则 |
|------|---------|
| 抽象升华词(命运、宿命、注定) | 用具体事件代替抽象概念 |
| 万能比喻(像潮水般、如闪电般、仿佛春风) | 优先不用比喻,确需时只留少数生活化、角色化比喻 |
### 引号只承载真实引用,不给普通名词加戏
不要用双引号给普通名词、常见动作或作者临时概括的概念做“引号强调”。这类写法会把没有特殊含义的词硬包装成术语,连续出现时尤其像模型在替读者划重点。`check-ai-patterns.js` 的 `quote-emphasis-tic` 只负责提示,最终按语境判断。
- **应改**:所谓的"机会"、完成这次"蜕变"、找到真正的"答案"。这些词若只是普通语义,直接去掉引号,用事件本身体现分量。
- **应保留**:角色对话、逐字直接引用、书名/篇名、确有设定含义的代号,以及手机消息、公告、系统播报等场内载体展示的原文。
- **边界**:第一次定义术语时可以用引号,但后文不要反复加;讽刺、反话或角色刻意咬重音时可以保留,前提是上下文能看出是谁在强调、为什么强调。
### 章末总结体
**禁止**在章节结尾用以下方式收束:
- 总结性感悟("他终于明白了……")
- 升华式感叹("这一夜,注定无人入眠")
- 哲理式收尾("人生就是这样……")
- 伏笔式预告("他不知道的是,更大的风暴即将来临")
**正确做法**:章尾用动作、对话或悬念收束,让情节本身制造余韵。
### 叠加式描写(同一动作掰开写三遍)
**检测模式**:一个动作/情绪先写发生,再补感知细节,再补身体反应,分三段依次写完。读者看到的是同一个动作被掰开写了三遍。
**典型特征**:
- 先写一个概括性动作,再展开写同一动作的细节,再写身体反应:三段说的是同一件事
- "发生层→感知层→反应层"按顺序分段出现
- 每个维度独立成段,而不是揉进同一段连续正文
**错误示例**:
> 林父低着头,左手把文书压住,右手拿笔,往纸上落。
>
> 手从肘到腕都在抖。
>
> 笔尖在纸上停了停,写了一横,又停。那个"林"字的撇写歪了。
→ 同一个动作(手抖/写字)分三段写,每段是同一瞬间的不同维度
**正确做法**:发生、感知、反应三个维度揉进同一段连续正文,读者读到一个完整瞬间:
> 林父左手压着文书,右手拿笔往纸上落,笔尖一触纸面就偏了,从肘到腕止不住地抖,那一横斜着拖出去。
→ 发生、感知、反应在一段里同时呈现
**处理原则**:保留有功能的情绪细节,把同一瞬间的重复描写合并成连续画面。若合并后明显变薄,优先恢复原文中有功能的信息,或把既有信息改成更自然的动作/对话表达;不要新增原文没有的情节、设定、关系或时间线。
---
## 核心规则
> **句长以规则 3 为准**:规则 1-4 和本文件其他地方的「短句 / 拆短 / 能删就删」说法,与规则 3 冲突时按规则 3 执行。
### 规则 1:段落密度诊断
段落长短没有固定优劣。检查重点是朗读和手机阅读是否卡顿:
- 一段通常只承载一个动作、一个信息变化或一组紧密相关的反应。
- 逗号串太长、多个完整动作挤在一段里,读起来需要换气时,按动作或信息变化拆开。
- 连续短段碎成提纲时,合并同一镜头内的相邻句,让画面保持连续。
```
过密:他看着窗外的雨,心中涌起一股说不清的感觉,这些年走过的路和很多已经忘记的事都在这一刻涌上心头。
更自然:他盯着窗外的雨,雨从下午下到天黑。
"你还在想她?"老刘问。
他没说话。
```
### 规则 2:动作 + 对话 + 情绪反应
三要素循环推进,不要单写心理活动超过 2 段:
```
动作 -> 对话 -> 情绪反应 -> 动作 -> 对话 -> ……
```
情绪不用"他感到/他觉得",用身体反应和行为表现:
- 不写"他很紧张" -> 写"手心全是汗,筷子差点掉了"
- 不写"她很愤怒" -> 写"她把杯子摔在地上,碎片弹到脚背上也没弯腰捡"
- 不写"他很伤心" -> 写"他在车里坐了二十分钟才发动引擎"
以上替换针对关键情绪节点;低强度过场情绪可一笔直写("他有点烦"),不必处处外化。
### 规则 3:句子该多长(短句是工具,不是默认)
叙述(旁白)默认写成**逗号长句**:一句用逗号串起 2-4 个动作或信息,再落句号;逗号之间 8-12 字,整句 20-30 字。短句是偶尔的孤立重拍工具,不是叙述的默认写法。
| 场景 | 句长 | 示例(长篇语料原句) |
|------|------|------|
| 日常 / 推进 / 描写(多数叙述句) | 逗号之间 8-12 字,整句 20-30 字 | 阴冷潮湿的气息扑面而来,身下铺着一层薄薄的稻草,湿漉漉地粘在皮肤上。 |
| 对话 | 口语化,长短随角色 | "你疯了?""可能吧。" |
**不合格(与 AI 腔同级)**:
- 逗号之间连着都是 ≤5 字的碎片("他抬手,开门,进屋,坐下"式)
- 通篇 3-8 字句、句号密得像提纲(电报体,见模式 9)
- 一长一短机械交替(同样是模板)
> **爆款语料校准**(七猫长篇 现言/都市/古言/玄幻/历史 125 本×前 8 章旁白统计):逗号之间平均 8.8-9.6 字;整句平均 22-24 字;逗号长句占叙述句 74-80%;≤5 字的短片段约占两成,多是孤立的时间词、转折、动作重拍。短篇(盐言体)段落更短(≤15 字的单句段可近一半,长篇约两三成),但句子内部的节奏和长篇一样:**段落随体裁变短,句子内部不碎**。
### 规则 4:口语化表达
- 允许用俚语、粗话(符合角色身份)
- 对话不要书面语("我认为此事不妥" -> "我觉得不靠谱")
- 叙述也不要端着("他目光如炬" -> "他眼珠子一动不动盯着")
- 短语优先于成语("无可奈何" -> "没办法")——只管对话和贴角色声口的叙述;旁白常用成语(不动声色、心不在焉一类)照留
---
## Show Don't Tell 原则
| Tell(告诉) | Show(展示) |
|-------------|-------------|
| 他是个胆小的人 | 他把检查报告在手里翻来覆去看了三遍,还是不敢打开 |
| 这间酒吧很吵 | 酒保凑到他耳边喊了两次他才听见 |
| 她很富有 | 她随手把一张信用卡丢在桌上,卡面上的数字比这顿饭贵十倍 |
| 两人关系很差 | 他把烟掐灭在她刚泡的茶杯里,她面无表情地把杯子推到一边 |
| 他很聪明 | 三秒钟。他看了三秒钟就把文件合上了。"第三页,第二行。" |
**核心方法**:
1. 用行为代替形容词
2. 用细节代替总结
3. 用对话代替旁白说明
4. 用反应代替情绪词
---
## 质量维度检查
### 1. 核心一致性(权重最高)
- 剧情是否与大纲/前文一致
- 人物行为是否符合人设
- 设定是否有前后矛盾
### 2. 表面改写(防AI指纹)
- 是否包含AI高频用词(见上表)
- 章尾是否有总结/升华
- 是否有大段纯心理描写
- 段落是否按戏剧单元/镜头自然断开,避免机械单句成段或为凑短碎成提纲(网文段落规则)
### 3. 格式一致性
- 对话格式统一:按项目/平台约定保持同一引号风格;知乎盐言短篇可用「」
- 标点节奏匹配语气:避免通篇句号化;保留有功能的问号和少量感叹号;用动作/短句表达迟疑或打断,不用省略号或破折号硬造停顿
- 场景切换有明显标记
- 时间线清晰可追踪
### 4. 可读性
- 是否有连续多个长句压住阅读节奏,且缺少动作、对话或短句换气
- 对话是否口语化
- 是否有未解释的生僻词/设定术语
- 节奏是否有快有慢(不能全是一种节奏)
### 5. 逻辑连贯性
- 角色动机是否合理
- 事件因果链是否清晰
- 时间线是否对得上
- 角色的知识范围是否合理(不能"开上帝视角")
---
## 快速自检口诀
```
一事一段,镜头自然断。
对话要像人说话。
心情不写心里话。
结尾不搞大升华。
打斗不写流水账。
日常要埋伏笔桩。
```
> 网文段落规则:按戏剧单元/镜头/一件事结束自然断段;短段快读,长段承载完整推理、氛围和情绪链,避免机械单句成段或通篇同长度。
---
> **番茄高分样本校准**:番茄正文更接近“手机端短段 + 自然虚词 + 场内动作/对话推进”,不是机械指标达标。番茄高分样本 305 章窗口显示:段落中位约 23.5 字,50-60 字行宽平均只占 5.1%;平均对话占比约 20.6%,对话≥50% 仅 3/305,开篇对话 59/305;`地/得` 305/305、`很` 275/305、`像/好像/仿佛/如同` 267/305、顿号 176/305、省略号 281/305。结论:这些只能按语境复核,不能做 0 容忍硬禁令。
>
> **反投机边界**:不要为了“反检测”强制每句换行、把 `……` 改成 `........`、把 `地/得` 全改成 `的`、禁用所有顿号/“很”/“像”、强行开篇对话或按三番四证重排章节。去 AI 味是润色,不是结构重写;除非用户明确要求重写,否则不改变章节顺序、伏笔分布、对话占比和人物信息释放节奏。
---
## 禁用词与句式速查
> 完整禁用词表和句式模板见 [banned-words.md](banned-words.md)
### 正确替代示例
- '他感到一丝紧张' -> '他的手在抖'
- '她很伤心' -> '她背过身,把袖口攥皱了'
- '"好的。"他说道' -> '"好的。"他把门卡塞回口袋'
- '他深吸一口气' -> '他把话咽回去'
---
## 10 种 AI 写作模式检测
### 模式 1:AI 高频词
| 禁用 | 替换为 |
|------|--------|
| 不禁 | 删掉 |
| 仿佛/宛如 | 删掉或用具体描写 |
| 映入眼帘 | 删掉 |
| 心中暗道 | 用动作展示思考 |
| 沉声道/淡淡地说 | 换成动作标签 |
| 脸色一变 | 用具体表情/动作 |
| 嘴角微扬 | 他笑了/他翘了下嘴 |
| 不由自主 | 删掉 |
| 只见/此时此刻 | 删掉 |
| 目光如炬 | 删掉或具体化 |
### 模式 2:弱化副词泛滥
阈值:每 1000 字超过 3 个 = AI 签名。重点监控:微微、淡淡、缓缓、轻轻。
### 模式 3:意义膨胀
- "意义深远" -> 写具体后果
- "前所未有" -> 给出对比参照
- "可谓" -> 删掉
### 模式 4:万能结论
- "未来可期" -> 用未解决的紧张感结尾
- "前途无量" -> 删
- "充满希望" -> 写具体的下一步动作
### 模式 5:论文体段落结构
小说中出现以下开头句 = AI 入侵:
- "不难看出""由此可见""事实上""综上所述"
### 模式 6:书面语连词泛滥
叙事散文中频繁出现:"于是乎""与此同时""从而""因而""诚然" -> 口语化替代或直接删除。
### 模式 7:三连排比癖
AI 喜欢把事情凑成三个以显"完整"。-> 砍到只剩最有力的一条。
跨段「不是A。/也不是B。/只是C。」由 `formulaic-parallelism` 作 advisory:它可能是工整铺排,也可能承担辩解、悬念排除或情绪递进;只有重复提纲、拖慢画面时才压缩。该类提示与「至于X不X,怎么X」、同动词「不V A,不V B」都只作语义复核:对话也要检查,但有明确人物声线或任务功能时可保留;若来自细纲多个字段对同一要求的重复,正文只能消费一次,不能逐项复述。
### 模式 8:解释腔 / 上帝视角 / 安排感
最难察觉、却最"像 AI"的一类。叙述者跳出角色当下,去解释、剧透、总结、定性、拔高,读者能闻到"作者在场"和"剧情被安排好了"的味道。这正是"说教感/上帝感/解释腔/机械感/刻意感/安排感"的来源。
| 表现 | 例(删/改) |
|---|---|
| 解释因果 | 「之所以…是因为」「原来…」「这意味着」「正是因为」-> 删。因果只从角色动作、对话、反应里让读者自己拼 |
| 上帝视角剧透 | 「她不知道的是」「殊不知」「多年以后」「冥冥之中」「仿佛预示着」-> 删。只写角色此刻知道的,悬念让读者自己悬 |
| 替读者下结论/定性 | 「演得真好」「这出戏她看过一遍」「他就是这样薄情的人」-> 删。把证据(神态、动作、台词)摆出来,定性留给读者 |
| 替角色总结心理 | 「她明白,这一切都是命」-> 换成一句带偏见的闪念或一个身体反应 |
| 总结/动机/评价链把意义说满 | 「他终于明白」「这是最好的选择」「所有人都会记住这一刻」-> 删掉定性,改成角色当下要处理的具体缺口、未完成动作或局部反馈;不是保留评价再硬塞物件/动作 |
| 安排感/硬铺垫 | 为后文强行交代背景、整段回忆倒叙 -> 背景按角色此刻真实所需,用闪念、半句话、物件零碎带出,不集中交代 |
| 升华式收尾 | 结尾对仗拔高、金句点题 -> 用一个动作或一句留白收住,把"意思"压进画面里 |
| 抽象命运/开端收束 | 「命运终于露出獠牙」「早已布好的棋局」「这一刻终于明白」「属于他的反击才刚刚开始」-> 改成角色当下可见的文件、动作、对话或物理后果;`check-ai-patterns.js` 报 `abstract-summary-tic` 时优先处理 |
| 套词密度过高 | 仿佛/一丝/一抹/深吸一口气/平静无波/指节泛白等成串复现(`cliche-density-tic`)-> 不是同义词轮换,整段回到角色当下证据:文件、动作、对话、物理后果 |
| 套式反应细节 | 指尖轻叩、袖口里攥紧、指节泛白、目光移开、“语气平静得像在念……”等反应成片(`stock-reaction-tic`)-> 逐处做删除测试;只标注情绪而不改变选择、关系、物件或动作结果的删掉,不换部位和同义动作;有伤势、动作失败或情节后果的身体细节可留 |
| 比喻密度过高 | 像/好像/仿佛/如同等比喻标记成片复现(`metaphor-density-tic`)-> 保留最能传递信息或情绪的一两个,其余改回具体动作、物件、声音、后果;不要换成新比喻 |
| 系统公告公文腔过密 | 方括号规则/面板/公告行里硬规则词成片(`system-notice-formality-tic`)-> 保留为角色看见的屏幕/公告/规则载体;只在载体内部白话化部分硬词,或补角色当场看懂的具体后果,不改成叙述者解释 |
**更隐蔽的一层(最难自查,没有标志词)**——同样是安排感/上帝感:
- 评判性副词/补语:「关切得恰到好处」「笑得恰如其分」「不多不少」-> 作者在替读者盖章"这是装的"。只写动作("她掩了帕子,眼睛没动"),装不装让读者自己判。
- 剧透式点破潜台词:「那点笑她看得分明」「谁都看得出他在撒谎」-> 把藏着的挑明了。留着别点破。
- 定性比喻/盖棺句:「像在宣判一件早已定好的事」「像看一件死物」-> 比喻在替角色下定论。非角色此刻强烈主观感受就删;要留也只能是她带偏见的瞬间感觉,不是客观断言。
自检:每句问一遍——这是"角色在经历",还是"作者在讲解/安排"?凡作者跳出来讲,删,或改成角色视角内的呈现。根治办法是锁定深度限知视角(见 writing-craft.md「视角姿态:深度限知」),镜头钉死在角色身体里,作者就没位置跳出来了。
改法优先级:先删或原位替换污染句,不在段尾另补“人味”尾巴。需要补信息时,把原来的总结/动机/评价句改成角色当下能碰到的问题、手续、回信、付款、门外动静等具体压力;已有手机/屏幕/公告/门牌/表单等信息,优先作为角色看见的场内载体保留,不要转写成叙述者解释。具体载体跟剧情走,不套固定清单。
**任务卡点不是固定公式,也不是通用补流程按钮**:它只是把已有解释落回角色当下要处理的缺口。先问原文有没有“要办的事”和“卡住的点”;有,才可以压成任务卡点;没有,就只删解释或改动作/对话,不新造事件链。改完再做“删掉试试”:删掉后不影响信息、情绪、关系、代价或伏笔,就压缩或删除。
**但删解释腔 ≠ 把读者读懵**:新名词/新设定/新道具首次出现时,仍要让读者抓到一个锚——靠角色的动作反应、对话里半句自然提及、或场景里的物理后果,一笔带出它此刻的作用或分量;既不整段讲来历原理,也别只甩个零信息生词让读者干懵。人物记忆、情绪缓冲、因果承接也一样:如果一句看似解释/评价,实际承担小连贯(让读者知道角色为什么脸热、为什么停顿、为什么这一声压不住),不要机械删成摘录清单;把它压成角色当下的白话、动作、物件或半句念头。例:「蓝晶」首次出现不写"这是储存记忆的装置",但可写她把蓝晶按上太阳穴、别人的记忆碎片炸开在眼前——功能被读者看见,全貌留作悬念。区分:锚是"角色此刻撞上的可感知后果/记忆或情绪承接"(留或压),解释是"作者跳出来讲设定来历/原理/替读者下结论"(删)。
### 模式 9:过度压缩(电报体)
去AI味删过头的反向指纹。每句都压到最短、结构虚词扫光、每个动作都补一个「了下/了一下」式轻反应。单句看着干净,连读像提纲,读者的体感是"不流畅、喘不上气"。删减的目标是删废话(解释、注水、凑数),不是删中文的自然冗余。
| 表现 | 修法 |
|---|---|
| 非峰值叙述句也全部压成最短句 | 重拍句(动作/情绪/悬念峰值)保持短促;铺垫、过渡、日常动作写成自然白话句,保留 了/的/就/的时候 等结构虚词 |
| 「扯了下/停了一下/拍了两下/松了半圈」式微动作高密度复现(check-ai-patterns.js 报 micro-action-tic) | 合并动作,换具体细节;不是每个动作都要接一个反应尾巴 |
| 强调副词(连/才/又/只/全/反而)被扫光 | 删前判语义:承担人设、对比、讽刺义的保留("才二十三天"删掉"才",人设强调就反了) |
| 对话语气词归零 | 按角色保留自然低频的 呢/吧/啊;也不反向猛加——人味来自结构自然,不是聊天腔 |
| 叙述残留公文/文言腔(不得/须/未/已然/当前) | 换白话(不能/要/还没/现在)。系统公告、规则条文、面板播报可以保留冷硬功能;若 `system-notice-formality-tic` 报警,只在原载体内白话化一部分,不改成叙述者解释 |
| 长文本里短叙述段成片(`overcompressed-prose-tic`) | 不是把所有短段拉长。先人工通读:重拍短句、密集镜头如果上下文顺,就保留;只处理读起来像提纲的过渡句,把它们并回同一镜头,让读者顺着动作、空间、因果读过去 |
| 引号外叙述低连接密度且缺中长句(`low-connective-density-tic`) | 不是全局补“的/了/就”,也不处理台词/弹幕/系统播报的天然短促。先找叙述层读起来像提纲/电报体的断裂处,恢复必要连接、指代和中长承接句;有中长句链条的低功能词文本可保留 |
自检:删完连读一遍,读感像提纲或流水口令,就是删过了——把非峰值句恢复成自然白话,不是接着删。
本模式约束的是删减的度,不降低清理力度:禁用词、套路句式、告知式心理照删照改,模式 1-8 与 Gate A-G 全额执行;回填只回结构虚词和连接,不保留、不恢复任何模板措辞。
### 模式 10:二修伪自然(油腻倒装 / 监控动作清单 / 对话指标化)
一些“反检测提示词”会把文本推向另一种模板:为了提高突发性而乱倒装,为了真人感而机械加口误和脏话,为了手机阅读而强制每句换行,为了对话占比而把心理和叙述硬改成台词。这些不是自然网文,是二修痕迹。
| 表现 | 修法 |
|---|---|
| 油腻倒装 | 不写“手里拿着刀,他冲了上去”这类伴随动作前置。连续同主语时,优先用场内物件、声音、局部身体或环境反馈自然换句首;不要滥用死物拟人 |
| 监控摄像头式动作清单 | 同段连续“伸手拿起、取过、挑开、放下、转身……”像步骤表。合并琐碎动作,只保留有情绪、情节或空间功能的动作;必要时用角色犹豫、误判、旁人反应或环境反馈做缓冲 |
| 高压场景误脱水 | 冲突、追杀、打斗可删解释和逻辑胶水;日常、暧昧、铺垫不能全章脱水。删的是废话,不是“的/了/就/但是”等自然连接 |
| 吃字漏词 | 去 AI 后如果动词没有对象、动作指向不清、读者不知道谁对谁做了什么,要补回必要宾语、承载物或物理反馈;中文可省略,但不能省到像提纲 |
| 对话指标化 | 不为凑 50%-60% 对话占比硬扩台词。台词只在角色真会说、此刻必须说时增加;长对白可拆动作,解释性对白优先压成冲突、回避或半句信息 |
| 硬格式投机 | 不强制每句换行、50-60 字一行、不把省略号改成英文点、不把 `地/得` 全改错。按平台和项目既有格式走 |
`check-ai-patterns.js` 的 `action-list-tic` 只提示监控动作清单,不是 blocking。功能性打斗/追逐/仪式步骤若动作链本身承担信息,可保留或标 `[需复核]`。番茄高分样本中该类命中为 0,因此适合作为“需通读”的风格提示,而不是硬性失败项。
#### 工具提示处理
`check-ai-patterns.js` 是本地写作 lint;blocking 只限确定性句式/标点问题,advisory 不作完成门槛。用户贴其他工具报告时,只把能落到正文的句式、段落、词汇问题转成具体修改点,不写“0% AI / 100% 真人”或“固定公式”,也不围绕分数反复微调。
工具提示不高于读感规则。参考文本里若出现“仿佛/非常/感到”等套词或告知式心理,仍按模式 1-8 清理;不要机械补词、故意错字或按题材套壳。
**去 AI 味补充判断**:
- 优先处理:作者解释总结、意义尾巴、把情节翻译成“他意识到 / 这意味着 / 真正重要的是 / 这次成长”。优先删掉,或落回场内动作、对话、物件状态、任务状态和角色当场要处理的后果。
- 场内载体优先:原文已有手机、屏幕、公告、门牌、表单、账单、物证、规则行时,保留为角色看见/读错/处理的文本或物件;不要把同一信息改写成叙述者解释规则。
- 白话但不注水:少用精致戏剧反应短语(头皮发紧、眼皮一跳、心口一沉、胃里翻涌)连续替代剧情推进;能写普通动作/普通感觉就写普通动作/普通感觉,并保留自然的“的/了/就/但是/已经/之后/没有”等连接。
- 题材文风优先:文风对标有帮助,但必须来自目标题材/本书文风指纹;不要把盘龙腔、旧网文腔、第一人称声口等当成跨题材万能修法。
- 不要当通用修法:单纯加标题、补物件、补动作尾巴、拉长/压短句子、增加排队/门禁/记录体,不能替代具体的情节、视角和语言问题处理。
#### 把提纲句写成连续段落
当文本已无 blocking / 明显 advisory,但读起来仍像提纲时,只处理断裂处:
1. 标出读起来像逻辑报告的段落:连续出现“他知道/他明白/这意味着/真正的问题/必须/需要”等判断链,却缺少当下动作、物件或对话反馈。
2. 把叙述者结论落地:用角色当下能触到、听到、被迫处理的后果替代“他意识到/这意味着”。不要套固定物件清单,也不要把某个场景外壳当通用规则。
3. 只在断裂处恢复自然连接和结构虚词;不设比例目标,不机械补连接。
4. 系统公告、规则条文、面板播报可以保留冷硬短句;`system-notice-formality-tic` 报警时,只在原载体内白话化一部分硬规则词,或让角色当场看到具体后果,不改成叙述者解释。
`overcompressed-prose-tic` / `low-connective-density-tic` 的具体修法:
1. 圈出连续短叙述段,逐段标注功能:爆点/反转/恐惧重拍、密集镜头可继续短;铺垫、空间、因果、动作承接应并回同一镜头。人工读着顺,就不因该 advisory 继续拉长。
2. 合并时优先补“动作顺序、空间方位、因果承接”,例如“抬头时/门外/已经/还/就/被”,而不是给每句硬塞“的/了/就”。
3. 合并后再删套词和告知心理:读顺不是恢复 AI 腔,不能把“仿佛/感到/非常/好像”成片加回来。
复核处理:如果清掉 `overcompressed-prose-tic` / `low-connective-density-tic` 后读感仍不稳,停止局部微调,转为段落级重写或人工读感对照。
示例:
```
过度压缩:
林遥抬头。
雨棚外的街灯灭了。
风也停了。
柜台上的纸杯晃了两下。
读顺后:
林遥抬头时,雨棚外的街灯正一盏盏熄下去。风忽然停了,柜台上的纸杯还在原地轻轻打转。
```
---
## 系统性去AI三遍法
### Pass 1:去泛化(Strip Generic)
- 抽象情绪总结句 -> 删或替换为具体动作
- 假深度句 -> 删
- 意义膨胀 -> 缩小到具体影响
- 空洞结论 -> 删
- 工整对比句式 -> 打散重写
- 装饰性形容词堆砌 -> 白描
- 过度使用"于是""然而""此刻" -> 删掉一半
- 所有角色说话一样"高级" -> 区分语气
**原则**:能删就删,不能删就用具体细节替换。这一遍去掉80%的AI味。
### Pass 2:去书面化(Cut Professional Diction)
- 分析性用词("机制""结构""逻辑""体系"出现在小说中)-> 换成日常表达
- 抽象名词滥用 -> 直接说事
- 体制内用语("进一步""深入""推进""落实")-> 删
- 专业术语堆砌 -> 只保留必要的,用白话解释
**例外**:保留专业感的场景(历史题材正式用语、文学向刻意密度、喜剧夸张修辞)。
### Pass 3:回自然感(Restore Natural Presence)
- 具体的感官细节(气味、温度、触感)
- 角色说话方式的区分(不同人不同语气)
- 句首变化:连续 3+ 句用同一主语或同一词性开头时换开法(动作、场景、对话引入)
- 节奏变化(长短句交错):按情绪 beat、动作推进和戏剧单元自然调节句段长短;忌连续多段同一长度,也忌为凑短而碎成提纲。长短不是随机,沉淀处可放慢,冲突/反转处可骤短,完整推理与情绪链优先保持连贯
- 社会位置感的对话(上级和下属说话方式不同)
- 场景特有的记忆点
- 项目特有的语言习惯(角色的口头禅)
**原则**:少即是多。每段加 1-2 个具体细节就够了。
### 升级策略
| AI味程度 | 策略 |
|----------|------|
| 轻度 | 只做 Pass 1 |
| 中度 | Pass 1 + Pass 2 |
| 重度 | 完整三遍 + 重点段落重写 |
### 自检清单
- 对话自然度检查:对话是否使用口语化表达,是否避免了书面语/正式腔调
- 删掉任何一句,会影响理解吗?不会 = 可能多余
- 不同角色能通过对话区分吗?
- 有没有一个细节是这个场景特有的?
---
## 去AI味补充技法
### Show vs Tell
| 告知类型 | AI写法 | 自然写法 |
|----------|--------|----------|
| 告诉期待感 | "他很期待" | 展示期待->情绪->满足的链条 |
| 告诉角色目的 | "她想离婚" | 用行动展示目的 |
| 告诉角色态度 | "她很冷静" | 用对话和反应体现 |
| 告诉剧情走向 | "接下来会发生大事" | 用铺垫->反转->延续展示 |
### 心理描写润物细无声
- 加括号标注内心活动 = 破坏代入感
- 大段内心独白解释动机 = AI签名
- 直接写"她感到""她意识到" = 告知情绪
**自然写法**:心理活动自然融入叙事,用行为暗示心理,用沉默/动作/反常行为表达内心。
### 代入感检查
- 主角行为读者能理解、共鸣、接受吗?
- 反派够强吗?(弱反派 = 读者觉得主角赢了没意义)
- 是否围绕人设写行为?(行为/语言/思维围绕人格展开)
- 读者已知信息是否被有效操控?(信息差制造情绪波动)
---
## 改写范例库
### 情绪外化范例
**紧张**
- '他感到一阵紧张,心跳不由自主地加快了'
- 他攥紧了手里的纸杯,水洒出来一些
**愤怒**
- '愤怒在他心中燃烧,他不由得握紧了拳头'
- 他把筷子往桌上一拍,碗里的汤溅了出来
**悲伤**
- '一丝悲伤涌上心头,她的眼中闪过泪光'
- 她低头搅着咖啡,搅了很久
**害怕**
- '恐惧瞬间笼罩了他,他感到一阵战栗'
- 他的背贴在墙上,不敢动
**失望**
- '她感到一丝失落,心仿佛被什么东西揪住了'
- "哦。"她把手机锁了屏
**惊讶**
- '他的瞳孔微微收缩,显然没有想到会听到这样的话'
- 他张了张嘴,什么都没说出来
### 场景描写范例
**AI风场景**
- '阳光透过窗帘的缝隙洒进来,在地板上投下斑驳的光影。空气中弥漫着淡淡的花香,仿佛整个世界都沉浸在一片宁静祥和的氛围中。'
- 下午三点,客厅里只有钟在走。
**AI风天气**
- '天空阴沉沉的,乌云密布,仿佛随时都会下起倾盆大雨。凛冽的寒风呼啸而过,带着一丝刺骨的寒意。'
- 要下雨了。风把晾在外面的衣服吹得乱晃。
**AI风打斗**
- '他的拳头犹如疾风骤雨般猛烈,每一击都蕴含着不容置疑的力量。对手的瞳孔微微收缩,显然没有预料到如此凌厉的攻势。'
- 他一拳怼过去,对方没躲开,嘴角破了。
### 结尾改写范例
**升华式结尾** -> '他站在窗前,望着远方的天际线,终于明白了生活的真谛:有时候,放手才是最好的选择。' -> 他把烟掐了,回屋睡觉。
**总结式结尾** -> '这一刻,一切都变了。她知道,从今以后,她的人生将翻开崭新的一页。' -> 她关上了那扇门。没回头。
**感慨式结尾** -> '岁月如流水般悄然流逝……' -> 直接删掉这种段落。
### 节奏调整范例
> 以下范例处理的是臃肿修饰、堆叠比喻和抽象总结,不是「见长就拆」:改写后叙述仍以逗号长句为主(规则 3),不要把正常的逗号长句拆成短句串。
**排比句**
- '他看着她的眼睛,看着她的嘴唇,看着她微微颤动的睫毛,心中涌起一股难以名状的情感。'
- 他看着她,她没说话。
**臃肿长句去修饰**
- '当他终于推开那扇沉重的木门时,映入眼帘的是一间昏暗的房间,空气中弥漫着陈旧的气息,墙角堆满了落满灰尘的箱子。'
- 他推开木门,屋里昏暗,墙角堆着几个落灰的箱子。
**工整段落打碎**
- '她喜欢春天的花朵,喜欢夏天的阳光,喜欢秋天的落叶,喜欢冬天的白雪。每一个季节都有它独特的美。'
- 她喜欢春天,别的季节也还行。
---
## 冲突对话改写范例
### AI式温和对话
- '我觉得你这样做不太合适,能不能考虑一下我的感受?' -> "你眼里还有我吗?"
### AI式完美解释
- '其实我这样做是有原因的,因为当时的情况非常复杂……' -> "你能怎么着?"她把茶杯重重放下。
### 对话情绪五级递进范例
同一冲突场景,从弱到强:
1. **客观陈述**:"你把我的东西扔了。"
2. **陈述+建议**:"你把我的东西扔了,以后能不能先跟我说一声。"
3. **主观指责**:"你凭什么动我的东西。"
4. **指责+命令**:"你算什么东西,也配碰我的东西?滚出去。"
5. **指责+PUA**:"我伺候你吃伺候你穿,你连个东西都放不好。你这辈子也就是这样了,离了我你什么都不是。"
### 震惊分层改写范例
**AI式一步到位**:所有人都震惊了,不敢相信自己的耳朵。
**自然分层震惊**:
1. 对面的男人手抖了一下,茶杯里的水洒出来。
2. 旁边的人互相看了一眼,有人往后退了一步,角落里有人开始掏手机。
3. 刚才还趾高气扬的女人,脸上的笑僵住了。她张了张嘴,一个字没说出来。
### 代入感修复范例
**被动主角**:她很害怕,不知道该怎么办,只能等着事情过去。
**主动主角**:她锁了门,把手机调成静音,打开了录音。
---
## 质量检查清单
写完每章后,按此清单逐项扫描:
- [ ] **段落控制**:段落按动作/信息变化断开,读起来不卡
- [ ] **正文无破折号**:正文(含叙述和对话)无 `——`/`—`/`--`(用句号、逗号、短句或动作断句),不设置对话例外
- [ ] **AI高频词扫描**:无不禁/仿佛/映入眼帘/心中暗道/沉声道/嘴角微扬/不由自主/只见
- [ ] **弱化副词计数**:每1000字"微微/淡淡/缓缓/轻轻"不超过3个
- [ ] **无三连排比**:没有AI式的"三个一组"修辞
- [ ] **工整否定清单已复核**:跨段「不是A / 也不是B / 只是C」及其他 `formulaic-parallelism` advisory 已连同台词逐条复核;功能性修辞可保留
- [ ] **无论文体**:无"不难看出/由此可见/事实上/综上所述"
- [ ] **无书面语连词堆砌**:无"于是乎/与此同时/从而/因而/诚然"泛滥
- [ ] **章尾无总结升华**:用动作/对话/悬念收束,无感悟/哲理/预告
- [ ] **无大段心理描写**:心理活动不超过2段,无括号标注内心
- [ ] **情绪用动作展示**:关键情绪节点无直接写"愤怒/伤心/紧张",用身体反应替代;低强度过场情绪可一笔直写,不必处处外化
- [ ] **对话口语化**:无书面腔,不同角色语气可区分
- [ ] **标点不压平**:没有把质问、爆发、犹豫全部压成句号;也没有随机堆砌 `?`/`!`,或用 `……`/`——` 硬造停顿
- [ ] **Show Don't Tell**:用行为代替形容词,用细节代替总结
- [ ] **句长达标**:叙述默认是逗号长句(逗号之间 8-12 字、整句 20-30 字,规则 3);短句只作偶尔的孤立重拍,用完回到逗号长句;没有连着的 ≤5 字碎片,没有通篇短句像提纲
- [ ] **detector advisory 逐条复核**:`micro-action-tic` / `stock-reaction-tic` / `abstract-summary-tic` / `cliche-density-tic` / `metaphor-density-tic` / `reasoning-chain-tic` / `system-notice-formality-tic` / `overcompressed-prose-tic` / `low-connective-density-tic` / `action-list-tic` 命中时按脚本给出的修法处理:先通读判断是不是机械复现,确属再改;功能性写法保留或标 `[需复核]`,不做同义词轮换、不机械注水
- [ ] **不做硬指标投机**:不为反检测强制每句换行、50-60 字一行、对话 50%-60%、英文点省略号,或把 `地/得` 全改成 `的`
- [ ] **任务卡点服从原文边界**:抽象总结若改成角色办事被卡住,必须来自原文已有任务/证据/手续/物件缺口;不新增原文没有的事件链
- [ ] **去AI三遍法执行**:轻度只做Pass1,中度做Pass1+2,重度完整三遍
- [ ] **对话自然度测试**:无书面语痕迹 = 通过
references/artifact-protocols.md›
# 产物创建模板
各产物的标准模板与创建指引。agent 在 Phase 2-3 过渡时按需加载此文件。
**模板列表:**
- 设定/关系.md
- 设定/题材定位.md(含读者契约 + 终局底牌/升级台阶 + 对标登记字段)
- 大纲/大纲.md(全书鸟瞰 + 全书体量与阶段总览)
- 大纲/卷纲_第X卷.md(含卷契约+终局储备+剧情单元+情绪弧线+反转规划)
- 追踪/_tracking-state.json(唯一结构化权威状态)
- 追踪/逐章记录/第NNN章.md(未来相关紧凑增量)
- 追踪/伏笔.md
- 追踪/时间线/作者真相.md + 读者已知.md(派生视图)
- 追踪/角色状态/{角色名}.md
- 追踪/上下文.md(续写状态卡,固定 7 栏)
- 对标/{对标书名}/拆文报告.md
- 对标/{对标书名}/原文/第XXX章_{章名}.md
**层级关系(全书 › 卷 › 剧情单元 › 章 › 情节点;故事线横向贯穿多个剧情单元):**
- 大纲.md = 全书鸟瞰(每卷一两句话定位)
- 卷纲_第X卷.md = 单卷规划(剧情单元+情绪+人物+伏笔+反转)
- 细纲_第XXX章.md = 单章蓝图(单元ID/位置 + 主角目标/关键选择 + 内容概括 + 多线情节安排 + 人物关系/出场顺序 + 情节细化 + 结尾设定/钩子)
**概念对照(统一叫法,减少混淆):**
- **剧情单元** = 一段完整剧情(1.5-3 万字/数章,一个矛盾从起到收)。拆书侧就是 `剧情/{剧情单元名}.md`,本书侧就是卷纲里的**剧情单元卡**;理论叫法是「一级结构」。同一粒度,统一叫剧情单元。
- **故事线**(`剧情/故事线.md`)= 贯穿多个剧情单元的线(主线/感情线/成长线/夺宝线…),比剧情单元大一层。
- 「循环」一词只在**节奏义**保留(爽点循环、升级循环、小/中/大循环等),不再指代规划单元。
---
## 对标/{对标书名}/拆文报告.md
> **拆文库/对标关系**:`拆文库/` = analyze skill 的原始产出(数据源)。`对标/` = 写作项目的引用视图。首次引用时从 `拆文库/` 复制到 `对标/`。
此文件由 `story-long-analyze` 拆解管道输出(快速预览报告或完整拆文报告)。write skill 的职责是**读取**,不创建。
如需手动创建简版对标摘要(未使用 analyze skill 时):
```markdown
# {对标书名} 对标摘要
## 基本信息
- 书名:{}
- 作者:{}
- 题材/类型:{}
- 目标平台:{}
- 成绩:{均订/在读/热度}
## 核心发现
- 开篇钩子:{类型 + 手法}
- 爽点密度:{约 N 字/次}
- 节奏模式:{描述}
- 可借鉴套路:
1. {}
2. {}
3. {}
## 不建议模仿(禁止照搬)
- {}(只学结构,不抄桥段)
```
创建参考:`plot-special-topics.md` (对标书选择法则)
---
## 对标/{对标书名}/原文/第XXX章_{章名}.md
对标书章节原文,由用户手动放入或拆文管道导入。
```markdown
# 第{N}章 {章名}
{本章完整原文内容}
---
> 来源:{手动输入 / story-long-analyze 导入}
> 原始字数:{约N字}
```
---
## 设定/关系.md
```markdown
# 角色关系图
## 关系总览
| 角色 A | 角色 B | 关系类型{亲情/爱情/友情/敌对/师生/主从/利益} | 情感倾向{正面/负面/中性/复杂} | 当前状态 | 起始章节 | 变化节点 |
|--------|--------|---------------------------------------------|-----------------------------|---------|---------|---------|
| {名} | {名} | {类型} | {倾向} | {描述} | 第{N}章 | {事件} |
## 关系演变
{角色A}<->{角色B}:
- 起点:{初始关系}
- 转折:{章节·事件·变化}
- 当前:{现状}
## 核心冲突关系
{列出推动剧情的2-3对核心对立/合作关系}
```
创建参考:`character-relations.md` (人物关系类型 + 关系图绘制)
---
## 设定/题材定位.md
```markdown
# 题材定位
## 基本信息
- 题材类型:{玄幻/都市/系统/...}
- 目标平台:{起点/番茄/晋江/其他;story-review 据此选平台 rubric}
- 核心梗:{一句话卖点}
- 微创新点:{与同类题材的差异}
## 读者契约(参 `reader-contract-and-progression.md`)
- 核心读者承诺:{读者来追什么爽感/情绪/关系/事业}
- 主角代理权承诺:{主角不可替代的判断、关键选择或贡献}
- 利益安全线:{核心资产/卖点不得被没收、转赠、无交换暴露的边界}
- 期待债:{开篇/本卷已承诺,何时以什么形式偿还}
- 题材边界:{个人逆袭/群像/导师/制度合作等;高层级机构出现时先核对}
## 终局底牌与升级台阶(防写无可写;开书填一次,日更只查。参 `reader-contract-and-progression.md`「终局储备与推进节奏」)
- 终局底牌(一次性资源,标最早解锁卷):头号宿敌={}·第{X}卷;终极真相/身世={}·第{X}卷;金手指上限={}·第{X}卷;身份/地位终点={}·第{X}卷;核心情感确定={无感情主线可删}·第{X}卷
- 升级台阶:主体系{境界/等级/地图/势力层级}共{N}档 × 每档约{W}万字 应 ≥ 全书目标字数(不足则拉长体系/加地图层);敌人/目标成梯队逐级解锁,禁止越级秒顶级
- 透支红线:① 未到解锁卷就动用终局底牌 ② 某条升级线逼近天花板、后面没台阶接
## 核心梗三分法
- 表层卖点:{读者一眼看到的吸引力}
- 深层爽点:{持续追读的情绪驱动力}
- 长线钩子:{支撑全书的悬念/目标}
## 对标分析(概要)
> 完整对标数据见 `对标/` 目录。此表仅做快速概览。
| 对标书 | 相似点 | 差异点 | 可借鉴 |
|--------|-------|-------|-------|
| {书名} | {点} | {点} | {点} |
## 对标登记(多对标时必填;cross-book-recall 跨书召回按此排序与预算)
- 主对标书:{书名;单对标可省,多对标必填}
- 对标书列表:
| 书名 | 题材类型 | 引用强度{辅/参考} | 用途 |
|------|---------|-----------------|------|
| {书名} | {类型} | {辅/参考} | {文风主对标/结构参考/…} |
## 题材框架
- 八节点位置:{当前处于哪个节点}
- 关键转折节点:{列出}
```
创建参考:`long-genre-mechanics.md` (核心梗解析与运用 + 微创新与差异化设计)
---
## 大纲/大纲.md
全书鸟瞰。顶部为「全书体量与阶段总览」(总章节数/目标字数/全书情绪曲线/阶段划分/各阶段节奏公式/关键节点与钩子链,结构见 [Phase 3:大纲搭建](workflow-setup.md#phase-3大纲搭建)),其后接卷级大纲一段式汇总:
```markdown
# 大纲
## 全书体量与阶段总览
{按 Phase 3「全书体量与阶段总览」结构填写}
## 卷级大纲
### 第一卷:{卷名}(约 {X} 万字,{Y} 章)
- 功能 / 所属阶段 / 卷契约 / 终局储备 / 阶段边界 / 核心事件 / 起始状态 → 结束状态
(一段式汇总;展开见各卷 卷纲_第X卷.md)
```
---
## 大纲/卷纲_第X卷.md
卷纲是大纲的展开——大纲决定方向,卷纲决定节奏。包含本卷全部创作规划。
```markdown
# {卷名} 卷纲
## 核心信息
- 章节范围:第{X}-{Y}章
- 字数目标:{W}万字
- 本卷定位:{铺垫/发展/高潮/转折/收尾}
## 卷契约与终局储备(参 `reader-contract-and-progression.md`)
> 单章放开密度、宏观管住终局储备。主推线之外的线按剧情自然给战果,一战多得允许;真正要守的是本卷别动用还不该解锁的终局底牌。
- 卷契约:{本卷读者期待、主角高光、主要期待债}
- 本卷主推线:{1条承担本卷最大高潮的升级线:战力线/资源线/身份线/关系线/信息线/地图线/制度线/势力线/事业线/情感确定性}
- 本卷战果:{其余顺带兑现的线,轻触到大涨皆可;一战多得是好设计}
- 本卷解锁的终局里程碑:{参 `设定/题材定位.md`「终局底牌与升级台阶」小节,本卷推进或解锁哪一个大里程碑}
- 本卷禁碰的终局底牌:{尚未到解锁卷、本卷不得动用的宿敌/真相/身份/金手指上限}
- 契约风险:{契约安全 / 需补强 / 契约破坏;需补强时写清补强方式}
## 剧情单元卡(1–3 万字为可调经验值;存于卷纲内;不另建单独文件)
> 剧情单元 = 卷纲里的一级结构单元(见 outline-structure-theory.md「对标节奏迁移」),与下方「对标结构坐标」是同一单元的不同视角,不重复编排。单元长度按本书题材、既有兑现节奏与对标调整,不是硬门槛。规划各关键节点时消费权威文件的“关键节点四问”和期待所有权;无需主角亲自执行每个动作。高潮/兑现后可留短暂低压,以小而可见的收益/奖励承接下一轮压力。引入新地图/机构/能力/敌人/谜团时先检查换书债,不得借新鲜感逃避旧承诺。
### 剧情单元 {L卷号-序号}
- 单元ID:{L卷号-序号}
- 章节范围:{第A-B章}
- 对标剧情参照:{{书名}《剧情标题》(类型/桥段标签;借什么:结构分布/情节点索引/兑现方式);可列 2-3 条,无对标写「无」}
- 单元节拍/章功能分配:{建立期待→尝试→加压/转向→决定性行动→兑现→余波;标对应章范围,可按题材删改;建卡时可按「对标剧情参照」剧情单元提炼的共性节拍填写,见 outline-structure-theory.md「按剧情批出细纲」}
- 单元承诺:{本单元向读者建立的情绪命题/期待,以及要偿还的期待债}
- 单元情绪引擎:{核心情绪命题→承载对象/情绪缺口→受阻或缺口维持原因→本轮触发→主角不可替代的点火/转化动作→意义变化或可见兑现→题材/契约兑现;承载对象可为人物/关系/目标/规则/场景;不适用环节可写无/即时,但须保持因果闭合;机制按题材选,不强制误解/物件/反转}
- 卷级贡献:{它如何服务本卷契约、阶段节奏或卷级目标}
- 主角局部目标与核心利益:{主角本单元要保住/拿到/证明什么}
- 因果入口:{由上一单元或既有事件自然引出的入口}
- 核心阻碍:{主要敌意、限制、误判或资源缺口}
- 关键选择与决定性行动:{主角不可替代的判断、选择和行动}
- 兑现方式与归属:{核心兑现如何发生,收益归谁、如何可见}
- 本单元主推线/战果:{沿用卷契约划分——主推线1条承担高潮,其余线给战果,一战多得允许}
- 终局底牌边界:{本单元不得动用的未解锁宿敌/真相/身份/金手指上限;碰到就按权威文件透支两问改纲}
- 禁止提前释放:{本单元不能提前解决/揭露/升级的内容}
- 下一单元因果钩子:{自然推入下一单元的问题、代价、线索或新目标}
- 风险等级:{契约安全 / 需补强 / 契约破坏;需补强时写清补强方式}
## 核心矛盾
{一句话:本卷要解决什么问题或达到什么目标}
## 对标结构坐标
{有对标书时填;无则写"无对标,按八节点占比自排"。迁移步骤见 outline-structure-theory.md「对标节奏迁移」;对标关键情节优先取自被参照剧情单元的「情节点索引」}
- 主对标卷段:{对标书}第{A}-{B}章(核心矛盾对应:{一句话})
| 归一化位置 | 本卷章区间 | 对标关键情节 | 本卷对应(换素材) | 类型{逆转/转折/激励} |
|-----------|-----------|-------------|-------------------|---------------------|
| 1/4 | 第{N}章 | {对标事件} | {本卷事件} | {类型} |
| 中点 | 第{N}章 | {对标事件} | {本卷事件} | {类型} |
| 3/4 | 第{N}章 | {对标事件} | {本卷事件} | {类型} |
## 情绪弧线
- 模板:{V形/倒V形/W形/渐进形/延迟满足形/急转弯形}
- 选择理由:{结合题材和本卷定位}
| 章节 | 章节定位{可留空} | 情绪基调{紧张/轻松/悲伤/热血/温馨/震惊} | 情绪强度{1-10} | 触发事件 |
|------|------------|-----------------------------------------|--------------|---------|
| 第{N}章 | {高压/推进/修炼试错/关系回收/低压生活/信息整理} | {基调} | {N} | {事件} |
> 章节定位可留空,留空按普通推进章处理(即退化为现状)。情绪强度是情感烈度,和章节定位的爆发压力是两回事——关系/泪目章可低压力但高情绪强度。一卷要有高低层次,低压 + 过场克制(合计不超约 15%,题材分档见 outline-structure-theory.md),别全程同一力度;逐行看相邻章情绪基调,别同一母题连超 2-3 章。章节定位与底线见 outline-structure-theory.md「章节定位与张弛」。
## 人物弧线
| 角色 | 本卷起点 | 本卷终点 | 关键转变 |
|------|---------|---------|---------|
| {名} | {状态} | {状态} | {事件} |
## 本卷反转(如有)
| 类型{身份/动机/阵营/信息/命运} | 涉及角色 | 误导路径 | 揭示章节 | 影响范围 |
|------|---------|---------|---------|---------|
| {类型} | {名} | {如何误导读者} | 第{N}章 | {影响哪些线} |
## 本卷伏笔
| 伏笔 | 埋设章节 | 预计回收 | 类型{短期/中期/长期} |
|------|---------|---------|---------------------|
```
创建参考:`outline-methods.md` (大纲三层结构法) + `outline-rhythm.md` (升级感三步设计法) + `emotional-arc-design.md` (六种弧线速查) + `long-reversal.md` (反转类型与长线层级)
---
## 大纲/细纲_第XXX章.md
细纲是正文写作的章节蓝图,而不是只列事件和钩子的清单。**模板唯一权威副本**见 [Phase 3:大纲搭建](workflow-setup.md#phase-3大纲搭建) 的「细纲(全书每章)」模板(含单元ID/位置、主角目标/关键选择、任务卡点、结构公式、契约风险行,以及不含逐点字数的情节点表格);本文件不再保留模板副本。新建、补建、回填都按权威模板补齐,未知字段写 `[待补充]`,不为补齐字段杜撰副线或人物关系。
`目标情绪` 与 `主角目标/关键选择` 要写实际内容,不能留 `[待补充]`:隔离实验里只补这两个字段就能复现补齐全部字段的正文收益,补满其余字段与只补这两个不可区分。其余字段未知时仍按上文写 `[待补充]`。
落盘后运行 `node scripts/check-outline-contract.js --json --project {书目录} --chapter {N}` 做结构验收:它只判字段、四个小节、五段式、四列情节点表和字数目标口径是否在场,不判内容好坏。exit 1 时只按 `repair_scope` 补报告点名的字段并复验,最多两轮;仍失败就报告检查 ID 停下,不改其他章。exit 2、脚本缺失或 node 不可用时如实报告验收未完成,不得声称细纲已合规。本检查只在新建/补建/回填时执行;既有项目的旧细纲不因此阻断写正文。
---
## 追踪体系
追踪产物由 `scripts/tracking_commit.py` 统一生成,完整 schema 和事务字段见 [tracking-transaction.md](tracking-transaction.md)。以下文件不得由模型各自追加或局部 Edit:
### `追踪/_tracking-state.json`
唯一结构化权威状态。记录 schema、最后提交章、导入截止章、`state_revision`、续写上下文结构,以及全部角色、伏笔和时间线当前状态。日更通过 `tracking_commit.py check` 的紧凑输出取章号和修订号,不把完整 state 加入正文 prompt。所有 Markdown 都从本文件确定性派生,程序不反向解析 Markdown。
### `追踪/逐章记录/第NNN章.md`
本章未来相关连续性记录,目标 ≤1536 字节、硬上限 3072 字节,只含:实际结果、角色变化、伏笔变化、时间/揭示、连续性约束、下一章承诺。过程日志、质检统计、参照章和提示词记录不进入。它不承诺单独无损重建全部当前状态;完整当前语义以 `_tracking-state.json` 为准。
### `追踪/伏笔.md`
每个 ID 只保留一行当前状态:内容、埋设章、计划回收章、状态、重要度、最近变更章。变化历史由对应逐章增量承担。尚未实际埋设的未来伏笔规划留在大纲;当前表只接受 `已埋 / 已回收 / 已过期 / 放弃`。
### `追踪/角色状态/{角色名}.md`
只为核心、会复用角色建立动态快照,含截至章节、身份、位置、当前目标、身心状态、能力资源、关键关系、已知信息和未结事项。目标 ≤4096 字节、硬上限 8192 字节;超过目标先合并失效能力、旧关系和已结事项,不把角色履历塞进当前快照。静态原始人设仍在 `设定/角色/{角色名}.md`;路人、一次性角色不建动态文件。
### `追踪/时间线/`
- `_tracking-state.json.timeline`:同一事件登记故事时间、客观事实、读者当前认知、实际揭示状态/章节。
- `作者真相.md`:从 `_tracking-state.json.timeline` 派生,作者侧可见全部客观事实和认知差。
- `读者已知.md`:从 `_tracking-state.json.timeline` 派生,只显示读者已经知道/相信的内容,不泄露客观真相。
未来揭示计划写卷纲/细纲,不写进既成事实登记;`未揭示` 事件的 `reveal_chapter` 必须为空。
### `追踪/上下文.md`
续写状态卡不超过 12288 字节,固定 7 栏:`当前位置 / 长期约束 / 核心角色状态 / 活跃伏笔 / 近三章速记 / 下一章承诺 / 连贯性风险`。它是当前语义检查点之一;不放文风、质量计数、普通待办、索引统计和长期概要。
references/author-memory.md›
# 作者记忆协议
作者记忆用于保存跨会话复用的创作偏好,不保存小说世界里的事实。它借鉴“原始证据 → 候选 → 已确认画像 → 变更记录”的记忆管道,但把决定权留给作者。
## 边界与优先级
加载优先级从高到低:
1. 安全、平台、字数、文件协议等硬性门禁;
2. 用户在当前请求中的明确要求;
3. 当前书的 `设定/文风.md`、题材定位、细纲和其他项目设定;
4. 作者记忆中的本书偏好;
5. 作者记忆中的题材、流程和全局偏好;
6. 对标素材、通用方法和默认值。
作者记忆不能把本书事实写进 `.story/作者记忆/`,不能覆盖当前请求,不能降低审稿 rubric,也不能让去 AI 味改动剧情意图。小说事实继续由各书的 `追踪/` 和 `设定/` 管理。
## 文件与所有权
工作区级目录:
```text
{工作区}/.story/作者记忆/
├── _author-memory-state.json # 唯一结构化权威
├── 作者画像.md # 仅 active,供作者查看与管理
├── 待确认.md # pending / conflict,不参与约束
└── 变更记录.md # 最近 100 次、最新在前的事务记录
```
三个 Markdown 文件都从 state 确定性生成,禁止手改;完整历史保留在 state,变更记录只展示最近 100 次。`作者画像.md` 是人类管理视图,普通写作 agent 不整份注入,而是调用 `query` 取得本次相关的紧凑上下文。作者记忆不存在时,普通写作、审稿和去味任务直接继续,不自动初始化空目录;首次 `record` 会随事务创建。
工作区必须显式传给脚本。优先使用已经包含 `.story/作者记忆/` 的最近祖先;首次初始化时使用承载多本书、`.active-book`、`长篇/`、`短篇/` 或 `拆文库/` 的创作工作区根。不要把用户主目录当默认工作区。
## 什么时候读取
长篇、短篇、去 AI 味开始前,如果 state 已存在,用 `query` 按本书、题材、流程和类型筛选 active 条目。查询输出固定不超过 2048 字节。不要先查询全部再让 agent 自行筛选,按任务直接选择 kind:
| 任务 | query kinds | 注入位置 |
|---|---|---|
| 正文初稿 / 续写 | `prose_style` + `story_design` | 主会话与实际正文 agent |
| 去 AI 味 / 改写 | `prose_style` | 主会话与实际改写 agent |
| 设定 / 大纲 | `story_design` + `workflow` + `interaction` | 主会话,不传正文 agent |
| 审稿 | `delivery` + `interaction` + 必要的 `prose_style` | 主会话,不降低 rubric |
审稿匹配项只用于交付格式、协作方式和“作者有意采用的表达选择”说明;问题严重度和 PASS/FAIL 仍由 rubric 决定。
待确认项不进入 prompt 约束,也不应为了确认它们中断当前任务。只有用户主动查看作者画像、候选积累到适合回顾的节点,或新偏好与 active 条目冲突时,才集中呈现。
## 可靠性与负荷边界
- 明确“记住 / 确认 / 替换 / 忘掉”的请求走单事件 `record`,不要求 agent 手工读取修订号或拼多操作事务。成功响应会给出 `Author Memory Receipt: rN · APxxx`;没有回执就不得声称“已经记住”。
- 普通创作只做一次本地 `query`,没有 state 时返回空结果且不创建文件;有记忆时也只返回相关 active 条目,硬上限 2048 字节。完整画像、证据、候选和 journal 不进入正文 prompt。
- 查询项是低优先级倾向,不是逐条打卡清单。自然吸收即可,不复述画像、不刻意提高词面命中率,也不得为命中偏好牺牲正文连贯、节奏、字数或本书既定笔调。
- 不安装会记录全部用户消息的 prompt hook。自然语言是否属于长期习惯仍需 agent 判断;这样不能承诺隐式偏好 100% 捕获,但避免把一次性要求、私人对话和小说事实静默写入长期记忆。需要确定写入时,用户可明确说“记住:……”,并以回执验收。
## 捕获判定
| 输入证据 | 处理 |
|---|---|
| “以后都这样”“我一直习惯……”等直接、稳定、范围清楚的原话 | `active`,`source=explicit_user` |
| 用户明确接受助手提出的长期做法 | `active`,`source=accepted_suggestion` |
| 同类修改反复出现,但用户没说这是长期规则 | `pending`,`source=repeated_correction` |
| 从成稿或操作轨迹推断出的模式 | `pending`,`source=inferred_pattern` |
| “这一章别……”“这次给我……”等一次性要求 | 只执行,不记录 |
| 角色、时间线、伏笔、世界观、当前剧情走向 | 写项目设定/追踪,不写作者记忆 |
| 助手自己生成的文字、默认模板、工具告警、rubric 结论 | 不自我学习 |
保留用户的否定词、限定词和适用范围,`quote` 写原话,`assertion` 只做不改变语义的紧凑归纳。范围规则:
- “本书 / 这个角色 / 这次连载” → `book`;
- “都市文 / 这类题材” → `genre`;
- 交稿、检查、确认节奏等操作习惯 → `workflow`;
- “以后 / 一贯 / 我习惯”且无更窄限定 → `global`;
- 范围含糊但可能稳定 → 取当前最窄合理范围并置 `pending`。
类型可选:`prose_style`、`story_design`、`workflow`、`delivery`、`interaction`。置信度与重要度均为 `low | medium | high`。
## 冲突、撤回与强化
- 同一类型、范围、归纳文本再次出现时,脚本强化原条目,累加证据和确认次数,不重复建条目。
- 新偏好与 active 条目矛盾时,先以 `conflict` 记候选,并在 `conflicts_with` 列出冲突 ID;当前任务仍按本轮明确要求执行。
- 作者选定新规则时用 `replace`,一次性启用新条目并把旧条目标成 `superseded`。
- pending 可以用 `decide=activate|reject`;冲突候选不能绕过旧规则直接 activate。
- 作者说“忘掉 / 这不再是我的习惯”时用 `forget`,保留历史证据但不再加载。
- active 条目的语义不可原地偷改;语义变化必须 replace,历史才可审计。
## 运行工具
先依次尝试 `python3`、`python`、`py -3` 找到 Python 3,再从当前 skill 根运行本地副本:
```text
{PYTHON} {当前 skill 根}/scripts/author_memory_commit.py init --workspace {工作区}
{PYTHON} {当前 skill 根}/scripts/author_memory_commit.py record --workspace {工作区} --input {单事件.json}
{PYTHON} {当前 skill 根}/scripts/author_memory_commit.py query --workspace {工作区} [--kind prose_style] [--book {书名}] [--genre {题材}] [--workflow {流程}]
{PYTHON} {当前 skill 根}/scripts/author_memory_commit.py commit --workspace {工作区} --input {事务.json}
{PYTHON} {当前 skill 根}/scripts/author_memory_commit.py check --workspace {工作区}
```
- `record`:常用单事件入口,自动读取当前修订、首次自动初始化;`event_id` 相同且内容相同会幂等返回原回执,内容不同会失败。
- `query`:只读相关 active 条目;`--kind` 可重复,不存在 state 时返回空结果且零写入。返回的 `omitted > 0` 时收窄 kind / book / genre / workflow 后重查,不得改读完整画像规避预算。
- `commit`:高级批量入口;先在内存完成 schema、引用、容量和所有视图校验,最后原子替换 state。事务文件在成功前必须保留;过期修订会在任何写入前失败。
- `check`:从 state 重建并逐字核验所有派生视图。
## 事务格式
常用单事件新增或强化:
```json
{
"schema_version": 1,
"event_id": "conversation-2026-08-25-message-42",
"operation": {
"action": "remember",
"preference": {
"kind": "prose_style",
"scope": {"level": "global", "value": null},
"assertion": "对话尽量短,用动作承接情绪,不用大段解释",
"quote": "以后对话都短一点,情绪放动作里,别让角色长篇解释。",
"source_ref": "conversation:2026-08-25",
"source": "explicit_user",
"confidence": "high",
"importance": "high",
"status": "active",
"reason": "用户以“以后”明确声明长期偏好",
"conflicts_with": []
}
}
}
```
把文件交给 `record`。待确认项的 `status` 用 `pending`;冲突候选用 `conflict` 并填写 active ID。确认或拒绝候选时,把下列对象作为新事件的 `operation`:
```json
{"action":"decide","item_id":"AP002","decision":"activate","quote":"对,这就是我的长期习惯。","reason":"作者明确确认"}
```
用新规则替代一个或多个旧条目时,`replace.preference` 与上例字段相同,但不传 `status`、`conflicts_with`,新条目直接 active;下列对象同样作为 `operation`:
```json
{
"action": "replace",
"old_ids": ["AP001", "AP002"],
"preference": {
"kind": "prose_style",
"scope": {"level": "book", "value": "雾港来信"},
"assertion": "本书对话允许更长的试探,但避免解释设定",
"quote": "这本书可以让对话慢一点,多试探,但还是别拿台词讲设定。",
"source_ref": "conversation:2026-08-25",
"source": "explicit_user",
"confidence": "high",
"importance": "high",
"reason": "作者明确用本书新规则替代旧候选"
}
}
```
撤回条目的 `operation`:
```json
{"action":"forget","item_id":"AP003","quote":"忘掉这个偏好。","reason":"作者明确撤回"}
```
需要把多个动作绑定成一次原子提交时才用高级 `commit`:顶层传 `schema_version`、唯一 `transaction_id`、当前 `expected_state_revision` 和含 1–32 项的 `operations`。操作按数组顺序应用,任一步失败则整份事务零写入。成功后删除临时输入文件;显式记忆请求还要把工具返回的回执原样告诉用户。
references/banned-words.md›
# AI味禁用词与句式表
<!-- 同名副本×6 字节同步,改动后跑 scripts/check-shared-files.sh -->
## 最毒禁用句式(出现即修,最高优先级)
写网文最毒的 AI 句式,作者一旦养成就会反复出现。Gate A 第一遍扫描必须命中:
| 毒级 | 句式 | 错误例 | 修法 |
|------|------|--------|------|
| ★★★★★ | "不是A,(而)是B" / "不是A,不是B,(而)是C"("而"可省略,省掉也算命中)| "他不是冷漠,而是绝望" | 直接写 B 或用更自然的表达 |
| ★★★☆☆ | 跨段「不是A。/也不是B。/只是C。」 | 「不是嚎啕大哭。/也不是扯着嗓子喊不舍。/只是一个人走远了……」 | 语义复核;重复提纲或拖慢画面时压成 C,有辩解/悬念排除功能可保留 |
| ★★★★ | ",带着……" 万能状语 | "他笑了一下,带着一丝不易察觉的嘲讽" | 删掉状语留主句,或换具体动作 |
| ★★★★ | 无情绪声线:"声音不大,却带着……" / "语气毫无波澜" / "平静无波" / "声音平直/平平/听不出情绪" | "她声音不大,却带着不容置疑的力量" | 直接写台词内容、声音特征或动作 |
| ★★★★ | "他/她知道……" | "他知道这一切都来不及了" | 用行为展示认知 |
| ★★★ | "仿佛/犹如/宛若……一般" | "仿佛能穿透一切一般" | 删掉或白描 |
| ★★★ | "眼中闪过一丝……" / "嘴角勾起一抹……" | "眼中闪过一丝悲伤" | 删掉;写他当场说的话或做出的决定 |
| ★★★ | "心中涌起一股……" / "心头一震" | "心中涌起一股暖流" | 写它改变了什么:选择、台词、物件或后果 |
| ★★★ | 抽象命运/开端收束:"命运……棋局/獠牙" / "这一刻终于明白" / "反击才刚刚开始" | "命运终于露出獠牙;属于他的反击才刚刚开始" | 回到角色当下可见的文件、动作、对话或物理后果 |
| ★★ | 章末预告 "他不知道的是……" | "他不知道的是,更大的风暴即将来临" | 用具体钩子物件/事件收束,避免空泛预告 |
> 凡命中 ★★★★★ 一处即视为重度AI味的强证据;★★★★ 命中 ≥2 处即触发中度复扫。
`check-ai-patterns.js` 的 `formulaic-parallelism` 还会提示「至于X不X,怎么X」和同动词「不V A,不V B」。这两类可能是功能性口语,因此只做 advisory;Gate B 必须连同台词读语境复核,若只是复述细纲/前文就压成一次判断,不能因 hook 豁免台词而跳过。
**标点**:正文(含叙述和对话)禁用破折号 `——`/`—`、双连字符 `--` 和省略号停顿,改用句号、逗号、短句或动作断句;不设置对话破折号例外。盐言「」引号不在此列。
---
## 一级禁用词(出现即替换)
> 什么词进一级:只收真人语料里几乎不出现、AI 特有的词。真人高频使用的自然副词和虚词不进一级,走二级密度控制。
### 情态类
仿佛、犹如、宛若、如同、一丝、一抹、些许、几分、隐约、毫无征兆、几不可闻、微不可察
### 动作类
深吸一口气、不禁
### 表情类
眼中闪过、嘴角勾起、眉头微皱、眉眼低垂、瞳孔微缩、瞳孔收缩、瞳孔一缩、指节泛白、眼神锐利、目光锐利
### 心理类
心中一动、心头一震、心下了然、心中暗道、心底泛起、不由得、心中一凛
### 判断类
不容置疑、不容置喙、不易察觉、显而易见、毫无疑问、不可否认、前所未有
### 形容类
坚定、闪烁着光芒、狡黠、深邃、凛冽、冰冷
### 过渡类
不由自主、情不自禁、自然而然、话锋一转
## 二级禁用词(高频出现时替换)
### 语境敏感词(仅高频或偷懒时处理)
突然、陡然、骤然、猛然、好像、似乎、瞬间、猛地、死死地(角色口语、真实突发、时间压缩、视角不确定时可保留;用同义变体轮换规避重复不算豁免,按同一个词计密度)
### 弱化副词(密度控制)
缓缓、微微、轻轻、淡淡(每千字合计 ≤3;这四个词同时计入 `cliche-density-tic` 的套词密度统计;孤立自然使用可保留,成串出现或每个动作都垫一个时才替换)
### 书面腔 → 口语化
| 书面腔 | 口语化替换 |
|--------|-----------|
| 瓦解 | 消失 / 散了 / 没了 |
| 无名火 | 烦躁 |
| 往我心上捅刀子 | 心烦意乱 |
### 总结句式
- "他/她终于明白..."
- "他/她这才意识到..."
- "这一刻,他/她终于明白/意识到..."
- "从这一刻开始..."
- "属于X的反击/复仇/故事,才刚刚开始"
- "命运/宿命 + 齿轮/棋局/獠牙/改写/安排"
- "此刻,他/她..."
- "一切...都..."
- "原来..."
### 排比句式
- 连续3句以上相同结构的排比
- "有的...有的...有的..."
- "一边...一边...一边..."
### 升华句式
- "这一刻..."
- "他知道..."
- "她明白..."
- "这就是..."
## 禁用句式模板
| 句式 | 示例 | 问题 |
|------|------|------|
| "不是A,而是B" | "他不是冷漠,而是绝望" | 最毒;直接写 B |
| "...,带着..." | "他说,带着一丝无奈" | 万能状语 |
| "声音不大,却带着……" | "她声音不大,却带着不容置疑的力量" | AI 最爱声音描写 |
| "仿佛能...一般" | "仿佛能穿透一切一般" | 文言腔 |
| 对话标签密度过高/公式化标签 | "好的,他说道" | 普通"说"可保留;高频或公式化时处理 |
| "他/她感到..." | "她感到一丝失落" | 告诉而非展示 |
| "他/她意识到..." | "他意识到事情不对" | 直接告知 |
| "眼中闪过一丝XX" | "眼中闪过一丝悲伤" | 模板化 |
| "嘴角勾起一抹XX" | "嘴角勾起一抹冷笑" | 模板化 |
| "心中涌起一股XX" | "心中涌起一股暖流" | 模板化 |
| "取而代之的是" | "笑容消失,取而代之的是冰冷" | AI 过渡模板;直接写新状态 |
| "淬了/淬着X" | "眼里淬了毒" | AI 通感套路;写动作或台词 |
| "显得(有些)X" | "他显得有些兴奋" | 告诉而非展示 |
| "心底/心里某个地方+软" | "心里某个地方软得一塌糊涂" | 言情套句;写动作 |
| "(浑身)散发着一股X气息/气场" | "浑身散发着一股生人勿近的气息" | 万能气场描写;写旁人的反应 |
| "命运/宿命 + 齿轮/棋局/獠牙/改写/安排" | "命运终于露出獠牙" / "早已布好的棋局" | 抽象作者总结;改成角色当下撞见的文件、动作、对话、物理后果 |
| "这一刻终于明白/从这一刻开始/才刚刚开始" | "这一刻,他终于明白" / "反击才刚刚开始" | AI 收束腔;删总结,用动作或未解决问题收尾 |
## 比喻分类(默认复核,不默认全删)
带"像/如/仿佛/犹如/宛若"的比喻不是一律 AI。真正高风险的是:成片堆叠、套用万能文学比喻、用精致比喻替代剧情推进,或在段尾替读者总结意义。本表用于识别需要复核的比喻类型:
| 比喻类别 | 例 | 处理 |
|---------|----|------|
| 生活/角色化 | "像一头被抛弃的野狗" | 若贴角色视角、能传递信息或情绪,可保留 |
| 物品/现象类 | "像一把刀" "脸色惨白得像这漫天的雪" | 普通功能性比喻可留;模板化或重复时改白描 |
| 状态类(陈词滥调) | "梨花带雨" "如沐春风" | 优先删或改成具体动作/表情 |
| 抽象类 | "像命运的齿轮" "像上辈子的尘埃" | 高风险,优先落回动作、物件、声音、后果 |
| 假设类 | "力道大得像是要把骨头捏碎" | 若是角色身体感知可留;夸张堆叠时改事实后果 |
处理原则:先看功能,再看密度。保留最能传递信息或情绪的一两个,其余改为直接描述、动词、名词、作用、结果或事实;不要把删掉的比喻替换成另一批新比喻。例 "脸色惨白得像这漫天的雪" 若只是套话 → "脸色惨白";若雪景正在压迫角色,可保留或改成角色当下看到的具体画面。
> `metaphor-density-tic` 是 advisory:提示通读复核,不是 blocking;生活化、角色化、单个有功能的比喻可以保留。
## 替换策略速查
| 原文类型 | 替换方法 | 示例 |
|----------|----------|------|
| 抽象情绪词 | 先看上下文是否已成立;再选选择、台词、物件、后果或一句直写 | “紧张”若不影响下一步可直写或删;若导致签名作废,就写作废的结果 |
| "感到XX" | 删除“感到”后按场景决定是否还要情绪句 | “他感到愤怒”可写“他火了”,也可直接写他撤回报价;不要默认换成攥拳 |
| 形容词堆砌 | 白描手法 | "美丽动人的笑容" → "她笑了" |
| 书面表达 | 口语化 | "不容置疑" → "就是" |
| 解释性描写 | 留白 | "他因为害怕而..." → "他退后一步" |
| 连续排比 | 保留最强一条 | 3 句排比留 1 句 |
| 总结升华句 | 直接删除 | "这一刻,她终于明白了..." → 删 |
| "不是A,而是B" | 直接写 B 或更自然的表达 | "他不是冷漠,而是绝望" → 直接写 B |
| 多余修饰(形容词/定语/量词/指示代词) | 删 | "白色的药片" → "药片";"手里那截链子" → "链子";"飞驰的汽车" → "车" |
**替换不复用**:右列是方向示例,不是标准答案。同一禁用词在一章内多次命中时,各处给不同的具体化写法;同一个替换写法反复出现(每次都「垂下眼」、每个动作都补「了一下」),替换产物本身就成为新的模板指纹。
**套词密度优先处理**:`check-ai-patterns.js` 报 `cliche-density-tic` 时,说明禁用词不是零星误用,而是聚成了模板腔。处理顺序不是同义词替换,而是先删抽象总结,再把情绪/判断落到角色当下可见的动作、物件、对话和具体后果。
**套式反应逐处删除测试**:`stock-reaction-tic` 报警时,不代表禁止身体描写。逐处问:删掉后信息、选择、关系、物件或动作结果是否受损?无损就删,不把“指尖轻叩”换成“目光微沉”。伤势、动作失败、人物习惯或情节后果明确时可以保留。
references/character-basics.md›
# 角色基础设计
> 设计主角/配角/反派时加载。先看决策路由,选对模板,再按步骤操作。character-designer 主输出参考。
---
## 决策路由
| 你在设计什么 | 用这个模板 | 见哪个章节 |
|------------|-----------|-----------|
| 主角 | 主角卡模板 | 第1节 |
| 配角 | 配角卡模板 | 第2节 |
| 反派 | 反派层级表 → 反派建立四要素 → 反派性格四步法 | 第3节 |
| 角色动机 | 动机链模板 → 动机冲突类型 | 第4节 |
| 角色塑造/深化 | 塑造方法速查(四层法/执念法/重复点/分层展示等) | 第5节 |
| 主角特殊问题 | 逼格/成长/红线/调子太高/身份与金手指 | 第6节 |
| 反派塑造深化 | 反派渲染/人设主角化 | 第7节 |
---
## 第1节:主角卡
### 填空模板
```
姓名:
性别:
角色定位:(一句话说清主角在故事中的功能)
身份标签:(如:废柴大学生、前特种兵、落魄皇子)
外貌特征:(3-5 个关键词,要有记忆点)
例:瘦高、总穿旧夹克、左手有疤、眼神懒散
性格关键词:(3-5 个,必须有矛盾面)
例:嘴毒心软、看似冷漠实则护短、冲动但有底线
核心目标:(全书终点想达成什么)
核心动机:(必须达成的理由——情感驱动,非理性驱动)
致命弱点:(让角色犯错的性格缺陷,非能力缺陷)
口头禅/标志动作:(让读者秒认的标签)
```
### 设计要点
- 动机必须是情感层面的——"为母亲复仇"优于"要成为最强"
- 弱点必须会在关键情节导致主角犯错,否则不是弱点
- 外貌和口头禅是读者记忆锚点,必须写
- 起名贴合故事的时代、地域和文化,别用与设定冲突的现代化或政治化名字;写同人或既有世界观时,原著角色沿用官方本名/译名不自造,新角色顺着原著对应地域的命名和译名风格来,同一地域不混语系
---
## 第2节:配角卡
### 填空模板
```
姓名:
性别:
角色功能:(导师/盟友/情报源/牺牲品/镜像对照)
与主角关系:
核心特质:(1-2 个关键词)
标志性特征:(一句话让读者记住)
退场方式:(何时/如何退出故事)
```
### 设计要点
- 每个配角必须有明确功能——没有功能的角色不要出场
- 配角退场要主动规划,不能写着写着忘了
- 同一场景配角不超过 3 个有台词
- 起名跟着设定的时代、地域、文化走;同人或既有世界观里,龙套和新配角也要顺原著对应地域的命名风格,别混语系、别塞与设定不符的现代化或政治化名字
---
## 第3节:反派设计
### 3.1 反派层级表
根据反派出场篇幅选对应层级,按表格要求设计。
#### 小反派(1-5 章)
| 维度 | 要求 |
|------|------|
| 功能 | 单个小弧线的障碍 |
| 设计 | 1-2 个鲜明特征即可(嚣张/贪财/欺软怕硬) |
| 退场 | 被打败或被揭穿,干脆利落 |
#### 中等反派(10-30 章)
| 维度 | 要求 |
|------|------|
| 功能 | 一卷的主要对手 |
| 动机 | 为什么跟主角作对(不能是"纯粹的坏") |
| 手段 | 武力/权谋/资源 |
| 逼格 | 至少赢主角一次,让读者恨得牙痒 |
| 退场 | 被主角正面击败,要有爽感 |
#### 大弧Boss(一卷或数卷)
| 维度 | 要求 |
|------|------|
| 功能 | 代表一个阶段的核心矛盾 |
| 人弧 | 完整的人物弧线,有自己的目标和逻辑 |
| 冲突 | 与主角有理念冲突(不只是利益冲突) |
| 对决 | 至少一场让主角陷入绝境 |
| 侧面 | 有一个让读者"恨不起来"的侧面 |
| 退场 | 有仪式感的终战 + 有余味的落幕 |
#### 最终Boss(全书)
| 维度 | 要求 |
|------|------|
| 功能 | 全书核心矛盾的具象化 |
| 伏笔 | 从第一章就有 |
| 对立 | 与主角的目标/动机直接对立,代表故事主题的反面 |
| 实力 | 碾压主角,主角必须蜕变才能赢 |
| 信念 | 有信念,不是纯粹的疯子/怪物 |
### 3.2 反派设计铁律
- 反派的智商/实力决定主角的含金量——反派弱 = 主角赢没意义
- 反派的行为必须有内在逻辑(从他的视角说得通)
- 不要让反派降智来给主角送赢
### 3.3 反派建立四要素
按顺序操作,缺一不可:
1. **实力展示**——出场就展示实力或手段
2. **动机可信**——从反派视角看行为说得通
3. **真实威胁**——至少赢主角一次
4. **终极意图时机**——真实目的留到关键反转点
### 3.4 反派性格确立四步法
| 步骤 | 操作 |
|------|------|
| 1. 反派也有梦想 | 在反派眼中他是自己故事的主人公 |
| 2. 挖掘创伤性过去 | 谁抚养他?谁爱他?谁伤害他?他避免什么痛苦? |
| 3. 磨练性格缺陷 | 遭遇逆境时不调动积极特质,而是磨练缺陷——"优势"本身就是致命缺陷 |
| 4. 反派是主角的镜子 | 反派的长处反映主角的弱点,两者完全相反 = 每次相遇必然摩擦 |
### 3.5 反派渲染分量的关键
- 障碍从反派人设上来,而不是故意给主角制造障碍
- 反派渲染公式:明确动机 → 动机驱动行为 → 行为形成障碍 → 障碍强度来自反派分量
- 反派异常强势时,主角要破得"高级""智慧""出乎意料"
---
## 第4节:动机设计
### 4.1 动机链模板
```
起因(Cause) → 角色经历了什么
意图(Intent) → 角色想做什么
约束(Constraint)→ 什么在阻碍他
风险(Risk) → 失败的代价是什么
```
**示例**:
```
起因:母亲被仇家杀害
意图:找到凶手并复仇
约束:凶手是当朝权臣,主角只是平民
风险:复仇失败会被灭门,复仇成功会失去所有现有生活
```
### 4.2 动机链设计要点
- 起因必须具体——"被欺负"不够,"在众目睽睽下被打耳光"才行
- 约束必须有力——否则主角一路碾压没有张力
- 风险必须真实——读者要相信主角真的可能失去重要的东西
- 动机可以随剧情演变,但不能说变就变
### 4.3 动机冲突类型
遇到角色需要内心挣扎时,从下表选一种冲突类型:
| 类型 | 定义 | 示例 |
|------|------|------|
| 目标 vs 道德 | 想做的事和应该做的事冲突 | 复仇但不想伤及无辜 |
| 情感 vs 利益 | 感性和理性的拉扯 | 知道对方不可靠但放不下 |
| 短期 vs 长期 | 眼前利益和远大目标的矛盾 | 妥协保命 vs 坚持原则赌未来 |
| 自我 vs 他人 | 个人需求和他人期望的冲突 | 想过平静生活但背负家族使命 |
---
## 第5节:角色塑造方法速查
### 5.1 角色塑造核心原则
**主角行为三必须**:
1. **必须可理解**——读者必须理解主角为什么这么做
2. **必须可共鸣**——主角的思考读者必须能代入
3. **必须可接受**——主角的三观读者必须能接受
**展示优于告知**:
- 角色的目的 → 通过行为展示,不是旁白解释
- 角色的行动 → 具体的动作和决定,不是形容词堆砌
- 角色的态度 → 通过对话和反应体现,不是心理独白
### 5.2 展示人物特质的方法
| 方法 | 操作 | 示例 |
|------|------|------|
| 敏感性 | 触碰弱点,看反应方式 | 惊慌失措/匆忙逃跑/转移注意力=不同性格 |
| 逃避 | 展现回避行为暗示弱点 | 角色的"不做什么"比"做了什么"更揭示深层性格 |
| 先正后缺 | 先展示吸引人特质,再揭示缺陷 | 读者先喜欢角色,才能容忍缺陷 |
### 5.3 四大性格属性
| 属性类别 | 定义 | 设计要点 |
|---------|------|---------|
| 道德属性 | 是非信念 | 影响其他性格形成 |
| 成就属性 | 推动达成目标 | 与道德属性一致,服务目标 |
| 互动属性 | 与人交流方式 | 数量最多的积极特质 |
| 身份属性 | 身份认同感 | 定义个性的基本组成部分 |
选择技巧:以其中一个特质为主要特质,其他为辅。
### 5.4 角色塑造四层法
| 层次 | 方法 |
|------|------|
| 移情作用 | 开头不要太多角色,先让读者了解主角并产生期待 |
| 最小特征(标签) | 主角由内而外塑造,配角由外到内塑造(贴标签) |
| 角色的不真诚 | 所说≠所想,举动≠态度,日常与便当是深化角色的两极 |
| 角色的聚光灯 | 配角必须与主角产生强烈联系性,配角压过主角时塑造新配角夺走光环 |
### 5.5 人物塑造与人物真相
| 层面 | 定义 | 示例 |
|------|------|------|
| 人物塑造(显型) | 读者第一眼看到的特质 | 外表青春可爱的萝莉 |
| 人物真相(隐性) | 角色内在的真实面貌 | 实际上是冷血杀手 |
| 价值取向(内隐) | 关键选择时起决定作用的价值观 | 在道义与野心间选择野心 |
操作要点:价值取向不必一开始揭示,在关键抉择时自然暴露;人物真相的揭示越晚,戏剧张力越强。
### 5.6 人设分层展示法
| 层次 | 操作 |
|------|------|
| 第一层 | 告诉读者类型模型(萝莉/御姐/少妇) |
| 第二层 | 贴特点标签(胸大/腿长/小麦色皮肤) |
| 第三层 | 为性格找原因(家庭/内在冲动) |
| 第四层 | 打破——可爱天然呆其实什么都知道,人设立刻升华 |
深化记忆:不要吝啬重复词汇,觉得太小白?其实在深化记忆。
### 5.7 人物经历三线时间法
| 时间线 | 内容 |
|--------|------|
| 过去 | 身世背景、遭遇变故、性格成因 |
| 现在 | 与主角的关系定位、当前互动模式 |
| 未来 | 制造变强动力或危机(老师被劫/女主被抓/反派揭底) |
### 5.8 配角执念设定法
快速让读者认同支线配角:
- 给角色一个执念 → 所有行为/爱好/性格围绕执念展开
- 不需要每次贴合执念,只要不写与执念冲突的东西,关键时揭示即可
- 过于极端的执念 → 加入"亲民"小细节 → 便于读者认同
- 适用:支线配角,不适合频繁出现的主要配角
### 5.9 人物行为重复点设计
维持长篇不歪的关键手法:
- 抓住一个人物行为特质反复写
- 构建方法:确定读者喜欢什么类型 → 具体化为行为 → 不同场景重复
- 人物看点 + 核心看点 = 层次感,两者循环产生差异化
- 反派/配角也需要重复看点,能让人爱上的反派会增加读者新鲜感
### 5.10 围绕人设写行为
行为、语言、思维都要围绕人格展开。如果为了剧情需要让角色做出不符合人设的行为 → 先修改剧情,不要改人设。
### 5.11 人推事件 vs 事件推人
| 驱动方式 | 特点 |
|---------|------|
| 人推事件 | 情节是人物性格/动机/选择的自然结果,深化人物弧光 |
| 事件推人 | 外部事件打破平衡,迫使暴露真实自我 |
卡文时 → 从人物动机找方向,不要硬编剧情。
---
## 第6节:主角特殊问题
### 6.1 主角逼格
- 主角必须有逼格——这是读者的代入基础
- 不要写太多降智的内心戏和爆粗口
- 主角可以不完美,但不能让人看不起
### 6.2 主角的成长
- 成长不只体现在实力上,更体现在心智和选择上
- 每次成长都要有触发事件和内在反思
- 网文主角成长非必须:开场三观圆满的正常人更容易代入,稳定人设本身就是魅力
### 6.3 主角红线
以下类型的主角绝对不要写:
| 禁止 | 原因 |
|------|------|
| 圣母型主角 | 读者要痛快而非道德说教 |
| 无脑战斗机器 | 难以产生情感共鸣 |
| 内核邪恶 | 读者无法代入 |
| 因蠢/圣母犯错 | 读者无法原谅 |
| 自暴自弃 | 比被欺负更让读者厌恶 |
### 6.4 主角调子起太高怎么办
**危害信号**:
- 失去成长空间——能力/地位/资源触达天花板
- 剧情缺乏张力——陷入"砍瓜切菜"的重复循环
- 读者失去追更动力
**化解方法**:
- **压势不压人**——压低气势和期待,但不打压主角本身的能力和尊严
- **留出维度差距**——即使某方面很强,总有其他维度是短板
- **超额收获法**——看似收获很大,经主角盘算后发现更大
### 6.5 主角开篇立人设
- 人设通过选择建立,开篇必须让主角做出选择
- 智斗型开局比暴力型开局更容易立人设
- 读者更容易代入"聪明但普通"的主角,而非"上来就无敌"的主角
### 6.6 主角的两个身份与两个金手指
| 维度 | 定义 | 作用 |
|------|------|------|
| 显性身份 | 社会身份/职业+状态 | 汇集前期矛盾,必须不断升级或换 |
| 隐性身份 | 不凡的身世来历 | 汇集中后期矛盾 |
| 显性金手指 | 系统/玉坠/重生记忆 | 开局获得贯穿全书 |
| 隐性金手指 | 主角性格 | 让主角与众不同的就是金手指 |
**最佳写法**:前期以金手指装逼 → 剧情推进中逐步把人设清晰
**人设与全书气质**:主角人设必须与世界基调相符,四点高度统一:社会身份+身世+金手指+性格
### 6.7 性格单一缺陷型主角+动物伙伴体系
如果主角性格故意设为单一 → 降低读者带入排斥感 → 少做少错 → 最大限度提升代入感。
**问题**:性格过于单一 → 影响精彩程度 → 难以推进故事
**解法**:给淡漠型主角配备 3-5 只动物伙伴,每只不同性格。
| 伙伴类型 | 功能 |
|---------|------|
| 蠢萌犯二型 | 负责搞笑,主角不宜吃瘪但动物可以 |
| 聪敏嘴贱型 | 负责嘴替,主角不该说的话由它说,保持主角逼格 |
| 耿直蠢笨型 | 负责反差萌 |
| 奇特能力胆小型 | 负责能力补充 |
### 6.8 核心情绪与表达欲平衡
- 需求的内核不变,变的只是形式
- 写完一段剧情后,站在读者角度审视是否偏离核心梗
- 主角牛逼了必须有所得,不能光付出没回报
- 表达欲旺盛时最容易偏离——要主动检查
### 6.9 压势不压人:矛盾的正确来源
**错误做法**:让反派莫名其妙针对主角,背后逻辑站不住脚。
**正确做法**:反派有自己的目的,行动客观上导致主角困境,但并非刻意针对主角本人。
**矛盾链条**:反派目的 → 压制主角所在群体(压势) → 主角推翻 → 底层依旧麻木 → 主角改变路径 → 新冲突自然产生
核心:所有人被自己想要的利益驱动,背后是三观不同,更深是成长环境,最深层是世界观。
---
## 第7节:反派塑造深化
### 7.1 反派塑造核心原则
- 经典反派一定有完整世界观和逻辑自洽的三观
- 同样的外部事件发生在不同人身上产生不同变化——外因与内因共振
- 反派塑造不能只有外部事件,缺乏内在三观和内在逻辑
### 7.2 反派人设主角化写法
**传统问题**:换地图后原反派跟不上节奏 → 引入新反派脸谱化
**解法**:
- 把反派当主角去写
- 在"配角衬主角"基础上加"配角衬配角"
- 换地图的正确处理:用新地图衬托旧角色含金量,而非用旧角色无力衬托新地图难度
---
## 质量检查清单
设计完角色后,逐项检查:
### 主角检查
- [ ] 动机是情感层面的(不是"要成为最强"这种空话)
- [ ] 有致命弱点,且会在关键情节导致犯错
- [ ] 外貌有记忆点(3-5 个关键词)
- [ ] 有口头禅或标志动作
- [ ] 逼格在线——不会让读者看不起
- [ ] 没有触碰红线(圣母/无脑战斗机器/内核邪恶/因蠢犯错/自暴自弃)
- [ ] 核心目标和全书主线对齐
### 配角检查
- [ ] 有明确功能(导师/盟友/情报源/牺牲品/镜像对照)
- [ ] 核心特质 1-2 个关键词能概括
- [ ] 有标志性特征让读者记住
- [ ] 退场方式已规划
- [ ] 同一场景不超过 3 个配角有台词
### 反派检查
- [ ] 按层级表设计,篇幅与层级匹配
- [ ] 出场展示了实力或手段
- [ ] 动机从反派视角说得通
- [ ] 至少赢主角一次(中等反派及以上)
- [ ] 没有降智送赢
- [ ] 大弧Boss有理念冲突(不只是利益冲突)
- [ ] 最终Boss从第一章就有伏笔
### 动机检查
- [ ] 起因具体(不是"被欺负"这种模糊说法)
- [ ] 约束有力(主角不能一路碾压)
- [ ] 风险真实(读者相信主角可能失去重要东西)
- [ ] 动机演变有铺垫,没有说变就变
### 塑造检查
- [ ] 角色目的通过行为展示,不是旁白解释
- [ ] 行为/语言/思维围绕人设展开,没有为剧情改人设
- [ ] 主要角色有行为重复点,维持长篇一致性
- [ ] 配角与主角有明确联系,不会抢主角风头
- [ ] 人物真相/价值取向在关键抉择时自然暴露
references/character-design-methods.md›
# 角色设计操作手册
> 用途:角色设计的方法指令集。按决策路由找到对应方法,按步骤执行。
---
## 决策路由
| 你在做什么 | 用什么方法 |
|-----------|-----------|
| 设计角色反差 | 三层标签反差法 + 行为反差进阶 |
| 设计配角 | 配角功能化 + 群像写作法 |
| 凸显人设 | 凸显人设速查表 |
| 设计感情桥段 | 高情商桥段模板 |
| 深化角色立体感 | 向人设深化法 + 九维人设框架 |
| 建立代入感 | 代入感构建法 |
| 管理角色关系 | 人设关系四阶段 + 职场思维结构 |
| 设计主角特质 | 金手指绑架人设 + 以梗为中心塑造 |
---
## 三层标签反差人设法
### 三层结构
| 层级 | 名称 | 含义 | 示例 |
|------|------|------|------|
| 第一层 | 身份标签 | 外界看到的身份 | 豪门弃妇 |
| 第二层 | 表现标签 | 角色展现给外界的行为 | 隐忍不发、逆来顺受 |
| 第三层 | 内核标签 | 角色真正的内心 | 冷静、有计划、步步为营 |
### 执行指令
1. 为角色填写三层标签,三层之间必须制造反差——反差 = 立体感
2. 身份标签和表现标签可以相似(强化刻板印象),但内核标签必须反转
3. 反差越大,角色的"亮牌时刻"越震撼
4. 每个重要角色都应至少有一层反差
5. 用行为对比来体现反差,不要直接描述:
```
身份标签:豪门弃妇
表现行为:被骂不还口,被赶不反抗
内核行为:悄悄录音、收集证据、提前转移财产
```
---
## 三层标签行为反差进阶
当关系进入第三层(亲密关系)后,角色在第一、二层关系中能做出的行为反而做不出来了。
| 关系阶段 | 可做行为 | 不可做行为 |
|----------|---------|-----------|
| 身份标签期(陌生) | 调戏、冷漠、保持距离 | — |
| 表现标签期(熟悉) | 继续之前的行为模式 | — |
| 内核标签期(亲密) | 展露真实自我 | 之前的调戏/冷漠反而做不出来了 |
### 执行指令
1. 检查角色当前处于哪个关系阶段
2. 行为反差本身是人设的一部分,必须写进剧情
3. 用"行为退化 = 感情深化"制造张力——身份标签期爱调戏主角的辣妹,进入亲密关系后反而不敢表白
4. 不要让角色在亲密阶段仍然维持早期行为,否则反差失效
---
## 人设关联分层(强/中/弱关联)
| 层级 | 定义 | 功能 | 数量要求 |
|------|------|------|---------|
| 强关联 | 直接影响剧情走向和核心梗装逼爽点的设定 | 推动人物碰撞、剧情推进 | 每个角色至少 3 个 |
| 中关联 | 配角的强关联设定,不能抢主角风头 | 为配角提供功能性和辨识度 | 适量 |
| 弱关联 | 丰富人物厚度的个人偏好设定 | 增加角色真实感和记忆点 | 不限 |
### 执行指令
1. 把主角的实力、钱财、人脉、背景等影响剧情走向的属性归为强关联
2. 检查强关联是否达到每个角色至少 3 个
3. 把"喜欢吃蛋糕""爱好看美女"等归为弱关联,仅用于丰富人设
4. 确保弱关联不喧宾夺主——强关联才是延伸剧情的核心
---
## 人设执行规则
人设 ≠ 人物设定表。
- 人物设定表 = 身高、外貌、家庭背景等信息堆砌(外在信息)
- 人设 = 围绕角色"灵魂/特殊人格"展开的功能性设计
- 人设的使命:服务戏剧张力与情绪拉扯,以人格驱动行为,而非被剧情硬推
**检查**:如果你写的人物设定只有身高体重爱好,没有"灵魂/特殊人格"的功能性设计,重做。
---
## 配角功能化设计
### 核心原则
1. 配角的能力和特质必须和剧情紧密相关
2. 配角是为了展现主角而写——配角的能力为主角所用,配角脱离困境靠主角帮助
### 复合型配角——白手套角色
| 功能 | 说明 |
|------|------|
| 替主角说话 | 凡是主角不适合说的话,他来说 |
| 替主角发狠 | 凡是主角不应该发的狠,他来发 |
| 绝对维护 | 对侵犯主角利益的人坚决反击 |
| 粗中有细 | 将反派密谋录音再播放,取得大众支持 |
| 适时搞笑 | 不断输出正反馈,缓解紧张情绪 |
**设计原则**:光环比主角弱一点,不抢风头;惊艳出场;对主角的质疑第一时间反驳。
### 立体人物 vs 扁平人物
1. 不是所有角色都要立体化,先看功能性
2. 扁平化角色保持神秘性,反而更恐怖/更强大
3. "洗白弱三分,黑化强三倍"——高手被立体化就变弱了
4. 需要什么工具就设计什么工具,不要把所有角色立体化
### 人设反差六维度法
| 反差对 | 操作 |
|--------|------|
| 表面性格 vs 内在性格 | 笑面虎/刀子嘴豆腐心 |
| 外表形象 vs 表面性格 | 看着凶实际软 |
| 外表形象 vs 内在性格 | 看着柔实际狠 |
| 身份 vs 生活方式 | 豪门子弟住地下室 |
| 身份 vs 爱好特长 | 杀手擅长插花 |
| 身份 vs 内在性格 | 军人内心文艺 |
### 执行指令
1. 设计配角时先确定其功能(替主角说话/发狠/搞笑/提供信息)
2. 从六维度反差中选 1-2 个维度给配角贴标签
3. 控制配角光环,不超过主角
4. 功能性配角不要强行立体化
---
## 配角人设逻辑
1. "正戏反写"——看似正面的行为背后有反派动机
2. 配角情感保护壳:看似冷漠无情,实则有深层情感驱动
3. 避免崩人设:角色的行为选择必须符合已建立的人设逻辑
4. 先从题材的"标签人物"直接用——成熟题材里的人设角色都是经受过市场考验的
---
## 凸显人设的方法
### 执行指令
1. 抓亮点——找到角色最突出的那个特质,集中火力展现
2. 用行动展现人设,不要用旁白描述(如出狱后不卑不亢、争取利益、展现老练)
3. 用反差碰撞制造张力
4. 反差拉张力会筛读者,控制尺度——反差太大会劝退部分读者
---
## 高情商/聪明人桥段写法
### 执行指令
1. 高情商通过具体剧情中的表现来体现,不要旁白夸赞
2. 写察言观色、临场应变、控场接话的具体场景
3. 高情商表现应参考经典网文中的成功案例模式,每个桥段至少包含一个"读者预期尴尬但主角化解"的反转
4. 每个桥段至少有一个"反转"——读者以为会尴尬,结果主角完美化解
---
## 用配角做期待枢纽(人物扣)
### 执行指令
1. 选一个配角做"任务基地"——一个人物同时承载多个短期和长期期待
2. 主角每次解决事件装完逼后去找该人物,开始新一轮装逼
3. 每个剧情单元结束后利用同一人物展开新剧情
4. 人物下线时带来更大的好处,用"歪打误撞收获更多"转变读者"损失厌恶"心理
---
## 群像写作法
### 执行指令
1. 每个角色出场都要有功能,没有水分——功能不明确的角色不要出场
2. 角色间的关系要有层次(引路人、对手、伙伴、障碍)
3. 不同角色要有不同的说话风格和行为特征
4. 通过行为而非旁白来展示角色特点
### 配角脸谱化描写
1. 抓住 1-2 个突出特点做鲜明标签(口头禅/标志性动作/极端性格)
2. 标签化让读者迅速记住,不过多占用笔墨
3. 功能性配角要有明确功能:推动剧情、衬托主角、提供信息
### 角色使用的节奏
1. 高人气角色的出场频率应控制在每3-5章一次,保持期待感而不审美疲劳。每次出场必须有新信息或新功能
2. 读者不感兴趣的角色该舍弃就舍弃,自然"下线"
3. 用"以角色带角色"引入新角色——喜爱延续
### 角色池编织法
1. 以角色带角色:女主讨喜 → 写女主爸妈/姐姐/闺蜜 → 喜爱延续到新角色
2. 像网一样编织下去 → 很快就有取之不尽的角色池
3. 每个新角色贴一个标签,个个鲜明
---
## 向人设深化法
### 执行规则
先判断当前项目适合“故事深化”还是“人设深化”:
| 条件 | 优先方向 | 执行动作 |
|------|------|------|
| 主线已经复杂、多势力、多反转 | 向人设深化 | 保持故事结构简单,在人物欲望、反差、关系互动上制造新鲜感 |
| 主线过直、人物已经鲜明但事件不足 | 向故事深化 | 增加阻碍、目标变化、信息差或代价,不新增无功能角色 |
| 短篇/轻量篇幅 | 向人设深化 | 用 1-2 个强人设标签驱动冲突,不铺大世界观 |
| 长篇关键卷/高潮卷 | 两者结合 | 故事升级一个维度,同时让关键人物关系发生可见变化 |
### 执行步骤
1. 拿一个简单甚至老套的故事结构
2. 在人物身上加"戏剧性"——能让目标读者找到乐子的设定
3. 通过几个人物的互动循环产生持续剧情
### 循环写法(一个简单情节可写5章以上)
- 第1章:主角装逼 → 师叔更迫切
- 第2章:师叔逼女生 → 恋人帮着威逼利诱
- 第3章:女生靠近主角 → 恋人在暗地暗爽
- 第4章:女生回去哭诉 → 恋人假意安慰一边暗爽
- 第5章:复命领赏 → 女生发现恋人对奖赏没那么高兴
---
## 人物塑造技巧
### 女性角色塑造(男频)
1. 读者喜欢的是女主的标签(高贵优雅、肤白大长腿),不是外貌描写
2. 利用刻板印象:吸血鬼=高贵优雅+外貌出众,不用特意描述读者就知道
3. 网文里美貌是最廉价的资源——不要花大量笔墨写外貌
4. 性格设定可极端化:傲娇到极致、对主角爱得深沉、不考虑自身利益
5. 保持性格一致性:设定后言行始终符合
### 主角可以犯错但需把握尺度
| 可原谅 | 不可原谅 |
|--------|---------|
| 因不可抗力或信息差导致的错误 | 因蠢、因圣母心泛滥导致的错误 |
| — | 与实力不匹配的错误(斗帝强者因小人物犯蠢) |
### 主角人设内外反差
1. 可设计表面与内心的反差(如表面色牛实际内心孤僻)
2. 反差感增加角色深度和趣味,提供丰富的情节冲突可能性
### 反派的本质
反派 = 与主角立场不同、利益相悖的人。赋予反派自己的想法和追求,不要写纯粹的恶。
### 渣人设写法
1. 开头就清晰传达主角人设,穿越前后保持一致
2. 避免"又当又立"——前面没描写主角是老色皮后面突然追女读者反感
3. 明确人设 = 筛选接受这种人的读者 = 预期管理
---
## 人物记忆点法
1. 每个人物至少有一个性格方面特别突出
2. 只有让某一特征特别突出,才有记忆点
3. 目标:哪怕剧情不推进,几个人物坐一起聊天,读者都看得津津有味
---
## 金手指绑架人设法
### 执行指令
1. 金手指不只是给主角超能力,目的是让主角的性格合理化
2. 用金手指规则绑架行为 → 配角反应自然塑造形象 → 不需要直接描写主角品格
3. 追求道德爽感(最高级爽感):让主角成为行为层面让读者心服口服的"活圣人"
---
## 以梗为中心塑造人设
### 执行指令
1. 单一标签"杀伐果断""热血"太模糊 → 用具体梗来建设角色 → 读者产生强记忆点
2. 例:配角每次看到主角成功 → 羡慕嫉妒恨 → "你真该死啊" → 强记忆点+趣味性
3. 好人设+平平无奇的金手指+俗套套路 → 也能发挥意想不到的吸引力
---
## 九维人设框架
| 维度 | 内容 | 要点 |
|------|------|------|
| 基本信息 | 前身今世/外貌特征 | 从人物下手建立长期期待感 |
| 性格 | 反差人设 | 为成长弧线铺垫 |
| 爱好习惯 | 贪财/好色/杀人后超度 | 做强烈记忆点反复强调 |
| 人际关系 | 关系网越复杂越能制造冲突 | 牵扯的重要人物个个有实力有背景 |
| 背景 | 家族/出身/成长环境 | — |
| 成长弧线 | 见下方三阶段 | — |
| 对比反差 | 恶人vs好人/医生救死扶伤→扛起枪杀人 | — |
| 价值观态度 | 不同身份地位看法不同 | 态度=行动目标 |
| 人物小传 | 典型重要故事 | 浓缩的生平经历 |
### 人物成长弧线(三阶段)
| 阶段 | 核心 | 对应 |
|------|------|------|
| 小我(幼年) | 虚构自己,想要成为他人眼中的我 | 动机 |
| 自我(青年) | 真实自己,夹在两者之间痛苦 | 态度 |
| 他我(成熟) | 别人眼中的自己就是追求的目标 | 价值观 |
情绪公式:满足(认同)→ 打击(同情)→ 怀疑(共鸣)→ 心痛(共情)
---
## 人设关系四阶段标签
| 阶段 | 了解程度 | 表现 |
|------|---------|------|
| 相遇(陌生人) | 只知道外表 | 警惕/保持距离/设防 |
| 相识(过客) | 初步了解不知底线 | 察言观色/阿谀奉承 |
| 相知(好哥们/闺蜜) | 知道秉性和底线 | 聊骚话/吐露心声/倾诉烦恼 |
| 相恋(爱人) | 了解内心伤疤 | 占有欲强/喋喋不休/任劳任怨 |
---
## 用职场思维理解网文关系结构
### 执行规则
网文本质:在一个"职场"爽透,然后再到另一个"职场"爽。
### 共性与差异
| 共性维度 | 说明 |
|---------|------|
| 层级 | 任何环境中都有上下级关系 |
| 互助 | 同级之间的合作和互利 |
| 互害 | 同级之间的竞争和倾轧 |
| 差异维度 | 说明 |
|---------|------|
| 合作方式 | 不同环境合作模式不同 |
| 资源类型 | 不同环境争夺的资源不同 |
| 个体能力 | 主角的独特优势 |
### 执行步骤
1. 为主角设计一个"职场环境"(学校/宗门/公司/军队)
2. 设置层级关系(上级/同级/下级/对手)
3. 利用层级关系自然产生矛盾和冲突
4. 主角在这个环境中爽透后,换到更大的"职场"
---
## 代入感构建法
### 执行规则
- 代入感维护规则:节奏和情感链条不断裂。断裂标志=读者开始用现实逻辑评判情节
- 一旦读者开始用现实逻辑评判 = 节奏出了问题
- 核心是情感链条不断
### 执行方法
| 方法 | 做法 | 效果 |
|------|------|------|
| 共情切入点 | 用日常生活常见事件 | 瞬间拉近距离 |
| 细节真实性 | 填充生活化细节 | 强化世界真实性 |
| 救猫咪情节 | 开头一个情节强调主角人设某方面 | 读者快速熟悉并代入 |
| 共情前提 | 让角色暴露真实一面(弱点/困境) | 读者产生保护欲 |
| 合理化虑点 | "缺钱"这类人人都懂的困境 | 天然共情 |
### 共情三层次
1. **表层共情**:经历类似
2. **深层共情**:情感类似
3. **认同感**:价值观一致
### 破坏代入感的行为(避免)
- 角色做出读者无法理解的选择
- 大段设定说明打断叙事
- 节奏拖沓导致情感链条断裂
- 主角三观与目标读者严重偏离
---
## 安全感与核心情绪把控
1. 不同题材的读者对安全感需求不同,先确认题材
2. 极道流等紧张感题材:安全感拉爆 = 危机感消失 = 核心情绪偏移——不要给主角找过强的靠山
3. 禁止为主角设置可随时解决危机的强力靠山——靠山的存在必须不削弱紧迫感。违反此规则时标记为"靠山过度"
4. 精力有限时,情节始终是第一位的,世界观只是加分项
---
## 质量检查清单
完成角色设计后,逐项检查:
- [ ] 角色是否有三层标签(身份/表现/内核),且至少有一层反差
- [ ] 强关联设定是否达到 3 个以上
- [ ] 人设是功能性设计还是只有外貌信息堆砌
- [ ] 配角是否有明确功能,是否抢了主角风头
- [ ] 每个角色是否有至少一个记忆点
- [ ] 配角出场是否都有功能,没有无用水分
- [ ] 不同角色是否有不同的说话风格和行为特征
- [ ] 主角的错误是否在可原谅范围内
- [ ] 反派是否有自己的逻辑和追求,不是纯粹的恶
- [ ] 人设言行是否前后一致,有没有崩人设
- [ ] 代入感情感链条是否连续,有没有被设定说明打断
- [ ] 安全感是否匹配题材要求(紧张题材不能给主角太强靠山)
- [ ] 高情商桥段是否通过具体剧情展现,而非旁白夸赞
references/character-relations.md›
# 角色关系与感情线操作手册
## 决策路由
| 你在设计什么 | 使用本章方法 |
|-------------|-------------|
| 角色间关系类型 | 人物关系类型表 |
| 感情线核心人设 | 感情流人设核心法 |
| 爱情线底层逻辑 | 男频/女频爱情线差异 |
| 穿书/穿游戏角色选择 | 穿书角色选择法则 |
| 多角关系/修罗场 | 修罗场收场策略 |
| 好感度推进节奏 | 好感度体系 + 男频恋爱文攻略 |
| 配角态度变化 | 配角攻略缓冲区 |
| 角色共情写作 | 角色行为自洽检查 |
| 角色目标与关系线 | 角色目标独立性 + 关系线设计 |
---
## 人物关系类型
查表确定角色间的关系类型,然后按原则执行。
| 关系类型 | 定义 | 功能 | 示例 |
|---------|------|------|------|
| 冲突型 | 双方利益/理念对立 | 制造张力,推动情节 | 宿敌、竞争对手 |
| 联盟型 | 双方有共同目标 | 提供助力,制造羁绊 | 战友、师徒 |
| 亲密型 | 情感纽带连接 | 制造软肋,提供情感支点 | 恋人、家人、兄弟 |
| 权威型 | 上下级/支配关系 | 制造压力,限制主角行动 | 师父、老板、监管者 |
**执行规则**:
- 每个重要关系至少安排一次考验(背叛/牺牲/误解)
- 关系必须有变化弧线(敌人变盟友、盟友变对手)
- 禁止所有关系都是"你好我好"的铁板一块
- 关系的功能必须服务于情节,不能只为甜/虐而存在
---
## 感情流人设核心法
感情流中剧情为人设服务——每次剧情都要丰满人物或推动感情发展,否则就是无效剧情。
### 构建步骤
1. **确定人设核心**:写下最初出现在脑海里的角色特征(如"想登上皇位的皇子""病弱皇子")
2. **围绕核心发散**:回答——为什么有这个核心?过去经历?环境影响?性格成因?
3. **延伸剧情线**:核心自带的剧情必须写(有目标→目标线;有伤痛→治愈线)
### 执行规则
- 俗套剧情配上丰满人设也能脱离套路感
- 两个主角都必须有闪光点和独立变化路线,不能一个人出彩另一个人黯淡
- 高光不等于装逼——所有让读者对角色印象深刻的时刻都是高光,包括痛彻心扉的时刻
- 生命不止恋爱——角色心里希望恋爱,但生命里不能只有恋爱,只有恋爱的角色立不住、很单薄
---
## 男频与女频爱情线底层逻辑差异
**先确定目标读者群,再选择对应逻辑。两者不可混淆,否则读者会觉得"不对味"。**
### 男频爱情线逻辑
| 维度 | 说明 |
|------|------|
| 核心 | "外在因素展示"——主角和对象在一起体现两人的外在因素多优秀 |
| 三种核心逻辑 | "她要是我的该多好" → "这么优秀的人是我的了" → "这么优秀的人都喜欢我,我更优秀" |
| 围观者想法 | "能得到这么优秀的女人,我好羡慕"(非"恋爱好甜") |
| 女主 | 最好有多个女性角色喜欢主角,越多说明主角越优秀 |
| 对象本质 | "奖杯"——一切动机的根本目的是胜利 |
写男频感情线时,围绕"展示优秀"设计事件。
### 女频爱情线逻辑
| 维度 | 说明 |
|------|------|
| 核心 | "连接"——两人之间唯一、坚不可摧、最优先的情感连接 |
| 连接要求 | "我爱的是你这个人,外貌、财富、才华都不能替代这份连接" |
| 纯洁性 | 连接形成后应逐渐舍去外在因素影响 |
| 双方 | 最好初恋+双洁——保障连接的纯洁性和唯一性 |
| 围观者想法 | "他们的恋爱好甜,我好羡慕" |
写女频感情线时,围绕"深化连接"设计事件。
---
## 穿书/穿游戏角色选择法则
### 必须满足的条件
- 叙事主角必须对原世界有相当熟悉度(最核心的期待感来源)
- 确定穿越进熟悉的世界,一两句话交代清楚,不能超过一章还不知道身处何方
- 必须选择穿越后有强戏剧性或强矛盾的角色(如穿越成恶毒女配)
### 信息差设计
- 在原世界基础上适当设计信息差,为叙事主角提供探索空间
- 可以用原世界知识卡bug获取超额收益
---
## 修罗场收场策略
修罗场本质是一种矛盾,控制对抗烈度,不能让爱情线对象之间出现不可调和的矛盾。
| 收场方法 | 操作 |
|---------|------|
| 关联回事业线 | 让爱情线对象们把争风吃醋转化为"比谁对主角事业线贡献更大" |
| 插入事业线突发事件 | 对抗进入白热化时,用突发事件让所有人从内斗切换成一致对外 |
| 一笔带过 | 最多两人互相看不惯、说两句嘲讽话就过去,非常克制 |
---
## 傻白甜角色塑造避坑
### 六个必避之坑
1. 女主犯错不能是故意的,不能明知不能做偏要做
2. 女主犯错不能违反道德——傻白甜最重要的是天真小孩子般的高道德感
3. 不能站在道德高地指责他人(道德婊行为),自己却做不好
4. 不能因为道德婊行为和队友发生矛盾后还让队友认错赞美她
5. 正确做法:有更高道德标准 → 所作所为符合 → 为此显得与众不同和有点傻气
6. 可以写成长线:坐到被她指责的人的位置上后,发现原来那个做法已是最好的选择
### 反向用法
塑造傻白甜反派时,把以上六点全加在她身上,让读者一见就厌恶。
---
## 人设改变的双向翻转法
爱情线中关系发生变化时的人设调整方法。
### 核心思路
- 最好的改变是两个人都改变,且改变后恰好与之前两人之间的对应关系相反
- 改变要基于原人设做局部调整,和原人设保持密切联系,避免随意改造
### 执行规则
- 人设变化发生在爱隔山海阶段之后(尤其是面对最大阻碍之后),不要再设计新的矛盾,只要发糖
- 真正的阻碍已在前面解决,此时读者最迫切的渴望是多吃糖
- 发糖要用实在的CP行为和悉心照顾表达爱意,不是"我爱你"式的工业糖精
---
## 角色行为自洽检查
### 第一步:排除外部强推
检查角色行为是否只是为了让剧情往某方向发展。如果角色"恰好"做了推进剧情的事但没有自身动机,标记为"人设偏移",必须为该行为补充角色层面的合理理由。
### 第二步:情绪目标确认
写每段前明确三个要素:
1. 本段目标情绪:这段剧情要让读者产生什么情绪?
2. 角色性格特征是否支持该情绪:角色的设定属性是否自然导向此情绪方向?
3. 角色行为是否符合使命定位:角色在本段的行为是否与其在故事中的功能定位一致?
### 第三步:人设行为推导
从角色已设定属性(经历/性格/目标/当前状态)推导其在场景中的行为:
- 列出该角色在此场景下的2-3种可能反应
- 评估每种反应与角色已有行为模式的一致性
- 选择最符合人设且最有戏剧张力的那一种
### 第四步:情绪一致性校验
检查角色表达的情绪核心与场景目标情绪是否一致。不一致则调整角色行为或场景目标情绪,确保输出内容在情绪维度上自洽。
**两种执行路径**:
- 路径A:先定目标情绪 → 按人设推导角色行为 → 校验一致性
- 路径B:先按人设推导角色行为 → 反推场景目标情绪 → 校验一致性
---
## 配角攻略缓冲区
配角对主角态度的变化过程 = 主角攻略配角的过程,伴随巨大的期待感和爽点。
### 缓冲区类型
线上线下、背后议论、异地相处、地位差距、亲密度差距、信任程度、信息差等。
### 操作步骤
1. 始终保持缓冲区存在
2. 在卷纲中挑出事件拐点(5~7个)
3. 在每个拐点处标注配角状态和对主角的态度变化
4. 每次攻略到关键点位时,配角的态度变化必须写清楚
5. 态度变化本身就产生情绪波动和期待感
### 执行规则
- 配角不能像NPC一样站着等主角触发
- 配角要有自己的行动,由配角观点引出事件
- 正面角色也一样:和主角立场相同的人也应有自己的行动和动机
---
## 利用角色身份认知差制造冲突
同一个角色在不同人眼中的"声望"是动态变化的,不是恒定值。
| 视角 | 看重什么 | 对男主的评价 |
|------|----------|-------------|
| 世俗视角 | 家境对等,抗风险能力 | 综合条件匹配度 |
| 男主自身 | 赚钱养家+感情 | 相对门当户对 |
| 女主视角 | 感情+专一+爱 | 只要在乎的就门当户对 |
| 富二代 | 外貌家世匹配度 | 我才更门当户对 |
| 路人 | 综合条件对比 | 女主该嫁富二代 |
**操作要点**:
- 不同人对同一个角色的评价差异 = 天然的矛盾冲突来源
- 恋爱文的核心爽点之一:不同维度的评价差
---
## 亦敌亦友关系
最有魅力的人物关系类型。
### 执行规则
- 前提:两个角色本身都要有魅力,否则只是强行五五开的狗皮膏药
- 核心:高度认可 + 绝对冲突 → 惺惺相惜 → 缺一魅力全无
- 真正的宿敌 = 双方相互认可,外人盖章不算
---
## 竞争者定位与亲情线用法
### 竞争者(鲶鱼效应)
- 定位:给男主/女主增加紧张感上压力 → 推动攻略进度
- 剧情设置重点在"高潮节点前" → 属于铺垫环节
- 对高潮后续写剧情作用不大 → 不是续命手段
### 亲情线的四个方向
| 方向 | 作用 | 使用时机 |
|------|------|---------|
| 男方助力 | 提供金钱地位权力 | 高潮前发挥 |
| 男方阻力 | 设置障碍让主角得到认可 | 节点前后都能用 |
| 女方助力 | 温柔乡感情补给站 | 高潮前发挥 |
| 女方阻力 | 父母不同意→为了认可去努力 | 节点前后都能用 |
助力主要在高潮前,阻力节点前后都能用,阻力更好发挥。
---
## 男频恋爱文写法攻略
### 读者为什么看恋爱文
| 价值 | 来源 |
|------|------|
| 情绪价值 | 填补"被需要、被在乎"的情感空缺 |
| 自尊价值 | 女主条件好→带出去有面子→配角羡慕嫉妒 |
| 高身份女主原因 | 更强的装逼打脸工具人+更大的自尊满足 |
### 核心技法:把恋爱当升级文写
- 暧昧拉扯的过程才是最有吸引力的
- 好感度进度条:每一步推进 = 升级文中的一个"等级"
- 每一个事件是一次"升级"→ 通过冲突、化解、理解和共鸣让好感攀升
### 好感度升级路径
路人 → 好人(扶老奶奶过马路) → 正直勇敢的好人(挺身而出) → 不错的朋友(理解原生家庭困境) → 喜欢但不知(特殊契机看到彼此不为人知的一面)
### 关键原则:主角不主动追求
- 当前男频读者普遍反感"舔狗"人设
- 推动好感靠男主自身优秀品质吸引,不是主动追求
- 男主帮女主是举手之劳不经意为之 → 女主因此记住他
### 感情升级的不对称性
- 两条进度线:表面社会关系(路人→朋友→情侣)+ 实际情感好感度
- 两条线不应齐头并进 → 一条快一条慢 → 带来丰富的矛盾冲突
- 情感线快于社会线 → 辉夜大小姐模式(双方好感拉满但嘴硬不表白)
- 社会线快于情感线 → 赘婿/择天记模式(表面夫妻实际好感为零)
### 写女主对主角好
| 女主类型 | 付出方式 |
|---------|---------|
| 自卑社恐 | 偷偷帮忙塞东西但害怕被发现 |
| 傲娇型 | 用心做便当但嘴硬"做多了顺便带的" |
| 直率泼辣 | 大大方方送礼物或直球表白 |
### 善用对比
| 对比类型 | 操作 |
|---------|------|
| 时间线对比 | 女主刚认识主角时 vs 熟悉后的态度变化 |
| 双标 | 不允许别人摸头但主角可以 → 凸显特殊地位 |
| 信息差 | 男女主双重身份(网上vs现实)→ 期待揭穿时反应 |
---
## 好感度体系(通用框架)
### 四阶段
萍水相逢 → 爱情喜剧 → 爱隔山海 → 大结局
### 好感度 × 关系阶段对照表
好感度(负/零/半/满) x 关系阶段(熟悉/试探/暧昧/确认)
阶段匹配原则:**按低的一方计算**。好感度到了但关系阶段没到 = 行为突兀。
### CP行为三类门槛
| 行为类型 | 门槛 | 说明 |
|---------|------|------|
| 需容忍行为 | 半好感+ | 主动亲密、妥协,必须给补偿否则变舔狗 |
| 特殊对待行为 | 半好感+ | 主权、信赖、牺牲、特殊待遇、安抚 |
| 关联行为 | 双方半好感+ | 默契、分享、陪伴 |
好感度不足时写需容忍行为 = 油腻/性骚扰感。
### 5套感情线结构模板
| 模板 | 核心 |
|------|------|
| 好感度变化 | 可能升/降/已降 → 各自处理路径 → 余韵 |
| 受益 | 享受伴侣带来的好处 = 爱情线装逼核心 |
| 争风吃醋 | 多角色为主角争风,不是主角吃别人醋 |
| 发展受阻 | 阻碍→试图解决→解决→余韵 |
| 狗粮 | CP日常互动 |
---
## 角色目标的独立性与关系线设计
### 主角目标独立性原则
- 主角的目标必须属于自己的 → 不能是"帮别人实现目标" → 否则主角变成配角/工具人
- 正确做法:把别人的目标转化为主角自己的(平叛=保护自己的利益/获得认可/获取资源)
- 自检方法:随机看一章 → 主角在主动追求什么 → 如果没有 → 主角沦为别人的棋子
### 感情线的层次设计
- 感情推进不是线性的,应该有升级节点,每个节点对应一个剧情高潮
- 社会关系线 vs 实质情感线的错位制造张力
- 最佳节奏:感情先慢后快 → 前期铺垫积累好感 → 后期集中爆发 → 匹配盛大仪式
### 配角的功能性定位
| 类型 | 功能 | 使用时机 |
|------|------|---------|
| 竞争者(鲶鱼型) | 制造压力推动主角行动 | 高潮节点前 |
| 助力型亲友 | 提供资源/情感支持 | 高潮前发挥 |
| 阻力型亲友 | 不认可→设置条件→主角克服→获得认可 | 节点前后都能用 |
---
## 绿茶/负面角色
- 可以推动剧情但要谨慎使用
- 确认该角色是否有不可替代性
- 主角强势时任何角色都能变正反馈
- 主角弱势时负面角色会被读者恨
---
## 质量检查清单
每次完成角色关系/感情线设计后,逐项核查:
- [ ] **关系类型明确**:每个重要关系已归类为冲突/联盟/亲密/权威之一
- [ ] **关系有弧线**:每个重要关系至少经历一次考验或变化
- [ ] **人设有核心**:主角人设有明确的核心特征和发散依据
- [ ] **目标独立性**:主角的目标属于自己的,不是帮别人实现目标
- [ ] **好感度匹配**:CP行为与当前好感度阶段匹配(按低的一方计算)
- [ ] **读者群对味**:男频围绕"展示优秀"设计事件,女频围绕"深化连接"设计事件
- [ ] **配角有行动**:配角不是NPC式站桩等待触发,有自己的行动和动机
- [ ] **缓冲区存在**:配角攻略过程中始终保持缓冲区,拐点处标注态度变化
- [ ] **修罗场可控**:多角关系中对象之间无不可调和的矛盾
- [ ] **发糖时机正确**:爱隔山海之后不再设计新矛盾,只发实在的CP行为糖
- [ ] **角色不止恋爱**:角色生命中有恋爱之外的内容,不是单薄的情感工具人
references/commercial-core-methods.md›
# 商业创作核心方法
> 卖点设计、情绪调动、节奏控制、金手指原理、期待感管理、全流程创作方法。用于大纲设计、选题定位、商业化策略时查阅。
---
## 决策路由
| 你在做什么 | 查阅哪个模块 |
|-----------|-------------|
| 确定选题/卖点 | 卖点论与实操法 -> 情绪缺口分析与用户画像法 |
| 设计金手指 | 金手指的核心原理与系统流演变 |
| 控制节奏/防崩盘 | 创作节奏法 -> 三种期待感与崩盘原因分析 |
| 设计开篇 | 从选材到留存的创作流程 -> 开篇设计 |
| 分析读者需求 | 情绪缺口分析与用户画像法 -> 核心卖点偏移诊断与修正 |
| 规划大纲结构 | 创作思路普适法 -> 从选材到留存的创作流程 |
| 设计留存/追读 | 核心卖点偏移诊断 -> 三种期待感与崩盘原因分析 |
| 检查商业化情绪交付 | 情绪调动与商业化执行规则 |
| 检查创作质量 | 质量检查清单(底部) |
## 指令语气
本文件以"创作策略"语气书写。所有公式和原则都要转化为选题、卖点、节奏、情绪或开篇的可执行约束。遇到冲突时:当前样本/用户要求 > 读者情绪 > 个人表达。
---
## 千均写作指南核心要点
- 金手指决定本书基调,崩追定大概率是偏离了核心梗
- 升级不能太快(失去期待)也不能太慢(失去耐心)
- 升级后展示新能力威力(爽点释放),同时引入更大危机(期待重建)
- 主角行动要推动剧情,不能漫无目的地闲逛
- 基础三幕式:建置 -> 对抗 -> 解决
- 每一幕之间要有"鸿沟"——主角计划和实际结果的落差 -> 意外 -> 悬念 -> 追读
---
## 传统文与脑洞文的留存技巧
### 留存四大支柱
- **升级**:实力/地位/金钱/资源
- **资源困境**:修炼需要资源 -> 引导期待感
- **设置目标**:大目标 + 小目标 + 假目标(目标失败但合情合理,反而眼前一亮)
- **解密**:冰山一角 -> 层层解密 -> 拨开迷雾
### 换地图框架设计(目的+高潮)
每到一个新地方两件事:
1. 来到新地方的目的 -> 要得到什么/查清什么真相
2. 大高潮结尾 -> 让人意犹未尽
### 快速过渡平淡剧情
- 设置激烈目标 -> 往大高潮过渡
- 直接设置激烈冲突 -> 先把剧情变激动人心
- 参考同题材高节奏作品的开头结构,将当前段落的目标冲突密度提升至每500字至少一个转折点
---
## 写作三要素——用梗、节奏、情绪
**用梗**:优先复用当前样本或对标书已验证的结构功能位;梗是否仍有效必须用目标平台样本验证。
**节奏**:常见问题是加无用对话/自以为牛的细节/大段铺垫。解决:砍,一句话能说清别用两句。
**情绪**:爽文核心就是这个"爽"字,情绪的塑造是起起伏伏关联性非常强的。
---
## 写作中的核心梗与结构思维
- 核心梗 = 一套固定的剧情发展模式,以核心卖点为支撑,不断换花样循环
- 绝大部分排行榜的书都有自己的核心梗
- "细化"替代"x级结构":一句话主线 -> 卷纲 -> 章纲 -> 正文
- 优先选套路重复凝聚主线,开一些支线放松
---
## 写作中的情绪处理与认知技巧
### 先入为主与峰终定律
- 塑造认知时先呈现的信息影响力更大
- 否定提前:把否定元素放前面,否定感更强
- 标题/简介/品牌口碑 = 给读者的第一印象,极其重要
### 情绪增强技巧
- 构建知识最好通过例子
- 用技巧前想想为什么,不要为用而用
---
## 写作技巧分类与常见误用
### 两种类型
1. 吸引读者来看:书名/简介/开局/爽点/噱头/爆梗
2. 吸引读者一直看:世界观/角色/升级感/节奏感/期待感/代入感
### 常见误用
- 拿"教人持续期待感"的技巧去写开头——目标不同
- 不分网站适用性——不同平台技巧需举一反三
### 写作三要素
选材(目标读者与题材边界)+ 剧情设计(大纲/卷纲/章纲)+ 文笔(行文交付),三项都要在 artifact 中落地。
---
## 创作中的反套路与重复认知
### 看点不等于噱头
- 有些核心卖点梗只具备一次吸引力 -> 只能当噱头引入
- 很少有一个卖点能完美撑到几百万字 -> 要剧情世界观和人物撑住
### 重复点的数据化判断
- 重复包括:人物重复点/套路重复点/剧情重复点 -> 含金量依次递增
- 核心看点抓不住 -> 数据没了 -> 换看点 -> 成绩也没了 -> 说明读者要的就是那个重复点
- 当核心看点在当前样本/读者反馈中表现稳定时保持重复策略;反馈下降时分析是否需要升级重复方式
---
## 创作节奏法
### 日常文执行规则
日常不等于平淡——修罗场就是日常但充满冲突,关键在于设置矛盾冲突 + 巧玩梗。
### 节奏自检法
每章写作前读状态摘要 `追踪/上下文.md`,按其 `## 近三章速记` 判断当前节奏:
- 拖沓信号:连续 2 章没有目标推进、阻碍升级或新信息 -> 下一章提高冲突密度。
- 过快信号:连续 2 章只爆点不留反应余波 -> 插入 1-2 个承接场景,但必须推进关系/伏笔。
### 高潮节奏标准
- 大高潮:7-10天完成,超过10天追读下滑
- 小高潮:3天左右完成
- 高潮结束后 -> 添加1-2章日常过渡
### 中后期追订下降两大原因
1. 爽点重复 -> 读者审美疲劳
2. 长远期待感缺失
- 解决:大纲阶段先定结局 -> 围绕结局设计中后期爆点
### 伏笔vs谜语人
- 谜语人:故意不说明原因,暗示有玄机 -> 激发好奇心
- 伏笔:巧妙融入剧情 -> 后续揭示惊喜
---
## 核心卖点偏移诊断与修正
### 卖点偏移
- 卖点偏移 = 核心吸引元素被稀释或替换
- 常见:爽文写着写着变成种田文 -> 核心读者流失
- 自检:每隔十章问"当初吸引读者的卖点还在吗?"
- 根源:核心卖点被写作过程替换,但读者期待没有同步改变
### 读者需求与网文类型对应
| 需求层次 | 网文类型 |
|----------|----------|
| 生理需求 | 肉文/后宫文 |
| 安全需求 | 无敌流/系统流 |
| 社交需求 | 后宫/团队文 |
| 尊重需求 | 爽文/打脸文 |
| 自我实现 | 升级流/探索流 |
跨层满足 = 爆款潜力。创作前明确满足哪层需求,所有设计围绕展开。
### 金手指+矛盾=剧情
- 金手指太强 + 矛盾不够 = 无聊
- 金手指太弱 + 矛盾太强 = 读者焦虑
- 最佳:金手指刚好解决当前矛盾 -> 暴露更大矛盾 -> 层层递进
### 主题统一性
- 一本书从头到尾要有统一的核心情绪
- 小情绪服从大情绪
- 检验:随机翻开一章 -> 情绪是否指向全书核心
---
## 可读性提升的矛盾性技巧
### 矛盾三层次
- 一般故事 -> 矛盾停留在角色之间
- 好故事 -> 矛盾放置在大背景中
- 巧妙故事 -> 矛盾放在作品与读者之间 -> 观念错位
### 观念错位
- 让主角的常识跟世界常识对着干 -> 读者边看边想"这也行?"
- 例:穿越古代主角当众算账揭穿伪善 -> 读者认同主角的现代价值观、配角震惊 -> 把主角"异类反应"和配角"正常反应"并置成反差
- 两种模式:
- 同认知背景+不同认知主角:主角特立独行吸引眼球
- 同认知主角+不同认知背景:穿越/末世/中世纪 -> 读者参照主角视角对抗世界
---
## 向精品冲击的攻略
### 黄金三章
前三章必须承担定调与留存功能。若项目已有强势作者品牌/IP 基础或用户另有要求,可降低套路化程度;否则按“核心冲突、金手指/优势、长期期待”三项检查。刻意套模板破坏既定基调时,以当前作品基调为准。
### 留住读者的核心:不间断的期待
- 即将得到但还没得到 -> 期待感最高
- 得到之前套上另一个钩子 -> 循环
- 一本书随时保持两条以上期待线 -> 大期待 + 小支线穿插
---
## 商业网文六大核心模块
### 一、定调——黄金三章的核心是回应期待
- 公式:令人不安的处境 + 亟待提升的地位 + 充满希望的外挂 + 能被展望的美好未来
- 定调三层次:情绪氛围 -> 故事走向 -> 价值观倾向
### 二、金手指——简单是核心
- 内核归类:信息挂(最优,不易失控)、加速升级挂、物体调用挂
- 最核心要素:简单。游戏化面板一眼就懂最好
### 三、角色——脸谱化不是坏事
- 为所有角色打下标签,越重要标签越多,行为基于标签
- 构建角色充满算计——送资源/被打脸/当小弟/当向导,分工明确
### 四、节奏——循环嵌套
- 本质循环:确立目标 -> 做出行动 -> 完成目标 -> 获得提升 -> 确立新目标
- 对抗审美疲劳:从数值对抗转为机制对抗
### 五、爽点——先不爽再拿掉不爽
> 相关:爽点的本质/六种类型/倒推设计法以 [plot-emotion-system.md](plot-emotion-system.md)「爽点设计体系」为准;本文只覆盖商业留存视角的爽点处理。
- 公式:生产诉求 -> 给予希望 -> 努力解决 -> 得偿所愿
- 无敌文本质是"人前显圣"
### 六、冲突与悬念
- 冲突简单直接可套路化;悬念需精巧构思
- 悬念信息释放梯度:每章末尾营造"即将达成"的临界状态
### 题材微创新三套路
- 热门设定+套路化流派写法
- 热门分类体系+热门噱头
- 成熟世界观的不同视角
---
## 情绪缺口分析与用户画像法
- 爆款书情绪一以贯之源出一孔 -> 非爆款书情绪散乱多头并行
- 升级/复仇/寻宝等小情绪应统一到主情绪之下
- **用户画像法**:从爆款网文提炼剧情元素 -> 框定读者画像 -> 推测心理需求 -> 对照分析
- 深层挖掘:不止分析读者需求,更要挖掘读者自己都不知道的情结
- 从读者评论中提取高频情绪关键词(爱/恨/渴望/逃避),与当前设计的情绪卖点逐一比对,识别未满足的需求
### 分析实例
**末日重生文**:
- 末日 = 颠覆社会秩序 -> 渴望高位者跌落底层草根爬上
- 囤货 = 巨大不安全感 -> 坐拥百亿物资 -> 安全感爆棚
- 重生 = 捡漏 -> 一分投入万倍收获
**新媒体战神赘婿文**:
- 核心痛苦:无能 -> 无法赡养父母照护孩子
- 第二层:家人否定 -> 百般付出不被认可
- 第三层:自卑 -> 不敢面对无能
- 战神归来 -> 一切反转 -> 暴爽
---
## 情绪调动与商业化执行规则
### 模仿的正确方向
- 应该模仿:故事套路/戏剧手法/叙事结构/角色类型
- 不应该模仿:文辞/经典桥段/语言风格
### 商业化的本质
- 网文本质是商品,商业化 = 尊重目标读者的阅读预期
- 网文的本质 = 持续调度读者情绪 -> 每章都要有明确情绪交付
### 情绪调动的终极认知
- 成功作品需要多重因素共同作用,不只使用单一技巧
- 读者期待感大部分来自长期对角色的感情投入,不来自表层文本
---
## 套路的多维度运用
- 一个套路爽点至少能用五六种方式写 -> 正着写/反套路写/再反/持续反/反了再正
- 拿"打脸装逼者"示范五种:
- 正 = 对方刚嘲讽完,主角当场亮身份打脸
- 反 = 主角故意装弱,让对方蹦达得更欢再翻盘
- 再反 = 对方以为主角在装弱,结果主角是真强,没装
- 持续反 = 对方连环误判,每次以为看穿主角又被反打
- 反了再正 = 兜一圈玩各种花活,最后还是靠硬实力碾压
- 高阶:用套路的基础逻辑 -> 换壳换场景换人物 -> 看似不同实则内核一致
---
## 章纲细化层级选择
| 项目复杂度 | 章纲粒度 | 使用条件 |
|------|------|------|
| 高复杂度 | 二级结构/起承转合逐条推演 | 多线、强反转、复杂世界观 |
| 标准长篇 | 每章300-400字章纲 | 首卷、关键卷、高潮卷 |
| 低复杂度/滚动续写 | 十几字目的句 + 关键情绪/钩子 | 已有卷纲和追踪文件支撑 |
选择规则:上下文越少、反转越强、人物线越多,章纲越细;已有稳定结构和追踪文件时可简化。
---
## 卖点论与实操法
### 卖点四步法
1. **思考**:想清楚整本书卖点、书名卖点、简介卖点、每段剧情卖点
2. **设计**:围绕卖点做扩散设计
3. **细化**:卖点面对什么读者群?什么风格合适?
4. **表现**:每章一个目的词,盯紧章纲和目的来写
### 卖点的表达技巧
- 让读者在阅读中自己发现 -> 发现比告知爽十倍
- 隐性展示:通过剧情/对话/反应来展示
- 三层递进:开头暗示 -> 中间深化 -> 高潮爆发
### 书名简介卖点
- 书名=第一道门,简介=第二道门,开篇=第三道门,层层传递并兑现核心卖点
- 不要使用无法传递核心卖点的文青书名
### 章纲目的法
- 每章一句话概括内容 + 标注"目的"词(铺垫/高潮/爽点/打脸/人物塑造/设定)
- 盯紧章纲和目的来写 -> 不容易跑偏
---
## 金手指的核心原理与系统流演变
故事流程:激励事件 -> 产生欲望 -> 建立目标 -> 开始行动 -> 遭遇阻碍 -> 克服困难 -> 收获奖励
**金手指可替换流程中的任一环节**:
- 替换"建立目标":系统发任务
- 替换"克服困难":按一下解决问题但要承受代价
- 替换"准备环节":跳过准备直接快进到遭遇阻碍
- 替换"激励事件":穿越到千年后
- 替换"收获奖励":系统使主角做公益获利
**金手指为什么包装成系统**:系统的限制保证故事结构完整 -> 有限制的系统 = 主角必须一步步行动。
---
## 需求驱动与节奏的本质
### 消遣之物的本质逻辑
为读者创造某种需求,然后满足。
- 公式:生产诉求 -> 给予希望 -> 努力解决 -> 得偿所愿
- "不该如此"是根本冲动 -> 读者看到不公/遗憾 -> 天生想看改变
- 好题材具备勾起惋惜/渴望改变的特质
### 题材的核心不在表面设定
- 只写设定有趣的作品往往成绩差 -> 抓住核心矛盾的作品才好
### 节奏的本质
- 不断解决现有矛盾 -> 不断制造新的矛盾
- 好节奏:困境层级层层提高 + 难度逐步提升 + 困境种类不尽相同
---
## 创作理念:地图切换与节奏
### 换地图时的读者过渡设计
都市到仙界订阅直线下降。解决:建立缓冲区 -> 将读者慢慢引导到新题材。
### 大纲哲学
- 只列主线 -> 分支在写作中慢慢完善
- 大纲必须可修改 -> 太严谨缺少灵性
### 节奏与情绪
- 节奏 = 让读者有愉悦的阅读感觉 -> 打脸不在多而在经典
- 爽文不等于打脸 -> 爽文意义是读得轻松+有期待感
---
## 三种期待感与崩盘原因分析
### 三种期待感
1. **剧情期待**:大目标 + 过程中挖的坑 + 立起来的妹子 -> 吊胃口
2. **主题**:每章给读者甜头的东西 -> 主题不偏,大多数章节读者想看
3. **新鲜感**:世界观矛盾的新鲜 + 剧情形式的多样
| 类型 | 定位 | 节奏 |
|------|------|------|
| 剧情期待 | 吊胃口 | 偶尔满足 |
| 主题 | 每天的甜头 | 持续满足 |
| 新鲜感 | 放下还愿意捡起来 | 间歇刺激 |
三者合一 = 不崩之书。
### 崩盘根因:偏离卖点
- 套路循环类:同一卖点重复角度不足 -> 读者审美疲劳
- 技术到位但仍然崩 -> 优先检查核心卖点是否仍在、期待线是否仍有兑现空间
### 拉长板vs补短板
- 优先强化题材长板:核心卖点、目标情绪、最高频爽点。
- 不为补短板引入会稀释核心卖点的支线。
- 开书前检查:(1)核心卖点背后的情绪清晰 (2)同一卖点能延展出至少 3 个角度 (3)题材长板与现有素材/对标资产匹配。
---
## 创作思路普适法
### 创作思路三步法
确定主角身份 -> 匹配金手指类型 -> 设定开局环境
### 开篇压力的两种类型
- 冲突型压力:指向性明确,节奏快但后期容易崩
- 环境型压力:生活上的小压力,更容易写长
- 推荐:优先用环境型压力开局
### 金手指反馈法
- 给出金手指后必须有即时变化
- 把金手指带来变化的过程掺杂在故事里
- 金手指契合主角当前职业,或作为打开困境的钥匙
### 不同题材不同写法
- 东方玄幻:快节奏,第一章只出现主角一人,迅速切入
- 西幻低位背景:慢节奏,多人物对话营造氛围,逐步带出世界设定
- 不能公式化,要根据题材和金手指调整
---
## 梗收集与阶级跃迁爽点
### 梗收集方式
- 从目标平台的近期评论、弹幕高频词中提取可用梗元素,建立梗-场景映射表
- 梗是创作灵感源泉,不是简单堆积
- 经典梗读者仍会期待 -> 巧妙运用满足期待
### 阶级跃迁爽点
- 描写赚第一桶金实现阶级跃迁 -> 爽感最强
- 从贫穷到有点小钱更容易引起大众读者共鸣
### 过渡避免流水账
- 每个副本结束必须留一条矛盾线 -> 串联到下一个副本
### 设置钩子拉期待
- 提前透露人物特殊技能/背景 -> 读者期待后续运用
- 设置阶段性钩子 -> 高潮时完整呈现
---
## 从选材到留存的创作流程
### 题材定位与读者筛选
- 题材关键词能否作为目标读者筛选信号 -> 快速触发读者自动解压信息
- 微创新 = 在经典题材上套皮新噱头
- 题材组合公式:新东西+旧东西+热门载体 = 新题材
- 代偿 = 给主角现实里缺的东西(赘婿其实是隐藏战神,弥补"被人看不起")
- 捷径 = 金手指让主角跳过苦熬(签到系统/一夜暴富),开局就给"不用努力也能赢"的解压感
### 吸量要素
- 书名构建:冲突报复+人无我有+槽点句子
- 简介最高标准:有趣+有槽点+悬念
- 简介不能依赖作者品牌,必须直接交付卖点
### 留存=情绪+饥饿
- 情绪:快速代入 -> 快速沉浸 -> 与角色共鸣
- 饥饿:利用信息差在读者视角植入问号
- 剥洋葱技法:简介植入核心悬念 -> 章节开头植入小问号 -> 章节末尾卡住关键信息
### 开篇设计
- 开篇两万字只需解决一件事:活下去
- 轻松向开篇:主角一无所有 + 金手指一眼就知道怎么用
- 300-500字内交代:处境+危险来源+破局希望
- 开篇主角的所有都不能是完美的 -> 否极泰来的开端
### 大纲与细纲
- 随笔 = 表达库;大纲 = 核心骨架+人物+背景
- 细纲 = 舞台上人与人发生的故事
- 章纲 = 对细纲进行易读性/可读性/节奏调整
- 核心梗 = 一套固定的剧情发展模式 -> 不断换花样循环
---
## 卖点原理补充:核心情绪的艺术化
卖点不能按"卖的人多"粗暴判定。核心情绪是凡人都会遇见、感同身受的东西。
小说的本质:把平凡的、每个人都有的情感,抽取其中一样,进行艺术化、抽象化、极端化。
| 处理方式 | 操作 | 例子 |
|----------|------|------|
| 极端化 | 把日常委屈推到生死/巨额对赌 | 赘婿被瞧不起 -> 战神归来当众甩出百亿 |
| 艺术化 | 别写"他很委屈",用动作演 | 他默默把工资卡推过去,转身就走 |
| 抽象化 | 只抓一种情感贯穿全书,砍掉旁枝情绪线 | 全书只咬住"不被认可",亲情爱情都为它服务 |
---
## 质量检查清单
完成大纲/选题/卖点设计后,逐项检查:
- [ ] **核心卖点明确**:一句话能说清这本书卖什么情绪
- [ ] **卖点无偏移**:每十章自检"当初吸引读者的卖点还在吗?"
- [ ] **金手指简单**:读者一眼就懂怎么用,功能与升级规则清晰
- [ ] **金手指+矛盾匹配**:金手指刚好解决当前矛盾,暴露更大矛盾
- [ ] **三种期待线并存**:剧情期待 + 主题甜头 + 新鲜感
- [ ] **节奏有标尺**:大高潮7-10天,小高潮3天,高潮后1-2章过渡
- [ ] **升级节奏合理**:不太快(失去期待)也不太慢(失去耐心)
- [ ] **主题统一**:随机翻开一章,情绪指向全书核心
- [ ] **书名简介开篇三道门**:层层过滤,不使用无法传递核心卖点的文青书名
- [ ] **章纲有目的词**:每章标注铺垫/高潮/爽点/打脸/人物塑造/设定
- [ ] **留存双引擎**:情绪(快速代入)+ 饥饿(信息差植入问号)
- [ ] **拉长板而非补短板**:题材长板与能力长板吻合
references/cross-book-recall.md›
---
name: cross-book-recall
description: 多对标跨书召回
---
# 跨书召回
## 触发
先按当前项目目录名、`.active-book` 与本书设定识别当前作品,排除同名或来源指向当前正文的 `拆文库/{当前书}/` 与历史误建的 `对标/{当前书}/`;它们是本书导入分析,不是跨书样本。排除后,项目根 `拆文库/` 或项目 `对标/` ≥2 本才启用。主对标书取 `设定/题材定位.md`「主对标书」字段,缺失则从排除后的候选中取字典序第一本(优先 `对标/`,否则 `拆文库/`),并在 `gaps.main_benchmark_unspecified: true` 中提示用户补。
> **数量规则**:主对标书最多 1 本,用于文风和最终正文输入;副对标 / 参考对标**不限制登记数量**。执行时按题材相关性、引用强度和阶段预算逐本召回;超过预算时裁剪条目,不删除书目。
## 三道防线
1. 副对标 `文风.md` 不读,避免多本文风互相污染
2. 角色/剧情/设定模块可从所有副对标召回,但必须按「同题材 > 弱相关 > 参考」排序,并受每本/总量预算约束
3. narrative-writer 正文 prompt 只吃主对标文风/原文锚点 + 预算筛选后的 `副对标召回摘要`;不读取、不传入副对标 `文风.md` 或副书原文
## 跨题材判断
从项目 `设定/题材定位.md`「对标书列表」字段读每本副对标的「题材类型」与「引用强度」(未登记的书按「参考」处理,并输出 `gaps.benchmark_registry_missing: true`):
- 同题材 + 引用强度=辅:全阶段可召回,按每本上限取条目
- 同题材 + 引用强度=参考:只取最相关条目,默认不超过每本上限的一半
- 弱相关:仅设定/大纲,每本 ≤1 条
- 不相关:跳过
排序规则:先按相关性(同题材 > 弱相关),再按引用强度(辅 > 参考),再按用户在 `对标书列表` 中的顺序;若缺少 `对标书列表` 或其中未登记某本书,则剩余副书按目录名/书名 Unicode 字典序稳定排序,并输出 `gaps.benchmark_registry_missing: true` 提示补全清单。副书数量不限;如果总条数超过阶段预算,裁条目不裁书目记录。
## 阶段消费
表中数字为**每本副对标召回上限**;同时设置阶段总预算,防止副书很多时挤爆上下文。`—` 行表示该文体无此阶段,整行忽略。
| 阶段 | 长篇产出 | 短篇产出 | 同题材每本上限 | 弱相关每本上限 | 阶段总预算 |
|------|---------|---------|----------------|----------------|------------|
| 设定 | `拆文报告.md` | `拆文报告.md` + `情节节点.md` | ≤2 | ≤1 | ≤8 |
| 大纲 | `章节/*_摘要.md` + `剧情/*.md` | `情节节点.md` + `写作手法.md` | ≤3 | ≤1 | ≤10 |
| 模块 | `角色/` + `剧情/` + `设定/` | — | ≤2 | 0 | ≤8 |
| 正文 | `文风.md` + 原文 | `写作手法.md` + 原文 | 0 | 0 | 0 |
> **大纲阶段按剧情单元检索**:检索键为剧情单元「类型」(第一键,必填枚举)/「桥段标签、套路框架位置」(第二键);同题材内同类命中条目优先进入预算。仅限大纲阶段按剧情单元检索时生效,不改其余阶段排序与预算数字。同类零命中时回退主对标来源条并输出非阻塞 `gaps.similar_plot_not_found: true`,流程继续。
## 输出要求
跨书召回输出必须包含:
```markdown
## 副对标召回摘要
| 书名 | 引用强度 | 相关性 | 召回阶段 | 召回条数 | 使用方式 |
|---|---|---|---|---|---|
| {书名} | 辅/参考 | 同题材/弱相关 | 设定/大纲/模块 | {n} | {用于补充某类结构,不进入文风/原文锚点} |
```
若副书很多,只输出被本阶段实际召回的条目;未召回的副书不代表被删除,只是本阶段预算未命中。正文阶段可传入本表作为结构/情绪/设定参考,但必须保留“副书不进文风、不进原文锚点”的边界。
## 拆文字段 → 写作参考
读 `_meta.json.structure_counts` 时,按此表回查当前 skill 已登记的对应写作 reference。短篇优先走 genre-styles 题材包与 short-craft,长篇优先走长篇同类理论文件;未在当前 skill `参考资料` 表登记的文件不要跨 skill 加载。
| 拆文字段 | 含义 | 写作参考 |
|---------|------|---------|
| `beats` | 结构段(开端/发展/高潮/结局) | `outline-methods.md` + 当前 `genre-prose-cards/` 题材卡 |
| `hooks` | 钩子数 | `long-chapter-hooks.md` / `long-suspense.md` |
| `setup_clues` | 反转铺垫线索 | `long-reversal.md` |
| `character_archetypes` | 反差人物 | `character-basics.md` / `character-design-methods.md` + 当前题材卡 |
| `reusable_structures` | 可复用手法 | `outline-methods.md` / `plot-core-methods.md`,按结构功能选择 |
| `reversal_type` | 反转类型(7 枚举) | `long-reversal.md` 对应骨架 |
references/dialogue-mastery.md›
# 对话设计操作手册
> 写对话场景时加载。先看决策路由选对话模式,再用操作指令控制质量。
---
## 决策路由
| 你的对话场景是 | 用这种模式 | 操作 |
|-------------|---------|------|
| 主角碾压/打脸 | 压制模式 | 对方长篇大论 → 主角一字回应 |
| 主角亮底牌/反转 | 反转模式 | 对方嚣张 → 主角一句话事实 → 对方沉默 |
| 关系破裂/心死 | 心死模式 | 对话越回越短:从辩解 → 沉默 → "随意" |
| 日常互动/立人设 | 日常模式 | 让其他人物参与冲突,不要主角一个人独白 |
| 群众震惊/弹幕 | 弹幕模式 | 递进:普通人震惊 → 专业人士分析 → 特殊身份者反应 |
| 信息展示/世界观 | 信息嵌入 | 用角色语气包裹信息,不是机械陈述设定 |
| 情绪拉扯/虐心 | 情绪推动 | 上行下行交替,像拉锯拉升期待 |
### 对话模式选择补充
| 对话类型 | 常见问题 | 修正操作 |
|----------|---------|---------|
| 问答式(通篇一问一答像审讯) | 改为一方主动说,另一方给反应;反应可用动作/表情/心理 |
| 冲突式(太礼貌不够劲) | 递进五级:委婉拒绝→友好人道→命令否定→PUA式→直接侮辱 |
| 日常对话(容易变成没功能的水) | 功能是立人设;能让人参与的冲突别让主角独白 |
| 多人对话(混乱/没营养) | 写前规划每个角色功能:信息提供者/情绪放大器/冲突制造者 |
---
## 对话核心规则
每句对话必须承载以下至少一项,否则删除:
1. **推进剧情**:透露新信息、推动事件发展
2. **增加期待感**:暗示即将发生的事、制造悬念
3. **展示人设**:通过语言风格传递角色性格
且在情绪场景里,每句还要**回应上一句对方的情绪状态**(承接/偏转/升级/退缩)——对话是两个人的情绪在碰,不是轮流播报信息。只推进剧情、句间无情绪承接 = 机械对话。
### 绝对禁止
| 禁止 | 理由 |
|------|------|
| 配角无脑夸主角 | 假 |
| 互相解释读者已知信息 | 水字数 |
| 大段说明文式对话 | 闷 |
| 所有角色说话方式一样 | 模糊 |
| 对话说服人物 | 现实中没人被几句话说服,用突发状况代替 |
| 情绪写完方向变了 | 需回退到情绪拆分 |
---
## 权力博弈对话
### 规则
对话长度 = 权力地位。掌控者话短且冷静,被动者话多且情绪化。
### 压制模式
结构:对方长篇大论(3-5 行)→ 主角一字回应。
```
"你以为你是什么东西?我告诉你,这个家轮不到你说话!你嫁进来的那天起就该明白自己的位置。"
"滚。"
```
### 反转模式
结构:对方嚣张(2-3 行)→ 主角亮底牌(1 行事实)→ 对方沉默。
```
"你有什么资格管?这是我家的钱,我想怎么花怎么花。"
"你妈的存折,密码是我的生日。"
```
### 心死模式
结构:对话越回越短,从辩解到沉默到「随意」。
```
"你听我解释,那天不是你想的那样。"
"嗯。"
"真的,我可以证明。"
"随意。"
```
### 操作指令
- 掌控者/主角亮底牌时:对话 ≤ 10 字,不加动作描写
- 被压制方:对话 ≥ 20 字,可加动作描写(攥拳/咬唇/站起来)
- 两人对话时:短句方 = 权力上位,长句方 = 权力下位
---
## 潜台词与议程
### 潜台词规则
- 角色真实动机绝对不能浅显地写在台词里
- 现实中人说话都给自己找借口,角色也一样
- 每句对白同时设计:角色的动机(可能角色自己都没意识到)和角色的借口
### 对话议程
- 每个角色进入对话时有自己的议程:想从这场对话中得到什么
- 两个角色的议程碰撞才是张力来源
- 双方议程一致(同立场)= 复述,失去意义
### 语气由三要素决定
关系 × 场合 × 目的 = 语气
| 场合 | 特点 | 适合内容 |
|------|------|----------|
| 私人(单对单) | 深入、感情流露透彻 | 内心剖白、密谋、表白 |
| 公众 | 需考虑体面,措辞收敛 | 需要冲击力时可打破(如当众翻脸) |
| 熟人(朋友/同门) | 深度介于两者之间 | 轻松互动和信息交换 |
私密的话在公众场合说才有冲击力。对话中不能完全表达的内容,通过动作、神态、环境补充。
---
## 情绪推动对话
### 强情绪对话
- 命令式+否定式最能激发读者情绪:"我说的还不够清楚吗?"
- 最强话术:打着为你好的幌子,句句不离关心,但句句都是嫌弃、指责、厌恶
- 直接否定比含蓄暗示更伤人
### 情绪连续性
角色情绪是连续的、循序渐进的。从生气到高兴:生气 → 不那么生气 → 不生气 → 高兴,每次转变需对应事件触发。不能跳步。
### 情绪四步法(缺一不可)
1. 遇到事件(失衡状态)
2. 情绪反应(外在表现:动作、表情、语言)
3. 内心思考(即使没思考也要写出"没有思考",表达鲁莽)
4. 采取行动(基于前三步结果回应)
### 对话不平淡三思路
- 对话本身带来/强化某个核心驱动力(期待、爽感、悬念)
- 信息交流因某原因受阻碍,阻碍可能导致驱动力到来
- 发展突然脱离读者预期(但必须合理、符合人设)
- 把长篇对话塞在期待点和爽点之间:读者为了看爽点愿意忍受中间对话
---
## 信息展示与世界观引出
- 大量信息通过对话展示会显得啰嗦,部分信息转化为情节、心理描写、旁白、环境、动作
- 用角色的语气和立场包裹信息,不是机械陈述设定
- 设定用到哪个稍微带出来就行,不需完完全全讲明白前因后果
- **角色不当"科普嘴"**:设定/原理/前因后果不能靠任何角色(尤其信息型/AI 配角)整段讲解——Gate G 同样适用于角色台词。拆成角色在压力下挤出的半句话 + 身体反应 + 留白,用到哪带哪点
### 信息拉扯示例(以"主角新书起飞了"为例)
| 角色 | 台词 | 功能 |
|------|------|------|
| 甲 | 听说成绩…… | 悬念拉期待 |
| 乙 | 肯定没人看! | 下行 + 拉期待 |
| 甲 | 听说成绩很不错 | 上行 + 拉期待 |
| 乙 | 首订一万三? | 展露核心信息 + 达成爽点 |
上行和下行交替,情绪像拉锯不断拉升期待。
---
## 人物语言差异化
每个角色要有自己的说话方式。对话时经常卡住不知道角色会说什么 → 人设模糊,去总结类似人设的说话方式。
| 差异化维度 | 操作 |
|------------|------|
| 口癖和惯用语 | 给每个主要角色一个标志性用词 |
| 说话节奏 | 长篇大论 vs 短句连击 |
| 信息偏好 | 技术型带专业术语,江湖人带切口 |
| 立场固定 | 某角色永远从某个角度发言(悲观派/乐观派/务实派) |
| 身份影响措辞 | 老者/少年/贵族/市井,身份不同则措辞、自称、敬谦词不同 |
| 性格影响语气 | 智谋型话里有话;鲁莽型想到什么说什么;冷静型措辞精确,偶尔情感外露反而有冲击 |
| 进度影响态度 | 初见/熟悉/对立/亲密,关系阶段不同则语气与信息量不同 |
---
## 弹幕/群众对话
三大核心作用:剧情推进(透露主角不知道的信息)、增加期待感(悬念、猜测)、情绪渲染(群众震惊/激动/愤怒传染读者)。锦上添花,不代替主线。
### 设计过的弹幕 vs 没设计的
- 没设计:只有"卧槽好厉害",单调、浪费
- 设计过:普通人震惊 → 专业人士分析 → 特殊身份者反应 → 情感升华
### 操作要点
- 不同人格化语气,不能每条都一个味
- 短小精悍,每条不超过一句话核心信息
- 善用递进:从最初震惊到逐渐认识全貌
- 可出现"反转"角色:看似路人一句话改变所有人认知
- 不用每章都写,关键爽点/燃点/泪点前后集中使用
---
## 节奏控制
### 大量对话保持节奏
- 不要删掉表现人物性格的语气助词来"精简"
- 对话段落间穿插动作描写、环境变化、心理活动调节节奏
- 紧张段落对话短促,舒缓段落可以长一些
- 关键信息放对话开头或结尾,中间用于拉扯情绪
### 动作和表情处理
- 刻意给每句对话配表情/动作会让行文机械
- 动作和表情在关键转折处使用效果最好,不需要每句都配
- 语气平淡场景(喝茶、散步)用微小动作和沉默体现氛围
### 对话的呼吸感
- 连续多轮对话后需要"换气",插入环境描写或角色心理
- 适当停顿(动作描写、换行、短句)比连续输出更有张力
- "你确定?"比长篇解释更有压迫感
---
## 篇幅控制
### 对话过多时
- 读者已知信息的对话用叙事一句话概括:"爱丽丝向安娜讲述了来城里的原因,安娜听后直皱眉头"
- 能用突发状况替代的对话段落直接替换
- 语气词删掉后干巴巴 = 对话本身缺乏信息量,需重写
### 对话过少时
- 能用其他人物对话讲出来的东西,不要让主角旁白平铺直叙
- 引入配角参与冲突和对话,但新人物必须安排主线戏份
---
## 以梗填充对话
### 梗式 vs 普通
- 普通:"兄弟别灰心,你一步步走到今天我是看着你过来的,这点挫折对于你来说算什么事儿?振作起来!"
- 梗式:"兄弟别灰心,我相信你总有人头落地,落地人头,头落地上……卧槽那句话怎么说的来着?兄弟你懂我意思是吧……"
- 梗式用"说不出来但意思到了"的状态制造趣味
### 操作
- 在对话中融入梗或骚话,有效提升整体趣味性
- 特别是主角或重要配角的突出对话,适合用梗强化记忆点
- 可用某个梗作为高潮点,整段剧情围绕达成这个梗来设计
- **场合例外(声线让位)**:高压/生死/悲痛/严肃 beat 里,搞笑担当与轻快配角的玩笑、口头梗、插科打诨一律收敛——声线让位于当前情绪基调,用短、冷、带情绪重量的反应替代;梗只在安全或喘息 beat 放。自检:这句玩笑放进当前基调会不会让读者出戏?会就删/改
---
## 质量检查
### 三大自查项(中一条以上需改进)
- [ ] 是否存在大量信息都必须用对话来展示
- [ ] 对话是否是问答式的一问一答
- [ ] 是否习惯依赖对话来推动剧情或人物变化
### 核心指令检查
- [ ] 权力博弈:掌控者对话 <= 10 字 / 被压制方 >= 20 字,是否有明确的压制/反转/心死模式
- [ ] 潜台词与议程:每个角色进入对话时有自己的议程,真实动机不在台词中
- [ ] 人物差异化:遮住角色名后能否区分是谁在说话(7维差异化)
- [ ] 弹幕递进:普通 → 专业 → 特殊身份,是否有层次感
- [ ] 对话推动剧情:每段对话结束时,剧情是否往前推了一步
- [ ] 篇幅控制:单次对话不超过全节 40%,信息密度是否足够
### 检验对话质量
- 对话自然度检查:逐句检查对话是否像自然口语交流,而非书面化的问答稿
- 对话结尾能否预示接下来的节奏变化
references/emotional-arc-design.md›
# 情绪弧线操作手册
> 写故事时选弧线、控制节奏、调动情绪的速查操作手册。
## 决策路由表
| 你想写的情绪效果 | 选哪个弧线 | 关键要点 |
|------------------|-----------|----------|
| 虐完翻盘 | V 形 | 谷底 60-70%,治愈急速回升 |
| 甜完刀死(BE) | 倒 V 形 | 高点 40-50%,坠落比上升快 |
| 多反转猜不到 | W 形 | 每峰比前高,上限 3 起伏 |
| 层层打脸升级 | 递进形 | 无回落,像台阶往上 |
| 隐忍后大爆发 | 延迟满足 | 前 70-80% 铺垫,最后集中爆发 |
| 结尾颠覆 | 急转形 | 70-80% 处急转弯,前面线索要能回看说通 |
可叠加两种弧线(如"延迟满足 + 急转"),不超过两种。
---
## 六种弧线速查
### 一、V 形弧线(虐 -> 治愈)
```
情绪
10 | *
9 | / \
7 | / \
6 | / * 治愈高点
1 | * 虐谷底
+------------------> 进度
0% 40% 70% 100%
```
操作要点:
- 谷底放在 60-70%,治愈急速回升,结尾情绪必须高于起点
- 谷底要够深,转折要突然,治愈不拖,谷底停留 1-2 场景即转折
| 题材 | 虐的部分 | 治愈的部分 |
|------|----------|------------|
| 重生复仇 | 前世被虐 | 重来后翻盘 |
| 破镜重圆 | 分开的痛苦 | 重新在一起 |
| 亲情催泪 | 误解/亏欠 | 和解/明白真相 |
| 成长治愈 | 低谷遭遇 | 重新站起来 |
字数分配(12000 字):起始 10% -> 下沉 30% -> 谷底 15% -> 转折 10% -> 治愈上升 25% -> 高点收束 10%
### 二、倒 V 形弧线(爽 -> 反转 -> 低谷)
```
情绪
10 | *
5 | * \
1 | * BE 落点
+------------------> 进度
0% 30% 60% 100%
```
操作要点:
- 高点放在 40-50%,反转后急速下坠
- 坠落速度必须快于上升,BE 结尾不加糖
| 题材 | 爽的部分 | 坠落的部分 |
|------|----------|------------|
| BE 虐恋 | 甜蜜/幸福 | 真相/分离 |
| 职场翻车 | 升职/成功 | 发现是陷阱 |
| 友情背叛 | 亲密无间 | 背后的算计 |
| 信任崩塌 | 深信不疑 | 被欺骗的真相 |
字数分配(12000 字):起步 10% -> 上升 35% -> 顶点 10% -> 反转 5% -> 坠落 30% -> 低谷收束 10%
### 三、W 形弧线(多起伏)
```
情绪
10 | * *
5 | * \ /
4 | *
+--------------------> 进度
0% 20% 40% 60% 80% 100%
```
操作要点:
- 至少两个波峰一个波谷,通常三个起伏
- 每个峰必须比前一个高,最终峰在 80-90%
- 起伏之间必须有喘息空间,上限 3 个起伏
| 题材 | 说明 |
|------|------|
| 多反转悬疑 | 每次以为猜到了就再来一个反转 |
| 追妻火葬场 | 反复拉扯,每次以为和好了又出问题 |
| 商战博弈 | 你来我往,每次以为赢了又翻盘 |
字数分配(15000 字,3 起伏):起步+第1峰 25% -> 第1谷 10% -> 第2峰 25% -> 第2谷 10% -> 第3峰 20% -> 收束 10%
### 四、递进弧线(逐步升级)
```
情绪
10 | *
7 | * /
5 | * /
3 | * /
+--------------------> 进度
0% 25% 50% 75% 100%
```
操作要点:
- 不能有回落,像台阶一阶一阶往上
- 最高点在 85-95%,中间只给小胜利,不提前释放
| 题材 | 递进方式 |
|------|----------|
| 打脸爽文 | 一个一个打,每个比上一个狠 |
| 层层揭秘 | 真相一层比一层震撼 |
| 逆袭翻盘 | 每一步翻盘都比上一步大 |
字数分配(10000 字):压迫 20% -> 第1阶反击 20% -> 第2阶反击 25% -> 第3阶反击 25% -> 收束 10%
### 五、延迟满足弧线(长铺垫 -> 爆发)
```
情绪
10 | *
5 | *--------|
3 | *------ |
1 | *------ |
+-------------------------> 进度
0% 20% 40% 60% 80% 100%
```
操作要点:
- 前 70-80% 压制/铺垫,最后 20-30% 集中爆发
- 铺垫阶段每段必须有信息量和张力,不能无聊
- 压的方式要多样,爆发要密集,爆发后快收
| 题材 | 压的部分 | 爆发的部分 |
|------|----------|------------|
| 复仇爽文 | 隐忍、装弱、被欺压 | 一朝翻盘、全面清算 |
| 身份揭秘 | 隐藏实力/身份 | 真实身份曝光,全场震惊 |
| 长线布局 | 主角暗中操作 | 所有棋子同时落位 |
字数分配(12000 字):初始压制 20% -> 深层铺垫 25% -> 压力最大 15% -> 爆发触发 5% -> 集中爆发 25% -> 收束 10%
### 六、急转弧线(70-80% 处急转弯)
```
情绪
10 | * 急转后的新高/低点
8 | *--/
3 | /
+-------------------------> 进度
0% 30% 70% 80% 100%
```
操作要点:
- 前 70-80% 正常弧线,70-80% 处突然转向
- 急转只占 1-2 段,前面埋的线索回看时必须说得通
| 题材 | 前半段 | 急转后 |
|------|--------|--------|
| 细思极恐 | 温馨日常 | 恐怖真相浮现 |
| 身份错位 | A 视角叙事 | 其实是 B |
| 动机反转 | 以为是爱 | 其实是恨/利用 |
字数分配(10000 字):建立假象 35% -> 推高假象 30% -> 假象高点 10% -> 急转 5% -> 真相展开 15% -> 新情绪收束 5%
---
## 中段加压四手段
1. **公开升级**:把私下伤害搬到公开场合(家宴、公司会议、直播、典礼)
2. **双重背叛**:已知一层背叛后再加一层(经济背叛、名誉背叛、立场反转、证据篡改)
3. **代价加速**:不行动的代价不断升高(失去机会、当众羞辱、连累他人)
4. **战略性沉默**:主角暂不反击,沉默本身持续加压(他人误读、反派更放肆)
---
## 题材赛道策略
| 赛道 | 最佳爽点 | 中段重点 | 结尾偏好 |
|------|----------|----------|----------|
| 婚恋/追妻火葬场 | 开篇羞辱->公开反杀->渣男后悔->身份翻盘 | 公开/私下反差、代价升级、至少一个 mini-payoff | 静默优越、社会地位反转 |
| 家庭伦理/亲情 | 高压现实场景、家人背叛断裂感 | 层层施压、道德绑架、一次拒绝兜底 | 边界清晰、脱离旧结构 |
| 都市逆袭/职场 | 被轻视->展现实力->身份揭露 | 能力被低估但持续展示、关键场合意外表现 | 身份真相大白、对手代价可视 |
| 悬疑反转 | 反常事实->层层剥开->颠覆认知 | 每层揭露引发新问题、至少一次"以为找到了但不是" | 真相一击(最后一句话重构全篇) |
---
## 期待感管理六法则
1. **期待最大化定律**:爽点到来前那一刻是全篇张力最高位置。将满足而未满足时,读者需求最大。
2. **信息顺序操纵**:先植入什么信息,读者就先入为主往哪个方向想。控制信息顺序 = 控制读者预期。
3. **期待递增法**:在基底期待上不断添加细节,注入更具体化的需求缺口。添加的细节必须与核心梗一致。
4. **断期待禁止**:下一个期待立起来之前,绝不能结束当前期待。旧期待即将兑现时,新期待的种子必须已种下。
5. **下行情节安全原则**:写情绪下行时,锅都是别人的,功都是主角的。下行中必须给读者安全感(可能的解法/潜在收获)。
6. **爽点递增对比**:连续爽点逐级递增。维度:影响范围(个人->群体->社会)、揭示深度(表象->本质->颠覆)、身份落差(路人->大佬->全场震惊)。
---
## 情绪核心公式
写每个场景时分离三层情绪:
1. 角色自己的情绪(角色感受到的)
2. 文本传递的情绪(文本要让读者感受的)
3. 读者实际感受的情绪(读者真正的体验)
同一场景三层可以完全不同:角色在哭,文本在撩,读者在爽。
例:女主当众被退婚,强忍着没掉泪——角色:屈辱;文本写她嘴角还挂着笑(角色:撑);读者替她憋着、等后面打脸(读者:爽前蓄力)。
---
## 前反应-复现-后反应情绪结构
用于虐/悲壮/遗憾类场景。按顺序执行三步:
1. **前反应**:让读者提前知道坏结果,然后描写美好事物(读者预知法)
2. **复现**:让坏结果真的发生
3. **后反应**:主角真情流露,作出改变(愤怒/拼命/振作)
操作示例:知道某人一天后要死 -> 让她经历美好(逛街、看烟花) -> 她真的死了 -> 主角愤怒拼命
---
## 以小搏大情绪结构
用于热血/逆袭类场景。按顺序执行四步:
1. **前反应**:铺垫弱者的苦,用对比强化(现在的弱 vs 以前的强)
2. **复现**:强者到来,"我知道你们苦,我来了"
3. **后反应**:弱势方被拯救
4. **士气如虹**:整体气势转变
---
## 冲突中的情绪层次与死亡赌注
### 选择死亡赌注
| 赌注类型 | 适用场景 | 操作要点 |
|----------|----------|----------|
| 肉体死亡 | 恐怖诡异文 | 主角过强时赌注必须转为事业死亡,否则全书崩溃 |
| 事业死亡 | 职场竞争、修仙门派争斗 | 失败 = 一切归零 |
| 心理死亡 | 感情崩塌、信念毁灭 | 情绪冲击最深,优先用于感情线 |
选一种作为主要赌注贯穿全书,其他辅助推动情节。
### 用黏结剂维持张力
对立双方必须无法轻易脱身。四种黏结剂:杀人理由(序列唯一性必然冲突)、工作职责、道德责任(亲人遇险)、实体场所(副本密室)。
### 长线维护规则
- 第一卷结局不能太圆满——完美解决会杀死后续追读动力
- 解决一个麻烦的同时必须埋下下一个麻烦
- 越到后期,情绪张力必须越大
---
## 基于不该如此的情绪驱动
- "不该如此"是最根本的情绪驱动力——写诬告、不公、恃强凌弱,读者天生生出"不该如此"的念头
- 核心情绪逻辑:想要爽,必先不爽;想要公平,必先不公平;想要强大,必先不强大
- "悬而未决"也是强驱动力
- 好的题材必须具备勾起人们惋惜、渴望改变的特质
---
## 理念矛盾的情感爆发力
- 理念之争比利益之争更能引发读者深层共鸣
- 少量关键场景即可,不需要大量笔墨
- 理想主义与现实的冲突是塑造配角封神级人设的手法
- 理念认同 = 人设认同 = 读者情感投入
- 在主线中穿插理念型角色,用他们的追求和牺牲拔高全书情绪上限
---
## 情绪调动的三层方法
三层:**长期感情投入**、**短期事件冲突**、**场景描绘**。三者可叠加,核心是前两层。
### 长期引导三步骤
1. **抛出共鸣炸弹**:找到角色最易引发共鸣的情感锚点(梦想、仇恨、恐惧)
2. **让读者变见证者**:展示角色付出和挣扎,每一步伴随收获
3. **让读者变参与者**:通过足够铺垫和细节,产生命运共同体感
### 短期情绪引导
短期靠独立事件冲突。**直白冲突比繁杂情节更容易引起共鸣**。
两种事件类型:
- **推动情节发展的事件**:让读者对角色处境产生认同
- **塑造人物性格的事件**:让读者对角色思想性格产生认同
开篇必须选择塑造人物性格的事件——先认同角色这个人才关心角色的事。
### 情绪代入的陷阱
读者未代入主角前:主角弱势可以引起同情,但**敌人弱势也同样引起同情**。读者还没建立认同时,不要把对手写得可怜。
### 情绪文笔技法
- **句长跟着情绪和节奏走**:紧张、决断处用短句提速,铺垫、沉淀处用长句蓄势;短句是提速工具,不是默认底色,别通篇拆短
- **情绪词**:骤然、猛然、刺眼——制造紧迫感
- **动作词**:抽、划、留下——画面感强,情绪外化
- **修饰词**:精准克制地使用形容词,不堆砌
- **进阶规则**:优先通过角色行为暗示情绪,而非直接描写(非硬性,必要的内心可以直写,别为外化堆无功能的小动作)。**以乐写悲**:角色在最悲伤时表现开心,情绪张力更强(赴死的人很开心,往往比哭更悲)
---
## 男频恋爱文情绪设计
### 两大核心需求
- **情绪价值**:读者缺爱,小说中漂亮优秀女生欣赏自己,填补情感空缺
- **自尊价值**:带校花/女总裁出场,旁人羡慕嫉妒恨
### 恋爱当升级文写
- 设定"好感度进度条"(路人->好人->朋友->喜欢不自知->...)
- 暧昧拉扯的过程通常比在一起的结果更吸引读者
- 制造内外部阻碍阻拦两人走到一起,通过克服阻碍加深感情
### 感情升级的不对称性
两条进度线不能齐头并进:
- **情感快于社会关系**:双方好感早已拉满但嘴硬不表白
- **社会关系快于情感**:穿越自带老婆/未婚妻,好感为零需逐步提升
### 关键禁忌与技巧
- 男主不要主动追求,不要舔狗——用自身优秀品质吸引女主注意
- 事业线不可或缺,女主对主角事业起积极作用
- 要写女主对主角好,根据人设设计付出方式(自卑型偷偷塞丹药、傲娇型嘴硬做便当、直率型大方送礼物)
- **对比法**:时间线对比(前后态度变化)+ 双标(对别人 vs 对主角)
- **信息差拉期待**:双重身份(网络身份 vs 现实身份),读者期待揭穿马甲时的反应
---
## 情绪调动统一视角
> 写完一段觉得不到位 / 读者反馈平淡时使用。
### 终极公式
**平静 -> 调动 -> 释放 -> 爽**
| 技法 | 调动 | 释放 | 结果 |
|------|------|------|------|
| 装逼打脸 | 反派嚣张 | 主角碾压 | 爽 |
| 拉仇恨 | 负面情绪 | 恶人受罚 | 爽 |
| 先抑后扬 | 打压 | 爆发 | 爽 |
| 期待感 | 制造鸿沟 | 弥合鸿沟 | 爽 |
### 实操要点
- 每个场景标注:读者当前情绪在哪个阶段;下一步是调动还是释放。
- 只有调动没有释放 = 读者憋屈弃书
- 只有释放没有调动 = 爽感平淡无力
- 调动程度决定释放爽度:仇恨拉多满,打脸就多爽
---
## 期待感维持的底层机制
> 写了目标但读者不关心 / 六法则用了但效果不好时使用。
### 期待感 vs 目标
- **目标** = 角色要做什么(找到宝物、打败魔王)
- **期待感** = 读者对目标达成后会怎样的预期
- 有目标无期待 = 读者不在乎结果,必须把目标转化为期待
### 确定型 vs 不确定型期待
- **确定型**(爽文):读者知道主角会赢,写"怎么赢"(过程创意 > 结果悬念)
- **不确定型**(悬疑):读者不知道结果(结果悬念 > 过程体验)
- 爽文不怕"剧透"——因为期待在过程不在结果
### 悬念的开环与闭环
- **开环** = 制造鸿沟(提出问题/悬念)
- **闭环** = 弥合鸿沟(回答问题/揭晓)
- **嵌套开环** = 闭环一个期待的同时开启新的(维持阅读连续性)
- 规则:闭环一个期待时,必须已有下一个开环在运行
### 感情线的鸿沟
感情线没有阻碍 = 没有期待 = 白给 = 无意义。必须设置鸿沟。
鸿沟来源:身份差距、家族反对、误会、使命冲突。
---
## 质量检查清单
写完情绪弧线后逐项检查:
### 弧线选择与节奏
- [ ] 弧线类型是否匹配你想写的情绪效果?(对照决策路由表)
- [ ] 关键转折点是否在正确的进度位置?(V形谷底60-70%、倒V高点40-50%、急转70-80%)
- [ ] 字数分配是否符合所选弧线的比例要求?
### 调动与释放
- [ ] 每个场景是否清楚当前是"调动"还是"释放"阶段?
- [ ] 是否存在只有调动没有释放的段落?(会憋屈弃书)
- [ ] 是否存在只有释放没有调动的段落?(爽感平淡)
- [ ] 连续爽点是否逐级递增?(影响范围/揭示深度/身份落差)
### 期待感
- [ ] 每个目标是否已转化为读者期待?
- [ ] 闭环一个期待时,下一个开环是否已在运行?(断期待禁止)
- [ ] 感情线是否设置了阻碍?(无阻碍 = 无期待)
### 情绪代入
- [ ] 开篇是否用了塑造人物性格的事件?(先认同人,再关心事)
- [ ] 读者未代入主角前,是否避免了把对手写得可怜?
- [ ] 下行情节中是否给了读者安全感?(锅是别人的,功是主角的)
### 长线维护
- [ ] 解决一个麻烦时是否同时埋下了下一个麻烦?
- [ ] 越到后期情绪张力是否越大?
- [ ] 死亡赌注是否选了一种贯穿全书?
- [ ] 对立双方是否有黏结剂无法轻易脱身?
references/emotional-methods.md›
# 情感设计方法:三板斧 + 拉扯节奏 + 失败模式
> 设计情感桥段时加载。先用下方通用长篇单元情绪引擎规划因果链;三板斧只在适用场景中作为可选技法。
---
## 长篇单元情绪引擎(通用正向框架)
每个剧情单元先设计能制造情绪与兑现的**正向发动机**,再做安全审查:
> **核心情绪命题 → 承载对象/情绪缺口 → 受阻或缺口维持原因 → 本轮触发 → 主角不可替代的点火/转化动作 → 意义变化或可见兑现 → 题材/契约兑现**
这条因果链适用于爽、燃、甜、虐、恐、治愈等不同核心情绪。承载对象可以是人物、关系、目标、规则或场景;不适用的环节可写“无/即时”,但必须保持因果闭合。它不要求每个题材都有长期受阻、最终画面或克制反应,也不规定单一机制:误解、物件、反转、死亡等都不是必备项。下文“情感虐心三板斧”是适合部分情感题材的**可选技法**,不是通用引擎的硬模板。
### 正向发动机与负向护栏的顺序
1. **先设计正向发动机**:明确读者会为什么投入,本轮如何让这份投入改变意义并得到可见兑现。
2. **后用主角代理权/成长负向护栏诊断**:以 `reader-contract-and-progression.md` 的因果权 + 结算权、期待所有权与终局储备排查契约/推进失败。“安全”只代表没踩红线,不代表好看;护栏不能代替情绪发动机。
### 合理性五问
1. 为何是该承载对象?
2. 为何是现在?
3. 为什么没有被直接解决 / 为何此前仍悬置?
4. 主角凭什么介入/转化?
5. 现实/设定边界如何约束?
五问用来截住巧合式工具人、为推情节而突然变蠢的机构,以及事后补一段说明的解释补丁。
### 强度原则
强情绪来自**具体投入、受阻/延迟、意义变化、可信反应等机制按题材组合**,不要求全部出现,也不来自堆叠死亡、疾病和哭喊。克制反应只是部分情绪的可选放大器。物件、对话、动作、身份、规则、关系都可作为可选锚点;锚点频率随篇幅和读者记忆需求调整,从不强制重复三次。集体或价值抬升也是可选的;只在题材需要时,才由个体兑现扩展到题材核心情绪。
---
## 决策路由
| 你的情感设计场景是 | 用这个策略 | 跳转到 |
|---------------|-----------|----------|
| 规划长篇剧情单元的情绪引擎 | 通用长篇单元情绪引擎 | 长篇单元情绪引擎 |
| 建立角色羁绊(让读者相信关系) | 羁绊铺设(第一斧) | 三板斧 §1 |
| 制造情感撕裂(反差/错位/背叛) | 情感撕裂(第二斧) | 三板斧 §2 |
| 写结尾余韵(安静细节击穿读者) | 余韵钝痛(第三斧) | 三板斧 §3 |
| 规划整体情感节奏曲线 | 拉扯节奏设计 | 拉扯节奏 |
| 不同题材的情感策略选择 | 题材策略差异 | 按题材 |
| 检查情感设计是否有效 | 失败模式排查 + 快速自查 | 底部清单 |
---
## 情感虐心三板斧
### 第一斧:羁绊铺设(前 1/3)
**目标**:用具体物件/数字/细节建立关系质感,让读者相信这段关系是真实的。
**方法**:
- 用具体数字建立时间感:「相恋八年」「昏迷五年」「七年光景」
- 用具体物件承载感情:金锁(姐姐的生日礼物)、账本数字(还债记录)、木头小马(父王磨的)
- 用重复动作建立习惯:每天一碗粥、每两周来看一次、每年冬天冻得睡不着
**案例**:
- 《迟来二十年》:用二十年的账本数字(八万块)建立母女关系的重量
- 《我在佛前求你》:昏迷五年、求神拜佛的细节、从初中开始的暗恋
- 《皇弟欺负幼子》:七年质子生涯的具体苦难(跪雪地、挨巴掌、吃馊饭)
**核心**:羁绊越具体,后面的撕裂越痛。不要用「他们很相爱」这种抽象描述。
---
### 第二斧:情感撕裂(中后段)
**目标**:制造反差,让读者以为恨对了 → 发现恨错了(或反过来)。
**方法**:
- **反差法**:先展示温暖一面,再用残酷真相击碎
- **错位法**:角色 A 以为在保护角色 B,实际上在伤害
- **延迟真相法**:关键信息在读者最不期待的时候揭示
**案例**:
- 《姐夫捎路要奶粉钱》:妈妈表面软弱可怜,实际一直操控姐姐索取钱财 → 金锁是假的(金包铜)→ 反差撕裂
- 《皇弟欺负幼子》:王氏表面温柔(送手炉、煎汤药)→ 实际下药逼疯先皇后 → 用诛心话逼死
- 《重生弟弟》:弟弟深爱女友 → 女友是诈骗犯 → 怀孕是假的 → 被骗到电诈园区
**核心**:撕裂的力度取决于铺垫的厚度。没有好的羁绊铺设,撕裂就是无根之木。
---
### 第三斧:余韵钝痛(结尾)
**目标**:不用大哭大闹,用安静细节击穿读者防线。
**方法**:
- 用日常动作承载巨大情感:继续喂粥、把衣服叠好、不回头
- 用物件细节制造余韵:坏掉的金锁、木头小马、沾血的戒指
- 用「不」制造留白:不解释、不回头、不流泪
**案例**:
- 《皇弟欺负幼子》:「他拿着那匹被我磨得很光滑的木头小马……他握着正好。」
- 《姐夫捎路要奶粉钱》:「我的手机清净了不少。那些困扰我很久的麻烦,在一瞬间变得很小很小。」
- 《准儿媳打分》:「办了收养手续后,她第一次踏进这个陌生的家……我知道,这一次我没选错。」
**核心**:最好的余韵不靠大哭,靠「看完之后很久都忘不掉」。
---
## 情感拉扯节奏设计
### 基本节奏曲线
```
温暖 → 残忍 → 善意 → 真相 → 原谅 → 来不及 → 释然 → 细节暴击
```
不是所有故事都走完整曲线。按题材选择子集:
| 题材 | 典型节奏 | 核心拉扯 |
|------|----------|----------|
| 世情/爽文 | 欺压 → 忍耐 → 爆发 → 打脸 | 情绪反弹快、打脸密度高 |
| 情感/虐心 | 甜蜜 → 破碎 → 挽回 → 错过 | 慢铺垫、后劲大 |
| 古言/复仇 | 隐忍 → 布局 → 揭穿 → 报应 | 设定简洁、暴力美学 |
| 悬疑/推理 | 平静 → 不安 → 真相 → 震惊 | 信息差制造不安 |
| 年代/亲情 | 误解 → 冲突 → 真相 → 和解 | 代际冲突、时代质感 |
### 拉扯原则
1. **情绪转向频率是题材与篇幅经验法则**:结合题材、篇幅和既有兑现节奏调整,不固定要求每 3-5 个小节转向
2. **每次转向都要有触发事件**(不能无理由地改变情绪)
3. **最后一次转向决定结尾余韵的基调**
4. **爽文允许快速反弹,虐文需要更长铺垫**
---
## 按题材的情感策略差异
### 世情/爽文
- 情绪反弹速度:快(受辱后 2-3 节内打脸)
- 打脸密度:每 3-5 节一次
- 反派嚣张度:递增(第一次小嚣张,最后一次大嚣张)
- 结尾基调:痛快、解气
- 案例:《准儿媳打分》— 打分制反制、铁盒零分、断绝关系
### 情感/虐心
- 羁绊细节密度:高(前 1/3 必须建立深厚羁绊)
- 反差设计:先暖后冷,先甜后苦
- 余韵技法:安静结尾 + 物件细节
- 结尾基调:意难平、释然
- 案例:《姐夫捎路要奶粉钱》— 金锁真相 → 假爱 → 独立
### 古言/复仇
- 设定简洁原则:人物关系清晰,不搞复杂世界观
- 暴力美学写法:打脸要直接,不拖泥带水
- 底牌时机:最后 1/4 揭示最大底牌
- 结尾基调:大快人心、因果报应
- 案例:《皇弟欺负幼子》— 一声令下打二十棍 → 查出真相 → 废后
### 悬疑/推理
- 信息差布局:读者知道角色不知道,或反过来
- 排除法结构:逐步排除可能性,最后只剩真相
- 动机揭示节奏:先揭示做了什么,再揭示为什么做
- 结尾基调:细思极恐、原来如此
- 案例:《重生弟弟》— 重生设定 + 诈骗犯身份 + 电诈园区
### 年代/亲情
- 代际冲突处理:不站队,展示双方的苦
- 时代细节质感:用时代特有的物件/习俗建立质感
- 和解节奏:不急和解,先让双方充分受伤
- 结尾基调:温暖中带着遗憾
- 案例:《姐夫捎路要奶粉钱》— 亲子关系 → 金锁真相 → 断裂
---
## 常见失败模式
| 失败模式 | 识别方法 | 修正方向 |
|----------|----------|----------|
| **太平** | 连续 5+ 节没有情绪转折 | 插入意外事件或新信息 |
| **太赶** | 重大转折缺少可辨认的铺垫 | 按转折重量与篇幅给予足够且可辨认的铺垫,不固定三节 |
| **假虐** | 读者不心疼,只是看着难受 | 检查羁绊铺设是否具体 |
| **割裂** | 前半部分和后半部分像两篇不同的故事 | 用伏笔/物件/主题贯穿 |
| **烂尾** | 反转后仍长时间重复交代 | 按题材与篇幅适配的速度收束或冷却,不固定五百字 |
| **人设崩** | 角色在关键时刻的行为不符合前面的人设 | 回顾人设,确保行为逻辑一致 |
---
## 快速自查
设计情感时,用这个清单:
- [ ] 前 1/3 有具体羁绊细节(不是抽象描述)?
- [ ] 中段有反差/撕裂(读者以为 A → 实际是 B)?
- [ ] 结尾有安静细节(不是大段抒情)?
- [ ] 情绪转向频率是否按题材、篇幅和既有兑现节奏调整,而非固定密度?
- [ ] 反派行为符合其人设逻辑?
- [ ] 不存在上述 6 种失败模式?
---
## 三板斧与 SKILL.md 五段结构映射
| 三板斧 | 对应 SKILL.md 五段 | 说明 |
|--------|-------------------|------|
| 第一斧:羁绊铺设(前 1/3) | 铺垫段(第二段,占 30-40%) | 用物件/数字/习惯建立关系质感 |
| 第二斧:情感撕裂(中后段) | 升级段(第三段)+ 反转段(第四段) | 反差/错位/延迟真相制造撕裂 |
| 第三斧:余韵钝痛(结尾) | 结尾段(第五段,占 5-10%) | 安静细节收尾,不写大段抒情 |
references/female-audience-writing.md›
# 女频写作操作手册(长篇)
> 写长篇女频(番茄女生/起点女生/晋江/七猫)时加载。先看决策路由,再按对应节执行。
> 简介五种基本类型、书名命名技法见 [genre-readers.md](genre-readers.md),本文不重复;平台定位本文按女频频道特化补充。
> 感情线总框架(好感度体系/CP行为门槛/男女频爱情线底层逻辑)以 [character-relations.md](character-relations.md)「好感度体系」为准,本文只补女频长线节奏。
---
## 决策路由
| 你在做什么 | 查看这个部分 | 核心操作 |
|-----------|-------------|---------|
| 定女频核心方向 | 女频核心原则 | 安全感/代入感/主动性/情绪即产品四条全过一遍 |
| 写长篇简介/开篇文案 | 女频文案结构体系 | 用安全感导向四段组合,必含女主成功暗示 |
| 判断目标读者要什么 | 读者群体与深层需求 | 先定读者画像,再定情绪方向 |
| 选长篇题材/找梗 | 长篇热门题材与梗 | 选有长线骨架的题材,叠梗组合,scan 验证热度 |
| 排感情线长线节奏 | 感情线长线深化 | 按卷级节奏排暧昧→确认→危机→升华 |
| 对比男女频底层逻辑 | 女频 vs 男频底层差异 | 核心驱动/虐的目的/反转类型全不同 |
| 选平台/调篇幅节奏 | 多平台女频写法定位 | 按目标平台调文风、安全感密度、篇幅节奏 |
| 收尾质检 | 质量检查清单 | 逐项核对 |
---
## 女频核心原则(长篇框架)
长篇连载比短篇更吃这四条,因为读者要追几十万字,安全感断一次就掉追读。
- **安全感优先**:女频读者要明确知道女主不会一直被虐。长篇尤其要在卷与卷之间给安全感锚点——每卷收尾女主必须有可见的成长或翻盘,不能整卷只铺虐。简介和开篇必须暗示结局会赢。
- **代入感优先**:女主的处境要让目标读者能投射进去。代入感低,女主做什么读者都不觉得爽。长篇里女主的每一次选择都在累积或消耗代入感。
- **女主主动性**:女主被动、被安排、无选择权 → 留存掉。长篇里"金手指/外挂帮她赢"不等于主动性,关键是女主自己做决定、自己推进。被宠也要是她选择被宠。
- **情绪即产品**:不论甜/虐/沙雕/正剧,本质都是情绪产品。长篇的核心是一条主情绪贯穿到底(追妻=从被虐到被深爱),小情绪都收编到主情绪之下。情绪散乱 = 长篇崩盘第一死因。
---
## 女频文案结构体系(长篇简介)
长篇简介比短篇多一个任务:除了抓人,还要让读者相信这本能追下去。基本五种类型见 [genre-readers.md](genre-readers.md),本节是女频专用的**安全感导向组合**。
文案由**状态、困境/意外、行动、成功/暗示**四段组合,长篇至少要让读者看到女主的"成功暗示"或"翻盘方向"。
| 组合 | 结构 | 适用长篇场景 |
|------|------|-------------|
| 安全感四段式 | 状态 → 困境 → 行动 → 成功 | 最主流,甜宠/事业/重生复仇通用 |
| 复仇预告式 | 状态 → 不公伤害 → 反杀宣言(截止) | 重生复仇/宅斗,留长线悬念 |
| 虐后翻盘式 | 状态 → 被虐 → 转身离开/翻盘 | 追妻火葬场,女主先走才有安全感 |
| 悬疑+成功叠加 | 悬疑钩 → 状态 → 困境 → 成功 | 开头一句悬念抓人,后面给安全感 |
长篇文案安全法则:
- 只铺虐、不给女主翻盘方向 → 读者怕入坑被虐 → 不点进
- 简介把几十万字主线写成流水账 → 信息过载劝退,只写第一卷钩子+全书承诺
- 货不对板(甜宠简介里正文全是虐)→ 长篇尤其致命,掉追读+差评
- 事业线突出的文,简介必须给事业成功暗示,不能只写感情
---
## 读者群体与深层需求
| 读者画像 | 深层需求 | 偏好长篇题材 |
|----------|----------|-------------|
| 家庭主妇型 | "有资格抱怨"+物质保障幻想 | 强取豪夺、先婚后爱、追妻火葬场、豪门 |
| 事业型女性 | 要情绪价值+自我实现 | 独立女主、事业线+感情线并重、种田经商 |
| 学生群体 | 相信爱情战胜一切 | 纯爱、校园、双向奔赴 |
| 中年下沉读者 | 改命+扬眉吐气 | 年代重生、极品家人打脸、重生复仇 |
女频长篇常用情绪方向(是否流行需 scan/analyze 验证):
| 情绪类型 | 代表题材 | 核心爽点 |
|----------|----------|----------|
| 反抗命运 | 年代重生、穿书觉醒 | 改变悲惨命运,打脸极品家人 |
| 事业独立 | 穿越经商、种田、娱乐圈 | 靠自己能力一步步做大 |
| 被宠爱 | 团宠、萌宝、先婚后爱 | 不用费力就被珍视 |
| 虐恋反转 | 追妻火葬场、强取豪夺 | 从被虐到被深爱 |
| 反差萌 | 沙雕修真、系统文 | 轻松里的意外爽感 |
深层需求落点:女频读者表面要"打脸/被宠",深层要的是**被认可、被珍视、被尊重**。长篇要一直抓着这个深层需求不偏移。
---
## 长篇热门题材与梗
长篇选题第一关:题材要有**长线骨架**——能撑几十万字的主线,不是一个梗写完就没了。短篇梗(一个反转、一次打脸)不够撑长篇。
### 主流长篇女频题材(需 scan 验证热度)
| 题材 | 长线骨架 | 主情绪 |
|------|----------|--------|
| 追妻火葬场 | 婚后受冷→女主离开/重生→男主追悔→拉扯→重新接受或彻底放下 | 虐恋反转 |
| 先婚后爱 | 联姻/换亲/契约婚→相处磨合→日久生情→外部危机→深爱 | 被宠爱 |
| 强取豪夺 | 身份压制下被掠夺→抗拒→博弈→反向掌控关系 | 虐恋反转 |
| 重生复仇 | 重生回到伤害前→步步布局→逐个清算→改命扬眉 | 反抗命运 |
| 种田/经商 | 起点低→发现机会→一步步做大→对照组打脸 | 事业独立 |
| 宅斗/宫斗 | 庶女/低位→识破阴谋→步步上位→掌权 | 反抗命运+事业 |
| 年代文 | 穿/重生到年代→搞钱+治极品家人+感情 | 反抗命运 |
| 团宠/萌宝 | 身份被错认→真相揭开→全员宠 | 被宠爱 |
### 长篇梗组合(需验证后用)
- 穿书 + 年代 + 八零 + 换亲 + 先婚后爱
- 重生 + 复仇 + 宅斗 + 伪血缘揭穿
- 种田 + 经商 + 萌宝 + 先婚后爱
- 强取豪夺 + 追妻火葬场 + 萌宝(带球跑)
- 重生 + 娱乐圈 + 打脸渣男渣女 + 事业封顶
### 长篇组合规则
- 一本长篇最多叠 2-3 个核心梗,再多读者记不住、主线散
- 事业线必须搭感情线,纯事业女频长篇出成绩难
- 复仇/宅斗类,仇恨对象要分梯度(小喽啰→中层→终极反派),对应卷级节奏逐个清算
---
## 感情线长线深化
只补**女频长篇感情线的卷级节奏**(总框架见 [character-relations.md](character-relations.md)「好感度体系」)。
### 卷级感情节奏(标准四段)
| 卷段 | 感情状态 | 操作要点 |
|------|----------|----------|
| 暧昧拉扯 | 萍水相逢→试探 | 制造缓冲区,多用反差萌、信息差、双标,慢推好感 |
| 确认 | 暧昧→在一起 | 一个剧情高潮兑现关系质变,匹配盛大节点 |
| 危机 | 确认后的考验 | 外部阻碍/误会/身份揭穿,不要为虐而虐,虐完必有反转 |
| 升华 | 共度危机→深爱 | 危机解决后只发糖,用实在 CP 行为,不再设新矛盾 |
### 女频长篇感情线规则
- **好感度绑事业/成长**:每一次感情升级最好踩在女主的一次事业进展或成长节点上,两条线咬合推进,避免"全书只谈恋爱"的单薄感
- **感情先慢后快**:前期慢铺积累好感,后期集中爆发,配盛大仪式
- **长篇虐的剂量控制**:长篇虐戏要分散、每段虐后必给反转或糖,连续整卷只虐 = 掉追读
- **双视角增张力**:男女主各自视角交替,长篇里尤其能放大拉扯感
### 感情线变体速查(按题材取)
| 题材 | 常用变体 |
|------|----------|
| 追妻火葬场 | 标准版/带球跑版/重生退婚版/反转暗恋版 |
| 强取豪夺 | 身份差版/抢婚版/伪亲属版/反向(男主当替身)版 |
| 先婚后爱 | 换亲版/契约版/年代联姻版/保姆日久生情版 |
| 暗恋/觊觎 | 阴湿暗恋/伪姐弟叔侄/双向暗恋/日记暴露 |
---
## 女频 vs 男频底层差异(长篇视角)
| 维度 | 女频 | 男频 |
|------|------|------|
| 核心驱动 | 情绪产品,几乎都含感情线 | 剧情爽感,纯感情线罕见 |
| 感情线本质 | "连接"——你爱我因为我是我 | "外在展示"——优秀的人是我的了 |
| 异性角色重视度 | 极高,男主人设决定留存 | 较低,女主功能性更强 |
| 虐的目的 | 制造情绪波动,虐完必有反转 | 升级打怪的前置铺垫 |
| 复仇方式 | 信息差式(真相揭露打脸) | 力量式(实力/身份碾压) |
| 长线主轴 | 感情线+成长线双轴咬合 | 实力升级单轴为主 |
| 情绪触发密度 | 约 3.23 次/千字 | 约 2.50 次/千字 |
| 反转类型 | 信息差型(心声/真相) | 力量型(身份/实力) |
跨频铁律:女频读者更在意角色间的情感张力和互动细节;女频长篇事业线必须搭感情线才容易出成绩。
---
## 多平台女频写法定位(需 scan 验证)
| 平台 | 定位 | 文风/安全感 | 篇幅与节奏 |
|------|------|------------|-----------|
| 番茄女生 | 下沉吸量 | 强钩子、强情绪、爽感直给,安全感要早给 | 章节短、节奏快,开篇 3 章必须立住钩子 |
| 起点女生 | 长线稳定 | 人设细、文风稳,可慢热 | 篇幅长、容忍铺垫,靠长线追读 |
| 晋江 | 高质量女频 | 主体性、人设细节、文案安全感要求最高 | 中长篇,重人物关系细密度 |
| 七猫 | 强情绪女频 | 甜虐交替、极限推拉、情绪钩子密集 | 章节密集钩子,推拉节奏快 |
平台选择规则:
- 强梗、快反馈、下沉读者 → 番茄女生/七猫,章节短、钩子密、安全感早给
- 人物细腻、文风稳、长线慢热 → 起点女生/晋江,可铺垫,但开篇仍要有钩子
- 同一题材不同平台写法不同,必须用目标平台样本校准节奏和雷点
---
## 质量检查清单
写女频长篇时逐项核对(§女频核心原则 安全感/代入感/主动性/情绪即产品 四条默认必过,以下查执行项):
- [ ] **感情线双轴**:感情升级踩在事业/成长节点上,不是全书只谈恋爱?
- [ ] **卷级感情节奏**:暧昧→确认→危机→升华节奏清晰,每段虐后有反转或糖?
- [ ] **虐戏剂量**:没有连续整卷只虐,虐的剂量分散可控?
- [ ] **题材有长线骨架**:选的题材能撑几十万字主线,不是一个梗写完就没了?
- [ ] **梗组合不超载**:核心梗不超过 2-3 个,主线没被叠梗冲散?
- [ ] **男主人设**:用细节描写加分(不只形容词),决定留存?
- [ ] **平台对位**:文风、安全感密度、篇幅节奏匹配目标平台?
- [ ] **货板一致**:书名=简介承诺=正文交付三位一体,没有货不对板?
- [ ] **热度已验证**:题材组合热度已用最新 scan/analyze 或用户指定平台信息验证?
references/genre-prose-cards.md›
# 题材正文提示词卡索引
> 本文只做**索引与召回规范**,每个题材的正文提示词已拆到同目录的 `genre-prose-cards/` 下。
---
## 使用原则
正文写作采用三件套:**通用正文要求 + 单题材正文提示卡 + 本书文风**。
- 通用正文要求只维护一份:严格消费细纲,按情节点义务写,缓慢推进,严禁提前写后续剧情,写完做确定性字数、钩子、禁用词、退化校验。
- 题材卡只管题材层稳定核心:世界观/生活逻辑、读者期待、核心爽点/情绪、常见场面、常见钩子和禁止漂移。
- 本书文风只管句长、标点、潜台词、锚点片段和笔调;它不覆盖题材卡,也不覆盖 `剧情/情绪模块.md` / `剧情/节奏.md`。
- 三者冲突时:章节细纲与连续性 > 情绪/节奏权威召回 > 题材卡 > 本书文风 > 通用技巧。
## 召回规则
1. 先读 `设定/题材定位.md`,确认主题材、目标平台、性向频道、主对标书和核心梗。
2. 先查本索引匹配题材,再只读取同目录的 `genre-prose-cards/{题材}.md` 这一张卡;不要把整套题材卡全部加载进 prompt。
3. 跨题材时,主题材读取 1 张完整卡,辅题材读取 1 张并只摘 1-2 条“常见场面/禁止漂移”;不要把两套节奏并行堆满。
4. 高置信卡可直接用于 Phase 2 `设定/题材正文提示卡.md`;中置信卡需结合本书对标/细纲对照;低置信卡只能兜底,必须标注低置信并优先补同题材对标。
5. 每章传给 narrative-writer 的 `genre_prose_card` 只保留本章相关条目,推荐 120-300 字;包含:题材限制、核心逻辑、读者期待、核心爽点/情绪、正文落点、前中后期打法、场景颗粒、禁止漂移、本章取舍、卡片置信度。
6. **题材卡只在写手内部校准题材味,绝不出现在正文里**:正文不得写卡名、题材标签、置信度、条目编号或“证据摘要”数据,也不得写“已按题材卡/满足字数/零违规”一类合规自评或写作过程说明——只输出故事本身。
## 题材卡写法原则
每张题材卡必须回答九件事:题材核心、主线目标、冲突发动机、爽点定位、常见情绪转化、场景颗粒、正文落点、前中后期打法和禁止漂移。可参考“都市日常”式写法:先给清晰生活目标,再说明低烈度冲突如何产生真实结果,然后把开场/冲突/结尾分别落到具体物件和场面,最后写哪些爽点是微小但可见的改变。不要把通用方法论硬套进所有题材。
## 不要把这些写成硬规则
本地长篇样本不支持固定 50-60 字行宽、固定 50%-60% 对话占比、全局替换“地/得/很/像/顿号”、随机倒装、三胺八情或三翻四震等机械模板。题材卡只给“该题材更常用的场面和情绪落点”,具体段落仍按细纲、文风和当前场景处理。
---
## 高置信题材卡
| 题材卡 | 常见别名/匹配词 | 置信度 |
|---|---|---|
| [都市脑洞](genre-prose-cards/都市脑洞.md) | 都市系统 / 听劝文 / 规则奖励 / 生活脑洞 | 高 |
| [豪门总裁](genre-prose-cards/豪门总裁.md) | 霸总 / 京圈 / 先婚后爱 / 契约婚姻 | 高 |
| [双男主](genre-prose-cards/双男主.md) | 纯爱 / BL / 耽美 | 高 |
| [都市日常](genre-prose-cards/都市日常.md) | 日常文 / 都市生活 / 温馨日常 | 高 |
| [都市高武](genre-prose-cards/都市高武.md) | 高武 / 灵气复苏 / 序列 / 异能都市 | 高 |
| [年代](genre-prose-cards/年代.md) | 年代文 / 七零 / 八零 / 随军 / 重生年代 | 高 |
| [玄幻脑洞](genre-prose-cards/玄幻脑洞.md) | 玄幻系统 / 反套路玄幻 / 多子多福 / 词条玄幻 | 高 |
| [战神赘婿](genre-prose-cards/战神赘婿.md) | 赘婿 / 战神回归 / 隐藏身份 | 高 |
| [传统玄幻](genre-prose-cards/传统玄幻.md) | 玄幻 / 东方玄幻 / 仙侠玄幻通用 | 高 |
| [古风世情](genre-prose-cards/古风世情.md) | 古代世情 / 古风家宅 / 古代婚恋世情 | 高 |
| [女频种田](genre-prose-cards/女频种田.md) | 古代种田 / 种田经商 / 带崽种田 | 高 |
| [职场婚恋](genre-prose-cards/职场婚恋.md) | 职场言情 / 都市婚恋 / 熟男熟女 | 高 |
| [科幻末世](genre-prose-cards/科幻末世.md) | 末世 / 灾变 / 废土 / 囤货末世 | 高 |
| [都市修真](genre-prose-cards/都市修真.md) | 都市修仙 / 都市仙尊 / 现代修真 | 高 |
| [历史古代](genre-prose-cards/历史古代.md) | 历史架空 / 古代权谋 / 朝堂 | 高 |
| [古言脑洞](genre-prose-cards/古言脑洞.md) | 古代言情脑洞 / 穿书古言 / 系统古言 | 高 |
| [女频悬疑](genre-prose-cards/女频悬疑.md) | 女性悬疑 / 悬疑言情 / 女主破案 | 高 |
| [宫斗宅斗](genre-prose-cards/宫斗宅斗.md) | 宫斗 / 宅斗 / 后宅 / 权谋古言 | 高 |
| [悬疑灵异](genre-prose-cards/悬疑灵异.md) | 灵异 / 惊悚 / 怪谈 / 民俗悬疑 | 高 |
| [抗战谍战](genre-prose-cards/抗战谍战.md) | 谍战 / 民国谍战 / 特工 | 高 |
| [星光璀璨](genre-prose-cards/星光璀璨.md) | 娱乐圈 / 文娱 / 影后 / 综艺 | 高 |
| [玄幻言情](genre-prose-cards/玄幻言情.md) | 女频玄幻 / 仙侠言情 / 神女 | 高 |
| [都市种田](genre-prose-cards/都市种田.md) | 经营日常 / 重生经营 / 乡村都市 | 高 |
## 中置信题材卡
| 题材卡 | 常见别名/匹配词 | 置信度 |
|---|---|---|
| [历史脑洞](genre-prose-cards/历史脑洞.md) | 历史天幕 / 历史系统 / 古代直播 / 工业历史 | 中 |
| [快穿](genre-prose-cards/快穿.md) | 快穿系统 / 炮灰逆袭 / 万人迷快穿 | 中 |
| [游戏体育](genre-prose-cards/游戏体育.md) | 网游 / 电竞 / 体育竞技 / 游戏文 | 中 |
| [青春甜宠](genre-prose-cards/青春甜宠.md) | 校园甜宠 / 校园恋爱 / 青春校园 | 中 |
| [现言脑洞](genre-prose-cards/现言脑洞.md) | 现代言情脑洞 / 女频系统 / 贵族学院脑洞 | 中 |
| [东方仙侠](genre-prose-cards/东方仙侠.md) | 仙侠 / 修仙 / 古典仙侠 | 中 |
| [悬疑脑洞](genre-prose-cards/悬疑脑洞.md) | 规则悬疑 / 系统悬疑 / 怪谈脑洞 | 中 |
| [西方奇幻](genre-prose-cards/西方奇幻.md) | 西幻 / 魔法 / 魔物 / 模拟器西幻 | 中 |
| [民国言情](genre-prose-cards/民国言情.md) | 民国虐恋 / 民国婚恋 / 军阀言情 | 中 |
## 低置信题材卡
当前无低置信单卡。新增低置信卡时,只能作为初稿方向;写作前必须优先读取同题材对标书、用户设定和最新扫榜结果。
---
## 低置信题材使用提示
低置信卡不能单独决定正文。写作前补三件事:
1. 同题材对标书的 `剧情/情绪模块.md` 与 `剧情/节奏.md`。
2. `设定/文风.md` 或对标 `文风.md`,确认句长、声线和段落节奏。
3. 本章细纲里的目标情绪、出场顺序、信息差和章尾钩子。
若三件事缺两件以上,只生成临时 `genre_prose_card` 并标注“低置信”,不要让题材卡压过细纲。
references/genre-prose-cards/东方仙侠.md›
---
genre: 东方仙侠
aliases: [东方仙侠, 仙侠, 修仙, 古典仙侠]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 东方仙侠正文提示卡
## 正文提示词
写东方仙侠时,把修行规则、身份位置、师门/宗门/皇权压力和个人选择写清楚。读者期待境界变化背后的选择和代价,不只是功法名词。每章至少有一个修炼、身份或局势层面的新进展。
## 开场抓手
从门规压力、师徒关系、试炼、劫难、宗门争端、皇权/妖魔压境、修行瓶颈切入。
## 冲突发动机
修行规矩 + 身份约束 + 道义/利益选择。战斗和修炼都要有规则限制和代价。
## 爽点与情绪释放
释放来自破境、悟道、守住重要关系、破局后身份提升、敌方重新评估。仙气服务选择,不替代冲突。
## 对话与声线
可比都市更克制,但不能空泛古风。师长、弟子、宗门对手、皇权人物要有身份分寸。
## 章尾钩子
适合用新试炼、师门秘密、境界异象、强敌拜山、规矩反噬、旧因果浮现收尾。
## 场景颗粒
优先落到山门、洞府、试炼台、命牌、剑痕、丹炉、符箓、妖气、诏令这些看得见的物件和场面。仙气不靠形容词堆,要让规矩、物件和人情债影响角色选择。
## 正文落点
开场落到门规、试炼、洞府异动或师徒命令;冲突落到境界瓶颈、宗门资格和道义选择;结尾落到命牌、剑痕、劫兆或强敌拜山。
## 前中后期打法
- 前期:先把主角放进门规、试炼或师徒命令里,让修炼资源和因果选择形成第一道压力。
- 中期:用宗门任务、劫难、同门站队和灵石丹药缺口反复卡住选择,每次破局都要改变名声或因果账。
- 后期:把个人突破推到宗门、道统或大劫层面,结尾用命牌、剑痕、天象或强敌拜山抬下一轮期待。
## 节奏密度
每章至少推进一条修行线、关系线或局势线。修炼章可以慢,但必须有瓶颈、试错、代价或外部压力,不写纯打坐说明。
## 本章取舍
若本章主打修行,就压缩世界观解释,放大瓶颈和代价;若主打宗门/皇权冲突,就让境界和法器服务场面变化,不抢人物选择。
## 禁止漂移
不要写成空泛古风散文;不要堆宗门设定;不要无代价开挂;不要让主角只被命运推着走。
## 证据摘要
样本说明:本地同题材长篇样本,可用 308 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 28.5 字,对话约占 22%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/传统玄幻.md›
---
genre: 传统玄幻
aliases: [传统玄幻, 玄幻, 东方玄幻, 仙侠玄幻通用]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 传统玄幻 / 仙侠玄幻通用正文提示卡
## 正文提示词
写传统玄幻时,正文核心是被看轻、资源、境界、敌人、突破和新地图。每章必须清楚主角当前位置、缺什么资源、敌人凭什么压他、这次行动得到什么收益或代价。
## 开场抓手
退婚羞辱、家族测试、宗门考核、资源被夺、秘境开启、强敌逼近都适合切入。
## 冲突发动机
境界压制 + 资源稀缺 + 身份位置。主角成长要一阶一阶见结果,突破要有代价和见证。
## 爽点与情绪释放
释放来自越级胜、资源到手、境界突破、身份翻转、新地图资格。每次爽点后留下更高层压力。
## 对话与声线
家族、宗门、反派、师长要有身份差,不要全员热血喊话。主角台词可以短硬,但要说出目标、判断或底线。
## 章尾钩子
适合用下一轮测试、秘境入口、仇人到场、资源暴露、长老态度变化、新地图资格收尾。章尾要抬高下一层压力。
## 场景颗粒
优先写演武场、测灵石、丹药、功法残页、妖兽尸体、宗门令牌、资源账、伤口和围观弟子。设定名词必须挂在具体收益或危险上。
## 正文落点
开场落到演武场、测试、资源被夺或秘境入口;冲突落到境界压制和资源缺口;结尾落到新试炼、秘境资格、仇人到场或长老改口。
## 前中后期打法
- 前期:用测试、资源被夺、家族羞辱或秘境资格压出被看轻的开局,先让读者看清升级缺口。
- 中期:围绕境界、丹药、榜单、擂台和秘境收益反复结算,打脸要和资源到账绑定。
- 后期:把仇怨、宗门利益和更高战力拉进同一场清算,结尾留强敌、秘境深层或长老改口。
## 节奏密度
前期节奏按五步循环:受压,试错,取证/得资源,小翻盘,更高压迫。突破和越级战之间要有准备过程,不能连续无成本升级。
## 本章取舍
修炼、资源、战斗三者每章选一个做主轴,其他只辅助。不要同时铺等级、地图、功法、血脉、势力,避免正文变设定表。
## 禁止漂移
不要空喊热血;不要堆等级表;不要无代价突破;不要只有打斗没有资源链和目标链。
## 证据摘要
样本说明:本地同题材长篇样本,可用 2430 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 24.0 字,对话约占 24%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/历史古代.md›
---
genre: 历史古代
aliases: [历史古代, 历史架空, 古代权谋, 朝堂]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 历史古代正文提示卡
## 正文提示词
写历史古代时,把身份、制度、权力和现实危险作为每个选择的限制。信息差可以制造爽点,但必须受时代身份、官职、家族、军政制度限制。
## 开场抓手
朝堂争执、家族危机、边关战事、案件审理、流放抄家、职位任命都适合切入。
## 冲突发动机
制度压力 + 身份限制 + 权力博弈。主角的聪明要通过可执行策略体现。
## 爽点与情绪释放
释放来自当众翻案、制度反用、权力站队、文书落定、敌人被自己规矩反噬。爽点要有凭据和场合,不能只靠主角嘴赢。
## 对话与声线
官员、军士、家族长辈、幕僚、百姓说话要分层。主角可以有现代思路,但表达要落回当时身份能说出口的话。
## 章尾钩子
用圣旨、公文、敌军消息、案情反转、盟友倒戈、家族新压力收尾。
## 场景颗粒
优先写官印、公文、军报、族谱、账册、路引、刑具、城门、驿站、朝堂座次和家族席位。权力变化要通过这些抓手被看见。
## 正文落点
开场落到公文、朝会、军报、家族席位或案件现场;冲突落到制度卡点和责任归属;结尾落到圣旨、公文落印、军情反转或敌方动作。
## 前中后期打法
- 前期:用公文、朝会、军报、家族席位或案件责任压主角入局,先交代制度阻力。
- 中期:让执行成本、官场站队、家族牵连和民生结果反复碰撞,破局必须留下账。
- 后期:把个人判断推到朝局、军情或法理结算,章尾用圣旨、军报、落印文书或敌方动作续压。
## 节奏密度
每章推进一个制度卡点或权力判断:谁有资格说话,谁承担责任,谁调动资源,谁被公开定性。慢章也要改变一项局势。
## 本章取舍
历史信息只写本章会用到的部分。权谋章压缩生活闲笔,生活章也要留一条制度或身份压力线。
## 禁止漂移
不要现代嘴替;不要纯爽不管制度;不要把历史写成换皮都市;不要无凭无据硬翻案。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1967 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 23.8 字,对话约占 31%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/历史脑洞.md›
---
genre: 历史脑洞
aliases: [历史脑洞, 历史天幕, 历史系统, 古代直播, 工业历史]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 历史脑洞正文提示卡
## 正文提示词
写历史脑洞时,把历史处境的危机感和主角带来的新变化放进同一场景。天幕、系统、工业、军政信息差、幼崽互动、忠烈翻盘都必须改变当下权力局面。读者期待古人被新信息击穿认知,并看到历史节点被撬动。
## 开场抓手
从战事、朝堂危机、抄家流放、天幕降临、关键人物误判、制度卡点切入。先写危机,再让新变化进入。
## 冲突发动机
历史制度约束 + 新知识/新技术 + 权力博弈。不能只靠主角会背历史,必须让信息差遇到执行成本。
## 爽点与情绪释放
释放来自古人态度变化、危局翻盘、忠奸立判、制度漏洞被利用、资源调动成功。震惊要有层次,别全员只会喊。
## 对话与声线
古人说话要有身份和分寸,皇帝、臣子、军士、百姓不能同一口吻。现代信息进入古代时要翻译成他们听得懂的利益与风险。
## 章尾钩子
适合用天幕下一条、圣旨变化、敌军动作、技术试验后果、历史人物提前站队收尾。
## 场景颗粒
天幕、榜单、工坊、军报、朝会、城墙、粮仓、学堂、驿站都是脑洞落地的场面。新知识必须被古人转化成资源、风险或命令。
## 正文落点
开场落到旧局势危机、朝堂误判或天幕/系统信息;冲突落到古人误读、权力争抢和执行成本;结尾落到下一条信息、技术试验或站队变化。
## 前中后期打法
- 前期:把天幕、系统、直播或技术信息抛进旧秩序,让古人误读和权力反应先炸开。
- 中期:用执行成本验证脑洞,不只展示知识;每次新信息都要让一派得利、一派恐慌。
- 后期:让制度、军政和钱粮承接前面的脑洞后果,结尾落到下一条信息或更高层站队。
## 节奏密度
每章按四步推进:旧局势压力,新信息进入,各方误读/争抢,局势偏移。震惊反应只占一小段,后果和站队才是主体。
## 本章取舍
科普、弹幕、系统提示都要压短,优先写古人如何理解和利用。若本章重技术,就少写朝堂群像;若重朝堂,就少铺技术细节。
## 禁止漂移
不要写成历史科普;不要忽略身份制度;不要让所有古人现代化;不要只写震惊不改变局势。
## 证据摘要
样本说明:本地同题材长篇样本,可用 621 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 27.0 字,对话约占 28%,系统/面板提示约 11%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/双男主.md›
---
genre: 双男主
aliases: [双男主, 双男主纯爱, BL, 纯爱, 耽美]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 双男主正文提示卡
## 正文提示词
写双男主时,关系张力要和外部事件一起推进。危险、误判、身份、占有欲、保护欲、同盟压力都能成为关系发动机。每章至少让两人的关系状态发生一点变化:试探限制、被迫合作、互相隐瞒、误会升级、公开维护、危险中选择对方。
## 开场抓手
- 优先从危险/异常、被迫同处、公开误会、手机消息、资源交换、师门/校园/职场围观切入。
- 两位主角一出场就要有差异:行动速度、说话方式、情绪露出方式不能相同。
- 糖点不要裸放,最好前面带一点风险或误判。
## 冲突发动机
外部压力逼近 + 两人目标不完全一致 + 彼此读错。关系线不能脱离主线,主线压力也不能吃掉关系反应。
## 爽点与情绪释放
释放来自“他本可以不管,但还是管了”“他嘴上否认,行动已经站队”“外人误判他们关系,结果被事实打脸”。甜要带克制,虐要给下一步安全感。
## 对话与声线
一个人可以冷、毒、端着,另一个人可以混、直、嘴欠、装乖,但不要脸谱化。对话允许答非所问、被动作打断、半句咽回去,重点是两人对同一压力的反应差异。
## 章尾钩子
适合用身份暴露、危险逼近、误会被第三方放大、其中一人替对方背锅、暧昧证据被围观收尾。钩子要让读者期待关系下一步变化。
## 场景颗粒
关系变化要落到手腕、外套、座位距离、聊天记录、挡刀站位、同住空间、公开称呼和第三方误会。不要只写眼神和心跳。
## 正文落点
开场落到同处压力、公开误会、危险或手机消息;冲突落到两人目标不一致和外人误判;结尾落到替对方承担后果、暧昧证据被看见或身份暴露。
## 前中后期打法
- 前期:用同处压力、公开误会、手机消息或危险场面把两人的目标差异推到台前。
- 中期:围绕替对方承担后果、限制试探、外人误判和关系证据做拉扯,不靠空泛暧昧。
- 后期:把私下偏袒推到公开选择,结尾留身份暴露、证据被看见或另一方反过来护短。
## 节奏密度
每章主线压力和关系压力至少各有一个小变化。高压章用行动推进感情,低压章也要埋一个外部代价或未说破的误会。
## 本章取舍
冲突和暧昧交替。若本章主线强,就用一个关键动作推进关系;若本章关系强,也要留下主线代价。
## 禁止漂移
不要把两位主角写成同一种腔;不要只靠外貌互夸;不要让关系线吞掉事件线;不要用工业撒糖代替选择;不要把攻受功能位写死。
## 证据摘要
样本说明:本地同题材长篇样本,可用 740 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 26.0 字,对话约占 30%,系统/面板提示约 14%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/古言脑洞.md›
---
genre: 古言脑洞
aliases: [古言脑洞, 古代言情脑洞, 穿书古言, 系统古言]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 古言脑洞正文提示卡
## 正文提示词
写古言脑洞时,用古代身份、家族规矩、宫廷/宅院秩序承接脑洞设定。系统、穿越、读心、身份错位必须改变女主当下处境和权力关系。
## 开场抓手
赐婚退婚、家宴审问、宫门/后宅规矩、穿书醒来、系统任务、身份被揭穿都适合切入。
## 冲突发动机
古代规矩 + 女主新认知/新设定 + 家族权力关系。脑洞要服务女主选择。
## 爽点与情绪释放
释放来自女主用新认知避坑、反用规矩、让恶意者当众失算、把婚约/身份/家族资源握回手里。脑洞设定要见结果到关系和名声变化。
## 对话与声线
女主可以清醒,但不能满口现代互联网腔。长辈、丫鬟、贵女、皇族要有身份差,试探比直白宣战更常用。
## 章尾钩子
用规矩惩罚、婚约变化、宫中传召、系统限制、身份漏洞、物证出现收尾。
## 场景颗粒
用请安、家宴、宫门、帕子、账册、婚书、药碗、丫鬟传话、赏罚、车马座次承接脑洞。系统/读心只做压力,不替代场面。
## 正文落点
开场落到请安、赐婚、家宴、系统提示或穿书醒来;冲突落到古代规矩承接新设定;结尾落到婚约变化、宫中传召、系统限制或物证出现。
## 前中后期打法
- 前期:从请安、赐婚、家宴、穿书醒来或系统限制切入,让古代规矩先压住新设定。
- 中期:每次脑洞落地都要改变名分、婚约、站队或家宅账目,不能只刷任务提示。
- 后期:把系统限制、宫中传召和婚产/家族后果合并结算,钩子落在规矩反噬或物证出现。
## 节奏密度
每章至少改变一个关系位置、名分风险或规矩后果。脑洞信息出现后,立刻带出选择,别连续解释设定。
## 本章取舍
本章若重脑洞,就只抓一个古代规矩承接;若重宅斗/宫斗,就让脑洞隐藏在判断里,不把提示写成主角外挂说明书。
## 禁止漂移
不要现代吐槽冲毁古言质感;不要让系统压过人物选择;不要只写概念不写礼法成本。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1406 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 31.0 字,对话约占 29%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/古风世情.md›
---
genre: 古风世情
aliases: [古风世情, 古代世情, 古风家宅, 古代婚恋世情]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 古风世情正文提示卡
## 正文提示词
写古风世情时,把礼法、家族面子、婚姻名分、人情账和物证写成冲突核心。爽点来自主角在规矩里抓住把柄、翻转名声或让恶人自食其果。
## 开场抓手
婚约变故、家宴发难、亲戚争产、账册物证、族老公堂、邻里流言都适合切入。
## 冲突发动机
名分规矩 + 家族利益 + 人证物证。主角不能只靠嘴硬,要拿得出能改变场面的证据或策略。
## 爽点与情绪释放
释放来自证据摆出、长辈改口、婚约/产业/名声变化、恶人被人情账反咬。情绪不靠大喊,靠场内位置和众人态度变化。
## 对话与声线
亲戚说话多绕弯、长辈重面子、晚辈要顾名分。主角可以锋利,但要借规矩、证据、人情说话。
## 章尾钩子
用新物证、长辈召见、婚约变化、族中判罚、恶人反咬收尾。
## 场景颗粒
抓家宴席位、族谱、婚书、账册、库房钥匙、邻里传话、祠堂、公堂、聘礼嫁妆。世情味来自办事流程和人情往来。
## 正文落点
开场落到家宴席位、账册、婚书、库房钥匙或邻里流言;冲突落到名分、人情账和证据;结尾落到新物证、长辈召见或婚产判定变化。
## 前中后期打法
- 前期:用家宴席位、账册、婚书、库房钥匙或邻里流言立住名分和人情账。
- 中期:让证据、长辈态度、亲戚算盘和钱产分配反复拉扯,每个小场都要改变关系位置。
- 后期:把婚产、名声、宗族和官面结果推到一处结算,结尾用新物证或长辈召见续局。
## 节奏密度
每章推进一笔人情账、名声账或财产账。低压章也要让一个人重新站队,或让一件物证改变后续局面。
## 本章取舍
少写泛古风氛围,多写谁占规矩、谁占证据、谁占人心。若本章重感情,就让感情受名分和家族利益约束。
## 禁止漂移
不要只写辞藻;不要现代价值观硬喊口号;不要无证据硬撕;不要让规矩只约束反派不约束主角。
## 证据摘要
样本说明:本地同题材长篇样本,可用 2460 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 30.0 字,对话约占 29%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/女频悬疑.md›
---
genre: 女频悬疑
aliases: [女频悬疑, 女性悬疑, 悬疑言情, 女主破案]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 女频悬疑正文提示卡
## 正文提示词
写女频悬疑时,把案件/异常和女主关系网绑在一起。线索推进的同时,女主被信任、被误解、被保护或被排斥的状态也要变化。
## 开场抓手
案件现场、陌生来电、旧案重启、亲友异常、职场/警方质疑、危险靠近都适合切入。
## 冲突发动机
案件压力 + 女性处境/关系压力 + 信息差。破案之外,女主的位置也要被改变。
## 爽点与情绪释放
释放来自女主发现别人忽略的细节、摆脱误解、反向试探成功、让亲近者或权威重新评估她。破案爽和关系爽要互相咬合。
## 对话与声线
女主问话要带策略,嫌疑人会闪躲、反问、装无辜。搭档或男主不能替她全程解释,最多提供资源或压力。
## 章尾钩子
用新线索、嫌疑人反转、亲近者涉案、女主被盯上、旧案物证出现收尾。
## 场景颗粒
用现场痕迹、监控、聊天记录、旧物、气味、药瓶、病历、报案记录、亲友反常举动承载线索。线索要能被角色接触和误读。
## 正文落点
开场落到案件现场、陌生来电、亲友异常或旧案物证;冲突落到线索误读和女主关系网压力;结尾落到新线索、嫌疑人反转或亲近者涉案。
## 前中后期打法
- 前期:用案件现场、陌生来电、亲友异常或旧物证引女主入局,危险要贴近关系网。
- 中期:让线索误读、情感压力和嫌疑人反转互相牵制,解一个小真相就暴露一个更近的人。
- 后期:把旧案、亲近者和新证据合成公开风险,结尾落到嫌疑身份翻转或女主被盯上。
## 节奏密度
每章至少给一个新线索和一个新误导,并改变女主在关系网中的安全程度。不要连续只堆谜面不改变处境。
## 本章取舍
案件章少写恋爱解释,关系章也要让线索推进一点。恐惧和情感都要落在女主当前可感知的信息上。
## 禁止漂移
不要只破案不写关系压力;不要靠上帝视角讲真相;不要把女主写成被男主全程带飞。
## 证据摘要
样本说明:本地同题材长篇样本,可用 134 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 36.0 字,对话约占 30%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/女频种田.md›
---
genre: 女频种田
aliases: [女频种田, 古代种田, 种田经商, 带崽种田]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 女频种田正文提示卡
## 正文提示词
写女频种田时,把女主从低资源状态一步步经营出安全感:吃穿住、田地/门店、亲友关系、孩子/婚恋、极品亲戚和钱。每章至少推进一个生活资源或关系位置。
## 开场抓手
分家、断粮、孩子生病、门店亏损、亲戚压迫、第一笔买卖、邻里评价都适合切入。
## 冲突发动机
低资源起点 + 家庭/邻里压力 + 经营机会。女主要靠判断、手艺、人情和小规模资源滚动变好。
## 爽点与情绪释放
释放来自饭吃饱、钱到账、口碑改善、亲友站队、极品吃瘪、孩子/家人安全感增加。
## 对话与声线
家人、邻里、买主、极品亲戚说话要带生活账和小算盘。女主可以温和,也要有限制和办法。
## 章尾钩子
适合用新订单、分家结果、孩子/家人态度变化、极品反扑、钱粮缺口、下一次赶集或开张收尾。
## 场景颗粒
多用灶台、粮袋、菜地、账本、铜钱、门店、赶集、布料、药钱、孩子衣食、邻居眼神。经营成果要让人摸得到、吃得到、算得清。
## 正文落点
开场落到断粮、分家、药钱、赶集或门店亏损;冲突落到钱粮缺口和邻里亲戚小算盘;结尾落到新订单、分家结果、孩子态度或极品反扑。
## 前中后期打法
- 前期:从断粮、药钱、分家、赶集、孩子或门店亏损切入,让生计缺口可见。
- 中期:围绕订单、邻里口碑、亲戚小算盘和钱粮周转推进,每章必须有一笔具体收益或损失。
- 后期:把家业、亲情站队和村镇规矩合并清算,钩子落在新订单、分家结果或极品反扑。
## 节奏密度
每章推进一个资源小台阶:吃饱、赚一笔、修一处、买一样、得一个人情。慢章也要有生活改善或关系稳固。
## 本章取舍
不要把经营过程跳成结果清单。若本章重赚钱,就少铺感情解释;若重家人关系,也要让钱粮或口碑有一点变化。
## 禁止漂移
不要只写物资清单;不要女主全靠外挂;不要经营线和感情线脱节;不要突然宫斗争霸。
## 证据摘要
样本说明:本地同题材长篇样本,可用 426 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 33.5 字,对话约占 28%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/宫斗宅斗.md›
---
genre: 宫斗宅斗
aliases: [宫斗宅斗, 宫斗, 宅斗, 后宅, 权谋古言]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 宫斗宅斗正文提示卡
## 正文提示词
写宫斗宅斗时,把规矩、名分、资源、子嗣、长辈态度和院内舆论写成战场。女主每次行动都要改变一点位分、话语权、人心账或资源归属。
## 开场抓手
晨昏定省、家宴、请安、账册、药膳、丫鬟背叛、长辈发难、名分被压都适合切入。
## 冲突发动机
礼法规矩 + 后宅资源 + 人证物证。斗争要有证据、场合和代价。
## 爽点与情绪释放
释放来自证据坐实、赏罚落定、长辈偏向改变、下人换主、院内资源转移。宅斗爽点要让规矩承认结果。
## 对话与声线
长辈重体面,妾室/姐妹多试探,下人看风向。女主说话可软可硬,但要知道场合和名分。
## 章尾钩子
用新物证、长辈态度变化、院内流言、赏罚结果、宫中/族中传话收尾。
## 场景颗粒
抓请安座次、茶盏、药膳、账册、库房钥匙、丫鬟口供、赏赐、祠堂、院门和传话。权力变化通过内宅秩序体现。
## 正文落点
开场落到请安、赏罚、家宴、宫门传召或下人传话;冲突落到名分、规矩、证词和站队;结尾落到一道旨意、一件物证或后宅位置变化。
## 前中后期打法
- 前期:用请安、赏罚、家宴、宫门传召或下人传话立住规矩和位置。
- 中期:围绕证词、赏罚、站队、名分和下人链条推进,暗斗要落到可验证物证。
- 后期:把规矩、旨意和位置变化推到明面上见结果,章尾用一道旨意、一件物证或某人失宠续压。
## 节奏密度
每章推进一个规矩回合:发难、取证、站队、赏罚、余波。不要连续吵架,必须让资源或人心有可见变化。
## 本章取舍
宫斗章可扩大到皇权,宅斗章守住院内和家族范围。不要为了爽点让女主无视礼法成本。
## 禁止漂移
不要只写古风辞藻;不要所有人低智争吵;不要忽略规矩成本;不要无证据硬撕。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1626 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 29.8 字,对话约占 29%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/年代.md›
---
genre: 年代
aliases: [年代, 年代文, 七零, 八零, 随军, 重生年代]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 年代正文提示卡
## 正文提示词
写年代文时,情绪要落在家庭、婚恋、户口、工作、票据、住房、随军、亲戚和人情压力上。读者期待主角在旧秩序里改命、治极品、挣安全感。年代感靠称呼、物件、办事流程和人情账自然出现,不靠大段历史介绍。
## 开场抓手
- 用分家、相亲/婚约、下乡返城、随军、票据粮食、工作名额、亲戚欺负、旧伤委屈切入。
- 第一场要让读者知道主角缺什么:钱、名声、住处、婚姻自主、孩子安全或工作机会。
- 若有重生/空间/系统,先服务眼前生活账。
## 冲突发动机
时代规则 + 家庭人情账 + 主角改命意志。压迫可以慢半拍,但每章要推动一个现实账或关系账。
## 爽点与情绪释放
释放方式是当场还回去、名声扭转、资源到手、长辈/组织态度变化、家庭位置改变。爽点要符合时代流程,别像现代网暴打脸。
## 对话与声线
称呼和分寸很重要。长辈、邻里、干部、军人、亲戚说话方式要不同。现代网络梗慎用,主角可以清醒,但不能像现代嘴替乱冲制度。
## 章尾钩子
适合用亲戚上门、干部通知、婚约变化、工作名额、票据/物证出现、旧人重逢收尾。
## 场景颗粒
多写粮票、布票、介绍信、搪瓷缸、供销社、筒子楼、家属院、炕桌、缝纫机、工作名额和亲戚饭桌。年代感来自物件和办事流程。
## 正文落点
开场落到票证、粮食、工位、知青点、家属院或婚姻安排;冲突落到资源短缺和熟人社会评价;结尾落到分配结果、调令、票证缺口或亲友站队。
## 前中后期打法
- 前期:用票证、粮食、工位、知青点、家属院或婚姻安排压出现实缺口。
- 中期:让熟人社会评价、钱粮周转、工位名额和亲友站队反复卡主角,收益要朴素可见。
- 后期:把分配、调令、家属关系和时代机会合并结算,结尾落到新指标、新票证或亲友选择。
## 节奏密度
每章至少解决或加重一个现实账:钱票、住处、工作、婚姻、名声、孩子安全。低压生活章也要让日子往好或往坏挪一步。
## 本章取舍
年代物件只挑能推进冲突的写。金手指低调服务改命,主角要主动经营关系、资源和名声。
## 禁止漂移
不要用现代网感冲掉年代感;不要堆物件清单;不要让金手指替主角做人情账;不要只写极品吵架不推进现实收益。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1222 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 27.0 字,对话约占 33%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/快穿.md›
---
genre: 快穿
aliases: [快穿, 快穿系统, 万人迷快穿, 炮灰逆袭]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 快穿正文提示卡
## 正文提示词
写快穿时,每个世界一开场就要有明确身份、关系压力和任务缺口。开局少解释系统,直接把主角丢进前任、白莲、男主、家人、合同、名声或危险场面里。爽点来自跨世界经验改写原剧情,并让原角色反应失衡。
## 开场抓手
用醒来即修罗场、退婚/分手/审判、任务失败警告、原主记忆冲击、关键剧情前一分钟切入。
## 冲突发动机
原剧情压力 + 系统任务限制 + 当前世界人物情绪。主角知道剧情不等于躺赢,每次改写都要引发新后果。
## 爽点与情绪释放
打脸白莲、改写炮灰命运、男主/反派态度偏移、名声反转、任务进度变化。系统反馈服务关系变化,不抢正文。
## 对话与声线
主角可以清醒、毒舌、装乖或反讽,但要符合当前身份。当前世界人物要像活人,不只为任务进度服务。
## 章尾钩子
适合用任务进度异常、原剧情提前、关键人物黑化/偏爱、下个惩罚条件、身份漏洞暴露收尾。
## 场景颗粒
每个世界先给身份牌、关系牌、任务牌和眼前麻烦,不急着铺完整世界观。系统面板只保留目标、限制、风险。
## 正文落点
开场落到原身困局、系统任务、剧情节点或关系审判;冲突落到人设限制和任务代价;结尾落到任务进度、角色态度偏移或小世界新规则。
## 前中后期打法
- 前期:先落原身困局、系统任务和剧情节点,让读者知道人设限制和改命目标。
- 中期:围绕任务进度、角色态度偏移和小世界规则反噬推进,每次破局都要改一个原后果。
- 后期:快速结算情感债、任务奖励和世界后果,章尾留新世界规则或上个世界余波。
## 节奏密度
单世界开局要快:身份落地、原主困境、任务压力、第一次反击尽量在前半章完成。世界中后段再放大情感和代价。
## 本章取舍
任务、关系、打脸每章选一个主轴。不要连续写系统解释,也不要让主角只靠上帝视角碾压原住民。
## 禁止漂移
不要每个世界开头模板化报剧情;不要让主角只靠知道原文躺赢;不要系统吐槽客服化过度;不要忘记当前世界的情绪重量。
## 证据摘要
样本说明:本地同题材长篇样本,可用 141 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 27.0 字,对话约占 21%,系统/面板提示约 14%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/悬疑灵异.md›
---
genre: 悬疑灵异
aliases: [悬疑灵异, 灵异, 惊悚, 怪谈, 民俗悬疑]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 悬疑灵异正文提示卡
## 正文提示词
写悬疑灵异时,先让角色碰到解释不了的事,再用职业、规则、物件或关系压力逼他继续查。恐惧来自有限视角和代价升级,别让怪物一出场就把规则讲满。
## 开场抓手
夜间异常、门店/案源、旧物件、亲友求助、规则纸条、职业现场都适合切入。
## 冲突发动机
未知现象 + 角色不得不查 + 代价逐步靠近。线索要有物件承载。
## 爽点与情绪释放
释放来自规则被摸清一点、角色躲过一次代价、找到关键物件、反过来利用怪异限制。爽点可以小,但要让恐惧变得更具体。
## 对话与声线
害怕的人会重复、否认、岔开话题;懂行的人也不能一次讲透规则。对话要保留信息缺口。
## 章尾钩子
用规则被破坏、物件变化、下一位受害者、亲近者卷入、职业身份暴露收尾。
## 场景颗粒
用门牌、钟声、照片、香灰、血迹、录音、手机电量、民俗器物、旧楼道、村规和夜路承载异常。怪异规则要有可观察限制。
## 正文落点
开场落到怪事现场、失踪、旧物、门禁或监控;冲突落到可验证线索和危险逼近;结尾落到新规则、死者信息、异常物证或主角被盯上。
## 前中后期打法
- 前期:用怪事现场、失踪、旧物、门禁或监控抛出可验证异常,不先解释规则。
- 中期:让调查、试探、误判和危险逼近反复推进,线索必须靠角色动作拿到。
- 后期:把死者信息、民俗规则和主角处境合成新危险,结尾落到异常物证或主角被盯上。
## 节奏密度
每章按这个顺序推进:异常出现,试探规则,付出小代价,得到一条更危险的信息。不能只吓人不推进规则。
## 本章取舍
恐怖氛围和解谜信息不能互相挤掉。若本章重惊吓,就用一个清晰线索收束;若重解谜,就保留一个未解释危险。
## 禁止漂移
不要只吓人不推进问题;不要怪物出场太早太满;不要用长篇设定解释恐惧。
## 证据摘要
样本说明:本地同题材长篇样本,可用 460 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 29.5 字,对话约占 31%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/悬疑脑洞.md›
---
genre: 悬疑脑洞
aliases: [悬疑脑洞, 规则悬疑, 系统悬疑, 怪谈脑洞]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 悬疑脑洞正文提示卡
## 正文提示词
写悬疑脑洞时,先给异常和代价,再让系统、规则、身份或关系信息一点点逼近真相。读者要的是未知变贵、危险变近;单纯藏答案撑不住一章。每章一个核心问题,结尾让问题更具体、更危险或牵出更亲近的人。
## 开场抓手
从异常现场、规则提示、失踪/死亡、身份错位、手机线索、亲近关系异常切入。
## 冲突发动机
有限视角 + 规则代价 + 角色误判。线索自然混在行动中,别用作者旁白讲谜底。
## 爽点与情绪释放
悬疑爽点来自小真相解开、错误判断被纠正、代价被暂时避开、危险对象缩小。每次解答要带来更尖的新问题。
## 对话与声线
对话不必完整正确,可以答非所问、试探、隐瞒、突然中断。人物越害怕,越不要长篇解释世界观。
## 章尾钩子
适合用规则新增、死者/失踪者消息、亲近者异常、监控/手机证据、主角身份被点破收尾。
## 场景颗粒
规则、系统、怪谈要落在公告、门禁、手机、监控、病历、契约、直播、身份档案等现实场面里。抽象异常必须有可验证的现象。
## 正文落点
开场落到规则提示、异常现场、手机线索或亲近关系异常;冲突落到规则代价和角色误判;结尾落到规则新增、身份被点破或更亲近的人卷入。
## 前中后期打法
- 前期:先给规则提示、异常现场、手机线索或亲近关系异常,让代价立刻可感。
- 中期:围绕规则验证、角色误判和亲友卷入推进,解答必须带来更具体的新问题。
- 后期:把规则限制、身份档案和亲近者异常合并,结尾用规则新增或身份被点破续压。
## 节奏密度
每章围绕一个核心问题推进:提出、试探、付代价、得到更危险答案。脑洞设定不要一次讲满,随角色验证展开。
## 本章取舍
若本章主打规则,就压缩人物背景;若主打人物关系,就让规则通过关系伤害或保护某个人。
## 禁止漂移
不要靠晦涩制造悬疑;不要每章塞新怪谈不回收;不要上帝视角解释真相;不要让系统把谜面讲完。
## 证据摘要
样本说明:本地同题材长篇样本,可用 215 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 28.0 字,对话约占 25%,系统/面板提示约 18%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/战神赘婿.md›
---
genre: 战神赘婿
aliases: [战神赘婿, 赘婿, 战神回归, 隐藏身份]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 战神赘婿正文提示卡
## 正文提示词
写战神赘婿时,围绕被看轻的身份、羞辱、隐忍理由、身份/实力反转和当众打脸运转。每章先给具体压迫,再给主角一个可以忍或不忍的选择,最后见结果身份、资源或实力差距。
## 开场抓手
家族羞辱、妻子受委屈、合同被抢、宴会公开贬低、危急救场、旧部找上门都适合切入。
## 冲突发动机
赘婿被看轻 + 隐藏身份 + 见证者围观。隐忍必须有理由:保护关系、查幕后、顾及承诺或等待时机。
## 爽点与情绪释放
释放来自当众反转、旧部称呼、资源到场、恶人失算、妻子/家族态度变化。见证者必须在场。
## 对话与声线
家族反派可以尖酸,但要有利益诉求;妻子/亲密对象要有自己的判断,不只负责被救。主角台词少解释身份,多用承诺、反问和行动压场。
## 章尾钩子
适合用旧部现身、身份线索暴露、妻子态度变化、反派搬更大靠山、下一场公开场合收尾。
## 场景颗粒
常用宴会、合同、公司门口、医院、家族饭桌、豪车/车牌、旧部称呼、转账记录、邀请函。反转必须有见证者和证据。
## 正文落点
开场落到家族饭桌、宴会、合同、医院或旧部上门;冲突落到被看轻的处境和隐忍理由;结尾落到旧部称呼、资源到场、妻子态度变化或更大靠山。
## 前中后期打法
- 前期:用家族饭桌、医院、宴会、合同或旧部上门制造被看轻的处境,同时给隐忍理由。
- 中期:让危险、靠山、资源和妻子态度轮流变动,打脸必须分层,不要一次亮完身份。
- 后期:把旧部称呼、资源到场和更大靠山推成公开清算,结尾回到妻子或家族关系变化。
## 节奏密度
每章先给具体压迫,再给隐忍理由,最后至少见结果一个身份、资源或实力差距。不能连续多章只受辱不回击。
## 本章取舍
如果要隐忍,必须写清保护谁、查什么或等什么。妻子线、家族线、敌人线每章选一条主压迫线,避免反派群骂。
## 禁止漂移
不要只让反派无脑骂;不要主角无理由隐忍;不要反转没有证据和见证;不要把妻子写成纯奖品。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1404 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 25.0 字,对话约占 31%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/抗战谍战.md›
---
genre: 抗战谍战
aliases: [抗战谍战, 谍战, 民国谍战, 特工]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 抗战谍战正文提示卡
## 正文提示词
写抗战谍战时,把身份伪装、行动目标、情报落点、组织压力和生死代价写清楚。每章至少推进一条情报线或暴露风险。
## 开场抓手
审讯、手术室/医院、接头、搜查、文件转移、叛徒线索、上级命令都适合切入。
## 冲突发动机
行动目标 + 身份风险 + 敌我信息差。情报不能靠旁白发放,要让主角从场内线索里摸出来。每次行动都要有时间、地点、接头物和撤离风险。
## 爽点与情绪释放
释放来自情报判准、身份掩护成功、敌方误判、同志脱险、行动完成但留下新风险。爽点要带生死代价。
## 对话与声线
谍战对话要有试探、暗号、停顿和双关。不同阵营说话方式不同,不能让角色把秘密直接说给读者听。
## 章尾钩子
用监视升级、接头地点变化、叛徒线索、新命令、身份漏洞暴露收尾。
## 场景颗粒
用证件、暗号、报纸、胶卷、电台、烟盒、车站、审讯室、宪兵巡查、接头地点承载信息。情报必须有传递路径。
## 正文落点
开场落到审查、接头、搜查、军令或密电;冲突落到身份伪装、情报真假和组织纪律;结尾落到暗号失效、名单暴露、追捕升级或上级新命令。
## 前中后期打法
- 前期:用审查、接头、搜查、军令或密电把身份伪装压紧,目标必须明确。
- 中期:围绕情报真假、暗号、组织纪律和追捕升级推进,每次过关都要留下新风险。
- 后期:把名单、上级命令和敌方搜捕合并引爆,章尾用暗号失效或身份暴露边缘续压。
## 节奏密度
每章推进一个行动节点:接头、取证、转移、掩护、审讯、撤离。结尾通常抬高暴露风险或引出新命令。
## 本章取舍
动作戏服务情报目标,系统/装备若存在也只解决眼前卡点。枪战、追车、爆破都要回到名单、密电、身份掩护或同志撤离,不要写成单纯军火爽文。
## 禁止漂移
不要写成纯爽战斗;不要让情报靠旁白发放;不要忽略身份暴露代价;不要把历史危险写轻。
## 证据摘要
样本说明:本地同题材长篇样本,可用 105 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 29.8 字,对话约占 31%,系统/面板提示约 15%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/星光璀璨.md›
---
genre: 星光璀璨
aliases: [星光璀璨, 娱乐圈, 文娱, 影后, 综艺]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 星光璀璨 / 文娱娱乐圈正文提示卡
## 正文提示词
写星光璀璨/娱乐圈时,让才华、舆论、资源、镜头和公开评价构成爽点链。正文按“被质疑、展示、反响、资源变化”推进,能力必须通过舞台、考试、直播、热搜、剧组或业内评价看见。
## 开场抓手
高考/试镜/节目开录、黑热搜、合约争议、对家挑衅、镜头事故、公开问答都适合切入。
## 冲突发动机
公开评价 + 资源竞争 + 才华被看见。主角要拿出具体作品或操作,别只让网友震惊。
## 爽点与情绪释放
释放来自舞台表现、镜头反应、热搜反转、业内评价、资源升级、黑粉失算。才华必须通过公开场面被看见。
## 对话与声线
经纪人重资源,导演/制片重利益,粉丝/网友情绪化,艺人台词要有镜头感和自保意识。别让所有人像营销号。
## 章尾钩子
用热搜发酵、下一轮节目、业内邀约、合同变化、对家反击、家人/身份公开收尾。
## 场景颗粒
用直播间、热搜截图、试镜房、录音棚、舞台灯、通告单、合同、粉丝评论、剧组现场承载娱乐圈反馈。
## 正文落点
开场落到试镜、热搜、合同、综艺现场或经纪人催促;冲突落到公众评价和职业资源争夺;结尾落到新通告、偷拍视频、榜单变化或角色邀约。
## 前中后期打法
- 前期:用试镜、热搜、合同、综艺现场或经纪人催促压出职业低谷和舆论误判。
- 中期:让作品机会、公众评价、粉丝反馈和对手操作反复变化,爽点落在资源转向和能力被看见。
- 后期:把榜单、奖项、偷拍视频或角色邀约放到明面上见结果,结尾留新通告或更大舆论风险。
## 节奏密度
每章至少推进两环:被质疑,展示,反响,资源变化。爽点之后要给资源后果,不只写全网震惊。
## 本章取舍
事业线和感情线不要互相吞。若本章重舞台,就少写舆论解释;若重舆论,就让一个具体资源或关系变化落地。
## 禁止漂移
不要只写网友震惊;不要才华展示没有具体内容;不要忽略经纪资源和舆论后果;不要把娱乐圈写成校园换皮。
## 证据摘要
样本说明:本地同题材长篇样本,可用 343 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 31.8 字,对话约占 28%,系统/面板提示约 11%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/民国言情.md›
---
genre: 民国言情
aliases: [民国言情, 民国虐恋, 民国婚恋, 军阀言情]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 民国言情正文提示卡
## 正文提示词
写民国言情时,把时代动荡、家族门第、婚约、身份危险和情感选择绑在一起。甜虐都要落到旧式礼法、报馆/商会/军政、车站码头、信件物证等具体抓手。
## 开场抓手
婚约变故、车站分别、报纸登载、商会冲突、军政搜查、家族逼迫、旧信物出现都适合切入。
## 冲突发动机
时代风险 + 门第/身份压力 + 情感承诺。爱情不能脱离局势,局势也要改变关系选择。
## 爽点与情绪释放
释放来自公开维护、逃过搜查、信物证明、家族态度松动、危险中选择对方。爱意要落在谁冒险递信、谁替谁担名声、谁在搜查前把人送走,别只写“乱世深情”。
## 对话与声线
军政人物说话带试探和压迫,商会/家族重面子和利益,男女主之间少直白告白,多用信物、称呼和选择表达。
## 章尾钩子
用新报纸消息、搜查逼近、车票/信件、婚约变化、身份暴露风险收尾。
## 场景颗粒
常用报纸、电报、车票、码头、舞厅、照相馆、商会账册、军车、旧宅、旗袍和信物。时代质感必须影响行动成本。
## 正文落点
开场落到舞会、报馆、军令、商会账目或家族婚约;冲突落到乱世权力、门第和情感安全;结尾落到军阀命令、报纸消息、车站离别或婚约变动。
## 前中后期打法
- 前期:用舞会、报馆、军令、商会账目或家族婚约立住乱世和门第压力。
- 中期:让情感安全、权力站队、报纸消息和家族利益互相挤压,甜虐都要落在具体选择。
- 后期:把军阀命令、婚约变动和离别/重逢推到结算,章尾用车站、报纸或密令续钩。
## 节奏密度
每章至少推进一个局势风险或关系承诺。甜虐都要被时代、家族、军政压力打断或加码。
## 本章取舍
氛围描写只留能改变关系或危险的物件。若本章重爱情,就让局势逼选择;若重局势,就留下情感代价。舞厅、旗袍、报纸这些只能服务婚约、搜查、商会账或离别。
## 禁止漂移
不要现代偶像剧换旗袍;不要只写氛围不推进局势;不要忽略时代危险和身份成本。
## 证据摘要
样本说明:本地同题材长篇样本,可用 54 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 29.0 字,对话约占 29%,系统/面板提示约 10%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/游戏体育.md›
---
genre: 游戏体育
aliases: [游戏体育, 网游, 电竞, 体育竞技, 游戏文]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 游戏体育正文提示卡
## 正文提示词
写游戏体育时,把赛制、数值、赛局和公开反馈写成爽点落点。目标要清楚,反馈要快,反向操作要能让旁人看见。排行榜、技能、队友、直播论坛、班级赛场、副本都要服务本章胜负。
## 开场抓手
从比赛/副本临场、队友质疑、天赋检测、榜单变化、直播事故、战术选择前切入。
## 冲突发动机
明确胜负目标 + 限制条件 + 旁人误判。赛制说明要短,马上进入操作过程。
## 爽点与情绪释放
爽点来自反常规打法、临场判断、极限翻盘、榜单跃迁、队友态度转变。写“怎么赢”,不只写技能名和结果。
## 对话与声线
队友、解说、观众、对手说话要分层。弹幕/论坛可以用,但别让网友替正文完成全部反馈。队友看配合,对手看破绽,解说看赛点,观众看爽感。
## 章尾钩子
适合用奖励结算、下一场强敌、榜单异常、战队邀请、隐藏规则开启收尾。
## 场景颗粒
用比分、排名、技能冷却、装备掉落、赛场灯牌、直播弹幕、队友耳麦、训练表、论坛帖子做反馈。数值要影响胜负取舍。
## 正文落点
开场落到比赛临场、副本开门、榜单刷新或队友质疑;冲突落到规则限制、操作选择和旁人误判;结尾落到结算奖励、下一场强敌、战队邀请或隐藏规则开启。
## 前中后期打法
- 前期:用比赛临场、副本开门、榜单刷新或队友质疑立目标和胜负规则。
- 中期:围绕操作选择、训练收益、队伍合约和直播/榜单反馈推进,规则说明只保留影响胜负的部分。
- 后期:把排名、奖励、战队邀请和下一场强敌一起结算,结尾落到隐藏规则或更高赛点。
## 节奏密度
每章至少有一个目标、一次操作/训练、一个反馈。比赛章快,训练章也要给可量化进步或关系变化。
## 本章取舍
赛制说明只写本章胜负要用的部分。团队关系、技术成长、公开评价三者每章选一项做重点。训练章也要有比分、排名、冷却、失误次数或队友态度变化。
## 禁止漂移
不要写成数值表;不要只有技能名没有操作;不要让队友和观众反应同质化;不要把比赛胜负写成纯旁白宣布。
## 证据摘要
样本说明:本地同题材长篇样本,可用 179 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 31.2 字,对话约占 19%,系统/面板提示约 35%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/玄幻脑洞.md›
---
genre: 玄幻脑洞
aliases: [玄幻脑洞, 玄幻系统, 反套路玄幻, 多子多福, 词条玄幻]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 玄幻脑洞正文提示卡
## 正文提示词
写玄幻脑洞时,先立一个反常规核心规则,再让它立刻改变修炼、宗门、身份、血脉或生死压力。读者期待的是玄幻规则被脑洞重写:系统、词条、召唤、多子多福、读书变强都要服务升级、资源和公开震惊。
## 开场抓手
- 用废柴身份、宗门危机、退婚羞辱、敌人上门、血脉检测、系统规则觉醒切入。
- 核心规则一句话能讲明白,第二个节拍就要见结果。
- 规则越离谱,限制越要清楚。
## 冲突发动机
旧修炼秩序 + 反常规规则 + 公开见证。别人按境界、血脉、宗门地位判断,主角用新规则改写结果。
## 爽点与情绪释放
小爽是规则第一次生效,中爽是境界/资源到账,大爽是长老、敌人、宗门公开改口。升级、收获、装逼要分层,不要一章全倒完。
## 对话与声线
玄幻角色可以更有仪式感,但台词仍要围绕利益、身份和危险。系统提示要短,宗门人物别全员喊震惊。
## 章尾钩子
适合用规则新限制、强敌登门、宗门任务、榜单排名、隐藏血脉/词条刷新、系统奖励异常收尾。
## 场景颗粒
脑洞规则要落到灵根、词条、系统面板、召唤物、族谱、宗门榜、丹药、擂台、秘境入口。反常规必须有旁人能看见的结果。
## 正文落点
开场落到废柴测试、宗门危机、血脉检测或系统觉醒;冲突落到旧修炼秩序被反常规规则撬动;结尾落到词条刷新、榜单排名、强敌登门或奖励异常。
## 前中后期打法
- 前期:用废柴测试、宗门危机、血脉检测或系统觉醒让反常规规则第一次落地。
- 中期:围绕旧修炼秩序、宗门资格、资源分配和公开误判反复升级,脑洞必须带来收益或代价。
- 后期:把词条、榜单、强敌和规则限制推到公开清算,结尾留奖励异常或更高层发现偏差。
## 节奏密度
每章按四步推进:旧玄幻压力,脑洞规则介入,公开误判,收益/代价落地。设定越怪,越要快见结果一次小结果。
## 本章取舍
设定短说明,马上给小试或代价。每章必须有规则见结果,不只铺设定。
## 禁止漂移
不要把脑洞写成万能没限制;不要系统刷屏;不要只有设定新奇没有敌人、目标和收益;不要把传统玄幻资源链写丢。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1228 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 23.0 字,对话约占 25%,系统/面板提示约 10%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/玄幻言情.md›
---
genre: 玄幻言情
aliases: [玄幻言情, 女频玄幻, 仙侠言情, 神女]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 玄幻言情正文提示卡
## 正文提示词
写玄幻言情时,让修炼、身份、神女/血脉、宗门压力服务女主主动选择和关系张力。超凡爽点和感情安全感要互相咬合。
## 开场抓手
宗门挑战、身份误判、系统/血脉觉醒、师门危机、男主/反派压迫、神女名分争夺都适合切入。
## 冲突发动机
超凡规则 + 女主身份压力 + 感情/同盟选择。女主不能只被设定推着走。
## 爽点与情绪释放
释放来自女主破境、血脉/身份被承认、宗门偏见反转、危险中被选择或主动选择别人。情感安全感和修炼收益要同场见结果。
## 对话与声线
宗门人物讲规矩,神族/妖族讲身份,亲密关系里多试探和克制。女主不能只靠男主解释世界。
## 章尾钩子
用境界/血脉异象、强敌登门、关系误会、同盟站队、系统奖励或代价收尾。
## 场景颗粒
用灵脉、命灯、契约、师门戒律、神器、伤痕、血脉异象、宗门试炼、神女祭典承载关系和修炼。
## 正文落点
开场落到劫难、师门规矩、灵兽/法器异动或身份压迫;冲突落到修炼代价和情感选择互相牵制;结尾落到境界异象、契约变化或旧因果浮现。
## 前中后期打法
- 前期:用劫难、师门规矩、灵兽/法器异动或身份压迫同时压修炼和感情选择。
- 中期:让境界代价、契约变化、师门站队和情感误会互相牵制,不把感情线写成外挂。
- 后期:把旧因果、境界异象和关系选择合并结算,结尾留契约反噬或前缘浮现。
## 节奏密度
每章推进一个修炼/身份节点,同时让关系位置变化一点。不要连续只谈恋爱,也不要修炼线吞掉女主情绪。
## 本章取舍
若本章重感情,就让感情牵动修炼或身份后果;若重战斗,就保留女主主动判断和关系余波。
## 禁止漂移
不要只写升级不写情感选择;不要让女主被救到底;不要系统压过人物关系;不要把男频玄幻爽点直接套上女主名字。
## 证据摘要
样本说明:本地同题材长篇样本,可用 480 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 29.2 字,对话约占 22%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/现言脑洞.md›
---
genre: 现言脑洞
aliases: [现言脑洞, 现代言情脑洞, 女频系统, 贵族学院脑洞]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 现言脑洞正文提示卡
## 正文提示词
写现言脑洞时,让现代情感关系遇到一个新规则:系统、直播、贵族学院规则、反派养成、身份错位、社交舆论。读者想看现言关系被脑洞设定放大,别滑成纯都市爽文或纯恋爱。
## 开场抓手
从社交公开处刑、系统任务、合同婚恋、校园/学院规则、反派关系失控、手机热搜切入。
## 冲突发动机
现代关系压力 + 脑洞设定 + 名声/利益反馈。设定要立刻改变关系权力。
## 爽点与情绪释放
释放来自女主主动破局、舆论反转、关系偏移、系统目标被反用、恶意者公开失算。
## 对话与声线
现代言情人物说话要生活化,有试探和防御。系统或规则只提供压力,不替角色谈恋爱。
## 章尾钩子
适合用任务惩罚、直播/热搜发酵、身份漏洞、男主/反派态度异常、下一条规则收尾。
## 场景颗粒
常用手机、直播、热搜、贵族学院规则、合同、评分面板、群聊、门禁、身份档案。脑洞规则要改变现代关系中的话语权。
## 正文落点
开场落到手机消息、热搜、系统任务、贵族学院/职场公开评价;冲突落到现代规则被脑洞设定改写;结尾落到新任务、公开反馈、身份漏洞或关系反转。
## 前中后期打法
- 前期:用手机消息、热搜、系统任务、贵族学院或职场公开评价切入,让现代规则被新设定撬动。
- 中期:围绕任务代价、关系误会、钱或身份收益和公开反馈推进,不只刷奖励。
- 后期:把身份漏洞、热搜发酵和关系反转合并,结尾落到新任务或公开处境变化。
## 节奏密度
每章按这个顺序推进:现实关系压力,规则介入,公开反馈,关系偏移。系统/直播信息只做触发器,后果落到人身上。
## 本章取舍
若本章重恋爱,就压缩规则说明;若重规则反转,也要让女主的关系处境变好或变坏。
## 禁止漂移
不要让系统提示比人物关系更重;不要只写概念不写场景;不要忽略女主主动性;不要把现言脑洞写成男频都市系统。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1966 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 25.0 字,对话约占 33%,系统/面板提示约 14%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/科幻末世.md›
---
genre: 科幻末世
aliases: [科幻末世, 末世, 灾变, 废土, 囤货末世]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 科幻末世正文提示卡
## 正文提示词
写科幻末世时,先给生存威胁、秩序崩坏或身份异化,再让系统、科技、空间、资源玩法提供破局可能。每章必须有明确资源、危险和选择代价。
## 开场抓手
灾变前兆、物资短缺、避难所门口、亲友背叛、感染/怪物出现、系统预警都适合切入。
## 冲突发动机
资源不足 + 信任成本 + 外部危险。爽点来自提前准备、判断正确、保护重要关系或抢到关键资源。
## 爽点与情绪释放
释放来自提前判断正确、资源到手、队伍活下来、基地规则被利用、怪物/灾害规律被摸清。爽点要带损耗和新危险。
## 对话与声线
末世里人说话会更短、更急、更现实。信任建立靠分物资、救人、守夜和共同冒险,不靠空泛宣誓。
## 章尾钩子
用新灾变、基地规则、资源暴露、队友异化、敌人盯上收尾。
## 场景颗粒
用水、电、药、食物、弹药、车钥匙、避难所门禁、感染痕迹、天气预警、基地公告承载生存压力。资源数字要能影响选择。
## 正文落点
开场落到断电、感染、物资清点、避难点冲突或异常天气;冲突落到生存资源和队伍信任;结尾落到新灾变、物资缺口、队伍分裂或基地规则变化。
## 前中后期打法
- 前期:用断电、感染、物资清点、避难点冲突或异常天气立生存缺口。
- 中期:围绕物资消耗、队伍信任、基地规则和感染风险推进,每次收益都要消耗代价。
- 后期:把队伍分裂、新灾变和基地秩序合并压迫,结尾落到物资缺口或规则变化。
## 节奏密度
每章至少有一个危险和一个资源选择。囤货/建设章也要有外部风险或内部信任成本。
## 本章取舍
生存压力优先,设定解释靠角色试错。不要把末世写成无成本采购清单,也不要连续打怪忘了资源账。
## 禁止漂移
不要只贴末世设定;不要无代价囤货;不要把危机写成旅游;不要忘记普通人的恐慌和选择成本。
## 证据摘要
样本说明:本地同题材长篇样本,可用 463 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 29.0 字,对话约占 25%,系统/面板提示约 28%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/职场婚恋.md›
---
genre: 职场婚恋
aliases: [职场婚恋, 职场言情, 都市婚恋, 熟男熟女]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 职场婚恋正文提示卡
## 正文提示词
写职场婚恋时,让工作目标和亲密关系互相施压:项目、客户、升职、办公室评价、婚姻/恋爱限制、经济安全。每章至少让事业线或关系线因另一条线发生变化。
## 开场抓手
项目事故、客户会议、办公室流言、加班冲突、婚恋限制、合同/升职机会都适合切入。
## 冲突发动机
职业目标 + 亲密关系需求 + 公开评价。人物不能只谈恋爱,也不能像职场 PPT。
## 爽点与情绪释放
释放来自专业能力被看见、关系分寸确认、公开维护、项目翻盘、经济安全感增强。
## 对话与声线
职场对话有试探、推责、客套和利益交换;亲密关系对话有限制、嘴硬和未说破的需求。不要让角色像汇报 PPT。
## 章尾钩子
用新项目、客户变脸、同事流言、关系被撞破、升职/合同变化收尾。
## 场景颗粒
用会议室、工位、客户电话、合同、群消息、打卡记录、加班餐、升职名单、酒店/家门口承载事业和关系压力。
## 正文落点
开场落到会议、合同、客户电话、加班饭局或婚恋尴尬场;冲突落到职业利益和亲密限制互相挤压;结尾落到项目结果、旧情消息或关系公开风险。
## 前中后期打法
- 前期:用会议、合同、客户电话、加班饭局或婚恋尴尬场让职业利益和亲密限制撞上。
- 中期:围绕项目结果、旧情消息、同事误判和合作限制推进,关系变化必须影响工作局面。
- 后期:把项目结算、关系公开风险和个人选择合并,结尾留升职/换岗/旧情返场。
## 节奏密度
每章至少让事业线或关系线因另一条线变化一次。职场卡点要带来信息、代价或关系变化,不能只当背景。
## 本章取舍
项目章少写恋爱长解释,感情章也要留一个职场后果。行业细节只写能推动选择的部分。
## 禁止漂移
不要只谈恋爱不工作;不要用解释性台词交代行业规则;不要让职场只做约会背景板。
## 证据摘要
样本说明:本地同题材长篇样本,可用 125 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 34.2 字,对话约占 32%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/西方奇幻.md›
---
genre: 西方奇幻
aliases: [西方奇幻, 西幻, 魔法, 魔物, 模拟器西幻]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 西方奇幻正文提示卡
## 正文提示词
写西方奇幻时,先建立可见的异世界制度、种族/职业身份和能力代价,再让系统、模拟、天赋或身份异化提供新变化。场景要有异世界质感,但冲突仍要快。
## 开场抓手
种族身份尴尬、城堡/学院规则、魔物生存、职业觉醒、模拟结果、家族压力都适合切入。酒馆委托、领地税、神殿审判、学院评定要直接卡主角,不要只做异世界背景板。
## 冲突发动机
异世界制度 + 身份限制 + 能力成长代价。不要只替换名词,要让制度影响角色选择。
## 爽点与情绪释放
释放来自职业评定翻盘、种族偏见被打破、契约/魔法代价被反用、学院或贵族重新站队。奇幻爽点要让制度承认变化。
## 对话与声线
贵族、教会、学院、佣兵、魔物种族的说话方式要分层。不要东方玄幻口吻套西幻名词。
## 章尾钩子
用模拟失败/成功、天赋变化、职业评定、魔物危险、贵族/教会/学院压力收尾。
## 场景颗粒
用徽章、契约卷轴、魔法阵、学院评定、酒馆委托、教会审判、城堡门禁、种族标记承载异世界制度。
## 正文落点
开场落到酒馆委托、领地税、魔法学院、神殿命令或怪物袭击;冲突落到契约、血统、魔法代价和阵营选择;结尾落到新委托、封印松动或领主/教会态度变化。
## 前中后期打法
- 前期:用酒馆委托、领地税、魔法学院、神殿命令或怪物袭击立契约和生存压力。
- 中期:围绕佣兵契约、魔法代价、血统/神权和阵营选择推进,设定要落到任务成本。
- 后期:把封印、领主/教会态度和队伍收益合并结算,结尾留新委托或怪物源头。
## 节奏密度
每章推进一个身份、职业、契约或危险节点。设定介绍必须伴随任务、评定、追捕或交易。
## 本章取舍
专名只保留本章会用到的。若本章重魔法规则,就少铺种族历史;若重冒险,就让职业能力在行动中体现。魔法代价要让角色当场付钱、受伤、失去资格或欠下契约。
## 禁止漂移
不要东方玄幻换皮;不要设定脱离本章事件;不要用一堆专名淹没冲突。
## 证据摘要
样本说明:本地同题材长篇样本,可用 84 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 43.8 字,对话约占 24%,系统/面板提示约 11%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/豪门总裁.md›
---
genre: 豪门总裁
aliases: [豪门总裁, 霸总, 京圈, 先婚后爱, 契约婚姻]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 豪门总裁正文提示卡
## 正文提示词
写豪门总裁时,核心放在亲密关系里的权力差、误会、契约、公开身份和安全感。奢侈品只做能改变局势的抓手。每章要让关系发生可见变化:靠近、退开、试探、护短、吃醋、揭身份、把分寸说清或旧误会加深。甜点和虐点都要落到具体场景。
## 开场抓手
- 优先用家庭逼迫、婚约契约、酒店医院、相亲宴会、手机热搜、公司公开场切入。
- 第一场要有关系压力,别先写豪门陈设。
- 男强女强或强弱差都可以,但弱位一方要有选择和反击,不做纯被摆布道具。
## 冲突发动机
亲密需求 + 身份/资源不对等 + 信息差。误会不能靠一句解释解决,要有面子、家族、舆论、合同或旧伤作为阻力。
## 爽点与情绪释放
女频爽点常来自当众维护、分寸确认、恶意者失算、资源转向女主、男主从冷到偏爱。释放时写动作和场内反应,少用“安全感拉满”这类总结。
## 对话与声线
霸总可以短、稳、克制,但不能只会命令。女主台词要有自尊和限制。亲密戏对话重潜台词:不全说破,用停顿、转移话题、反问、嘴硬承接情绪。
## 章尾钩子
适合用身份暴露、旧人出现、热搜爆料、家族电话、契约条款反噬、男主公开站队收尾。钩子要继续压关系,别只换一个新误会。
## 场景颗粒
关系压力落到合同、戒指、病历、热搜、家族电话、董事会、酒店门卡、车内空间、公开座位和转账记录。豪门感靠资源如何改变局面。
## 正文落点
开场落到合同、医院、宴会、热搜、家族饭桌或电梯偶遇;冲突落到阶层体面、契约限制和私下失控;结尾落到关系被公开、协议变更、旧情回归或家族施压。
## 前中后期打法
- 前期:用合同、医院、宴会、热搜、家族饭桌或电梯偶遇压关系分寸和阶层差。
- 中期:围绕契约条款、家族施压、旧情回归和私下失控推进,每章让关系明确前进或后退。
- 后期:把公开身份、协议变更和家族站队推到结算,章尾继续压关系风险,不只制造新误会。
## 节奏密度
每章至少让关系状态前进或后退一步:误会加深、分寸确认、公开维护、旧伤暴露、契约反噬。不要连续只堆暧昧。
## 本章取舍
关系压力先行,豪门物件只选一个能改变局势的抓手。强情绪后留半拍冷却,让读者看见下一次关系风险。
## 禁止漂移
不要只堆品牌和豪宅;不要让霸总成为命令机器;不要所有矛盾都靠“听我解释”消失;不要把女主主动性写没;不要用成人式油腻台词替代真实拉扯。
## 证据摘要
样本说明:本地同题材长篇样本,可用 4457 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 23.0 字,对话约占 31%,系统/面板提示约 8%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/都市修真.md›
---
genre: 都市修真
aliases: [都市修真, 都市修仙, 都市仙尊, 现代修真]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 都市修真正文提示卡
## 正文提示词
写都市修真时,让修真能力解决都市里的关系、金钱、家庭、身份和危险问题。爽点来自现代人按常识误判,主角用超凡规则翻盘,但翻盘后必须有现实后果。
## 开场抓手
家庭困境、医院危机、债务合同、校园/公司羞辱、古玩药材、危险冲突都适合切入。
## 冲突发动机
现代规则 + 修真规则不对称 + 旁人误判。修炼不能把都市生活写没。
## 爽点与情绪释放
释放来自医院救人、古玩药材捡漏、债务/合同翻盘、恶人被现代规则反噬、普通人重新评估主角。超凡能力要让现实处境改变。
## 对话与声线
现代角色说现实账,修真相关人物说规矩和代价。主角不要长篇讲道法,能用结果证明就不解释。
## 章尾钩子
用药材线索、隐藏高手、家族/公司压力、身份暴露风险、下一次现实麻烦收尾。
## 场景颗粒
用医院、药铺、古玩摊、债务合同、公司门口、家族饭桌、银行卡、监控和伤口承载修真翻盘。
## 正文落点
开场落到医院、古玩、家族羞辱、灵气异常或救人现场;冲突落到现代规则和修真能力限制;结尾落到病情反转、法器线索、仇家上门或修炼资源出现。
## 前中后期打法
- 前期:用医院、古玩、家族羞辱、灵气异常或救人现场让现代规则撞上修真能力。
- 中期:围绕法器线索、病情反转、钱、账资源和仇家上门推进,能力越强越要有限制。
- 后期:把现代势力、修炼资源和旧仇合并清算,结尾留更高修士或资源源头。
## 节奏密度
每章一半以上篇幅留在现实问题上,修真能力只解决当前卡点并引出更高层麻烦。
## 本章取舍
若本章重修炼,就必须挂现实需求;若重都市打脸,就让修真规则有代价或暴露风险。
## 禁止漂移
不要一进修真就脱离现实关系;不要纯装逼没有生活账;不要把都市场景写成古代宗门。
## 证据摘要
样本说明:本地同题材长篇样本,可用 893 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 25.8 字,对话约占 28%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/都市日常.md›
---
genre: 都市日常
aliases: [都市日常, 日常文, 都市生活, 温馨日常]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 都市日常正文提示卡
## 正文提示词
写都市日常时,正文要让普通小事带出关系、钱、职业、家庭和身份变化。主线围绕一个清楚的生活目标推进:创业翻身、家庭修复、小店经营、社区治愈、职业转稳都可以。读者看的是生活一点点变好的确定感,大事件密度反而靠后。每章安排一个可见生活问题,再让主角的选择让关系或处境前进一步。
## 开场抓手
- 用手机消息、吃饭接送、账单、工作班级、邻里亲友误会、家庭小争执切入。
- 开场可以低压,但必须有具体麻烦或具体期待,不能只写天气和心情。
- 金手指若存在,要服务生活改善,不要把日常冲成升级爽文。
## 冲突发动机
小问题 + 熟人关系 + 现实成本。冲突可以低烈度,但每段日常都要产生结果:一顿饭改善关系,一次误会改变社交圈,一笔小钱决定下一步。冲突要和角色长期处境有关:谁误会了,谁心软了,谁欠谁一个人情,谁的日子因此变好或变坏。
## 爽点与情绪释放
爽点来自可见改善:一顿饭吃踏实,一笔钱解决,一个人愿意开口,一个关系缓和,一个机会到手。常见情绪曲线是小挫折里的疲惫、怯意和窘迫,转向问题解决后的温馨、从容和安定。释放要细,不靠作者总结“生活真好”。
## 对话与声线
对话要像熟人说话,有岔开、打断、嘴硬、顺手关心。生活场景里不要让角色长篇讲道理,信息尽量从闲聊和小动作带出来。
## 章尾钩子
适合用一条新消息、一个上门的人、一个未说出口的请求、下一顿饭/下一次见面的约定收尾。钩子可以温和,但要有继续看的理由。
## 场景颗粒
抓早餐、公交/地铁、外卖、账单、群聊、钥匙、门口鞋、菜市场、办公室小物、店门铃、老物件和邻里招呼。生活质感来自可复用的小物件、小动作和小关系,人物的消费能力、社交分寸和说话习惯要贴近现实。
## 正文落点
开场落到账单、饭桌、群聊、店门铃、接送或邻里误会;冲突落到小目标被现实成本卡住;结尾落到一条新消息、一个上门的人或下一次生活约定。
## 前中后期打法
- 前期:用账单、饭桌、群聊、店门铃、接送或邻里误会压出一个小目标。
- 中期:围绕钱和账周转、亲友态度、工作/小店变化和熟人评价推进,每段日常都要产生结果。
- 后期:把生活目标、关系修复和下一次选择合并,结尾用新消息、上门人或约定留温和钩子。
## 节奏密度
低压不等于无事。每章至少有一个小问题、一次互动变化、一个余波或伏笔。
## 本章取舍
低压章允许无显性打脸,但要有关系进展、生活收益或伏笔推进。节奏靠“具体生活问题的解决和余波”,别靠强行反转。
## 禁止漂移
不要写成吃饭睡觉流水账;不要让普通人天天出入顶级场所、突然获得巨额资源;不要连续几十章没有目标变化;不要突然变仙侠/高武升级;不要用温馨总结代替细节;不要为了冲突把熟人全写成极品。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1572 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 21.8 字,对话约占 30%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/都市种田.md›
---
genre: 都市种田
aliases: [都市种田, 经营日常, 重生经营, 乡村都市]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 都市种田正文提示卡
## 正文提示词
写都市种田时,把家庭、土地/门店/产品、钱、邻里和身份变化写成经营循环。爽点来自一点点把生活盘活,并被身边人看见。
## 开场抓手
下岗/离婚、门店亏损、邻里关系、孩子/家人心声、第一笔生意、产品试卖都适合切入。
## 冲突发动机
低资源起点 + 经营机会 + 家庭关系压力。每章至少推进一个资源、口碑或关系位置。
## 爽点与情绪释放
释放来自第一笔利润、产品被认可、家人安心、邻里改口、竞争对手失算。经营爽点要能算账,也要有人情反馈。
## 对话与声线
家人和邻里说话带现实顾虑,顾客说需求和挑剔,主角要会谈价格、谈品质、谈人情。不要全员只夸产品。
## 章尾钩子
用新订单、邻里反应、家人态度变化、竞争对手、下一笔投入风险收尾。
## 场景颗粒
用摊位、门店、地块、货车、收款码、账本、食材、包装、顾客排队、邻里闲话承载经营变化。
## 正文落点
开场落到小店、菜地、订单、乡村人情或第一笔买卖;冲突落到经营成本、口碑和熟人社会;结尾落到新订单、资金缺口、邻里站队或下一次开张。
## 前中后期打法
- 前期:用小店、菜地、订单、乡村人情或第一笔买卖立经营目标和成本缺口。
- 中期:围绕订单、口碑、资金周转和邻里站队推进,经营收益必须可见可复用。
- 后期:把新订单、资金缺口和熟人社会评价合并结算,结尾留下一次开张或竞争者动作。
## 节奏密度
每章推进一个经营环节:选品、试卖、口碑、复购、扩张、竞争。慢章也要让资源或关系位置变化。
## 本章取舍
经营过程要有阻力和取舍,不能只写收入上涨。若本章重家庭,就让家庭态度影响经营决策。
## 禁止漂移
不要把经营写成账本流水;不要突然争霸;不要失去日常生活质感;不要全靠外挂跳过经营过程。
## 证据摘要
样本说明:本地同题材长篇样本,可用 451 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 25.0 字,对话约占 33%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/都市脑洞.md›
---
genre: 都市脑洞
aliases: [都市脑洞, 都市系统, 听劝文, 规则奖励, 生活脑洞]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 都市脑洞正文提示卡
## 正文提示词
写都市脑洞时,先让读者看见一个具体的现实窘境,再让核心脑洞立刻改变这件事。系统、面板、听劝、绑定、吹牛成真、异常能力都不能悬空展示,必须落到手机消息、账单合同、家庭关系、学校公司、围观评价这些现实场面上。爽点优先写“别人按现实常识判断错了,主角用新规则当场翻盘”。
## 开场抓手
- 用欠钱、离婚、退队、被嘲、求职失败、亲戚压力、手机消息等低门槛困境切入。
- 金手指不要先讲说明书,先给一次能被现实场景验证的小见结果。
- 若有系统面板,面板只给目标、奖励、限制三件事,立刻回到角色反应。
## 冲突发动机
现实身份被看轻 + 新规则介入 + 旁人误判。冲突要围绕“谁不信、谁阻拦、谁要付账、谁会被公开打脸”推进,别让主角一个人看面板自嗨。
## 爽点与情绪释放
小爽点是现实收益到账,钱、形象、技能、关系位置改变;中爽点是围观者态度反转;大爽点是旧秩序被主角的新规则改写。奖励到账后必须有外部反馈。
## 对话与声线
都市脑洞的对话要带生活口吻:吐槽、急眼、装镇定、嘴硬都可以。系统提示冷一点,人说话热一点,别让角色替系统解释设定。
## 章尾钩子
适合用新任务、新奖励到账、手机热搜、陌生来电、检测结果、下一位误判者登场收尾。钩子要指向下一章的现实麻烦,而不只是“系统又响了”。
## 场景颗粒
现实场面优先:手机通知、账单、合同、体检表、监控、门禁、直播间、公司群、亲戚饭桌。脑洞规则必须在现实场面上被验证。
## 正文落点
开场落到系统提示、手机消息、家庭/职场尴尬或公开评价;冲突落到脑洞规则改变现实收益;结尾落到奖励异常、热搜发酵、关系误会或新任务。
## 前中后期打法
- 前期:用系统提示、手机消息、家庭/职场尴尬或公开评价让脑洞规则第一次改变现实收益。
- 中期:围绕任务代价、钱和收益、关系误会和公开反馈推进,规则越爽越要给限制。
- 后期:把奖励异常、热搜发酵和身份漏洞合并,结尾落到新任务或更大公开评价。
## 节奏密度
每章至少有一次规则小见结果和一次外部反馈。面板信息越长,现实反应越要具体,否则会变成自嗨。
## 本章取舍
系统信息压短,现实反馈放大;设定用到哪写到哪。跨题材时,都市脑洞只承担“新规则改写现实”的主干,别抢走情感线或悬疑线的主节奏。
## 禁止漂移
不要写成纯系统说明书;不要连续贴面板;不要只罗列奖励;不要让主角没有主动选择;不要为了去AI味硬删“的、了、地、得”导致中文别扭。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1837 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 21.5 字,对话约占 32%,系统/面板提示约 10%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/都市高武.md›
---
genre: 都市高武
aliases: [都市高武, 高武, 灵气复苏, 序列, 异能都市]
platform: 长篇通用
confidence: high
source: local_longform_sample_derived
---
# 都市高武正文提示卡
## 正文提示词
写都市高武时,要把现代生活压力和超凡危险绑在一起。学校、家庭、城市秩序、职业考试、序列等级、异常灾害都要变成能力见效后的的现实后果。爽点落在被看轻的主角解决别人解决不了的危险。
## 开场抓手
- 用异常事故、天赋检测、校园/训练场压力、家庭负担、官方通报、职业考试切入。
- 先给危险或等级压迫,再给主角的破局方式。
- 设定名词只给当前场景需要的部分。
## 冲突发动机
现实身份被看轻 + 超凡等级秩序 + 异常危险。旁人按等级、天赋、履历误判主角,主角用能力、信息差、胆识或策略打破判断。
## 爽点与情绪释放
能力展示要有见证者、代价和后果:检测记录改写、老师/官方注意、家人处境改善、敌人重新评估。战斗爽点写策略,不只写数值碾压。
## 对话与声线
官方/学校角色说话有制度感,学生/市民有生活压力,主角台词要带目标和判断。别让所有人围着等级表念设定。
## 章尾钩子
适合用新异常预警、天赋复测、官方征召、榜单变化、敌方盯上、系统/检测结果异常收尾。
## 场景颗粒
用检测仪、训练馆、校服、城市警报、伤检报告、职业证、积分榜、官方通报和家中账单承载高武现实感。
## 正文落点
开场落到体测、武考、异兽警报、训练馆或排名刷新;冲突落到战力差距、资源名额和公开评测;结尾落到榜单变化、强者关注、异兽入侵或新训练资格。
## 前中后期打法
- 前期:用体测、武考、异兽警报、训练馆或排名刷新压出战力差距和资源名额。
- 中期:围绕训练收益、补给资源、公开评测和危险、事故、案件推进,升级要有可见测量。
- 后期:把榜单变化、强者关注和异兽入侵推到明面上见结果,结尾留新训练资格或战场召唤。
## 节奏密度
每章推进一个能力节点和一个现实后果。训练、检测、战斗、官方反应不要断成互不相关的清单。
## 本章取舍
设定跟着事件走,战斗跟着目标走。现代场景不能丢,超凡能力要改变现实身份和资源分配。
## 禁止漂移
不要连篇解释力量体系;不要写成古典宗门玄幻;不要只有数值提升没有现实反馈;不要让战斗没有空间、规则和代价。
## 证据摘要
样本说明:本地同题材长篇样本,可用 1695 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 26.0 字,对话约占 27%,系统/面板提示约 12%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-prose-cards/青春甜宠.md›
---
genre: 青春甜宠
aliases: [青春甜宠, 校园甜宠, 校园恋爱, 青春校园]
platform: 长篇通用
confidence: medium
source: local_longform_sample_derived
---
# 青春甜宠正文提示卡
## 正文提示词
写青春甜宠时,把校园、同学、家庭、误会、公开围观和小危险变成感情推进器。甜要落在试探、护短、别扭、吃醋、共同面对麻烦里,不能只靠互夸。每章关系要有一点可见变化。
## 开场抓手
从换座位、考试排名、同学起哄、家长电话、社团活动、雨天接送、校园误会、一次小伤小险切入。
## 冲突发动机
青春身份限制 + 同龄人围观 + 不敢说破的好感。冲突轻中有钩,甜点短而密。
## 爽点与情绪释放
释放来自公开维护、称呼变化、消息置顶、帮忙补课、一起承担惩罚、误会后低头。让关系前进一步就够,不必每章大告白。
## 对话与声线
台词要年轻、别扭、嘴硬,有停顿和转移话题。不要让高中生说霸总式台词,也不要全员网络段子手。
## 章尾钩子
适合用新座位、新分组、下一次考试/比赛、家长发现、同学误会升级、未发出的消息收尾。
## 场景颗粒
用课桌距离、草稿纸、校服外套、便利店、成绩单、班群消息、操场、社团道具、家长电话承载甜点和压力。
## 正文落点
开场落到班级、宿舍、考试、社团、校门口或一条消息;冲突落到误会、竞争和青春期面子;结尾落到约定、公开围观、成绩/比赛变化或暧昧证据。
## 前中后期打法
- 前期:用班级、宿舍、考试、社团、校门口或一条消息制造误会和青春期面子。
- 中期:围绕成绩/比赛、同学围观、约定落地和小吃醋推进,甜点要和具体事件绑定。
- 后期:把公开围观、成绩变化和暧昧证据合并,结尾留下一次约定或关系被同学看见。
## 节奏密度
每章一个小压力、一个小靠近、一个未说破的余波。甜点短而准,关系变化要能被下一章继承。
## 本章取舍
校园规则和同龄人围观不能消失。若本章重撒糖,就留一个考试、家长或同学误会压力;若重冲突,就给读者一个关系安全感回扣。
## 禁止漂移
不要只写脸红心跳;不要连续撒糖没有外部压力;不要成人化油腻;不要让校园规则消失。
## 证据摘要
样本说明:本地同题材长篇样本,可用 143 本;抽样 24 本,前/中/后章节段 24/24/24,共 72 个。
正文参考:段落中位约 26.8 字,对话约占 24%,系统/面板提示约 8%。
使用提醒:只作题材参考,帮你抓常见场面和前中后写法;本书设定与同题材对标仍优先。
references/genre-readers.md›
# 读者心理与题材适配
> **用途**:读者心理需求、题材生命力规律、跨网站适配、平台差异、书名/简介技法、代入感管理。选题和定位时对照使用。
> **语气**:指令式——每个规律都要转化为选题、定位、书名、文案或开篇的可执行约束。
> **配合**:长篇题材结构见 `long-genre-catalog.md`,声线见 `genre-prose-cards.md`,核心梗设计见 `long-genre-mechanics.md`。
---
## 决策路由:按决策类型选章节
> 做选题和定位决策时,先确认你在做什么决定,然后翻到对应章节。
| 你要做的决定 | 先看哪个章节 | 核心问题 |
|-------------|-------------|---------|
| 选题材/判断题材潜力 | 题材生命力规律 | 这个题材还有没有红利? |
| 确认目标读者想要什么 | 读者心理需求与题材匹配 | 读者深层缺什么?我的题材给不给得了? |
| 选平台/调整写法 | 跨网站题材适配 | 同一题材在目标平台怎么改写法? |
| 判断题材边界/能不能混搭 | 题材边界感 | 当前素材、知识储备和篇幅能否支撑这个题材? |
| 取书名 | 书名命名技法 | 书名能不能在3秒内抓住目标读者? |
| 写简介/文案 | 简介/文案分类体系 | 简介有没有给出安全感+钩子? |
| 检查代入感 | 代入感与塑料感 | 读者能不能把自己投射进主角? |
---
## 读者心理需求与题材匹配
### 从爆款反推读者心理
- 从爆款提炼核心剧情元素→框定读者画像→推测心理需求→双管验证
- 爆款情绪一以贯之(斗破="莫欺少年穷"从头到尾);非爆款散乱多头并行
- 小情绪(升级/复仇/寻宝)应统一到主情绪之下
- 验证法:提炼出的情绪需求对照目标读者真实生活状态
- 特别关注"别人觉得剧毒但核心读者痴迷"的元素
### 题材→读者画像→深层需求
| 题材 | 读者画像 | 三层心理需求 |
|------|----------|-------------|
| 末日重生 | 对阶级跃升绝望的人 | 颠倒秩序(权力渴望)+不安全感(生存焦虑)+捡漏(最小努力最大回报) |
| 战神赘婿 | 中年男人,经济压力大 | 无能的痛苦→不被体谅的愤怒→羞耻的自卑→需要借口合理化隐忍→反转暴爽 |
| 网文通用 | — | 深层需求落在被认可/被理解/被尊重,表面"打脸"只是外壳 |
### 深层需求挖掘法
- 潜入读者集体潜意识→爱什么恨什么渴望什么逃避什么
- 不同题材读者画像不同→必须先定位读者再设计情绪
- 写作前先问:目标读者现实生活中最缺什么?最想要什么?
- 情绪需求深度决定作品天花板——越触及深层需求共鸣越强
### 情绪根源
情绪来自"不公平"和"为什么"。区别对待→读者理所当然觉得不公平→这就是情绪根源。
都市情绪例:事业小有成就→爸要创业→妈要给弟弟买婚房→不公平感自然产生。
---
## 题材生命力规律
- 题材生命力按“样本验证”判断,不把历史经验当作当前事实。
- 先用当前 scan/analyze 或用户指定样本确认目标平台仍有读者反馈。
- 判断题材所处阶段:新鲜期 / 成熟期 / 审美疲劳期。
- 新鲜期优先提炼创意方向;成熟期优先稳定交付边界期待;疲劳期必须给出新切入点。
- 跟风只能复用结构功能位,不能复刻剧情内容。
- 无法确认阶段时,按成熟期处理:保守满足边界期待,微创新不超过 3 个。
### 时代变革三阶段
| 时代 | 特征 |
|------|------|
| 自由时代 | 无固定风格,灵感来自传统文学/漫画 |
| 游戏化时代 | 等级+关卡+BOSS+副本+装备,引导消费 |
| 生活化倾向 | 重故事轻升级,有生活细节,贴近时代,反游戏化;是否适用需以当前平台样本验证 |
---
## 跨网站题材适配
同一个题材在不同网站写法完全不同,由目标读者群体决定。不能用A网站的样本直接套到B网站;必须用目标平台样本校准读者期待、节奏和雷点。
### 平台核心差异
| 平台 | 核心驱动力 | 不适配题材 |
|------|-----------|-----------|
| 刺猬猫 | 整活与人设,动漫同人/二游基础 | 全民流、高武流基本行不通 |
| 起点(非轻小说) | 正常剧情推进的节奏与代入感 | 纯整活难以长期维持 |
| 起点轻小说 | 整活+人设+节奏并重 | 需持续整活能力 |
| 番茄 | 强情绪、噱头、爽感直给 | 需慢热铺垫的题材 |
### 读者群体差异
| 平台 | 读者特征 |
|------|----------|
| 起点 | 筛选成本高,读者更耐心,慢节奏也能接受 |
| 新媒体(30岁+) | 偏爱接近真实的故事,被打击的生活才是常态 |
**关键**:同一套写法不同平台效果截然不同,必须针对平台调整。
### 刺猬猫要点
同人优先验证目标圈层样本 | 脑洞要加成在次元文化里 | 逻辑以圈层接受度为准 | 少写打斗多写日常 | 对"梗"要求很高,需用最新榜单/评论校准
### 番茄书测改名策略
书名 A/B 方案:金手指相关 / 第一个单元剧情相关 / 主线相关 / 与原书名相近的保守款 / 稍微夸张吸量的款。用目标平台规则和用户要求筛选。
---
## 题材边界感
### 有边界感 vs 无边界感
| 类型 | 特点 | 适合人群 |
|------|------|----------|
| 有边界感 | 已有成熟受众、写法有迹可循 | 样本验证充分,适合稳定交付 |
| 无边界感/创新 | 受众不确定、写法需探索 | 风险高,需降低篇幅和创新数量 |
### 玄幻三大核心
- **代入感**:玄幻王朝比赛博朋克代入感强百倍;肉身成圣拳拳到肉比斗法对波好代入
- **期待感**:期待感不崩贯穿全文,读者流失很慢
- **认同感**:读者代入主角对主角认同=死忠粉极难流失。"小德可缺大义不能失"
### 都市文暧昧四要素
1. **女人**:没有女人的都市文不是都市文(男频)
2. **轻松**:读者图轻松愉悦不写苦大仇深
3. **互动**:角色间互动+读者与主角的"秘密"互动
4. **私密**:隐藏主角能力,读者和主角之间的小秘密
### 金手指设定原则
必须与主角生活/职业息息相关。医生配医术秘籍=合理;医生配隐身=牵强。金手指跟主线有关,技能能升级,一个技能衍生不同效果,不要频繁开新金手指。
### 历史文红线
- 核心立场:"基于民族主义的圣主平等",前后立场摇摆=严重割裂
- 历史网文≠历史,以读者为第一要素不是以真实为第一要素
- 历史人物评判跟随当代权威共识,尤其是教员的评判,不要逾越
- 爽感阈值管理:前期家族/势力升级过快→后续难以为继
---
## 代入感与塑料感
### 代入感
代入感高度重叠于爽感。代入感低时主角做什么读者都不觉得爽。越代入越爽越爽越想看。
### 塑料感来源
仙侠不仙、武侠不侠、画风撕裂(仙侠世界搞科研)。去塑料感:让世界像真实存在的世界不是纸糊的。
### 同人为什么开头高追读
世界观够硬,初始代入感够高。例外:搞笑文/梗文核心偏有趣,爽感居次,需旁观者视角,不需要强代入感。
### 有效扫榜
扫榜规则:1) 运行当前 scan/analyze 流程获取目标平台近期样本 2) 排除自带粉丝基础的头部作品 3) 分析可复用样本的开头结构共性。开头必须在300字内建立核心冲突,一万字定高下。
### 商业化认知
私人表达占比规则:非核心情绪的个人表达不超过全篇5%,且不得打断叙事节奏。商业化不是故意恶心读者。商业化原则:所有私人表达必须服务于核心卖点,不得独立于主线剧情存在。
---
## 书名命名技法
### 身份法(覆盖约1/3书名)
| 类别 | 公式 | 示例 |
|------|------|------|
| 高逼格身份 | [仙帝/魔神/财阀]爹妈+[反差行为/目标] | "武神爹,财阀妈,我当躺赢狗怎么了?" |
| 戏剧身份对照 | [低位]替[高位]做[超出预期的事] | "让你当书童,你替少爷科举中状元?" |
| 身份擦边型 | 身份关系制造暧昧暗示 | 有风险但吸量极强 |
### 其他方法
| 方法 | 核心 | 适用平台 |
|------|------|----------|
| 掉马甲型 | 隐藏身份逐渐暴露 | 若目标平台近期同质样本过多则慎用 |
| 逼格起名法 | 意境感强的词汇 | 起点 |
| 反义词法 | 正反反差制造好奇 | 通用 |
| 主线+爽点法 | 主线剧情核心+爽点暗示 | 起点 |
### 平台起名差异
| 平台 | 风格 | 关键原则 |
|------|------|----------|
| 番茄 | 噱头优先吸量第一 | 书名决定80%流量上限 |
| 起点 | 轻度反差+金手指+主线+爽点 | 内容必须贴合书名 |
---
## 简介/文案分类体系
### 五种基本类型
| 类型 | 结构 | 效果 | 适用 |
|------|------|------|------|
| 四段式成功型 | 情境→冲突→行动→成功 | 安全感,明确会赢 | 最通用 |
| 三段式行动型 | 情境→冲突→行动(截止) | 留悬念 | 事业线突出的文 |
| 二段式悬疑型 | 情境→一个反转/悬念 | 制造好奇 | 悬疑/烧脑/冷门 |
| 四段式失败型 | 情境→冲突→行动→失败 | 虐感和愤怒 | 追妻火葬场 |
| 三段式成功型 | 情境→转折→成功 | 简洁明快 | 甜文/轻松向 |
### 组合策略
- 成功型+悬疑型=安全感+好奇心
- 行动型+成功型=先期待再满足
- 失败型+悬疑型=虐后留悬念
### 文案要点
- 必须体现女主主体性——主体性差会提高吸引力和留存风险
- 读者需要安全感——至少暗示主角会成功
- 文案和书名货不对板会劝退
- 悬疑型不宜叠过多——太"谜语人"理解不了且安全感不足
---
## 质量检查清单
> 选题定位完成后逐项核对。全部通过才算合格。
- [ ] **读者画像明确**:能用一句话说出目标读者是谁、现实生活中最缺什么
- [ ] **深层需求对位**:题材提供的核心情绪与读者深层需求匹配,不是自嗨
- [ ] **题材生命力判断**:已用当前样本确认题材阶段,不把历史热度当作当前事实
- [ ] **平台适配**:写法已针对目标平台调整,不是用A平台的经验硬套B平台
- [ ] **边界感确认**:当前素材、知识储备和篇幅能支撑所选题材
- [ ] **书名3秒抓人**:书名在目标平台的命名规则内,3秒内能传递核心卖点或钩子
- [ ] **简介有安全感+钩子**:简介类型选择正确,给了安全感同时留了悬念
- [ ] **代入感无塑料感**:世界观自洽,画风统一,没有"仙侠搞科研"式撕裂
- [ ] **书名简介内容三位一体**:书名暗示的卖点=简介承诺的内容=正文实际交付的东西
- [ ] **金手指与生活关联**:金手指设定与主角职业/生活紧密相关,不是硬贴的
references/long-chapter-hooks.md›
# 长篇章级钩子:章首/章尾选择与跨章期待
> 写长篇章首或章尾时加载。先按章节功能和跨章期待选类型,再决定落点与篇幅。
---
## 决策路由
### 章尾钩子:根据本章情绪选类型
| 本章情绪/阶段 | 推荐钩子 | 为什么 |
|-------------|---------|-------|
| 悬念/未知 | 突然揭示 / 神秘物品 / 留白 | 激发好奇 |
| 紧迫/危机 | 紧急危机 / 倒计时 / 未完成动作 | 制造焦虑 |
| 反转/真相 | 身份反转 / 隐藏含义 / 回声 | 颠覆认知 |
| 情感/关系 | 两难抉择 / 承诺威胁 / 情感转折 | 拉扯情绪 |
| 系统文特有 | 系统激活 / 选择型 | 期待金手指 |
| 氛围/日常 | 意象钩子 / 离奇消失 / 信息差 | 暗流涌动 |
### 章首钩子:根据开篇策略选类型
| 开篇策略 | 推荐钩子 | 为什么 |
|---------|---------|-------|
| 直接冲击 | 未完成动作开局 / 倒计时开局 | 即时紧迫感 |
| 制造好奇 | 悬念对话 / 闪前碎片 / 神秘独白 | 信息差驱动 |
| 对比冲击 | 反差场景 / 意象预示 | 反差吸引 |
### 章节阶段与钩子强度
| 故事阶段 | 推荐类型 | 强度 |
|----------|---------|------|
| 第 1 章 | 系统激活 / 截断 / 危机升级 | 必须强 |
| 2-3 章 | 选择 / 信息差 / 情感转折 | 强 |
| 中期日常 | 对话悬念 / 信息差 / 身份即将揭露 | 中 |
| 高潮前 | 危机升级 / 悬念预知 | 强 |
| 大结局 | 时间跳跃 / 情感转折 | 收束 |
---
## 章尾钩子 13 式
| # | 名称 | 公式 | 示例 |
|---|------|------|------|
| 1 | 突然揭示 | 抛出改变全局的信息 | "信上的日期,是他死后第七天。" |
| 2 | 紧急危机 | 下章必须回应的紧迫威胁 | "裂缝在扩大,灵石还差三块。" |
| 3 | 未完成动作 | 动作被新变量打断 | "他刚伸手,手腕忽然被人扣住。'别动。'身后传来一个声音。" |
| 4 | 身份反转 | 身份真相偏离读者预期 | "她叫林小月。但档案上写的是:林小月,已故。" |
| 5 | 两难抉择 | 被迫在两个坏选项中选一个 | "签了这份文件,公司保住了,但他得进去。" |
| 6 | 神秘物品 | 重要但含义未知的物件 | "包裹里是一把钥匙,附了张纸条:'你欠我的。'" |
| 7 | 倒计时 | 时间不够用 | "医生说还有三个月。那是两个月前的事了。" |
| 8 | 承诺/威胁 | 有人宣布了行动意图 | "今晚十二点之前,我会告诉所有人你做了什么。" |
| 9 | 离奇消失 | 不可能的消失 | "手铐还在,人没了。整个房间只有一个门,门没开过。" |
| 10 | 隐藏含义 | 表面正常,实际暗藏信息 | "他说:'你和妹妹真像。'可她是独生女。" |
| 11 | 意象钩子 | 反复出现的意象发生变化 | "窗台上那盆枯了一个月的茉莉,突然冒出了花苞。" |
| 12 | 回声钩子 | 章尾句呼应开头,关键细节变了 | 开头:"她说她永远不会原谅他。" / 结尾:"她说她永远不会原谅他。但她的手,攥得更紧了。" |
| 13 | 留白钩子 | 只展示反应,不揭示发生了什么 | "他看了信。脸色变了。什么也没说,把信叠好放进口袋。" |
---
## 章首钩子 7 式
| # | 名称 | 公式 | 示例 |
|---|------|------|------|
| 1 | 悬念对话开局 | 直接从意味深长的对话开始 | "你确定要这么做?/ 确定。/ 那你就别后悔。" |
| 2 | 闪前碎片 | 先给结果碎片,再回正常叙事 | "后来他才知道,那个电话改变了所有事。但此刻他还一无所知。" |
| 3 | 倒计时开局 | 开头就建立紧迫感 | "距离合同到期还有 72 小时。" |
| 4 | 神秘独白 | 第一人称诡异内心独白 | "我一直在想,那天如果我没有回头,一切会不会不一样。" |
| 5 | 反差场景 | 两个截然不同的场景并列 | "一边是婚礼现场,香槟塔堆得老高。另一边,医院走廊的灯在闪。" |
| 6 | 未完成动作开局 | 动作进行中被截断 | "他刚把钥匙插进锁孔,门里传来一声轻响。" |
| 7 | 意象预示 | 用环境意象暗示即将发生的事 | "天边烧得通红,像是什么东西在着。她抬头看了一眼,继续走。" |
---
## 章尾实战模板
### 一、系统激活型
```
就在{主角}{最低谷状态}之际。
{一个感官描写}。
叮!
【{系统名},正式启动。】
```
> 就在他万念俱灰之际。一个冰冷的机械音,突然在他脑海中响起。叮!【年少轻狂系统,正式启动。】
### 二、悬念预知型
```
{主角}{冷静/冷漠地}看着{对方的嚣张行为}。
{一个短句:继续吧/慢慢来/不着急}。
{预告即将发生的反转,不透露细节}。
```
> 我冷眼看着笑得前仰后合的人。笑吧。多笑会儿。过了今天,你们就再也笑不出来了。
### 三、截断型
```
{一个小动作}。
{剧烈反应}。
{震惊/疑问。本章结束,不给答案}。
```
> 仅仅一口!她的瞳孔猛地收缩成针尖状。轰!一股恐怖到难以形容的热流,瞬间在她的腹中炸开!这粥有问题!里面到底放了什么?
### 四、选择型
```
【选择一:{诱人选项}】奖励:{极其诱人} 代价:{隐含风险}
【选择二:{另一选项}】奖励:{另一种诱人} 代价:{另一种风险}
```
章节结束,不给出选择结果。
### 五、危机升级型
```
{突然的声响/动作}!
{新威胁出现}。
{主角的恐惧/紧迫反应}。
```
> "都给老子出来!快点!"哐啷!!!一只沾满泥污的军靴,粗暴地踹开了笼门。
### 六、身份即将揭露型
```
{一个旁观者}突然{提出疑问/发现线索}。
"{暗示主角真实身份的话}"
{其他人不以为意,主角暗暗紧张}。
```
### 七、情感转折型
```
就在这时,{角色}的{表情/态度}突然{大变}。
{一个出人意料的示弱/请求动作}。
"{戳中主角软肋的话}"
```
### 八、信息差型
```
{主角的自我怀疑/感慨}。
{一个意象/比喻}。
{暗示即将改变,但不明说}。
```
> 花有重开日,人无再少年。自己怎么就把日子,过成了这副狗屎样?
### 九、对话悬念型
```
"{提出请求的前半句}"
"{对方回应}"
"{意想不到的后半句,不是读者预期的}"
```
> "我有一个请求。"苏牧缓缓说道。"你说。""离婚之前,我要证明一次自己。"
### 十、时间跳跃型
```
{精确/模糊的时间标记}。
{出人意料的结果}。
{暗示过程的一句话}。
```
> 三分三秒后。江亦瑶神色从容地走出房间,整理了一下微乱的衣服。
---
## 三种速写章末钩子
### 收获预告型(副本/任务尾声)
```
{当前行动接近完成}。
{暗示即将获得的奖励}。
{一句话暗示奖励比预期更大}。
```
### 反派逼近型(铺垫段结尾)
```
{主角当前状态}。
{暗处/远方,反派的某个行动}。
{暗示这个行动将影响主角}。
```
### 行动预告型(装逼/打脸前)
```
{主角做出一个决定}。
{一个准备动作}。
{暗示即将发生的行动}。不写结果。
```
---
## 爽点与看点设计规则
### 爽点核心公式
爽点 = 两个逻辑的冲突点:
- **大众逻辑**:对手不可战胜 → 恐惧/绝望
- **主角逻辑**:正好手痒/轻描淡写
- 落差越大 → 爽点越爽
### 爽点三要素
| 角色 | 操作 |
|------|------|
| 吃瓜群众 | 用议论吹高对手逼格 → 震惊反应完成打脸升华 |
| 对手 | 嚣张到让读者恨 → 被打脸时才爽 |
| 主角 | 铺垫时低调 → 释放时干脆 |
看点 = 吊起读者期待;爽点 = 满足期待。一一对应:前面铺垫多少,后面爽点就有多少。
### 装逼打脸节奏
| 阶段 | 公众期(5 章循环) | VIP 期 |
|------|-------------------|--------|
| 人设 | 1 章 | 1-2 章 |
| 铺垫 | 2 章 | 5 章 |
| 打脸 | 1 章 | 1-2 章 |
| 善后 | 1 章 | 1 章 |
**关键**:
- 前置小无敌:打脸前必须把道具/人物/实力准备好,没有则读者担惊受怕,嘲讽变虐主
- 铺垫比打脸重要:铺垫到位后主角站着不说话都能装逼
- 打脸对象层级决定爽感层级:路人甲震惊不叫爽,有分量的人震惊才叫爽
- 章末钩子只写到期待成立为止;篇幅服从信息复杂度,不设固定百字配额
---
## 质量检查
写完章首/章尾后对照:
- [ ] 章首尽早出现可识别的行动、异常或未闭合期待;不按固定百字位置机械卡点
- [ ] 章尾有让读者想翻下一页的东西
- [ ] 钩子强度与章节阶段匹配(日常章不必强钩子)
- [ ] 连续两章不用同一种钩子
- [ ] 钩子没有为凑长度重复解释,落点与本章功能、下一章承接一致
references/long-chapter-quality.md›
# 长篇章节质量检查清单
## 目录
- [一、通用检查](#一通用检查)
- [二、长篇专项](#二长篇专项)
## 一、通用检查
### 章节结构
- [ ] 开头有钩子(不是天气/风景/日常开场)
- [ ] 中段有推进(快节奏题材要有可见事件;慢热题材状态变化即可)
- [ ] 局势有变化(读完这章,世界跟之前不一样了)
- [ ] 结尾落在变化上(不是总结)
### 开篇检查(前 300-500 字)
- [ ] 有钩子,能抓住注意力
- [ ] 不从天气/风景/日常开始
- [ ] 主角快速出场
- [ ] 卖点或危机可见
### 章节推进
- [ ] 本章至少改变目标 / 风险 / 信息 / 关系 / 资源 / 身份 / 情绪立场七类状态之一;快节奏(番茄/爽文)应有可见事件或爽点,慢热/情感文才可只靠低压小变化达标,不强求每章高潮
- [ ] 不是水字数(删掉这章会损失哪项状态变化?答不出才需压缩)
- [ ] 任务卡点有用:卡住之后是否带来上述状态变化?
- [ ] 推进强弱是否符合本书已建立的题材、兑现节奏与对标,而非套固定通用字数
### 信息传递
- [ ] 没有大段设定说明文
- [ ] 信息跟着冲突走(通过事件传递设定)
- [ ] 设定量可控(一章不超 3 个新概念)
### 场景检查
- [ ] 场景有目标(人物要什么)
- [ ] 场景有阻碍(什么挡着)
- [ ] 场景有变化(结束后跟之前不同)
- [ ] 人物在做事情,不是在感觉事情
- [ ] 没有可删除的段落
### 章尾
- [ ] 结尾落在变化上
- [ ] 有危机/决定/发现/反转中的至少一个
- [ ] 不是总结式结尾
- [ ] 拉住读者翻下一页
### 语言
- [ ] 没有空洞的抒情段落
- [ ] 没有连续多段同一情绪
- [ ] 对话符合人物身份(不同人说话方式不同)
- [ ] 情绪通过动作落地(不是直接说"他很难过")
- [ ] 标题行以外没有章节/写作元信息:不得出现 `第[一二三四五六七八九十百千万两0-9]+章|上一章|上章|前一章|本章|这一章|前文|后文|伏笔|细纲|读者` 这类词;需要承接前文时改成角色能感知的事件锚点或相对时间;故事内真实阅读/讨论“第X章”或真实读者身份语境除外
### 连载连续性
- [ ] 没有遗忘之前的承诺/伏笔
- [ ] 没有突然塞入大量新设定
- [ ] 伏笔有推进
- [ ] 故事引擎还在运转
- [ ] 对照本章批准细纲,没有新增会影响后续的独立事件、人物决定、关系变化、揭示或支线;闲话、即时反应和服务既有情节点的微连接不算,新的饭局、承诺、选择、结果或后续义务属于 blocking
### 水(filler)检测
以下信号出现 = 可能水了:
- 全章对话没有任何新信息
- 同一个情绪写了 3 段以上
- 场景描写超过 500 字但不推进剧情
- 角色回忆之前发生的事但没有任何新视角
- 连续 2 章以上没有冲突
- 删掉无损的流程细节 / 任务卡点 = 水;压缩或删除
---
## 二、长篇专项
### 黄金三章检查
- [ ] 第一章前 500 字有钩子?
- [ ] 主角第一章就出场?
- [ ] 第一章有事件(不是纯铺垫)
- [ ] 第二章有升级(矛盾加深)
- [ ] 第三章有追读理由(给出继续看的动力)
- [ ] 前三章有至少 2 个爽点?
- [ ] 世界观没有大段说明文?
- [ ] 每章结尾有往下看的理由?(低压/过场章弱钩子或阶段目标即可,不强求强悬念)
### 节奏检查
- [ ] 最近 5 章是否有明确进展?
- [ ] 爽点间隔是否超过 5000 字?(按章节定位:高压/推进章查间隔;低压/关系/信息整理章不计入)
- [ ] 有没有连续 2 章以上没有冲突?(呼吸章正常;红线是连续两章压力级≤1 或相邻章情绪趋同)
- [ ] 一卷是否有章节定位高低层次,没有全程同一力度?低压+过场是否克制(合计不超约 15%)?
### 人物检查
- [ ] 主角行为符合人设?
- [ ] 配角是否有存在感?
- [ ] 反派逼格是否匹配当前阶段?
### 五维评分标准
每个维度 0-100 分,根据评分结果选择精修策略。
### 维度 1:核心一致度
检查:关键冲突、关键行动、人物动机是否前后一致。
| 问题 | 严重度 | 修复 |
|------|--------|------|
| 人物动机突然改变无铺垫 | critical | 补充动机转变的触发事件 |
| 核心冲突前后不一致 | high | 回溯修改冲突设定 |
| 关键行动与人物性格矛盾 | high | 调整行动或补充解释 |
| 次要矛盾遗忘 | medium | 回收或弱化 |
### 维度 2:表层重写度
检查:句式与措辞是否足够原创,避免套路化表达。
| 问题 | 严重度 | 修复 |
|------|--------|------|
| 照搬原句导致语气不自然 | medium | 只在确有 AI 腔时改写,正常原句可保留 |
| 大量使用 AI 标志词 | high | 替换为具体描述 |
| 同一句式重复出现 | medium | 变换表达方式 |
| 描写过于文学化(辞藻堆砌、书面腔、比喻成串) | medium | 改为口语化/动作化;动作化不是切成三五字短句串,改写后叙述仍以逗号长句为主 |
### 维度 3:格式一致度
检查:段落是否按戏剧单元/镜头自然断开,主语/角色名节奏是否自然,开头结尾格式是否统一。
| 问题 | 严重度 | 修复 |
|------|--------|------|
| 机械按字数切段或主语过密 | medium | 按戏剧单元重排段落,段首点名、段中代词/省略、关键转折再点名 |
| 章节字数偏离目标 | **high** | 写作/大纲修复时先回到细纲补足计划内情节点,再展开;去AI味已有正文时不得新增剧情 |
| 格式混乱(对话/描写不统一)| low | 统一格式 |
### 维度 4:可读性
检查:是否有啰嗦、AI 腔、空泛总结、套路修辞。
| AI 腔特征 | 如何识别 | 如何修复 |
|-----------|----------|----------|
| 空泛总结 | 「他终于明白了」「一切尽在不言中」 | 删掉,用行动代替 |
| 套路修辞 | 「命运仿佛在和他开玩笑」 | 删掉或换成具体描述 |
| 比喻堆叠 | 连续多处「像/好像/仿佛/如同」,每个画面都靠比喻解释 | 只留最有叙事功能的少数比喻,其余改成动作、物件、声音或后果 |
| 情绪标签 | 「他感到一阵悲伤」 | 改为行为表现 |
| 心理描写空转 | 内心独白无新信息、重复同一情绪或复述读者已知 | 只压缩空转部分;带新信息、决断或情绪转折的独白不按句数压缩 |
### 维度 5:逻辑连贯
检查:句间/段间是否通顺,有无设定冲突。
| 问题 | 严重度 | 修复 |
|------|--------|------|
| 设定前后矛盾 | critical | 查找并统一设定 |
| 时间线错误 | high | 标记时间线并修正 |
| 角色信息不一致 | high | 建立角色档案对照 |
| 因果链断裂 | medium | 补充过渡 |
### 精修策略
根据五维评分结果,选择精修策略:
| 主要问题 | 策略 | 说明 |
|----------|------|------|
| 核心一致度低 | rewrite | 围绕核心冲突重写相关段落 |
| 字数超标 | compress | 删减不推动剧情的内容 |
| 无意义卡点 | compress | 保留卡出的变化,压掉流程 |
| AI 腔重 | de_ai | 替换禁用词、改写句式 |
| 小问题多 | polish | 打磨语言细节 |
### 读者契约与终局储备双向审查
参 `reader-contract-and-progression.md`。先问“无毒吗”,再问“好看吗”:**无毒不等于好看**,没有 契约破坏 只代表不踩雷,还要确认情绪兑现足够强。
- [ ] 读者契约:本章/本卷是否兑现开篇承诺,还是把核心卖点交给机构、配角或偶然性?风险标记:契约安全 / 需补强 / 契约破坏。
- [ ] 主角代理权:按因果权 + 结算权审查,而非按出场时长;用“关键节点四问”核对决定、不可替代选择、后果与核心结算。配角可执行局部动作,但不能无声夺走期待所有权。
- [ ] 期待债:承诺是否被偿还、延期并支付利息,还是被解释/流程/设定吞掉?
- [ ] 终局储备:本单元是否动用了本阶段还不该解锁的终局底牌(宿敌/真相/身份/金手指上限)?是否让某条升级线逼近天花板、后面没台阶接?两问皆否即放行——单章一战多得(多线齐涨)是好设计,不算超速。
- [ ] 兑现归属:期待所有权是否按承诺结算;自愿让渡只有在“长期净收益为负 + 控制/因果权下降”同时出现时亮红灯,战略性让步的更大控制/未来收益/权力/信息交换是否可见?
- [ ] 节奏续接:高潮/兑现后是否允许短暂低压和小而可见的收益/奖励,而非机械立即加危机?新元素是否支付换书债、没有逃避旧承诺?
- [ ] 题材特定风险:履约爽文/能力幻想中,主角是否反复以愚蠢或可避免的无能制造灾难并由他人收拾,损害因果权与结算信任?
- [ ] 反向审查:若删除“安全解释”,情绪是否更强?若保留风险情节,是否带来更强期待、代价或爽点?
- [ ] 综合线:契约、主角代理权、期待债、终局储备是否互相支撑,而不是只做到“无毒”。
### 单元情绪因果可证伪检查
- [ ] 目标是否只有“热血/悲伤”等情绪标签,却没有前状态→触发→后状态的情绪因果?
- [ ] 承载对象是否只是等待主角解决问题的工具角色?
- [ ] 高潮是否依赖巧合或最后一刻新增设定?
- [ ] 主角的硬能力是否服务核心情绪,而非只服务自我证明?
- [ ] 个体/关系/群体兑现是否回到本书的题材契约?群体兑现只在题材需要时使用。
- [ ] 是否错把“更安全”或“获得成长”本身当成高潮,却没有情绪意义变化?
- [ ] 机制是否保持可选:不把物件、误解、反转、死亡、疾病、哭喊或群体抬升当成通用硬模板?
references/long-format.md›
# 长篇正文格式
> 只约束长篇章节的段落、对话、标点与工程元信息。短篇 `###1.` 小节、8–15 节全文结构和 500–800 字/节口径不适用。
## 章节与段落
- 章节标题、编号和文件名服从项目既有格式;正文内部不再重复章节号。
- 按戏剧单元、镜头变化、新行动、新信息或新对话自然断段,不按固定字数切段。
- 短段是节奏工具,不是默认模板;完整推理、氛围和情绪因果可以使用长段。
- 爽点、转折和关键选择写密,过场、赶路与已知信息连接写疏;不要让每个 beat 一样长。
- 段首需要时点名角色,段中使用代词、省略或动作承接;不要每句机械重复角色名。
- 正文相邻段落之间只允许一个换行符 `\n`,不得出现空行或连续换行 `\n\n`。
- 正文不缩进,不使用 ` `(全角空格)或半角空格开头。
## 对话
- 引号风格服从项目/平台约定,全章统一;未指定时使用半角双引号。
- 对话独立成行,动作承接放在同一角色的话前后,不把每句都标成“他说/她道”。
- 问号用于真实疑问、质问或反问;感叹号只留给爆发峰值,不连用。
- 停顿、犹豫、吞咽、打断或拖长用动作、短句、换行或未完成句承担;正文和对话不使用省略号、破折号作万能停顿。
- 台词必须改变信息、关系、策略或权力位置;整段设定讲解改成问答、试探、反驳或行动后果。
## 长篇章级约束
- 章级 `字数目标` 与 `visible_chars_v1` 是唯一字数口径;内部带 ±12%,用户带 ±15%,以确定性工具测量。
- 字数不足先检查细纲中批准的情节点是否全部落地,不新增独立事件、角色、规则、反转或伏笔凑字。
- 字数超标优先删除重复解释、重复反应、流程和无功能微动作,不删除批准情节点、因果、选择、兑现与钩子。
- 章节可以包含多个场景或 beat,数量由细纲和因果决定;不套短篇全文小节数。
## 工程元信息隔离
- 标题行以外,正文叙述、对话和心理描写不得出现“本章、上一章、前文、后文、伏笔、细纲、读者”等写作工程词。
- 需要承接时改成角色可感知的事件锚点或相对时间;角色在故事世界内真实讨论章节/读者身份时例外。
- 正文不使用加粗、斜体、分隔线或检查报告;合法章节标题除外。
## 交付检查
- [ ] 段落按镜头与行动变化断开,不是固定句数模板,段间没有空行、没有缩进。
- [ ] 引号、问号、感叹号和停顿方式全章一致。
- [ ] 长篇字数按章级细纲和确定性口径处理,没有短篇小节阈值。
- [ ] 正文没有写作工程元信息、自检或说明。
references/long-genre-catalog.md›
# 长篇题材框架速查
> **用途**:长篇选题和大纲设计时对照使用。节点占比用于检查整卷/全书功能分配,不是每章硬配额;短篇结构转交 `story-short-write`。
---
## 题材选择路由
根据以下条件快速定位对应框架。先判断大类,再看具体变体。
| 如果故事核心是... | 走这个框架 | 备注 |
|---|---|---|
| 男人伤害女人,离开后悔但追不回 | **追妻火葬场** | 女主离开后不回头是核心 |
| 前世惨死,重生利用信息差复仇 | **重生复仇** | 反派需分层嵌套 |
| 伴侣出轨/算计,觉醒独立 | **小三/婚恋** | 发现过程要有悬念 |
| 奇葩/恶霸欺压老实人,恶有恶报 | **世情** | 靠细节不靠大事件 |
| 女主被虐至死,男主死后追悔 | **死人文学** | 核心是"来不及" |
| 特殊相遇,男主追求宠溺 | **霸总/甜宠** | 甜的密度决定粘性 |
| 底层崛起,升级打怪(都市+武道) | **都市高武** | 金钱驱动+分层地图 |
| 废材/落魄天才,修仙世界登顶 | **仙侠/玄幻** | 力量体系必须清晰 |
| 独特金手指/创意设定为核心卖点 | **脑洞文** | 核心梗决定赛道 |
| 主角无天赋,靠谨慎算计生存(修仙) | **凡人流** | 利弊权衡是核心模式 |
| 穿越/重生到历史节点改变命运 | **历史/架空历史** | 信息差=最大金手指 |
| 娱乐圈才华展示+围观震惊 | **文娱/娱乐圈** | 反应链是核心写法 |
| 用户明确目标 IP、平台允许且近期样本有效 | **同人流派** | 只抽“已知世界 + 新变量 + 名场面改写”结构,不保留具体 IP 清单 |
| 玩家被抽入规则副本求生 | **规则怪谈**(见其他题材速查) | 金手指包合理外衣 |
| 主角长生看沧海桑田 | **长生流**(见其他题材速查) | 凡俗时期最好看 |
| 其他(西幻/新媒体/搞笑/无限流/悬疑/高武/后悔流) | **其他题材速查** | 各有要点,按需取用 |
### 定位后查阅关联文件
| 还需要什么 | 加载 |
|-----------|------|
| 核心梗设计与循环机制 | `long-genre-mechanics.md` |
| 读者心理与期待管理 | `genre-readers.md` |
| 对应长篇题材卡 | `genre-prose-cards.md` 索引及 `genre-prose-cards/` 对应题材卡 |
---
## 追妻火葬场
### 长篇(8节点)
**设定**:女主被伤害 → 离开 → 男主后悔追回但女主不回头。场景:豪门/职场/娱乐圈/古代贵族,需权力差。
**人物**
| 角色 | 弧线 |
|------|------|
| 女主 | 隐忍付出 → 心死离开 → 独立成功 → 掌控主动权 |
| 男主 | 高冷傲慢 → 后期卑微追悔,痛点要"活该但又心疼" |
| 第二男主(选配) | 温柔守候,制造男主危机感+读者情感出口 |
**8节点**
| 节点 | 内容 | 占比 | 情绪 |
|------|------|------|------|
| 1.开篇钩子 | 展示女主痛苦现状 | 5% | 压抑 |
| 2.虐待加深 | 冷漠/背叛达顶点 | 10% | 悲愤 |
| 3.女主觉醒 | 决定离开 | 10% | 痛→决绝 |
| 4.离开与新生 | 独立生活/事业 | 15% | 爽(解脱) |
| 5.男主追悔 | 意识女主重要性 | 10% | 痛快 |
| 6.事业/成长 | 新领域取得成绩 | 15% | 爽(逆袭) |
| 7.反复拉扯 | 多次求复合被拒 | 20% | 爽(打脸) |
| 8.结局 | 开放/回头/悲剧 | 15% | 释放 |
---
## 重生复仇
### 长篇(8节点)
**设定**:前世惨死→重生利用信息差逐一复仇。场景:宅斗/宫斗/商战/校园,需复杂人际网。
**人物**
| 角色 | 要点 |
|------|------|
| 女主 | 前世天真→重生腹黑,金手指=前世记忆,核心矛盾=是否变成仇人一样的人 |
| 反派层 | 小(3-10章)→中(20-50章)→大(全书),层级嵌套 |
| 盟友/男主 | 前世可能被误解,逐步信任,制造信任危机 |
**8节点**
| 节点 | 内容 | 占比 | 情绪 |
|------|------|------|------|
| 1.冲突揭露 | 前世惨死真相 | 5% | 震惊/愤怒 |
| 2.重生认知 | 梳理记忆定目标 | 5% | 期待 |
| 3.前世今生交织 | 对比被蒙蔽vs清醒 | 15% | 爽(信息差碾压) |
| 4.逐层复仇+新问题 | 打小反派揭大阴谋 | 25% | 爽→悬念交替 |
| 5.多重阻碍 | 中反扑+信任危机 | 15% | 紧张 |
| 6.高潮致命一击 | 终极布局对决 | 15% | 爽(最高潮) |
| 7.反派下场 | 逐一报应 | 10% | 爽(宣泄) |
| 8.新生活 | 选择新方向 | 10% | 治愈/释然 |
---
## 小三/婚恋
### 长篇(8节点)
**设定**:发现伴侣出轨→觉醒→独立→惩恶扬善。场景:现代都市/家庭,强代入感日常。
**人物**:女主(家庭主妇/职场→独立) | 渣男(精神/肉体出轨/转移财产/家暴/PUA,程度递进) | 第三者(选配,催化矛盾) | 支持系统(闺蜜/家人/律师)
**8节点**
| 节点 | 占比 | 情绪 |
|------|------|------|
| 1.日常压迫/不公 | 10% | 憋屈 |
| 2.发现出轨/算计 | 15% | 震惊→愤怒 |
| 3.决定离开 | 10% | 痛→爽 |
| 4.事业重建 | 20% | 爽(成长) |
| 5.渣男纠缠 | 10% | 紧张 |
| 6.反击 | 15% | 爽(打脸) |
| 7.报应 | 10% | 爽(宣泄) |
| 8.新生活 | 10% | 治愈 |
---
## 世情
### 长篇(8节点)
**设定**:反派超常理恶行→善良者被欺压→反击→恶有恶报。场景:农村/小镇/社区/家族,熟人社会压力环境。
**人物**:主角(老实人有底线) | 反派(奇葩/恶霸/极品亲戚,恶得有创意) | 围观群众(势利眼/墙头草/少数正义)
**8节点**
| 节点 | 占比 | 情绪 |
|------|------|------|
| 1.奇葩登场 | 10% | 气愤 |
| 2.欺压升级 | 15% | 憋屈 |
| 3.压力顶峰 | 10% | 极度不平 |
| 4.第一次反击 | 15% | 爽(初爽) |
| 5.反扑 | 10% | 紧张 |
| 6.打脸 | 15% | 爽(高潮) |
| 7.报应 | 15% | 爽(宣泄) |
| 8.善有善报 | 10% | 治愈 |
---
## 仙侠/玄幻
### 长篇(8节点)
**设定**:主角遭重大打击→从低谷崛起。场景:修仙/玄幻世界,需清晰力量等级体系。
**人物**:主角(废材/落魄天才→登顶,金手指=特殊体质/传承/系统) | 反派层(同辈→长辈→宗门Boss→天道,维度递升) | 导师(阶段性,不能太强也不能太弱)
**8节点**
| 节点 | 占比 | 情绪 |
|------|------|------|
| 1.打击降临 | 5% | 震惊/悲愤 |
| 2.冲突深化 | 10% | 压抑 |
| 3.第一次反击 | 15% | 爽(初爽) |
| 4.最大危机 | 15% | 极度紧张 |
| 5.突破/成长 | 10% | 爽(逆袭) |
| 6.致命一击 | 15% | 爽(高潮) |
| 7.报应/清算 | 15% | 爽(宣泄) |
| 8.新征程 | 15% | 期待 |
**关键维度**:力量体系清晰不崩 | 金手指独特有限制随成长 | 战斗有策略非纯数值 | 地图逐层展开 | 升级节奏均匀
---
## 死人文学
### 长篇(8节点)
**设定**:女主被虐待至死→男主追悔→真相揭开→报应。场景:豪门/古代贵族/娱乐圈,权力差极大化。
**人物**:女主(隐忍善良→死亡,死后影响>生前) | 男主(冷漠→死后空洞→真相→痛不欲生→终生赎罪) | 幕后黑手(选配,增加反转)
**8节点**
| 节点 | 占比 | 情绪 |
|------|------|------|
| 1.层层虐待 | 20% | 极度压抑 |
| 2.女主死亡 | 5% | 极度悲痛 |
| 3.后悔开始 | 10% | 压抑→不安 |
| 4.真相发现 | 20% | 痛心 |
| 5.幕后黑手 | 10% | 震惊/愤怒 |
| 6.报应 | 15% | 爽+痛 |
| 7.因果终结 | 10% | 释放 |
| 8.余韵结局 | 10% | 意难平 |
---
## 都市高武
### 长篇(分层地图结构)
**设定**:底层穷学生/武者→升级打怪挣钱→更高层级。场景:现代都市+武道体系,学校/武馆/武道厅/军部多条线。
**人物**:主角(钱是核心驱动,学校→武馆→武道厅→军部→星际) | 配角层(同学/导师/感情线/校霸) | 反派层(校霸→地下势力→邪魔→跨国→外星)
**分层地图事件池**
| 地图 | 可用事件 |
|------|----------|
| 学校 | 天才班、月考、联考、高考、校霸对决、校花剧情、助学金 |
| 武馆 | 获赏识、传承武学、师兄对决、市/省/国联赛 |
| 警局/治安 | 劫匪、邪魔、副本、城内Boss |
| 大学 | 学校事件升级版 |
| 武道厅/军部 | 武馆事件升级版 |
| 星际 | 全国事件升级版+世界观扩张 |
**关键**:金钱驱动反复挂钩 | 换地图用过渡人物连接 | 10万字前数据偏弱是常态 | 前三章=底层处境→金手指→第一次展示
---
## 霸总/甜宠
### 长篇(五阶段)
**设定**:特殊相遇→男主追求→感情升温→外部阻力→化解。场景:豪门/商界/上流社会。
**五阶段**
| 阶段 | 内容 | 情绪 |
|------|------|------|
| 1.相遇 | 男主被女主某特质吸引 | 新鲜 |
| 2.追求 | 用身份/财富制造便利,闺蜜震惊 | 甜/爽 |
| 3.确认 | 女主心动走到一起 | 满足 |
| 4.阻力 | 家族/前女友/商业对手 | 紧张 |
| 5.化解 | 共同克服,感情升华 | 爽/治愈 |
**人物**:男主(强势专一宠溺,用权力/财富为女主做事=代入核心) | 女主(不能花瓶,要有让男主"非她不可"的戏剧性) | 阻力方(家族长辈/前女友/商业对手)
**关键**:甜的密度决定粘性 | 宠要"别人做不到的方式" | 阻力不能太强(虐就跑偏)不能太弱(没张力) | 女主要独立闪光点
---
## 同人流派
### 核心机制
借用已有IP世界观和角色写新故事。核心卖="如果在这个世界里有主角会怎样"。
### 使用边界
不保留具体 IP 题材清单。只有用户明确目标 IP、平台允许且近期样本有效时,才抽取“已知世界 + 新主角变量 + 名场面改写”的结构功能。
### 写法要点
- 读者大多"云爱好者":没看过原著的比看过的多,硬核非必要
- 爽第一:不为还原原著牺牲爽感
- 时代设定可简化,适度改编不影响阅读;但人物命名不脱离原著的地域和文化——原著角色用官方本名/译名,新角色顺对应地域的命名风格,别混语系或塞与设定不符的现代化/政治化名字
- 优势:自带世界观省铺设定 | 风险:原著粉考据挑刺
- 深层写法:装逼背后加亲情/救赎/遗憾弥补;震惊不止"太强了"还有激动/后悔/释然
### "造反后方知"流派
主角在自己世界做到巅峰后发现身处某IP世界。书名公式:[达成某成就],方知是[某IP世界]。
---
## 脑洞文
### 核心机制
以独特金手指/创意设定为核心卖点,题材只是外壳,真正卖点落在"这个点子"。
### 创作流程
获得点子→判断潜力(有遐想空间=有潜力)→选适配题材→加工为情绪缺口→设计金手指骨相→构建卖点→主线→框架→单元剧情
### 金手指骨相分类
| 类型 | 机制 | 示例 |
|------|------|------|
| 条件触发型 | 满足X→获得Y | 摸尸得宝、签到得奖 |
| 多条件阶段型 | 多条件→阶段升级 | 收集碎片、完成成就 |
| 逆向型 | 失去X→获得更强Y | 越惨越强、负债越有钱 |
### 写长方法
核心卖点确定后多套路交织循环;单元故事围绕一个套路展开,主线串联;一级结构循环(模式重复但对象/场景/规模升级)
### 脑洞四类
1. 金手指类(聊天群/系统/戒指老爷爷)
2. 剧情类(反转/设定)
3. 设定类(世界观/修行体系)
4. 角色类(身份/人设)
**忌**:全盘照抄必扑;核心梗决定赛道和受众
---
## 凡人流
### 核心特征
主角无特殊天赋/背景,靠谨慎、机智、利弊权衡在残酷修仙世界生存。
### vs 传统升级流
| 维度 | 凡人流 | 传统升级流 |
|------|--------|-----------|
| 天赋 | 普通/低劣 | 天才/特殊体质 |
| 金手指 | 微弱或没有 | 强力系统/传承 |
| 行为 | 谨慎算计逃跑优先 | 热血正面对抗越级挑战 |
| 爽点 | 智商和准备碾压 | 实力碾压 |
| 节奏 | 慢热细腻伏笔多 | 快节奏爽点密 |
### 副本切入公式
小配角出场→小配角故事→透露副本信息→主角决定进入
### 关键维度
主角谨慎必须真实(不能嘴上说谨慎行为疯狂) | 利弊权衡是核心模式 | 配角有独立利益考量 | 伏笔和回收要精巧
---
## 历史/架空历史
### 长篇
**设定**:穿越/重生到历史节点,利用现代知识/信息差改变命运。
**子类型**
| 类型 | 核心卖点 | 写法要点 |
|------|----------|----------|
| 科举文 | 现代知识碾压古代考试 | 诗词装逼、仕途攀升、权谋 |
| 军史文 | 现代军事知识改造古代战争 | 练兵、装备改革、以少胜多 |
| 经营/种田 | 古代搞经济建设 | 技术引进、商业帝国、改善民生 |
| 国潮/非遗 | 传统文化魅力 | 盘点式装逼、民族自豪感 |
**关键**:大部分读者是"云爱好者"爽感优先于还原度 | 现代认知信息差=最大金手指 | 架空可降低门槛 | 盘点+历史共鸣感强
---
## 文娱/娱乐圈
### 核心机制
主角在娱乐圈发展,核心爽="才华展示+围观者震惊"。
### 子类型
| 类型 | 特点 | 现状 |
|------|------|------|
| 华娱 | 国内娱乐圈 | 主流,精品最多 |
| 韩娱 | 韩国娱乐圈 | 小众 |
| 架空文娱 | 虚构娱乐圈 | 单女主居多,系统直接给奖励 |
### 写作要点
才艺展示=最核心装逼场景,写观众/评委/对手反应链 | 可结合盘点文模式 | 架空虚构明星避免真人争议自由度更高 | 金手指模糊化处理(先知性后期会冲突,用"梦"等方式自洽)
### 进阶
配角情景剧:主线之间填充日常,设定在某个空间里几个角色产生化学反应 | 共情反差法:角色可高高在上但不能让读者产生距离感,所有角色必须有一份普通人特质
---
## 其他题材速查
### 规则怪谈
类无限流,玩家被抽入规则副本冒险求生。绑定国运+直播性价比最高。副本构建:背景故事→规则包装→通关线+dead end→节奏(别人死→主角装→揭露→升华)。番茄主流走爽文路线,智斗和金手指负责包合理外衣。
### 长生流
核心卖=时移世易沧海桑田,主角长生看别人浴血搏杀。凡俗时期最好看。天然缺陷:开始修仙后实力增长→身边同级别出现→"熬时间"失去意义→变成寻常修仙文。延续方向:保持时间碾压感/代际传承/分层世界/凡俗时期充分展开。
### 西幻/骑士文
西幻=东方玄幻内核换皮。骑士自带晋升属性是天然力量体系骨架。推荐DND式/巫师式/种田领主文,不写日式奇幻。开篇从低位开始(马奴/铁匠学徒),凿壁偷光式努力。
### 新媒体文
一切为情绪服务。第一情绪对:不爽→装逼/愤怒→解气。双向结构=强+虐(反差/矛盾)。矛盾必须源于现实逻辑。核心三重点:用梗+节奏+情绪。极致信息差=强烈期待感。
### 搞笑文
两大原则:搞笑必须符合逻辑(规则之内出人预料);玩梗要化用内核不是照搬。自己先觉得爽;主角身边人无条件对主角好。
### 无限流
游戏副本式结构(20-30章一个副本),每个副本自成一故事;设现实主线保底串联副本。
### 悬疑
核心靠铺垫+氛围描写营造悬疑感,非靠血腥暴力。信息释放节奏要控好。
### 高武
爽点相对单一(升级打怪)但套路成熟不易翻车。可高仿成功作品世界观架构降低门槛。
### 后悔流
避免退婚等老套外衣,需创新包装(后悔对象可从爱情转为事业选择/人生抉择)。
---
## 长篇设计提醒
| 检查项 | 说明 |
|--------|------|
| 题材识别 | 属于哪个框架?有无跨框架混搭? |
| 节奏比例 | 节点功能是否在对应卷/全书阶段出现,偏移是否有题材或人物因果支持? |
| 反转位置 | 是否在阶段旧认知已经支撑过行动、且揭示后仍有后果空间时出现? |
| 钩子密度 | 高压、推进、低压章节是否形成张弛,期待链有没有断? |
| 字数效率 | 有无废段落?哪些可删? |
| 情绪落点 | 读完最后一句是什么感觉? |
---
## 质量检查清单
每次使用本手册完成长篇定位或大纲后,逐项核对:
| # | 检查项 | 通过标准 |
|---|--------|----------|
| 1 | **题材定位正确** | 已通过路由表确认框架,无模棱两可 |
| 2 | **结构功能完整** | 8节点/5阶段承担的功能齐全;实际比例服从题材、卷功能与人物因果,不按固定 ±5% 判死 |
| 3 | **情绪节拍完整** | 压抑→爆发→释放的完整情绪弧线存在,无断层 |
| 4 | **人物弧线明确** | 主角有清晰的起点和终点变化;反派有独立动机不是工具人 |
| 5 | **期待链不断** | 章节强弱符合定位;回收旧期待前已经建立下一层期待,不按固定字数配钩子 |
| 6 | **金手指自洽** | 金手指规则明确,使用有限制,后期不崩 |
| 7 | **信息差利用到位** | 有读者知道但角色不知道、或角色知道但对手不知道的信息差设计 |
| 8 | **技法匹配题材** | 已对照对应题材的"技法"条目,无遗漏 |
| 9 | **无废段落** | 每段都推进情节或深化人物,无纯填充 |
| 10 | **结局情绪对位** | 结尾情绪与题材核心匹配(爽文=释放/治愈;虐文=意难平/余韵) |
references/long-genre-mechanics.md›
# 核心梗解析与微创新设计
> **用途**:核心梗三层递进设计(主题→题材→情绪),微创新五法、冲突网络、金手指匹配、事业线/爱情线设计。构思和验证大纲时对照使用。
> **语气**:指令式——每个原则都是"必须做到"的硬规则,违反就有明确后果。
> **配合**:长篇题材结构与声线见 genre-prose-cards.md,读者画像见 genre-readers.md。
---
## 决策路由:按设计阶段选工具
> 构思大纲时按阶段推进,每个阶段用对应的工具核对。
| 设计阶段 | 要做的事 | 对应章节 |
|---------|---------|---------|
| 定核心梗 | 确定主题、题材核心、核心情绪三层 | 核心梗三层递进设计 |
| 检验核心梗 | 确认没有偏离、没有挂羊头卖狗肉 | 每章循环检查 + 检验清单 |
| 微创新 | 在模板边界内做差异化,不超过3个点 | 微创新与差异化设计 |
| 建冲突网络 | 铺设纵+横+交叉三层矛盾 | 冲突网络设计 |
| 选金手指 | 金手指与世界观压迫度匹配 | 金手指与世界观匹配 |
| 做事业线/爱情线 | 铺骨架和藤蔓,控制比例 | 事业线/爱情线设计 |
| 防崩盘 | 检查卖点偏移、题材匹配度 | 卖点偏移检验 |
---
## 核心梗三层递进设计(主题→题材→情绪)
三代指**迭代层次**,一本小说通常由2-4条核心梗融合。
### 一代:主题/中心思想
| 维度 | 说明 |
|------|------|
| 定义 | 小说的主题和中心思想 |
| 作用 | 赋予目标和立意,防止偏离核心 |
| 关键 | 没有主题=立意不明确=文字干巴巴没情绪 |
主题在不同阶段可有不同表现,不一定只有一个。
### 二代:题材核心
| 维度 | 说明 |
|------|------|
| 定义 | 该题材独有的核心吸引力 |
| 作用 | 筛选读者、划定边界、产生氛围感 |
| 提取法 | 看同题材火书的核心卖点和核心情绪 |
**核心原则:偏离题材核心=抛弃吸引读者的最大依仗,在读直线下降。**
偏离案例:
| 作品 | 题材 | 偏离 | 后果 |
|------|------|------|------|
| 《一级一个金词条》 | 都市高武 | 对比对象从地球人跳到异世界神 | 在读直线下降 |
| 《普攻永久加生命》 | 网游文 | 走出新手村后仍和NPC打 | 热度持续下滑 |
### 三代:核心情绪
| 维度 | 说明 |
|------|------|
| 定义 | 一种核心情绪体验(扮猪吃虎/弥补遗憾/莫欺少年穷等) |
| 作用 | 筛选读者、提升戏剧性 |
核心情绪不等于爽点表现形式。装逼打脸只是形式,核心梗是完整的情绪链条(期待→满足)。
### 剧情构建顺序
**核心卖点 → 情绪套路 → 具体剧情**
先确定核心情绪(读者要看什么),再设计情绪套路(怎么让读者感受到),最后设计具体剧情(用什么事件)。
### 核心梗定义
核心梗=金手指最核心的使用方式+读者最想看的爽点模式。金手指是工具,核心梗是最有趣的使用方式。核心梗可平替:女帝→朱元璋→嬴政,背景任意置换。
### 每章循环检查
每章必备三选一:①拥有核心梗相关的期待点 ②拥有核心梗相关的爽点 ③介于期待点和爽点之间。
**断期待的判断**:某章既无期待点也无爽点,前一爽点已结束,本身没拉起新期待→读者觉得书失去了"灵魂"开始弃书。
**两种运转模式**:
- 不断循环型:每个一级结构运行一次,变奏场景/对象/条件
- 只运行一次型:围绕一个核心情绪分阶段推进
### 检验清单
- 读者翻开最想看什么?(核心梗)
- 每个剧情单元是否在展示核心梗?
- 核心梗爽点模式能否循环?
- 有无挂羊头卖狗肉?
- 全文每章是否满足三要素中至少一个?
### 常见误区
| 误区 | 表现 |
|------|------|
| 核心梗太多 | 什么都想写=没有核心梗 |
| 立意不明确 | 没有情绪目标,文字干巴巴 |
| 纯装逼打脸无主题 | 剧情没有意义 |
| 核心梗用完不升级 | 生硬重复,审美疲劳 |
| 挂羊头卖狗肉 | 书名暗示与实际内容不符 |
### 偏离核心梗的典型案例
| 作品 | 偏离方式 | 后果 | 改善方向 |
|------|----------|------|----------|
| 《完美世界》 | 后期核心情绪崩塌 | 月票直线下降 | 独断万古可以但要有实质收获 |
| 《十方武圣》 | 杀光所有人换地图 | 核心情绪崩坏,留存风险显著升高 | 换地图不要清空旧角色资产 |
| 《诡舍》 | 所有角色成工具人 | 高开低走 | 身边人遭遇危机后最终克服 |
| 《一人镇守孤城》 | 始终沉浸悲壮无变化 | 读者麻木 | 穿插其他情绪 |
**关键原则**:悲情不需通过身边人死绝体现,多创造挫折即可。刀人是手段不是目的。主角目标必须让读者觉得有意义。
### 悲剧命运改写法
1. 选取悲剧原型
2. 选取切入点(主角介入时间节点)
3. 选取装逼方式
4. 敲定贯穿表现力的道具
5. 选取参与配角(不超5人)
6. 重塑事件,构想改写命运画面
7. 处置悲剧变喜剧反转+主角收获+下一故事引子
核心:把行侠仗义具体化,打怪装逼高尚化,改写命运命题小白化——融为一体。
---
## 微创新与差异化设计
创新范围限制在:**人物、人物关系、情节。最多3个微创新点。** 不能超出模板内容边界。
### 灵感源头
| 阶段 | 来源 | 方法 |
|------|------|------|
| 前期 | 标签系统 | 热门标签交叉组合 |
| 中期 | 热搜/评论区/弹幕 | 高频话题提炼 |
| 后期 | 电影/游戏 | 视觉化叙事、交互式体验 |
### 标签系统
每个标签评估四维度:
| 维度 | 说明 | 权重 |
|------|------|------|
| 兼容度 | 能和多少其他标签组合 | 高 |
| 影响度 | 对故事整体影响深度 | 中 |
| 新鲜度 | 多久没被大量使用 | 高 |
| 喜爱度 | 读者偏好 | 中 |
选标签策略:**高兼容+中等影响+高新鲜度=最佳切入点**
### 70/20/10元素法则
- 70%来自过去经历和记忆(共同代际记忆/流行文化)
- 20%来自当前生活状态(工作/爱好/感情)
- 10%来自时事热点话题和趋势
### 五种微创新手法
| 手法 | 核心 | 示例 |
|------|------|------|
| 精炼法 | 把已有套路做到极致 | 打脸一巴掌→三巴掌层层递进 |
| 升级法 | 框架不变元素升级 | "公司"→"跨国集团","校花"→"国民校花+学霸+隐藏身份" |
| 加料法 | 已有框架加新元素 | 重生+规则怪谈,种田+末日 |
| 反套路法 | 反过来写 | 废材逆袭→天才跌落重新站起 |
| 组合法 | 两个不相干套路组合 | 种田+修仙,系统+悬疑 |
### 微创新检查清单
- [ ] 创新点是否在3个以内?
- [ ] 是否在模板内容边界内?
- [ ] 是否影响读者核心期待?
- [ ] 是否有足够素材支撑?
- [ ] 是否增加了创作难度?
### 冲突网络设计
好的长篇至少3层矛盾同时运作。
**矛盾类型**
- 纵向(上下级):控制与服从/压制与反抗/师徒/君臣
- 横向(平级):理念冲突/资源争夺/同行/情敌/竞争对手
- 交叉:A和B矛盾,B和C矛盾,A和C因此也产生矛盾
**编织顺序**:定地图→定阵营→定角色→对齐阵营填充纵+横矛盾→推理交叉矛盾
### 换瓶不换酒三条路径
| 路径 | 做法 |
|------|------|
| 换世界观 | 相同节奏和金手指换到不同题材 |
| 换职业/元素 | 世界观固定,不同职业或问题解法 |
| 加新机制 | 已有框架加入读者熟悉但网文中新鲜的元素 |
### 界限感扩容技术
融合多种题材元素时用"更大的圆"圈在一起:
1. 找统一解释(覆盖所有元素的框架)
2. 利用界限服务主角(不同题材边界差=信息差和优势)
3. 原创替代搬运(经典角色为原型创作,非直接拿)
### 信息操控意识
时刻思考:①读者看书前已知什么?②看设定后已知什么?③看完剧情后已知什么?操控读者已知的东西是解决剧情设计困境的核心方法。
### 金手指与世界观匹配
| 世界观类型 | 压迫特征 | 适配金手指 |
|------------|----------|------------|
| 极道流(原教旨) | 阶级固化+环境恶劣 | 无条件强行升级(加点流) |
| 极道流(改良) | 压迫感降低 | 熟练度变种(花哨但底层肝) |
| 常规升级流 | 换地图升级 | 碎片化/解锁型 |
| 轻松日常流 | 低压迫 | 人际关系/种田型 |
**功能单一金手指风险**:解决矛盾模式单一,只适用于强压迫世界观,其他题材硬用必须找补。
### 认知差异核心梗
主角视角"理所当然"vs旁人视角"不可思议"形成张力。配合无敌流效果最佳。
| 场景 | 主角视角 | 旁人视角 |
|------|----------|----------|
| 无敌流 | 死了复活没啥 | 这人比诡异还诡异 |
| 幕后流 | 随手布置 | 幕后boss深不可测 |
| 迪化流 | 想帮茶农卖茶 | 他在下大棋 |
### 基调/氛围感贯穿原则
全文基调必须贯穿如一,变了=换了一本书。人设性格变化不等于基调变化。金手指发展不能破坏基调。
### 故事构思四法
| 方法 | 核心 |
|------|------|
| 发散法 | 以逻辑起点为基础发散出大量爽点 |
| 联系法 | 将两个跨度大的素材关联想象,跨度越大戏剧性越强 |
| 去常态法 | 取人事物特征反常化(恰恰相反/极端化) |
| 点推法 | 在散碎故事间建立逻辑联系串联完整故事 |
**组合流程**:灵感→联系法/去常态法处理→发散法基于处理后灵感发散→点推法串联
### 爽点阈值递升原则
后一个剧情的情绪满足必须高过前一个。
**递升维度**:影响力范围扩大 | 人物层级升高 | 收获价值增大 | 认知颠覆加深
**递升失效信号**:读者对相似规模爽点不再反应 | 主角升级无差异化展示 | 人际网没随等级变化
### 男女频核心梗差异
| 维度 | 女频 | 男频 |
|------|------|------|
| 核心任务 | 精细化一个卖点 | 深挖可复用运转逻辑 |
| 字数支撑 | 短中篇,一个梗写透 | 长篇大长篇,逻辑反复运转 |
| 创新重点 | 同一卖点新表达 | 底层情绪机制新组合 |
| 拆解方法 | 拆一本书的精彩点 | 拆一本书的运转机制 |
### 模拟文结构
**单元**:模拟制造情绪缺口→模拟后得奖励(形成信息差→拉期待)→现实满足
**卷纲**:模拟得知大危机→[模拟+得奖励+现实推进]循环→核心危机未解决→达成最终满足
### 同人深层情绪写法
装逼震惊之下加更深层情绪:亲情/救赎/遗憾弥补。原著人物震惊不止"太强了"还有激动/后悔/释然。重新认识熟人有代价,震惊熟人效果远高于震惊陌生人。
---
## 事业线/爱情线设计
### 执行规则
- 事业线是长篇骨架,爱情线是藤蔓。天花板取决于事业线质量
- 主线要落成一件事;升级只是达成目标的行为,不能顶替主线本身
- 《斗破》主线="被退婚→上云岚宗复仇",《全职》主线="被辞退后重回巅峰"
### 事业线要点
- 事业线本质="主角从弱变强的过程"
- 每阶段有明确目标和对手,完成后难度升级
- 没有事业线时抽取有共鸣的人生主线(高中/大学最有效)
### 爱情线四阶段
| 阶段 | 内容 | 爽点 |
|------|------|------|
| 萍水相逢 | 展示外貌/性格/他人评价/习惯 | 新鲜感 |
| 怦然心动 | 产生好感注意对方存在 | 期待感 |
| 暧昧升温 | 互动增多关系微妙变化 | 最强拉扯感 |
| 确认关系 | 突破窗户纸 | 满足感 |
### 爱情线推进技巧
- **关系拉扯**:推进和拉开交替,不能只拉近。扯开可用心有芥蒂/暂时冷静/误会,避免直接分手
- **英雄救美**:男主事业线行为无意间救女主→女主倒追(非白给)
- **误会**:制造隔阂延缓推进,也是装逼打脸工具
- **窗户纸事件**:好感度质变→关系阶段变化,事业线为主的放在一级结构小高潮
### 狗粮文循环
不能模仿升级文突破模式(牵手/接吻/上床是一次性的)。正确循环:稳定人设组合+变化情境=无限可用套路(复用短视频固定流程模式)。感情升温通过共同困境/互相理解/意外发现,非身体接触升级。
### 事业线与爱情线平衡
- 互相促进:事业为爱情提供场景和冲突,爱情为事业增加牵挂
- 九一开原则:事业线为主的文爱情线最多占一成,且必须为事业线服务
- 核心观感必须一致,观感偏移=核心梗偏移
### 男频感情线特殊规则
- 不写拉扯式恋爱,不能写男主追女人为女人付出
- 正确逻辑:男主追求事业→无意间英雄救美→女主倒追
- 女主倒追vs白给:区别在于是否有说服力的铺垫
- 读者目的:收获现实中缺失的异性情绪价值补偿
### 后宫与炒股
结构共性:中间写法一致(逐个暧昧不确认关系,结局确认)。后宫规则:不能和一个确认后再攻略下一个(显渣男)。修罗场三处理:一笔带过/关联回事业线(最推荐)/被害人设梗。炒股结尾可选择开放性结局。
### CP行为分级体系
好感度越高CP行为越亲密/深入,不能跨阶段。
| 级别 | 行为 | 表现 |
|------|------|------|
| 1 | 主动亲密 | 肢体亲密接触及以上 |
| 2 | 主权行为 | 争风吃醋、宣示主权 |
| 3 | 信赖行为 | 无条件分享秘密、绝对信任 |
| 4 | 安抚行为 | 敏锐察觉负面情绪并主动安抚 |
| 5 | 特殊待遇 | 对待方式与其他人完全不同 |
| 6 | 优先特权 | 做决定时对方是最重要因素 |
| 7 | 默契行为 | 不约而同、无需交流自然配合 |
### 爱情线底层逻辑
**友情vs爱情**:恋爱双方必须在持续低烈度"斗争"底色上实现鸡毛蒜皮互相妥协达成共识,爱情"存异"区间比友情小很多。
**四检查原则**:
1. 人物决策时"男/女人"成分是否超过"人"的成分?超过时有无足够外部条件?
2. 突出性别特质描写是否匹配基础性格/成长经历/身份地位?
3. 避免完全靠外部因素推动,加入更多内生动力的碰撞
4. 不会写就按挚友写再修正(挚友改写法)
---
## 卖点偏移检验
### 防崩盘三检查
1. 能否用一句话说清题材核心卖点的目标情绪
2. 卖点是否能拆出至少5个不重复的剧情展开方向
3. 卖点展开所需的核心能力是否可由已有写作方法论覆盖
### 题材选择与知识领域匹配
| 步骤 | 操作 |
|------|------|
| 1 | 评估自身专业知识储备和了解深度 |
| 2 | 评估能否构建符合的价值观和世界观 |
| 3 | 检验对该题材社会运行规律的了解 |
| 4 | 确认文字能否让读者代入 |
### 金手指设计进化方向
| 阶段 | 特征 |
|------|------|
| 1.0 | 纯极道加点(深蓝系统) |
| 2.0 | 加点+探索+装备合成 |
| 2.5 | 熟练度变种+多机制融合 |
| 3.0 | 核心机制+副功能引出剧情 |
### 赛道选择
不要直接冲大众赛道。选自带流量但竞争少的赛道做区别化。扩宽时新作与老作要有重叠要素保留老读者。案例路径:动画宝可梦→都市宝可梦→都市原创御兽→仙侠御兽→纯仙侠,每步有重叠。
### 脑洞金手指创新:错位系统
- 时间错位:都无敌了逆袭系统才来
- 环境错位:正常世界觉醒末世系统
- 人员错位:本应寄生皇帝的寄生在了皇后身上
- 错位→落差→戏剧性
### 脑洞分类
1. 金手指类脑洞(聊天群/系统/戒指老爷爷)
2. 剧情类脑洞(反转/设定)
3. 设定类脑洞(世界观/修行体系)
4. 角色类脑洞(身份/人设)
创造阶段:金手指→金手指+角色→+设定→四类全创→相辅相成。不要跨阶段。
### 核心卖点开发流程
得到点子→思考开发潜力→放入合适题材→提炼核心卖点→通过设定加工为情绪缺口/读者期待→梳理故事雏形→动笔验证
---
## 质量检查清单
> 大纲完成后逐项核对。全部通过才算合格。
- [ ] **核心梗明确**:能用一句话说出"读者翻开最想看什么",不是泛泛而谈
- [ ] **三层递进齐全**:主题(立意)→题材核心(吸引力)→核心情绪(体验链条)三层都有定义
- [ ] **每章不离梗**:每章至少有期待点或爽点之一,无"断期待"空白章
- [ ] **偏离预警**:对比"偏离案例"表格,确认没有同类偏离
- [ ] **微创新不超3个**:创新点在人物/关系/情节范围内,数量不超过3
- [ ] **冲突三层铺满**:纵向+横向+交叉矛盾至少各有1条在运作
- [ ] **金手指匹配世界观**:金手指类型与世界观压迫特征对应,功能单一金手指有补丁
- [ ] **爽点阈值递升**:后一个爽点在影响力/层级/收获/认知至少一个维度上超过前一个
- [ ] **事业线/爱情线比例**:事业线为主的文爱情线不超过一成,且爱情线为事业线服务
- [ ] **基调贯穿**:全文基调一致,金手指发展没有破坏基调
- [ ] **卖点不偏移**:书名、简介、开头前3章传递的卖点与实际内容一致,没有挂羊头卖狗肉
references/long-reversal.md›
# 长篇反转设计
> 操作手册:反转类型、嵌套反转、误导技巧、打脸节奏。按决策路由选用,按设置/揭示步骤执行,用自检清单验收。
> 反转类型枚举与拆文 `_meta.json.reversal_type` 字段一致:视角/身份/动机/时间线/信息/认知/无反转。
## 决策路由
| 你要设计什么 | 用哪种反转 | 关键操作 |
|-------------|-----------|---------|
| 角色不是你以为的人 | 身份反转 | 埋3处行为细节暗示 |
| 真相从另一个角度完全不同 | 视角反转 | 引入另一角色视角打破认知 |
| 角色做某事的原因不是你以为的 | 动机反转 | 高压场景中二选一暴露真动机 |
| 时间顺序跟读者理解不同 | 时间线反转 | 不撒谎只调叙述顺序 |
| 读者掌握了错误信息 | 信息反转 | 新证据直接否定旧"事实" |
| 读者对整个角色/关系的理解被颠覆 | 认知反转 | 全程铺感情色彩,结尾翻转色彩 |
| 甜宠/喜剧/报应型,本就没有反转 | 无反转 | 走报应兑现或甜度递进,不硬塞反转 |
| 要叠多层反转 | 嵌套反转 | 主次分明,间隔递减 |
---
## 反转类型
### 1. 身份反转
**触发条件**:角色真实身份与读者认知不同。
**设置步骤**:
1. 确定表面身份和隐藏身份
2. 通过行为细节泄露(禁止用叙述者直接说明)
3. 回看至少埋3处暗示
**揭示步骤**:
1. 用场景同时揭示身份和动机
2. 禁止让角色自说"其实我是XX"
3. 选在读者最不期待揭示的时机
| 表面身份 | 隐藏身份 | 铺垫线索 |
|----------|----------|----------|
| 乖巧继女 | 幕后操控者 | 总在关键时刻「恰好」不在场 |
| 热心邻居 | 伤害主角的人 | 对主角家里的布局太熟悉了 |
| 死去的恋人 | 还活着 | 「遗物」里有一件不该存在的东西 |
| 陌生人 | 主角失忆前的至亲 | 叫出了主角只有至亲才知道的小名 |
示例铺排:
```
铺垫1(5%):邻居帮修水管,对水管走向异常熟悉
铺垫2(25%):邻居「随口」提到主角家灯每天几点关
铺垫3(50%):梦到有人站床前,醒来闻到烟味——邻居抽烟
揭示(75%):监控里,每晚站床前的人穿邻居那件灰色外套
```
### 2. 视角反转
**触发条件**:叙事者视角是片面的,真相从另一个角度完全不同。
**设置步骤**:
1. 确保所有叙述都是事实,但不是全部事实
2. 叙述者解读引导读者走错方向
3. 关键信息被「合理地」跳过或淡化
4. 叙述者自己也真诚地相信这套叙事——他不是在骗读者,他自己也被骗了
**揭示步骤**:
1. 引入另一角色视角/证词
2. 展示主角「没看到」的场景
3. 用证据打破认知
| 主角视角 | 真实视角 | 关键差异 |
|----------|----------|----------|
| 丈夫出轨对不起我 | 我才是被蒙在鼓里的第三者 | 时间线上的空白 |
| 同事在排挤我 | 我的「好心」一直在伤害别人 | 别人视角下我的行为 |
| 我在拯救这段关系 | 我在控制对方 | 对方的反应其实是在自保 |
| 我是受害者 | 我是施害者 | 记忆被叙述者篡改了 |
**铁律**:叙述者必须真诚地相信自己的视角,禁止叙述者明知真相而故意误导读者。
### 3. 动机反转
**触发条件**:角色做某事的真正原因与读者以为的不同。
**设置步骤**:
1. 给角色一个「表面动机」让读者觉得合理
2. 真正动机藏在表面之下
3. 埋下行为细节与表面动机的微小矛盾(矛盾不要太大)
**揭示步骤**:
1. 制造高压场景迫使角色二选一
2. 表面动机指向选A,但角色选了B
3. 选择行为直接暴露真正动机
| 表面动机 | 真正动机 | 行为矛盾线索 |
|----------|----------|-------------|
| 想和前夫复婚 | 想拿回藏在婚房里的东西 | 从不关心他的生活,只关心那套房子 |
| 保护妹妹 | 嫉妒妹妹,想控制她 | 每次「保护」都让妹妹更孤立 |
| 追求公平正义 | 报个人私仇 | 目标人物恰好和当年的事有关 |
| 害怕失去朋友 | 害怕朋友发现自己背叛了她 | 每次朋友接近真相就制造新危机 |
### 4. 时间线反转
**触发条件**:故事的实际时间顺序与读者理解的顺序不同。
**设置步骤**:
1. 确定真实时间顺序和读者理解的顺序
2. 用叙述技巧让读者以为A在B之前,实际B在A之前
3. 不撒谎,只调整叙述顺序
4. 用时态、季节、物品新旧作为天然时间线索
**揭示步骤**:
1. 找一个不可能存在的时间矛盾
2. 或让角色提到「还没发生」的事
3. 或展示物品状态与时间线不符
| 读者以为的时间线 | 真实时间线 | 揭示方式 |
|------------------|-----------|----------|
| 丈夫丧妻后变质 | 妻子「死后」还活着 | 时间戳对不上的消息 |
| 姐姐在弟弟出事后崩溃 | 弟弟出事因姐姐先做了某事 | 医院记录上的时间 |
| 两人正在恋爱 | 这是一段回忆,已分开 | 「我当时不知道那是最后一次」 |
| 重生后第二天 | 重生前的最后一天循环 | 镜子里倒影和之前不一样 |
**铁律**:写完必须画时间线图自查。
### 5. 信息反转
**触发条件**:读者(和主角)掌握了错误的关键信息。
**设置步骤**:
1. 给读者一个来自可靠来源的「事实」
2. 所有人物基于此「事实」行动
3. 在后果中埋下矛盾证据
**揭示步骤**:
1. 新证据直接否定旧「事实」
2. 读者和主角同时发现被骗
3. 前面所有剧情获得新解读
| 错误信息 | 真实信息 | 揭示的连锁反应 |
|----------|----------|---------------|
| 遗嘱遗产给长子 | 遗嘱被调包,本给次子 | 长子所有「孝心」都是演戏 |
| 医生说孩子亲生 | DNA报告被篡改 | 配偶从受害者变加害者 |
| 朋友说看到他出轨 | 朋友在撒谎 | 朋友的「安慰」其实是操控 |
| 老板说提拔我 | 岗位已取消 | 老板画饼为让我多干活 |
**核心区别**:信息反转是认知层面的——你以为世界是A,其实是B。核心是「一条假信息」。
### 6. 认知反转
**触发条件**:读者对某个角色/关系的整体理解被颠覆;重点在整段感情色彩翻转,而非单条信息纠错。
**与信息反转的区别**:信息反转翻一条事实(遗嘱归属、亲子关系真伪);认知反转翻读者对整个角色/关系的感情判断(恨了全程的妈其实一直在护着她)。信息反转改事实答案,认知反转改"我对他的感觉"。
**设置步骤**:
1. 全程让读者积累一种感情色彩(这个妈狠心/这个丈夫凉薄/这个对手纯坏)
2. 每个负面场景都埋一个被忽略的反向细节(狠话之后多塞了钱、转身擦了眼泪)
3. 细节要小到读者当时不在意,回看才发现处处都是
**揭示步骤**:
1. 用一个场景或一件遗物,让所有负面行为同时获得反向解读
2. 不解释,让读者自己把全程重新过一遍
3. 揭示后情绪从"恨/怨"翻成"亏欠/意难平"
| 全程认知 | 翻转后认知 | 反向细节铺垫 |
|----------|-----------|-------------|
| 后妈刻薄赶我走 | 她赶我走是怕她仇家牵连我 | 每次骂完都往我包里塞钱 |
| 丈夫冷漠不管家 | 他在外面替我扛了所有债 | 深夜接的"应酬"电话都是催债 |
| 师父偏心打压我 | 他压我是知道我会被盯上 | 每次罚我都安排在别人看得见的地方 |
**追妻/世情主力反转**:这是追妻火葬场、世情最常用的反转——男主/婆婆/亲人全程被恨,结尾翻成"原来一直在爱/在护",意难平拉满。
### 7. 无反转
**触发条件**:甜宠、喜剧、反差萌、报应型复仇/重生——这类故事本就没有传统反转,硬塞反转反而毁节奏。
**爽感来源(替代反转)**:
- **报应兑现型**(复仇/重生爽文):爽点不在"真相翻转",在反派一步步走向毁灭、每条恶行精确对应一条报应(以彼之道还施彼身)。用报应设计表:恶行→报应→爽感来源。
- **甜度递进型**(甜宠/青春):爽点在关系一步步升温,反差萌反复"装失败"。全程正向情绪阶梯上升,不经历反转的负向回落。
**写法要点**:
1. 不为"显得有设计感"硬加反转
2. 报应型:每个报应要让读者等过、铺过,兑现时才解气
3. 甜宠型:在关系阶段节点给甜点/反差点,不为每章硬塞反转
> 拆文时遇到此类,`reversal_type` 填「无反转」,`setup_clues`(反转铺垫)一项跳过阈值(见 analyze output-contract 的「structure_counts 数值校验」)。
---
## 嵌套反转
长篇可在单元、卷和全书三层安排反转,但每层只能有一个主认知变化;下位反转服务上位谜团,不能不断推翻世界规则。
### 双层嵌套
```
读者以为:A(铺垫阶段)
第一层反转:其实是 B!(阶段假答案)
第二层反转:B 解释了局部,但 C 才是更高层机制!(卷末认知升级)
```
**执行要求**:
- 第一层反转必须足够有说服力,让读者接受B就是真相
- 第一层后给至少一个行动后果或关系变化,不在同一场景立刻翻回去
- 第二层要能同时解释A和B,比第一层更震撼
示例:
```
铺垫:丈夫出轨了,妻子收集证据准备离婚
第一层(70%):丈夫没出轨,那女人是他线人——他在调查妻子的公司
第二层(90%):妻子公司确实有问题;举报人换成妻子自己,丈夫只是被引导发现
——她故意让丈夫发现,只有丈夫「不经意」揭发她才能拿到保险赔偿
```
### 三层嵌套(慎用)
只在“单元假答案 → 卷级机制 → 全书真相”确有不同叙事职责时使用。每层必须改变角色下一步行动,并留下可回溯证据;若只是连续换答案,砍到两层。
---
## 反转时机
### 揭示位置按叙事层级决定
| 层级 | 合适时机 | 揭示后必须发生什么 |
|------|----------|--------------------|
| 场景/单章 | 当前行动获得可验证结果时 | 角色立刻调整选择或关系 |
| 单元 | 阶段目标看似完成、旧解释无法覆盖新证据时 | 开启下一阶段目标并支付代价 |
| 卷级 | 本卷承诺已兑现、读者能回看证据链时 | 改写对主线机制的理解,保留全书真相 |
| 全书 | 核心矛盾具备结算条件时 | 完成因果、情绪与收益归属结算 |
不要把全书百分比当铁律。反转太早或太晚的判断标准是:旧认知是否已经支撑过真实行动、揭示后是否还有足够篇幅展示后果。
---
## 误导技巧
误导要引导读者自己走向错误结论,不能欺骗读者。
### 两大底层路径
- **加法路径(分层法)**:在真实信息上叠加假信息。线索既可用逻辑线A解释为A',也可用B解释为B'。A'是误导方向(常见故事),B'是真相(不常见故事)。误导读者以为是A'时,必须同时暗埋与B'相关的线索。
- **减法路径(信息残缺法)**:不添加假信息,隐藏关键信息的一部分。只让主角得知成功的部分。导致下行的最好不是主角主动行动获得的,可以让配角获得那半信息后交给主角时发生意外。
### 五种技巧速查
| 技巧 | 操作方法 | 示例 |
|------|---------|------|
| 选择性叙述 | 主角只关注某些信息,读者跟着走 | 主角在意丈夫和女同事暧昧,忽略「客户」的奇怪电话 |
| 情绪引导 | 用情绪场景引导判断 | 暖的父女戏→其实是愧疚,他做了对不起女儿的事 |
| 假线索(红鲱鱼) | 给可疑角色/事件吸引注意力 | 诡异邻居和主线无关,真正威胁是一直正常的人 |
| 刻板印象利用 | 利用社会认知偏见 | 强势婆婆其实是保护儿媳,她知道一些儿媳不知道的事 |
| 信息分层 | 真相同假信息混在一起 | 丈夫确实秘密联系人(真)→前女友(假)→亲妹妹(真) |
**红鲱鱼铁律**:红鲱鱼必须在故事里有自己的功能(推进情节/增加趣味),只是不是反转的答案。
---
## 反转自检清单
### 合理性
- [ ] 回看铺垫至少有3处暗示指向反转
- [ ] 反转不依赖巧合——角色选择推动了反转
- [ ] 没有引入前面完全没提过的新信息
### 冲击力
- [ ] 反转后情绪强度高于反转前
- [ ] 反转改变了读者对前面所有剧情的理解
- [ ] 反转让读者想翻回开头重看
### 公平性
- [ ] 读者有可能在反转前猜到(不是必须,但有可能)
- [ ] 没有对读者撒谎——只是没说出全部真相
- [ ] 揭示方式自然,不靠角色大段独白解释
### 节奏
- [ ] 揭示场景没有被解释独白淹没;复杂机制可以分行动、证据和后果多拍展示
- [ ] 揭示后有足够篇幅展示反转影响
- [ ] 反转后结尾在反转产生的情绪上收束
---
## 常见反转错误
| 错误 | 问题 | 修正 |
|------|------|------|
| 天降反转 | 前面完全没铺垫 | 至少埋3条线索 |
| 解释过多 | 大段文字解释反转 | 用行动/场景让读者自己明白 |
| 反转太弱 | 读者早就猜到了 | 加误导或换反转类型 |
| 反转太多 | 3个以上反转堆在一起 | 砍到1-2个做到极致 |
| 反转无感 | 只改变信息没改变情绪 | 反转必须同时改变读者情感判断 |
| 反转作弊 | 引入前面不存在的信息 | 所有反转要素必须在前文中出现过 |
---
## 特殊反转技法
### 虚晃一枪反转法
先给出"应该不会发生"的预期让读者放松,然后意外以反转形式发生。类似鬼片推开门什么都没有->松口气->回头撞鬼。
### 超额收获反转
反转后收获超出预期,产生二次惊喜:
- 长篇:主角解决阶段问题,同时获得通向更高层矛盾的资源、身份或证据
- 网游文模式:Boss爆三样——立刻能用的 / 送人拉关系的 / 暂时用不到但一看很厉害的
### 情绪拉扯反转标准流程
1. 展示物品/能力强大,读者期待+1
2. 配角因信息差认为鸡肋,读者期待打脸+1
3. 展示反派特性恰好克制,读者期待+1
4. 配角拿更强装备打反派失败,期待+1
5. 众人看衰主角,期待继续+1
6. 主角秒杀,期待满足
7. 众人震惊,配角马后炮分析,期待满足
8. 新一轮收获,满足+新期待产生
---
## 打脸的深层节奏
### 三种打脸方式
| 方式 | 特点 | 适用场景 |
|------|------|----------|
| 主动挑衅->打脸 | 简单粗暴 | 小白文最常见 |
| 对手挑衅->被打脸 | 压主角同时给读者安全感和反击暗示 | 需要积蓄仇恨时 |
| 借他人之手打脸 | 支持者代为回击,无损主角形象 | 保持主角高逼格时 |
### 打脸节奏铁律
- 压抑长度服从单元功能;连续失败必须带来信息、能力、关系或策略积累,不能只换场景重复受挫
- 压的同时必须给读者信心暗示(主角自信到自大:"我们还是联赛前四!")
- 比起主角被欺负,读者更厌恶主角自暴自弃
- 高潮部分要拉长,最大化利用(球迷反应、解说员、赛后跟进)
- 大高潮不要险胜——充分铺垫后要尽情碾压,干净利落的大胜
### 高潮间过渡
升级练功也有爽点,但大爽点落在升级后打脸,读者期待升级后的兑现。
references/long-suspense.md›
# 长篇悬念编排
悬念构建、强度分级、多线周期、分层钩子、期待接力、震惊分层的完整操作指南。
---
## 决策路由表
| 你在写什么 | 用什么方法 |
|------------|------------|
| 设计悬念体系 | 多线悬念周期 + 强度5级分级 |
| 单章悬念 | 四种信息顺序模板 + 触发型分层钩子 |
| 跨卷悬念 | 期待接力法 + 震惊分层 |
| 判断悬念强度 | 强度5级分级表 |
使用方法:先看左列定位你的当前任务,再用右列指定的方法。
---
## 悬念构建核心法则
### 悬念的本质
读者心理预期出现两个及以上不同走向时,剧情就有了悬念——读者觉得都有可能发生。
### 悬念 vs 伏笔:区分清楚
| 维度 | 悬念 | 伏笔 |
|------|------|------|
| 目的 | 让读者猜测接下来会怎样 | 为后面的揭示埋下前期线索 |
| 位置 | 章节结尾/段落结尾 | 叙事中自然带出 |
| 揭示时机 | 短期内揭晓 | 长期后才揭示 |
| 情绪效果 | 紧张/好奇/期待 | 震惊/恍然大悟 |
判断依据:短期揭晓+紧张感 = 悬念;长期埋线+揭示时震惊 = 伏笔。两者经常配合使用,但不要混淆。
### 四种悬念信息顺序模板
| 类型 | 结构 | 适用场景 |
|------|------|----------|
| 直白剧情 | 提出疑问 → 公布答案 | 基础叙事 |
| 探索剧情 | 提出疑问 → 正常提示 → 公布答案 | 铺垫段 |
| 意外剧情 | 提出疑问 → 虚假提示 → 公布答案 | 反转段 |
| 意外+反转 | 提出疑问 → 虚假提示1 → 虚假对立提示2 → 公布答案 | 高潮段 |
操作要点:选择模板后,严格按结构顺序排列信息。虚假提示必须足够可信,否则读者不买账。
### 触发型钩子(分层钩子)
单章内多层递进悬念,按以下步骤操作:
```
第1层:展示初步成果 → 观众初步反应
第2层:揭示这还不是最终结果 → 观众期待升级
第3层:展示超出预期的元素 → 观众震惊
第4层:主角还能进一步提升 → 留下钩子,开启下一段
```
关键要求:每一层都必须有角色的反应来验证悬念的力度。没有角色反应 = 悬念落空。
---
## 悬念强度分级
| 等级 | 名称 | 效果 | 适用 |
|------|------|------|------|
| 1 | 微悬念 | 好奇 | 过渡章 |
| 2 | 小悬念 | 想看下一段 | 正文章 |
| 3 | 中悬念 | 想看下一章 | 关键章 |
| 4 | 大悬念 | 放不下书 | 爆发章 |
| 5 | 极悬念 | 睡不着 | 卷末高潮 |
使用方法:写完每章后对照此表判断悬念等级。过渡章至少要达到1级,正文章至少2级,关键章至少3级。不达标则需要补强。
---
## 多线悬念周期
| 弧线长度 | 跨度 | 示例 |
|----------|------|------|
| 短弧 | 2-3 章 | 一场打斗、一次冲突 |
| 中弧 | 5-8 章 | 一段关系变化、一个小谜题 |
| 长弧 | 整卷 | 终极秘密、主线大反转 |
规划时同时铺设三种弧线,保证任何时刻都有至少两条悬念线在运行。
### 三段钩子设计(单章内)
按章节功能安排,而不是把每章机械切成固定百分比:
1. **种**:在本章第一个有效场景中提出异常、目标或未完成动作。
2. **养**:用行动受阻、新证据或关系变化加压;过渡章可以只推进一拍。
3. **收**:本章兑现一项状态变化,并把尚未解决的问题交给下一章。
延迟引爆 = 比引爆更强的钩子,用于拉到下一章。
---
## 期待接力法
### 基本规则
- 确保读者脑中有三个好奇的东西:两长一短
- 长期待收回后变短期爆发,同时新的长期待已铺好
- 长篇中:短期、中期、远期悬念不能在同一章全部引爆;每次回收至少保留或新建一条更长的期待线。
### 持续拉期待操作框架
1. 每章结尾必须有至少一个未解的问题或未达成的期待
2. 期待分三层同时运作:短期(下章)、中期(本卷)、远期(全书)
3. 当一层即将满足时,先铺好下一层的期待,形成"期待链"不断裂
### 不间断期待与钩子链
- 主角即将得到某样东西但还没得到时,读者期待感最高
- 在主角得到之前,必须套上另一个钩子
- 大期待(主线)+ 小期待(支线)来回穿插,一个勾着一个无限循环
- 任何时刻保持至少两条期待线并行运行
---
## 驱动力公式
**核心公式**:产生诉求 → 给予希望 → 努力解决 → 得偿所愿
| 阶段 | 操作 | 要点 |
|------|------|------|
| 产生诉求 | 制造不爽——低地位/困境/威胁/不曾拥有 | 读者看到不公 → "不该如此"的冲动 = 最根本驱动力 |
| 给予希望 | 展示金手指 = 改变的希望 | 清晰展示金手指 = 给读者看下去的动力 |
| 努力解决 | 不能太快得偿所愿 | 方式一:困境分层递进;方式二:解决一个 → 新困境升级 |
| 得偿所愿 | 爽点释放 | 困境层级越高、种类越不同 → 爽感越强 |
**"悬而未决"技巧**:持续的"未解决"状态 = 持续的关注和期待。设置信息差保持张力。
---
## 情绪折线与蓄力释放节奏
### 情绪折线
`铺垫(上行)→ 挫折(下行)→ 再铺垫(上行)→ 再挫折(下行)→ 爆发(大幅上行)`
操作规则:
- 上行可以多一些,下行要精准控制力度
- 下行太猛 = 节奏断裂(弃书),太轻 = 打不响
- 网文的"下行"用小挫折、小波折制造落差,避免让主角真憋屈
### 期待蓄力与释放的力度控制
- 蓄力 = 铺垫期待,释放 = 爽点爆发
- 蓄力太久 = 读者疲惫;不够 = 爽感不足;断裂 = 弃书
- 小期待不断(持续满足),大期待适度,每次释放后爽感要比上一次更强
### 道具能力展示的8步期待模板
按顺序执行:
1. 展示宝物功能强大(期待+1)
2. 配角因信息不足认为鸡肋(信息差,期待打脸+1)
3. 展示反派,宝物恰好克制反派(期待+1)
4. 配角拿更强装备打反派失败(期待主角出手+1)
5. 主角做针对性方案(期待+1)
6. 主角上场,众人不看好(期待继续+1)
7. 主角秒杀反派 → 众人震惊 → 鸡肋成神器(期待满足)
8. 新收获 + 新期待产生
---
## 震惊分层写法
### 震惊三层结构
从弱到强依次使用:
1. **点震惊**:一个人震惊了一下(最弱)
2. **网震惊**:震惊关系网——不只一个人震惊,周围人都有反应
3. **深度震惊**:多层震惊叠加——成就1震惊 → 成就2震惊 → 更厉害的成就3引爆震惊
### 关键原则
- 金手指对剧情的效果必须展示得清清楚楚
- 放了底牌,反派就要受到对应压制
- 该爽的时候不爽到位,观感上是很毒的
### 关系网震惊层级
| 层级 | 震惊对象 | 效果强度 | 后续价值 |
|------|----------|---------|---------|
| 陌生人震惊 | 路人、群演 | 弱 | 纯情绪满足,无后续 |
| 熟人震惊 | 有过互动的配角 | 中 | 可能产生态度变化 |
| 重要角色震惊 | 有后续戏份的角色 | 强 | 伴随信息展露、关系进展、拉起期待 |
| 高位者震惊 | 行业顶层人物、高阶位者 | 最强 | 侧面拉起读者对主角的期待 |
选择依据:根据该角色后续戏份决定震惊层级。有后续的角色震惊才有价值。
### 震惊递进的道具体现法
| 阶段 | 道具表现 | 震惊强度 |
|------|----------|----------|
| 成就1 | 对方将椅子把手捏出一道裂痕 | 轻 |
| 成就2 | 椅子满是裂纹 | 中 |
| 成就3 | 对方捏爆椅子把手 | 强 |
要点:道具变化比"他震惊了"有力一百倍。每次递进都要有明确的视觉/物理变化。
---
## 期待感设计的核心方法
### 多线运行法(画线法)
1. 一个剧情线一道大横线
2. 其他期待线在下面画线
3. 规划剧情节点
4. 落入正文时再详写
### 永留悬念大结构设计
- 大结构是"欺骗式的主线":贯穿全文的噱头,并不实际推进
- 每次看似砍了99%,但总剩1%变成新的100%,一直吊着读者
### 信息差运用
- 读者知道主角获得了强力物品但配角不知道——天然信息差产生期待
- 反派恰好被克制——期待叠加
- 别人拿更好装备却失败——期待再加倍
- 信息差抹平时 = 爽点爆发
### 读者预知法(提前告知大事件制造紧张)
提前告诉读者即将发生的大事件,读者知道但主角不知道,形成紧张感和期待感。"倒计时"变体:把事件变成不断逼近的倒计时,每隔1-2章放一小段进展。
### 底牌前置法
先展示主角底牌,再安排找事的冲突。读者知道主角有底牌但反派不知道。需要两对信息组合:**底牌 + 即将发生的冲突**。
---
## 拉期待手法速查(8大类36种)
| 类别 | 手法 | 说明 |
|------|------|------|
| 角色行为 | 持续伪装等待暴露 | 主角持续扮演某身份,期待暴露时刻 |
| 角色行为 | 非常规能力展示 | 主角用特殊能力解决,期待更大规模 |
| 角色行为 | 违反人设预期的行为 | 做出与形象不符的行为,制造惊喜 |
| 角色行为 | 展示部分实力留底牌 | 展现部分实力,期待全面爆发 |
| 时局/事件 | 突发意外 | 意外事件打破当前平静,迫使剧情加速 |
| 时局/事件 | 暗中蓄力等待时机 | 角色暗中蓄力,期待亮剑时刻 |
| 时局/事件 | 高风险中谋利 | 在危险中谋利,紧张感拉满 |
| 时局/事件 | 混乱中周旋 | 在混乱局面中巧妙保全或谋利 |
| 关系网扩展 | 跨势力角色串联 | 不同势力角色产生意外联系,扩大冲突面 |
| 关系网扩展 | 多方势力不同反应 | 多方势力对主角/事件不同反应 |
| 关系网扩展 | 名声扩散引起新关注 | 名声扩散引起新势力注意 |
| 关系网扩展 | 帮助支线改变境遇 | 支线角色因主角帮助境遇改变,建立忠诚 |
| 关系网扩展 | 重要角色遇麻烦等主角出手 | 重要角色遇麻烦,期待主角出手 |
| 矛盾升级 | 逐步接近目标每步拉期待 | 逐步接近目标,每步拉起新期待 |
| 矛盾升级 | 暗中威胁浮现 | 暗中威胁线索逐渐浮现,读者先于主角察觉 |
| 矛盾升级 | 不可调和矛盾到爆发临界 | 不可调和矛盾积累到爆发临界 |
| 矛盾升级 | 解决一个麻烦引出更大麻烦 | 解决一个麻烦后引出更大麻烦 |
| 矛盾升级 | 升级引发各方反应 | 各方势力对主角实力升级的不同反应 |
| 资源/实力 | 获得稀缺资源暗示用途 | 获得稀缺资源,期待用途 |
| 资源/实力 | 独特方式变废为宝 | 用独特方式将无用变宝物 |
| 资源/实力 | 恰好解决当前困境的手段 | 恰好有解决当前困境的手段 |
| 资源/实力 | 信息或实力远超他人认知 | 掌握的信息/实力远超他人认知 |
| 新线索/设定 | 前往新地图 | 即将前往新区域,刷新场景和冲突 |
| 新线索/设定 | 新规则或设定揭示 | 新规则/设定/体系的揭示 |
| 新线索/设定 | 已有能力新组合方式 | 已有能力的新组合方式 |
| 新线索/设定 | 已知信息下更深内容 | 已知信息下的更深层内容 |
| 新线索/设定 | 谜团逐步揭开 | 谜团层层揭开,满足好奇心 |
| 新线索/设定 | 绝路出现转机 | 看似绝路出现转机 |
| 等级/技能 | 描写升级路径拉期待 | 描写升级路径,期待每次突破 |
| 等级/技能 | 新能力效果展示 | 展示新能力的具体效果和应用场景 |
| 等级/技能 | 升级后装逼期待 | 升级后读者期待装逼打脸剧情 |
| 等级/技能 | 主角能力克制当前对手 | 主角能力恰好克制当前对手 |
| 等级/技能 | 晋升展现多种能力 | 晋升后展现不同新能力,保持新鲜感 |
| 情绪/氛围 | 适当隐藏部分信息 | 适当谜语人,隐藏部分信息 |
| 情绪/氛围 | 重要角色牺牲 | 重要角色牺牲带来的情绪冲击和剧情转折 |
| 情绪/氛围 | 主角暗中布局期待收网 | 主角暗中布局,期待收网 |
**组合原则**:技巧服务表达,不是为了用而用。构思时可同时考虑多种技巧丰富剧情,没用就丢弃。
---
## 反派强时的三层破局写法
反派应对异常强势时,主角的破局要让读者感到"降维打击"。按层次递进:
| 层次 | 名称 | 做法 |
|------|------|------|
| 1 | 硬碰硬 | 实力碾压,简单粗暴 |
| 2 | 预判反制 | 反派出A,主角早准备了B克制A |
| 3 | 反预判 | 反派精心准备针对A,主角不仅避开A,还利用A作陷阱引导反派落入预设的B |
核心爽点:主角在更高层面的思考、准备和掌控力。计谋要比反派更早一层。
---
## Hook上瘾模型
套用 Hook 上瘾模型(触发 → 行动 → 奖励 → 投入),每个要素对应一个人性原罪:
| 要素 | 钩子 | 原罪 | 网文对应 |
|------|------|------|----------|
| 触发 | 欲望 | 妄想 | 切入点——提醒读者他想要什么,不是硬塞的 |
| 行动 | 简单 | 懒惰 | 行文标准——开篇繁琐 = 门槛太高,简单才能重复上瘾 |
| 奖励 | 运气 | 贪婪 | 收获期待——可预见的奖励乏味,随机不确定才让人期待"下一次" |
| 投入 | 财富 | 痴迷 | 发展高潮——极品装备/排名/宗门小弟 = 沉没成本难以割舍 |
**奖励随机性**:收获感不仅要有,还得出乎意料(预期收获经验和钱,结果偷回一颗龙蛋)。
---
## 悬念深度机制
### 意外 vs 悬念
意外是炸弹突然爆炸;悬念是听到定时器滴答作响——悬念远比意外有力量。
### 章末断章留悬念
每章结尾让人物面临未解决的危险,读者不得不回来。
### 时间锁
故事前期设置必须在限定时间内发生的事件,压缩时间增强紧张感。
### 期待 > 爽点
铺垫期待远比展现爽点更重要。爽是释放过程,不是情绪本身——紧张/好奇/担忧/愤怒/憋屈比"爽"更持久。长篇关键 = 延迟满足。
### "麻烦消失"是失去读者的根本原因
诡异流升级过快变无敌、种田文发展过快变平推——都是麻烦消失。迎合读者短期喜好可能损害长线期待。
---
## 质量检查清单
写完每一章/每一卷后,逐项检查:
- [ ] **悬念等级达标**:对照强度5级分级表,本章悬念等级是否符合章节定位
- [ ] **期待链不断裂**:是否至少有一条未解的期待线在运行
- [ ] **角色反应到位**:每个悬念点是否有角色反应来验证力度
- [ ] **信息差存在**:读者与角色之间、角色与角色之间是否有信息差
- [ ] **章末有钩子**:每章结尾是否有至少一个未解决的问题或未达成的期待
- [ ] **下行力度适中**:挫折是否控制在"小波折"范围,没有导致节奏断裂
- [ ] **震惊有层次**:震惊是否从点 → 网 → 深度递进,而非一次性爆发
- [ ] **道具变化可视化**:震惊递进是否有明确的视觉/物理变化支撑
- [ ] **爽感递增**:每次释放后的爽感是否比上一次更强
- [ ] **麻烦没有消失**:主角解决问题后是否有新的困境或挑战出现
- [ ] **多线并行**:是否保持至少两条期待线同时运行
- [ ] **底牌有压制**:展示底牌后反派是否受到对应压制
references/opening-design.md›
# 开头设计:网文开篇操作手册
> 开新书、写前 3 章时加载。先看决策路由选开头类型,再套题材模板。
---
## 决策路由
```
你的故事是?
|-- 女频言情
| |-- 总裁豪门 → 用"被迫+极端环境"或"纪念日+白月光"
| |-- 古代宅斗 → 用"被害+回归+身份反差"
| +-- 青春校园 → 用"苦难叠加+遇见"
|-- 男频爽文
| |-- 都市脑洞 → 用"中年危机+系统"
| |-- 玄幻修仙 → 用"群众恐慌+主角报名"
| +-- 动漫衍生 → 用"原作场景+系统选择"
|-- 现实题材
| |-- 家庭伦理 → 用"场景冲突+被背叛"
| +-- 行业文 → 用"专业场景+异常事件"
+-- 轻喜剧 → 用"吐槽式反应+认知错位"
```
> **路由只示意每个题材一个可行的开头方向,不是必用套路。** 箭头是"起手候选之一",不是查表取的唯一解。每本书按主角、卖点、对标自选或自造开头切口;同一题材连续开书不复用同一套路骨架——照套就成了可检索的开头指纹(同 writing-craft.md 身体细节规则:照抄或复用,产物本身就是新模板指纹)。下方「题材开头模板」同理,是菜单不是模具。
### 开头策略选择
| 策略 | 操作 | 适用 |
|------|------|------|
| 危机开局 | 从生死压力开始 | 系统文、玄幻、都市 |
| 悬疑开局 | 用悬念钩好奇心 | 悬疑、身份错位 |
| 反转开局 | 颠覆读者预期 | 重生、穿越、脑洞 |
---
## 黄金一章检查清单
开篇前 3 章必须通过以下全部检查:
### 必达指标
- [ ] 从故事最精彩、最有冲突的地方写起
- [ ] 主角三种状态选一:身处危机 / 令人羡慕 / 被丢入陌生环境
- [ ] 300 字内主角登场,1000 字内出现爽点或期待点
- [ ] 三个基点前 3 章内全部完成(人设基点 / 切入点基点 / 金手指基点)
- [ ] 第一个冲突影响重大,事先点明解决的好处和不解决的坏处
- [ ] 第一章必须说明:主角目标 + 本文卖点
### 绝对禁止
| 禁止 | 理由 |
|------|------|
| 大段背景介绍 | 开头全是"缓"没有"冲突",读者秒退 |
| 天气/风景开头 | 除非反差极大 |
| 出场 3 个以上主要角色 | 信息过载 |
| 序章/楔子/引 | 除非以叙事为主、足够简短且与第一章逻辑紧密 |
| 插叙/切视角/回忆梦境 | 正叙为主 |
| 世界观详细解说 | 至少等到第一个一级结构结束 |
### 冲突节奏
- 背景融入冲突(如用旁人议论同时完成背景和冲突)
- 两个紧张场景间要有缓和,但缓和 ≠ 无冲突
- 背景信息分批释放(信息团排版),优先级:危机感 > 人设 > 金手指暗示 > 世界观,每次释放服务于当前情绪目标
### 开篇结构范例(鬼灭之刃)
| 阶段 | 内容 | 功能 |
|------|------|------|
| 起 | 冒雪卖炭+家庭日常+嗅觉帮人+对话引世界观 | 四板斧立人设+嵌入主线 |
| 转 | 惨案→妹妹鬼化→义勇出现→跪地求饶→智慧反击 | 危机叠加+获得动力和目标 |
| 合 | 留下短/中期目标+凄冷景色渲染+牵亲人奔向未知 | 新篇章开启 |
---
## 三大基点与核心模板
| 基点 | 内容 | 作用 | 完成时机 |
|------|------|------|---------|
| 人设基点 | 展示主角核心性格和处境 | 建立代入感和共情 | 前 3 章 |
| 切入点基点 | 主角遭遇的第一个冲突/机遇 | 制造紧迫感和阅读动力 | 最好第 1 章 |
| 金手指基点 | 展示主角独特优势 | 制造期待感和差异化 | 前 3 章 |
困境型先人设,优势型先金手指。切入点必须跟主线强相关。
### 模板一:困境切入型
```
1. 主角处于不利处境(人设基点=共情入口)
2. 遭遇压迫/危机(切入点=紧迫感)
3. 金手指激活/展示(金手指=反转期待)
4. 初步解决问题但引出更大问题(钩子)
```
### 模板二:优势切入型
```
1. 主角已有独特优势但被低估/隐藏(人设+金手指合一)
2. 优势在某个场景中意外暴露(切入点)
3. 周围人的认知被刷新(震惊反应)
4. 暴露引来更大的关注/麻烦(钩子)
```
---
## 开头常见问题速查
| 问题 | 症状 | 修正操作 |
|------|------|---------|
| 信息传达不清 | 主角在哪/干什么/动机不明 | 开局交代背景和处境,明确目标再进事件 |
| 人设逼格过低 | 见美女紧张/无意义内心戏 | 主角要有逼格,配角要有特色 |
| 情绪缺失 | 战斗枯燥/看几段不想读 | 战斗中穿插情绪——恐惧、愤怒、决心 |
| 节奏拖沓 | 出场过多无关人物/铺垫太长 | 删无关互动,尽快进主线 |
| 金手指出场突兀 | 像写日记一样冒出金手指 | 用危机或困境触发金手指 |
| 铺垫章掉追读 | 章节名暴露是铺垫 | 用有戏剧性的标题把读者"骗"进来 |
### 情绪波动线操作
上行-下行交替法:穿越成仙人(上行)→ 只是记名弟子(下行)→ 杂活累活还背锅(下行到最低+共鸣点)→ 有金手指了(上行)→ 金手指是同归于尽的(下行+戏剧性)→ 和穿越前有什么区别(触底)
关键:每次波动要有具体信息支撑;共鸣是关键步骤;戏剧性情节必须写出来。
### 信息差与期待感
期待感公式:情绪 + 情节(人设+动机)+ 信息差,三者缺一则不足。核心循环:情报 → 收获 → 震惊,短平快过渡到下一个有用剧情。
### 期待感三路径
- **事业线**:设定新颖,读者预见结局但猜不到过程
- **爱情线**:人设搭配有吸引力,开头抛出亮点
- **双线缠绕**:事业线与爱情线同时进行,互相影响
### 改进方向
- **强情绪开头**:从高潮事件或复仇类强情绪切入,重大事件不能写得像闹着玩
- **情报与期待感**:每个情报都要有期待价值,关键情报拉起"然后呢?"
- **目标驱动**:主角目标要交代清楚,打斗必须基于主角目标
- **共鸣**:通过角色处境产生共鸣,先让读者站在主角这边
### 创意的正确展开
- 创意验证规则:每个创意点必须转化为具体的剧情冲突,而非仅停留在概念层面
- 书名/简介/正文三者统一(书名写"苟"但主角张扬=一致性违规)
---
## 题材开头模板
> 下列每个题材只给一个填空骨架,**是示意方向、不是要照填的模具**。填空即成稿会让同题材两本书开头逐句同构(同样的地点句→场景句→反常行为句→悬念句),正是"开头同质化"的来源。用它定"开头该解决什么"(快速抛冲突/身份反差/悬念),具体切口、句序、信息释放顺序按本书主角和对标一本一变;同一题材连续开书别复用同一骨架。
### 都市脑洞
范例:《病娇妈妈们找上门》
```
{城市名}。
{简短场景描述}。
{主角}{一个反常行为}。
{一句话解释为什么这么做,但留悬念}。
实际上,{真相,制造更大悬念}。
```
### 豪门总裁
范例A:《禁她入骨》
```
{极端/异国地点}。{季节}。
{2-3个感官细节}。
{困境描写,1-2句}。
{主角身份交代}。
{一句话揭示谁害了她}。
```
范例B:《不愿再让你低头》
```
出了{医院/法院/某场所},{天气映射心情}。
{主角}{一个会改变现场的选择、台词、任务动作或后果;必要时才用身体细节}。
脑海中闪过{某人}的话——
"{冲击性的一句话}"
{主角的反应}。
{一个动作推动下一步}。
```
### 古代宅斗
范例:《十年前他们要我顶替妹妹进青楼》
```
{N年前,被害/被弃的事件}。
{亲人选择救别人不救主角}。
"{被弃时的伤人台词}"
{N年后,主角已{隐藏身份/实力}}。
{回归场景,制造身份反差}。
```
### 玄幻修仙
范例A:《西游你叫我吗喽》
```
"{一条震惊的新闻/传闻}"
"{群众反应/讨论}"
——安静——
{场景转换:学校/公司/日常}
{权威人物宣布一个危险任务}
{所有人退缩}
"我报名!"
{主角站出来,所有人震惊}
{暗示主角有隐藏优势}
```
范例B(动漫衍生)
```
{原作角色名}的声音{描述}
{原作角色向主角提出请求/挑战}
主角内心:{穿越者视角的分析}
系统/面板出现:
【选择一:{选项}】奖励:{xxx} 代价:{xxx}
【选择二:{选项}】奖励:{xxx} 代价:{xxx}
主角选择+理由。
```
### 青春校园
范例:《你携盛夏,渡我寒冬》
```
最{负面状态}那年,我遇到了{对方}。
我{被欺负},被{家人伤害},被{社会歧视}。
{对方}则{不良/叛逆行为列举}。
我走投无路。
"{交易/请求台词}"
"{对方的反应,出人意料}"
```
### 现实情感
范例:《五年恩情,一朝两清》
```
{对方}{重要事件}那天,是{我们的重要日子}。
{被忽视的场景细节,暗示等待}。
手机屏幕亮了:"{敷衍的消息}"
{主角查看{朋友圈/聊天}——真相}。
{一句话内心独白,冷静但心碎}。
```
### 年代文
```
{主角}这会儿{状态},{反应}。
明明{昨天在做的事},一{闭眼/醒来},居然就{穿越了}。
{记忆涌入——原主的悲惨经历}
"{情绪爆发——愤怒/不甘}"
利用{前世知识/穿越者优势},{第一个行动目标}
```
---
## 书名/简介/开篇三位一体
- 书名告诉读者金手指和题材
- 简介只写三件事:主角处境、金手指能干嘛、第一个爽点预览
- 开篇必须呼应书名和简介的承诺
- 书名翻车预警:三字四字看不出亮点是大忌;不要拿悬念当期待感,直接告诉能干嘛
### 噱头三分法
| 噱头类型 | 写法 | 要点 |
|----------|------|------|
| 事件噱头 | 书名即事件,极快进入故事 | 用日常常见事件开局;一上来就进事件,不要铺垫穿越/金手指 |
| 金手指噱头 | 主角→困境→目标→金手指首次施展→少许成果 | 可结合事件写法:事件拉成主线→诞生目标→出金手指 |
| 人设噱头(高复杂度) | 出彩人设直接影响剧情构建 | 只有当该人设能持续驱动剧情和冲突时使用;单纯“杀伐果断”不算出彩人设 |
噱头吸引读者后立刻嫁接主线,事件结束后马上接新目标。
---
## 金手指与人设匹配
| 人设类型 | 适合的金手指 | 翻车组合 |
|----------|-------------|----------|
| 开朗/搞笑型 | 自爆类(装逼爽+吐槽契合) | 搞笑型+自爆金手指=不搭 |
| 心狠手辣型 | 传统型(升级、资源获取) | 冷酷型+搞笑金手指=违和 |
---
## 七步法字数分配
| 段落 | 字数 | 内容 |
|------|------|------|
| 世界观+穿越事实+前身经历 | 300 字 | 快速交代背景 |
| 第一个吸睛小剧情 | 500 字 | 用事件制造初始吸引 |
| 前置金手指获得安全感 | 400 字 | 金手指首次展示 |
| 感受到不安全 | 400 字 | 新的威胁出现 |
| 遇见危机 | 500 字 | 核心冲突到来 |
| 直接使用金手指 | 400 字 | 解决问题,完成第一个爽点 |
---
## 卖点设计与验证
### 卖点的显性与隐性分层
- 商业性卖点(噱头、创新、新鲜金手指)vs 文学性卖点(文风、笔力、世界观)
- 卖点被"海水"淹没=需要更多努力(番茄波涛最大,起点次之)
- 即使已有强品牌或强 IP,也需要多卖点叠加
### 五步验证法
1. 检查核心梗/金手指/开头情节(不能以"升级""爽文"为卖点)
2. 围绕核心特化世界观和情节
3. 检查人设反差/卖点
4. 检查个人写法特色
5. 蹭热点/蹭话题
---
## 平台差异化
| 维度 | 番茄 | 起点 | 晋江 |
|------|------|------|------|
| 核心取舍 | 节奏 > 代入感 | 代入感 > 节奏 | 人设 > 情节 |
| 开头策略 | 强情绪+强噱头 | 人物铺垫+慢热可接受 | 角色魅力先立 |
| 期待感 | 核心情绪深挖+反复提及 | 多线铺垫+伏笔 | 情感推进即期待 |
| 爽点密度 | 每 2000 字一个 | 每 3000-5000 字一个 | 情感推进即爽点 |
| 节奏 | 快,不能停 | 可慢,不能散 | 细,不能水 |
---
## 循环套路参考
| 类型 | 循环模式 |
|------|----------|
| 升级文 | 展示优势→制造信息差→展示信息差→装逼震惊→收获奖励→铺垫下文 |
| 日常/狗粮文 | 稳定人设+固定剧情流程=读者稳定期待 |
| 高武/升级文 | 练武→拜师→比赛,靠升级循环的稳定期待感拉住读者 |
---
## 内容红线
- 擦边和三观不正风险极大,非要写用外国背景+提前跟编辑打招呼
- 女频特殊规则:双洁是基础规则,不要挑战;补救用"其实是同一个人(转世/穿越)"化解
references/outline-conflict.md›
# 矛盾与结构设计
Phase 3 设计矛盾与主线结构时加载。包含矛盾设计、主线支线、双线结构、冲突结构化设计。
## 决策路由
| 你在设计什么阶段 | 用什么方法 | 见哪个章节 |
|------------------|-----------|-----------|
| 确定主线矛盾 | 矛盾四重递进 / 底层矛盾 / 三种动机 / 矛盾来源 | 矛盾设计方法 |
| 搭建主线结构 | 高潮逆推法 / 主线支线 / 双线结构 / AB交织法 | 结构方法 |
| 设计冲突 / 拉长剧情 | 设门槛拉长 / 驱动力反推 / 冲突设计要点 / 救赎文八法 | 冲突设计 |
| 设计反派 / 对抗 | 压势不压人 / 反派视角信息差 / 主角行动力 | 对抗设计 |
| 设计感情线 | 爱情线四阶段 / 事业感情配合 | 感情线设计 |
| 设计金手指 / 身份 | 金手指设计 / 双身份双金手指 | 金手指与身份 |
| 设计循环 / 核心梗 | 核心梗三分法 / 题材循环核心 / 爽点层次 / 并列式写法 | 循环与爽点 |
| 设计动机 / 困境 | 给人物一个梦想 / 困境循环 / 设定推演 | 动机与困境 |
| 组织剧情节奏 | 信息传达顺序 / 分步缓冲区 / 事件驱动 / 关系网扩展 | 剧情组织 |
---
## 矛盾设计方法
### 矛盾四重递进
按此顺序递进架设矛盾层次:人与自我 -> 人与自然 -> 人与人 -> 人与世界。
### 底层矛盾建设世界
从最根源、最不可调和的矛盾开始架设世界观。确保核心梗不偏离,否则中期订阅下降。
### 三种动机来源
| 来源 | 操作方式 |
|------|---------|
| 世界背景 | 设定环境迫使主角变强(如妖魔乱世->没实力就没自保之力) |
| 金手指 | 利用金手指机制产生利益驱动(如斩妖获得实力) |
| 人物关系 | 通过亲朋遭遇制造情感驱动(如被欺负/被杀->复仇/救人) |
### 动机变化过渡
- 危机解除后,立即通过配角/反派强调"更强力量才能生存",自然过渡到下一阶段。
- 生死危机不适合所有题材--调整困难烈度匹配题材边界。
- 上一个危机解决时必须埋下下一个危机的伏笔。
### 矛盾来源分类
根据题材选择矛盾来源:
| 来源 | 适用场景 |
|------|----------|
| 资源/利益 | 通用 |
| 阵营/种族 | 奇幻、玄幻 |
| 超凡途径 | 诡秘类 |
| 信仰/宗教 | 西幻、历史 |
| 政教之争 | 中世纪、权谋 |
| 理念/三观 | 所有题材 |
---
## 结构方法
### 高潮逆推法
按以下步骤逆推主线结构:
1. 先确定一句话结局。
2. 逆推各级目标(世界首富<--本州<--本国<--省<--市<--县<--镇<--村<--家庭)。
3. 大主线拆为中主线,中主线拆为小主线,不断细化。
4. 小主线完成后,中主线变为新的小主线,循环推进。
### 主线 = 冲突驱动
主线故事 = 解决冲突。将大冲突拆分为多个小冲突形成故事线。每个阶段必须有一个无法解决的核心冲突。
### 支线 = 完成主线的手段
按此逻辑组织支线:赚钱(主线)-> 怎么赚(支线)-> 用什么赚(金手指确认)。支线最终必须汇聚为主线。
### 双线结构法
#### 明线与暗线
- **明线**:主角线(读者直接看到的行动和成长)。
- **暗线**:反派线/隐藏元素线(目的:衔接、铺垫、嵌套后续剧情)。
- 暗线后期必须与明线交汇,形成卷内高潮。
#### 四象限结构
| | 明线 | 暗线 |
|--|------|------|
| **主线** | 主角能力升级+核心剧情推进 | 反派暗中行动/隐藏信息线 |
| **支线** | 资源线、人脉线、地位线 | 配角暗线 |
**性价比最高的结构**:明线有主线+支线("二带一"),暗线只有主线。
高潮阶段:暗线与明线融合,支线融合到主线或暂时放下。
### 升级文AB交织法
| 线路 | 定义 | 内容 |
|------|------|------|
| A线(升级线) | 战力升级 | 加点、学技能、装备提升 |
| B线(剧情线) | 矛盾冲突 | 拉出矛盾->卷入矛盾->爆发冲突->解决冲突->收获 |
交织节奏:
```
变强 -> 拉出矛盾 -> 变强 -> 卷入矛盾 -> 变强 -> 引发冲突 -> 变强 -> 解决冲突 -> 收获 -> 变强 -> 拉出矛盾...
```
**核心原则**:保持主角稍占上风的角力,每次小角力以主角胜利告终,最后迎来大胜利。
丰富代入的方法:
1. A线中丰富:详细设定可掌握的资源、人脉、装备。
2. B线中丰富:插入世界观、环境、情绪、人物互动,给反派/配角贴标签。
---
## 冲突设计
### 设门槛拉长剧情法
用门槛拆分主线为阶段小主线,每个阶段都有明确驱动力:
| 门槛类型 | 操作方式 |
|----------|---------|
| 系统门槛 | 第一次免费升级,第二次需要资源,后续分普通/超级两档 |
| 目标门槛 | 考进顶级院校需要气血值+灭杀战绩+比赛排名,逐个完成 |
| 收集门槛 | 突破境界需要收集多个物品,逐个寻找 |
| 消耗门槛 | 资源太多时提高门槛消耗掉 |
### 三大驱动力反推剧情法
| 驱动力 | 操作方式 |
|--------|---------|
| 戏剧性 | 设计意外收获、阴差阳错 |
| 矛盾 | 设计无法避免的冲突/灾难 |
| 欲望/恐惧 | 利用想得到什么/害怕失去什么 |
**操作步骤**:先确定主角阶段性成长(金手指升级/武力提升/CP好感/宝具/大佬人脉/金钱/地位),给每个成长尝试三种驱动力反设计剧情。
优势:绝对不卡文,随时充满新鲜感。
### 冲突设计要点
#### 冲突核心标准
- 冲突必须升级:言语->行动->激烈对抗->决定胜负。
- 冲突必须有明确结果。
- 本质是"有人阻止主角得到他想要的东西"。
#### 矛盾和冲突的区别
- "矛盾"是一级结构(全书/全卷层面),"冲突"是二级结构(具体场景层面)。
- 矛盾决定主线方向,冲突是具体表现。
#### 第一幕陷阱
主角在解决第一个冲突的过程中,为导致下一个冲突爆发而埋伏笔。功能:让故事自然衔接。
#### 超额收获技巧
超额收获是万能技巧:可以是后文伏笔、铺垫、情节钩子,本身出现时也是一个爽点。
经典模式:Boss爆三样东西--1.主角接着就能用的 2.可以送人拉关系的 3.暂时用不到但一看就很厉害的。
### 救赎文冲突设计八法
| 方法 | 操作方式 |
|------|---------|
| 救赎目标冲突 | 救赎来自对方牺牲;创伤制造者是对方至亲 |
| 救赎行为冲突 | 救赎靠谎言维持;必须伤害对方才能完成自我救赎 |
| 三角关系 | 救赎导致第三方需要被救赎 |
| 救赎倒计时 | 必须在某事发生前完成,否则堕入深渊 |
| 增大救赎代价 | 付出代价越来越大 |
| 救赎资源稀缺 | 资源只够救赎一个人 |
| 立场对立 | 立场分歧但彼此需要对方帮助 |
| 性格反差 | 乐观vs悲观、冷血vs富有同情心 |
---
## 对抗设计
### 压势不压人
反派不针对主角个人,而是针对一个地区/阶层/群体的规划,客观上导致主角陷入困境。
操作步骤:
1. 给反派设定自己的目的(如打压某地区修行者)。
2. 让主角身处被压迫环境。
3. 主角推翻反派后,底层人依旧麻木。
4. 底层人也可能利用主角善意攫取利益->新冲突。
优势:矛盾有逻辑根基,可持续。
### 反派视角与信息差技巧
#### 功能
转视角到反派密谋,制造读者知道而主角不知道的信息差:深化反派人设、拉期待感、让读者期待反派被打脸。
#### 写法
- 不要谜语人--大大方方写出反派计划。
- 信息差 = 提前让读者知道部分信息,制造期待。
暗线规则见上文双线结构法。
### 主角行动力设计
从以下三个维度设计主角行动:
| 维度 | 含义 | 示例 |
|------|------|------|
| 做别人不敢做的事 | 反抗权威,挑战强者 | 斩上司 |
| 做别人做不到的事 | 死里逃生,超越极限 | 必死局面生还 |
| 做别人没想到可以这么做的事 | 阴差阳错,曲线救国 | 用烤肠秘籍凑收藏 |
戏剧性是展现行动力的方法,人设是行动的缘由。不能为了意外崩人设。
---
## 感情线设计
### 事业线与感情线配合
先判断:看书名简介吸引进来的读者想看什么。
| 模式 | 设计重点 | 读者想看 |
|------|---------|---------|
| 事业线为主 | 金手指展示和升级,恋爱对象是奖励 | 主角变强 |
| 感情线为主 | 关系变化,情节根据对方人设设计 | CP互动 |
### 爱情线故事四阶段
按以下顺序推进爱情线:
| 阶段 | 核心内容 | 关键操作 |
|------|----------|---------|
| 萍水相逢 | 初次相遇,第一印象 | 用差异评价制造张力 |
| 爱情喜剧 | 被迫/偶然频繁接触 | 试探阶段是核心,占30-50%剧情 |
| 爱隔山海 | 外部压力/身份真相/误会分开 | 烈度要高,人设变化基于原人设 |
| 大结局 | 克服最大阻碍 | 不要再设计新矛盾,专注发糖 |
#### 试探阶段写法
试探阶段是爱情线核心:两人在不确认对方心意的情况下反复试探、拉扯。每次试探都要有"甜蜜"和"酸涩"两种读法。
#### 人设变化对冲法
爱情线高潮后关系升级:**双方都改变**,改变后与之前的对应关系**反转**。人设变化基于原人设部分改变,不是凭空创造新人设。
---
## 金手指与身份
### 开篇与切入点设计(双身份双金手指)
| 要素 | 设计要求 |
|------|---------|
| 显性身份(社会身份) | 摆在明面上的标签=职业+状态。必须不断变化 |
| 隐性身份(身世) | 流落凡尘的皇子、穿越者等。与全书核心矛盾联系 |
| 显性金手指 | 系统、重生记忆等。必须是能力集合,每次有新东西 |
| 隐性金手指=主角性格 | 让主角与众不同的就是金手指。中后期提供爽感 |
**四点统一原则**:社会身份、身世、金手指、性格四个东西必须高度统一。
### 金手指设计要点
#### 合格五问
设计金手指时逐条检查:
1. 能否凸显主角与众不同?能否不断协助克服困难?
2. 和世界环境、设定之间是否有紧密联系并拥有反差?
3. 是否有喧宾夺主可能?是否可预防?
4. 主角资源提升百倍千倍时,是否还能解决主要矛盾?
5. 能否通过金手指解决矛盾的同时表达思想和主题?
#### 碎片化处理
把复杂金手指能力拆分细分,碎片化融入剧情。没收集完之间是远期期待,收集到每一片就必须解决至少一个冲突。
---
## 循环与爽点
### 爽点层次设计与循环写法
#### 循环(套娃)设计
核心创意点->挖掘核心卖点->定主线->金手指配合主线衍生。
#### 并列式写法
在剧情A的铺垫中穿插剧情B,B的铺垫中穿插C,保持铺垫和爽点相续不断。
#### 多层爽点
按以下层次叠加爽点:
1. 当场观众震惊
2. 别处观众震惊
3. 专家看到手法后震惊
4. 配角信息差抹平后再震惊
爽点 = 主角装逼 + 配角认知变化。把注意力放在配角的前后变化上。
### 核心梗三分法
| 类型 | 运行方式 | 适用 |
|------|----------|------|
| 可重复型 | 每个一级结构中重复运行 | 升级文、系统文、文抄娱乐 |
| 不可重复型 | 贯穿全文但只在最高潮爆发一次 | 追妻、掉马、禁忌之恋 |
| 长期铺垫型 | 以期待点形式贯穿 | 悬疑、复仇、解谜 |
运行节奏:第一个一级结构中必须运行一次或完成首次铺垫。连续多个一级结构不运行 = 读者弃书。
双线构思法:布两条线--一条重复运行核心梗,另一条不重复,交替推进。
### 按题材设计循环核心
根据题材确定循环核心,并确保持续条件不被破坏:
| 题材 | 循环核心 | 持续条件 |
|------|---------|----------|
| 肝熟练度/低位开局 | 地图(训练场/地头蛇/破坏者) | 地图不崩 |
| 长生 | 社会变迁 | 社会一直在变 |
| 无限游戏 | 副本与现实 | 副本现实不崩 |
| 公路文 | 人际交往 | 人物不崩 |
| 无敌流 | 敌人 | 敌人不崩 |
| 种田/签到/囤积 | 外部环境破坏 | 外部持续被破坏 |
| 脑洞文 | 核心卖点循环 | 核心卖点不偏 |
**警告**:循环偏离核心卖点 = 失去差异化竞争力。
---
## 动机与困境
### "给人物一个梦想"动机法
| 概念 | 特征 | 示例 |
|------|------|------|
| 动机 | 外力推动,趋向物质 | 因为穷->想买大房子 |
| 梦想 | 内在驱动,追求精神 | 想当伟大的作家 |
操作:除了外在压迫/利益驱动,再给人物一个"梦想"。两个层次结合,人物自然鲜活。
人物目标必须结合人设--杂役弟子梦想拯救宗门缺乏说服力,宗门圣女拯救宗门就合理。
### 困境循环结构(极道流)
```
困境(环境压迫)-> 行动(运行金手指)-> 转折(更大困境)-> 行动(更强实力突围)
```
核心:不停给主角上强度,主角始终主动解决问题。搭配扮猪吃虎+情绪拉扯+装逼打脸。
要点:压迫有度,让读者觉得主角有破局希望;后期压力必须高于前期。
### 设定推演剧情法
核心公式:**环境 + 人物 = 情节**
操作步骤:
1. 给出环境(时间/地点/情境)。
2. 给出人物(身份/关系/动机/弱点/梦想/过往)。
3. 每增加一个设定点,扮演法做逻辑推演。
4. 筛选最符合核心情绪的设定组合。
### 噱头-主线-核心爽点框架
#### 噱头类型
| 类型 | 特点 | 开篇写法 |
|------|------|---------|
| 事件噱头 | 书名就是事件 | 一上来就进入事件 |
| 金手指噱头 | 分布在全文,前期多后期少 | 先描写主角->困境->目标->金手指施展->少许成果 |
| 人设噱头 | 人设直接影响剧情 | 人设本身产生戏剧性 |
**规则**:事件噱头和金手指噱头写法不同。用金手指写法写事件,读者会弃书。
#### 噱头->主线嫁接
事件结束后**立马嫁接**主角目标。也可以在事件进行中就铺垫目标。
#### 核心爽点 = 切在主线上的爽点
偏离主线的装逼是偏移爽点,不是核心爽点。
#### 逼格反应规则
逼格规则:主角面对挑衅时的反应力度应与其设定中的实力/阅历成正比。高实力角色的反应应为轻描淡写而非暴怒反击。根据角色实力等级设计反应模板:高实力→轻描淡写/一指灭杀;低实力→隐忍蓄力。被骂时的反应设计:
- 毒点:气得要死,面红耳赤
- 不毒:微微一笑--"他什么都不是"
- 歇斯底里->不爽;风轻云淡一指灭杀->爽
---
## 剧情组织
### 信息传达顺序体系
| 类型 | 结构 | 适用 |
|------|------|------|
| 直白剧情 | 提出疑问->公布答案 | 基础叙事 |
| 探索剧情 | 提出疑问->正常提示->公布答案 | 铺垫段 |
| 意外剧情 | 提出疑问->虚假提示->公布答案 | 反转段 |
| 意外+反转 | 提问->假提示1->假提示2->公布答案 | 高潮段 |
信息只有成为"疑问"时读者才关心。每个事件至少一个价值改变,且至少能推进主线。没有价值改变的事件 = 水章节。
### 主角生活路线扩展关系网
确定主角日常活动路线->在日常接触点引入新角色->新角色自带关系网->新的故事素材。
### 分步骤与缓冲区
- 缓冲区 = 主角和配角间因利益/事件/感情产生的距离,随着距离被攻略产生爽感。
- 目标分阶段拆解(类似练气/筑基/金丹),不只大目标,小目标也可拆。
- 剧情推进三种模式:主动处理推进目标的麻烦 / 主动推进目标遇到麻烦 / 被找上门的麻烦反而推动目标。
### 事件驱动原理
- 正文章节必须由事件组成,事件内容比重不能小于一半。
- 事件是价值改变的契机:没有事件,主角和主线不会改变。
- 设定尽量通过事件演绎,而非旁白强塞。
### 基于设定推演冲突
优先级:
1. **先有趣再有用**:先确保事件有戏剧性。
2. **拆出来的情节就是戏剧性**:拆书时有爽点的事件直接用。
3. **不够有趣时做铺垫拉期待**。
---
## 质量检查清单
完成矛盾与结构设计后,逐条检查:
- [ ] 矛盾是否按四重递进(自我->自然->人->世界)有层次推进
- [ ] 底层矛盾是否与世界观紧密绑定,不偏离核心梗
- [ ] 主角是否有三种动机来源中的至少两种(世界背景/金手指/人物关系)
- [ ] 主线结构是否用高潮逆推法拆分为大/中/小主线
- [ ] 冲突是否持续升级(言语->行动->激烈对抗->决定胜负),且有明确结果
- [ ] 每个阶段是否有无法解决的核心冲突驱动读者继续看
- [ ] 支线最终是否汇聚回主线
- [ ] 暗线(如有)是否在高潮与明线交汇
- [ ] 感情线(如有)是否按四阶段推进,试探阶段占30-50%
- [ ] 金手指是否通过合格五问,能力是否碎片化融入剧情
- [ ] 显性身份/隐性身份/显性金手指/隐性金手指四点是否统一
- [ ] 核心梗是否在第一个一级结构中运行一次或完成首次铺垫
- [ ] 循环核心是否匹配题材,是否偏离核心卖点
- [ ] 每个事件是否有至少一个价值改变,能推进主线
- [ ] 信息传达顺序是否匹配场景类型(基础/铺垫/反转/高潮)
- [ ] 动机过渡是否自然(上一危机解决时埋下下一危机伏笔)
references/outline-methods.md›
# 大纲核心方法
Phase 3 建大纲时加载。包含大纲创建法、结构分级、节点设计、细纲实操。
## 决策路由:你现在该用什么方法
| 你在大纲的哪个阶段 | 用什么方法 |
|--------------------|------------|
| 刚开始建大纲 | 五步大纲创建法 |
| 已经有框架要细化 | 节点设计法 + 三层结构法 |
| 设计单卷结构 | 八节点故事结构 |
| 做细纲/章纲 | 细纲与章纲节 |
| 卡文/逆推 | 推演与逆推方法 |
## 故事结构分级
| 级别 | 特征 | 适用 |
|------|------|------|
| 一级 | 单元剧松散连接,靠时间串联,最后大高潮 | 入门 |
| 1.5 级 | 单元剧间有逻辑线索串联,指向核心目标 | 进阶 |
| 二级 | 小高潮→意外下行→上行转折→大高潮链 | 高阶 |
## 五步大纲创建法
### 第1步:确定高潮剧情
高潮有绝对优先级:最大冲突规模、最多出场人物、最强情绪波动。
检查清单:
- [ ] 是否本卷最大冲突?
- [ ] 出场人物是否最多?
- [ ] 是否与阶段目标高度一致?
- [ ] 读者情绪波动是否最大?
### 第2步:确定单元剧
每个单元剧 = 主角用金手指优势获得爽点。同类型重复 = 剧情套路,有逻辑关系的成组出现 = 剧情套路链路。
操作要求:
- 每个单元剧必须展示金手指不同用法
- 相邻单元剧禁止使用相同金手指逻辑
- 单元剧之间必须建立因果关系
### 第3步:故事线组织与信息点预埋
同时管理 8 条故事线,每条必须标注预埋时机:
| 故事线 | 内容 | 预埋什么 |
|--------|------|----------|
| 地图线 | 层级地点 | 新地图解锁时机 |
| 阵营线 | 势力与地图匹配 | 阵营冲突爆发点 |
| 人物线 | 角色按类型分组 | 新角色登场时机 |
| 金手指线 | 获得的物品/技能 | 能力升级节点 |
| 世界观线 | 世界设定规则 | 设定揭示时机 |
| 矛盾线 | 冲突放入矛盾网络 | 矛盾升级链 |
| 收集线 | 材料/线索收集 | 渐进式收集层级 |
| 感情线 | 感情关系进展 | 亲密度升级节点 |
### 第4步:确定开篇舞台
按此顺序构建开篇:
```
情节钩子 → 迅速陷入异常状态 → 获得/介绍金手指 → 矛盾/欲望出现,主角运转金手指 → 目标建立
```
开篇必须预埋的期待感:新目标/冲突升级方向、实力升级暗示、资源升级暗示、感情线升级暗示、人际网络扩展暗示、混乱程度升级暗示、新线索/新设定暗示。
### 第5步:确定收尾
检查清单:
- [ ] 解决主线/副线高潮,展示后续影响
- [ ] 主角获得足够奖励 + 额外奖励(用于下一阶段)
- [ ] 给本卷角色合适的结局
- [ ] 节奏放缓
- [ ] 为下一卷内容做铺垫
## 剧情质量控制
### 剧情相似度检查
比较两个剧情是否过于相似,检查维度:冲突/矛盾类型、金手指使用方式、剧情链路段落、剧情结局。
### 剧情匹配度检查
| 维度 | 检查内容 |
|------|----------|
| 阶段匹配 | 剧情/感情线进度是否匹配本卷阶段 |
| 场景匹配 | 场景是否在本卷场景列表内 |
| 人物匹配 | 出场人物组合、关系、行为是否一致 |
### 约束规则(必须遵守)
- 时空关联:逻辑关联 >= 1:3(每1个因果推进,至少3个场景推进)
- 后续剧情情绪值不能显著低于前序
- 相同金手指逻辑禁止连续使用
- 同类剧情套路间隔 >= 3个不同类型剧情
## 节点设计法
### 核心框架(起始→终点→关键节点)
- **起始状态**:主角初始状态(废材/穷困/弱小)
- **终末状态**:主角最终状态(无敌/首富/最强)
- **节点**:保证故事不偏离终点的关键成长点
### 设计原则
- 开始与终末越有戏剧性越好
- 限定词:一个向上,一个向下(好的越好,坏的越坏)
- 流派 = 主角从开始走向终末的手段
- 节点确定后,大纲就是这些节点的排列
### 节点设计实操步骤
1. 确定主角起始状态和最终状态
2. 拆解达到终末需要的路径(提升境界线/提升实力线/收集线等)
3. 每条线设定子节点
4. 在节点间填充故事
## 大纲体系
### 大纲三层结构法
| 层级 | 内容 | 自由度 |
|------|------|--------|
| 大纲 | 主体发展方向,几百字 | 必须坚守 |
| 剧情纲 | 完整故事线,相对细腻 | 可适度变化 |
| 细节纲 | 创意爆发点、对话、小场景 | 完全灵活 |
剧情偏离大纲时必须能拉回来。限制越多,想出来的故事反而越好。
### 三种大纲写法
| 方法 | 适用场景 | 核心操作 |
|------|----------|----------|
| 地图式 | 玄幻 | 按地图更换写进度,标注实力变更/配角/大事件/爽点 |
| 分卷式 | 进阶 | 按主干剧情节点分卷,设起始点+终点+重大节点 |
| 填鸭式 | 创作初期 | 先建框架,再往里填内容 |
### 大纲设计优先顺序
1. 先确定核心创意点→挖掘核心卖点
2. 根据核心卖点定主线,金手指配合主线衍生
3. 金手指必须具备两个功能:给主角开挂 + 不断拉出目标推进主线
4. 金手指脱离核心卖点 = 整本书偏了,必须回正
## 细纲与章纲
### 细纲
- 细纲:正文 = 1:2.5~1:3
- 不展开具体情节,只关注目的和效果
- 每个节点标注"详写"还是"略写"
- 核心目的:让后续写作能快速定位要交付的目的和效果
### 章纲
- 直接看大纲和细纲够用就不必写章纲
- 按关键事件写粗纲(一个关键事件约3-5章)
- 标记钩子、伏笔、写作目的
### 即兴写作注意事项
- 滚动续写时细纲不要写太细,保留可调整空间
- 大纲是动态的,关键节点围绕核心梗发展即可
- 写完检查:主角当前行动是否和目标有关;新章节是否建立了后续期待?
### 高潮式大纲写作法
- 每10万字设计一个大高潮
- 大高潮提前确定(200-300字写清楚),前面5-6万字用小剧情填充
- 小剧情必须能推进感情线或与大高潮有关
- 极限约40-50万字
## 八节点故事结构
长篇网文通用结构,每卷/每大弧线均可套用。每个节点可跨越多章。
### 节点速查
| 节点 | 核心任务 | 占比 | 章数 | 节奏 |
|------|---------|------|------|------|
| 1.开篇 | 抓住读者,建立期待 | 5-10% | 1-2章 | 快 |
| 2.发展 | 递进事件推进情节,铺设伏笔 | 30-40% | 5-15章 | 中 |
| 3.转折一 | 打破预期,拉升张力 | 5-10% | 1-3章 | 快 |
| 4.转折二 | 升级赌注,更深困境 | 5-10% | 1-2章 | 快 |
| 5.高潮 | 核心冲突正面对决 | 10-15% | 2-4章 | 极快 |
| 6.矛盾结果 | 解决矛盾,给读者喘息 | 10-15% | 2-3章 | 慢 |
| 7.转折三 | 最终转折,投最后一弹 | 5-10% | 1-2章 | 快 |
| 8.结局 | 收束情感,留有余韵 | 10-15% | 2-5章 | 慢 |
### 各节点关键规则
**开篇**:必须 in media res,前500字有钩子。禁止从背景介绍/天气/风景开始。
**发展**:3-5个递进事件,每个推动主线。每3000-5000字一个爽点。至少埋2条伏笔。
**转折一**:改变格局的信息/事件。三要素:意外性+合理性+推动力。
**转折二**:升级版转折,赌注比转折一更高,类型与转折一不同。
**高潮**:快节奏,不留水。主角必须展现成长。
**矛盾结果**:主要矛盾解决,战利品通过情节展现(非罗列),为下弧线埋钩子。
**转折三**:颠覆读者对"结局"的预判。必须有前期铺垫。
**结局**:核心悬念解决,情感收束。不要所有伏笔都回收,留白更有余味。
### 爽点节奏公式
- 每章至少1个微爽点(按章节定位:高压/推进章必达;低压/关系/修炼/信息整理章不强求,但每章仍要给读者一个往下看的理由——微好奇/阶段目标/暧昧期待)
- 每3章解决1个冲突
- 每7章1个大爽点
### 五项驱动检查(每3-5章必查)
1. **压力来源**:主角面临什么具体威胁?
2. **实力展示**:用什么能力解决?方式是否有新意?
3. **认知颠覆**:哪个认知被打破?反转是否合理?
4. **资源增值**:获得了什么?
5. **悬念增殖**:解决后引出什么新疑问?
## 爽文五阶段小循环
| 阶段 | 定义 | 要点 |
|------|------|------|
| 稳定态/危机潜伏 | 主角相对稳定,潜在危机存在 | 不一定是好状态 |
| 危机触发 | 外部创造危机 | 必须抓人眼球 |
| 破局行动 | 利用金手指挫败阴谋 | 爽点爆发,可大量铺垫拉期待 |
| 收益结算 | 明确有价值的回报 | 资源/权力/声望/人脉/能力 |
| 新平衡与预埋 | 达到更高稳定态,新挑战出现 | 连接下一个循环 |
## 情绪拉扯五折线结构
| 段落 | 方向 | 内容 |
|------|------|------|
| 第1段 | 上行 | 铺垫/主角获得有利条件 |
| 第2段 | 拐点+下行 | 不利转折(不能是主角的错)|
| 第3段 | 上行 | 主角采取行动/出现转机 |
| 第4段 | 拐点+下行 | "虚晃一枪"——先放松后意外发生 |
| 第5段 | 爽点爆发 | 金手指发威,目标达成 |
10万字尺度用五折线规划,每段可继续套娃。卡文时靠结构推出方向。
### 情节下行原则(必须遵守)
- "功都是主角的,锅都是别人的"
- 情绪下行原因绝不能是主角的失误
- 虐主受1点憋屈,报复10倍起步
- 下行后用歪打正着、贵人扶持、好人好报补充情绪缺口
## 推演与逆推方法
### 推演式大纲设计
从核心设定出发逐步推演:主角起点状态→家庭条件→金手指合理性→冲突来源。每一步推演都可能发现新剧情点。
### 倒推法设计章纲
设计顺序:爽点→期待点→铺垫。先清楚想通过什么方式让读者满足,再倒推如何铺垫。
六种爽点类型:能力碾压、目标达成、收获盘点、态度转变、隐藏身份/掉马甲、情感圆满度。
### 真相逆推法
1. 确定核心真相
2. 将真相拆成碎片分散埋在不同章节
3. 每个碎片揭示时触发角色行动或转折
4. 高级变体:叙述性诡计——用信息误导读者
适用:悬疑线、身份线、前世今生线、伏笔密集型故事。
### 逆推锚点法
将书分为【世界观】和【剧情】两部分。先定开头和结局锚点,以锚点为中心提问,每个问题衍生一条线。
分卷逆推:先想高潮点→以高潮为锚点逆推→提问→逆推得出铺垫和主线→细纲便出。
## 章节名策略
1. 禁止用干瘪概括("开始""觉醒""升级")
2. 用最有梗的一句话或最冲突的信息
3. 铺垫章标题也要有噱头
4. 选择章节中最装x的一句话做标题
5. 避免"分析""局势""博弈"等字眼
references/outline-rhythm.md›
# 节奏与升级感 操作手册
Phase 3-4 节奏把控时加载。包含升级感设计、情绪模块公式、桥段结构化设计、高潮分类、开篇公式、期待感管理。
---
## 决策路由
| 你在设计什么 | 用什么方法 |
|-------------|-----------|
| 升级感 / 升级节奏 | 升级感三步法 + 循环嵌套 + 对比表 |
| 情绪节奏 | 情绪模块公式 + 桥段结构化 |
| 高潮设计 | 高潮分类 + 反推四要素 |
| 开篇节奏 | 黄金五章 + 开头精简法 + 节奏底线 |
| 期待感管理 | 拉期待原则 + 真空期急救 |
| 战斗 / 智斗 | 回合制卡牌 + 三步两线法 |
---
## 升级感三步设计法
### 第一步:列出起点
列出主角当前的身份、阶层、地位、资源。
### 第二步:列出终点
列出本卷/本阶段结束后的收获和提升。
### 第三步:反向设置情绪缺口
| 获得什么 | 铺垫什么 |
|----------|----------|
| 关键道具 | 配角强调稀缺性 + 别人求而不得 + 展示效果 |
| 地位提升 | 羡慕该地位的权力 + 凸显等级待遇差别 |
| 人物帮助 | 展示该人物价值 + 别人对他的态度 |
### 升级循环嵌套
挑战A副本 → 获得B道具 → 达成C目的 → 升级 → 挑战D副本。
核心:**一直在升级,和为升级做准备。升级后能完成以前做不到的事。**
### 多角度强化对比
| 对比维度 | 升级前 | 升级后 |
|----------|--------|--------|
| 数值/战力 | 平A 300伤害 | 平A 650伤害 |
| 技能数量 | 放完只能躲 | 还有第二个 |
| 排名/地位 | 没人鸟你 | 有人主动来找你 |
| 社交态度 | 被嘲笑 | 一片掌声惊叹 |
| 资源获取 | 苦哈哈攒材料 | 高价值信息主动送上门 |
### 升级文具体技法
**升级前后铺垫**:
- 升级前:铺垫未升级时的待遇差距、资源获取难度
- 升级后:多方面展示变化——战力、待遇、人际关系、资源获取
**升级次数控制**:主角升级最好不超过3次,质量提升而非数量堆叠。
**即时反馈与延迟反馈**:
| 反馈类型 | 作用 | 示例 |
|----------|------|------|
| 即时反馈 | 每次行动给小奖励,维持动力 | 打怪掉落 |
| 延迟反馈 | 积累到一定程度爆发大奖励 | 经验满升级 |
**升级与现实概念关联**:越日常越好理解——呼吸变强、睡觉变强、多子多福生崽变强。
**升级后写长三种方式**:
| 方式 | 操作 |
|------|------|
| 扩展地图 | 增加力量体系上限,多层世界设定 |
| 压等级+复杂化 | 一个晋级目标拆成三个剧情的篇幅 |
| 转换写作内核 | 从写升级转向写人设——配角线和支线 |
---
## 情绪模块系统
### 提炼层级
| 层级 | 名称 | 内容 |
|------|------|------|
| 零级 | 具体故事 | 原文完整情节 |
| 一级 | 经典故事情节 | 去除描写,保留核心素材 |
| 二级 | 故事构型 | 去除所有素材,只剩逻辑走向 |
| 三级 | 戏剧单元 | 戏剧性的抽象——有戏剧性的大致走向 |
| 四级 | 情绪模块 | 情绪的抽象——读者想看什么 |
### 戏剧单元 vs 情绪模块
| 维度 | 戏剧单元 | 情绪模块 |
|------|---------|--------|
| 本质 | 构建戏剧性的逻辑结构 | 读者想看什么的情绪需求 |
| 磨损 | 会磨损(同类结构用多不好看) | **不磨损**(英雄救美从史诗时代至今) |
| 例子 | 「误会→冲突→反转」这种走向骨架 | 「读者就想看打脸/追悔」这种诉求 |
一句话判断:能画成流程图的是戏剧单元,能写成「读者就想看 XX」的是情绪模块。
### 使用方式
1. **重构使用**:保持素材不变,修改故事构型。适用于长篇(百万字级别必须掌握)。
2. **微调使用**:直接用经典情节,深挖人设微调。适用于短篇。
---
## 常用情绪模块公式
### 英雄救美
```
关系平平或恶劣 + 危机产生 + 化解危机 + 关系质变
```
核心:关系质变的爽感。适用于任何角色关系正向质变的节点。事业线为主→重点在金手指展示;感情线为主→重点在关系变化。
### 装逼
```
被打压嘲讽(可选)+ 展示能力 + 打造落差 + 震惊
```
核心:落差——前后反转落差 + 平行对比衬托。
五种模式:作对比、装逼打脸、自我否定+他人吹捧、他人否定+被打脸、借人之手。
### 以小博大
```
小代价 + 入水之鱼的环境 + 获得大收获
```
核心:"占了便宜"心理。成本与收获倍数比例越大,爽感越强。过程要有随机性 + 主角主观能动性。
### 点石成金
```
不被看好的某物/某人 + 主角改造 + 产生价值
```
### 慧眼识真
```
主角已知价值 + 众人不看好 + 唯有主角知晓的情报 + 真相揭晓 + 众人震惊
```
### 歪打正着
```
暗示宝物重要性 + 主角在错误方向上努力 + 偶然获得宝物 + 众人震惊
```
### 少年热血
```
主角团面对强大恶劣环境 + 明知不可为仍然努力 + 打破困境
```
### 临危受命
```
危机超出现场能力 + 配角穷尽办法无法解决 + 主角接手 + 完成任务
```
### 情绪模块组合
| 组合 | 效果 |
|------|------|
| 以小博大 + 英雄救美 | 双重爽感 |
| 点石成金 + 装逼 | 先压抑再爆发 |
| 少年热血 + 神器认主 | 经典套路 |
| 临危受命 + 装逼 + 英雄救美 | 危机中展现实力 |
---
## 桥段与节奏的结构化设计
### 桥段的标准四章结构
300万字 ≈ 40-50个单元 → 每单元4-5个桥段 → 每桥段约4章。
**四章一桥段标准结构**:
| 章 | 功能 | 要点 |
|----|------|------|
| 第一章上 | 代入:日常+熟悉角色互动 | N+1原则 |
| 第一章下 | 信息差:展示对手/困境 | 切镜头展示 |
| 第二章 | 拉扯增强:配角反应 | 结尾必须让主角开始装 |
| 第三章 | 兑现:爽感写透 | 最好写的一章 |
| 第四章 | 承上启下 | 收尾或开启下个目标 |
**圈内不圈外原则**:先给内容画圈,整本书只在圈内写核心卖点相关。
### 高潮节奏铁律
- 大高潮:7-10天完成(日双更/约14章),超10天读者反感
- 小高潮:3天左右完成
- 高潮结束后:1-2章日常过渡
### 阶段衔接三大解法
1. **高潮中埋钩子**:上一段高潮扩散中放下段钩子
2. **尾巴给目标**:一段结束时给主角明确的下阶段目标
3. **连续小期待**:过渡章持续放小钩子
---
## 高潮分类与反推
### 高潮两大类
**1. 现实高潮**(社会热点):路怒症、出轨、霸凌等。不照搬,要把情绪极限化。一般放在开头或上架节点。
**2. 作品高潮**(8类):
| 类别 | 典型 |
|------|------|
| 情绪共鸣 | 热血、七情、爱恋 |
| 六感冲击 | 玄幻大场面、恐怖视觉 |
| 冲突爆发 | 争权夺势、背叛谋利 |
| 升级收获 | 境界突破、装备获取 |
| 反差震惊 | 装逼打脸、身份曝光 |
| 高智解密 | 悬疑推理、计谋揭秘 |
| 怪诞诡异 | 规则怪谈、克苏鲁 |
### 高潮反推四要素
确定高潮后反推:①角色 ②背景 ③故事线 ④情绪演变(后两个必须结合)。
---
## 开篇公式
### 黄金五章公式
| 章 | 内容 | 功能 |
|----|------|------|
| 第1章 | 穿越/背景/人设/金手指/建立欲望 | 建立基础认知 |
| 第2章 | 明确主线 | 点题 |
| 第3章 | 展示金手指强大 | 运行金手指 |
| 第4章 | 拉仇恨/设正反方/信息差/铺垫 | 拉期待 |
| 第5章 | 装逼成功/触发新事件 | 第一个爽点闭环 |
### 开头精简法
1. 整理开头第一个一级结构的矛盾
2. 把介绍性、抒情性文字逐条向上连——尝试与矛盾直接关联
3. 隔了好几层逻辑才能连上的 → **无效信息,删除**
4. 后文没戏份的配角不给名字
### 开头节奏底线
| 要求 | 标准 |
|------|------|
| 爽点/期待点出现 | 1000字内必须看到 |
| 打斗 | 第一章不能上来就打 |
| 爱情线对象 | 第一个一级结构内必须出场 |
| 金手指展示 | 第一个冲突由金手指解决,主角主动选择使用 |
---
## 断期待诊断与修复
### 四种根本原因
| 原因 | 读者感受 |
|------|----------|
| 延迟满足过度 | "到底什么时候才能爽?" |
| 换地图处理不当 | "之前期待的都没了" |
| 核心梗重复度太高 | "又是这样,没意思了" |
| 爽点满足感不足 | "就这?" |
### 持续拉期待原则
**核心公式:拉期待速度 > 断期待速度**
1. 当前目标完成前,提前铺设下一目标线索
2. 满足当前期待后迅速给出新期待
3. 砍掉不服务核心梗的支线
4. 保持主角目标始终清晰
5. 同一核心梗做好差异化
### 期待真空期急救
| 手段 | 操作 |
|------|------|
| 反派视角转接 | 展示反派行动,制造信息差 |
| 突发意外 | 不按计划发展的事件强行介入 |
| 配角杠杆 | 用配角的危机重新制造紧迫感 |
| 超额收获 | 远超预期的额外奖励 |
---
## 卖点与读者需求匹配
### 卖点偏移论
崩盘根本原因常是"卖点偏移"——爽点背后满足的需求和读者想看的东西偏开了。
**需求清单**:三情(亲情爱情友情)、成为大人物幻想、不劳而获幻想、被尊重/认同/理解、惩恶扬善、公平、优越感、冒险欲、好奇心、成长、收获、暴力欲、安全感、新鲜感、情怀、弥补遗憾。
**爆款公式**:抓住一种需求且一直抓着不偏移。
### 卖点双层论
- **题材卖点**:读者为什么看这类题材?
- **书的卖点**:读者为什么看"你这本书"?
自检:爽点偏向了另一个题材的卖点 = 偏题。
---
## 战斗系统设计
### 回合制卡牌思路
每回合一般只能用一张"牌"。打出"组合技"时,最多只有一张是读者没见过的。
### 强弱对决性价比
| 对决类型 | 难度 | 效果 | 使用规则 |
|----------|------|------|------|
| 以强击弱 | 容易 | 好 | 多用 |
| 以弱胜强 | 难写 | 需铺垫 | 少用 |
| 强强对决 | 最难 | 最好 | 一个中故事最多一次 |
### 战力设定规则
- 高等级意味着身居高位或影响深远
- 高等级战斗必须写出"史诗感"
- 跨越大境界对敌必须有合理解释
---
## 智斗构型(三步两线法)
1. 反派制定三步计划(目标→手段→时间线)
2. 主角有自己既有的计划
3. 两人的计划互相牵扯
牵扯方式:资源争夺、利益威胁、间接碰撞。
智斗要点:反派也会根据观察调整计划,利用信息差让反派误判。
---
## 创作辅助方法
### 改编法
1. 确定目标矛盾类型,在剧情原型库中检索
2. 将匹配剧情拆为细纲放左边,自己的情况放右边,逐点改编
3. 验证改编后是否满足情绪目标、与主线衔接、无逻辑漏洞
### 同人衍生型大纲法
阅读内容 → 资料收集 → 信息提取(偏重高逼格和极致情绪)→ 衍生创作(拆分融合)。
### 三重重复循环法
- **看点重复**:抓住读者想看的那个点,死死写。边界:同一看点情绪兑现连续3次以上无差异化时调整
- **人物重复**:同一行为换场景重复
- **套路重复**:基础模板不变,场景变化
### 极简大纲法
把升级体系本身当作大纲。每一卷 = 一个关卡:入口条件 → 核心挑战 → Boss战 → 通关奖励。
---
## 质量检查清单
完成节奏设计后,逐项检查:
- [ ] **升级感**:起点和终点是否清晰?情绪缺口是否铺垫到位?
- [ ] **升级循环**:是否"一直在升级或为升级做准备"?升级后是否展示了以前做不到的事?
- [ ] **对比展示**:升级前后是否有至少3个维度的对比?
- [ ] **情绪模块**:当前桥段的情绪模块是否明确?公式是否完整走通?
- [ ] **桥段结构**:每4章一个桥段,是否有代入→信息差→拉扯→兑现→承上的完整链条?
- [ ] **高潮节奏**:大高潮是否控制在7-10天内?小高潮是否控制在3天左右?高潮后是否有日常过渡?
- [ ] **阶段衔接**:高潮结束后是否埋了钩子或给了新目标?
- [ ] **开篇检查**(如适用):前5章是否满足黄金五章?1000字内是否有爽点/期待点?
- [ ] **期待感**:拉期待速度是否大于断期待速度?是否存在期待真空期未处理?
- [ ] **卖点一致性**:爽点满足的需求是否与书的卖点一致?是否偏移到另一个题材的卖点?
- [ ] **战斗/智斗**(如适用):对决类型选择是否合理?智斗是否有信息差和计划牵扯?
- [ ] **重复边界**:同一看点情绪兑现是否超过3次无差异化?是否需要调整?
references/outline-structure-theory.md›
# 深度结构设计
> 一二级结构、三幕/五幕/六幕结构、因果链、重剧情vs重人设、五级逐层展开法、换地图、多线写长。用于大纲结构设计时查阅。
---
## 决策路由
| 你在做什么 | 查阅哪个模块 |
|-----------|-------------|
| 选择整体结构层级 | 一级结构与二级结构 -> 三级结构 |
| 设计单卷/单章因果链 | 故事基本结构 -> 因果链建立手段 -> 五幕式 |
| 选择故事架构模板 | 三幕式与五幕式 -> 三幕/起承转合/五幕的关系 |
| 设计装逼的深层逻辑 | 网文第六幕:余波 |
| 搭建大纲框架 | 五级大纲逐层展开法 -> 布局八条线 |
| 选择重剧情还是重人设 | 大纲结构选择:重剧情型 vs 重人设型 |
| 设计换地图节奏 | 换地图与地图架构 -> 换地图三法 -> 顶层框架法 |
| 拉长篇幅不崩盘 | 多线写长技法 -> 传统文框架与四大留存手段 |
| 写西幻题材 | 西幻创作要点 |
| 把对标书节奏搬进自己大纲 | 一级结构=对标书的剧情单元 + 对标节奏迁移 |
| 排章避免每章像短篇 | 章节定位与张弛 |
结构规则是**必须遵守**的框架约束(如五幕式的因果链环数、每幕功能)。遇到冲突时:因果链规则 > 结构模板 > 具体技法。
---
## 一级结构与二级结构
### 一级结构 = 单元剧串联
一条故事线由若干单元剧组成,互相孤立,主角如绳子串起所有单元剧。
- 优势:爽点密集,结构简单不易出错
- 劣势:撑不起长篇幅,期待感单一,上限有限
### 二级结构 = 单元剧套娃升维
把一级结构的"单元剧"拉长到整卷,每卷是一个完整故事。核心问题:一卷二三十万字只展开一个故事,铺垫太长。
**解决方案 = 套娃**:大故事的每个结构部分本身也是一个小故事,小故事有爽点,同时暗中铺垫大故事。层层递进,高潮时串在一起引爆。
### 三级结构
卷与卷之间不再孤立,按一个故事结构统一,所有情节互相联系互相作用。对编织情节能力要求极高。
### 长篇特殊认知
- 最小冲突单元 = 节拍(一个动作对应一个反应)
- 过渡章节的问题往往是信息铺垫太多、冲突太少
- 剧作理论不适用两点:①人物弧——几百万字主角早该成熟,主角可当工具人 ②细节打磨——长篇读者不会深研潜台词
## 故事基本结构(主角->障碍->目标)
**核心模型**:主角->障碍->目标
从基础到好的三步升级:
1. **加曲折**:多个障碍才叫故事
2. **递增难度**:难度一致=单调,难度递减=乏味,必须越来越难
3. **意料之外**:主角即将到达目标时给一个意外——计划失败。解法:灵机一动(临时想到)或神秘一笑(隐藏已久的招)
### 支线与主线的双向对接法
从支线端和主线端同时开凿,最后对上->前后能圆回来。让支线不成"孤例"——大政策层层传导,主角遭遇只是大现象切面。
### 短篇到长篇的连接
长篇 = 一个个短篇连接,连接物 = 钩子。短篇结束前必须留没处理干净的东西。钩子有"定向"作用。
## 三幕式与五幕式
### 故事的本质:事实->事件->故事
- **事实**:静态呈现,不是故事
- **事件**:变化的事实(从X到Y的变化)
- **故事**:对事件进行选择、排序、因果化的产物
- **因果产生意义**:加入因果逻辑后读者会问"为什么?",意义自成
### 因果链建立手段
| 手段 | 说明 |
|------|------|
| 排序 | 打乱时间顺序建立因果关系 |
| 铺垫 | 在事件b之前,在事件a旁边埋下因 |
| 伏笔 | 事件a + 事件h的因,隔很多事件后才揭示 |
| 钩子 | 在事件d旁边埋下事件e的因,制造悬念 |
### 五幕式:因果链的最优弯曲模板
| 幕 | 规则 | 因果链状态 |
|----|------|-----------|
| 第一幕:开局 | 因必须在此埋下 | 种子 |
| 第二幕:发展 | 果+因,发展为下一幕的因 | 生长 |
| 第三幕:转折 | 果+因,质变为下一幕的因 | 转折 |
| 第四幕:行动 | 果+因,白热化 | 冲刺 |
| 第五幕:结局 | 果,收束 | 完成 |
**五幕式规定**:因果链必须有五环;每一环有固定功能;不能跳步、不能乱序。
### 三幕、起承转合与五幕的关系
- **三幕**(冲突开始->对抗->解决):世界矛盾本身够强、不靠主角推就成立时用(末世、天灾)
- **四幕/起承转合**:外力推着主角走,他来不及反抗、被动承受(追妻火葬场前期、宿命局)
- **五幕**:主角被逼到墙角后主动反杀(爽文、复仇)
**转折的本质**:冲突性质的质变——冲突变得更严重,主角处境更糟。转折的因要偷偷提前埋下。
### 网文第六幕:余波(装逼的深层逻辑)
装逼的**本质冲突**是"主角与社会认知的冲突",不是主角与反派的冲突。
主角实力两个维度:
- **明线**:战力体系里的晋升
- **暗线**:社会对主角的认知定位
明线高于暗线时产生冲突->装逼->暗线拉高到一致。小失衡有小装逼,大失衡有大装逼。
装逼的正确方式:少让主角主动证明"我很强",多让环境、他人、时间告诉社会"你确实变强了"。
### 八股文套路化写作六大模块
1. **定调**(黄金三章本质):回应读者期待。核心公式:令人不安的处境 + 急待提升的地位 + 充满希望的外挂 + 能被展望的美好未来
2. **金手指设计**:信息挂(最优,不易失控)> 加速升级挂 > 物品调用挂(容易失控)。核心:简单,功能与升级规则清晰
3. **脸谱化角色**:给角色贴标签,一看到特征就想起角色
4. **升级流节奏**:目标->行动->完成->奖励循环,周期要短
5. **密集爽点轰炸**:不爽->移除不爽=爽
6. **套路化冲突**:冲突本身越简单越好理解,悬念构建越复杂越好吸引人
## 五级大纲逐层展开法
| 级别 | 说明 |
|------|------|
| 1级 | 统筹全文,一句话概括全书 |
| 2级 | 一个故事情节 = 一条2级主线 |
| 3级 | 具体剧情 |
| 4级 | 更细的剧情推演,如堂哥矛盾->羞辱->奋发->金手指->干死对手 |
| 5级 | 最细致的具体过程,获得金手指的具体过程 |
**下一级服务上一级**。3级足以支撑长篇,5级容易混乱。从上往下推不会卡文,从下往上推容易卡且脱离主线。
### 暗线设计
- 暗线 = 读者看不出来的线,出其不意
- 暗线统筹全文,从开始到结束不明写但留伏笔
- **一伏千里** = 答案从开局就给了,读者到最后才发现
- 悬疑常用多暗线同时进行->汇合->再汇合其他暗线->最终统筹全文
### 布局八条线
用三到四条线就够——主线(推目标)+ 感情线 + 一两条支线/暗线(埋伏笔),下级服务上级。
## 大纲结构选择:重剧情型 vs 重人设型
### 强主线(二级结构)
典型:升级文、悬疑文。重剧情轻人物,配角是工具人。
核心特征:
- 每卷有完整三幕式,每幕又有小三幕式(嵌套)
- 只有一条主线,所有支线推动主线
**大钩子设计**:主线拆成大支线,每个最终目标 = 大钩子。
- 大钩子必须不间断,一个断了马上接另一个
- 更换大钩子关键是铺垫,不能突兀
### 弱主线(一级结构)
典型:无敌文、日常文。轻剧情重人设。
核心特征:
- 单元剧模式,各有完整三幕式
- 公式:核心爽点 + 讨喜人设 + 单元剧舞台
- 不需要明确主线,主角串联一切
- 人设的新颖是重点
### 过渡型
开局弱主线(单元剧日常),后期逐渐过渡为强主线。
### 支线设计原则
支线必须与主线有关,否则是废线。支线人物身份设定自然服务于主线。
## 传统文框架与四大留存手段
### 每卷框架设计(目的+高潮结尾)
框架 = 骨相,剧情 = 皮相。每卷做好两件事:①来到新地方的目的是什么 ②设置大高潮结尾。
### 四大留存手段
1. **升级**:不只打斗实力,还包括地位、金钱
2. **资源困境**:修炼需要资源,谋求资源是留住读者的好手段
3. **设置目标**:大目标+小目标+假目标(不一定要实现,用来勾起期待)
4. **解密**:展现冰山一角->层层解密->不断拨开迷雾
## 换地图与地图架构
### 换地图的四种演进方式
| 代际 | 核心 | 问题 |
|------|------|------|
| 1.0 飞升流 | 凡间->仙界->神界 | 人际关系全抛弃 |
| 2.0 莲花地图法 | 莲心核心地图+花瓣分支 | 空间有局限 |
| 3.0 新玩法 | 家族流/模拟器/版本迭代 | 需从中期开始铺垫 |
### 换地图三法
1. **千丝万线法**:两个大地图间不断穿针引线
2. **不换大地图法**:只换小地图,都在一个大地图里转
3. **莲花地图法**:地图像莲花层层展开
### 顶层框架法(防崩盘)
开书前先设整张地图所有顶尖势力作为"柱子"。从顶层向下延展:区域->小家族->小宗门->功法宝物。每个出场人物都与某个顶层势力挂钩。
**刻度尺思维**:提前设计顶层实力表现力作为标杆。开头boss=5,中期=50,后期才写100。
### 人际关系先行法
去下一个地图前,先把人际关系铺出去。核心:人际关系动了->主角再动。
### 换地图关键认知
- 大地图转换可能掉三分之一追订
- 损失的读者永远回不来
- 如果后续写得好追订可涨回来
## 多线写长技法
### 多线并进与挖坑填坑
从开头主线就要埋伏笔开支线。主线+两条以上支线同时展开,主线一停->支线接入。不断挖坑填坑 = 剧情不断延展。
### 多线缓解疲劳
长剧情中间插入半章配角视角的无关事件->短暂放松。切换要自然:主线中埋支线伏笔->适当展开->回到主线。
## 西幻创作要点
**选材**:选DND式、巫师、种田、领主文等常青树。避开高武和日式奇幻。
**世界观**:通过人物对话和行为展现,不搞大段设定文旁白。
**人物**:用中文谐音做译名降低门槛;先设计金手指特性,人物性格围绕金手指展开;道德爽感是最高级爽点。
---
## 一级结构 = 对标书的剧情单元(节奏对标的轴)
一级结构是一个完整单元剧:一个矛盾从起到爆发收束,约 1.5-3 万字 / 数章。拆对标书拆出来的「剧情单元 / 章节摘要 / 爽点循环」就是它的一级结构序列;自己卷纲里的「剧情单元」也是一级结构。所以「一级结构」是理论叫法,落到产物就是**剧情单元**(对标侧=拆出的剧情单元,本书侧=卷纲里的剧情单元卡)。所以对标节奏不是另起炉灶——是把对标书的一级结构序列,保留情绪与功能、换素材,搬进自己的卷纲。
### 关键点法(统一各尺度的节奏锚)
任意尺度(全书 / 卷 / 一级结构 / 支线 / 章)都有五个关键点:开场、1/4、中点、3/4、结尾。其中 1/4、中点、3/4 是放关键情节的位置。关键情节三类:
| 类型 | 含义 |
|------|------|
| 情节逆转 | 发展在读者意料内,但主角的解决方式让人直呼精彩(装逼打脸、英雄救美) |
| 情节转折 | 意料之外(身份反转、敌变友、局势骤变) |
| 激励情节 | 全书或一卷第一个、与核心主线直接相关的命运改变时刻 |
不是每个尺度都把三处填满,但一卷至少在 1/4、中点、3/4 各安排一个关键情节,避免全程一个力度。
### 对标节奏迁移(卷纲定稿前做一次,无对标书可跳过)
1. **选段(以剧情单元为单位)**:在主对标里圈出本卷要对标的一级结构序列——选段单位就是拆文产出的剧情单元(`剧情/{剧情标题}.md`)。检索顺序:先读主对标 `剧情/README.md`「剧情单元清单」(有清单则一书一文件,按「类型 / 桥段标签」直接命中同类);无清单则在 `剧情/*.md` 里按「类型」行(第一键,必填枚举)+「桥段标签 / 套路框架位置」行(第二键)圈同类;仍无命中回退按章节范围圈段,全程不阻塞。多对标时按 `cross-book-recall.md` 大纲预算从副对标补同类条目。读取必备权威文件 `剧情/节奏.md`(爆发密度 / 爽点循环);缺失时先修复或重跑拆文 Stage 3,不从摘要猜测节奏。本卷对标几条一级结构 ≈ 本卷字数 ÷ 1.5-3 万。
2. **标关键点**:看对标这几个一级结构在 1/4、中点、3/4 各放了什么关键情节,判为逆转 / 转折 / 激励。摘要里「类型=转折点」的情节点 + 基调突变(如温馨→压抑)就是关键点的确定性锚,不靠凭感觉;剧情单元的「结构分布」(铺垫/发展/高潮/收尾期)与「情节点索引」同为确定性锚。
3. **换素材**:保留对标的情绪链和功能位,把对象、场景、事件全换成自己的,禁止照搬具体桥段。功能位清单取必备权威文件 `剧情/情绪模块.md` 的可替换项;缺失时先修复,不生成替代清单。
4. **修正硬伤**:换素材前比对 `拆文报告.md`「不建议模仿」。对标若在某个关键点是弱处理(慢热留白、主角长期旁观等已知硬伤),迁移时要在该位置补一个缺的关键情节、或把后面的关键情节前置,而不是把弱处理一起抄过来——关键点该有的力度不能因为对标偷懒就跟着偷懒。
5. **排章 + 落卷纲**:把换好(并修正)的关键情节落到本卷相同相对位置——这里的 1/4·中点·3/4 是**卷尺度**(1/4≈总章×0.25、中点×0.5、3/4×0.75);卷里有几条一级结构时,每条一级结构内部另有自己的铺垫→逆转→收尾,别和卷尺度的关键点混为一谈。关键点之间用普通推进章过渡,每个关键点之后按需插一章呼吸 / 关系章;写进卷纲「对标结构坐标」与情绪弧线的章节定位列,细纲承接时每章标章节定位。同时把选中的剧情单元以 {书名}《剧情标题》写入剧情单元卡「对标剧情参照」。
近精细远模糊:只精排当前卷,后续卷做粗坐标即可,不必一上来规划全书。
一个最小例子(demo《让你管账号,你高燃混剪炸全网》):对标结构的 1/4 是“小人物拿出粗糙作品,无人看好”,中点是“作品爆火,体制内外同时关注”,3/4 是“专业力量进场替代,反而证明主角不可复制”。换到江晨这条军宣线后,1/4 落成他用手机拍《诸君,且听龙吟》、画质粗糙却先把军魂拍出来;中点落成视频引爆全网和参军热潮;3/4 落成专业团队高清重拍,却被周薄森当场指出“缺了灵魂”,张耀祖最终拍板继续用手机原版。保留的是“轻视→市场验证→权威替代失败→价值坐实”的情绪链,素材、场景和角色关系都来自本书。
### 按剧情批出细纲(细纲分批边界)
一批细纲 = 卷纲里的一个剧情单元(约 5-15 章)。体量换算:剧情单元字数 ÷ 单章目标字数 → 章数,单章目标字数取本书既有细纲惯例,无惯例按题材节奏档取默认(快节奏/短平快约 2000,均衡约 3000);剧情单元超过 1.5 万字且节拍含两个以上独立高潮时拆成多个剧情单元,否则单个剧情单元。剧情单元 >10 章拆两批建纲,两批共享同一次召回;首批 = 前 10 章封顶、可跨单元(跨入的剧情单元建卡时召回一次,余章由后续滚动批共享剧情单元卡结论),停靠规则不变(见 [Phase 3:大纲搭建](workflow-setup.md#phase-3大纲搭建))。
建卡时做一次**剧情批召回**:读剧情单元卡「对标剧情参照」指向的剧情单元(≤3 个文件)的「结构分布」「情节点索引」,回查该书 `剧情/节奏.md` 同章节区间的爽点循环 / 触动点与被引情绪模块卡,提炼 5-8 拍共性节拍写入剧情单元卡「单元节拍/章功能分配」,单元情绪引擎字段对照主对标 `剧情/情绪模块.md` 的可复现模块校准。若主产物存在但被引的单个情绪模块卡未命中,只跳过该卡;`剧情/情绪模块.md` 或 `剧情/节奏.md` 文件缺失仍按上方 fail-fast 规则先修复。换素材与修硬伤纪律同上方迁移步骤 3/4——保留情绪链和功能位,对象、场景、事件全换,对标弱处理就地修正。结论固化进剧情单元卡后,逐章细纲只消费剧情单元卡,不重读剧情单元。
日更中途发现卷纲缺少「对标剧情参照」等当前协议必需字段时,先补齐卷纲再建细纲;锁定卷纲不得自动回写,必须停在补纲边界。节拍分析过程不写进追踪文件,只有最终影响未来连续性的约束或下一章承诺才进入本章追踪事务。
## 章节定位与张弛(破「每章像短篇」)
一卷里章的压力本就该有高有低。这里的压力级指**爆发 / 冲突烈度**(复用悬念刻度 1 微 / 2 小 / 3 中 / 4 大 / 5 极),不是情感烈度——关系回收 / 泪目这类章可以压力低(爆发小)但情感强度顶满,情感烈度由卷纲情绪弧线的「情绪基调 + 强度」承载。章节定位由「这一章在它所属一级结构里的位置」自然落出,不是另贴一套独立标签:一级结构首章多为铺垫 / 共情,中段承载逆转,收尾爆发收束;黄金开篇、高潮结算 + 温情这类章可复合标注(如「高压 + 关系」)或留空。
| 章节定位 | 功能 | 压力级 | 卷内占比(均衡/长书基线,非硬配额) | 钩子要求 |
|------|------|--------|--------------------------|----------|
| 高压章 | 打脸 / 掉马 / 反转 / 高潮;关键点的关键情节落点 | 4-5 | 约 15-20% | 章尾强钩子;承载逆转 / 转折 |
| 普通推进章 | 主线推进、冲突升级、单元剧中段 | 2-3 | 约 40-50% | 章尾中钩子;至少一个小爽点或期待递进 |
| 修炼试错章 | 实力 / 资源积累、能力铺垫、失败试错 | 2 | 约 5-10% | 进度钩子(差一点 / 即将突破),可无反转 |
| 关系回收章 | 感情线兑现、关系转折、身边人日常 | 2-3 | 约 5-10% | 情感钩子;拉扯仍带主线相关 |
| 低压生活章 | 高潮后喘息、关系升温、张弛调节 | 1-2 | 不超过约 10% | 允许弱钩子或仅情绪钩子;不强求反转 / 爽点 |
| 信息整理章 | 转场、设定交代、时间缝合 | 1 | 不超过约 5%,能并章就并章、少独立成章 | 允许无显性爽点;信息用「表演」承载;结尾给下一段目标 |
两条底线:
- **期待不断、爆发分布**。低压章可以没有爽点和反转,但每章都要给读者一个往下看的理由(微好奇、阶段目标、暧昧期待)。掉的是爆发烈度,不是往前的拉力——番茄追读尤其吃这条。
- **禁情绪母题扎堆**。比「每章像短篇」更隐蔽的疲劳源,是连续多章同一情绪母题高位运行(如连五章家国 / 泪目)——章节定位分得再开也救不了。排卷纲情绪弧线时逐行看相邻 3-4 章的情绪基调,同母题别连超 2-3 章;靠换情绪、换钩子方式、多线穿插来差异化,不是靠砍钩子。
题材分级(上面占比是均衡 / 长书基线,按题材分档):番茄短平快 / 男频事业线,高压可到 30% 以上、呼吸章压到 5% 上下都正常,别拿基线去「补呼吸、砍高压」反而掉追读;女频 / 世情 / 追妻,人设关系容量大、关系 / 低压章可更多,但仍走情绪折线、不必每章三折。低压 / 关系章定位是看点(主角身边人的日常本身是订阅点),不是填充。
与字数目标的衔接:章节定位决定节拍功能与展开取舍,但不把每个情节点换算成固定字数,也不靠增点凑目标。写后由程序按双层长度带验收:明显欠长先判断已批准义务是否未实现,容量不足或不明确就协商自然长度、补纲或目标,绝不自动补写;明显超长可做一次不新增语义、逐项保留批准情节点与章尾钩子的净删型压缩,复检仍带外就停止,不进入循环删改。
---
## 质量检查清单
完成大纲/结构设计后,逐项检查:
- [ ] **结构层级匹配**:选择的层级(一级/二级/三级)与题材和篇幅匹配
- [ ] **因果链完整**:五幕式每幕有固定功能,无跳步、无乱序
- [ ] **转折有因**:每个转折的因已提前埋下,不是突兀出现
- [ ] **难度递增**:障碍难度从低到高,没有递减或匀速
- [ ] **钩子不间断**:大钩子一个断了马上接另一个,没有空窗期
- [ ] **支线不废**:每条支线与主线有关,支线人物服务于主线
- [ ] **五级展开合理**:下一级服务上一级,不超过3级(长篇)
- [ ] **暗线有伏笔**:暗线从开局就埋伏笔,不是后期硬塞
- [ ] **换地图有铺垫**:人际关系先行,不是突然跳地图
- [ ] **刻度尺一致**:顶层实力标杆已设,boss难度在合理区间
- [ ] **多线挖填平衡**:挖的坑有计划填,填完有新坑接上
- [ ] **装逼暗线匹配**:明线战力 > 暗线社会认知时触发装逼,装逼后暗线拉平
- [ ] **章节定位分布**:本卷有高压 / 推进 / 呼吸的层次,不是全程同一力度?低压 + 过场克制(合计不超约 15%)?
- [ ] **期待不断**:低压 / 过场章仍给了往下看的理由(不是裸奔无钩子)?相邻章没有情绪趋同?
- [ ] **对标坐标**(有对标书时):1/4·中点·3/4 各锚定一个关键情节,且是换素材而非照搬桥段?
references/plot-core-methods.md›
# 剧情核心方法 — 操作手册
> 小纲设计、高潮构建、卡文对策、循环设计、连续性追踪等剧情创作的核心方法。
> 遇到问题先查路由表,找到对应方法再操作。
---
## 决策路由表
| 你在做什么 | 用什么方法 | 跳转到 |
|-----------|-----------|--------|
| 建小纲/细纲 | 小纲四步法 | [小纲四步法](#小纲四步法) |
| 设计高潮 | 高潮构建公式 + 逆推法 | [高潮逆推法与AB粗纲](#高潮逆推法与ab粗纲) → [高潮构建公式](#高潮构建公式) |
| 卡文了 | 卡文对策 + 循环设计 | [卡文对策与剧情循环设计](#卡文对策与剧情循环设计) |
| 管理连续性 | 连续性追踪 + 节奏管理 | [连续性追踪与节奏管理](#连续性追踪与节奏管理) |
| 设计过渡衔接 | 剧情过渡 + 场景转换技巧 | [剧情过渡与衔接](#剧情过渡与衔接) → [场景转换技巧](#场景转换技巧) |
| 开书/设计噱头 | 噱头分类与开篇流程 | [噱头分类与开篇流程](#噱头分类与开篇流程) |
| 拉长剧情 | 设门槛 | [设门槛——拉长剧情的核心技巧](#设门槛拉长剧情的核心技巧) |
| 管理期待感 | 大剧情拉期待法 | [大剧情拉期待法](#大剧情拉期待法) |
| 写日常文 | 日常文大纲框架法 | [日常文大纲框架法](#日常文大纲框架法) |
| 判定是否自嗨 | 自嗨判定法 | [自嗨判定法](#自嗨判定法) |
---
## 小纲四步法
细纲与正文比例控制在 **1:2.5 ~ 1:3**。
按以下四步操作:
1. **分段判断** — 把大纲按剧情节点分段
2. **标注目的和效果** — 每段标注,不展开情节
3. **标注详写/略写** — 明确哪些段展开、哪些段带过
4. **快速定位** — 让后续写作能快速定位本段要交付的目的和效果
记住:细纲只关注目的和效果,不展开情节。
---
## 高潮逆推法与AB粗纲
### 核心思路
从高潮反推前面需要铺垫的人物和情节,再用AB交替法填充。
### AB粗纲法
| 标记 | 含义 | 操作 |
|------|------|------|
| A | 压情绪/铺垫/伏笔 | 铺设困难、对手强势、悬念埋线 |
| B | 抬情绪/擦边/小收获 | 小反转、小进步、读者爽一下 |
操作流程:确定高潮 → 反推所需铺垫 → ABABAB排列 → 写作时只关注当前AB段。
适用场景:节奏快、有明确高潮节点的剧情。
---
## 高潮构建公式
### 五步公式
按顺序执行:**蓄能 → 假胜 → 崩解 → 交叉死磕 → 悬置收尾**
1. **蓄能**:牺牲+焦灼打底,让观众从"看客"变"参与者"
2. **假胜**:先给希望再击碎(情绪落差 = 反转冲击力)
3. **崩解**:所有伏笔一次引爆 + 推入单人绝境(帮手全失)
4. **交叉死磕**:对抗线+绝境线来回切换(每切一次紧张感+1)
5. **悬置收尾**:余劲不散,胜负不立刻揭晓
关键操作:假胜是常用高潮技法。适合强反转、强压迫或大高潮;低压力章节、纯奖励章、日常/关系回收章可不用。没有假胜时,需用别的方式提供情绪落差或明确兑现。
---
## 噱头分类与开篇流程
### 三种噱头类型
| 噱头类型 | 特点 | 写法要点 |
|----------|------|----------|
| 事件噱头 | 集中在开篇,约5章 | 一上来就进入事件,不铺垫穿越/金手指 |
| 金手指噱头 | 分布全文,前期多后期少 | 先写主角和困境,再引出金手指 |
| 人设噱头 | 人设直接影响剧情构建 | 只有当人设本身能持续制造戏剧性时使用 |
规则:事件写法和金手指写法不能混用。
### 两种标准开篇流程
**事件开篇**:事件切入(5章)→ 嫁接主线 → 拆分目标 → 阶段性爽点循环
**主线开篇**:描写主角现状 → 营造代入感 → 描写社会环境 → 设立主角目标 → 拆分目标(设门槛)→ 绑定金手指 → 获得第一次提升 → 情绪拉扯2-3次 → 完成 → 引出下一个目标
### 噱头吸量策略
| 策略 | 做法 |
|------|------|
| 噱头延伸型 | 以开头噱头为核心,后续找类似噱头继续构建 |
| 噱头引流+常规型 | 开头噱头只负责吸量,后续走常规题材内容 |
开头噱头的功能是建立点击和追读承诺。目的达到后必须嫁接主线。
开书前评估:噱头能不能延伸出后续更多字数?不能延伸就用"噱头引流+常规"策略。
---
## 主线的正确定义
**主线不等于升级**。主线是一件事,升级是主角达成目标的行动。
| 概念 | 定义 | 示例 |
|------|------|------|
| 目标(主线) | 主角要完成的一件事 | 斗破苍穹:上云岚宗复仇 |
| 行动 | 主角为达成目标做的事 | 努力修炼、不断提升实力 |
检查主线是否符合以下特征:
- 主线是一件事,不是一个元素
- 主线完成后,要么通过铺垫开启第二条主线,要么完结
- 锚点错误会导致后续所有剧情偏差
---
## 卡文对策与剧情循环设计
### 核心公式
题材 + 金手指 + 主角身份 = 循环模式。三要素必须统一。
### 6种经典循环模式
| 模式 | 循环机制 | 循环燃料 |
|------|---------|---------|
| 案件串循环 | 案件→解谜→部分真相→更大谜团→新案件 | 信息差+推理 |
| 扮猪吃虎循环 | 默默发育→挑衅→碾压→震惊→继续发育 | 读者-角色信息差 |
| 资源积累循环 | 资源→技能→实力→新地图→新资源 | 螺旋上升 |
| 戏剧性反转循环 | 亏钱→反转赚更多→拿更多钱去亏→又赚 | 不依赖数值膨胀 |
| 组织枢纽循环 | 各自冒险→信息汇聚→衍生新剧情 | 信息交换+多线 |
| 公路片循环 | 走一段路→遇一个人→又走→又遇 | 人物塑造力 |
### 地图四势力框架
新手村(开局首张地图)必须包含四种势力形成资源闭环——这是全量框架;后续换地图可简化(见下「换地图的地图详略设计」),但变现/资源闭环渠道别丢:
1. **学校/武馆** — 学技能、提升实力
2. **商贩/药行** — 卖出收获、获取资源
3. **山贼/敌人** — 展现学习成果的靶子
4. **官府/管理机构** — 更高的上升通道
### 地位-环境同步原则
地位升高必须环境危险度升高。两者不同步 = 读者觉得无聊。
### 换地图三策略
1. **新旧地图联动**(新势力是旧势力的上级)
2. **带人走**(把重要人物带到新地图)
3. **提前铺垫吸引力**(让读者主动盼着去)
### 特殊类型处理
- **天才流**:大幅增加等级数量,防止数值几十章就崩
- **无敌流**:循环核心转为信息差(来一个秒一个,每次刷新认知)
---
## 日常文大纲框架法
### 创作路径
按以下步骤操作:
1. 从阅读中发现有趣的设定/关系/背景
2. 围绕灵感确定事业线+感情线
3. 选择节奏最快、情绪最足的节点切入
4. 对每个阶段拆分信息差+人际关系+情绪
5. 按时间顺序排列事件
6. 写作前勾勒章纲
### 大纲推演法
以"实现房东租客关系"为例:
1. 目标:实现男女主房东租客关系
2. 拆分:主角家中要有空房,距离高中近
3. 推演:有空房=家庭条件好 → 最好是贷款买,有压力
4. 逆转理由:父母上世投资失败 → 这世主角逆转 → 买学区房
### 大纲节点格式
```
事件名称:
信息差:1. 主角知道什么/配角不知道什么 2. 读者视角 vs 角色视角
人际关系与情绪:1. 主角情绪 2. 女主/配角反应 3. 负面情绪提供者
```
### 关键原则
- 大纲服务正文生成,不是枷锁
- 日常文不要有太多猛增好感的大事件,用小事件串联缓慢增长
- 事业线要和女主自身及家庭串联,达到日常和事业互相糅合
---
## 大剧情拉期待法
### 自上而下的创作逻辑
按顺序执行:
1. **明确核心和目的** — 先确定这段大剧情的爽点
2. **确定篇幅目标**
3. **设计分阶段剧情** — 围绕爽点设计若干小剧情,每个是下一个的铺垫
4. **技巧杂糅填充**
### 案例演示:参加好歌曲演唱青花瓷
**核心爽点**:主角登台演唱青花瓷,引起震撼
分阶段设计:
1. 收邀请+公园哼唱《送别》→ 震惊评委(前置暗示)
2. 彩排现场挑衅 → 制造压力
3. 节目前夜给邓紫棋写《泡沫》→ 叠加实力展示
4. 现场PK → 设备故障(加压)→ 演唱青花瓷 → 震惊
5. 评委扣分 → 分数持平(反转压制)
6. 歌手演唱主角作品 → 曝光主角是创作者(二级震惊)
7. 设备故障说明 → 得分逆袭(反转翻倍)
8. 评委要求唱《送别》→ 持续拉期待
要点:先有大爽点,再分阶段去抵达;从局部看节奏快,从整体看推进慢(只讲了一件事)。
---
## 连续性追踪与节奏管理
### 热度状态
| 状态 | 定义 |
|------|------|
| hot | 当前驱动冲突的核心元素 |
| warm | 近期活跃的元素 |
| cold | 超过安全线未触及,有被遗忘风险 |
| archived | 已完结/有意关闭的元素 |
### 有效触碰判定
以下算有效触碰:直接推进该线索、施加压力、改变关系状态、产生实际后果、交代合理的休眠原因。
不算有效触碰:纯粹提个名字、空头回调、随机提及。
### 回顾阈值
| 元素类型 | 触及间隔 |
|----------|----------|
| 核心角色 | 3-5 章 |
| 主要支线 | 4-6 章 |
| 活跃伏笔 | 2 次错过机会 |
| 不稳定关系 | 2 次出场 |
### 每章必做自检
1. 当前 hot 的元素是什么?
2. 有没有 cold 了但该 warm 的?
3. 哪些可以合理保持休眠?
4. 哪条线索的回归能加深压力?
### 失败信号(出现就要修正)
- 读者问"那个谁去哪了?"
- 重要的线索到结尾才突然冒出来
- cold 的铺垫突然变成 hot 的回报(没有预热)
### 核心冲突的节奏保护规则
1. 非大结局章节通常不解决全书核心冲突;若阶段核心冲突收束,要同步开启下一期待
2. 章末约200字宜保留悬念、决定、发现、余韵或阶段目标;低压章节不强求硬悬念
3. 局部胜利可伴随新的代价、风险或下一任务;纯奖励/低压回收章可只提供明确收益和后续期待
### 事件后的冷却章节数
| 事件类型 | 冷却(章) |
|----------|-----------|
| conflict_thrill(大冲突/打斗) | 2 |
| bond_deepening(关系深化) | 1 |
| faction_building(建立势力) | 2 |
| world_painting(世界观展开) | 3 |
| tension_escalation(压力升级) | 2 |
规则:冷却期内该类型不能作为主beat;conflict_thrill最多连续2章;每5章必须包含bond_deepening或world_painting。
### 过渡章节管理
- 单元故事结束前先把下一个目标拉出来
- 过渡章节必须维持至少一条活跃的期待线
### 换地图期待感延续
| 延续方式 | 做法 |
|----------|------|
| 复仇线 | 未完成的目标跨地图持续 |
| 旧日关系线 | 老角色在新地图出现 |
| 信息差 | 某方以为某事,实际不是 |
| 提前铺垫 | 换地图前让新地图角色/传说与主角接触 |
### 金手指的四阶段演进(基础→发展→成熟→升华)
| 阶段 | 操作要点 |
|------|---------|
| 基础 | 明确核心作用,建立读者认知 |
| 发展 | 增加新的使用方式,核心作用不变 |
| 成熟 | 与世界观深度结合,可与其他系统联动 |
| 升华 | 作用对象从个人扩到世界/天道层级,需足够伏笔支撑(签到系统:签到得物→万物可签→对人/地脉签到→签到本身成世界规则、人人信仰) |
规则:金手指重心可转移但必须有足够伏笔;可部分淡化不能完全抛弃;呈现力度应随阶段递增。
### 矛盾网设计
- 同一时刻保持2-3条矛盾线同时运行
- 矛盾线之间要有关联(因果、利益冲突、信息差)
- 每次解决一个矛盾,必须激活或加深另一个矛盾
| 层级 | 范围 | 说明 |
|------|------|------|
| 章级 | 2-3章 | 小冲突,服务于当前单元 |
| 卷级 | 一卷 | 本卷核心矛盾,卷末解决 |
| 书级 | 全书 | 终极矛盾,大结局解决 |
### "两长一短"期待法则
- 1个短期期待:当前单元的明确目标(只能有一个)
- 1-2个长期期待:远期目标预告/悬念/组织/人物
### 持续拉期待的方法
1. 在"基底期待"上添加细节,注入新的具体化需求缺口
2. 设置多个核心梗交替运行(装逼线A + 解密线B + 感情线C)
3. 设计世界观层面的"秘密"和"阴谋"
### 升级差异化管理
| 维度 | 说明 |
|------|------|
| 能力差异化 | 每个等级有质变性的新能力(炼气只能御剑→筑基能御物攻击) |
| 待遇差异化 | 不同等级获得不同的社会待遇(练气当杂役→筑基分独立洞府) |
| 人际关系网差异化 | 不同等级面对不同层次的人际关系(练气只接触师兄弟→筑基有长老正眼相待) |
如果升级前后在三个维度上没有明显差异,读者就不会有升级快感。
### 单元故事嵌套
- 在第一个单元故事高潮前,插入第二个故事的期待线
- 完成当前目标前,提前给出下一个目标的线索伏笔
- 完成当前目标后,迅速给出反转或变故,营造新期待
### 长线节奏设计
- 一卷 = 一个完整的中套娃,有自己的起承转合
- 每卷开头是代入期(5-10章),中间是发展期,结尾是高潮+收束
- 信息密度:高密度(情绪强烈、推进快)与低密度(铺垫积蓄)交替,不能一直高或一直低
- 每个低密度章节至少埋一个让读者想知道后续的点
### 期待感管理
三层期待同时运行:
- 短期期待(下一章会发生什么)
- 中期期待(这个剧情单元会怎么收)
- 长期期待(主角最终能不能达成目标)
---
## 剧情过渡与衔接
### 从一个剧情点到下一个
核心问题:主角实力提升了,但下一步干什么不清楚。解决方案:每次提升后立即引入新的挑战或目标。
### 剧情嵌套(套娃结构)
- 大套娃:整本书的主线
- 中套娃:每个卷/阶段的阶段性目标
- 小套娃:每个剧情单元的即时目标
- 三层套娃同时运行,读者始终有事可看
### 场景过渡
- 过渡场景该跳过就跳过,不拖泥带水
- 过渡不是填充,没有信息量就删掉
### 情绪衔接
- 上一场景的情绪要自然过渡到下一场景
- 不能前一个场景还在热血,下一个场景突然平淡
### 信息差衔接
- 前一个场景埋下的信息差在后一个场景回收
- 读者带着疑问进入下一场景,衔接自然有效
---
## 设门槛——拉长剧情的核心技巧
### 门槛的本质
门槛不宜只放一个敌人挡路;它应形成系统性的条件设置:主角要达成目标,必须满足一系列条件。
### 设门槛的具体方法
| 门槛类型 | 示例 |
|----------|------|
| 资源型 | 系统升级需要1000灵石,主角身上没有 |
| 成就型 | 考顶级院校需要气血值达标+独自灭杀XX级怪物+比赛前五名 |
| 多条件型 | 把一个大目标拆分成多个阶段小目标 |
| 动态门槛 | 主角资源超标时提高门槛 |
| 收集型 | 突破境界需要多件宝物 |
### 规则
- 门槛必须围绕核心卖点设计,脱离金手指和脑洞的门槛是无效剧情
- 门槛要分批提出,不要一次全甩给读者
- 每跨越一个门槛就立刻设立下一个
### 循环从设定中诞生
- 核心卖点通过"设定"体现,设定确定后自然产生反馈机制
- 设定多一条,循环元素就多一层,可写的内容就越多
- 写着写着把设定写丢了 = 把卖点写丢了
---
## 场景转换技巧
- 过渡场景没有信息量就直接跳过
- 前一个场景留下悬念,后一个场景回应悬念
- 前一个场景热血收尾,下一个场景开头要有余韵
- 切换视角时在悬念点切出,不要在平淡处切出
- 每条线在切换前都要留下一个"钩子"
- 多条线的读者关注度不同,主线占比要最大
### 换地图的深层设计
- 新地图 = 新环境 + 新角色 + 新规则 + 新目标 + 新冲突
- 换地图前:旧地图的核心冲突至少阶段性解决
- 换地图后:前5章必须快速建立新的代入感和期待感
避免以下操作:旧角色一刀切全部抛弃、新设定一次性全部倒出、新地图与旧地图毫无关联。保留至少一条贯穿主线。
每换一次地图,循环要升级:更大的规模、更高的门槛、更强的对手。
### 换地图的地图详略设计
- 换地图(非新手村)按三种势力简化铺:训练场(武馆/学校)、地头蛇(豪绅/地方势力)、破坏者(山贼/麻匪)——这是「地图四势力框架」的精简版,仍要保留变现/资源闭环渠道(商贩/药行),别只剩打斗
- 日常路线扩展关系网:上学/归还装备/逛集市作为新故事弧线的桥梁
---
## 悬念与伏笔技巧
- 小剧情伏笔:先确定结局再倒推线索,从终点往回铺确保逻辑闭合
- 整本书伏笔:大纲阶段确定关键情节,书中不断埋设细节呼应,长线伏笔要记录避免遗忘
- 谜语人vs伏笔:谜语人是故意不说明(容易惹烦);伏笔是巧妙融入剧情、自然不刻意。判定:信息延迟超过 3 章且中间无任何推进=谜语人(删或提前给);主角随口说怕水、后期落水危机才回收=伏笔
- 烧脑剧情:视角只跟主角走,不写反派视角,避免破坏悬念张力
---
## 信息团概念
- 信息团 = 一段剧情要表达的核心信息单元
- 每个信息团必须能一句话概括"这段在讲什么"
- 信息团之间要有逻辑递进关系
- 节奏快 = 信息团密集;节奏慢 = 信息团稀疏;水章节 = 信息团为零或与主线无关
- 例:一章里「主角识破骗局」是 1 个信息团,「顺带交代反派背景」是第 2 个——两个无关就是水章,砍掉第二个或让它服务第一个
---
## 自嗨判定法
### 三个自检问题(必须全部回答清楚)
1. 我这书写给谁看?(至少包括目标读者的年龄段、职业、性别、常用平台、人生处境、普遍渴望)
2. 我的目标读者群体在看网文时希望看到什么内容?
3. 我的这本书有哪些内容是目标读者群体想看的?
判定标准:三问有一问答不好 = 自嗨。立刻停下修正。
### 纠正方法
- 分析同类书的读者评论,提取高频正面关键词
- 对比同类书中高互动与低互动段落的差异特征
- 用同类书的目标读者画像反向校验本书的情节选择
---
## 质量检查清单
每次完成一段剧情设计或一卷大纲后,逐项检查:
### 基础完整性
- [ ] 主线是否明确为"一件事"(避免写成元素罗列或升级条)
- [ ] 循环模式是否与题材+金手指+主角身份统一
- [ ] 三层套娃(大/中/小)是否同时运行
### 节奏与期待
- [ ] 三层期待(短/中/长)是否同时在线
- [ ] 章末约200字是否保留悬念、决定、发现、余韵或阶段目标
- [ ] 信息密度是否有高低交替(不能一直高或一直低)
- [ ] 冷却期规则是否遵守
### 连续性
- [ ] hot/warm/cold 状态是否正常(无该 warm 却 cold 的元素)
- [ ] 核心角色 3-5 章、主要支线 4-6 章内是否有有效触碰
- [ ] 换地图/换阶段后是否保留至少一条贯穿主线
### 高潮与过渡
- [ ] 高潮是否需要假胜(先给希望再击碎);若不用,是否有其他情绪落差/兑现方式
- [ ] 胜利是否需要代价/风险/下一任务;若是纯奖励章,收益是否足够明确
- [ ] 过渡场景是否删掉了无信息量的部分
- [ ] 场景切换是否在悬念点切出
### 避坑检查
- [ ] 门槛是否围绕核心卖点设计(非无效剧情)
- [ ] 金手指是否按四阶段演进(未跳跃、未抛弃)
- [ ] 自嗨三问是否全部能回答清楚
- [ ] 信息团是否每段都能一句话概括"在讲什么"
references/plot-emotion-system.md›
# 情绪体系操作手册
> 主角与对手递进对抗、情绪模块分类、爽点设计、情绪升级与对比、驱动读者欲望。
---
## 决策路由表
遇到具体写作场景时,按此表定位对应方法:
| 你在写什么 | 用什么方法 |
|------------|-----------|
| 主角与对手对抗 | [递进对抗写法](#主角与对手的递进对抗写法) + 装逼层级 |
| 爽点设计 | [爽点设计体系](#爽点设计体系) + 密度建议 |
| 情绪升级 | [情绪升级与对比的核心技巧](#情绪升级与对比的核心技巧) |
| 制造拉扯/误会 | [误会制造拉扯法](#误会制造拉扯法) |
| 用梗驱动剧情 | [以梗构建剧情法](#以梗构建剧情法) |
| 搭配情绪模块 | [情绪模块与戏剧单元分类](#情绪模块与戏剧单元分类) |
| 控制节奏与高潮 | [节奏与高潮控制技巧](#节奏与高潮控制技巧) |
| 驱动读者追读欲望 | [驱动读者欲望的四步公式](#驱动读者欲望的四步公式) |
| 选择驱动方式 | [情绪驱动与事件驱动](#情绪驱动与事件驱动) |
---
## 主角与对手的递进对抗写法
### 核心原则:角力而非碾压
主角与反派的对抗不是一路碾压。让主角在每次小角力中稍占上风,最后迎来大胜利。
斗地主比喻:主角对三,反派对四,主角对A,反派对2,最后主角王炸一锤定音。
### 装逼层级分类
| 层级 | 特点 | 使用场景 |
|------|------|----------|
| 日常小装逼 | 无需剧情,日常生活展示优势 | 距离下个大爽点远时,维持读者耐心 |
| 核心爽点 | 切在主线上,围绕主线目标装逼 | 推进主线同时让读者爽 |
| 偏离爽点 | 背离主线去别处装逼 | 应避免,浪费读者耐心 |
### 角色逼格管理
- 升级线与主角反应线分开管理。
- 同样被骂:主角暴怒反击 = 毒点;主角微微一笑毫不在意 = 逼格。
- 主角反应规则:升级提升的是实力,不自动改变主角的从容反应。面对低级挑衅时,主角应表现为不被牵着走。
### 爽点密度规则
- 不要拉长单个爽点的铺垫,而是多想几个爽点。
- 用层次划分法制造连锁震惊:当场观众震惊 -> 别处观众震惊 -> 专家震惊 -> 配角间信息差抹平 -> 再震惊。
---
## 情绪驱动与事件驱动
### 事件驱动型叙事
- 故事由外部可见的事件串联:被打脸 -> 升级 -> 反打脸。
- 读者刺激来自事件结果:"他能不能打赢?"
- 优点:节奏快、爽点明确、易上手。
- 缺点:开篇用S级事件后,后续A级/B级事件会让读者疲劳。
### 情感驱动型叙事(人物驱动型)
- 故事由人物内在动机、情感变化、人际关系推动。
- 事件悬念是一次性的,人物悬念是持续性的。
- 读者更容易代入、情感拉扯更绵长。
### 本质
两者共同本质是"情绪的波动"。事件驱动通过外部冲突制造波动,情感驱动通过内部冲突和人际张力制造波动。怎么选:
- 番茄爽文/打脸文 -> 事件驱动:每章给一个外部结果(赢了、升级了、对手栽了)。
- 追妻/虐心/世情 -> 情感驱动:事件可以少,但人物心结要一直悬着(他后悔了没?她原谅了没?)。
- 混合 -> 主线用事件往前推,每 3-5 章插一段情感停顿(独处、回忆、试探),让人物心结透口气。
---
## 情绪升级与对比的核心技巧
### 情绪升级
- 爽点不是一次到位的,需要层层铺垫和递进。
- 负面情绪要逐步升级到饱和,再转化为正面情绪。
- 通过反复的拒绝、嘲笑、质疑来不断加码负面情绪。
### 对比手法
- 对比是爽文的底层逻辑之一。
- 配角失败 vs 主角成功(关羽温酒斩华雄)。
- 配角得意 vs 主角碾压(比袈裟:金池长老沾沾自喜 vs 唐僧袈裟降维打击)。
- "没有对比就没有伤害"。
### 负面情绪的正确用法
- 负面情绪只是让鸡下蛋的一种手段,不是唯一方法。
- 关键是理解题材的情绪链条朝什么方向走。
- 《登神》几乎没有情绪压抑套路,照样是大爽文——"情感缺口"来自读者对俗套情节的厌倦。
### 情绪拉扯的实用素材
- 过渡、日常、平淡剧情中也可以做情绪拉扯。
- "求人办事"类桥段:阻碍设置、权力展示、以退为进。
- 以退为进、欲左先右是过渡章节中有效的情绪拉扯结构模式。
---
## 爽点设计体系
### 爽点的本质
- 爽点不只是装逼打脸,而是包含各种各样的情绪满足。
- 纯输出正面情绪也可以形成爽点,但无法将爽感最大化。
- 让负面情绪转化为正面情绪 = 最大程度满足读者。
### 六种爽点类型
| 类型 | 核心 | 功能延伸 |
|------|------|----------|
| 能力碾压 | 实力远超对手,纯粹优越感 | -- |
| 目标达成 | 完成阶段性目标 | 引出行动线和下一步计划 |
| 收获盘点 | 清点获得的资源/人脉/能力 | 利用收获引出下一步剧情 |
| 态度转变 | 配角从轻视到敬佩 | 利用配角引出下一步剧情 |
| 隐藏身份/掉马甲 | 身份逐步被揭开 | 不断制造震惊 |
| 情感圆满度 | 追夫/妻火葬场,关系修复的满足感 | -- |
### 设计爽点的倒推法
1. 先确定用什么方式让读者满足(爽点类型)。
2. 再设计如何拉起期待(期待点)。
3. 最后设计如何铺垫(铺垫)。
4. 设计章纲时也按这个顺序思考。
---
## 情绪模块与戏剧单元分类
### 提炼层级
从原型故事逐级提炼出可复用工具。核心原则:**戏剧性会磨损,情绪不会磨损**。
| 层级 | 名称 | 内容 | 说明 |
|------|------|------|------|
| 零级 | 具体故事 | 原文完整情节 | 直接搬用 = 抄袭 |
| 一级 | 经典故事情节 | 去描写,留素材(人名/地名/事件) | 换汤不换药,仍有雷同风险 |
| 二级 | 故事构型 | 去素材,只剩逻辑走向 | 戏剧单元 + 情绪模块的组合体 |
| 三级 | 戏剧单元 | 戏剧性走向的抽象 | 可自由组合的逻辑结构 |
| 四级 | 情绪模块 | 读者想看什么的抽象 | 期待感方向 + 爽感方向 |
**故事构型 + 素材 = 具体故事**。用法两种:①**重构**(保留素材,彻底改构型,长篇必备);②**微调**(用经典情节,按人设深挖微调,短篇适用)。人设与经典情节冲突时必须重构。
贯穿例子(拿一篇追妻文逐级往上扒):
- 零级 = 《某追妻文》原文,连对白带场景照搬。
- 一级 = 去掉描写,只留素材:"前夫上门求复婚被拒"。
- 二级 = 连素材也扔掉,只剩走向:"施害方追悔 -> 受害方已经不在乎了"。
- 三级戏剧单元 = "迟来的追悔"。
- 四级情绪模块 = 读者想看的两件事:"渣男后悔 + 主角不回头"。
换壳示范:抓住二级走向"施害方追悔 -> 受害方不在乎",换一套素材就是新故事——职场版(坑过你的上司栽了来找你,你已经跳槽当老板)、古言版(休妻的夫君败落来求和,你已是诰命)。
### 情绪模块与戏剧单元的关系
- 大/中戏剧单元 = 戏剧性的抽象,笼罩整本书或大段剧情的基调。
- 情绪模块 = 情绪核心的抽象,对应具体的情绪爽点。
- 叙事元素和结构技法合称"辅助工具",不能独立提供完整框架,必须应用在某个完整框架内。
### 戏剧性与情绪的关系
- 同一套路(如英雄救美)反复用不腻,腻的是结构不变;每次换场景/换对手/加新情绪就不算重复。
### 情绪模块卡片
#### 修罗场卡
- 多个人喜欢同一个人,在被喜欢的人面前互相竞争。
- 递进设计:初期(跟男1逛街被男2撞见)-> 中期(跟男2接吻被男主撞见)-> 后期(男1、男2大打出手)。
#### 倒计时卡
- 需要一个计时,倒计时结束时必须有事情发生。
- 常结合实力悬殊的战斗:打不过但必须打。
#### 恩怨情仇卡(大/中戏剧单元)
- 两个人因特定事件形成带有强烈情感或道德伦理枷锁的关系。
- 重点不在"形成恩怨的过程",而在恩怨形成后的行为和情感。
- 作为大戏剧单元是笼罩整本书的"基调"。
#### 双重身份卡
- 两个身份重叠的一刹那给读者带来意外。
- 设计要点:A身份的日常塑造 + 隐藏信息 + B身份揭示时的冲击。
#### 特殊对待卡
- 拯救人物OOC的神器。
- 用"特殊对待"来合理化角色在特定情境下的行为偏离。
#### 好感变化卡
- 核心在于展示情绪链条的质变。
- 英雄救美作为载体:关键是关系质变,不是怎么救。
- 避免重复:每卷的复杂程度和收获上升,情绪呈螺旋上升趋势。
#### 装逼的深层理解
- 核心在于牛逼和不牛逼之间的对比。
- 可用"几成力"来对比:对完招再吹用了几成力。
- 前期铺垫:嘲讽压抑的情绪、主角扮猪。
#### 以小搏大
- 成本与收获之间的比例要巨大。
- 过程要有随机性和主观能动性,不能让读者觉得100%成功。
- 可以不成功,但通过歪打正着、贵人扶持等方式补充情绪缺口。
#### 误解卡
- 系列误会步骤:确定核心误会 -> 自然衍生各小误会 -> 确定解除条件 -> 设计障碍。
- 误解消除规则:对事业线/爱情线有负面作用的必须消除;没有负面作用或有正面作用的可以不消除。
### 叙事元素卡片
| 卡片 | 核心用法 |
|------|----------|
| 工具人卡 | 特定场景满足叙事需求:烘托/推动/提供情报 |
| 迷之少女卡 | 梦/回忆/幻觉中对剧情起关键作用的线索,不能随便放开头 |
| 失能卡 | 角色不能用意识正常控制身体/道具,可与人设绑定成为缺陷 |
| 关系卡 | 角色间特定关系配置,决定互动基本模式 |
| 秘密卡 | 保守秘密/挖掘秘密/无意得知秘密 |
| 闹矛盾卡 | 意见不合/误会/伤害 -> 争吵/对抗/散伙 -> 后悔/和谈/危机促和好 |
| 双界联系卡 | 穿越型/联系型/融合型 |
| 紧追其后卡 | 追逐/追踪/跟踪三种形式 |
| 隐蔽行动卡 | 角色的隐蔽行动/调查他人的隐蔽行动/他人对角色的隐蔽行动 |
| 未来窥视卡 | 预言/穿越记忆/系统提示,反应:避免/争取/利用/换取好处 |
| 禁忌卡 | 特定个体/群体/物品/场所/活动的禁忌,必须明示触犯下场 |
| 新环境扮演卡 | 卧底/被挟持/失忆/穿越,确认要素:对方背景、性格、技能、弱点 |
### 结构技法卡片
| 卡片 | 核心用法 |
|------|----------|
| 差异评价卡 | 两种思路:打压与反转;借人之手是变体 |
| 戏剧三角卡 | 迫害者、受害者、拯救者三者可转换 |
| 翻弄风云 | 强调主角行为对不同角色的意义和影响 |
| 解谜设计 | 设命题P1/P2 -> 推导P3 -> 取反推导P4 -> 隐藏P3产生误导 |
### 组合与提炼
- 一级提炼:从成功作品中提取基本叙事模式。
- 二级提炼:在一级框架上加入特定题材元素。
- 不同类型卡片可叠加:核心梗卡 + 关系卡 + 限制卡 = 完整剧情单元。
- 重构使用:保留素材名称,替换故事走向。
- 微调使用:保留故事走向,增加新的情绪模块。
- 螺旋上升:同一套路每次出现时复杂程度和收获都上升。
### 常见误区
1. **故事雷同**:只做一级提炼(换名字不换结构),读者眼里和抄袭无区别。
2. **人设崩坏**:为套用经典情节强行让人物做不符合人设的事。
3. **创新失控**:脱离情绪模块的"创新"容易变成毒点。
4. **扼杀核心创意**:"读者爱看"和"自己爱写"别变成二选一。
---
## 误会制造拉扯法
### 误会的本质
"我原先以为 A,后来发现全错了" -- 信息差制造情绪落差。核心是信息差的运用。执行时必须确保每一步都有明确的信息差设计。
| 场景 | 用法 |
|------|------|
| 装逼打脸 | 主角谦虚 -> 配角误以为主角弱 -> 反转打脸更爽 |
| 感情线 | 误会制造心有芥蒂 -> 阻碍感情发展 -> 解开时更甜 |
| 人设反差 | "我以为主角很弱,但他其实超级强" |
| 世界观设定 | "我以为世界能修仙,但其实不能" |
### 操作要点
- 感情线中:不能真正扯开(不能分手),而是"心有芥蒂""暂时冷静"。
- 拉近关系用英雄救美,扯开关系用误会。
- 装逼打脸中:主角的谦虚/低调本身就是误会制造器。
---
## 以梗构建剧情法
### 四段式
1. **发生**:建立初始情境,引出梗的前提条件。
2. **发展**:通过反复挫败或积累,推向梗的触发点。
3. **转折**:利用金手指或关键手段实现梗的反转。
4. **高潮**:梗的完整释放 -- 前后反差最大化。
用梗作为高潮点倒推剧情,天然避免流水账。只要有新梗,就能持续写出有意思的剧情。
---
## 节奏与高潮控制技巧
| 要素 | 规则 |
|------|------|
| 大高潮周期 | 7-10天完成(一天双更,14章),超过10天读者易反感 |
| 小高潮周期 | 控制在3天左右 |
| 高潮后过渡 | 加1-2章日常过渡,给读者喘息空间 |
| 追订下降应对 | 快速进入下一段故事,不要在低谷期犹豫 |
| 公众期5章循环 | 1章人设建立 + 2章铺垫 + 1章打脸 + 1章反响 |
| VIP节奏 | 1-2章人设 + 5章铺垫 + 1-2章打脸 + 1章总结 |
| 多线缓解疲劳 | 插入半章配角视角,换视角换节奏 |
| 高潮过渡技巧 | 高潮前穿插支线人物埋伏笔,高潮后拎出来自然过渡 |
---
## 驱动读者欲望的四步公式
**核心公式**:生产诉求 -> 给予希望 -> 努力解决 -> 得偿所愿
### 第一步:生产诉求
- 用"低地位""困境""迫在眉睫的威胁""不曾拥有"让读者感同身受。
- 读者看到诬告、不公、恃强凌弱,天生生出"不该如此"的念头。
### 金手指的本质
金手指是现实中我们难以拥有的特质/能力。没有金手指,困境的痛苦会让读者感到无力。
### 节奏的本质
- 不断解决现有矛盾 + 不断制造新矛盾。
- 方式一:"逐渐变好" -- 目标拆分。
- 方式二:"新的困境" -- 矛盾层级递进。
- 好的节奏:困境层级层层递进,种类多样,解决方式也多样。
---
## 质量检查清单
完成一个章节或一段剧情后,逐项检查:
- [ ] **决策路由**:是否按路由表选对了对应方法?
- [ ] **对抗递进**:主角与对手的每次交锋是否逐级升级?是否存在一上来就碾压?
- [ ] **装逼层级**:日常小装逼 / 核心爽点是否区分清楚?是否出现偏离主线的装逼?
- [ ] **爽点类型**:是否明确使用了六种爽点之一?是否能说清属于哪种?
- [ ] **爽点倒推**:是否先定爽点类型,再设计期待,最后补铺垫?
- [ ] **情绪升级**:负面情绪是否逐步加码到饱和再释放?是否一步到位?
- [ ] **对比手法**:是否用了配角衬托来放大主角的爽感?
- [ ] **误会拉扯**:感情线误会是否控制在"心有芥蒂"而非真正分手?
- [ ] **梗的四段式**:发生 -> 发展 -> 转折 -> 高潮是否完整?是否缺少转折直接跳到高潮?
- [ ] **节奏周期**:大高潮是否在7-10天内完成?小高潮是否在3天左右?
- [ ] **读者欲望**:是否走完"生产诉求 -> 给予希望 -> 努力解决 -> 得偿所愿"四步?
- [ ] **卡片组合**:情绪模块、叙事元素、结构技法是否叠加使用而非单独依赖?
- [ ] **螺旋上升**:同一套路再次出现时,复杂程度和收获是否比上次更高?
references/plot-frameworks.md›
# 剧情框架 — 操作手册
> 指令语气:直接、具体、可执行。不说"可以考虑",说"必须做"。每个条目都是一个可落地的写作操作,不是理论探讨。
---
## 决策路由表
根据当前写作场景,定位到对应章节。不要从头读到尾,按需取用。
| 你的场景 | 操作 | 跳转到 |
|---------|------|--------|
| 选定了题材/类型,需要搭大结构 | 先确认题材属于哪种循环模式,再选对应框架 | [题材→框架路由](#题材框架路由) |
| 升级文/系统文/玄幻:需要设计等级循环和奖励节奏 | 看RPG结构与奖励设计 + 玄幻框架拆解 + 套路模板重复法 | [RPG结构与奖励设计](#rpg结构与奖励设计) / [玄幻框架拆解](#玄幻框架拆解) |
| 爽文/装逼文:需要设计打脸装逼的节奏 | 看阵营手牌法 + 套路模板重复法 + 装逼五步法 | [框架与阵营手牌法](#框架与阵营手牌法) / [套路模板重复法](#套路模板重复法) |
| 感情线/追妻/虐文:需要设计拉扯节奏 | 看双线法与信息差 + 结构与人物的关系 + 悬念技巧 | [双线法与信息差](#双线法与信息差) / [结构与人物的关系](#结构与人物的关系) |
| 开新卷/开新书:需要设计开头和卷结构 | 看开头设计要点 + 大结构的设计 + 热门书大框架拆解法 | [开头设计的要点](#开头设计的要点) / [大结构的设计](#大结构的设计) |
| 多线并行:需要管理主线+支线+日常 | 看框架与阵营手牌法 + 热门书大框架拆解法的多线穿插 | [框架与阵营手牌法](#框架与阵营手牌法) |
| 卡文/不知道下一步写什么 | 看分步骤与缓冲区 + 有进无出原则 + 悬念与冲突深化 | [分步骤与缓冲区](#分步骤与缓冲区) |
| 套路用腻了,需要变招 | 看故事构型与套路运用 + 核心梗与细化法 | [故事构型与套路运用](#故事构型与套路运用) / [核心梗与细化法](#核心梗与细化法) |
| 需要细化到章级结构 | 看结构化拆书法(单桥段四章结构) | [结构化拆书法](#结构化拆书法) |
| 全局把控:整本书会不会崩 | 看剧情流判断标准(五不崩) + 故事本质与六幕结构 | [剧情流判断标准与优势](#剧情流判断标准与优势) |
| 需要设计冲突和悬念 | 看冲突结构 + 死亡赌注 + 五种矛盾类型 + 悬念技巧 | [冲突的结构与有进无出原则](#冲突的结构与有进无出原则) |
| 画面感不足/写出来干巴巴 | 看分镜与画面感 | [分镜与画面感](#分镜与画面感) |
| 设计双线/现实+副本交替结构 | 看双线交替框架拆解 | [双线交替框架拆解](#双线交替框架拆解) |
| 设计死亡赌注与黏结剂 | 看冲突的死亡赌注与黏结剂设计 | [冲突的死亡赌注与黏结剂设计](#冲突的死亡赌注与黏结剂设计) |
| 选择矛盾推动类型 | 看利用矛盾推动剧情的五种类型 | [利用矛盾推动剧情的五种类型](#利用矛盾推动剧情的五种类型) |
| 补充情绪调动/剧情技巧 | 看补充结构与剧情技巧 | [补充结构与剧情技巧](#补充结构与剧情技巧) |
### 题材→框架路由
| 题材类型 | 核心循环模式 | 主用框架 | 辅助框架 |
|---------|------------|---------|---------|
| 升级文(玄幻/修仙/都市异能) | 夺宝+比武+美女 三要素轮换 | 玄幻框架拆解 | RPG奖励设计、阵营手牌法 |
| 系统文/无限流 | 任务→奖励→兑换→新任务 | 核心梗循环法 | RPG奖励设计 |
| 追妻火葬场 | 伤害→追悔→挽回→反复拉扯 | 双线法与信息差 | 结构与人物关系、悬念技巧 |
| 重生复仇 | 前世记忆→布局→反杀→升级 | 有进无出原则 | 九条主线套路法 |
| 都市装逼文 | 扮猪→吃虎→震惊→换地图 | 套路模板重复法 | 阵营手牌法、装逼五步法 |
| 种田/基建 | 筹备→建设→收获→扩张 | RPG奖励设计 | 核心梗循环法 |
| 苟道文/扮猪吃虎 | 隐藏实力→被看低→碾压→继续隐藏 | 双线交替框架 | 信息差技巧 |
| 甜宠/日常向 | 小冲突→解决→甜蜜→新小冲突 | 结构化拆书法(桥段四章结构) | 缓冲区概念 |
| 悬疑/解谜 | 线索→推理→反转→新谜题 | 故事本质与六幕结构 | 悬念技巧、伏笔展开 |
| 热血战斗 | 升级→挑战→失败→爆发→碾压 | 装逼五步法 + 温酒斩华雄式 | 有进无出原则 |
---
## 双线法与信息差
### 双线法的基本思路
- 主线:让主角在做事的过程中产生情绪
- 副线:让配角在挖掘主角身份/态度的过程中产生情绪
- 把主角的幕后身份、人脉、背后故事写清楚,设计好缓冲区
- 配角不断发现、不断被震惊就是一条很好的情绪线
### 信息差的运用
- 信息差是并列式衔接的关键工具
- 主角知道读者知道但配角不知道 -> 配角发现时的震惊
- 利用信息差可以制造多层爽点
- 切换视角时用信息差做钩子,重新拉起读者兴趣
### 《作家之旅》式的情绪推动
- 先让主角走符合逻辑的路(拒斥召唤)
- 通过一系列情绪拉扯、安全感打破,让主角选无可选
- 最终选A但一切符合逻辑、顺其自然
---
## 分步骤与缓冲区
### 缓冲区概念
主角和配角之间因利益、事件、感情产生了一段距离。随着这段距离不断被攻略,产生爽感。设计缓冲区需要把主角背后故事写清楚。
### 目标的分步骤拆解
- 主角始终有根本目标,把目标分成几个阶段
- 不止大的目标,当前小目标也可以这样拆
- 目的明确后行动才不会拖拉
### 剧情推进的三种模式
1. 主角主动去处理能推进目标的麻烦事
2. 主角主动推进目标,过程中遇到麻烦
3. 主角被找上门的麻烦事,解决后反而推动了目标
### 计划-阻碍式结构
计划1 -> 意外1 -> 计划2 -> 意外2 -> 高潮
每一步计划都可能被打断,形成新的期待。
---
## 大结构的设计
### 大结构是欺骗式的主线
大结构作为噱头吊着读者,每次接近完成又差一点,悬念永不断。如马甲曝光线:每次都被质疑,每次都能打破质疑,但总是差一点曝光。
### 起承转合的大框架
| 阶段 | 内容 |
|------|------|
| 起 | 建立世界观、引出主角、给出金手指 |
| 承 | 主角利用金手指推进,填充大量小剧情 |
| 转 | 局势变化,引入更大的敌人或危机 |
| 合 | 大高潮解决核心矛盾 |
主要笔墨集中在"承"上。
### 填充的小剧情越多越好
- 大期待前的小剧情越多,追读越稳定
- 小剧情之间不能留空隙
- 并列式写法是填满空隙的最佳方法
---
## 开头设计的要点
- 书名、简介、开篇必须成为一个整体
- 金手指出现后,剧情必须跟金手指产生强关联
- 代入感模糊时,搭建读者能理解的社会权力结构来增加代入感
- 视角转变太多会导致不流畅
- 开篇场景要有动作、有信息、有画面感
- 从具体动作切入,引出金手指,再切入剧情
---
## 分镜与画面感
### 分镜写作的基本方法
- 机位1:主角视角(主角看到了什么)
- 机位2:目标视角(主角做了什么反应)
- 不要同时搞太多机位
- 根据信息团要点进行脑内拍摄
### 分镜的本质
分镜不负责把信息团机械写长;它让整块内容更具体、更有画面感。先保证戏剧性,再考虑分镜。
### 提升画面感
- 规划一章只写主要信息,不要规划写到多少字
- 拉片规则:画面到文字转化存在鸿沟,需做视觉到文字的转译
---
## RPG结构与奖励设计
### 升级文的本质是RPG
核心是反馈点的设计:读者在什么位置获得满足感。升级文的剧情相对不重要,重要的是阅读观感。
### 奖励点编织
- 每个阶段都要给读者"奖励"——不仅是主角升级,还包括配角反应、环境变化、新信息揭示
- 奖励不能太密也不能太稀
- 奖励的形式要多样化:混合收获、认可、揭秘等类型
### 飞升换地图的循环
- 换地图可以有多种理由:被追杀隐瞒身份、找宗门伪装、从外门弟子开始扮猪吃虎
- 每次重置都要带来新的信息和新的人设展开空间
- 避免简单重复,做到螺旋上升
---
## 故事构型与套路运用
### 从原型故事到套路的三层抽象
| 层级 | 说明 |
|------|------|
| 经典故事情节(具象化) | 起因、经过、结果都具体确定 |
| 戏剧单元(戏剧性抽象) | 保留逻辑结构,可换壳重用 |
| 情绪模块(情绪抽象) | 读者想看什么的直接反映 |
举例:经典情节=「萧炎被退婚后三年崛起打脸纳兰家」;戏剧单元=「主角被某势力羞辱→蛰伏变强→当众反杀」(退婚可换逐出宗门、夺嫡失败);情绪模块=「憋屈→翻盘」。换壳就是保留「憋屈→翻盘」,把退婚换成校园被踢出社团。
### 戏剧单元的特点
- 戏剧单元越抽象,可变性越强
- 多个戏剧单元可以组合成"故事构型"
- 戏剧性会磨损:同类结构用多了就不好用了
### 情绪模块的特点
- 戏剧性会磨损,但情绪不会磨损
- 当戏剧单元磨损后,可以通过强化或更换情绪模块来重组
### 正确使用套路 vs 错误使用套路
| 做法 | 结果 |
|------|------|
| 直接套用经典故事情节 | 故事雷同、人设崩坏 |
| 重构使用(更换故事构型) | 正确 |
| 微调使用(深挖人设,根据人设调整情节) | 正确,且让人物动机和故事逻辑更合理 |
长篇作品(百万字级)必须掌握重构使用,否则必然同质化。
---
## 结构与人物的关系
### 人物驱动结构
- 你在为创造出来的人物选择剧情结构,而不是为剧情结构选择人物
- 如果先合成新人物再找合适剧情结构,容易崩塌
### 感情线与事业线的结构设计
- 事业线关键点:阻碍、危机、装逼、探明、取得、义举
- 感情线要有明确的戏剧性和结构
- 感情线需要层次感和阶段性,不是堆砌好看的桥段
- 不同题材的感情线写法有区别:战斗类写生死与共,不要硬塞都市约会
- 不同人设的女主感情线要做出区分,避免观感趋同
### 事业线与感情线的绑定
- 帮助女主和事业线目标完全绑定是高效写法
- 更泛用的写法:男主主观上忙事业线,顺便帮助了女主
### 以退为进
- 以退为进也是拉扯,只要情绪上行下行拉扯好,无所谓付出毒点
- 但只在必要的时候用,前提是先有大格局的装逼/帮助情节
---
## 框架与阵营手牌法
**框架的本质**:主线 + 支线 + 日常的比重与排列组合。
**阵营手牌法**:像三国杀一样,不同阵营按回合出牌,每张牌带来反应后果,排序成主线。
**三个阵营**:主角阵营 / 敌人阵营 / 观众阵营
**线性剧情三层次**:基础版/进阶版/高阶版的完整出牌结构见 plot-special-topics.md「阵营手牌法」三版本,本处不重复。
**避免毒点**:主角吃瘪时必须从其他角度拉回情绪(揭示深层逻辑/意外收获)。
**框架进阶**:线性剧情天花板有限 -> 高阶用螺旋并线:两条以上主线轮流推进、每轮都比上轮升一级(如查案线和升级线交替,每破一案实力涨一档、案子也更大),避免单线打到天花板。
---
## 热门书大框架拆解法
### 单段剧情结构模板(每段10-40章)
1. **起因**:主角面临新矛盾/进入新环境
2. **发展**:金手指运用/结识新角色/获得新资源
3. **铺垫**:为下一段剧情埋线
4. **高潮**:装逼打脸/比武/夺宝的关键场景
5. **转折**:身份暴露/关系变化/真相揭示
6. **结局/收获**:战利品清点
### 多段剧情的排列规律
- 三种核心元素变化组合:夺宝+美女+比武,三种轮换避免重复
- 每段结束后收获必须明确列出
- 铺垫线和收获线交替
### 多线穿插的节奏
| 线索 | 频率 |
|------|------|
| 战力提升线 | 每段至少一次实力跃升 |
| 装备收获线 | 每段至少获得一件关键道具/技能 |
| 情感线 | 每段与至少一位女性角色深化关系 |
| 声望线 | 每段至少一个"震惊旁观者"的场景 |
四条线不同步推进,错开节奏避免同质化。
### 卷的结构
- 100章左右为一卷,卷末同时解决当前矛盾+开启新地图
- 卷的最后一幕同时是下一卷第一幕 -- 无缝衔接
---
## 九条主线套路法
### 主角三要素
| 要素 | 说明 |
|------|------|
| 目标 | 支撑主角行进的原动力,没有确切目标不是好主角 |
| 性格 | 单一化最佳,根据性格发展情节 = 上乘手法 |
| 修炼体系 | 照抄无压力,改头换面即可 |
### 上乘矛盾冲突写法
| 类型 | 说明 |
|------|------|
| 复仇 | 为亲人/门派复仇,关键 = 写出热血感 |
| 理念冲突 | 两方理念对立,最自然 |
| 门派恩怨 | 两大势力恩怨,主角夹其中不得不战 |
| 生存之战 | 为势力生存而战,不得不出力 |
| 上层恩怨 | 师父/上层人物与对方有恩怨,主角牵连其中 |
| 怀璧其罪 | 获宝物 -> 消息泄露 -> 引来追杀 |
### 下乘冲突(避免)
- 富二代故意欺辱 -> 翻来覆去 -> 读者烦闷
- 无故挑衅 -> 流于肤浅
### 套路与反套路
- 掌握套路是创新的前提
- 套路 = 骨架,往里填充血肉,变化场景/人物/情绪,模板不变内容变
---
## 套路模板重复法
### 通用升级装逼模板
要素固定:男主 + 男反(高逼格)+ 女人(奖励)+ 名额 + 时间限制
1. 烘托:男反高逼格表现,众人追捧
2. 扮猪:主角选择看似最差的选项,被人看低
3. 吃虎:最后一刻爆发,超越所有预期
关键:场景更换,套路不变,金手指/人物/剧情的变化会自然产生不同故事。
### 套路重复的三个层次
| 层次 | 说明 |
|------|------|
| 看点重复 | 市场上已有成功模板,选最好的拿来用 |
| 人物重复 | 给人物一个固定行为特质,在不同场景重复展现 |
| 剧情重复 | 核心看点 + 人物看点结合后自然诞生的套路循环 |
### 避免审美疲劳
- 好的套路和写作,读者看不出有套路,但其实是有的
- 最高境界:看不出套路,但读者已被深陷其中
### 立Flag技巧
让配角说一句flag:"这里面不会有怪物吧?""我做完这个任务就能回家娶老婆了"。有效就反复用。
---
## 玄幻框架拆解
### 整体结构模式
三大要素循环:夺宝+美女+比武 -> 美女+副本+比武 -> 副本+美女+比武,三种变化着来。
### 关键抽取点
- 节奏明快爽点密集,每个事件都有明确高潮和收获
- 女性角色人设立得深入人心
- 装逼舞台搭建层次分明
- 多线穿插:战力提升+装备收获+情感线+声望,紧密安排
- 每个事件结尾都有收获+铺垫下一事件
---
## 双线交替框架拆解
### 交替结构模式
现实线和副本线交叉:现实线用主角不平凡+灵气复苏展开,副本线提升实力+收获。
### 三压一爆三震技巧
- 一压:友好势力 -> 觉得男主是大佬
- 二压:敌方势力 -> 两次铺垫 + 不服让男主上
- 三压:中立势力
- 一爆:男主出手碾压
- 三震:对三方势力的震惊反应
### 排行榜的三个功能
1. 期待男主排名提升 -> 提供升级动力
2. 通过排行榜介绍新对手 -> 期待碰撞
3. 排行榜出现 -> 以后装逼有余震效果
### 底牌管理
手里始终保持3个以上底牌没用,每次只出1个,同时获得新技能。
### 伏笔展开原则
每一个不同之处/天赋都可以成为伏笔,开启一条线。
### 温酒斩华雄式
B打败A -> C打败B -> 主角打败C -> 引出大BOSS。升级文替换:"台词"换"战斗特点","主持会议"换"登台"。
---
## 结构化拆书法
### 长篇的桥段拆分结构
300万字的书约等于40-50个单元,每个单元6-8万字,包含4-5个桥段,每个桥段约4章。整本书约200-300个桥段。
### 单桥段四章结构
| 章 | 内容 |
|----|------|
| 第一章 | 上半做代入(日常场景),下半做信息差(展示金手指可解决的困境) |
| 第二章 | 通过人物互动增强期待,结尾让主角开始装 |
| 第三章 | 兑现期待,把爽感写透 |
| 第四章 | 上半善后收尾+体现推进,下半开启下一个目标 |
### 核心原则
- 代入用N+1原则:用熟悉内容让读者接受新内容
- 信息差 = 最常用的拉期待方式
- 拉长/缩短/升级/反转/多轮拉扯 -> 灵活变化但基础结构不变
- 拆书要用整体视角,将视野拉高俯瞰群山
---
## 故事本质与六幕结构
### 故事的定义
- 事实 = 静态的呈现
- 事件 = 变化的事实
- 故事 = 对事件进行选择、排序、因果化的产物
### 因果链
因果产生意义 -- 意义是故事的灵魂。同样的事件顺序,不同因果链 -> 完全不同的主题。
- 铺垫本质:在事件B发生之前,在事件A旁边埋下因
- 伏笔本质:提前埋下远期事件的因
- 钩子本质:在当前事件末尾埋下下一段的因
- 封死主角其他路 -> 他自然会走向你设计的那条剧情
### 四种组织事件的方式
| 方式 | 说明 |
|------|------|
| 筛选 | 筛掉与主线无关的事件 |
| 时间排列 | 顺叙/倒叙/插叙 |
| 因果逻辑 | 事件之间建立因果关系(网文99%用此) |
| 主题/联想逻辑 | 按主题关联组织 |
### 开篇技巧为什么有效
列出开篇所有事件 -> 找到最有戏剧张力的事件 -> 安排在开头。
### 五幕式本质
五幕 = 因果链的弯曲模板,把平直的因果链弯出节奏,节奏产生情绪。每幕功能 + 因果链状态见 outline-structure-theory.md「五幕式」,本处不重复。
### 三幕/四幕/五幕统一论
三幕、起承转合、五幕本质是同一种结构,根据冲突激烈程度自由选择删减。
### 转折的核心
转折的目的 = 增加冲突 -> 增加情绪。重点在冲突性质质变,让主角处境变得更糟;要做到"意料之外,情理之中"。
### 第六幕:余波(网文特色)
- 明线(实力)vs 暗线(社会认知):每次明暗线失衡就是装逼机会
- 装逼 = 文本论证主角社会地位提高的过程
### 爽感来源图谱
| 类型 | 回答的问题 |
|------|-----------|
| 升级 | 我能变强吗 |
| 碾压 | 我够强吗 |
| 装逼 | 我的强被认可了吗 |
| 复仇 | 不公会被纠正吗 |
| 绝境逃亡 | 我能逃脱吗 |
| 种田 | 弱者该如何变强 |
| 苟道 | 弱者该如何生存 |
### 情节的定义
情节 = 把事件因果化,把因果链塞进五幕式后形成的结构。主线 = "主"(主题)+ "线"(因果链结构)。支线 = "支"(子题)+ "线"(解决子题的方案)。
---
## 核心梗与细化法
### 核心梗的定义
核心梗 = 一套固定的剧情发展模式,不断换花样循环。排行榜的书几乎都有核心梗。核心梗决定了整本书的观感基调。
### 经典核心梗案例
| 作品 | 循环模式 |
|------|----------|
| 诡秘之主 | 灰雾空间 -> 迪化脑补 -> 交流情报 -> 交易材料 -> 赞美愚者 |
| 放开那个女巫 | 魔女被唾弃 -> 拯救 -> 现代知识震撼 -> 魔法训练 -> 教会追杀 |
| 无限流 | 主神 -> 轮回 -> 穿越 -> 完成任务 -> 获得奖励 -> 兑换 |
| 阵营法(传统) | 反派打压 -> 友军劝阻渲染 -> 中立观望 -> 打脸 -> 反应 |
### 细化法
从一句话主线到正文的细化路径:
```
一句话主线 -> 粗略卷纲 -> 详细卷纲 -> 章纲 -> 正文
```
每一层都是对上一层更具体的展开。天然形成多级结构,无需额外设计结构框架。
结构选择规则:结构是为故事服务的工具,不是必须遵循的模具。细化法本身即构成结构。
---
## 冲突的结构与有进无出原则
### 核心公式
冲突+情节+悬念 = 情感上令人满足的体验。悬念最重要。
危机感可用收获感替代:从"不做就死"改为"做了就获得"。
### 三种危机(死亡)类型
| 类型 | 示例 |
|------|------|
| 肉体死亡 | 叶凡被抓炼药 |
| 身份/职场死亡 | 萧炎天才陨落、被退婚 |
| 心理死亡 | 道诡异仙开头,"幻觉是不是真的" |
确定一种主要类型贯穿全局,次要类型推动情节但不喧宾夺主。
### 开篇 = 从乱子开始
开局必须让主角发生不平常的情况。值得追随的主角 = 他是谁 -> 遇到什么乱子 -> 怎么处理 -> 读者好奇他的处理方法。
### "有进无出"原则
主角从安逸到激烈需要一个强迫性理由 -- **读者必须相信主角非踏入不可**。
期待感 = 有进无出 = 铺垫。所有期待都是在说"快看我之后要写这个"。
### "有进无出"的铺垫手法(三个层次)
| 层次 | 手法 |
|------|------|
| 基础 | 渲染敌人和主角的不共戴天 -> 塑造压迫感 |
| 进阶 | 写主角变得前所未有地强 -> 敌人恰好跳出来 -> 主角拿他试刀 |
| 更好 | 铺垫敌人背景,解决他引发什么大地震 -> 多重期待叠加 |
趋势:正向驱动(收获感/升级)比传统仇怨渲染更受欢迎。
### 网文 = 复数个乱子 + 复数个关口
传统文学一个乱子两个关口,网文不断重复关口,不断将大门塑造成有进无出。每个关口之间用收获感和升级感连接。
---
## 冲突的死亡赌注与黏结剂设计
### 四种黏结剂设计
| 黏结剂 | 说明 |
|--------|------|
| 杀人理由 | 反派有强烈理由必须置主角于死地 |
| 工作职责 | 侦探接案必须破案,宗门弟子必须完成任务 |
| 道德责任 | 亲人朋友遇险,主角无法袖手旁观 |
| 实体场所 | 特殊场所束缚对抗双方(副本、密室) |
如果读者感觉人物可以随时脱离困境,冲突紧张感荡然无存。
### 常见冲突类型
复仇、灾祸、反抗、恋爱阻碍、野心、身份矛盾、环境矛盾、生死危机、阶层矛盾、理念矛盾。
---
## 利用矛盾推动剧情的五种类型
| 类型 | 核心逻辑 |
|------|----------|
| 身份矛盾 | 通过身份自带的外部压力创造矛盾,天然明确目标 |
| 环境矛盾 | 外部压力直接创造矛盾,适合大格局小说 |
| 生死危机矛盾 | "打了小的来老的",始终保持高压,经典推进结构 |
| 阶层矛盾 | 人的欲望层层递进,每个阶段有不同诉求 |
| 理念矛盾 | 理想主义vs现实,高级手法,上限极高 |
### 进阶:序列唯一性设定法
- 扮演法:升级有风险,必须做xxx -> 给主角做支线剧情的理由
- 序列唯一性:你升级就触碰既得利益者的利益 -> 同序列超凡者全是敌人 -> 天然矛盾线
---
## 悬念与冲突的深化技巧
### 期待感 > 爽点
> 相关:爽点设计体系(六种类型/倒推法)以 [plot-emotion-system.md](plot-emotion-system.md)「爽点设计体系」为准;本文只对比"期待感比爽点更持久"。
- 爽 = 情绪的释放过程,释放完就没了
- 读者的紧张/好奇/担忧/愤怒/憋屈比"爽"更持久
- 恋爱文最吸引人的是暧昧拉扯 -> 确认关系后反变无聊
- 教训:过于完美的情节解决 -> 损害长线期待感
### 悬念vs意外
- 意外 = 桌子底下炸弹突然爆炸
- 悬念 = 观众听到定时炸弹在滴答但不知道何时爆炸 -> 悬念远比意外有力
- 章末断章留悬念 = 章结尾尚未解决的危险(高压/推进章用强悬念;低压/过场章弱钩子或阶段目标即可,按章节定位——见 outline-structure-theory.md「章节定位与张弛」)
### 时间锁
限定时间内必须完成某事,显著增强紧张感和节奏感。不知道如何写开篇时,尝试设置一个时间锁。
---
## 剧情流判断标准与优势
### 什么是剧情流
一本书在后期是否还精彩、"有劲"、有让读者津津乐道的高潮 -- 有就是剧情流。脑洞文高开低走容易崩,剧情流越到后期越精彩。
### 千均写作指南:作品五不崩
1. 目标不缺失:主角始终有明确目标
2. 卖点不减少:核心卖点不能中途消失
3. 主角社会关系不空白:必须有互动的人际网络
4. 上层地位不缺失:要有对上位者的追求和接触
5. 地位收获提升不能停:持续的成长感
### 千均写作指南:三线结构
- 世界线:世界观层面的宏大叙事
- 剧情线:具体事件和矛盾冲突的推进
- 升级线:主角实力/地位的持续成长
- 三条线交织推进,缺一不可
### 千均写作指南:装逼五步法
1. 主角很强但别人不知道
2. 渲染困境难度
3. 配角不看好主角
4. 主角用金手指轻松解决
5. 众人震惊
---
## 补充结构与剧情技巧
### 情绪调动的结构层次
角色情绪引导原则:每个角色都引导 = 每个角色都没引导 -- 必须选择重点角色。
好的反转结构:先引导对某角色持续恶感,再在关键事件中揭示其崇高品质。
### 四项自检
1. 有没有记得住的爽点 / 人设钩子?
2. 有没有给足题材该有的爽(升级给升级、追妻给拉扯)?
3. 冲突够不够直白带情绪?
4. 句子顺不顺?
一项偏弱可以,四项都垮才扑街。直白冲突比精巧构造更容易引起大众情绪共鸣。
---
## 质量检查清单
每次搭完框架或写完一段剧情后,用这张清单过一遍。逐项打勾,不通过就改。
### 结构层
- [ ] 主角始终有明确目标(当前小目标 + 长线大目标都清晰)
- [ ] 当前段落有起因→发展→高潮→收获的完整闭环
- [ ] 段落结尾同时完成两件事:收获清点 + 铺垫下一段
- [ ] 大结构有"欺骗式主线"吊着读者(每次接近完成又差一点)
- [ ] 主线和支线错开节奏推进,没有同时爆也没有同时空转
### 冲突与悬念层
- [ ] 冲突有明确的黏结剂(读者认为主角不可能随时退出)
- [ ] 每章结尾有让读者往下看的理由(断章留钩子;低压/过场章弱钩子或阶段目标即可,不强求强悬念)
- [ ] 期待感 > 爽点:铺垫的篇幅不少于释放的篇幅
- [ ] 主角吃瘪时从其他角度拉回了情绪(揭示深层逻辑 / 意外收获)
### 爽感与节奏层
- [ ] 升级文:每个阶段都有明确的奖励点(升级/装备/认可/揭秘至少一项)
- [ ] 装逼文:有"三压一爆三震"或"装逼五步法"的节奏结构
- [ ] 感情线:有拉扯有层次,不是堆砌桥段
- [ ] 套路重复时更换了场景/人物/情绪,读者看不出模板
- [ ] 没有连续两段使用相同的核心要素组合(夺宝+美女+比武要轮换)
### 人物层
- [ ] 角色行为由性格驱动,不是由剧情需要倒推
- [ ] 配角有自己的立场和动机,不是单纯工具人
- [ ] 感情线和事业线有绑定或交叉,不是两条独立线
- [ ] 底牌管理:手里始终有2-3个未揭示的底牌
### 全局不崩检查(五不崩)
- [ ] 目标不缺失:主角始终有明确目标
- [ ] 卖点不减少:核心卖点没有中途消失
- [ ] 社会关系不空白:主角有互动的人际网络
- [ ] 上层地位不缺失:有对上位者的追求和接触
- [ ] 成长不停止:地位/实力的提升持续给出
references/plot-special-topics.md›
# 特殊题材操作手册
> 金手指设计、同人vs原创、都市高武模板、题材边界、扫榜方法、脑洞文框架、对标书选择、爱情线、身份行为论、阵营剧情、改编三步法。
>
> 本手册是指令格式:读到哪里就照做。按决策路由表定位你需要的章节,执行对应操作。
---
## 决策路由表
**使用方法**:根据你当前面对的写作场景,在左侧找到匹配项,跳转到右侧对应章节。
| 你的场景 | 跳转到 |
|----------|--------|
| 设计金手指 / 担心战力崩坏 | [金手指拆分理解与战力防崩](#金手指拆分理解与战力防崩) |
| 金手指要做得更有趣(错位、反套路、极道流) | [金手指进阶设计](#金手指进阶设计) |
| 有脑洞但不知怎么铺成完整故事 | [脑洞文完整写作框架](#脑洞文完整写作框架) |
| 不确定题材边界在哪 / 担心写偏 | [题材边界感](#题材边界感) |
| 需要研究市场 / 拆解竞品 | [扫榜与拆书方法](#扫榜与拆书方法) |
| 要选对标书但不知道怎么选 | [对标书选择法则](#对标书选择法则) |
| 写同人或原创,把握不好节奏差异 | [同人vs原创的节奏差异与核心框架](#同人vs原创的节奏差异与核心框架) |
| 写都市高武,需要情节素材 | [都市高武情节模板](#都市高武情节模板) |
| 不清楚不同题材写法差异 / 主角行为出戏 | [不同题材不同写法与身份行为论](#不同题材不同写法与身份行为论) |
| 写爱情线 / 后宫文 | [爱情线提纯策略](#爱情线提纯策略) |
| 故事不知道往人设还是往剧情深化 | [向人设深化vs向故事深化](#向人设深化vs向故事深化) |
| 要改编已有剧情为自用 | [剧情改编三步法](#剧情改编三步法) |
| 开头上架三万字卡点 / 中后期写法 | [三万字卡点倒推法与中后期写法](#三万字卡点倒推法与中后期写法) |
| 设计阵营冲突 / 完善角色动机 | [阵营剧情安排与动机完善法](#阵营剧情安排与动机完善法) |
| 用卡牌思维设计主线节奏 | [阵营手牌法——用卡牌思维设计主线剧情](#阵营手牌法用卡牌思维设计主线剧情) |
| 写作遇到常见问题不知哪里出错 | [四类常见问题诊断](#四类常见问题诊断) |
| 想融合多本书创出新故事 | [三本书融合为新故事](#三本书融合为新故事) |
---
## 金手指拆分理解与战力防崩
### 金手指本质拆分
**操作**:把金手指拆成以下元素再重新拼接,不要把金手指当成一个不可拆的整体。
| 元素 | 作用 | 示例 |
|------|------|------|
| 面板 | 目标感明确,最直观的收获感来源 | 数值/等级/进度条 |
| 不倒退 | 重复行动获得的提升永续 | 熟练度不会衰减 |
| 重复提升 | 核心循环机制 | 做A->获得B->继续做A |
**拼接操作**:拆分后自由组合。例如"杀怪+熟练度"=斩妖除魔流,"收集+提升品质"=焚决异火流。
**核心警示**:如果金手指后期只剩"品质提升"一个维度,提升感会消失。必须保持多个维度同时成长(词条、功能、品质)。
### 战力崩坏三原因
**操作**:逐项检查你的设定是否踩中以下三雷,踩中就按解法修正。
| 原因 | 解法 |
|------|------|
| 没写升级线 | 用经典境界体系提供升级框架 |
| 金手指设计缺陷 | 金手指提升要有多维度,不能只靠单一维度 |
| 社会环境太简单 | 设计正经社会关系:酒馆、师门、朋友、情报组织 |
---
## 金手指进阶设计
### 错位系统设计
**操作**:让系统没有正确生效,利用系统与主角人设的反差产生戏剧性。
| 错位类型 | 示例 |
|----------|------|
| 时间错位 | 主角已经无敌了,逆袭系统才来;都上大学了,幼儿园攻略系统才来 |
| 空间错位 | 主角在正常世界,觉醒的是末世系统 |
| 对象错位 | 本应寄生在皇帝身上的系统寄生在皇后身上 |
**原则**:错位产生的落差要大,且戏剧性必须是目标读者期待的。
### 系统反套路写法
- 书名要直接点明系统的"反套路"作为最大噱头
- 简介要说清楚系统运行一次的爽感
- 不要只展示"反"的噱头,要展示反了之后主角怎么用
### 常见系统类型
**操作**:根据你的故事需求,从下表选择匹配的系统类型。
| 类型 | 特点 |
|------|------|
| 加点系统 | 简单直观但单一,适合强压迫世界观 |
| 熟练度系统 | 能延伸情绪和普适性,底层机制可做变种 |
| 抽卡系统 | 读者熟悉又新鲜的包装 |
| 商城/兑换系统 | 资源获取型,适合种田经营类 |
### 极道流金手指的特殊考量
- 极道流世界观特点:绝对的阶级固化,按部就班修炼不可能跨越阶级
- 极道流的进化方向:单一极道加点已过时,需要元素融合(极道+恐怖+探索、极道+末日+苟道)
---
## 脑洞文完整写作框架
### 从灵感到成书的四步流程
**操作**:严格按顺序执行这四步,不要跳步。
1. **得到点子**:一个金手指雏形/画面/切入点
2. **匹配题材**:思考点子能融合进什么题材
3. **构建框架**:围绕升级体系、金手指、框架三要素搭建
4. **设计剧情**:在框架内用小剧情循环填充
### 金手指设计:条件-反馈模型
**操作**:从下表选择一种模型作为金手指核心机制。
| 变体 | 设计 | 示例 |
|------|------|------|
| 单条件单反馈 | 摸尸体->得宝物 | 最基础形式 |
| 单条件阶段反馈 | 摸尸->得摸尸点->升级解锁新功能 | 保留机制,丰富表现形式 |
| 条件升级反馈 | 击杀->掠夺词条->词条可融合 | 后期天花板更高 |
**创新手法**(任选叠加):
- 设置多个条件对应一个反馈
- 一个条件对应概率性反馈
- 反馈产生新的子能力
### 主线与过渡的框架设计
**操作**:框架 = 主线 + 剧情间的过渡。回答核心问题:每个剧情存在的目的是什么?
设计步骤:
1. 确定主角初始状态
2. 确定每个剧情的功能并向前衔接
3. 后续剧情渗透到前一个剧情
4. 根据框架穿插嵌套小剧情循环
框架内的具体素材可以灵活替换,但核心功能不变。
### 小剧情循环构思法
**操作**:每个小剧情严格按四步走。
| 循环步骤 | 内容 |
|----------|------|
| a1 | 铺垫起点(主角处境+目标) |
| a2 | 困难出现(引入具体矛盾) |
| a3 | 金手指/实力发挥作用 |
| a4 | 爽点释放(震惊/收获/关系突破) |
**升级流的小循环节奏**:遭遇困境 -> 金手指提升 -> 剧情展开 -> 收获和日常 -> 大目标铺垫、世界观扩展
**多级嵌套**:小循环 -> 中循环(次级目标)-> 大循环(卷目标)。小循环中必须铺垫大循环的期待。
### 脑洞文写长三关键
1. 在重复中变化:同一核心卖点的不同角度/不同矛盾
2. 扩展世界观:新的地图/势力/设定逐步展开
3. 核心卖点抓准市场:覆盖足够多的读者需求
### 多套路交织循环模式
**操作**:从下表选择一种循环模式。
| 模式 | 效果 |
|------|------|
| 多角度循环 | 从核心卖点找出若干角度,每个角度写1-2卷 |
| 设定扩展循环 | 从脑洞设定角度扩展多种套路,比第一种简单 |
| 核心不扩展(反面) | 只反复用同一个梗换对象(一直打脸不同反派、收不同小弟),写到二十万字读者就腻 -- 本质没新东西,别这么干 |
| 强情绪事件循环(反面) | 靠不断制造惨/虐来刺激(主角一次比一次惨、反派一次比一次坏),情绪阈值越拉越高,后面写啥都满足不了读者 |
---
## 题材边界感
### 执行规则
- 每个题材都有明确的读者期待边界,超出边界读者不买账
- 选错题材方向 = 正文再顺也无法兑现目标读者期待
- 边界感用于瞄准 -- 在边界内做到极致就是爆款
### 边界感的判断方法
**操作**:按以下步骤判断题材边界。
- 看同题材精品到万订之间的书,它们的共同元素就是边界
- 超出边界的"创新"大概率是毒点
- 上下文不足或题材资产不足时,不突破题材边界;先在边界内交付核心期待,再做微创新
### 题材边界与金手指的关系
- 金手指必须配合题材边界
- 金手指的核心卖点循环不能偏离题材
- 判断标准:读者冲着什么进来的,后续就必须持续给什么
---
## 扫榜与拆书方法
### 扫榜原则
**操作**:按平台看不同榜单。
- 番茄看阅读榜和新书榜,起点看三江推荐和各类推荐
- 夹子上的文看的是热点元素 -- 为什么能上夹子
- 金榜是成熟作品,适合抽取结构标准
- 市场扫描时优先看同平台、同题材、非头部光环作品,以获得更可复用的结构样本
### 拆书正确姿势
**操作**:拆书前先明确你要拆的维度,不要泛读。
- 不以个人喜好判断对标价值;只判断该书是否能提供可复用的结构/情绪/节奏模块
- 带着具体问题去拆:怎么冲突拉扯情绪?找十段冲突情节分析
- 优先拆中层样本;排除强品牌、强粉丝基础、不可复用的头部样本
- 每次只拆一个维度:人设/节奏/对比手法/悬念等
### 拆书素材提取要点
- 扫榜时以写作功能位提取:热点元素、冲突结构、情绪链条、节奏编排
- 拆书记录应标注具体维度,而非笼统读后感
- 针对性拆解比泛读更有价值
- 不要脱离题材拆书
---
## 对标书选择法则
### 核心原则
**操作**:对标书选精品到万订之间、套路框架易懂、题材经过市场验证的书。
### 三不选
**操作**:以下三类书排除,不要作为对标书。
| 不选类型 | 原因 |
|----------|------|
| 强品牌/强粉丝基础的头部作品 | 品牌势能和笔力遮蔽结构,功能位不可直接复用 |
| 刚火的题材跟风书 | 流量已被火书吸光,粗制滥造必死 |
| 个人风格极强的好书 | 独特世界观和风格无法复制 |
### 完整流程
**操作**:按以下顺序执行。
```
检索同题材TOP 20作品的核心卖点与读者评论,提取高频剧情模式
-> 确定题材内有哪些方向 -> 确定自己要写的方向
-> 选5-10本参考书(读2-3遍到基本记下)
-> 从参考书里选1本对标书
```
| 思考方向 | 问题 |
|----------|------|
| 好看的书 | 哪些书最好看?读者评论和自己的想法一样吗? |
| 方向共性 | 最好看的书大概怎么写?有哪些相似性? |
| 不好看的书 | 不好看的根因:自己不是受众 vs 写得不好? |
---
## 同人vs原创的节奏差异与核心框架
### 同人vs原创的节奏本质差异
- 同人不用铺垫,直接拿过来就自带期待感和爽感
- 同样的字数,同人文比原创爽——铺垫快
### 原创破解节奏问题的方法
**操作**:写原创时按此节奏递进。
- 前期牺牲部分爽感(小爽就够了),快速重复核心套路
- 拉住读者后再做详细铺垫
- 节奏递进模式:开头1万字一个剧情x3 -> 2万字一个剧情x2 -> 3万字一个剧情x2 -> 8万字xN
### 一级结构 vs 二级结构
**操作**:根据平台特性选择结构。
| 结构 | 特点 | 订阅表现 |
|------|------|----------|
| 一级结构(单元剧) | 爽点分布均匀,每天有小高潮 | 追读稳定 |
| 二级结构(铺垫->反转->大高潮) | 大高潮后有平缓期 | 订阅波动,阶梯型流失 |
### 行文啰嗦自检
**操作**:逐条对照,中了任何一条就回去删。
- 一句话能准确表达的,绝不过多解释
- 与主线无关的剧情尽量少写
- 减少副词出现频率
- 反复描述同一件事 = 让章节失去重点
### 同人写作要点
- 标题要吸引人:从讨论度最高的剧情切入
- 支线人物压缩:标题对准某个经典人物时,支线人物不超过2章
- 命名贴合原著世界:原著角色沿用官方本名/译名不自造;新角色顺着原著对应地域的文化命名和译名风格,同一地域不混语系,别用与设定不符的现代化或政治化名字
---
## 都市高武情节模板
### 通用目标池
**操作**:从下表选择目标组合,所有目标必须和钱挂钩。
| 目标类型 | 具体选项 |
|----------|----------|
| 物质 | 换房子、拿必要资源、挣更多钱 |
| 学业 | 考大学、考军校、打各种考试 |
| 职业发展 | 进武道厅、进治安局、进军部 |
| 亲情 | 治母亲、救父亲、治自己、帮亲戚 |
| 感情 | 青梅竹马好感、天降校花好感 |
| 激励 | 每天看世界第一天骄的画像打鸡血 |
**核心原则**:所有目标都必须和钱挂上钩,反复挂钩。没钱寸步难行,有钱打遍天下。
### 可用剧情事件(按场景)
**操作**:根据当前场景从下表选取事件。
| 场景 | 可用事件 |
|------|----------|
| 学校 | 进天才班、获奖励、打虚拟比赛、月考、打校霸、多校联考、全国高考 |
| 武馆 | 获馆主赏识、获传承武学、打武馆师兄、市内/省级/国级武馆联赛 |
| 警局 | 配合打劫匪、打邪魔、打邪恶副本、打动乱boss |
| 竞争 | 武馆/学校/武道厅/军部/国安局/虚拟网/明星赛事合约 |
### 换地图公式
**操作**:当地图用尽时,按此公式换地图。
高中->大学,武馆->天下第一武道会,武道厅->中央武道厅,蓝星->其他星域。周而复始。
火箭跳法:打大学老师->打校长->打财阀->打仿美国->打中boss->打大boss->打邪神。
---
## 不同题材不同写法与身份行为论
### 收放压起节奏论
**操作**:写任何章节前先确认收放压起。
- 写小说要讲究:收、放、压、起
- 高潮结束后的第二章怎么处理,才是见功底的时候
- 写任何高潮剧情前先问:主角目前的等级够不够格?
### 身份行为边界
**操作**:主角确定身份后,严格按身份限制行为。
- 主角确定身份后,什么样的身份做什么样的事情
- 越级行动 = 结构性破坏,代入感直接出戏
- 步子太大的后果:剧情变成跳跃式,高潮多但没连成一条线
### 不同题材的写法差异
**操作**:对照你的题材,按对应要点写。
| 题材 | 写法要点 |
|------|----------|
| 西幻低位背景 | 不写冲突,写环境;不需要反转和拉扯,最重要的是流畅 |
| 东方玄幻 | 不写多余角色,第一章只出现主角,靠独白和心理推进 |
| 带冲突的开篇 | 需要不断拉扯空间,节奏会越来越快,容易崩 |
| 带环境的开篇 | 慢节奏推进,信息密集但阅读体验流畅,更容易写长 |
### 强情绪开局的陷阱
**警告**:强情绪开局需要后续升级能力支撑。
- 如果卷纲无法给出更高代价、更强对手或更深情绪反转,不要用强情绪开局。
- 强情绪开局后,后续每个大节点必须至少在代价、范围、真相或关系破裂上升级一个维度。
### 流派要素合成法
**操作**:把流派A的要素提炼出来,把流派B的要素提炼出来,两个要素合成一个新点子 -> 创作出一本新书。换皮法:把背景一换,思路套用不同题材。
---
## 爱情线提纯策略
> 相关:感情线整体框架(好感度体系/四阶段/男女频差异)以 [character-relations.md](character-relations.md)「好感度体系」为准;本文只覆盖"两种核心梗支撑"的提纯选择。
### 爱情线的两种核心梗支撑
**操作**:从两种模式中选择一种作为爱情线核心。
1. **特定的有戏剧性的爱情过程**(如禁忌之恋、追妻后悔流)-- 不同阶段有不同核心情绪链
2. **特定的有戏剧性的人设/人设组合/两人关系** -- 整本书的观感主要由两人互动模式带来
### 互动模式不变的铁律
**操作**:男女主角的互动模式一旦建立,持续到全文最后。改变互动模式 = 改变读者追这本书的核心观感。
### 事业线为爱情线服务
**操作**:以爱情线为主时,所有事业线情节都必须为爱情线服务。
- 事业线功能:导致相识 / 引发关系改变 / 情敌/长辈考验
- 装逼可以写,但装逼后要引出爱情线内容
### 后宫文角色设计原则
- 女主外表要有相似性 -- 萝莉就全部萝莉,御姐就全部御姐
- 如果近期目标平台样本中“男主好基友”明显削弱吸引力,改用“欢喜冤家青梅竹马妹子”等能制造关系戏的角色位
---
## 向人设深化vs向故事深化
### 两种深化路径
**操作**:根据项目复杂度、已有素材和目标情绪选择深化路径。
| 路径 | 特点 |
|------|------|
| 向故事深化 | 构思复杂阴谋、多层推理、智斗 -- 上限高但难度大 |
| 向人设深化 | 在人物关系和互动中找戏剧性 -- 适合主线已清楚、需要持续新鲜感的项目 |
向人设深化的核心:在简单、读者熟悉的故事框架中,通过人物互动制造"乐子"。先列出几个人物的相处关系、欲望差异和互动模式,再把互动模式映射成可重复的情节点。
---
## 剧情改编三步法
### 核心原则:好剧情是改出来的
**操作**:严格按三步执行。
1. **通过矛盾找目标**:确定主角当前面临什么矛盾 -> 在"内容库"里搜索类似剧情 -> 找到源头作品
2. **对照法**:将原型作品拆成细纲,纵向罗列桥段放左边 -> 右边放自己的书的情况 -> 逐桥段改编
3. **调整优化**:改编后的故事已和原型不同 -> 按节奏、情绪、悬念、人物动机逐项验收
**改到不一样就是原创**。两本书基础不一样:世界观不同、人物关系不同、金手指境况全不同,想照抄也做不到。
---
## 三万字卡点倒推法与中后期写法
### 三万字卡点倒推
**操作**:按此顺序倒推。
- 先确定卡点(上架高潮场景)
- 从卡点倒推开头剧情 -> 一步步严丝合缝推导
- 三万字内无关卡点的装逼打脸一个字不要写
- 核心反派要围绕卡点设计
### 中后期写法两大原则
**原则一**:啥也没干 -> 一年推进一次主线
- 女主能不改观就不改观,能找个由头圆回去就圆回去
- 主线偶尔推进一次 -> 像柯南 -> 日常破案+偶尔推进暗线
- 咬死硬撑撑满80万字再破坏基本元素 -> 基本就大火了
**原则二**:着眼于一天后的事
- 剧情围绕眼前事件展开 -> 岳父即将回来、老太君大寿
- 而非从头就散线
---
## 阵营剧情安排与动机完善法
### 阵营剧情的四种基本模式
**操作**:从四种模式中选择适合当前剧情的。
1. 主角->敌方:最常见,敌人直接找主角麻烦
2. 友军->敌方->(动机转换)主角->敌方:友军被针对->主角挺身而出
3. 主角->敌方a->(动机延伸)主角->敌方bcd:打小子来老子
4. 主角->友军:误会/理念分歧/证明实力->调剂剧情+丰富人设
### 第三方阵营的关键作用
不只是吃瓜群众用来围观震惊,更重要的是"完善逻辑" -- 衡量反派有没有脑子、主角方高人是不是因主角光环强行帮忙。
### 动机完善的核心
- 情绪是动机的助燃器 -> 情绪越足 -> 读者与角色越能感同身受
- 转移仇恨时动机必须强烈+符合逻辑
- 动机要从人设为锚点
### 多层铺垫法(动机完善案例)
**操作**:按此模式层层递进铺垫动机。
层层递进:
1. 穿越发现原身被毒死 -> 复仇动机
2. 受原主记忆影响 -> 与家人感情深厚
3. 家人担忧之色未褪 -> 情绪铺垫
4. 晚餐好吃好喝补身子 -> 亲情体现
5. 家境贫寒父母日夜劳作 -> 家庭困境
6. 为凑药费欠债 -> 经济压力
7. 妹妹想从了纨绔帮家 -> 终极情感引爆
**规则**:情绪别一直压 -> 爽文情绪是波浪式 -> 压太低要介绍金手指回升。
### 强主角方(种田/领主/门派建设文)
弱主角方 = 配角独立装逼与主角无关 = 读者不爽
强主角方 = 领民/弟子/学生装逼 = 主角装逼 = 扩充爽点
---
## 阵营手牌法——用卡牌思维设计主线剧情
### 核心概念
框架 = 主线 + 支线 + 日常的比重与排列组合顺序。
| 类型 | 定义 |
|------|------|
| 主线 | 推进故事直到完成最终期待的过程 |
| 支线 | 获得辅助道具/能力的任务 |
| 日常 | 与角色互动的温情填充 |
### 阵营手牌法操作
**操作**:像卡牌游戏一样,不同阵营按回合出牌。
- 站在主角角度思考应对方法(功法/法宝/知识点)
- 站在敌人和观众阵营角度出牌和讨论
- 核心要点:按实力高低排序各阵营角色 -> 逐级递进 -> 主角最后出手碾压
### 三版本
**操作**:根据项目复杂度和可用上下文选择版本。
| 版本 | 结构 |
|------|------|
| 基础版 | 不同立场角色针对同一事件有不同态度 -> 加先抑后扬 |
| 进阶版 | 经典结构:观众->配角A->配角B->敌人C->主角碾压->引出大BOSS |
| 高阶版 | 主角不下场,教下属关键知识 -> 敌人历经千辛万苦来到面前 -> 一败涂地 |
### 各类型通用
升级文 = 功法/法宝替代知识/科技 = 手牌 -> 战斗特点替代台词 -> 登台替代开会。无论升级文还是非升级文,剧情设计原理相同,一通百通。
---
## 四类常见问题诊断
**操作**:遇到写作问题时,从下表定位问题类型,按修正方向执行。
| 问题 | 外在表现 | 修正方向 |
|------|----------|----------|
| 选错题材 | 题材缝合/难度过高/不适配 | 扫榜分析题材门槛,选择适配的题材 |
| 不知好坏 | 自嗨/忐忑/无法判断质量 | 建立具体评判维度(节奏/情绪/悬念)逐项对照 |
| 不研究市场 | 写源于自我认知的内容 | 扫同题材榜上书,提取读者评论中的需求关键词 |
| 不用套路 | 一拍脑袋全凭感觉写 | 拆书总结题材通用套路,建立可复用的结构模板 |
---
## 三本书融合为新故事
### 操作步骤
**操作**:严格按顺序执行。
1. 选取 3 本同平台、同题材、同类型且近期数据/评论可验证的对标书。
2. 为每本书提取 300-500 字故事梗概、核心梗、卖点结构和读者评论关键词。
3. 三层拆解:(1) 故事梗概提炼——核心梗和卖点结构 (2) 叙事手法分析——节奏编排和情绪触发机制 (3) 读者吸引力归因——评论中的高频正面关键词。
4. 融合时只复用功能位:核心梗、节奏、情绪触发、人物关系,不复用具体桥段。
5. 输出新故事核心后,先用 200 字概括验证,再进入大纲。
### 检验方法
**操作**:先把想写的东西用200字概括故事核心,逐项检查:核心矛盾是否明确、情绪钩子是否到位、金手指展示是否充分。三项至少满足两项为合格,否则说明故事核心不够清晰。
---
## 质量检查清单
**使用方法**:完成特殊题材写作后,逐项对照检查。任何一项不通过,回到对应章节修正。
### 金手指与战力
- [ ] 金手指是否拆分成多个元素(面板/不倒退/重复提升),而非单一维度?
- [ ] 后期金手指是否仍有多维度成长(词条+功能+品质),不会只剩品质提升?
- [ ] 升级线是否已建立(境界体系或等效框架)?
- [ ] 社会环境是否有足够的社会关系支撑(不只是主角+敌人)?
### 题材与边界
- [ ] 是否已确认题材边界(通过同题材精品到万订之间的共同元素)?
- [ ] 金手指核心卖点循环是否在题材边界内,未偏离?
- [ ] 读者冲什么进来的,后续是否持续给什么?
### 框架与节奏
- [ ] 每个剧情存在的目的是否明确(主线/过渡/小循环)?
- [ ] 小循环是否严格按 铺垫->困难->金手指发挥作用->爽点释放 四步走?
- [ ] 小循环中是否铺垫了大循环的期待?
- [ ] 同人是否用一级结构(单元剧),原创是否按节奏递进模式?
### 阵营与动机
- [ ] 阵营冲突模式是否明确(四种基本模式之一)?
- [ ] 第三方阵营是否完善逻辑(不只是围观震惊)?
- [ ] 动机是否从人设锚点出发,且层层铺垫?
- [ ] 情绪是否波浪式推进(避免一路压抑或一路爽到底)?
### 爱情线(如涉及)
- [ ] 爱情线核心梗是"过程型"还是"人设互动型",是否二选一明确?
- [ ] 男女主互动模式是否全文一致,未中途改变?
- [ ] 事业线情节是否服务于爱情线?
### 市场与改编
- [ ] 对标书是否为同平台、同题材、同类型的可复用样本(排除强品牌、跟风粗制、强风格书)?
- [ ] 拆书是否每次只拆一个维度(人设/节奏/对比/悬念)?
- [ ] 改编后的剧情是否与原型已有本质差异(世界观/人物/金手指不同)?
### 三万字卡点(如涉及)
- [ ] 是否已确定上架高潮场景(卡点)并从卡点倒推开头?
- [ ] 三万字内是否有与卡点无关的装逼打脸(有则删除)?
- [ ] 核心反派是否围绕卡点设计?
references/reader-contract-and-progression.md›
# 读者契约与终局储备
本文件是 `story-long-write` 关于读者契约、主角代理权(叙事能动性/主导性)、利益安全与阶段推进的权威参考文件。相关洞察由授权社区样本提炼而来;样本多数是问题帖/避坑帖,属于非统计共识,也不能替代具体题材、平台和对标书判断。
**安全边界**:本文件不得包含来源站点隐私数据、访问凭证、cookies、tokens、请求签名、私有标识符,或任何能反推出私域账号/请求环境的信息。
## 1. 核心概念
### 读者契约
- 读者契约 = 开篇、题材、主角配置、叙事口吻共同许诺的阅读快感。
- 写作前先确认:读者是来看主角解决问题、见证团队群像、看导师托举后辈,还是看制度合作建设?不同契约下同一情节风险不同。
- 题材边界先于单条禁忌:政府、宗门总部、跨国组织、多国公司等高层级机构一出现,可能开启制度/势力范围情节线;先检查本书是否从开篇承诺了这种玩法。
### 主角代理权:因果权 + 结算权
- 主角代理权首先看**因果权 + 结算权**,不看出场时长,也不要求主角永远亲自动手或垄断每个镜头。
- 主角不可替代首先体现为因果权:主角通过决策、布局、授权、不可替代的信息/资源,或主动选择关键后果,决定事情为什么发生、如何进入与怎样转向。
- 结算权 = 核心收益、认可、权力或关键后果依照既有承诺回到应得者。可以借力、组队、被救、接受指导或让他人执行局部动作,只要因果与结算没有被无声夺走。
- 职业/权力幻想题材尤其敏感:读者通常期待主角掌握资源、做出决策、承担或选择后果并拿回可见收益。
- 题材例外(直给爽文):番茄战神/赘婿/打脸/都市异能等,主角亲自出手、当面碾压本身就是契约兑现,代理权不能拿来给主角划水、让下属封神;只有布局/权谋/经营/群像/导师题材才默认可幕后运筹、隔人兑现。
### 期待所有权
- 承诺的兑现/高光属于本卷或本单元已经许诺的主角或其他承诺所有者;配角可以执行局部动作,但不能无声夺走期待所有权。
- 群像、导师或制度合作可把期待所有权明确给团队成员/学生/机构角色;关键是预先承诺、按约结算,而非事后解释抢戏合理。
### 关键节点四问
大纲、正文与审查遇到关键节点时统一问;答案可以指向主角,也可以指向本卷已承诺的其他所有者,不要求主角亲自完成每个动作:
1. 谁决定事情为什么发生/如何进入?
2. 谁作出不可替代的关键选择?
3. 谁承担或选择关键后果?
4. 核心收益/认可/权力最终结算给谁?
### 利益安全与兑现归属
- 利益安全 = 读者相信自己追的核心卖点不会被没收、稀释、转赠或交给无关角色消化。
- 兑现归属 = 谁铺垫、谁承压、谁选择,谁就应拿到主要情绪回报;旁观者/配角反应可以放大爽点,不能替代主角爽点。
- 核心资产(金手指、关键资源、身份底牌、独家技术、关键证据)不得无交换地交出、暴露给外部机构或被上级接管。若必须交出,需要可见交换:权力、保护、资源、渠道、名分、债权、信息、阶段胜利或更大局面的主动权。
### 期待债
- 每次埋承诺(主角会反击、资源会升级、身份会揭开、感情会推进)都产生期待债。
- 期待债可以延期,但要付利息:阶段性进展、新信息、局势变化、情绪释放或更清晰的下一目标。
- 用解释、设定或机构流程拖延兑现,会增加合理化债务。
### 终局储备与推进节奏
“写无可写”的病根是两类**宏观资源**被提前打光,跟单章涨多少关系不大。管住这两类、放开单章密度,才既不透支又不憋屈。
**两类会打光的宏观资源(开书时定,逐卷解锁)**
- **终局底牌**:头号宿敌、终极真相/身世、金手指上限、身份/地位终点、核心情感的最终确定。一次性资源,用了就没。开书时列进 `设定/题材定位.md` 的「终局底牌与升级台阶」小节,每项标最早可解锁的卷/阶段(从终局倒推成卷级里程碑,一卷只解锁一个大里程碑)。
- **升级台阶**:境界/等级/地图/势力层级的剩余档数。开书时做一次台阶检查——体系档数 × 每档停留篇幅 ≥ 全书目标字数;台阶不够是设计病,设计期补(拉长体系/加地图层),不靠每章憋。敌人/目标/地图成**梯队**,逐级解锁,禁止越级提前秒顶级 boss / 解决终极目标。
**单章 / 单个剧情单元放开密度(爽感来源,不要压)**
- 每个剧情单元设 1 条**主推线**(战力线/资源线/身份线/关系线/信息线/地图线/制度线/势力线/事业线/情感确定性等升级线其一,承担本轮最大高潮),其余线按剧情自然给**战果**(轻触到大涨皆可)。**一战多得——一场大胜同时破境、缴获、收势力、涨声望、抱得美人——是允许且常见的好设计,该给就给。**
- 章级推进按平台/题材分档:快节奏(番茄/爽文)保留“每章要有可见事件或爽点推进”的下限;慢热/种田/情感文才放宽到“改变目标 / 风险 / 信息 / 关系 / 资源 / 身份 / 情绪立场七类状态之一即可”。低压/过渡章用小而可见的变化承接,不强求每章高潮。
- 高潮/兑现后可安排一段短暂低压,让读者先拿小而可见的收益/奖励,再进下一轮压力;不强制兑现后立即加危机。
- 可选工具:行动成本/成功代价。重要成功可带时间、关系、暴露、资源消耗或新敌意等成本;低压/过渡/纯奖励章不强制附加代价。
**推进过快判定(透支两问)**
1. 是否动用了本阶段还不该解锁的终局底牌(宿敌了结、终极真相、身份终点、金手指触顶)?
2. 是否让某条升级线逼近天花板、后面没台阶接?
任一为“是” = 真正的透支预警 → 回退或改纲;两者皆否,多线齐涨放行。这套判定是经验法则,档位与里程碑按本书题材、平台与对标调整,不是硬门槛。
### 合理化债务
- 解释成本用于说明机构响应/接管、保密、资源调动、跨区执法、组织协作等为什么成立。
- 检查:这些解释是否服务核心情绪?若解释本身吞掉爽点、代入或主角高光,就先缩短解释、改为可见交换,或把机构反应降级为旁观/阻碍/资源接口。
## 2. 制度/机构与旁观者设计
- 提到政府、宗门总部、跨国组织、多国公司等不天然有毒;它们只是高层级叙事开关。
- 国家合作 / 政府合作类故事可以算契约安全,前提是开篇已承诺制度合作,主角保持不可替代,并获得可见权力、保护、资源、收益或更高行动权限。
- 若本书承诺的是个人逆袭、职业掌控、独享金手指,外部机构接管核心问题通常需要强交换与主角主动选择。
- 旁观者/反应层适合做:震惊、误判、舆论扩散、资源报价、敌我站队、见证主角选择。避免让旁观者替主角复仇、替主角做最终裁决、替主角拿核心收益。
## 3. 风险等级
| 等级 | 定义 | 处理 |
|---|---|---|
| 契约安全 | 与开篇题材契约一致;主角仍拥有关键选择/不可替代贡献;收益归属清楚 | 可写,注意把交换和收益可视化 |
| 需补强 | 可能稀释主角高光或推进过快,但能通过铺垫、交换、成本、题材声明修复 | 写前补理由、补代价或调整为阶段性而非终局兑现 |
| 契约破坏 | 没收核心卖点;自愿让渡同时造成**长期净收益为负 + 主角控制/因果权下降**(尤其没有可见战略交换);无关角色夺走期待所有权;核心资产无交换上交或被接管 | 修纲;战略性让步可用局部聚光灯/资源换取更大控制、未来收益、关系/制度权力、信息优势,或兑现已承诺的群像/导师高光,不按让渡本身判红灯 |
## 4. 好/坏例与例外
### 职业/权力幻想主角自愿让出聚光灯
- 红灯组合:让渡同时导致长期净收益为负、主角控制/因果权下降,且看不到战略交换;不是任何自愿让渡都算 契约破坏。
- 好:主角授权下属执行,但方案、关键资源、最终谈判和风险承担由主角掌控;或用局部聚光灯/资源换取更大控制、未来收益、关系/制度权力、信息优势。下属表现反过来证明主角识人/组织能力。
- 例外:若本书从开篇承诺“导师/经营组织/群像成长”,主角的高光可以是培养体系、选人眼光和关键兜底。
### 给出资源或核心资产
- 坏:主角把独家技术、金手指产物、关键证据无条件交给机构,换来口头感谢,后续由机构推进主线。
- 好:主角交换到牌照、保护、渠道、话语权、独占收益或更大舞台,并保留不可替代的控制点。
### 无关角色替主角复仇
- 坏:压迫主角多章的敌人,被路过强者或随机事故解决,主角没选择、没出手、没获得认知/资源/地位变化。
- 好:配角可以助攻或见证,但关键证据、布局、决断、公开裁决或最后反击由主角完成。
- 例外:悲剧、悬疑、群像战争可让他人完成局部动作,但要让主角获得新的核心任务、代价或认知推进。
### 提前打光终局储备(多线齐涨本身没问题)
- 坏:一个剧情单元把全书级底牌一次性烧光——解决头号宿敌、揭终极身世、坐实终局身份、金手指直接触顶,后面没大目标可写。
- 好:本单元让主角一战多得(破境+缴获+声望齐涨),但都在体系台阶之内、不碰终局底牌;宿敌只退一个梯队、真相只揭一层,大底牌留到后续卷偿还期待债。
### 合法群像 / 导师故事例外
- 群像契约:每个 POV 有自己的目标和偿还,主角不是唯一爽点来源;卷契约应写清谁在本卷拥有高光。
- 导师契约:导师主角的高光在设计训练、识破困局、关键兜底、承担更高层代价,而不是每次亲手收割。
- 制度合作契约:开篇即承诺国家/机构协作,主角以专家、指挥者、关键资源拥有者或不可替代执行者身份获得明确权力和收益。
## 5. 续接与换书债
- **换书债**:引入新地图、新机构、新能力、新敌人或新谜团,既要支付必要的铺垫成本,也会新增期待债;不能靠新鲜元素逃避旧承诺。
- **题材特定高风险**:在履约爽文/能力幻想中,主角反复因愚蠢或可避免的无能制造灾难,再由别人收拾,会持续损害因果权、控制感和结算信任;这是依题材契约判断的高风险,不是所有故事的绝对禁令。
references/state-tracking.md›
# 状态追踪协议
> 本文件定义"本节速记"的提取逻辑和"角色状态记录"的格式。写作 skill 在写前准备的状态筛选步骤中加载此文件。
---
## 本节速记
写作每一章/每一节前,从所有已加载的上下文中筛选出只与本节相关的信息。目的是避免全量加载导致 LLM 上下文被无关信息稀释。
### 筛选逻辑
从上下文中提取三类信息:
1. **当前状态**:本章涉及角色的最新能力、关系变化、公众形象
2. **历史因果**:与本章事件直接相关的伏笔成因、前史事件
3. **世界约束**:本章涉及的世界观规则(力量体系、社会规则、地理限制)
### 筛选标准
**只保留"如果不知道这个,本章会写错"的信息。**
具体判断方法:
- 本章细纲中提到了某个角色 → 保留该角色的当前状态
- 本章有伏笔回收 → 保留伏笔的埋设细节和前文铺垫
- 本章涉及特定地点/能力/规则 → 保留相关世界观约束
- 纯背景知识(与本章事件无因果关联) → 丢弃
### 输出格式
筛选后输出一个简洁的"本节速记":
```
## 本节速记(第{N}章)
### 角色状态
{角色A}:{一句话当前状态,含最近变化}
{角色B}:{一句话当前状态}
### 相关伏笔/前史
{伏笔1}:{埋设细节,{埋设章节}},本章需要{回收/推进}
### 世界约束
{约束1}:{与本章相关的规则/设定}
```
**示例(demo《让你管账号,你高燃混剪炸全网》第 10 章):**
```
## 本节速记(第10章)
### 角色状态
江晨:火箭军文工团宣传兵,《诸君,且听龙吟》已爆红,正从军宣新人升为军内认可的创作者
钟嘉嘉:军报记者,采访稿已经过审,与江晨从采访关系转为稳定合作
周薄森:文工团副团长,已从担心江晨惹事转为认可其创作能力
### 相关伏笔/前史
五天百万粉任务:第1章发布,第10章仍未结算;本章只推进声量,留到第11章结算
专业团队重拍:本章用高清专业版“缺了灵魂”反衬江晨手机原版不可替代
### 世界约束
军宣作品采用要经过组织决策;江晨可以靠作品效果赢得认可,不能跳过军内流程直接拍板
```
---
## 角色状态记录格式
> ⚠️ **本节仅适用于长篇写作。** 短篇通常不需要独立角色状态追踪。
动态状态按核心角色拆成 `追踪/角色状态/{角色名}.md`,由 `tracking_commit.py` 根据事务 JSON 整份覆盖;静态原始人设仍在 `设定/角色/{角色名}.md`。只为后续会复用的主角、反派、核心配角建快照,不为路人、一次性功能角色建文件。
### 格式
```markdown
# 江晨|当前状态
- 截至章节:第10章
- 身份:火箭军文工团宣传兵;军宣爆款创作者
- 位置:火箭军文工团高层看片会
- 当前目标:完成五天百万粉任务,持续做出真正能打的军宣内容
- 身心状态:专业团队反向验证原版价值,军内认可继续抬升
## 能力与资源
- 前世 MCN 爆款运营经验
- 《中国军魂》伴奏
- 大师级导演能力
## 关键关系
- 钟嘉嘉持续提供军报资源
- 周薄森和张耀祖已明确认可其创作能力
## 已知信息
- 《军报》采访稿已经过审
- 原版视频将继续作为正式军宣内容
## 未结事项
- 五天百万粉任务尚未结算
- 钟嘉嘉所谓“只猜对一半”仍未解释
```
### 更新规则
1. 每章只记录身份、位置、目标、身心状态、能力资源、关系、已知信息、未结事项中真正发生变化的内容。
2. 核心复用角色发生变化时,在同一事务的 `character_changes` 写变化,并在 `character_snapshots` 提交其**截至当前已写最后一章**的完整快照;工具以快照是否存在判断核心/临时角色,整份覆盖核心角色小文件,不追加历史。
3. 修订旧章时,从修订章检查到最后已写章,按各维度和各关系对象重算当前状态,再提交完整快照;不得把最后一条单维度变化当成角色全状态。
4. 无变化可不提交快照;核心角色重新进入当前场景时直接读取其已有小文件,并由事务工具把必要信息带入续写状态卡。
5. 角色变化历史属于 `逐章记录/第NNN章.md`,当前快照不重复保存逐章履历。
6. 完整 JSON 字段、4096 字节目标与 8192 字节硬上限见 [tracking-transaction.md](tracking-transaction.md)。
references/style-combat-face.md›
# 装逼打脸与爽点释放
> 装逼打脸框架、爽点释放法则、无敌文要领、打斗/智斗写作、战斗描写三板斧。用于设计装逼打脸场景和战斗场景时查阅。
---
## 决策路由
| 你在做什么 | 查阅哪个模块 |
|-----------|-------------|
| 设计装逼打脸场景 | 装逼打脸框架分析 -> 装逼进阶:二级结构化装逼技法 |
| 释放爽点但怕写不到位 | 爽点释放到位法则 |
| 设计战斗/打斗场景 | 打斗/智斗写作 -> 战斗描写三板斧 |
| 写无敌文主角 | 无敌文核心要领 |
| 设计打脸节奏和情绪调动 | 打脸节奏与脑洞创意 -> 情绪调动三阶法 |
| 设计后宫/爱情线 | 后宫文女主人设设计法 / 男频极简爱情线构型 |
| 写新媒体/短平快装逼 | 新媒体写作与题材套路 |
| 搭建装逼舞台 | 舞台搭建法 |
| 打脸写了但不爽 | 检查:爽点释放到位法则 + 前置小无敌准备了吗 + 对手层级够不够 |
| 战斗场景枯燥/流水账 | 检查:战斗描写三板斧 + 情绪调动三阶法 + 缺少感官细节和身体反应 |
## 指令语气
本文件以"战术指令"语气书写。装逼打脸和战斗描写是网文核心商业价值所在,所有规则都是**必须执行**的操作规范。爽点释放法则 > 装逼框架 > 具体描写技巧。核心铁律:**该爽不爽,比毒点还毒**。
---
## 爽点释放到位法则
### 核心问题
爽点场景如果只追求合理性而没有兑现期待,会导致“该爽不爽”。
### 执行立场
先确认本场景承诺的爽点,再保证释放强度匹配铺垫强度;合理性用于支撑爽点,不得削弱爽点。
### 典型错误写法
主角有底牌,读者期待放出来。主角确实放了,然后:
- 观众:"看不懂,这什么垃圾?"
- 敌人:"确实出乎预料,不过仅此而已?"
- 紧接着敌人不仅没被底牌制服,还爆发出来揍了主角一顿
- 结果:主角漏了金手指还被揍 = 扶不起的废物
### 正确写法
围绕核心,把各个视角写到位。放了底牌,反派就要受到对应的压制:
- 该写破防写破防
- 该写羡慕写羡慕
- 该受伤扭转战局就写扭转
- 金手指对剧情的效果必须展示得清清楚楚
为了情绪的顺畅,甚至可以在一定程度上牺牲合理性、牺牲行文。
### 关键原则
- 前期拉了期待,爽点释放必须匹配期待高度,否则反作用
- 寸止可以,拉扯可以,但**别让主角委屈**
- 配角、反派、人设、剧情都是为了服务核心卖点
- 核心卖点是为了服务读者
- 发刀子本身不等于难受;想爽而没爽起来,才是真正的难受
---
## 装逼打脸框架分析:人际关系驱动的装逼
### 执行规则
装逼方式随时代变化,但核心不变——核心是被环境认可的鄙视链。
| 环境 | 鄙视链 | 核心 |
|------|--------|------|
| 学校 | 成绩 | 考出更高分数 |
| 职场 | 职位和业绩 | 创造的价值 |
| 神豪文 | 钱的多少 | 财富带来的地位和话语权 |
| 古代架空 | 文采 | 文人地位和仕途便捷 |
### 装逼三步框架
1. **铺垫人际关系**:用各种方式建立主角与配角的联系(棋艺吸引大佬、救人获得感激、讲故事吸引学生)
2. **构架舞台**:通过人际关系搭建分层舞台(群众层 -> 中间层 -> 核心层)
3. **层层传递震惊**:主角行动 -> 第一层震惊 -> 传递到第二层 -> 传递到核心层 -> 核心层反应反向传递回群众层
### 震惊传递链(以赘婿诗会为例)
```
丫鬟(最内层崇拜)
-> 传递
商贾诗会(妻子、组织者、才子震惊)
-> 传递 + 反向
顶级诗会(大佬膜拜、士族震惊)
-> 反向传递
女伶人震惊 -> 群众震惊 -> 丫鬟二次震惊
```
### 操作要点
- 装逼前必须先铺设人际关系,否则没有传递通道
- 装逼不仅仅正向的(由下往上),还有反向的(大佬震惊传回群众)
- 鄙视链核心要对:你想让谁认可主角,就给主角匹配该角色重视的资源
- 闭环:高潮后众人对主角态度的转变,完成情绪闭环
---
## 装逼进阶:二级结构化装逼技法
### 核心逻辑
基础装逼 = 主角展示实力 -> 旁观者震惊。二级结构化装逼 = 主角的展示不仅震惊旁观者,还直接影响旁观者的目标/利益/计划,产生连锁反应。
### 二级结构设计
1. **一级效果**:主角展示 -> 直接震惊("他好强")
2. **二级效果**:主角的展示改变了在场某个角色的处境/计划/利益计算
- 主角的成果正好是A苦苦追求的东西 -> A的焦虑升级
- 主角的实力打破了B的认知框架 -> B必须重新规划
- 主角的存在威胁到C的地位 -> C产生敌意或靠拢
### 操作要点
- 震惊不只是"好厉害",而是"这跟我有关系"——震惊变成利益反应
- 每个在场角色的反应要基于自身利益和目标,不是统一的"倒吸一口凉气"
- 二级效果创造新的矛盾和关系变化,为后续剧情提供动力
- 主角的每次装逼至少波及一个角色的核心利益,产生后续剧情钩子
### 震惊波及链
主角展示 -> 直接目击者震惊(一级)-> 消息扩散 -> 未目击者基于利益产生反应(二级)-> 利益相关方开始行动(三级)
---
## 无敌文核心要领
### 唯一铁律:主角不能拖拉
无敌文中,哪个人物拖拉都行,主角登场时一点都不能拖拉。
- 开头塑造主角杀伐果断的性格 + 战力前置无敌 = 天然期待感
- 读者知道主角不拖拉后,会形成"无论剧情怎么发展,只要主角登场就会大杀四方"的期待
- 无论剧情让读者多么不爽,都会有一大批读者等主角强势解决的那一刻
- 常见错误:主角和反派有血海深仇,但杀反派时磨磨唧唧、喜欢嘴炮、出手不一击必杀 -> 读者耐心崩溃
---
## 后宫文女主人设设计法
### 核心思路
后宫文的关键是弱化男主"主动渣"的感觉,让女主自身设定成为推动后宫的主力。
### 设计原则
1. **女主人设要预设方向**:开书前就设计好每个女主的核心特质
2. **差异化设计**:不同女主有完全不同的价值观和背景
3. **同居培养感情**:开局让女主们同住一个屋檐下,彼此成为朋友
### 温水煮青蛙法
以三个女主为例:
| 角色 | 人设设计 | 在后宫中的作用 |
|------|----------|---------------|
| 青梅(正宫) | 传统价值观,占据防守位 | 从小一起长大,天然正宫 |
| 女主B | 家庭圆满家教开明,理性看待感情 | 不在意名分,只在意快乐 |
| 女主C | 缺少父爱和社交,爱情观模糊 | 不存在一夫一妻制思想束缚 |
核心逻辑:
- 青梅占据正宫与防守位
- 另两个女主不在意后宫,只在意跟主角在一起
- 把"主角脚踏多条船"的问题转化为"青梅防守 vs 另两人共享"的问题
- 一点一点突破青梅的防守底线,等反应过来时已经是既成事实
---
## 男频极简爱情线构型
### 核心原则
男频爱情线不需要复杂的情感博弈,核心是"英雄救美 + 事业舞台 + 对手衬托"三要素。
### 极简构型
1. **英雄救美**:女主陷入困境 -> 主角用金手指/实力解决 -> 建立初始好感
2. **事业舞台**:主角在事业上展示金手指 -> 女主在场作为重要观众 -> 好感随事业成就升级
3. **对手衬托**:情敌/对手同时是事业对手 -> 打败对手既是事业胜利也是感情胜利
### 关键操作
- 女主的每一次好感升级都绑定在主角的事业成就上,不单独写纯感情戏
- 女主有自己的事业线/目标,不是花瓶——她的事业目标与主角有交叉但独立
- 情敌的价值在于他同时威胁主角的事业和感情,打脸时有双重爽感
- 感情节奏跟着事业节奏走:事业低谷时感情拉扯,事业高峰时感情升温
### 爱情线与事业线融合检查
- 删掉所有爱情线段落,事业线是否还成立?如果不行 = 爱情线拖后腿了
- 删掉所有事业线段落,爱情线是否还有看点?如果不行 = 爱情线太弱
- 理想状态:两条线互相增强,拆开各自能看,合在一起更好看
---
## 打斗/智斗写作
### 打斗的本质
- 打斗是一场表演,是主角展示收获的舞台,必须服务于爽点
- 能秒杀就秒杀,不秒杀就稍微反转再杀,不必刻意追求复杂打斗
- 打斗建立在主角展示和世界观理解之上,不能脱离设定空写
- 打斗不是水字数的手段,精彩打斗应给读者刀尖舔血的爽快
### 心-体-技三维模型
**心(意志/心态)**
- 角色的意志力、心理素质、战斗意志
- 钢铁意志可以成为以弱胜强的关键——豁命去换,对方新生畏惧反而被杀
- 心态崩溃导致招式变老,是战败的常见原因
**体(身体素质)**
- 力量、敏捷、耐力等基础属性
- 装备加成、血脉之力、身体极限
- 是否能超越极限强行使用能力
**技(技能/招式)**
| 类型 | 说明 | 适用题材 |
|------|------|----------|
| 武技 | 剑法、枪法等需要现实招式配合 | 骑士文、高武、武侠 |
| 法术 | 脱手攻击如法术、真气、灵气 | 西幻巫师、高武超出部分、低玄 |
| 法则 | 时空、法则等抽象力量 | 玄幻最终阶段 |
### 战斗设计流程
1. **铺垫先行**:打斗起因、对手身份、双方实力对比都要提前铺垫
2. **预判结局**:写前确定战斗结果类型——碾压 / 以弱胜强 / 逃走进入第二阶段,并把该结果写入细纲或写前准备
3. **构建爽点**:确定这场战斗要达成什么爽点效果
4. **拉开维度**:
- 主角用什么老技能和新技能达成对比?
- 对方用什么技能给读者"主角可能要输"的错觉?
- 过程中是否需要震惊旁观者?
5. **反转设计**:长篇打斗不能势均力敌,必须有反转
### 不同力量体系的打斗特征
| 体系 | 特征 | 要点 |
|------|------|------|
| 低魔(武侠/低武/骑士) | 以现实招式为基础 | 强调体术和装备,动作描写需要具体 |
| 中魔(巫师/高武/低玄) | 法术和真气参与战斗 | 平衡招式华丽度和战斗逻辑 |
| 高魔(玄幻巅峰) | 抽象力量如时空、法则 | 逻辑自洽比画面感更重要 |
### 战斗描写实操技巧
- 修饰词每个动作应有信息量——读者脑中能浮现画面就合格
- 重复使用的招式一句带过,只写效果,再用旁人震惊渲染
- 大招首次出场可以详细描写,后续使用精简为"结果概括+旁观反应"
- 白描写法要用在关键处迸发强烈情感,战斗全用白描反而不易写好
- 技能喊名是读者习惯的信号机制,不算出戏,但不要每次都详细重复描述同一个招式
- 用情绪展示境况:感叹、震惊、窃喜表现谁优谁劣
### 智斗与阴谋设计
- 智斗的本质是信息差的博弈——谁掌握更多情报,谁就占据主动
- 一环套一环的阴谋诡计要能自洽,主角破局方式要有逻辑基础
- 玩转人性才能破局:了解对手的性格弱点比蛮力更有效
- 正邪立体的写法:魔宗里与众不同的赤心主角比全员好人的正道更有张力
- 该阴险时阴险、对自家人善良——灵活的底线,拒绝愚蠢的正义
### 以弱胜强的设计要点
- 钢铁意志+豁命去换 -> 对方新生畏惧 -> 招式变老 -> 反而被杀
- 超越极限强行使用高阶能力,但要付出明确代价
- 信息差利用:主角知道对手弱点,对手不了解主角底牌
- 环境利用:战场地形、天气、第三方势力介入
- 心理博弈:激怒对手使其失去冷静,或示弱诱敌深入
### 打斗中的情绪节奏
- 打斗不是匀速的:急 -> 缓 -> 急的节奏感比全程紧张更吸引人
- 穿插心理活动让读者明白前因后果,但不能打断战斗节奏太久
- 不知道怎么编排动作措辞时,参考经典打斗场景的动作编排模式(如:蓄势-爆发-余波三段式)
- 在写打斗时融合角色的性格特征,让战斗本身也成为人物塑造的一部分
---
## 战斗描写三板斧(玄幻/修仙/武侠)
### 玄幻战斗核心原则
- 无论主角参与还是旁观,输赢如何,务必突出一点:男主很牛逼
- 战斗结构:气势对拼 -> 语言交锋 -> 出招展示 -> 敌人防御 -> 碾压/秒杀 -> 路人惊叹
- 反派要先铺垫得极强(功法牛逼、准备充分、自信满满),然后被秒杀——反差即爽感
### 玄幻战斗旁观写法
- 双方打得精彩,男主淡定喝茶/旁观
- 被波及时轻描淡写化解力道,自然转入主动出手
- 或观摩高手战斗顿悟新招式,开辟副战场展示
- 核心原则:别人的战斗最终也要服务于"突出男主牛逼"
### 修仙斗法逼格四要素
- **时间**:七七四十九日、甲子之数、元会之数——用大时间尺度制造厚重感
- **数字**:可量化的数量/体积/重量——千灯船龙、百丈法身
- **意识流元素**:怨念、七情六欲、唯心概念——增加神秘感
- **用典**:书中已形成的典故,或现实典故——增加文化深度
### 斗法的关键在"斗"字
- 所有元素的设计目的是为了对比——我的一滴水破你千灯船龙
- 三种斗法方向:
1. 物极必反:极寒则类阳,最光明处生阴影
2. 善泳者溺于水:在对方最强方面打败他(巧胜为上,消磨为中,碾压为下)
3. 上天有好生之德:万事不可完满,大劫下必有一线生机,从生机破局
### 战斗升级路线图
- 从拳打脚踢 -> 法术对轰 -> 规则机制对抗
- 从具象 -> 抽象,从肉搏 -> 肉搏+机制 -> 纯智斗
- 数值对抗转为机制对抗,机制很难出现审美疲劳
- 适当穿插感情、权谋、种田、经营、美食,有效减缓战斗审美疲劳
---
## 打脸节奏与脑洞创意
### 情绪调动三阶法
**长期情绪引导三步法**——将读者转化为忠实粉丝:
1. **丢出共鸣炸弹**:通过角色的经历、期许、愿景,唤醒读者心中的强烈情感。关键在共鸣,不在新奇。
2. **让读者变为见证者**:让读者感受到角色的付出——每一步付出必须伴随收获。
3. **让读者变为参与者**:引导读者以为自己付出了很多。付出越多越离不开。
**短期情绪引导要点**:
- 独立的事件冲突比繁杂精巧的情节构造更容易引起情绪共鸣
- 塑造人物性格的事件使剧情变慢,推动剧情进展的事件使剧情加快——调节节奏的核心方法
- 每个角色都引导 = 每个角色都没引导。重点突出、层次分明才是艺术品
### 打脸节奏的核心原理
- 成功作品依靠多重因素共同引导情绪,不能只靠表层文本结构的单一技巧
- 持续压抑中,读者的期待感大部分来源于长期对角色的感情投入,而非单纯想看打脸
- 常见问题常在感情基础未建立时急着压抑,并非单纯"压抑过度"
### 白描情绪调动的四要素(以《斗破苍穹》为例)
- 句子:干净利落,不堆砌形容词,让动作词和情绪词自己发力
- 情绪词:骤然、猛然、刺眼等精准情绪锚点
- 动作词:抽、划、沾染、留下等连续动作链
- 以乐写悲:不描述悲伤,而描述开心——开心到让人心碎
### 上瘾模型应用于网文创作
| 要素 | 网文对应 | 勾出的原罪 |
|------|----------|-----------|
| 触发 | 切入点——共鸣点要精准对准读者自己想要的东西 | 妄想(越要越多) |
| 行动 | 行文标准——开篇别想太多,爽点安排有明确周期 | 懒惰(轻松入坑) |
| 奖励 | 收获期待——收获感必须出乎意料,有高有低 | 贪婪(期待下次) |
| 投入 | 发展高潮——主角的装备/荣誉/社交关系/势力等积累 | 痴迷(难以割舍) |
收获感的设计原则:
- 收获感必须有,且出乎意料
- 刺激不论高低,只要稳定就会趋于平淡
- 只有随机的不确定,才能让人对"下一次"充满期待
### 装逼五步法
1. 主角很强但别人不知道
2. 渲染困境难度
3. 配角不看好主角
4. 主角用金手指轻松解决
5. 众人震惊
### 作品五不崩原则
1. 目标不缺失——主角始终有明确目标在追
2. 卖点不减少——核心爽点不能中途消失
3. 主角社会关系不空白——不能变成独狼
4. 上层地位不缺失——要有比主角更强的存在
5. 地位收获提升不能停——持续成长感
---
## 新媒体写作与题材套路
### 新媒体文核心原则
**情绪第一**:新媒体的核心是情绪,剧情服务情绪调动和释放。
情绪分类:
- 不爽 -> 爽(通常通过装逼实现)
- 愤怒 -> 解气(通过报复/惩罚实现)
情绪值分轻重两种:轻压 = 走路上撞人被骂;重压 = 女朋友被人捅了一刀。
### 三种装逼方式
| 类型 | 操作 | 效果 |
|------|------|------|
| 基础装逼(不压,直接装) | 利用人性的表现欲——你很牛逼但无人知道,你表现出来就是装逼 | 突然装逼,路人惊叹 |
| 温酒斩华雄式(侧面压,装逼) | 配角突出反派的牛逼,反派突出主角的牛逼 | 压得不重,一切服务于更好的装逼 |
| 狠压式(核心中的核心) | 在第二种基础上狠压,压到读者上头再装逼 | 打脸+装逼的终极爽,强于单纯装逼 |
### 三种打脸方式
| 类型 | 操作 | 示例 |
|------|------|------|
| 愤怒式(单层次) | 别人瞧不起男主+做了令读者上火的事 -> 打脸一次 | 拆穿反派假画 |
| 循环打脸(多层次递进) | 同一剧情打三四次,一波比一波爽 | 拆穿假画 -> 奶奶偏袒说是真画 -> 假画上写着"中国制造"继续打脸 |
| 狠压式(核心) | 压得越狠,打脸越爽 | 买车被狗眼看人低 -> 买下砸了 -> 再买再砸 -> 暴露身份 |
愤怒式与瞧不起式是两种不同压点,千万不能写串:愤怒式是做了令读者上火的事;瞧不起式是狗眼看人低。
---
## 舞台搭建法
**舞台两大维度**:
- **大小** = 观众数量:室友看 -> 直播间万人看 -> 全赛区看 -> 全世界看
- **高度** = 对手身份+比赛重要程度:普通排位 -> 王者局 -> S赛决赛
**实操方法**:
- 每次主角装逼时检查:舞台还能不能更大、更高?
- 扩大舞台:增加人物(设定几个白银室友目瞪口呆看着主角一飞冲天)
- 抬高舞台:增加剧情铺垫(对手的历史统治力、队友的托孤、父母从反对到现场见证)
- 在不崩的前提下,观众能拉多少拉多少,意义能附加多少附加多少
---
## 质量检查清单
设计完装逼打脸/战斗场景后,逐项检查:
- [ ] **爽点到位**:底牌放出后,反派受到了对应压制,没有被反打
- [ ] **主角不委屈**:寸止可以,拉扯可以,但主角没有被羞辱/被打脸
- [ ] **铺垫充分**:装逼前有人际关系铺垫,有传递通道
- [ ] **震惊分层**:避免所有人统一"倒吸一口凉气",改成基于自身利益的不同反应
- [ ] **舞台够大**:观众数量和对手身份匹配爽点高度
- [ ] **战斗服务于爽点**:打斗是展示收获的舞台,不是为了写打斗而写打斗
- [ ] **无敌文主角不拖拉**:主角登场即杀伐果断,不一击必杀时也有明确理由
- [ ] **情绪节奏**:急-缓-急交替,不是全程匀速
- [ ] **以弱胜强有逻辑**:有明确的信息差/环境利用/心理博弈,不是靠运气
- [ ] **五不崩**:目标不缺、卖点不减、社会关系不空、上层存在不缺、成长不停
- [ ] **装逼闭环**:高潮后众人对主角态度转变,完成情绪闭环
references/style-craft.md›
# 写作技法
> 镜头式写作、白描、视角、文笔、毒点规避、开篇定调。用于正文写作和行文质量提升时查阅。
---
## 决策路由
| 你在做什么 | 查阅哪个模块 |
|-----------|-------------|
| 写正文、润色文笔 | 写作四要点 -> 写作基础技巧 -> 镜头式写作法 |
| 控制文字情绪密度 | 行文验收两字诀 -> 文笔三要素与水分控制 |
| 选择视角和叙事方式 | 视角选择与叙事 |
| 避开读者反感点 | 毒点解析与规避 |
| 设计开篇三章 | 黄金三章=定调与预期管理 |
| 优化段落画面感 | 文本构成要素 -> 文笔全面解析 |
## 指令语气
本文件以"操作指令"语气书写。所有规则都是**必须遵守**的写作约束。遇到冲突时:镜头式写作法的规则 > 基础技巧 > 认知类参考。
---
## 写作四要点
### 要点一:"然后呢"基点法
每一段文字都要回答读者心中的"然后呢"。写完一个信息点,立刻用下一个信息点接上。
### 要点二:间接描写法
正面描写只是铺垫,侧面反应才是爽点。写配角嚼饼的吃相、哄抢的情形,比干巴巴说"这饼宇宙第一"有效百倍。
### 要点三:围绕核心情绪设计全部情节
动笔前确定目标读者的核心情绪需求(被认可/复仇/恋爱/升级),所有情节、人设、冲突都围绕这根弦演奏。
### 要点四:宏观微观一体把控
宏观把控整体节奏和情绪走向,微观把控每段文字的细节和张力。
---
## 写作基础技巧
### 白描
白描 = 最少的字 + 最准确的信息和情绪。用精准的动词和名词直接勾勒画面,给读者留白想象空间。
### 五感描写法
- 至少调动两到三种感官(视觉/听觉/触觉/嗅觉/味觉)
- 写"感受到什么"而非只写"看到什么"
- 五感必须服务情绪——恐惧时写冷、暗、静;兴奋时写亮、快、响
### 动态描写优于静态描写
- 人物特征用动作和反应展现,不用形容词堆
- 示范:众人看到她时,说话的声音不自觉地放轻了
- 环境不要大段铺陈,在角色行动中穿插点染
### 对话描写要点
- 每句话至少满足一项:推进剧情 / 展示人设 / 制造冲突
- 用语气、动作、省略来暗示潜台词
- 日常用语,不要书面腔
### 场景切换与转场
- 用相似物/相似五感/相似情绪做转场
- 时间跳转:动作或物件衔接
- 空间跳转:声音或光影衔接
### 镜头与分镜思维
- 每个段落 = 一个镜头,有明确的"拍摄对象"
- 镜头类型:远景(环境/氛围)-> 中景(人物关系)-> 近景(表情/细节)-> 特写(关键物品/情绪)
- 快节奏:短句、短段、密集动作、快速切换
- 慢节奏:长句、环境描写、心理活动、静止镜头
### 代入感建立
- 主角的目标清晰且让读者认同
- 主角的行为读者能理解动机
- 叙事立场必须站在主角一侧
### 向人设深化 vs 向故事深化
- 向故事深化:复杂阴谋、多层推理——上限高但难度大
- 向人设深化:人物关系和互动中找戏剧性——更容易上手
- 核心让读者觉得"来看热闹"——人物化学反应本身就足够有趣
### 高情商/聪明人角色塑造
- 通过行为展现聪明,不靠旁白说他聪明
- 将真实案例的核心逻辑提取后适配到网文语境(保留逻辑骨架,替换具体细节)
---
## 行文验收两字诀
### 第一字:顺
| 卡顿类型 | 解法 |
|----------|------|
| "了"字卡顿 | 控制不必要的"了"字使用频率 |
| 玩梗卡顿 | 只用目标读者群体熟悉的梗 |
| 信息缺失卡顿 | 适时补上必要信息 |
| 伏笔过远卡顿 | 揭示前简短提示前文 |
### 第二字:准
什么情绪写什么味——该热血热血,该温暖温暖,该恐怖恐怖。
| 情绪 | 关键 | 反面信号 |
|------|------|----------|
| 悲壮 | 牺牲要有分量,代价要真实 | 角色死了读者无感 |
| 温暖 | 日常细节中的关心 | 刻意煽情 |
| 恐怖 | 未知和失控感 | 靠血腥描写堆砌 |
| 热血 | 宣言感 | 口号空洞无铺垫 |
---
## 镜头式写作法
忘掉全知视角,你是跟在主角身后的摄像机。读者只能看到主角看到的东西。
### 核心原则
1. 只写能看到/听到/闻到/摸到的,不写"他心里想""他感到"
2. 每句对话都要推进剧情、塑造人物、或传递信息
3. 动作代替描述:"他很紧张" -> "他的手在抖"
4. 手机屏幕优先:按动作/信息变化换行,读起来卡时拆段;拆的是段落,叙述句仍以逗号长句为主(句长标准见 anti-ai-writing.md 规则 3)
### 高危清单
**高危视角**
- 全知叙述:"此时的他还不知道,三天后..."
- 上帝视角:"如果她知道真相..."
- 心理分析:"他内心深处其实..."
**高危词汇**
仿佛、犹如、一丝、一抹、深吸一口气、不禁、眼中闪过、嘴角勾起、眉头微皱、不容置疑、不易察觉(“好像”按语境判断,不机械替换;缓缓、微微、轻轻、淡淡走密度控制,每千字合计 ≤3,孤立自然使用可保留)
**高危句式**
- "...,带着..."(如:他说,带着一丝无奈)
- 对话标签密度过高/公式化标签 -> 高频时用动作神态替代,普通“说”可保留
- "他/她知道..." -> 直接展示,不告诉
- 陈词滥调/万能比喻 -> 改成生活化比喻或白描
### 替代技巧
| 禁用 | 替代 |
|------|------|
| 他感到紧张 | 他的手在抖 |
| 她很伤心 | 她转过身,肩膀微微颤动 |
| 高频公式化对话标签 | 用动作、语气或上下文承接;普通“说”可保留 |
| 他深吸一口气 | 他把烟摁灭在烟灰缸里 |
| 她眼中闪过一丝惊讶 | 她的手停在了半空 |
### 对话写作规范
每句对话必须满足至少一个:推进剧情 / 塑造人物 / 制造张力
**对话格式**
- 用动作打断长对话
- 每次说话不超过3句
- 避免高频/公式化对话标签;普通“说”可保留,仅在机械重复或语气单一时用动作/上下文替代
**对话情绪五级递增**
1. 客观陈述事实
2. 客观陈述 + 提出建议
3. 主观指责
4. 主观指责 + 强制命令
5. 主观指责 + PUA抬升自己(最强)
### 三机位法
| 机位 | 视角 | 内容 | 功能 |
|------|------|------|------|
| 机位1 | 近景 | 主角动作、表情、心理 | 推进主线,读者代入 |
| 机位2 | 远景 | 配角反应、环境变化、围观者 | 扩展信息面,制造反差 |
| 机位3 | 旁白 | 设定补充、背景交代 | 适时补充必要信息 |
机位交替原则:核心1和2,机位3穿插。设定都由冲突引出。
---
## 文本构成要素
### 核心分类
- **画面感**:人+环境(静/动),如高清摄像机忠实记录
- **思想**:计划/目标/吐槽/揣测/分析等内心活动
- **情绪**:藏在画面感与思想之中,不直接写出来
- **旁白**:身世背景/设定/人物关系/回忆,尽可能简洁
### 情绪表达层级(由低到高)
1. 最低:直接写"xx愤怒/伤心/快乐"——告诉情绪,读者感受不到
2. 低:用思想"xx暗骂"
3. 中:用神态"xx脸色铁青"
4. 高:用动作"xx猛地攥紧拳头,指甲掐进肉里"
核心:离底层情绪越远的表达越高级 = 侧面描写。
### 环境交互(环境描写核心)
没有交互的环境描写不值得写。
- 物理交互:梨花飘到鼻尖打喷嚏 / 雪山瑟瑟发抖 / 河水洗脸
- 精神交互:食物比喻人物关系 / 喂饭=暧昧 / 餐刀切鱼=威胁
- 题材交互:仙侠写遮天蔽日鲲鹏 / 武侠写匹夫一怒血溅五步
---
## 文笔三要素与水分控制
### 文笔三要素
- **精准**:一个词能说清的不用一句话,动词选择决定画面感
- **节奏**:叙述默认用逗号长句,短句只作偶尔的孤立重拍、用完回到逗号长句;忌通篇同长度,也忌一长一短机械交替(句长标准见 anti-ai-writing.md 规则 3)
- **画面感**:调动五感,不只写"看到"
### 水分控制
- 水分 = 不推动剧情也不塑造人物的内容
- 合理的"水":伏笔铺垫/氛围营造/角色互动——暗流涌动
- 有害的水:重复已知信息/无意义环境描写/角色自言自语
- 检验法:删掉这段后读者会不会困惑 -> 不会 = 水
### 长篇网文的文笔取舍
长篇不需要精致文笔,需要可读性和流畅度。文笔的目标:让读者忘记在看字,直接看到画面。
---
## 文笔全面解析与环境交互法
### 文笔重要性的阶段差异
| 阶段 | 重要性 | 说明 |
|------|--------|------|
| 小学生文笔 | 10分 | 基础不过关,什么都谈不上 |
| 基础达标 | 5分 | 达标后短板在结构和选材 |
| 精品级别 | 7分 | 精品之间文笔开始拉开差距 |
| 万订 | 10分 | 顶级作品的文笔是核心竞争力 |
判断:成绩好但文笔差 -> 提升文笔性价比极高;成绩差但文笔好 -> 补选材和剧情。
### 一笔多用
一段文字同时承担多种功能:
- 环境交互 + 人设 + 感情线 = 一笔三用
- 设定融入情节:世界观通过小故事穿插
- 埋伏笔:表面信息之下藏隐藏信息
- 紧凑节奏:枯燥背景设定藏在有趣小情节中
### 结构简化
"x级结构"核心是"细化":一句话主线 -> 细化 -> 卷纲 -> 细化 -> 章纲 -> 细化 -> 正文。逆推比顺推效率更高。
---
## 文笔的本质与层级
### 三项输出检查
- **选材**:目标读者、题材边界、核心卖点是否清楚。
- **剧情设计**:大纲/卷纲/章纲是否能持续制造目标情绪。
- **文笔**:正文是否用具体动作、对话、物件和节奏交付情绪。
如果正文问题来自选材或剧情设计,不要只润色句子;回到对应 artifact 修正。
### 表达情绪的层级(由低到高)
| 层级 | 写法 |
|------|------|
| 最低 | 直接写"xx愤怒" |
| 低 | 用思想"xx暗骂" |
| 中 | 用神态"脸色铁青" |
| 高 | 用动作"猛地攥紧拳头,指甲掐进肉里" |
核心:不写情绪本身,写情绪引发的外在表现。
---
## 视角选择与叙事
### 网文常用视角
| 视角 | 特点 | 适用 |
|------|------|------|
| 第三人称有限 | 跟随主角视角 | 最常用,代入感最强 |
| 第一人称 | "我"叙述 | 悬疑、日常文 |
| 第三人称客观 | 只写外部行为 | 群像 |
| 跳跃视角 | 不同角色间切换 | 制造信息差 |
| 上帝视角 | 全知全能 | 传统文学,网文少用 |
### 使用要点
- 网文最推荐第三人称有限视角
- 跳跃视角主要用于制造"读者知道而主角不知道"的信息差
- 切换视角要有明确分隔标志
- 第一人称慎用——限制信息量,后期展开困难
### 抽象与具体的平衡
- 套路是共性,每本书的个性才是读者留下来的理由
- 好网文文笔=大白话能读懂,但删到只剩推动情绪的动作和对话
- 好的网文文笔:粗看大白话,细看有水平
---
## 毒点解析与规避
### 五大毒点方向
| 方向 | 规避方法 |
|------|----------|
| 主角塑造 | 叙事立场站在主角一侧;主角做事必有正反馈 |
| 题材雷点 | 了解目标读者群体,避开敏感话题 |
| 氛围代入感 | 氛围感比梗重要一百倍(乐子文除外) |
| 期待破坏 | 把握节奏,适时满足或引入新期待 |
| 题材选择 | 参考三五千均订的作品而非顶流 |
### 核心原则
- 主角是心头爱:叙事立场必须站在主角一侧
- 明确读点:毒点随题材变化,讨好目标受众而非所有读者
- 期待管理:连续多次破坏读者期待会引发信任危机
- 开头简洁:第一章就展现关键要素
---
## 黄金三章=定调与预期管理
黄金三章 = 验证"实物是否与图片一致",快速回应读者期待。
### 公式
令人不安的处境 + 亟待提升的地位 + 充满希望的外挂 + 能被展望的美好未来
### 定调三层次
1. 情绪氛围
2. 故事走向
3. 价值观倾向
### 两种写法
- 代入感路线:快速代入主角
- 期待感路线:开头创造危机
规则:刻意黄金三章对基调破坏大,不可强求。
### 留住读者的核心:不间断的期待
- 主角即将得到但还没得到 -> 期待感最高 -> 追读最多
- 得到之后追读立刻下降 -> 解法:得到之前套上另一个钩子 -> 循环
- 一本书随时保持两条以上期待线
---
## 质量检查清单
写完每段/每章后,逐项检查:
- [ ] **段落控制**:按动作/信息变化断段,读起来不卡
- [ ] **高危词扫描**:少用"仿佛/犹如/一丝/不禁/眼中闪过/嘴角勾起"等模板化表达
- [ ] **高危句式扫描**:公式化对话标签/"他感到"/"带着一丝XX"等不要过量
- [ ] **情绪展示**:关键情绪节点没有直接写"他愤怒/伤心/紧张",用动作/神态替代;低强度过场情绪允许一笔直写,不必处处外化
- [ ] **对话有效性**:每句对话至少推进剧情/塑造人物/制造张力之一
- [ ] **五感调动**:每个场景至少调动2种以上感官
- [ ] **环境交互**:环境描写有角色交互,不是空镜头
- [ ] **镜头感**:每段有明确拍摄对象,远景/中景/近景/特写交替
- [ ] **水分检查**:删掉任意一段后读者是否困惑——不困惑则该段多余
- [ ] **视角一致**:没有全知叙述/上帝视角/心理分析混入
- [ ] **节奏交替**:叙述默认是逗号长句(句长标准见 anti-ai-writing.md 规则 3),短句只作偶尔的孤立重拍、用完回到逗号长句;忌通篇同长度,也忌机械长短交替;快慢场景交替
- [ ] **代入感**:主角目标清晰、行为可理解、叙事立场站在主角一侧
references/style-genre-modules.md›
# 题材风格模块
> 各题材的核心原则、关键技法与写作要点。用于确定题材方向后查阅对应模块。
---
## 决策路由
| 你在做什么 | 查阅哪个模块 |
|-----------|-------------|
| 写幽默/搞笑/沙雕 | 幽默 / 搞笑文 / 沙雕风 |
| 写悬疑/推理/恐怖 | 悬疑 / 推理 / 恐怖 |
| 写言情/救赎 | 言情 / 救赎文冲突设计法 |
| 写玄幻/修仙/奇幻 | 奇幻/玄幻 + 升级流/爽文 |
| 写现实/世情/新媒体 | 现实/世情 |
| 写轻小说/二次元 | 轻小说/二次元风 |
| 写赛博朋克 | 赛博朋克风 |
| 写盘点/模拟/直播 | 盘点文/信息差文 / 模拟文 / 直播流 |
| 选题材/定赛道 | 市场定位与选材策略 -> 吸量与赛道 -> 跟风与创新 |
| 设计开篇 | 创作思路与开篇设计 -> 低位身份开篇的流畅写法 -> 开头五要诀 |
| 判断题材边界 | 边界感与氛围感 -> 各网站风格差异 |
| 按题材分类生成正文提示卡 | `genre-prose-cards.md` 索引 + `genre-prose-cards/{题材}.md` 单卡 |
| 设计战斗/打斗 | 转到 style-combat-face.md |
## 指令语气
本文件以"题材操作手册"语气书写。每个题材模块给出该题材的**核心规则和操作要点**,是写对应题材时**必须遵守**的约束。遇到跨题材缝合时:主题材规则 > 辅题材规则 > 通用建议。
## 正文提示卡组合模式
正文写作采用「通用正文要求 + 题材正文提示卡 + 本书文风」三件套,不再为每个题材复制一整套正文 prompt。
- **通用正文要求**由 `story-long-write` Phase 4 负责:严格消费细纲,按情节点义务写,缓慢推进,不提前写后续剧情,完成确定性字数/钩子/禁用词/退化校验。
- **题材正文提示卡**只管题材层的稳定核心:世界观或生活逻辑、读者期待、核心爽点/情绪、节奏密度、场景颗粒、禁止漂移。项目优先从 `genre-prose-cards.md` 索引匹配,再读取 `genre-prose-cards/{题材}.md` 单卡,本文件只作通用流派补充。
- **本书文风**来自 `设定/文风.md` 或对标 `文风.md`:只管句长、标点、潜台词、锚点片段和笔调,不覆盖题材核心与章节意图。
- 三者冲突时:章节细纲与连续性 > 题材正文提示卡 > 本书文风 > 通用技巧建议。
### 题材正文提示卡模板
项目可在 Phase 2 生成 `设定/题材正文提示卡.md`。没有该文件时,Phase 4 写前先用 `设定/题材定位.md` 匹配 `genre-prose-cards.md` 索引并读取 `genre-prose-cards/{题材}.md` 单卡;仍无匹配再从本文件即时抽取一张轻量卡。卡片保持短,给 `narrative-writer` 传摘要,不把参考文件整段复制进 prompt。
```markdown
## 题材正文提示卡
- 主题材 / 平台:{如 番茄男频·都市高武}
- 题材边界:{这本书读起来必须是什么味,不能串到什么味}
- 核心逻辑:{世界观/社会关系/生活压力/能力规则如何驱动冲突}
- 读者期待:{读者进来等什么:打脸、升级、情感债、信息差、悬疑逼近等}
- 核心爽点 / 情绪:{本题材最稳定的 1-3 个释放方式}
- 节奏密度:{铺垫、爆发、冷却的比例;低压章允许的功能}
- 场景颗粒:{该题材需要哪些具体载体:账单/门店/宗门规矩/弹幕/案件线索等}
- 对话与人物声线:{该题材下台词承担什么功能,哪些角色不能说成同一种腔}
- 禁止漂移:{不能变成说明文、纯设定、纯科普、纯撒糖、纯战报等}
- 本章取舍:{仅本章使用的 2-4 条;从上面抽取,不全量执行}
```
### 番茄优先校准
番茄是长篇正文的重点平台时,卡片强调「入口钩子清楚、情绪兑现快、功能位复用、过渡少」。但不要把伪指标写成硬门禁:
- 不强制每行 50-60 字;优质样本的段落长度随场景变化,固定行长会显假。
- 不强制对话占比 50%-60%;对话只在冲突、关系、信息揭示需要时增加。
- 不全局替换「地/得/很/像/顿号」;先判断是否真的油、虚、模板化。
- 不随机倒装;需要打破平滑时,优先换视点入口、物件入口、声音入口或动作结果入口。
- 不为自然感补“办事流程”;任务卡点必须卡出信息、关系、代价、选择或伏笔变化。
### 生成 / 读取规则
1. 先从 `设定/题材定位.md` 读取主题材、目标平台、主对标书、核心梗。
2. 项目先在 `genre-prose-cards.md` 精确匹配分类,再读取 `genre-prose-cards/{题材}.md` 单卡(如 都市脑洞 / 豪门总裁 / 年代 / 双男主);低置信卡必须标注低置信并用同题材对标书校准。
3. 无分类命中时,再在本文件中找到最接近的通用题材模块;跨题材时只取主题材 3-5 条,辅题材 1-2 条。
4. 把抽取结果写成 `genre_prose_card`,每章只携带与本章情绪/事件相关的条目。
5. 题材卡不得改剧情顺序、不得替换角色人设、不得覆盖 `剧情/情绪模块.md` / `剧情/节奏.md` 的权威召回。
---
## 幽默
### 核心原则
幽默是压力释放器,不是笑话delivery。最好的幽默来自角色试图维持尊严/权威/冷静,但现实不配合。
### 幽默来源
- 角色的尴尬(想装酷但翻车)
- 冷面反差(正经人遇到荒诞事)
- 关系调侃(熟人之间的损)
- 黑色幽默(绝境中的一句毒舌)
- 观察式幽默(对日常场景的精准吐槽)
### 操作规则
- 幽默来自角色的欲望/偏见/固执/误判,不是脱离剧情的段子
- 包袱改变地位、暴露关系、制造未来代价
- 铺垫要短,回报要清晰,余波比包袱本身更重要
- 回调必须升级(更尴尬/更公开/更严重)
### 混搭规则
- 幽默+言情:暴露吸引力/固执
- 幽默+悬疑:来自虚假自信
- 幽默+文学:服务尊严与社会质感
---
## 悬疑
### 核心原则
悬疑的关键在于:让读者感到一个问题/危险/代价正在逼近,而答案始终够不着;不要只靠藏信息。
### 核心规则
- 每章一个主要未解问题
- 延迟揭示需要故事内的理由(时机、视角限制、代价、可能的错误)
- 悬疑靠"问题变得更昂贵"工作,不是"信息变得更稀少"
- 场景必须清晰(晦涩不是悬疑)
### 章节操作
1. 定义未知
2. 定义搞错的代价
3. 安排读者/角色/对手的信息不对称
4. 后半段收窄选择或提升赌注
5. 从已有线索生长钩子,不插入突如其来的惊吓
### 混搭规则
- 悬疑+推理:接下来怎么办 vs 到底发生了什么
- 悬疑+恐怖:逼近 vs 扭曲
- 悬疑+言情:关系暴露、错过时机、情感代价作为悬疑源
---
## 言情
### 核心原则
言情靠欲望、恐惧、骄傲、关心、误判和情感债不断摩擦,不靠"终于在一起了"。
### 核心规则
- 化学反应来自具体的人物差异,不是空洞赞美
- 最好的张力 = 想靠近 + 害怕失去/暴露/负债
- 每场重头关系戏改变信任/希望/占有欲/脆弱/边界/误解的深度
- 延迟可以,但必须带来新的压力/债务/理解/代价
- 最动人的亲密藏在小事、关心、误判和没说出口的话里
### 章节操作
1. 定义各自主角想要什么、怕什么
2. 决定本章拉近、推远,还是拖入更危险的纠缠
3. 让一个实际行动承载情感含义
4. 如果是误解,扎根于角色的认知/处境/伤疤,不是低级的"不说开"
5. 结尾要有新的情感债/风险/期待
---
## 推理
### 核心原则
推理的核心是"读者觉得自己也能破案",所以线索必须公平呈现。
### 关键技法
- 线索要混在自然叙事中(不能专门停下来列线索)
- 每条真线索旁放1-2条误导线索
- 揭示顺序比真相本身更重要(先猜对动机,再猜对人)
- 嫌疑人每人一个关键秘密,只有一个跟案子有关
---
## 恐怖
### 核心原则
恐怖靠"有限视角"工作——角色不知道的东西,比展示的怪物更可怕。
### 关键技法
- 恐惧要升级(不能一直同一个强度)
- 限制信息来源(断电、断信号、独自一人)
- 用生理反应代替直接描写恐惧
- 安全感的短暂回归让下一波恐怖更猛
---
## 奇幻/玄幻
### 核心原则
世界观的力量在于规则和代价,不在于"什么都能做"。
### 关键技法
- 力量体系必须有明确边界和代价
- 世界观展开跟剧情推进绑定(不搞说明文)
- 日常细节比宏大设定更让世界"活"(集市上的货币、旅店的价格)
- 每5章必须有一次世界观层面的新信息
### 金手指设计要点
- 金手指决定爽点上限:越强能解决的矛盾越大
- 避免只能靠一次性秘宝——越写越崩
- 金手指碎片化处理:把复杂能力拆分细分,碎片化融入剧情
- 没收集完成之间就是远期期待,收集到每一片就意味着能解决至少一个冲突
- 设定服务剧情,不要被设定反向限制;主角必须是规则中的特殊变量
---
## 现实/世情
### 核心原则
现实题材的力量在于"读者认识这些人",共鸣来自精准的日常观察。
### 关键技法
- 对话必须口语化(不能有书面腔)
- 场景要具体到店名、品牌、地段(越具体越真实)
- 矛盾来自真实的社会压力(钱、面子、关系、阶层)
- 细节用五感(油烟味、麻将声、电动车充电的嗡嗡声)
### 价值观与商业原则
- 网文是商业写作,判断文字好坏以目标读者反馈和写作目标为准
- 表达朴素价值观:杀人偿命、欠债还钱、睚眦必报、有恩必报、善恶有报
- 高端表达观点 = 讲故事让读者自己得出结论
- 观点要鲜明,立场要犀利:坏人做了坏事必须受惩罚
- 不要为了展示"人性复杂"而恶心读者
---
## 升级流/爽文
### 核心原则
爽文的本质是"读者知道结局的未知过程"。核心期待是变强、变富、被认可。
### 关键技法
- 升级-收获-装逼三循环是通用核心循环
- 升级带来收获(对比),收获带来装逼(震惊),装逼推动新的升级
- 收获要分层释放,额外的、不确定的收获比固定收获更有惊喜感
- 爽点核心就四个字:主角牛逼——解决问题的方式决定爽感
- 风轻云淡一指灭杀 >> 歇斯底里艰难取胜
- 该爽的时候不爽到位,观感上比毒点还毒
### 核心梗提炼
- 搞清楚核心梗才能确定赛道和受众,盲目模仿跟风全扑
- 核心梗决定金手指资源获取方式(杀杀杀 vs 经营关系网+种田)
- 核心梗影响全书基调(轻松日常 vs 严肃热血)
### 人设一致性原则
- 权力来源决定行为逻辑:
| 权力类型 | 来源 | 行为特征 |
|----------|------|----------|
| 个人实力型 | 仙侠型,实力即王道 | 技能法宝归自己 |
| 服从型 | 领主型,权力来自下位者服从 | 利益不一致就叫不动人 |
- 智者人设不能崩:有脑子的角色必须遵守节能原则(最小代价换最大收益)
- 反派集结军队硬刚时,要考虑军队是否服从、利益是否一致
- 人设崩塌 = 角色做出与权力结构/性格不符的行为只为推动剧情
### 战力/量级设计原则
- 量级上限取决于题材边界和可控性,保证不写崩
- 单体宇宙级之下基本够用,不需要多元宇宙花活
- 规则类能力尽量回避,太容易失控
- 量级需匹配题材的边界感
---
## 搞笑文
- 搞笑不等于神经病,逻辑是根基——搞笑情节必须在符合逻辑推理的情况下搞笑(规则之内的办法,但不在预料之内)
- 无逻辑的神经病主角前期好玩,后期读者对不上脑电波就觉得尬
- 玩梗法则:硬玩梗不如不玩梗——梗有生命周期,热度过了只剩尴尬
- 正确做法:提炼梗的内在搞笑逻辑,化用到小说情境中
---
## 轻小说/二次元风
- 核心定义:以卖戏剧性人设为主的小说,尤其以卖各种美少女人设为核心
- 人设即卖点:每个角色都有鲜明的"标签化"特质,读者一眼记住
- 日常感重于剧情推进:角色互动和日常碎片是主要内容
- 吐槽/内心戏密集:主角作为"吐槽役",对荒诞事物的反应本身就是爽点
- 人设差异要极端化:傲娇/病娇/三无/天然呆,标签越鲜明越好
- 卖人设 > 卖剧情:剧情服务于展示角色魅力
- 对话量 > 描写量:角色互动靠对话推进,减少大段心理独白
---
## 沙雕风
- 沙雕风 = 用荒诞、反常规的叙事制造笑点
- 角色行为出人意料但逻辑自洽(有脑子的荒诞,避免乱来)
- 严肃场景被角色的沙雕行为化解,反差制造笑点
- 宗门日常 > 战斗升级:沙雕宗门风中,升级只是不起眼的元素
- 群像感强:一群人互相衬托,笑点不靠单人硬撑
- 沙雕不等于降智:角色的行为要有自己的逻辑,只是这个逻辑很离谱
- 核心风险:纯沙雕没有情感深度,读者笑完就忘,需要有真情实感的底色
---
## 赛博朋克风
- 高科技低生活的质感:霓虹、义体、数据流、阶级固化
- 信息密度大:大量世界观细节需要自然融入叙事,不能写说明文
- 冷硬基调:疏离感、压抑感、技术异化感贯穿始终
- 世界观细节 > 剧情复杂度:赛博朋克读者来看的是世界观氛围
- 必须在开头几章建立足够的氛围感:雨夜、霓虹、义体改造、虚拟网络
- 避免写披着赛博皮的玄幻:力量体系要服从科技逻辑
---
## 盘点文/信息差文
- 核心机制:通过主角掌握的独有信息向不知情的围观者展示,制造震惊和装逼效果
- 知识类信息差是核心爽点:读者和主角一起"碾压"不知情的世界
- 单元结构:一个盘点对象 = 一个装逼单元,循环推进
- 共鸣优先:盘点方向必须选择读者能产生民族/文化/专业共鸣的内容
- 每个盘点单元需要:铺垫环境的不了解 -> 主角展示 -> 围观者震惊 -> 信息差抹平
- 可以与其他题材缝合:盘点+游戏文、盘点+穿越文、盘点+娱乐圈
- 边界感规则:盘点文的节奏是信息差驱动,不能变成纯科普
---
## 模拟文
- 核心结构:通过"模拟"获得奖励和信息差,再在现实中推进主线、满足期待
- 单元结构:模拟制造情绪缺口 -> 模拟中获得奖励(形成信息差)-> 现实满足期待
- 卷纲结构:模拟得知大危机/大期待 -> 多次【模拟+得奖励+现实推进】的小单元循环 -> 最终达成/解决核心期待
- 模拟中的信息差 = 现实装逼的筹码
- 模拟内容可以展示"如果不干预会怎样"的后果,强化紧迫感
- 奖励分层:小模拟给小奖励(升级资源),大模拟给关键信息(剧情转折)
- 模拟不是全知:保留未知变量,不能让主角通过模拟知道一切
---
## 直播流
- 核心机制:以直播场景为框架,融合搞钱、装逼、对抗、整活多种爽点
| 爽点来源 | 具体表现 |
|----------|----------|
| 搞钱 | 直接收打赏/礼物,金钱数字直观增长 |
| 对抗 | PK、打榜、与同行竞争 |
| 身份马甲 | 观众中有隐藏大佬,弹幕信息差制造惊喜 |
| 整活 | 抽象/搞笑的直播内容吸引围观 |
| 才艺展示 | 主角独特能力的展示窗口 |
- 目标感明确:每场直播有具体目标(圈够X钱/涨X粉),给读者确定预期
- 直播间弹幕 = 即时反馈系统:相当于内置的装逼观众,不需要额外设计
- 可以融合世情:每场直播接待一个客人/处理一件事 = 一个单元世情故事
- 节奏要求:不能一直直播,需要现实线穿插推进
---
## 救赎文冲突设计法
| 冲突类型 | 做法 | 示例 |
|----------|------|------|
| 救赎目标冲突 | 一方想得到的救赎来自另一方的牺牲 | 萧峰与阿朱 |
| 救赎行为冲突 | 救赎建立在谎言/伤害/零和博弈上 | 顶替他人身份 |
| 三角关系 | 一方的救赎行为导致第三方需要被救赎 | 连锁效应 |
| 救赎倒计时 | 必须在某事发生前完成,否则彻底堕入深渊 | 时间压力 |
| 增大救赎代价 | 一方救赎另一方的付出越来越大 | 情感/资源/身心代价递增 |
| 救赎资源稀缺 | 双方都需要救赎,但资源只够一个 | 零和博弈 |
| 立场对立 | 双方有立场分歧,但彼此需要对方的帮助 | 救赎与立场的矛盾 |
| 性格反差 | 乐观vs悲观、冷血vs有同情心 | 阻碍理解和沟通 |
---
## 边界感与氛围感
### 边界感本质
边界感 = 题材/流派特有的信息点集合。用这些信息点塑造氛围,让读者产生"这就是那个味"的感觉。
### 边界感的三个层次
| 层次 | 内容 | 失败表现 |
|------|------|----------|
| 题材边界 | 该题材特有的设定、节奏、情绪基调 | 都市文写出仙侠味、种田文写出争霸味 |
| 风格边界 | 该流派的语言质感、叙事节奏 | 轻小说写出严肃文学腔、世情文写出玄幻腔 |
| 受众边界 | 目标读者群体的期待和雷点 | 用男频节奏写女频、用起点标准写番茄 |
### 基调一致性原则
- 全文基调必须贯穿如一,基调中途改变 = 核心吸引力崩塌
- 基调 = 读者对"这本书在讲什么感觉"的共识
- 检查法:写完每章后问"这章和开篇的基调一致吗?"
### 题材缝合的边界感判断
- 缝合前先明确两个题材各自的核心梗
- 缝合后碰撞出的看点是否超脱了核心梗?超脱 = 脱离边界感 = 危险
- 缝合的正确姿势:保持一个题材为主基调,另一个提供金手指或设定外衣
- 错误姿势:两套节奏交替,读者不知道自己在看什么
### 对标书选择的边界感
- 对标书必须同网站+同题材+同类型,三者缺一不可
- 不同网站的读者群体期待不同,写法不能直接搬
---
## 各网站风格差异
| 网站 | 核心竞争力 | 读者偏好 | 策略 |
|------|-----------|----------|------|
| 起点主站 | 升级流/事业线为主 | 偏长线期待、稳定节奏、世界观深度 | 优先选择边界清楚、已有成熟受众的题材 |
| 番茄小说 | 短平快、强情绪、高密度爽点 | 快节奏、不拖沓、第一章就要有钩子 | 拆解同平台同题材样本的前期结构,复用功能位而非桥段 |
| 刺猬猫 | 整活 > 节奏,人设 > 剧情 | 动漫同人+二游读者,对"好玩"的需求大于"节奏稳定" | 适配同人、轻小说、脑洞、整活向 |
| 下沉市场 | 乐子文为核心 | 颠、搞怪、放飞自我 | 放开了写,风格要对味 |
---
## 市场定位与选材策略
- 优先选择受众广、样本多、边界清楚的类别;具体热度必须由当前 scan/analyze 或用户样本验证。
- 热门类别只代表潜在读者池更大,不代表任何具体梗当前有效。
- 降低竞争压力的做法:保留题材边界,替换切入角度、人物关系或情绪触发方式。
- 不用"传统文就是如此"解释节奏慢、冲突弱或卖点不清。
---
## 题材本质=元素拼接
- 题材的本质:所有题材就是元素的排列组合
- 元素 = 读者感兴趣的东西 + 在网文里流行过的东西
- 元素不等于金手指,也不等于频道分类
- 签到流的元素:【苟+高强度收获+强期待感】
- 两个元素割裂的题材(仙侠+科技)难度极高,要先自圆其说+制造趣味
- 赛道选择规则:优先选择竞争分散、近期样本有效的新兴赛道;避免进入强品牌集中且功能位难复用的成熟赛道。
- 研究中层样本而非只分析顶流——前者结构更可复用。
- 商业化 = 尊重目标读者,私人表达不能凌驾于核心卖点和阅读体验上。
---
## 吸量与赛道
- 吸量 = 一个题材的上限/天花板,有时就是题材不行不是写得不好
- 赛道 = 题材跑道,不同赛道的读者池和期待不同。
- 赛道选择的三个维度:吸量(天花板)+ 竞争度(对手数量)+ 素材/能力匹配度。
- 选择赛道前先看天花板;读者池太小的赛道要降低篇幅和商业预期。
---
## 跟风与创新
- 网文写作的核心 = 会不会讲故事,不是文采好/创意标新立异/知识面广
- 跟风 = 复用已验证功能位,是降低风险的方式之一
- 同质化本质 = 跟风过程中对目标没有深加工,只是一味仿照
- 跟风没问题,问题是连行动和语气都相似——退婚流可以各种组合
- 标新立异的设定不等于创新——主流之所以是主流因为大部分人接受认同
- 创新的核心:提炼梗的内在搞笑逻辑,化用到新情境中
---
## 题材的元素拼接与流派思维
- 把一个流派的要素提炼出来 + 另一个流派的要素提炼出来 -> 合成一本新书
- 点子只有在“素材、人物、冲突、篇幅”都能支撑时才可用。
- 反套路 = 推翻旧有模式的写法,让读者产生新鲜感。
- 常见问题:正文没有把关键信息显性化,读者无法理解卖点。
- 小说需要被目标读者识别到核心卖点,否则商业价值无法兑现。
---
## 市场认知与创作要点
- 开书节奏规则:前期聚焦核心卖点/金手指的快速展开,避免在设定和伏笔上过度投入导致正文节奏缓慢
- 一旦追求完美 -> 沉迷写设定写剧情挖伏笔 -> 正文节奏缓慢
- 信息差风险:写前准备想的是后续精彩展开,正文呈现出来却是男主拖沓和女主坑队友
- 新媒体入口依赖噱头和第一眼吸引力;开篇必须立刻兑现入口承诺
- 不要东一榔头西一棒子,每段剧情都要紧密推动核心矛盾
---
## 创作思路与开篇设计
- 创作思路三步法:确定主角身份 -> 匹配金手指类型 -> 设定开局环境 -> 设立意象(标签)
- 意象 = 给人物和剧情贴标签提升深度
- 开篇不需要写冲突,可以写环境,关键是流畅,把所有信息带出来
- 不要通过旁白介绍背景,多通过对话把信息掺杂在里面
- 主角身份 -> 面临的困境 -> 想办法解决 -> 能力不够 -> 金手指来了
- 不要一次性灌太多信息
- 关于节奏的误区:书让读者没兴趣,哪怕第一章成神王大帝都没用
---
## 低位身份开篇的流畅写法
- 低位开局核心 = 流畅,不需要反转和拉扯
- 把所有信息带出来同时做到流畅——读者的思绪跟着内容往下顺
- 不要一次性把所有压力灌给主角,压力一点点给
- 多通过对话传递信息,少用旁白介绍背景
- 给出金手指后要有即时变化——让读者看到变化的过程
- 金手指要在主角积极应对危机但能力不足时才来——这样主角不是废物
- 什么身份做什么事:马奴不配有道德,步子太大 = 结构破坏
- 写大剧情时检查:主角目前的等级、身份和资源是否够格?
---
## 开头五要诀
- **简单点**:简明扼要交代五要素(谁/在哪里/有什么/为什么/要做什么),第一章就点明
- **不能偏**:开头剧情必须符合主线,跑偏 = 零分开头
- **要快**:切入剧情速度要快,磨磨蹭蹭交代背景 = 啰嗦
- **要爽**:开头第一个小剧情必须有爽点,五章之内没有震惊 = 失败,不能有毒点/雷点/劝退点
- **不能平**:文似看山不喜平,没有冲突矛盾平淡如水 = 失败
**常见开头问题**:
- 上来楔子 -> ABCD世外高人对话 -> 打哑谜 -> 读者满脸懵
- 云里雾里不知所云 -> 读者看不懂直接走人
- 罗里吧嗦"铺垫" -> 实际全是废话 -> 节奏太慢
---
## 质量检查清单
写完某个题材的章节/卷后,逐项检查:
- [ ] **题材边界感**:这章读起来是目标题材的味道,没有串味
- [ ] **基调一致**:与开篇基调一致,没有中途变调
- [ ] **题材核心技法执行**:对应题材模块的"核心规则"全部遵守
- [ ] **人设符合标签**:角色行为基于标签,没有人设崩塌
- [ ] **对话口语化**:无书面腔(现实/世情/升级流强制要求)
- [ ] **五感细节**:场景有具体感官细节,不是抽象概括
- [ ] **开篇五要诀**(如检查开篇):简单/不偏/快/爽/不平
- [ ] **缝合边界感**(如跨题材):主题材为主基调,辅题材提供外衣
- [ ] **对标书一致**:对标书同网站+同题材+同类型
- [ ] **市场匹配**:目标赛道读者池足够,题材与现有素材/能力长板吻合
references/tracking-transaction.md›
# 追踪状态协议
`追踪/` 使用“一个结构化权威状态 + 多个确定性派生视图”。模型只提交一份语义 JSON,不分别 `Write/Edit/echo >>` 多个追踪文件。
## 权威层与派生层
| 层级 | 文件 | 语义 |
|---|---|---|
| 唯一权威 | `_tracking-state.json` | schema、最后提交章、导入截止章、状态修订号、上下文结构、角色/伏笔/时间线,以及已提交章节的简短字数记录 |
| 章节记录 | `逐章记录/第NNN章.md` | 本章对未来连续性有用的紧凑变化;目标 ≤1536 字节,硬上限 3072 字节;导入范围内修订写成覆盖记录 |
| 派生视图 | `上下文.md`、`角色状态/{角色名}.md`、`伏笔.md`、`时间线/作者真相.md`、`时间线/读者已知.md` | 完全从 `_tracking-state.json` 生成;禁止手改,不作为程序输入 |
Markdown 只负责给作者和 Agent 阅读,工具不再反向解析 Markdown。`check` 直接从 `_tracking-state.json` 重渲染并逐文件比较。未来“第几章揭示”的计划写在卷纲/细纲,不写成时间线既成事实。
逐章记录只是便于人阅读的紧凑变化记录,不承诺单独无损重建全部当前状态;完整当前语义以 `_tracking-state.json` 为准。
## 运行工具
先按运行环境探测 Python 3 解释器(依次尝试 `python3`、`python`、`py -3`)。追踪事务脚本使用当前 skill 根目录;字数与章节闭环统一使用 `story-long-write` skill 根目录:
```text
{PYTHON} {当前 skill 根}/scripts/tracking_commit.py init --project {书项目根} --input {初始化事务.json}
{PYTHON} {当前 skill 根}/scripts/tracking_commit.py check --project {书项目根}
{PYTHON} {story-long-write skill 根}/scripts/storyctl.py wordcount checkpoint --file {前半段临时文件} --target {目标} --chapter {N}
{PYTHON} {story-long-write skill 根}/scripts/storyctl.py chapter check --project {书项目根} --chapter {N}
{PYTHON} {story-long-write skill 根}/scripts/storyctl.py chapter commit --project {书项目根} --chapter {N} --input {逐章事务.json}
{PYTHON} {story-long-write skill 根}/scripts/storyctl.py chapter accept-current-length --project {书项目根} --chapter {N} --input {逐章事务.json}
```
- `init`:只在 `_tracking-state.json` 不存在时执行,绝不覆盖已初始化项目。
- `wordcount checkpoint`:纯测量;返回当前实际字数、用户带与剩余用户区间,不写正文、不写 tracking、不做语义判断。每章最多调用一次。
- `chapter check`:重新读取当前正文与细纲目标,返回确定性长度状态、现有 blocking quality、`state_revision` 和当前可执行动作,不保存 approval。`under` 不提供自动补写;`over` 额外返回一次净删型 `compress-once` 及进入内带/用户带所需的机器删除区间。
- `chapter commit`:再次读取当前文件、重新计数并重跑 blocking quality;只接受用户带内章节,把简短字数记录与逐章事务一起原子提交。
- `chapter accept-current-length`:只接受带外但 quality pass 的章节;接受动作发生时重新读取、重新计数并立即原子提交,不保存可陈旧的历史决议。
- `check`:严格验证 state schema、逐章记录连续性/规范名/体积、固定 7 栏、角色快照硬上限、派生文件集合,以及所有派生视图与 state 的逐字一致性。
每本书由 `追踪/.tracking-commit.lock` 串行写事务,`expected_state_revision` 再拒绝基于旧状态构造的 stale transaction。两个不同事务并发时至多一个修订成功。字数记录也在锁内对当前正文和目标重新验证,正文或目标变化会让预先构造的记录直接失败。
事务 JSON 是临时输入,不是项目产物:成功前必须保留;提交成功且紧随其后的 `check` 通过后立即删除,不能把 `init_transaction.json`、`chapter_*_transaction.json` 等输入长期留在书项目根目录。若文件写入失败,`_tracking-state.json` 尚未推进;修正环境后直接重跑**同一份** `commit`。append 重跑只接受内容完全相同的既有逐章记录,不维护 `dirty/pending/repair` 状态机。
校验失败与写入失败处理方式不同:校验失败(字段非法、退役结构、容量超限)要按报错改事务本身,重跑同一份结果不变。派生视图被手改或外部改动导致 `check` 报 `derived view differs from _tracking-state.json` 时,重新提交**该章**的 `mode=revision` 事务让工具整份重建,`expected_state_revision` 取 `追踪/_tracking-state.json` 的 `state_revision` 字段——`check` 失败时只往 stderr 打 ERROR,不输出 JSON;不手改派生文件,也不删 `_tracking-state.json` 重来。手写出的逐章记录会让同章 `append` 永久报 `chapter delta N already exists with different content`——删掉那个手写文件后重跑原事务即可。
本工具不解析旧 `_tracking-meta.json`、`时间线/事件库.json` 或更早追踪结构,不提供语义兼容层。`init` 遇到这类旧文件时,先把它们按原样整体移入 `追踪/_旧追踪存档/`,再在原地建当前协议:旧内容留给作者查阅,不参与解析,当前状态完全以 init 输入为准。校验失败的 `init` 不移动任何文件。`commit` 与 `check` 仍直接拒绝旧结构——它们只在已建协议的项目上运行。
## 初始化事务
新书从第 0 章初始化。`story-import` 导入已有小说时把最后完整章写入 `last_chapter=N`;第 1..N 章不伪造日更记录,常规续写从 N+1 章开始。
```json
{
"schema_version": 1,
"book_title": "让你管账号,你高燃混剪炸全网",
"last_chapter": 0,
"context": {
"position": {
"volume": "第一卷·军宣整顿",
"volume_start_chapter": 1,
"story_time": "江晨到火箭军文工团报到前",
"scene": "火箭军文工团"
},
"long_term_constraints": ["军宣爽点要用作品效果和围观反应链兑现,不能只靠系统播报"],
"active_character_names": [],
"continuity_risks": [],
"recent_chapters": [],
"next_chapter_commitments": ["让江晨报到,并落下五天百万粉的新手任务"]
},
"character_snapshots": {},
"foreshadow": [],
"timeline_events": []
}
```
导入初始化时直接传入当前核心角色快照、伏笔当前行、时间线事件和固定 7 栏状态输入。阶段/卷级回看按需查询正文,不作为每章强一致追踪产物。
调用方的逐章 JSON 不写 `wordcount`;正式入口 `chapter commit` 或 `chapter accept-current-length` 在提交当下生成并注入。最终 state 只为已提交章节保留 `metric / target / actual / status / resolution / body_sha256`,不保存 MEASURE/RESOLVE 事件、ID 链、policy fingerprint 或独立 chapter state。
## 逐章事务
```json
{
"schema_version": 1,
"mode": "append",
"chapter": 10,
"chapter_title": "专业团队拍得还不如他拍的好?",
"expected_state_revision": 9,
"delta": {
"result": "专业团队重拍的高清版在高层看片会上被判定缺了灵魂,张耀祖拍板继续采用江晨的手机原版。",
"character_changes": [
{"name": "江晨", "change": "作品价值获军内高层确认,从爆款新人升为不可替代的军宣创作者"}
],
"foreshadow_changes": [
{
"action": "upsert",
"id": "F027",
"summary": "专业团队仍拍不出江晨原版的灵魂,继续验证其创作能力不可复制",
"planted_chapter": 10,
"planned_resolution_chapter": null,
"status": "已埋",
"importance": "中"
}
],
"timeline_events": [
{
"action": "upsert",
"id": "E010",
"story_time": "实弹训练两天后",
"objective_fact": "文工团高层否决专业重拍版,决定沿用江晨手机拍摄的原版视频",
"reader_knowledge": "读者已看到周薄森指出专业版缺了灵魂,张耀祖当场拍板用回原版",
"reveal_status": "已揭示",
"reveal_chapter": 10,
"characters": ["江晨", "周薄森", "张耀祖"]
}
],
"constraints": ["后续继续用作品落地效果和围观反应放大江晨的高光,不能只写系统奖励数字"],
"next_chapter_commitments": ["结算五天百万粉任务,并承接老兵主题的新任务"]
},
"context": {
"position": {
"volume": "第一卷·军宣整顿",
"volume_start_chapter": 1,
"story_time": "实弹训练两天后",
"scene": "火箭军文工团高层看片会"
},
"long_term_constraints": ["军宣爽点要用作品效果和围观反应链兑现,不能只靠系统播报"],
"active_character_names": ["江晨"],
"continuity_risks": ["钟嘉嘉说江晨只猜对一半,未公开的培养安排不能被当成读者已知事实"]
},
"character_snapshots": {
"江晨": {
"identity": "火箭军文工团宣传兵;军宣爆款创作者",
"location": "火箭军文工团高层看片会",
"goal": "完成五天百万粉任务,持续做出真正能打的军宣内容",
"state": "专业团队反向验证原版价值,军内认可继续抬升",
"abilities_resources": ["前世MCN爆款运营经验", "《中国军魂》伴奏", "大师级导演能力"],
"relationships": ["钟嘉嘉持续提供军报资源", "周薄森和张耀祖已明确认可其创作能力"],
"knowledge": ["《军报》采访稿已经过审", "原版视频将继续作为正式军宣内容"],
"open_threads": ["五天百万粉任务尚未结算", "钟嘉嘉所谓只猜对一半仍未解释"]
}
}
}
```
约束:
- 构造事务前运行 `check`,把当前 `state_revision` 原样写入 `expected_state_revision`;若状态已经变化,重新读取 state 并重构事务。
- `context` 的允许字段随子命令不同:`init` 收 `position`、`long_term_constraints`、`active_character_names`、`continuity_risks`、`recent_chapters`、`next_chapter_commitments` 六项;`commit` 只收前四项。`recent_chapters` 与 `next_chapter_commitments` 在 commit 时由工具从当前视图和本章 `delta` 派生,手填会在任何写入前被拒(`context contains unsupported fields: ...`,exit 2)。照 init 示例套 commit 事务是最容易踩的一处。
- `character_snapshots` 中出现的角色视为核心复用角色,必须同时出现在 `character_changes`;已经建立快照的核心角色再次变化时必须提交新快照。
- 角色快照的四个列表不限制条数,只限制单项长度和最终文件总字节:目标 ≤4096 字节,超过警告;硬上限 8192 字节,超过则在任何写入前拒绝。
- 没有快照的角色变化视为临时角色,不建立状态文件;`context.active_character_names` 最多 6 人且必须已有当前快照。
- `context.long_term_constraints` 和 `context.continuity_risks` 是整份提交的当前值。凡是上一版有、本次没有的条目,必须逐条列进 `delta.retired_context_items`,否则工具在任何写入前拒绝——漏写不会被当成删除。实际退役的条目由工具写进本章逐章记录的 `## 本章退役登记`,随后仍可回查。
- 不再复用的核心角色写进 `delta.retired_characters`:工具删除其当前快照与 `角色状态/{角色名}.md`,并在逐章记录留档。同一事务里不能既退役又提交快照,也不能退役仍列在 `context.active_character_names` 的角色。角色阵亡/退场这一章,把变化照写进 `character_changes` 即可,本章退役的角色不必再交一份马上要删的快照,逐章记录仍按核心角色标注。退役只表示不再进入热上下文,正文与逐章记录不受影响。
- 两类退役都只能在 `mode=append` 提交。退役表示「从此刻起离开当前状态」,而修订事务的逐章记录属于被改写的旧章,落在那里会谎报退役发生的章节;`mode=revision` 必须原样重交当前全部上下文条目,需要退役就放到下一次 append。
- `伏笔.md` 只呈现已经埋设过的当前状态。未来规划仍留在大纲。
- `timeline_events.action` 可为 `upsert/delete`。`未揭示` 的 `reveal_chapter` 必须为 `null`;部分/完全揭示只能填写已经发生的实际章节。
- `mode=revision` 时,逐章记录必须重算为修订后该章仍然成立的完整连续性记录;当前角色、伏笔、时间线和上下文则提交受影响对象截至最新已写章的当前值。
- 修订导入截止章内的正文时,会新增或覆盖该章的逐章记录;`imported_through_chapter` 不变。
## 续写状态卡固定格式
`上下文.md` ≤12288 字节,由 state 整份生成,只含以下 7 个顶层区块:
1. `## 当前位置`
2. `## 长期约束`
3. `## 核心角色状态`
4. `## 活跃伏笔`
5. `## 近三章速记`
6. `## 下一章承诺`
7. `## 连贯性风险`
其中活跃角色最多 6 人、活跃伏笔确定性选取最多 8 条、近章只保留 3 章。这些是下一章热上下文容量,不是完整角色状态的容量限制。
references/workflow-chapter.md›
# workflow-chapter.md:单章正文工作流(Phase 4-5)
本文件是「写一章正文」的完整流程。SKILL.md 路由到 Phase 4 后按本文件执行;日更批量由 `workflow-daily.md` 控制批次与追踪事务,每章正文仍走本文件。
项目文件结构、产物映射表、缺失文件处理、对标分析权威优先级在 `SKILL.md` Phase 4 开头,本文件不重复(SKILL.md 恒在上下文里)。
本文件提到的 agent 都只检查当前端 canonical 目录;Antigravity 使用 `.agents/agents/agent-name/agent.md`(`agent-name` 为目标 agent 名)和 `invoke_subagent` + 同名 `TypeName`,其余端使用各自 Agent 工具。
---
## 单章写作流程
当用户准备写某一章时:
1. **检查细纲**:读取 `大纲/细纲_第{N}章.md`,并从对应 `大纲/卷纲_第X卷.md` 读取当前剧情单元(单元ID/位置、卷契约、本卷主推线/战果、终局底牌边界、风险等级)。如果不存在或缺少当前章节蓝图的必需字段,**必须先补建细纲再写正文**,不允许跳过细纲直接写作。补建时参考卷纲中本章对应的事件规划和上下文,补齐阶段位置、结构公式、禁止提前释放、内容概括、情节安排、人物关系/出场顺序、情节细化、结尾设定;无法从已有证据判断的字段写 `[待补充]`,不杜撰副线或关系。补建后按 `artifact-protocols.md` 跑 `check-outline-contract.js` 结构验收,失败只补点名字段再复验。
2. **读取上下文**(按需选择;缺失时遵循各项及SKILL.md Phase 4 的「缺失文件处理」,仅明确标为可选的非主产物跳过。可选快捷路径:对应 agent 已部署时 spawn story-explorer 一次获取上下文。Prompt:`项目目录:{dir}\n查询类型:context_load\n查询参数:准备写第 {N} 章\n追踪状态:last_committed_chapter={check 的值},state_revision={check 的值}`):
- (1) `正文/第{N-1}章_*.md` — 上一章正文
- (2) `大纲/细纲_第{N}章.md` — 本章细纲(含钩子设计)
- (2a) `大纲/卷纲_第X卷.md` — 当前剧情单元、卷契约与终局储备(主推线/战果、终局底牌边界)
- (3) `tracking_commit.py check` + `追踪/上下文.md` — `check` 无 ERROR 输出即通过,从它的紧凑 JSON 取 `last_committed_chapter` / `state_revision`,不把完整 state 加入 prompt;待回收伏笔取 `## 活跃伏笔`,角色当前状态取 `## 核心角色状态`,下一章硬承诺取 `## 下一章承诺`
- (4) `设定/角色/{相关角色}.md`、`设定/势力/{相关势力}.md`(如存在)— 本章涉及的角色与势力(按细纲出场筛选)
- (5) 对标书路径下 `拆文报告.md`(按对标书路径查找)— 对标参考
- (6) `对标/{对标书名}/原文/第{N}章_*.md`(如存在)— 同位置章节参考
- (7) `参考资料/{topic}.md`(如存在)— 历史研究资料(由 story-researcher 产出)
- (8) 对标书路径下 `剧情/故事线.md`(按对标书路径查找)— 剧情单元索引,用于确定本章涉及哪些剧情单元
- (9) 对标书路径下 `剧情/{相关剧情单元}.md`(按对标书路径查找)— 从索引中选择与本章相关的剧情单元文件
- (10) 对标书路径下 `设定/世界观/*.md`(glob,按对标书路径查找)— 从当前拆文产出的主题化设定中获取参考;目录缺失则记录缺口并跳过本项,不读取扁平历史路径
- (11) 对标书路径下 `剧情/情绪模块.md`(按对标书路径查找)— 读者需求 / 情绪引擎、爽文套路框架、可复现模块;缺失按SKILL.md Phase 4 的「缺失文件处理」设置 `missing_primary_contract` 并停止准备
- (12) 对标书路径下 `剧情/节奏.md`(按对标书路径查找)— 关键信息推进、情绪触动点、爆发节奏;缺失按SKILL.md Phase 4 的「缺失文件处理」设置 `missing_primary_contract` 并停止准备
- (13) `设定/题材正文提示卡.md`(如存在)— 本书正文层题材卡;缺失时从 `设定/题材定位.md` + `references/genre-prose-cards.md` 索引 + `references/genre-prose-cards/` 单题材卡目录(按题材分类优先)+ `references/style-genre-modules.md`(兜底)即时生成 `genre_prose_card`,不阻塞写作
3. **写前准备**(下面的 3 步是核心方法在单章写作中的落地:筛选状态 → 召回模块 → 确认意图):
- **状态筛选**:从 `追踪/上下文.md` 的 `## 核心角色状态` 取当前角色,从 `## 活跃伏笔` 取需回收/推进项,从 `## 下一章承诺` 取本章必须履行项,输出本节速记(参考 state-tracking.md)。久别角色按名读取 `追踪/角色状态/{名}.md`;只有追查变化原因时才定点查逐章增量。续写状态卡或 meta 不存在时按 workflow-daily 的当前协议处理,不手写替代文件
- **模块召回、题材卡与文风召回**:
- ① 本章目标情绪词?② 借鉴哪个参考文件的哪个技法?③ 用在哪些段落?答不出 → 先回读参考再动笔
- (a) **情绪模块召回**:按「对标书路径查找」规则读 `{对标书路径}/剧情/情绪模块.md`,选出 1 个与本章目标情绪最贴近的 `selected_emotion_module`(读者需求、触发器、戏剧单元、可替换要素、反抄袭提醒)。缺失时设置 `missing_primary_contract: true`,返回明确 `repair_action` 后停止准备
- (b) **节奏召回**:读 `{对标书路径}/剧情/节奏.md`,选出 1 条 `rhythm_reference`(关键信息 → 扩写技法 → 情绪触动点 → 爆发/冷却)。缺失时设置 `missing_primary_contract: true`,返回明确 `repair_action` 后停止准备
- (c) **题材正文提示卡召回**:优先读 `设定/题材正文提示卡.md`;缺失则先读 `设定/题材定位.md` + `references/genre-prose-cards.md` 索引,按主题材精确匹配后只读取 `references/genre-prose-cards/` 中对应单题材卡(如 都市脑洞 / 豪门总裁 / 年代 / 双男主;低置信卡必须在意图确认标注低置信,并要求同题材对标校准),无命中再读 `references/style-genre-modules.md` 通用流派模块。跨题材时主题材抽 3-5 条、辅题材抽 1-2 条,生成短 `genre_prose_card`(题材边界、核心逻辑、读者期待、核心爽点/情绪、正文落点、前中后期打法、节奏密度、场景颗粒、禁止漂移、本章取舍、卡片置信度)。题材卡只约束正文层题材味,不改细纲剧情、不覆盖 `selected_emotion_module` / `rhythm_reference` / `设定/文风.md`;只在内部校准取舍,正文里不得出现卡名/标签/置信度/条目/合规自评
- (d) **文风召回**:先直接读 `设定/文风.md`(不经 explorer):含实质内容(去空白 ≥200 字,或含 句长 / 标点 / 对话 / 锚点 / 笔调 小节且小节内有可执行约束:比例 / 例句 / 禁止或偏好描述)则置 `custom_style=true`、进入「自定义文风模式」,它作权威风格基(句长 / 软标点 / 潜台词 / 情绪交替),对标 / 拆文 `文风.md` 降为参考(锚点 + 句长兜底);空 / 仅空白 / 仅标题 / 占位 stub(待办 / 待补充 / ___)视为不存在。否则按「对标书路径查找」规则读 `{对标书路径}/文风.md`(路径优先 `{项目}/对标/{书名}/`,回退 `拆文库/{书名}/`);多本对标书时从 `设定/题材定位.md` 读 `主对标书` 字段。**未进入自定义文风模式且**文风文件不存在 → **fail-fast 报错**:「对标书 X 缺少 文风.md。请用 `/story-long-analyze` 跑 Stage 6 生成文风,再 `/story-import` 同步。」不 inline 生成(自定义文风模式则不 fail-fast;情绪 / 节奏轴 `missing_primary_contract` 仍独立阻塞)
- (e) **匹配章节挑选**:从 `{对标书路径}/章节/*_摘要.md` grep `基调:(紧张|轻松|悲伤|热血|爽|甜|温馨|恐怖|压抑|其他)`(全角冒号),按本章目标情绪挑章 K——多章同基调时选择规则:先看爽点类型是否接近,再看情节点数量/原文章节估算字数是否接近本章目标字数,最后取章节号最小者;必读 `{对标书路径}/章节/第K章_摘要.md`,若同章存在 `第K章_深度拆解.md` 则加读,否则回退黄金三章深度拆解/文风文件里的可借鉴技巧,不因非黄金三章缺少深度拆解而失败
- (f) **结构化模块召回**:从对标的结构化子目录(角色/剧情/设定)中按本章情节检索相关模块;若与 `剧情/情绪模块.md` / `剧情/节奏.md` 冲突,权威文件优先,记录 `conflict`
- (g) 输出"主对标召回摘要 + 副对标召回摘要 + selected_emotion_module + rhythm_reference + genre_prose_card + 文风召回指令 + 原文锚点片段引用",作为 narrative-writer 的输入。**多对标书时**参 `references/cross-book-recall.md`:主对标提供文风、原文锚点与 selected_emotion_module / rhythm_reference;副对标/参考对标按阶段预算提供结构化摘要,不限制登记书目,不读取副书 `文风.md` / 原文,超过预算时裁条目不裁书目记录。
- **快捷路径**:项目已部署 story-explorer agent 时,可一次性召回文风/模块材料。
- 按本文件顶部规则确认 story-explorer 已部署。
- 查询类型:`benchmark_style_load`;传入项目目录、章节号、目标基调/字数和爽点类型。
- 需要返回:`style_profile_path`、`style_profile_summary`、`selected_emotion_module`、`rhythm_reference`、来源路径、匹配章节、锚点片段、`gaps`。
- `gaps.missing_primary_contract` 为 true 时先按 `repair_action` 修复,不进入正文生成。
- 主会话另行直接读 `设定/文风.md`:含实质内容时作为本书风格基准;但不豁免情绪/节奏缺失。
- **指令确认**:综合细纲、本节速记和模块召回结果,用一句话写清本章意图。
- 新版细纲必须消费:阶段位置、单元ID/位置、主角目标/关键选择、结构公式、禁止提前释放、内容概括、情节安排、人物关系/出场顺序、情节细化、结尾钩子,并对照当前剧情单元的卷契约、本卷主推线/战果、终局底牌边界。
- **细纲优先边界**:正文只能展开本章细纲已有事件、人物、冲突、伏笔和结尾钩子;不得为了凑字或"更精彩"自造新主线、新角色、新反转、提前写后续章剧情,必要的过渡动作只能服务于细纲已列情节点。后续阶段真相、底牌、关系结论和终局矛盾不得因为章尾钩子提前泄露。反过来,细纲是"要发生什么"的契约、不是正文的形状:正文可自由编排叙述顺序、合并/穿插情节点,不必一个情节点一段、也不必按五段式顺写,把每个点演成场景而不是照抄概括语(见 writing-craft.md「从细纲到正文」)。
- **细纲语义去重**:同一要求在核心事件、五段式、情节安排和情节点中重复,只算一个语义点;生成前合并,不把重复次数当强调,不沿用提纲原句逐项复述。比如多处都写“不带摄像机、先听完再决定拍不拍”,正文只通过一个自然动作或一句人物判断兑现,不能拆成「至于拍不拍,怎么拍…」「不带摄像机,不带采访灯」两轮说明。
- 爽点出手前要有可指认的危机/期待铺垫;装逼/打脸/揭露章要写在场配角的差异反应。
- 高压/生死/悲痛节拍 要收紧对话声线:搞笑担当让位,信息型角色不当科普嘴,对话逐句承接对方情绪。
- 检查任务卡点:本章如果有“办事被卡住”,它必须卡出信息、关系、代价、选择或伏笔变化;没有就不强补。
- 契约风险检查:按 `references/reader-contract-and-progression.md` 判定 契约安全 / 需补强 / 契约破坏;若高光/收益被配角、机构或偶然性拿走且没有可见交换,先修纲再写。
- 例:「快节奏打脸——账单暴露→逼问→反证→公开代价;读者等了三章,这章必须一拳到位。」
4. **资料研究**(按需):遇到需查证的外部事实且 story-researcher 已部署时,spawn 搜索并输出到 `参考资料/`;不可用则主线程直接执行。研究完成后再继续写作。
5. **标题预检**:写正文前从细纲读取章名;如与既有章节同名或明显重复,先按本章核心事件改名,并同步细纲标题与正文文件名。
6. **写作与唯一 checkpoint**:将批准情节点按叙事顺序分成连续两组,同一 session 先写前组临时 segment,再且只运行一次 `{PYTHON} {skill 根}/scripts/storyctl.py wordcount checkpoint --file {前组临时文件} --target {字数目标} --chapter {N}`。把 `actual`、`remaining_user_range` 和后组原始情节点交回 writer,并明确:
- 只完成剩余情节点,不得为字数新增独立事件、人物决定、关系变化、揭示或支线。
- 剩余情节点完成即停,即使仍欠长也不加剧情。
两段完成后一次组装最终正文;不做逐点配额、字数 retry、完整重写或落盘后扩写。
- **正文元信息隔离**:`章节:第{N}章`、`上一章:正文/第{N-1}章_*.md`、`匹配第K章`、`细纲文件` 等只用于定位材料。标题行以外的正文不得出现 `第[一二三四五六七八九十百千万两0-9]+章|上一章|上章|前一章|本章|这一章|前文|后文|伏笔|细纲|读者` 这类写作工程词。需要承接前文时,改成角色能感知的事件锚点或相对时间,例如“比第一章那三秒开火更疼”必须写成“比那三秒开火更疼”。例外:角色在故事世界内真实阅读/讨论“第X章”文本,或真实身为作者/读者并谈论读者身份时,可保留相应词。
7. **正文执行**:
- 按本文件顶部规则确认 narrative-writer 已部署。
- 如可用,spawn `Agent(subagent_type: "narrative-writer", prompt: ...)`,prompt 只传本章必需材料:
- 项目目录、章节、细纲文件、上一章、输出路径。
- 写前准备输出:本节速记、情绪目标、涉及角色、参考技法。
- 主对标/拆文路径、主/副对标召回摘要。
- `selected_emotion_module`、`rhythm_reference` 及来源路径。
- `genre_prose_card`(题材正文提示卡摘要,只含本章相关条目)。
- 文风路径、文风召回指令、原文锚点片段。
- `author_preferences`:作者记忆 `query` 结果中匹配本章的 `prose_style` / `story_design` 项;无则不传,禁止把完整画像或待确认项塞进 prompt;作为低优先级倾向自然吸收,不逐条展示或最大化命中,不牺牲连贯、节奏和字数。
- 阶段位置、本章结构公式、本章可释放信息、本章禁止提前释放信息。
- 字数目标、`visible_chars_v1` 口径、格式硬约束;前组后由机器给出一次剩余用户区间,不让 writer 心算或填写逐情节点配额。
- 细纲优先边界(内容层):只展开本章细纲,不自造新剧情;每条情节点都要独立落地,不许漏、不许两条并一句。不得仅为追字数自动补纲、扩写或重写;实际长度统一留到步骤 8 测量。
- 正文形状(形状层):落地位置、顺序、拆成几处由子代理编排,可打散重排、把相邻几条缝进同一个连续动作;不要一条一段平推,不把细纲措辞原样搬进叙述。
- 不把本文件整套规则复制进 prompt;细节以已加载 references 和 narrative-writer 模板为准。
- agent 在同一 session 内按上述流程写两个临时 segment;主会话确认二者只消费批准情节点后,组装并写入 `正文/第XXX章_章名.md` 一次。如 agent 未部署,由主线程执行同一流程。
8. **非对称收口**:运行 `{PYTHON} {skill 根}/scripts/storyctl.py chapter check --project {项目根} --chapter {N}`;文件变更重跑,不存决议。
- 带内 + pass → `chapter commit`;fail / `invalid` → 停止。
- `under` + pass → 展示 `accept-current-length / revise-outline-or-target / discard`,不补/重试;接受命令会重读、重数、原子提交。
- `over` + pass → 删除区间随 `compress-once` 交 narrative-writer;一次净删,零新语义/契约改动。会话核对情节点与钩子后复检;带内提交,否则上述三动作。
9. **检查**:章尾是否有往下看的理由(低压/过场章弱钩子或留阶段目标即可,不强求爽点)、爽点是否到位(按章节定位,高压/推进章必查)。两条可证伪核对(不达标→只修复细纲已批准内容):① 爽点前是否有可指认的危机/期待段落?② 装逼/打脸/揭露章,在场配角是否有差异化反应?质量修复后重跑步骤 8,但不得借质量修复补新剧情追字数。
10. **元信息扫描**:检查标题行以外的正文,命中 `第[一二三四五六七八九十百千万两0-9]+章|上一章|上章|前一章|本章|这一章|前文|后文|伏笔|细纲|读者` 时必须改写为场景内表达;只有角色在故事世界内真实阅读/讨论“第X章”文本,或真实身为作者/读者并谈论读者身份时例外。
11. **禁用词扫描**:先过**最毒句式速查**(实测最易漏,命中即改):①「不是A,(而)是B」全家族——含「没有X,没有Y(,只是Z)」排比否定、「是B,不是A」反序、「他没X,也没有Y。他只是Z」先抑后扬,;②声线反差「声音不大/不高…却…」;③「,带着……」万能状语;④预告/总结收尾「没人知道…」「(这)才刚刚开始/开头」「正朝着…压过去」「即将拉开序幕」「这一刻…」;⑤叙述里短词加引号强调(他是被请来"把关"的)。再复核 detector 的 `formulaic-parallelism` advisory:跨段「不是A。/也不是B。/只是C。」、`至于X不X,怎么X`、同动词 `不V A,不V B` 即使写在台词里也不能跳过,确属人物当场的功能性表达才保留。然后对照 `references/banned-words.md` 全表:一级词(高频AI腔)命中即替换;二级词(低频/语境相关)高频出现时替换,偶发可参考 `references/anti-ai-writing.md` 定性裁定
12. **更新追踪**:最终 `chapter check` 后取最新 `state_revision`,按 workflow-daily 构造不含 `wordcount` 的逐章 JSON。长度在用户带内执行 `storyctl.py chapter commit`;用户接受当前自然长度则执行 `storyctl.py chapter accept-current-length`。两条命令都在提交前重新读取正文和目标、重新计数、重跑 blocking quality,并把简短字数记录与追踪事务一起原子提交。写入失败保留原事务重跑;校验失败重构事务。派生视图损坏按 tracking 文档用 revision 修复,禁止手改。本章首次引入复用角色/势力时,仍按 workflow-setup Phase 3 补建静态档案。
13. **中途快照**(长篇写作安全网):每连续写完 3 章,在继续前执行以下快照操作:
- 执行 `scripts/tracking_commit.py check`,确认 `_tracking-state.json` 有效、逐章记录连续且未超限、所有派生视图一致、续写状态卡恰好 7 栏且 ≤12288 字节;通过后删除本章逐章事务 JSON 与临时 segment,失败时保留事务 JSON 供原样重跑
- 用 `ls -la 正文/` 确认最近 3 个章节文件已成功写入磁盘且大小正常(>100 bytes)
- 如果发现文件缺失或大小异常,立即重新写入
- 快照完成后可继续写作
> **日更模式**:此步骤自动跳过——workflow-daily Step 2 已按章更新上下文.md。
## 写作技巧提醒
| 场景 | 技巧 |
|------|------|
| 开篇 500 字 | 必须有钩子,不能从天气/风景开始(除非反差极大) |
| 对话 | 推进剧情或揭示性格,不能只为了凑字数 |
| 打斗 | 不要流水账,写策略和反转,不写「你一拳我一脚」 |
| 日常 | 日常要有人物互动和伏笔,不能只是「吃饭睡觉」 |
| 任务卡点 | 角色办事被卡住,必须卡出信息/关系/代价/选择/伏笔变化;删掉无损就压缩或删除 |
| 爽点释放 | 铺垫要充分、释放要干脆,读者等得越久释放越要爽 |
| 爽点密度 | 高压/推进章每 3000-5000 字一个「爽」的情绪节点;低压/关系/修炼/信息整理章不强求,但每章仍要有往下看的理由(见 references/outline-structure-theory.md「章节定位与张弛」) |
| 长篇结构约束 | 参考 genre-prose-cards.md 与当前题材卡的长线约束 |
| 章尾 | 每章结尾都要有让读者想翻下一页的东西 |
| 情绪验证 | 写完每章回头检查:读者到这里应该感受到什么?感受到了吗?没感受到 → 按章节定位补:高压/推进章补冲突或钩子,低压/关系章补关系或情绪质感,别一律加爽点 |
## 字数测量权威
字数权威默认是细纲 `字数目标` + `visible_chars_v1`:内带 ±12%,用户带 ±15%;**本轮用户明确给出上下限时,原样范围优先于自动比例带**。无节奏下限,缺目标即 `invalid`。带内提交,`under` 不补,`over` 最多净删一次;仍带外由用户接受、改目标/细纲或放弃。下一章只看 tracking 提交。
---
## 质量检查
检查三个维度:(1) **情绪交付**——每章是否交付了细纲中规划的目标情绪?(2) **契约风险**——按 `references/reader-contract-and-progression.md` 检查因果权 + 结算权、关键节点四问、期待所有权、期待债、终局储备(透支两问)与换书债;章级推进按权威文件的七类状态分档(快节奏保留可见事件/爽点下限),强弱相对本书题材与对标判断,标记 契约安全 / 需补强 / 契约破坏;契约破坏 先修正文或修后续纲。(3) **技术质量**——一致性、格式、禁用词。参考 [references/long-chapter-quality.md](long-chapter-quality.md) 中的通用检查和长篇专项清单。
**新增独立剧情 blocking**:新饭局、承诺、选择、关系变化、支线或后续义务均阻断;闲话、微连接允许。命中不自动修、不重试、不提交,并提示偏纲。
**正文元信息扫描**:按上方步骤 10 清掉标题行以外的写作工程词,再进入其他检查。`check-degeneration.js` 会确定性复扫这一项。
**写后同轮清零**:正文落盘不是汇报时机——每章落盘后必须在**同一轮**内跑完上方步骤 10-11 扫描、下方确定性收尾脚本与 narrative-writer 审查,blocking 清零才算本章完成;不得先汇报"已写完"再等指示。写后 hook 会对落盘正文自动扫描确定性毒句式并把命中推回——那是兜底网不是替代,hook 报出的命中当轮清零。**唯一豁免**:用户显式说"本章不去味/跳过检查"——豁免时在该章标题行下加一行 `<!-- 去味:跳过 -->`(写后 hook 的毒句式推回与写下一章前的欠账拦截都认这个标记;其余网照常)。
**确定性收尾**:本批正文写完后,主会话对实际落盘文件运行 `node scripts/check-ai-patterns.js --check --fail-on=blocking 正文/第XXX章_*.md` 与 `node scripts/check-outline-copy.js 正文/第XXX章_*.md`(细纲照搬复扫)。blocking 命中先回正文改写并复扫;advisory 与细纲重合逐条读原文判断,确属问题才改,功能性写法标 `[需复核]`——每条都要有结论,不为归零机械改写;细纲重合里判定保留的补进细纲「复沓锚句」,下章起不再复报。其中 `formulaic-parallelism` 必须连同对话一起复核,不能因为 hook 不阻断台词就略过;`stock-reaction-tic` 必须按 `writing-craft.md`「反套话四问」逐处做删除测试,交付摘要写明候选数、删除数及每个保留项的叙事功能,不能只写“已检查”。
随后运行 `node scripts/normalize-punctuation.js 正文/第XXX章_*.md`(默认 `--quote-mode keep`)清理无功能省略号、破折号、双连字符和独立分隔线;盐言「」不受影响。narrative-writer agent 不运行这些脚本。
**退化防护**:正文落盘后运行 `node scripts/check-degeneration.js --check 正文/第XXX章_*.md`。blocking(复读、截断、拒绝语、tier1 工程词泄漏)只重写受影响章节,最多 2 次;仍失败就报告证据让用户定夺。
advisory 只提示可疑处,先看脚本给出的例外;故事内系统/界面用语、弹幕刷屏、重复台词等有功能则保留。
### Agent 调用:consistency-checker
质量检查阶段,consistency-checker 已部署时,仅按当前运行时的 canonical agent 目录检查并 spawn,获取 S1-S4 报告。Prompt:`项目目录:{dir}\n检查范围:{本次写作的章节}\n检查类型:事实冲突+伏笔断线+角色属性不一致`。不可用则主线程参照 long-chapter-quality.md 直接检查。
### Agent 调用:narrative-writer(去AI味审查)
质量检查阶段,narrative-writer 已部署时可 spawn 文字质量与去AI味检查。Prompt:`项目目录:{dir}\n任务描述:审查+去AI味\n检查范围:{本次写作的章节}\n作者偏好:{本章 query 命中的 prose_style/story_design 项}\n删除优先:每条 AI 味项先判能否删除——删后不丢伏笔/钩子/角色/情节/必要信息的直接删,会丢才润色(删除受比例上限与字数下限约束,跌破下限改降AI重写)\n检查项按你自己的 7 Gate、禁止事项与写完后对话自检全量执行,其中否定翻转句式和台词里的工整否定清单不因脚本豁免台词而跳过`。不可用则主线程按 `references/anti-ai-writing.md` 与 `references/banned-words.md` 执行。
检查后若正文修订改变了连续性事实,必须构造 `mode=revision` 的同章追踪事务并执行 `scripts/tracking_commit.py commit`:
- 伏笔变化用 `foreshadow_changes` 更新同一 ID 的当前行,不追加重复历史;
- 时间线变化写入 `timeline_events`,由 `_tracking-state.json` 统一派生 `作者真相.md` 与 `读者已知.md`,不得把作者秘密泄露到读者视图;
- 核心角色状态变化同时提交该角色截至当前章的完整快照;
- 事务失败后保留原事务 JSON,修正写入环境并重跑同一 `commit`;成功后执行 `check`,确认 state 与全部派生视图一致,删除该临时事务 JSON 后再继续写作。
references/workflow-daily.md›
# workflow-daily.md:日更续写工作流
本文件为"日更续写"场景的完整指引。SKILL.md 路由到本文件后,按以下流程执行。
> **日更准备步骤**:每章写作前 4 步——状态筛选 + 题材正文提示卡召回 + 文风召回 + 意图确认,嵌入 Step 2 逐章循环。
>
> 写前资料清单、对标书路径查找、题材正文提示卡、自定义文风模式、文风缺失 fail-fast、模块/节奏缺失停止、权威冲突规则、无对标项目处理,一律按 `SKILL.md` Phase 4 的「缺失文件处理」「对标分析权威优先级」和 workflow-chapter.md 写前准备 (a)-(g) 执行;本文件不另立一套。读者契约、主角代理权、期待债、终局储备参 `reader-contract-and-progression.md`。
>
> **多本对标书**:从 `设定/题材定位.md` 读 `主对标书` 字段;字段指向当前作品时按缺失处理(老项目可能把本书自身登记成了主对标)。缺失时用 `对标/` 下字典序第一本并提示用户补字段——先按当前项目目录名、`.active-book` 和 `设定/题材定位.md` 中的本书信息识别当前作品,排除同名或来源指向当前正文的 `对标/{当前书}/`;排除后为空则按无对标处理。
---
## 适用条件
- 项目已有 `正文/` 和 `追踪/` 目录
- 用户明确说"日更""续写""继续写",或明确指定"写第 N-M 章"
- 目标:每次会话写 2-3 章(4000-9000 字)
> **裸调用不进日更**:如果用户只是触发 `/story-long-write` / `$story-long-write`,没有说"日更/续写/继续写/写第N章/只写1章/逐章确认",不得进入本 workflow。回到 `SKILL.md` 的"裸调用与停靠点",只展示当前进度与可选命令,避免重启会话后自动写 3 章。
---
## Step 1:快速上下文加载
**可选:使用 story-explorer agent 批量加载上下文**。如果项目已部署 story-explorer agent(检查 `.claude/agents/story-explorer.md` 是否存在),可以用 `Agent(subagent_type: "story-explorer", prompt: "项目目录:{dir}\n查询类型:context_load\n查询参数:准备写第 {N} 章\n追踪状态:last_committed_chapter={上一步 check 的值},state_revision={上一步 check 的值}")` 执行 `context_load` 查询,一次获取全部写作上下文。spawn 返回后直接使用其 results,跳过下方手动加载步骤。如果 agent 不可用或返回不完整,回退到下方手动加载。
手动加载(默认方式):
| 序号 | 文件 | 用途 | 如果不存在 |
|------|------|------|-----------|
| 1 | `tracking_commit.py check` | 校验唯一结构化 state 与全部派生视图,并取得最后提交章和修订号;不把完整 state 加入 prompt | state 缺失且新书尚无正文时执行初始化;已有正文则停止并要求由 `story-import` 重新导入为标准项目 |
| 2 | `追踪/上下文.md` | 续写状态卡(≤12KB,固定 7 栏,每章整份读) | 不手写;由初始化/逐章事务生成 |
| 3 | `大纲/细纲_第{N}章.md` | 本章写作计划 | **必须先补建**,不允许跳过 |
| 4 | `大纲/卷纲_第X卷.md` | 卷契约、当前剧情单元、终局储备与未来揭示计划 | 缺必需字段时先补齐;锁定卷纲绝不自动修改 |
| 5 | `设定/角色/{角色名}.md` | 本章涉及角色的静态原始人设 | 只为核心复用角色按 Phase 3 规则补建 |
| 6 | `追踪/角色状态/{角色名}.md` | 久别核心角色的派生当前快照;只按细纲涉及角色加载 | 缺失即视为派生视图损坏:先运行 `tracking_commit.py check`,再重跑产生当前状态的完整事务;已有正文却无 state 时重新 `story-import` |
`追踪/伏笔.md`、`追踪/时间线/`、`追踪/逐章记录/` 默认不整份读取。续写状态卡没有某个旧信息时,才按「旧信息查找步骤」定点查询。
**按需加载**:需要期待感、爽点或信息差约束时,加载 `references/plot-emotion-system.md`、`references/plot-core-methods.md` 或当前 `references/genre-prose-cards/` 题材卡。默认不全量加载。
### 续写状态卡与追踪事务
`追踪/上下文.md` 不是历史档案,而是当前语义检查点中的续写状态卡;顶层只能有以下 7 个栏目:`当前位置 / 长期约束 / 核心角色状态 / 活跃伏笔 / 近三章速记 / 下一章承诺 / 连贯性风险`。目标 8192 字节,硬上限 12288 字节。文风每章从 `设定/文风.md` / 对标文风读取;质量计数、普通待办、文件行数索引、参照章使用记录、去 AI 味统计都不进入续写状态卡。
所有追踪文件的 schema、事务 JSON、初始化和失败修复统一见 [tracking-transaction.md](tracking-transaction.md)。每章只向工具提交一次结构化事务,由 `scripts/tracking_commit.py` 确定性生成逐章增量、角色快照、伏笔当前视图、作者/读者时间线和续写状态卡;主会话和子 agent 都不得分别直接改这些最终文件。
**首次初始化**:
1. `_tracking-state.json` 不存在且项目尚无正文:构造 `last_chapter=0` 的初始化事务,执行 `tracking_commit.py init`。
2. `_tracking-state.json` 不存在但项目已有正文:停止日更。该目录停在旧追踪结构上,走 `/story-import` 的「旧追踪项目迁移」重建 `追踪/`——**不用重跑全书拆解**,只按最后完整章号和现有追踪文件构造初始化事务。本 workflow 自己不解析旧追踪结构、不推测状态。`init` 会把旧结构按原样整体移入 `追踪/_旧追踪存档/` 再建当前协议——旧内容不删除也不参与解析。
3. `tracking_commit.py check` 报告派生视图与 state 不一致:重新提交该章的 `mode=revision` 事务让工具整份重建(`expected_state_revision` 取 `追踪/_tracking-state.json` 的 `state_revision` 字段——`check` 失败时只往 stderr 打 ERROR,不输出 JSON);不得手改 Markdown 或继续写下一章。手写出的逐章记录会让同章 append 永久报 `chapter delta N already exists with different content`,删掉那个手写文件后重跑原事务即可。
**长期约束溢出**:工具最多接受 6 条。出现第 7 条时,在提交事务前先合并语义重叠项或请用户裁定取舍;不得自动删除旧约束,也不得把待办塞进派生视图。
**退役必须显式声明**:`context.long_term_constraints` 和 `context.continuity_risks` 每章整份提交,因此每次都要把仍然成立的条目原样带上。凡是上一版有、本次不再提交的条目,必须逐条写进 `delta.retired_context_items`;漏写会被工具在任何写入前拒绝,不会被当成删除。不再复用的核心角色同理写进 `delta.retired_characters`;角色本章阵亡/退场时照常写 `character_changes`,不必再交一份马上要删的快照。两类退役都只能在 `mode=append` 提交——修订事务的记录属于被改写的旧章,写在那里会谎报退役章节;回炉必须原样重交当前全部上下文条目。两类退役都会留档在本章逐章记录,事后可回查。
**与项目 rules 的关系**:永久生效的设定裁定进入事务 `context.long_term_constraints`;短期强承诺进入 `delta.next_chapter_commitments`;已完成或只影响本章的过程决策不进续写状态卡。
> **确定下一章编号 N 与状态修订号**:执行 `tracking_commit.py check`,从其紧凑 JSON 输出取 `last_committed_chapter + 1` 与 `state_revision`,同时核对 `上下文.md` 的当前位置。逐章事务必须把该修订号写进 `expected_state_revision`;若提交前状态已经变化,工具会在任何写入前拒绝旧事务,此时重新读取当前状态并重构。不要把会随历史增长的完整 state 读进 prompt;章号不一致时修复,不扫描正文猜测编号。
确定本轮写作范围后直接进入 Step 2,不做"是否继续"式确认。K 默认 2-3 章;用户明确说"只写1章"/"日更3章"/"逐章确认"时按用户要求调整。用户给出 N>3 时,本轮只写前 3 章并在 Step 4 进度摘要提示"剩余章节下轮继续"。仅在章节号冲突、细纲缺失、请求范围超过已有细纲、用户要求会改变大纲/追踪,或存在其他会导致写错的阻塞信息时暂停确认。
---
## Step 2:串行批量写作
一次加载多章细纲,但**必须在主会话内串行逐章写作**:不得把多章同时交给多个子代理并发写。长篇章节依赖上一章正文和追踪文件,并发会导致上下文断裂、追踪覆盖和标题去重失效。
**批量 continuation 规则**:进入本 Step 后,"继续"/"续写"/"日更"只表示继续当前日更批量流程。不得把这些词解释为跳过「状态筛选」或「对标模块/节奏/题材卡/文风召回」的直接正文续写;也不得在每章之间重复询问是否继续,除非用户明确要求逐章确认或出现阻塞。到达本轮 K(最多 3 章)后必须进入 Step 3/4 收尾并停止,不能因为仍有后续细纲就继续写下一批。
1. **读取写作计划**:写作计划按 **卷契约 → 当前剧情单元 → 章节细纲** 的顺序确定;已写内容仍以正文与 `追踪/` 文件为准。先从 `大纲/卷纲_第X卷.md` 读取卷契约、当前剧情单元(单元ID/位置)、单元情绪引擎、本卷主推线/战果与终局底牌边界,再加载本次要写的 2-3 章细纲。卷纲或细纲缺少当前协议的必需字段时按既有流程先补齐,未知字段写 `[待补充]`;已锁定卷纲不得自动改动。细纲读取阶段位置、结构公式、禁止提前释放、内容概括、情节安排、人物关系/出场顺序、情节细化的语义义务/执行边界及结尾钩子,不读取或心算逐点字数预算。只有真正影响后续连续性的结果才进入本章事务。
- **批次定位与阶段约束**:写本批前先从 `大纲/大纲.md`、对应 `大纲/卷纲_第X卷.md` 和本批细纲提取:当前章节区间属于哪个阶段、本批推进目标、本批可释放的信息、本批严禁提前释放的信息、章尾钩子不能越过的边界。必须按终局储备确认本批主推线与战果,别动用本阶段还不该解锁的终局底牌(多线齐涨的战果允许);行动成本可无,不硬造代价。未来揭示计划留在大纲,不写入时间线事实;只有下一章必须消费的边界才进 `## 下一章承诺`。
- **阶段进度自检**:每批写完或补完细纲后检查是否超前、拖慢或偏离阶段节奏;若偏离,把下一章必须执行的补偿动作放入事务 `next_chapter_commitments`,跨多章风险放入 `continuity_risks`;不得通过提前泄露后期信息强行提速。
2. **逐章执行**:每章按 [workflow-chapter.md](workflow-chapter.md) 的「单章写作流程」步骤 1-13 完整走一遍(写前准备、正文执行、字数验证、钩子/爽点检查、元信息与禁用词扫描、追踪事务)。批量模式下再叠加下列日更专属动作:
- **上一章欠账检查**:写本章正文前,确认上一章正文无未清 blocking 毒句式欠账(写前 hook 会自动拦;hook 不可用时对上一章跑 `node scripts/check-ai-patterns.js --check --fail-on=blocking`);有欠账先清完再写本章,除非上一章标了 `<!-- 去味:跳过 -->`(用户显式豁免)
- **状态来源纪律**:不要为取状态/章号把完整 `_tracking-state.json` 加载进 prompt;缺失内容按下方「旧信息查找步骤」定点查询,不得用未标明来源的聊天记忆替代,也不得为了方便通读所有逐章记录。
- **久别角色交叉检查**:本章细纲列出的核心复用角色若不在 `## 核心角色状态`,直接读取小文件 `追踪/角色状态/{名}.md`;不存在即视为当前检查点损坏,运行 `tracking_commit.py check` 并通过完整事务修复,不能临时扫描增量后手写替代。`设定/角色/{名}.md` 只有静态原始人设,不能替代动态快照。角色重新活跃后,把名字放进本章事务 `context.active_character_names`,由工具更新续写状态卡。
- **story-explorer 召回的 gaps 分支**(用 `benchmark_style_load` query_type 一次拿到 `{style_profile_path, style_profile_summary, selected_emotion_module, rhythm_reference, module_source_path, rhythm_source_path, matched_chapter_K, matched_chapter_techniques, anchor_excerpts, gaps}` 后按此分流):
- 若 `gaps.no_benchmark: true` → `custom_style` 为真则进入「自定义文风模式」(用 `设定/文风.md` 写作;无对标可召回,情绪 / 节奏目标改从本书细纲「目标情绪」、卷纲、`设定/题材定位.md` 等内部材料取,`selected_emotion_module` / `rhythm_reference` 记为「无」,不声称从对标召回);否则跳过文风召回,在「意图确认」标记"无对标参考"
- 若 `gaps.missing_primary_contract: true` → 停止本章准备,按 `repair_action` 提示重跑 `/story-long-analyze` Stage 3+ 或重新 `/story-import`;不得进入 narrative-writer(情绪 / 节奏轴独立于文风轴,**自定义文风模式不豁免此停止**——补 `剧情/情绪模块.md` / `剧情/节奏.md`,而非写 `设定/文风.md`)
- 若 `gaps.benchmark_book_missing: true` → 停止,核对 `expected_path` 与 题材定位.md 登记名(逐字一致)后重查;不得换书
- 若 `gaps.conflict` 或 `gaps.module_rhythm_conflict: true` → 意图确认必须说明冲突并按 `剧情/情绪模块.md` / `剧情/节奏.md` 的权威优先级执行;不得让 `文风.md` 覆盖情绪/节奏目标
- 若 `gaps.profile_missing: true` → `custom_style` 为真则进入自定义文风模式继续;否则按上文 fail-fast 流程停止
- 若 `gaps.profile_degenerate: true`(对标文风不可用) → `custom_style` 为真则用 `设定/文风.md` 写作;否则跳过文风、回到默认 Gates 写作
- 若 `gaps.tone_match_failed: true` → 仅用整书文风写作,不喂 matched_chapter
- 否则原样传给 `style_profile_path`、`style_profile_summary`、`selected_emotion_module`、`rhythm_reference`、`module_source_path`、`rhythm_source_path`、`matched_chapter_K`、`matched_chapter_techniques`、`anchor_excerpts` 和 `genre_prose_card` 给 Step 2 末尾的 narrative-writer spawn prompt;其中 `selected_emotion_module` 必须进入情绪目标,`rhythm_reference` 必须进入节奏/爆发安排,`genre_prose_card` 必须进入题材取舍,`matched_chapter_techniques` 必须进入「文风召回指令」。写前准备记录必须保留 `gaps` 原值,尤其 `gaps.module_missing`、`gaps.rhythm_missing`、`gaps.conflict`、`gaps.matched_deep_dive_missing`;若 `matched_deep_dive_missing` 为 true,文风召回指令中明确写“同章深度拆解缺失,已回退黄金三章/文风技巧”,不得在后续报告中反转为 false
- **无 story-explorer 时直接执行**:主会话按 workflow-chapter.md 写前准备 (a)-(f) 手动依次召回情绪模块、节奏、题材卡、文风与匹配章 K;模块或节奏文件缺失时设置 `missing_primary_contract` 并停止修复
- **写后清零不拖到批末**:写后 hook 推回的毒句式命中当轮清零,不得攒到 Step 3。
- 每章写完后**立即提交一次追踪事务**:
1. 从刚落盘的正文、细纲和上一版续写状态卡提取 `result / character_changes / foreshadow_changes / timeline_events / constraints / next_chapter_commitments`。只记录会影响未来章节的变化;过程日志、质检计数、参照章和去 AI 味统计全部排除。
2. 需要长期复用的核心角色,把完整动态快照放进 `character_snapshots`,并在 `character_changes` 写对应变化;一次性路人只写变化、不交快照。已有动态快照的核心角色再次变化时必须提交新快照。静态人设继续以 `设定/角色/{名}.md` 为准。
3. `context.long_term_constraints`、当前卷/故事时间/场景、活跃核心角色名、连贯性风险提交当前完整值;活跃伏笔、近三章速记和下一章承诺由工具从当前视图/本章增量派生,不重复手填。
4. 运行 `storyctl.py chapter check`,取 `state_revision` 写入无 `wordcount` 的事务。带内 + quality pass → `chapter commit`;`under` 不补,`over` 按 workflow-chapter 步骤 8 净删一次并复检;仍带外走该步骤三动作。提交会重读、重数、重跑 quality;成功后删临时 JSON,tracking 提交后才继续。
5. 失败时 `_tracking-state.json` 尚未推进;保留临时 JSON,修正写入环境后重跑同一 `commit`。不得另写下一章、不得手工补派生视图、不得忽略返回码。
`追踪/逐章记录/第NNN章.md` 由工具按 5 类变化生成,目标 ≤1536 字节、硬上限 3072 字节。它不是正文摘要大全,更不保存写作过程。`伏笔.md` 每个 ID 只有一行当前状态;角色状态按核心角色拆文件;时间线的客观事实和读者认知只在同一事件登记中维护,再派生作者/读者两个视图。
状态更新仍由主会话负责。narrative-writer 只写正文并回报必要的写作结果,不直接写 `追踪/`;主会话也不绕过事务工具直接修改最终追踪文件。
- **质检提示**(可选):本章写作完成。如需一致性检查,运行 `/story-review lean`。批量写作模式跳过此步骤,全部写完后再统一审查。
3. **不中断但不并发**:tracking 已提交即进下一章(除非用户要求确认);`under` 或一次压缩后仍带外则展示证据/动作,不静默推进。下一章先读上一章正文与追踪更新。
**资料研究(按需)**:如果写作中遇到需要查证的外部事实(历史年代、地理方位、职业细节等),暂停写作,spawn `story-researcher` agent 搜索并输出到 `参考资料/` 目录。研究完成后再继续写作。
### 旧信息查找步骤
状态摘要里没有、但本章确实需要的旧信息(20 章前埋的伏笔、久别角色的当前状态、某个时间锚点),按以下顺序查找,**每一步的读取量都有上限**。不允许因为"查着方便"退化成读历史记录文件全文。
| 级别 | 手段 | 成本 |
|------|------|------|
| 1 | 续写状态卡已有 → 直接用 | 0 |
| 2 | 伏笔 ID 查 `grep -n "F007" 追踪/伏笔.md`;角色查 `追踪/角色状态/{名}.md`;读者认知查 `时间线/读者已知.md`,作者真相查 `时间线/作者真相.md` | 一个当前行或一个有界小文件 |
| 3 | 需要变化原因/历史时,调用 story-explorer 的 `foreshadow_status / character_status / timeline`;各 adapter 按自身 agent 调用方式,agent 不可用就直接 Grep/Read | 子代理/主会话只返回相关条目 |
| 4 | explorer 不可用 → `grep -R -n --include='第*.md' "F007" 追踪/逐章记录/ 2>/dev/null \| tail -5`,只取最近 5 条匹配增量 | 只读取匹配行 |
| 5 | 仍不够 → `Read` 对应增量或埋设章正文 | 1 个紧凑增量或单章正文 |
| 6 | 全量读取所有逐章增量/正文 | **日更禁止**。只在 `/story-review` 或用户明确要求全面审计时 |
**查询次数限制**:单章执行步骤 3 和步骤 4 合计超过 3 次,说明细纲没写清本章要消费哪些旧信息。这时一次性让 story-explorer 查询多项,并在批末口头提示细纲需补清回收项,不另写过程日志。
查询结果只有在本章结束后仍影响后续时才进入追踪事务;当前伏笔由 `foreshadow_changes` 更新,核心角色由快照更新,事实/认知由 `timeline_events` 更新。不要直接改续写状态卡某一行。
---
## Step 3:质量检查
每章的质量检查已在 Step 2 随 [workflow-chapter.md](workflow-chapter.md)「质量检查」节完成。批末只做下列**跨章**核对,不重复逐章项:
1. **标题去重检查**:汇总本轮新写章节与既有标题;发现同名或明显重复时,回到对应细纲和正文文件统一重命名
2. **契约与细纲双向核对**:先按 `reader-contract-and-progression.md` 检查读者契约、因果权 + 结算权、关键节点四问、期待所有权、期待债偿还、终局储备(透支两问);章级推进按权威文件七类状态分档(快节奏保留可见事件/爽点下限),相对本书题材与对标判断;高潮后允许短暂低压和小而可见的收益/奖励。新地图/机构/能力/敌人/谜团须检查换书债;履约爽文/能力幻想另查主角是否反复以可避免的无能制造灾难再由他人收拾。再核对正文是否消费了细纲的内容概括五段式、情节安排多线、人物关系变化/出场顺序、行动成本(可无)/收益归属;并加三条写作要求兑现核对(不达标→修复):① 爽点出手前是否有可指认的危机/期待铺垫段落?指不出=空洞 → 回 Step 2 补铺垫情节点(plot-emotion-system 倒推法);② 装逼/打脸/揭露章是否写出在场配角差异化反应(集体震惊/各异),还是只写主角动作?没有 → 补在场配角反应(plot-core-methods);③ 详略是否按目的词(爽点/卖点点展开、过渡点带过、信息密度交替),还是均匀注水?均匀 → 删过渡、扩爽点点。
3. **伏笔盘点(仅本轮增量)**:确认本批新增/推进/回收的每个 ID 在 `追踪/伏笔.md` 恰好有一行当前状态,并能在对应 `逐章记录/第NNN章.md` 找到本次变化;不得追加第二行历史,也不得在日更流程扫描全部正文做全量伏笔审计
批末再对本批全部落盘正文整体跑一遍 workflow-chapter.md「质量检查」的确定性收尾三脚本(`check-ai-patterns.js` → `normalize-punctuation.js` → `check-degeneration.js`),确认逐章清零后没有回潮。
> 若本步修文改变了会影响后续的事实、角色状态、伏笔、时间线或下一章承诺,必须在进入 Step 4 前为受影响章节提交 `mode=revision` 事务并通过 `check`;其中 `delta` 要重算修订后该章仍成立的完整当前记录,不能只传本次改动;纯措辞调整不重复提交。
---
## Step 4:批末收尾
**本步不再写任何追踪内容**——每章 Step 2 已完成事务。只做两项验证:
1. 对项目运行 `tracking_commit.py check`;验证 state schema、逐章记录连续/规范/未超限、续写状态卡固定 7 栏且不超过 12288 字节,以及全部派生视图与 state 一致。
2. 确认本批每章都有对应 `追踪/逐章记录/第NNN章.md`,每个文件 ≤3072 字节。缺失或超限时不手工补文件,回到该章事务修正并重跑 `commit`。
然后向用户口头汇报本批完成情况(章数、字数、漂移、下一批建议),不另存为文件。
---
> **漂移处理**:aligned = 按计划推进;adaptive = 细节适配但不改契约;structural 漂移 / 结构性漂移 = 正文已经改变卷契约、单元承诺、推进线或兑现归属,必须修正文或重规划未来章节细纲,不能只在增量里备注。下一章必须修的漂移进入 `next_chapter_commitments`,跨章风险进入 `continuity_risks`;两者都受续写状态卡上限约束,完整语义以紧凑增量和大纲为准。
## 细纲缺失补建流程
当检测到细纲不存在时,不能跳过。按以下步骤补建:
1. 加载 `大纲/卷纲_第{N}卷.md`(本章对应的事件规划),读取本章所属剧情单元卡;剧情单元卡含「对标剧情参照」时加读其指向的剧情单元文件(1 个),以其「结构分布」对应位置作本章功能参照;若本章起整个剧情单元均无细纲,按 outline-structure-theory.md「按剧情批出细纲」整批补建而非单章补。卷纲缺必需字段时先补齐,不绕过当前模板继续
2. 加载本章涉及的 `设定/角色/{角色名}.md`(角色状态)
3. 读取最新一章正文(情节衔接)
4. 按 SKILL.md Phase 3 的新版细纲模板补建本章细纲,补齐阶段位置、本章结构公式、本章禁止提前释放、内容概括、情节安排、人物关系/出场顺序、情节细化、结尾设定;无法从卷纲/正文/设定确认的字段写 `[待补充]`,不杜撰
5. 补建完成后继续 Step 2 写作
---
## 常见问题
| 问题 | 处理 |
|------|------|
| 细纲不存在 | 执行上方"细纲缺失补建流程" |
| 细纲缺当前蓝图字段 | 先按当前模板补齐,未知项写 `[待补充]`;未补齐前不写正文 |
| 追踪文件为空 | 正常继续,写作中逐步填充 |
| 用户要求改大纲 | 提醒"改大纲会影响后续细纲",确认后修改,标记受影响的细纲 |
| 写到卷末 | 提示用户"当前卷已完成,是否开新卷?" |
| 用户中断批量写作 | 保存当前章节,已更新追踪文件,下次从断点继续 |
references/workflow-revision.md›
# workflow-revision.md:大修工作流
本文件为"大修/回炉"场景的完整指引。SKILL.md 路由到本文件后,按以下流程执行。
---
## 适用条件
- 用户说"修改第X章""回炉第X章""重写第X章"
- 目标:修改已写好的章节内容
> 用户必须指定章节号或章节名。无法自动推断需要修改哪一章。
---
## Step 1:定位章节
1. 根据"第X章"找到文件:`正文/第{X}章_*.md`
2. 如果用户说的是章节名而非编号,用 `find 正文/ -name "*{关键词}*"` 搜索
3. 找不到时让用户确认具体章节
4. 如果用户指定段落范围("第3-5段"/"那场打斗"/"对话部分"),记录为局部修改目标
---
## Step 2:加载上下文
加载比日常写作更多的上下文(因为修改需要理解前后衔接):
| 序号 | 文件 | 用途 | 如果不存在 |
|------|------|------|-----------|
| 1 | `正文/第{X}章_*.md` | 待修改章节 | 必须存在 |
| 2 | `大纲/细纲_第{X}章.md` | 原始写作计划 | 跳过 |
| 3 | `正文/第{X-1}章_*.md` | 前一章(衔接) | 第1章时加载 `设定/世界观/背景设定.md` 替代 |
| 4 | `正文/第{X+1}章_*.md` | 后一章(衔接) | 末章时检查 `大纲/细纲_第{X+1}章.md`(如有)确保连续性 |
| 5 | `tracking_commit.py check` + `追踪/上下文.md` | 用工具确认唯一 state 与派生视图一致;续写状态卡提供当前连续性,不把完整 state 加入 prompt | 缺 state 时停止;已有正文项目必须经 `story-import` 生成标准追踪状态 |
| 6 | `设定/角色/{相关角色}.md` + `追踪/角色状态/{相关角色}.md` | 静态人设 + 动态当前快照 | 动态快照缺失时从相关增量重算 |
**相关角色判定**:从 `大纲/细纲_第{X}章.md` 中提取角色名。如果细纲不存在,从待修改章节正文中搜索 `设定/角色/` 目录下的角色名关键词。将角色名映射为文件名:`设定/角色/{角色名}.md`。
---
## Step 3:修改
1. **阅读原文**:读完整章内容,用 `{PYTHON} {story-long-write skill 根}/scripts/storyctl.py wordcount check` 记录原始 `visible_chars_v1` 结果
2. **备份原文**:将原文复制为 `正文/第{X}章_章名_原稿_{YYYYMMDD}.md`,确保可回退
3. **确认修改范围**:问用户是"全文重写"还是"修改特定段落"
- 全文重写:基于细纲重新写,保留备份
- 局部修改:只改指定段落(按场景序号或关键词定位),保持其他部分不变
4. **执行修改**:改写文件
5. **字数对比**:修改后重跑同一计数器;与原文差异 >30% 或 >800 字时提醒用户(取较大值),并报告 `internal_pass / borderline / under / over / invalid`。测量状态不触发静默覆盖或二次改写正文
**资料研究(按需)**:如果修改涉及需要验证的外部事实(历史年代、地理方位、职业细节等),spawn `story-researcher` agent 搜索验证。
---
## Step 4:级联检查
修改完成后,用一次 `mode=revision` 追踪事务完成级联更新,协议见 [tracking-transaction.md](tracking-transaction.md):
1. **重算修订章增量**:对比旧正文/旧增量与新正文,只保留新版本对未来仍有效的 `result / 角色变化 / 伏笔变化 / 时间与揭示 / 约束 / 下一章承诺`。事务工具整份重写 `追踪/逐章记录/第{X}章.md`,不保留被新正文推翻的结论。
2. **伏笔当前值**:对受影响 ID 从第 X 章检查到最后已写章 M,提交修订后的**截至 M 章当前状态**。若修订删除了埋设,但后文仍引用该 ID,先列为正文冲突,不能简单删除;确定整条线不存在时才用 `action=delete`。`伏笔.md` 始终每 ID 一行,不追加修订历史。
3. **时间与读者认知**:为受影响事件提交客观事实、读者截至 M 章的当前认知、实际揭示状态/章节;删掉的事件用 `action=delete`。未来揭示计划仍留大纲。工具把事件合并进 `_tracking-state.json` 并重建作者/读者视图,禁止分别手改。
4. **角色当前快照**:对受影响核心角色从 X 检查到 M,按身份、位置、目标、能力资源、关系对象、已知信息、未结事项分别重算,提交一份截至 M 的完整快照;不得用最后一条单维度变化覆盖其它维度。
5. **导入截止范围**:若 X ≤ `_tracking-state.json.imported_through_chapter`,事务为第 X 章新增覆盖记录;导入截止章不变,当前结构化状态按修订结果更新。
6. **提交与重试**:把修订开始时 `tracking_commit.py check` 返回的 `state_revision` 写入 `expected_state_revision`,再执行 `tracking_commit.py commit`;若期间状态已变化,重新读取当前状态并重构事务。任一步骤失败时保留原事务 JSON,修正写入环境后重跑同一 `commit`;成功并通过 `check` 前禁止继续修下一章或写新章。
7. **后续影响**:如果修改改变了角色状态/关系/世界观设定,扫描后续章节正文标记受影响项:
```
⚠️ 修改第{X}章后,以下章节可能需要同步调整:
- 第{X+1}章:{原因}(建议检查)
- 第{X+3}章:{原因}(建议检查)
```
8. **正文元信息扫描**:检查标题行以外是否混入 `第[一二三四五六七八九十百千万两0-9]+章|上一章|上章|前一章|本章|这一章|前文|后文|伏笔|细纲|读者` 这类写作工程词,命中即改成角色当下可感知的事件锚点或相对时间;故事内真实阅读/讨论“第X章”或真实读者身份语境除外
9. **禁用词扫描**:对照 `references/banned-words.md` 检查修改后的内容,并运行 `tracking_commit.py check` 验证 state 与全部派生视图一致
---
## Step 5:质量检查
对修改后的章节执行 Phase 5 质量检查(至少包含):
1. **禁用词扫描**:如 Step 4 未覆盖全章,再次扫描
2. **正文元信息扫描**:同「级联检查」中的「正文元信息扫描」,确认覆盖全章。
3. **人物一致性**:修改后的角色行为是否与角色设定一致
4. **节奏检查**:修改是否破坏了章节节奏
> 完整检查清单见 [workflow-chapter.md 的「质量检查」节](workflow-chapter.md)。
---
## 常见问题
| 问题 | 处理 |
|------|------|
| 用户没说改哪里 | 问"你想改哪一章?哪方面?情节/节奏/对话/描写?" |
| 修改后字数暴增/暴减 | 提醒用户,由用户决定是否调整 |
| 连续改多章 | 逐章修改,每章独立执行 Step 2-5 |
| 改完发现后续不一致 | 列出受影响章节,由用户决定是否现在修改 |
references/workflow-setup.md›
# workflow-setup.md:开书工作流(Phase 1-3)
本文件为"开书/建设定/搭大纲"场景的完整指引,从 SKILL.md 的 Phase 1-3 抽出。
SKILL.md 只保留场景路由与停靠规则;进入任一 Phase 前读本文件对应小节,按其中步骤执行。
> 这三个 Phase 每本书只跑一次(开新卷时回 Phase 2/3 增量补充)。日更续写与单章写作不需要本文件,
> 走 SKILL.md 的 Phase 4 与 `workflow-daily.md`。
---
### Phase 1:确认选题方向
**先查选题决策**:如果项目根存在 `选题决策.md`(story-long-scan Phase 5 产出),读取它——取排在最前(可行性最高)的推荐选题作为开书起点,向用户确认:「扫榜建议写 X(能爆的原因 Y,差异化 Z),按这个开书?」并看 `扫榜日期`:距今较久则提示"市场数据可能过期,建议复扫"。用户认可 → 带该选题的题材/卖点/差异化进入 Phase 2。
缺失时先自动找一遍:从项目根及其上一级目录起、向下最多 3 层按文件名搜 `选题决策.md`(跳过隐藏目录),按 mtime 由新到旧取最新 2 份。搜到 → 用 AskUserQuestion 列候选(路径 + 文件里的 `扫榜日期`,另加「我自己给路径」和「都不用」);选中某份 → 复制到项目根,再按上一段读取;选「我自己给路径」→ 让用户粘路径,同样复制到项目根;选「都不用」→ 走下面的常规提问。搜不到 → 问一句:「有扫榜生成的 `选题决策.md` 吗?放到项目根或粘贴路径;没有就直接答下面的问题。」仍无 → 走下面的常规提问。
如果用户已有方向 → 跳过下面的方向提问,但仍先做下方「对标上下文加载」(含对标发现),再进入 Phase 2。
如果用户没有方向:
问用户:**「你想让读者什么感觉?有没有喜欢的书想对标?你的优势是什么(脑洞好/文笔好/节奏感好/生活经验丰富)?」**
#### 对标上下文加载
> **拆文库/对标关系** 与 **对标书路径查找** 的定义见 SKILL.md「路径与术语约定」,本文件与 Phase 4 共用同一条规则。
**对标发现(先于下方反应式加载)**:无论用户是否点名对标书,先扫 `拆文库/` 按题材主动推荐,不要被动等用户开口。
1. `ls 拆文库/`(数据源)与项目 `对标/`(引用视图)列已有书目;先按当前项目目录名、`.active-book` 和 `设定/题材定位.md` 中的本书信息识别当前作品,排除同名或来源指向当前正文的 `拆文库/{当前书}/`。story-import 为重建工程生成的本书拆文分析不是对标候选,也不得复制回 `对标/`。排除后都为空 → 跳到第 4 条。
2. 逐本读题材(短篇读 `拆文库/{书}/_meta.json` 的 `genre_detected`;长篇读 `概要.md` 头部或 `拆文报告.md`「基本信息」的「题材」),与本书题材/方向比对,标 同题材 / 弱相关 / 不相关。
3. 有同题材或弱相关候选 → 用 AskUserQuestion 推荐(列候选书 +「都不用」+「另拆一本」),主对标 1 本走文风/正文、其余作副对标。选定后写入 `设定/题材定位.md`「对标登记」的 `主对标书` / `对标书列表`(Phase 2 落文件,此处先记选择),并按 SKILL.md「路径与术语约定」的「首次引用对标书」规则把选中书从 `拆文库/{书}/` 复制到 `对标/{书}/`。
4. 无候选 → 无对标继续(大纲按八节点自排,见 Phase 3);用户想对标可先 `/story-long-analyze` 拆一本。
如果用户提到对标书或工作目录下已存在 `对标/` 目录:
1. 先按上方「对标发现」第 1 条的同一口径识别当前作品,排除同名或来源指向当前正文的 `对标/{当前书}/`——老导入项目里可能留着历史误建的自对标目录。排除后没有外部对标书时不进入下面几步,按无对标继续。
2. 按对标书路径查找规则检查 `剧情/情绪模块.md` 与 `剧情/节奏.md`。
3. 任一主产物缺失时必须停止,设置 `missing_primary_contract: true`,并给出 `repair_action`:重跑 `/story-long-analyze` Stage 3+ 或重新 `/story-import`;不得以 `拆文报告.md`、章节摘要或故事线代替。
4. 两个主产物都存在时,先读 `剧情/情绪模块.md` 的读者需求 / 情绪引擎与可复现模块,再读 `剧情/节奏.md` 的关键信息推进、情绪触动点和爆发节奏;`拆文报告.md` 只用作人类可读概览。
5. 如果角色、普通剧情单元或设定子目录存在,写作时按需召回相关模块。
根据回答做匹配:
- 脑洞好 → 推荐:系统文、诸天流、无限流
- 文笔好 → 推荐:仙侠、历史、文艺向都市
- 节奏感好 → 推荐:都市爽文、重生文、游戏文
- 生活经验丰富 → 推荐:行业文、都市日常、种田文
#### Agent 调用:story-architect
story-architect 属于高层级结构设计 agent。轻量题材定位优先由主会话完成;只有涉及复杂世界观、多线结构、强反转工程或用户明确要求时,才调用 story-architect。确认选题方向后,如果项目已部署 story-architect agent(检查 `.claude/agents/story-architect.md` 是否存在),可 spawn `Agent(subagent_type: "story-architect", prompt: "项目目录:{dir}\n任务类型:题材定位\n查询参数:{用户选择的方向+对标信息}")` 辅助题材分析和核心梗设计。如 agent 不可用,由主线程直接执行。
> **story-architect 契约摘要(spawn 时必须原样附带)**:部署的 story-architect agent 不认识本 skill 的 `references/reader-contract-and-progression.md`,只能靠 spawn prompt 里带的这段摘要对齐 schema,否则主线程和委托产出会用不同的推进规则。摘要内容:
> - **终局储备边界**:终局底牌(头号宿敌/终极真相/金手指上限/身份终点/核心情感终点)是一次性资源,逐卷解锁,不得提前打光;升级台阶(境界/等级/地图/势力层级)按剩余档数逐级解锁,不得越级。
> - **透支两问**(任一为"是"即需回退或改纲):①是否动用了本阶段还不该解锁的终局底牌?②是否让某条升级线逼近天花板、后面没台阶接?
> - **剧情单元**:卷纲内写剧情单元卡,含单元ID、主推线(1条)+ 战果线(若干,一战多得允许)、章级推进下限(快节奏保留可见事件/爽点下限)。
> - **细纲层字段**:每章细纲必须带 单元ID/位置、主角目标/关键选择;「行动成本(可无)/收益归属」替代旧字段「代价兑现」——行动成本可无,不硬造代价,收益归属必须可见。
> - **读者契约与主角代理权**:主角不可替代看因果权(决策/布局/授权/关键信息决定事情如何发生转向)+ 结算权(核心收益/认可按承诺回到应得者),不要求主角事事亲自动手;配角可执行局部动作,但不得无声夺走已承诺的高光/收益。
> - **关键节点四问**(设计关键节点时统一问):①谁决定事情为什么发生/如何进入?②谁作出不可替代的关键选择?③谁承担或选择关键后果?④核心收益/认可/权力最终结算给谁?
> - 完整规则以主会话已加载的 `references/reader-contract-and-progression.md` 为准,此处只是给 story-architect 的压缩版;agent 本身不部署该文件,不能自己读取。
---
### Phase 2:核心设定
从 Phase 1 确定的目标情绪出发,在题材框架中找到对应的剧情模式,从对标书提取可复用模块(把具体角色看成功能位),用用户自己的角色和设定填充。
帮用户确立以下核心要素:
```
## 核心设定表
### 基本信息
- 书名:{暂定名}
- 题材/类型:{主类型 + 副类型}
- 目标平台:{起点/番茄/晋江/其他}
- 预计字数:{X} 万字
- 目标读者:{画像}
- 读者契约:{本书承诺的核心阅读快感;参 reader-contract-and-progression.md}
- 主角高光/代理权:{主角不可替代的判断、选择或贡献}
- 核心期待债:{开篇必须偿还的承诺}
### 一句话梗概
{主角 + 目标 + 阻碍 + 反转,一句话概括全书}
### 主角设定
- 姓名:{}
- 年龄:{}
- 核心特质:{2-3 个关键词}
- 金手指/核心能力:{}
- 弱点/缺陷:{让角色更立体的地方}
- 核心动机:{他为什么要做这件事}
### 世界观骨架
- 时代/背景:{}
- 核心设定:{区别于同类作品的独特设定}
- 力量体系:{如果有,简单概括}
- 社会结构:{影响故事的关键设定}
### 核心冲突
- 主线矛盾:{}
- 终极 Boss/终极阻碍:{}
```
完成核心设定后,创建以下 artifact(加载 [references/artifact-protocols.md](artifact-protocols.md) 中对应模板):
- **设定/关系.md**:角色关系映射(参考 character-relations.md「四种关系类型」)
- **设定/题材定位.md**:题材核心梗三分法+对标分析(参考 long-genre-mechanics.md「核心梗解析」)。对标分析表保留 2-3 行摘要,详细数据见 `对标/` 目录
- **设定/题材正文提示卡.md**:从 `设定/题材定位.md` + `references/genre-prose-cards.md`(索引)+ `references/genre-prose-cards/`(单题材正文卡目录,按题材分类优先)+ `references/style-genre-modules.md`(通用流派补充)抽取本书正文层题材卡,只写题材边界、核心逻辑、读者期待、核心爽点/情绪、正文落点、前中后期打法、节奏密度、场景颗粒、禁止漂移;不写通用格式规则,不覆盖 `设定/文风.md`
> **多对标书时**:参 `references/cross-book-recall.md`,副对标 anchor 入「对标分析」表附录
#### Agent 调用:story-architect + character-designer
核心设定阶段,当前端已部署对应 agent 时可 spawn;Antigravity 按 SKILL.md 用 `invoke_subagent` + 同名 `TypeName`:
- `Agent(subagent_type: "story-architect", prompt: "项目目录:{dir}\n任务类型:核心设定\n查询参数:世界观构建+核心冲突设计")` — 辅助世界观和核心冲突设计;spawn prompt 必须原样附带 Phase 1 的「story-architect 契约摘要」(升级台阶检查约束力量体系设计)
- `Agent(subagent_type: "character-designer", prompt: "项目目录:{dir}\n任务类型:角色设定\n查询参数:{主角设定信息}")` — 辅助角色设定和语言风格档案
如 agent 不可用,由主线程直接执行。
---
### Phase 3:大纲搭建
#### 全书体量与阶段总览(卷纲前置)
卷级大纲前先写全书体量与阶段边界,作为后续卷纲、细纲、日更补纲的共同约束。比例只作默认参考,必须按题材、目标字数和对标节奏调整,不能机械套模板。
```
## 全书体量与阶段总览
- 全书总章节数:{X} 章
- 目标字数:{X} 万字
- 全书情绪曲线:{压抑/期待 → 加压/反转 → 爽感/震撼 → 余韵/圆满;标注关键阶段}
### 阶段划分
1. 开篇期(第 {A}-{B} 章,参考 10%-15%):核心任务 {立人设/立世界/埋主线钩子};情绪基调 {压抑/期待/惊奇};阶段结束时读者应建立 {对主角的认同 + 对主线冲突的期待}
2. 发展期(第 {A}-{B} 章,参考 50%-60%):核心任务 {矛盾展开/支线并行/资源与关系升级};情绪基调 {期待/紧张/间歇爽感};阶段结束时读者应建立 {对核心反派或终局矛盾的迫切期待}
3. 高潮期(第 {A}-{B} 章,参考 20%-25%):核心任务 {核心冲突爆发/多线收束/连续爽点};情绪基调 {爽感/震撼/反转};阶段结束时核心矛盾应 {基本解决或进入最终对决}
4. 收尾期(第 {A}-{B} 章,参考 5%-10%):核心任务 {伏笔回收/关系落定/结局余韵};情绪基调 {释然/感动/圆满};阶段结束时主线伏笔应 {回收完毕,结局落定}
### 各阶段节奏公式
- 开篇期:核心任务 / 情绪基调 / 爽点密度 / 伏笔策略 / 冲突层级 / 阶段钩子 / 禁止提前释放
- 发展期:核心任务 / 情绪基调 / 爽点密度 / 伏笔策略 / 冲突层级 / 阶段钩子 / 禁止提前释放
- 高潮期:核心任务 / 情绪基调 / 爽点密度 / 伏笔策略 / 冲突层级 / 阶段钩子 / 禁止提前释放
- 收尾期:核心任务 / 情绪基调 / 爽点密度 / 伏笔策略 / 冲突层级 / 阶段钩子 / 必须回收清单
### 关键节点与钩子链
- 关键转折点:第 {X/Y/Z} 章,各自承担 {事件功能 + 情绪效果}
- 小/中/大高潮:小高潮第 {X/Y/Z} 章;中高潮第 {X/Y} 章;大高潮第 {X} 章
- 阶段钩子链:开篇期结尾指向发展期;发展期结尾指向高潮期;高潮期结尾指向收尾期
```
#### 卷级大纲(全书结构)
```
## 卷级大纲
### 第一卷:{卷名}(约 {X} 万字,{Y} 章)
- 功能:{铺垫/起步/第一个大爽点}
- 所属阶段:{开篇期/发展期/高潮期/收尾期;可跨阶段时写清分界章}
- 卷契约:{本卷承诺的读者快感、主角高光、主要期待债}
- 终局储备:{本卷主推线1条 + 战果线若干(一战多得允许);本卷解锁哪个终局里程碑、禁碰哪些未解锁底牌,参 `设定/题材定位.md`「终局底牌与升级台阶」小节 与 reader-contract-and-progression.md}
- 剧情单元:{1–3 万字剧情单元卡写在卷纲内,不另建单独文件;字段模板见 `references/artifact-protocols.md`,契约/推进规则见 `references/reader-contract-and-progression.md`}
- 阶段边界:本卷可释放 {信息/关系/能力};本卷禁止提前释放 {后期核心真相/终局底牌}
- 核心事件:{一句话}
- 起始状态 → 结束状态:{主角从 {A} 变成 {B}}
### 第二卷:{卷名}
...
### 最终卷:{卷名}
- 功能:{高潮 + 收尾}
- 核心事件:{一句话}
```
> **多对标书时**:参 `references/cross-book-recall.md`,副对标 `章节/*_摘要.md` + `剧情/*.md` 召回卷级节奏
> **对标节奏回流(有主对标书时,卷纲定稿前做一次)**:读主对标 `对标/{书}/剧情/节奏.md`;缺失时设置 `missing_primary_contract: true` 并停止,提示重跑 `/story-long-analyze` Stage 3+ 或重新 `/story-import`,不得用章节摘要、故事线或拆文报告代替。文件存在时,按 references/outline-structure-theory.md「对标节奏迁移」把对标的一级结构关键点(1/4·中点·3/4)换素材排进本卷卷纲「对标结构坐标」——选段以主对标剧情单元为单位,按「类型/桥段标签」圈同类(详见该节步骤 1),选中的剧情单元写入剧情单元卡「对标剧情参照」。若尚未登记主对标书但 `拆文库/` 有同题材候选,先回 Phase 1「对标发现」登记再排节奏;确无对标书则按八节点占比自排。
#### 细纲(全书每章)
⚠️ **大纲安全七检(批次级必答:每卷/每批细纲设计前答一遍全量;逐章设计时只复答⑥⑦并把风险等级写入该章细纲「契约风险」行,不逐章重答全表;中途追加剧情单元时,⑦的关键情节锚定按单元内 1/4·中点·3/4 口径执行,不改已锁定的卷尺度坐标表)**:① 本卷交付什么情绪?什么剧情模式能可靠交付?② 本卷核心冲突是什么?③ 卷节奏(起承转合)哪段加速哪段减速?④ 本卷需要新埋设的伏笔有哪些?上一卷待回收的伏笔如何处理?⑤ 章节定位分布是否有高低层次(不是全程高压)、低压+过场是否克制(合计不超约 15%)?⑥ 本卷/本章处在全书哪个阶段,可释放什么,必须压住什么?⑦ 读者契约、主角代理权、期待债、终局储备(终局底牌/升级台阶)是否按 reader-contract-and-progression.md 评为 契约安全 / 需补强 / 契约破坏?有对标书时,1/4·中点·3/4 是否各锚定一个关键情节(见 references/outline-structure-theory.md「章节定位与张弛 / 对标节奏迁移」)?
**大纲安全审查(顺序不可倒置;批次级执行一次,覆盖本批全部剧情单元与章)**:先按 `references/emotional-methods.md` 设计正向情绪发动机与题材核心兑现,再用权威文件的主角代理权/所有权/成长负向风险护栏诊断。后者按因果权 + 结算权、关键节点四问与期待所有权,检查每个剧情单元的主角目标、关键选择、兑现归属、核心资产交换、机构/势力边界、换书债和推进线;不要求主角亲自完成每个动作。契约破坏 必须修纲,需补强 必须补交换/铺垫/成本。再做两个可证伪降级检查:① 删除题材核心的对象/关系/问题后,是否退化为通用职业升级或换皮情节?② 删除主角后,情绪兑现是否仍基本不变?任一为“是”就先修引擎。
**每章必须有一个细纲文件**(`大纲/细纲_第XXX章.md`),不允许跳章。
默认分批建纲:先建前 10 章细纲后**停靠**,报告"已可开始写第1章/日更";只有用户明确要求写正文时才进入 Phase 4。滚动补纲按编号规则执行(见 references/outline-structure-theory.md「按剧情批出细纲」):
1. **批次边界**:一批 ≈ 一个剧情单元(5-15 章);>10 章的剧情单元拆两批。**首批 = 前 10 章封顶、可跨单元**:跨入的剧情单元在建卡时召回一次,余章由后续滚动批共享该剧情单元卡结论。写到单元末段(剩余未建细纲 ≤2 章)即滚动补下一单元整批;用户显式给出章数/范围时按用户要求执行,单批仍建议 ≤10 章、分批连续交付。
2. **批次定位与阶段约束**(每批补纲前先写):当前章节区间属于哪个阶段与哪个剧情单元(单元ID)、本批推进目标、本批可释放信息、本批严禁提前释放信息、章尾钩子不能越过的边界。
3. **剧情单元消费**:建卡批读本批剧情单元卡「对标剧情参照」指向的剧情单元(≤3 个文件,含结构分布/情节点索引),按节拍→章映射铺章、情节点换素材;同一剧情单元的后续批共享剧情单元卡固化结论,不重读剧情单元。当前卷纲缺少必需剧情单元字段时先补齐卷纲,不带缺失字段进入日更。
4. **批末结构复核**(每批建完必做):按现有大纲流程确认章级目标与 `visible_chars_v1` 口径、核心字段、禁止提前释放和可执行情节点齐全。不得用“每个情节点固定等于多少字”预测容量或自动补事件;每章细纲落盘后必须跑 `node scripts/check-outline-contract.js --json --project {书目录} --chapter {N}`:exit 1 只按 `repair_scope` 补点名字段再复验,最多两轮。**旧章细纲缺字段是常态,不要照抄同目录既有文件的字段集**,以本节模板为准。语义仍不设 checker。
不要在单次对话里强行产出 30 章完整细纲。
如果全书章数较少(≤30 章),可以在 Phase 3 一次全部建完。
```
## 细纲(第 N 章)
### 第 N 章:{章名}
- 核心事件:{一句话;供日更与导入统一消费}
- 字数目标:{X} 字
- 字数口径:visible_chars_v1
- 阶段位置:{开篇期/发展期/高潮期/收尾期;第X阶段第Y章;本章在阶段内承担什么}
- 单元ID/位置:{卷纲剧情单元ID;单元内第几拍/承担功能}
- 目标情绪:{具体情绪前状态→后状态;本章推进单元情绪引擎的哪一环;不得只写“热血/悲伤”等标签}
- 主角目标/关键选择:{主角本章要什么;必须做出的判断或选择}
- 章节定位:{高压/推进/修炼试错/关系回收/低压生活/信息整理;可留空,留空按推进章。见 references/outline-structure-theory.md「章节定位与张弛」}
- 本章结构公式:{节点1(目的) + 节点2(目的) + 节点3(目的) + 节点4(目的)}
- 章首钩子:{从章首7式中选择} — {具体内容;低压/过场章可写“弱钩子/仅情绪钩子,功能是…”}
- 爽点:{本章爽点;低压/修炼/过场章可写“无显性爽点,功能是…”,但仍须给读者一个往下看的理由}
- 本章禁止提前释放:{后续阶段核心真相/底牌/关系结论/终局矛盾;没有就写“无”}
- 契约风险:{契约安全/需补强/契约破坏;逐章只按七检⑥⑦复核后填写,批次级已答全表}
#### 内容概括(五段式)
- 起因:{本章事件为什么发生}
- 发展:{冲突如何推进}
- 转折:{信息/关系/局势哪里改变}
- 高潮:{本章情绪或动作峰值}
- 结尾:{本章最后落在谁的什么动作/画面/台词上——写具体落点,不写"尘埃落定""一切结束"式状态判词}
#### 情节安排(多线)
- 主线推进:{本章对主目标的推进}
- 辅线推进:{可写“无”,不能凭空制造}
- 事件线 / 任务线:{外部事件链}
- 任务卡点(如适用):{角色要办什么事 → 卡在哪里 → 卡出什么变化 → 删掉后损失 → 收束动作;没有就写“无”,不强补}
- 感情线 / 关系线:{无显性感情线时写“无显性,但关系变化为…”}
- 逻辑线:原因 → 行动 → 结果 → 后果/新问题
#### 人物关系和出场顺序
- 出场顺序:{角色/势力/关键物件按实际出现顺序列出}
- 人物关系变化:{本章前 → 本章后}
- 视角/信息差:{谁知道什么;读者知道什么;主角误判什么}
#### 情节细化
- 情节点序列(逐行填下表;写清动作与叙事功能,不填写逐点字数):
| # | 情节点(谁做了什么) | 功能标签 | 执行边界 |
|---|---|---|---|
| 1 | {主角在账单上发现4800元转出} | {信息揭示} | {只确认异常,不揭露幕后者} |
功能标签=目的词:铺垫/高潮/爽点/打脸/人物塑造/设定,用于判断该点承担什么义务;执行边界写本点不能提前释放或新增什么。点数由语义需要决定,不用 `目标字数 / beat 数`、固定字数档位或历史偏差系数反推。结构预检只判输入是否可安全执行,不宣称细纲一定能撑到目标字数。
- 任务卡点说明:如果某情节点是“办事被卡住”,功能标签必须写清它服务的是信息揭示、关系变化、代价兑现、伏笔推进、选择压力、节奏喘息或钩子承接;删掉无损的卡点不进细纲
- 复沓锚句:{须一字不差进正文的原话(誓言、面板、旧案原话),一行一条并注明落点,如"点3:立此为凭…";没有写"无"}
- 行动成本(可无)/收益归属:{可无行动成本;若有则写谁付出什么成本;收益归谁、如何可见、是否留下后续账}
#### 结尾设定和钩子
- 结尾设定:{收束落到什么具体动作或画面(不写"就这样……""他终于明白……"式状态判词);未解决问题;下一章推动力}
- 章尾钩子:{从章尾13式中选择} — {具体内容,期待度:强/中/弱;低压/过场章可弱钩子或留阶段目标;与下一章如何承接}
```
**大纲锁定**:已进入正文写作的前 10 章细纲锁定,未经用户确认不得修改;后续滚动细纲可随正文反馈微调。**卷纲锁定的定义**:某卷一旦已有正文章节,该卷已写区间对应的既有剧情单元卡与对标结构坐标即视为锁定——未经用户确认不改既有内容,但允许在卷尾**追加**新剧情单元卡(只增不改)。追加同样只发生在用户明确要求补纲/扩纲时;日更/写正文流程不自动追加剧情单元卡。workflow-daily 各处「锁定卷纲绝不自动修改」均按此定义执行。
**中途补纲/扩纲小流程**(项目已有大纲,用户要求"出细纲/补细纲/规划下一段剧情"时走这里):
1. 定位当前卷、已写进度与既有剧情单元卡:读 `大纲/大纲.md`、当前 `大纲/卷纲_第X卷.md`、`追踪/上下文.md`(续写状态卡,待回收伏笔取 `## 活跃伏笔`、主角当前状态取 `## 核心角色状态`),以及 `设定/题材定位.md`(终局底牌与升级台阶)——续写状态卡缺项按 workflow-daily「旧信息查找步骤」按需查询,不读全部逐章增量;
2. 按 references/outline-structure-theory.md「对标节奏迁移」步骤 1 选同类剧情单元,设计新剧情单元卡(含「对标剧情参照」),**追加**到当前卷卷纲卷尾,并随卡在卷纲「情绪弧线」表与「本卷伏笔」表**只增不改**地追加对应规划;尚未实际埋设的伏笔留在大纲,不提前登记为时间线/追踪事实——用户主动要求补纲即视为已授权追加,锁定的既有剧情单元卡不动;新剧情单元体量超出本卷规划时,先与用户确认扩卷还是开新卷;
3. 批次级答一遍上方「大纲安全七检」并执行「大纲安全审查」(追加剧情单元时⑦按单元内 1/4·中点·3/4 口径);
4. 按「按剧情批出细纲」以新剧情单元为批次滚动补细纲(一批 ≈ 一个剧情单元,>10 章拆两批共享召回),每批建完执行「细纲后设定补全」与批末合计核对;
5. 新剧情单元和未来揭示边界已经在卷纲/细纲落盘,不复制进追踪续写状态卡;只有下一章必须履行的承诺才在下一次逐章事务里进入 `next_chapter_commitments`。
**细纲质量要求**:每章细纲都要按当前章节蓝图直接指导正文(阶段位置、结构公式、禁止提前释放、内容概括、情节安排、人物关系/出场顺序、情节细化、结尾设定齐备),但**强度按章节定位分配、不是每章顶满**:高压/推进章配齐钩子+爽点+悬念;低压/关系/修炼/信息整理章允许无显性爽点、弱钩子或仅情绪钩子,重点是把功能(喘息、关系、铺垫、转场)写到位。底线是每章都给读者一个往下看的理由、相邻章不情绪趋同(见 references/outline-structure-theory.md「章节定位与张弛」)。字段不完整时先补齐;无法从材料确定的关系或副线写 `[待补充]`,不得杜撰。
> **细纲钩子来源**:优先沿本批剧情单元卡「对标剧情参照」剧情单元的节拍与兑现方式设计钩子链;多对标书时参 `references/cross-book-recall.md`,副对标同基调 `章节/*_摘要.md` 仍可作单章钩子灵感(可选)
**章节标题规则**:只做轻量去重;发现同名或明显重复标题时,按本章核心事件改名,并保持细纲标题与正文文件名一致。
**细纲后设定补全(每批细纲建完后执行)**:扫描本批细纲新出现的具名角色/势力/关键设定,对**会复用**的(按卷纲/细纲判断:后续多次出场或承担剧情功能)自动建档,不等用户确认:
- 角色 → 建 `设定/角色/{名}.md`(填空模板见 character-basics.md 主角卡/配角卡);核心复用角色真正进入正文后,由追踪事务建立 `追踪/角色状态/{名}.md` 动态快照;
- 势力/组织 → 建 `设定/势力/{名}.md`(名称、定位、核心目标、关键人物、与主角关系);
- 影响多章的世界观规则 → 建/补 `设定/世界观/{主题}.md`(规则、适用范围)。
已存在的设定文件按细纲新信息**增量补充、不覆盖**。一次性路人、后文无戏份的配角不建静态档案或动态快照。建档只填细纲已确定的信息,未定字段留占位符,不提前杜撰。
大纲完成后,创建以下 artifact(加载 [references/artifact-protocols.md](artifact-protocols.md) 中对应模板):
- **大纲/大纲.md**:全书卷级鸟瞰(卷名+字数+章数+核心事件+状态变化,一段式汇总)
- **大纲/卷纲_第X卷.md**:每卷的剧情单元+情绪弧线(含章节定位)+人物弧线+伏笔+反转+对标结构坐标(参考 outline-methods.md「大纲三层结构法」 + outline-structure-theory.md「章节定位与张弛 / 对标节奏迁移」 + emotional-arc-design.md「六种弧线速查」 + long-reversal.md「反转类型」)
- **追踪事务初始状态**:按 `references/tracking-transaction.md` 构造第 0 章初始化 JSON,执行 `scripts/tracking_commit.py init`,生成检查点、续写状态卡(固定 7 栏)、空的伏笔/时间线视图与目录;紧接着运行 `check`,通过后删除初始化事务 JSON;核心角色动态快照可在第一次正文事务中创建
前 3 章细纲额外加载 [references/opening-design.md](opening-design.md)(黄金三章法则+六大标准)。
#### Agent 调用:story-architect
大纲搭建阶段优先由主会话产出卷纲+首批细纲;只有结构复杂、反转链多或主会话方案不稳时,才调用 story-architect agent。
当前端已部署 story-architect 时可让它辅助;Antigravity 调用规则同上:
- 任务:卷级结构、首批细纲、钩子/反转/情绪弧线。
- 章节定位:每章标高压/推进/修炼试错/关系回收/低压生活/信息整理;低压章可弱爽点,但仍要有往下看的理由。
- 目标字数:只填写章级 `字数目标` 与 `visible_chars_v1` 口径;情节点不分配精确字数,也不让模型心算容量。
- 主会话校验:按既有细纲流程复核目标、核心字段、可执行情节点和 `[待补充]`;本阶段不把语义判断复制进多端 Hook。
- **契约摘要必须原样附带**:本阶段的卷纲要直接产出终局储备(本卷主推线/战果、本卷解锁的终局里程碑、禁碰的未解锁底牌)和剧情单元(单元ID等字段),spawn prompt 必须带上 Phase 1「Agent 调用:story-architect」中的「story-architect 契约摘要」,让主线程与委托产出共用同一 schema。
如 agent 不可用,由主线程直接执行。
references/writing-craft.md›
# 写作技法:可执行指令集
> 6 个写作技法的 agent 可执行指令。写作全程参考。
---
**本文件职责**(其他内容去哪看):
- 本文件只管「贯穿道具的三次出现编排规则」,不管「羁绊铺设」(羁绊功能见 emotional-methods.md)
- 对话相关(含权力博弈的规则/模式/示例/操作指令)一律见 dialogue-mastery.md,本文件不重复
- 本文件只管「开头事件密度指令」,不管「开头设计」(开头设计见 opening-design.md)
- genre-prose-cards.md 提供题材声线与长线约束;本文件的「贯穿道具系统」提供跨章可执行设计模板
- 本文件第 8 节「场景写法(三维度揉进)」是 Phase 3 的写作方法,`long-format.md` 负责长篇章节的段落、对话与工程元信息规范
- 本文件「贯穿道具系统」只规定物件的三次出现编排时机和意义翻转规则;物件的初始情感含义设计(选什么物件、承载什么羁绊)由 emotional-methods.md 负责(信物型物件与羁绊铺设功能重叠,但视角不同)
---
## 1. 情绪落地:不把身体微动作当默认答案
### 规则
情绪没有固定译法。上下文已经让读者感到,就不另补反应;情绪推动了剧情,就优先写角色的选择、台词、策略、关系变化、物件变化或实际后果;一句直写最准确时可以直写("他听烦了")。身体状态只是候选之一,只有它带来新信息、影响动作,或确实属于这个角色和这个场景时才写。
### 落地顺序
写到情绪节点时按下面顺序判断,不做“情绪词逐个替换”:
1. **上下文已经成立**:前面的冲突、对话或结果足够让读者看懂,删掉补充说明,不再加一个动作尾巴。
2. **情绪改变下一步**:写角色因此说了什么、没说什么、选了哪条路、改了什么策略、付了什么代价。
3. **场内事物能承载变化**:写正在处理的合同、药、饭、门、消息、工具出了什么变化;物件必须来自当前场景,不临时搬一只茶杯来表演情绪。
4. **身体确实受影响**:写动作失败、疼痛、失衡、伤势或可见后果。只有“指尖动一下、指节白、嘴唇抿、目光移开、呼吸一顿”而没有后果,通常可以删。
5. **直写更准更省**:低强度或过场情绪可以一句直写,不必为避开一个普通情绪词绕成三十字表演。
同一节点只取最有信息量的一种,除非情绪升级确实产生连续后果,不把“动作 + 身体 + 比喻 + 心理解说”叠成四重注释。
### 好细节的功能
| 情况 | 处理 |
|------|------|
| 上下文已显出不耐烦 | 直接进入下一句对话,或一句“他听烦了”带过 |
| 愤怒使谈判改变 | 写他撤回报价、叫停合作或当面追问;变化比攥拳更有信息 |
| 紧张妨碍正在做的事 | 可以写笔尖划坏签名、钥匙插错锁孔等具体后果 |
| 身体细节只是在句尾标注情绪 | 删除;不要换一套部位或同义动作 |
### 反套话四问
逐章检查重点情绪段,并指出对应原句;不是要求每段补一种反应:
1. 删掉这处身体/语气细节,信息、选择、关系或物理结果有损失吗?没有就删。
2. 换个人名、换个房间仍然成立吗?成立说明它可能是通用表演,不是角色细节。
3. 本章是否反复出现“部位 + 轻微动作/状态 + 一下”,尤其指尖、指节、目光、嘴唇、呼吸、袖口?命中后回到整段重写或删除,不做同义词轮换。
4. 同一情绪是否已经被对话、上下文和动作重复解释?只留最有力的一处。
---
## 2. 贯穿道具系统(三次出现规则)
### 规则
每个叙事单元(短篇/长篇卷)设计 1-2 个贯穿道具。每个物件必须出现 3 次,每次意义不同。
### 三次出现编排
| 出现时机 | 功能 | 示例 |
|----------|------|------|
| 第 1 次出现(前 1/4) | 建立初始意义 | 金锁 = 姐姐送的生日礼物(温暖) |
| 第 2 次出现(中段转折) | 意义被颠覆 | 金锁 = 金包铜的假货(虚伪) |
| 第 3 次出现(结尾) | 情感暴击 | 金锁被丢进垃圾桶(彻底决裂) |
### 物件设计模板
填写以下模板,写入设定.md:
```
物件:{名称}
第1次出现:第{N}节 | {场景} | 含义:{初始意义}
第2次出现:第{N}节 | {场景} | 含义:{转折意义}
第3次出现:第{N}节 | {场景} | 含义:{结尾意义}
```
### 物件类型速查
| 类型 | 特征 | 代表 |
|------|------|------|
| 信物型 | 承载关系的象征物 | 金锁(姐夫捎路)、木头小马(皇弟) |
| 工具型 | 日常使用的功能性物件 | 打分本(准儿媳)、账本(迟来二十年) |
| 痕迹型 | 残留的身体/环境痕迹 | 手腕旧疤、墙上身高刻度 |
| 数字型 | 承载关系的具体金额/年限 | 八万块账单、二十年、800 块 |
---
## 3. 对话中的权力博弈
对话权力博弈的完整技法(对话长度=权力地位、压制/反转/心死三种模式、示例、≤10字/≥20字操作指令)见 dialogue-mastery.md「权力博弈对话」,本文件不重复。结构化用法:在场景编排时,把权力反转放在爽点/反转节点上,用对话长度的突变标记权力易主。
---
## 4. 数字/金额作为叙事工具
### 规则
用具体数字替代模糊描述。数字承载情感重量,数字变化推动情节。
### 操作指令
| 场景 | 操作 | 示例 |
|------|------|------|
| 建立重量 | 用具体金额/年限替代「很久」「很多」 | 「相恋八年」不是「在一起很久」 |
| 伤害递增 | 数字逐次增大 | 800 → 1000 → 8 万 → 120 万 |
| 反差暴击 | 极端膨胀后骤降到极小值 | 「我姐为了供我读书,欠了八万块。我姐夫转给我一块钱。」 |
| 时间重量 | 用年限承载情感 | 「二十年了,她第一次叫我妈」 |
### 数字叙事模板
```
数字线:
第{N}节 | {数字1} | 含义:{初始}
第{N}节 | {数字2} | 含义:{升级}
第{N}节 | {数字3} | 含义:{暴击/反转}
```
---
## 5. 动静有起伏,不按节配额
### 规则
一章整体要有推进与停顿的起伏,但不要求每个小节各塞一个“动”和“静”。停顿可以来自信息悬置、对话空白、环境压力或角色暂不行动,不等于安排擦灰、理衣领一类微小动作。
### 动与静的分类
| 类型 | 内容 | 示例 |
|------|------|------|
| 动 | 物理冲击、暴力、冲突爆发 | 砍人、摔东西、打耳光、吐血、掀桌子 |
| 静 | 信息悬置、对话空白、环境压力、等待或必要的日常过程 | 回信迟迟没来、全桌没人接话、雨声盖住门外脚步 |
### 操作指令
- 按整章和场景需要安排动静,不给每个小节设数量指标
- 连续多节全「动」时复核是否造成暴力疲劳;追逐/战斗有意连续可保留
- 连续多节全「静」时复核是否停滞;等待/压迫有意延长可保留
- 情绪高低不对应固定动作类型:爆点可以突然安静,低谷也可以持续劳动
### 节奏编排示例
```
节5(动):萧衍一声令下,打了萧琅二十棍
节6(静):报数停了,殿里没人替萧琅求情
节7(动):王氏扑过来,跪在地上磕头
节8(静):王氏跪在原地,只听见宫门落锁
```
---
## 6. 开头事件密度
### 规则
前 100 字必须包含 ≥ 3 个事件。不做背景铺垫,直接上事件链。
### 操作指令
- 删除所有开头背景介绍(「在古代XX年间」「她是一个XX的女孩」)
- 第 1 句就是事件,不是描述
- 事件密度检查:数前 100 字里有几个独立的「发生的事」
### 事件密度示例
```
❌ 低密度(1 件事/100 字):
「沈栀是沈家的嫡女,自幼聪慧,深得父亲喜爱。这一天,她收到了一道圣旨。」
✅ 高密度(4 件事/50 字):
「萧衍回朝那天,母后已经死了,儿子被他皇弟打成痴傻,他提刀就进了宫。」
(回朝 → 母死 → 子被虐 → 打人,4 件事)
```
密度指一段里发生几件事,不是把一件事拆成一句一句、句句断开;上例用逗号把四件事连成一句,照样是高密度。
### 密度检查模板
写完开头后,列出前 100 字的事件清单:
```
事件1:{事件}
事件2:{事件}
事件3:{事件}
(如果列出 < 3 个,重写开头)
```
---
## 7. 小节密度诊断
### 规则
写完一个小节如果感觉偏短,用以下诊断清单排查。不要为了凑字数加描写。
### 诊断清单
小节写完后偏短?按顺序检查:
| 检查项 | 偏短原因 | 补救 |
|--------|----------|------|
| 关键子事件读得懂吗? | 现场、因果或角色下一步缺了必要信息 | 只补真正缺失的维度;不为凑齐三项补感官或身体动作(见第8节) |
| 对话只有 1-2 轮? | 缺少对话交锋 | 加一轮权力博弈对话(见第3节) |
| 情绪信息落地了吗? | 只贴标签,或又用无功能微动作重复解释 | 优先落到选择、台词、物件和后果;必要时直写,身体细节须有功能(见第1节) |
| 仍偏短且关键 beat 写薄? | 冲突、选择、代价或关系变化没有演到位 | 回到细纲内已有事件补交锋与后果;没有内容就补纲,不拿感官/回忆注水 |
### 子事件不够时怎么扩
写 outline 时子事件不够?按以下顺序选择:
```
IF 主事件是冲突/对抗 → 加「阻碍」:主角被中途打断或阻止
IF 主事件涉及配角 → 加「反应」:配角的意外反应
IF 主事件有空间移动 → 加「发现」:移动途中发现新线索
IF 主事件触发回忆 → 加「倒叙」:插入一段 2-3 句的简短回忆
IF 主事件是一连串动作 → 加「递进」:动作引发的连锁反应
```
### 任务卡点:只在“办事本来会卡住”时使用
任务卡点不是多写流程,也不是为了显得自然;它是让角色想办成一件具体事时被卡住一下,并卡出变化。
判断句:角色本来就要办这件事 → 这一步被卡住 → 角色选择/付代价 → 卡出信息、关系、代价、选择或伏笔变化。
可用时机:
- 主事件是对抗:卡点暴露对手权力、规则漏洞或隐藏后手。
- 主事件是查证:卡点逼出新证据、新证人或新信息差。
- 主事件是关系推进:卡点逼角色表态、帮忙、拒绝或背叛。
- 主事件是低压过场:卡点只作轻阻力,服务关系、伏笔或生活质感,不喧宾夺主。
删掉试试:删掉后没有信息、情绪、关系、代价或伏笔损失,就不是有用卡点;不要为了显得自然或凑字数去补流程。
### 反注水规则
以下行为禁止:
- 为凑字数加环境描写("窗外阳光明媚")
- 为凑字数重复已表达的情绪
- 为凑字数加角色内心独白总结
- 为凑字数让角色做无意义的动作
- 为显得自然而加流程细节;删掉无损就删
- 为凑字数重复解释情绪,或给每段补一个无功能身体反应
---
## 8. 场景写法(三维度揉进)
### 从细纲到正文:把规格演成场景,不照抄形状
细纲各字段是本章"要发生什么"的规格,**不是正文的形状**。照着细纲的形状逐格填,正文就成了一条一条交代的电报体、一拍一句平推的生硬解说——这是"照抄大纲形状",和照抄范例形状同属 AI 味来源。
- 情节点序列是"要发生什么"的清单,不是句子模板:不要一个情节点写成一句或一段、按序平推;把每个点演成角色此刻可感知的选择、动作、对话、物件、结果,必要时才用身体反应——**演出来,不是交代出来**。
- 同一约束如果在「核心事件 / 内容概括 / 情节安排 / 情节点」里重复出现,生成前只合并成**一个语义点**;重复字段不是强调,更不是四次复述额度。正文不得沿用提纲里反复出现的同一措辞逐项交代。
- 五段式(起因/发展/转折/高潮/结尾)是给细纲作者的功能拆解,不是正文的五个自然段;正文不必逐段顺叙,也不必一段对一格。
- "谁做了什么"的概括句、"A→B→C"箭头链、"收束到什么状态"是规划口径,不要原样搬进叙述。
- 情节点之间可以合并、穿插、重排,让相邻的点织进同一个连续场景;密点展开成慢镜头,疏点带过(见「疏密分配」)。
- 章尾落在最后一个具体的动作、画面、台词或悬念上;细纲「结尾设定/收束状态」是规划口径,不要在正文里写成"就这样……""他终于明白……"式的状态总结句(结尾去升华见 anti-ai-writing.md)。
### 视角姿态:深度限知(贴地沉浸)
三维度揉进之前,先定叙述姿态。默认锁死主视角角色的"此刻感知"——只写他此刻看到、听到、闻到、身体感到、脑中闪过的东西。这一条同时解决两个最顽固的 AI 味:代入感不足,和"作者在场"的说教/上帝腔。
- **镜头不拉远、不俯瞰、不切他人内心**:别写"整个大厅陷入死寂"这种摄像机视角,写"她听见自己的心跳,旁边的呼吸声一下子全没了"。
- **读者与角色同步获知**:角色不知道的不写;不提前剧透,不补全背景。悬念来自"她也不知道",禁止提前剧透句如"她不知道的是"。
- **念头是动作的一部分**:心理用"闪念 + 身体"呈现——半句的、被打断的、带情绪偏见的主观判断,不写完整理性的内心独白。
- **主观偏差代替客观叙述**:场景被角色情绪染色。她恨谁,谁就被写得可憎;她慌,光线就晃。不写中立的、谁看都一样的描述。但只能是她此刻带偏见的瞬间感觉,不能写成"像在宣判一件早已定好的事"这类客观盖棺断言(那是作者下场定性,见 anti-ai-writing.md 模式 8)。
深度限知是"自然去 AI"的根:把镜头钉死在角色身体里,作者就没有位置跳出来解释、总结、安排了(配合 anti-ai-writing.md 模式 8)。
### 文风指纹:按题材借 cadence,不套万能腔
不同题材的真实文风 cadence 会影响读感;有效写法不同。男频/军旅可以借旧网文连贯叙事惯性,现代日常可写普通任务推进;悬疑、科幻、古代不要硬套盘龙腔、旧网文腔或第一人称声口,先读本书 `设定/文风.md`、对标拆文和匹配章摘要。
落地顺序:先按本章情绪和题材文风写顺,再处理解释总结、过度压缩和比喻堆叠;不要把句子机械拉长/压短,也不要全局替换成某个对标书的词法。
### 规则
关键子事件不能只剩一句提纲概括。发生是主干;感知和反应只在提供新信息时加入,并与发生织进同一镜头,不按维度分段,也不要求三项齐全。
### 三维度揉进规则
发生、感知、反应是可选的信息维度,不是逐段配额。详写的关键子事件可以把其中确有内容的维度织在同一镜头里;上下文已经清楚的维度留空,不为凑齐三项补感官或身体动作。过场、赶路、信息交代类子事件 1-2 句带过即可(见「疏密分配」),把字数预算让给情绪节点。
| 维度 | 内容 | 要点 |
|---|---|---|
| 发生 | 事情出现了 | 1-2句,包含一个具体细节 |
| 感知 | 主角注意到什么 | 只取会改变理解、判断或气氛的一处声音、物件、空间或身体感受,不按感官凑数 |
| 反应 | 角色接下来怎么办 | 可以是选择、台词、策略、任务动作、明确感受或有后果的身体反应,不默认写微动作 |
任务卡点写法可从三维中取需要的内容:发生 = 事情办不下去;感知 = 被退回的纸、扣住的物件、对方半句话等具体凭据;反应 = 角色改策略、付代价、求助、硬闯、退让或记下一笔。不要把“为什么被卡住”解释成一段说明书,也不要在 scene 末尾另补动作尾巴来解释意义。
### 反模式:堆叠式描写(绝对禁止)
把三个维度分成三段依次写完,是 AI 最常见的写作痕迹。读者看到的是同一个动作被掰开写了三遍:
> ❌ **堆叠式(错误)**:
> 林父低着头,左手把文书压住,右手拿笔,往纸上落。
>
> 手在抖。
>
> 手从肘到腕都在抖,笔尖在纸上停了停,写了一横,又停,那个"林"字的撇写歪了,他顿了顿,把笔往下压,重写,写完了,笔在手里还是没稳。
→ 一件事写成发生→感知→反应三段,同一个动作掰开三遍
### 正确写法:揉进式
需要的维度融进同一段连续正文,读者读到一个完整瞬间:
> ✅ **揉进式(正确)**:
> 林父左手压着文书,右手拿笔往纸上落,笔尖一触纸面就偏了,从肘到腕止不住地抖,那一横斜着拖出去。他顿了顿,把笔往下压,重写,写完的"林"字撇是歪的,笔在手里还是没稳住。
→ 这里的身体反应改变了落笔结果,承担信息;不是为了证明人物紧张而另加微动作
### 自检方法
对详写的关键场景用“三维遮盖法”:分别遮住发生、感知、反应,判断现有内容是否各自提供了不同信息。某维缺失不等于要补;只有读者因此看不懂现场、因果或角色下一步时,才把缺失信息织回同一镜头。若遮住一处身体/语气细节后什么也没损失,删掉它。逐章再做第 1 节“反套话四问”,指出原句处理,不用“已遵守”代替检查。
### 画面分段(防止一段到底)
三维度揉进不是把一个子事件塞进一个长段。揉进解决"同一瞬间被拆成发生/感知/反应三段"的问题;断段解决"手机阅读时一段过密"的问题。
断段按镜头/信息变化,不按维度变化:
| 触发点 | 断段方式 |
|---|---|
| 新动作开始 | 另起一段,让读者看到下一拍 |
| 新物件/线索出现 | 另起一段,单独承载这个信息 |
| 角色视线转移 | 另起一段,形成镜头切换 |
| 直接引语出现 | 对话独立成段 |
| 心理定格/判断落下 | 可以单句成段,制造停顿 |
判定规则:
- 一段只承载一个镜头拍点/一个动作单元,或一条尚未结束的连续推理、氛围、情绪链。
- 常规叙事段可短,但句子内部不碎——叙述句不要一个动作一句号、句句断开(叙述默认逗号长句,详见 anti-ai-writing.md 规则 3);细密描写、推理判断、氛围压迫、情绪沉淀可以稍长,前提是仍在讲同一件事。
- 长度只是诊断,不是强制阈值:读起来拥挤、包含多个动作/信息/视线切换时才拆;完整戏剧单元未结束时不要为凑短而硬拆。
- 常规正文保持短段、稍长段、对话、动作段交替;高压冲突、打脸、反转段可以更碎更短。
- 不要连续多段同长度,也不要把一个完整推理链切成机械碎片。
输出前必须做一次自然节奏重排:
1. 扫描每个自然段;先问“这段是否只完成一件事/一个镜头/一条推理或情绪链”。是则保留,不因字数单独拆。
2. 若同段里出现新动作、新物件、新信息、新对话、视线转移、场景结束,就在这些位置断段。
3. 若连续多个极短段仍属于同一镜头/同一件事,合并相邻句,避免碎成提纲或诗行。
4. 若一个长句朗读卡顿或信息过载,先删修饰或拆句;拆句后仍保持同一段的戏剧单元完整。
### 主语与名字节奏(防止“主语过密”)
主角名/角色名承担“主语重置”和“强调”功能,不承担每句打标签的功能:
- 段首、场景切换、多人同场、视角重置时,用主角名建立主语。
- 同一动作链/同一段内部,优先用“他/她”、动作承接或省略主语,让句子自然流动。
- 关键转折、情绪爆点、身份反差、读者需要重新盯住主角时,再点名强化。
- 反面信号:连续多句或连续多段都以同一主角名开头,但中间没有主语混淆、场景切换或强调需要。
- 不按全章名字出现次数机械裁判;最终标准是读起来是否有“每句都在报名字”的卡顿感。
错误修法:为了短,把一条完整推理/氛围链切成多段;为了省主语,把多人同场写到指代不清。
正确修法:保留同一件事的连续性,在新动作、新物件、新信息、新对话处断开;段首点名建立主语,段中用代词/省略流动,关键转折再点名。
### 疏密分配(详略不均)
不要每个 beat 一样长、一样细——平均用力是 AI 腔的根源,也是读起来"哪都写得满、哪都不出彩"的原因。按情节权重分配笔墨:
| beat 类型 | 笔墨 | 写法 |
|---|---|---|
| 爽点/打脸/反转/情绪高潮 | 密(详写) | 感知、动作、对话交锋铺满,慢镜头逐拍展开 |
| 过场/赶路/信息交代/时间跳转 | 疏(略写) | 1-2 句带过,甚至一句概括,不展开三维度 |
| 铺垫/日常/关系升温 | 中 | 挑一两个有代入感的细节写实,其余略 |
原则:一章里详写的 beat 集中在情绪节点,过场坚决压缩。读者记住的是密处的画面,疏处只是把他们快速送到下一个爽点。密度有起伏,节奏才有呼吸。
### 子事件连接
子事件之间按真实关系连接:因果推进、对话接招、新信息、空间移动或角色下一步都可以;不规定必须插入身体动作,也不规定连接句长度。
- ❌ 为了过渡另补“我把账本搁在膝盖上,手心出了一层薄汗。”
- ✅ “最后一笔支出没有收据,下一页却夹着他的签名。”(新信息直接推动下一拍)
### 感知素材库
| 场景类型 | 可用的感知细节 |
|---|---|
| 阅读/翻看 | 字迹深浅、纸张触感、墨水洇开、页角卷曲 |
| 对话场景 | 对方表情变化、语气停顿、空气里的沉默 |
| 回忆场景 | 画面中的某个细节突然清晰(气味/声音/触感) |
| 室内场景 | 光线变化、物品的位置、温度 |
| 移动场景 | 脚步声、地面的触感、风的方向 |
### 三维度的边界
- ✓ 感知是主角主动注意到的细节(有注意力的焦点)
- ✓ 反应是角色受此影响后的下一步,可落在选择、台词、策略、任务动作、明确感受或有后果的身体变化
- ✗ 感知不能是装饰性场景描写("阳光洒在窗台上")
- ✗ 反应不能只用无功能微动作给已经清楚的情绪再贴一次标签
- ✗ 三个维度不能重复表达同一个信息
---
## 9. 语气标点谱系(标点跟着语气走)
### 规则
标点承担语气、权力关系和情绪节拍,不能当装饰。写正文时先判断“这句话在场景里做什么”,再决定用句号、逗号、问号、感叹号、冒号或换行/动作 beat;不再用省略号和破折号制造停顿。
### 标点谱系
| 语气 / 功能 | 可用标点 | 操作指令 | 禁忌 |
|---|---|---|---|
| 压迫 / 冷静 / 克制 | 句号、逗号、冒号、短句 | 用不动声色的陈述压迫,用冒号落判断;少解释 | 不要为了“有变化”乱加 `!` |
| 质问 / 试探 / 反问 | 问号、短跟句、动作停顿 | 关键问题用 `?`,追问可短句独立成行 | 不要连续 5 句全是 `?` |
| 惊讶 / 爆发 / 打脸 | 少量感叹号、单句成段 | 只在情绪峰值用 1 个 `!`,爆点前后用短句承接 | 禁止 `!!!` 和整段喊叫 |
| 犹豫 / 未说完 / 心虚 | 逗号、句号、短句、吞咽/停手等动作 | 用动作或句长变化停顿;必要时另起短句 | 不用 `……` 替代停顿 |
| 被打断 / 拖长音 | 动作打断、换行、短句、未完成动作 | 用“他抬手截住她的话。”这类动作切断 | 正文和对话都不用 `——`/`—`/`--` |
| 信息揭示 / 判断落点 | 冒号、分号、短句 | “证据只有一个:门锁从里面扣上了。”可用冒号制造落点 | 不写论文式长分号链 |
### 执行步骤
1. 读本场景目标情绪和角色声线,给每个关键对话 beat 标一类语气(压迫/试探/爆发/迟疑/被打断)。
2. 精修时扫一遍句尾:如果一整段只剩句号,检查是否把质问、迟疑、爆点压平;如果满屏 `?`/`!`,删到只保留有功能的位置。
3. 正文(含对话)里的 `……`、`——`、`—`、`--` 都改成句号、逗号、短句、换行或动作断句。知乎盐言 `「」` 只是引号风格,不影响问号、感叹号的合法使用。
scripts/author_memory_commit.py›
#!/usr/bin/env python3
"""Maintain evidence-backed author preferences and deterministic Markdown views.
The language model supplies compact semantic transactions. This tool validates
and applies them in memory, renders every derived view, and writes the JSON state
last as the commit point. Author memory is workspace-level and deliberately
separate from each book's story-continuity tracking.
"""
from __future__ import annotations
import argparse
import copy
import hashlib
import json
import os
import stat
import sys
import tempfile
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
INPUT_SCHEMA_VERSION = 1
STATE_SCHEMA_VERSION = 1
STATE_MAX_BYTES = 2 * 1024 * 1024
PROFILE_MAX_BYTES = 12288
PENDING_MAX_BYTES = 12288
JOURNAL_MAX_BYTES = 24576
QUERY_MAX_BYTES = 2048
KINDS = ("prose_style", "story_design", "workflow", "delivery", "interaction")
KIND_TITLES = {
"prose_style": "文风与表达",
"story_design": "故事设计",
"workflow": "创作流程",
"delivery": "交付格式",
"interaction": "协作方式",
}
SCOPE_LEVELS = ("global", "genre", "book", "workflow")
STATUSES = ("active", "pending", "conflict", "rejected", "superseded")
CONFIDENCE_LEVELS = ("low", "medium", "high")
IMPORTANCE_LEVELS = ("low", "medium", "high")
SOURCES = (
"explicit_user",
"accepted_suggestion",
"repeated_correction",
"inferred_pattern",
"manual",
)
RANK = {"low": 0, "medium": 1, "high": 2}
class AuthorMemoryError(ValueError):
"""Expected validation or state error."""
def require(condition: bool, message: str) -> None:
if not condition:
raise AuthorMemoryError(message)
def as_mapping(value: object, label: str) -> dict[str, Any]:
require(isinstance(value, dict), f"{label} must be a JSON object")
return value
def as_list(value: object, label: str) -> list[Any]:
require(isinstance(value, list), f"{label} must be a JSON array")
return value
def as_int(value: object, label: str, *, minimum: int = 0) -> int:
require(isinstance(value, int) and not isinstance(value, bool), f"{label} must be an integer")
require(value >= minimum, f"{label} must be >= {minimum}")
return value
def require_known_keys(mapping: dict[str, Any], allowed: set[str], label: str) -> None:
unknown = set(mapping) - allowed
require(not unknown, f"{label} contains unsupported fields: {', '.join(sorted(unknown))}")
def clean_text(value: object, label: str, *, max_bytes: int = 768) -> str:
require(isinstance(value, str), f"{label} must be a string")
cleaned = " ".join(value.replace("|", "|").split())
require(bool(cleaned), f"{label} must not be empty")
require(len(cleaned.encode("utf-8")) <= max_bytes, f"{label} exceeds {max_bytes} bytes")
return cleaned
def optional_text(value: object, label: str, *, max_bytes: int = 768) -> str | None:
if value is None:
return None
return clean_text(value, label, max_bytes=max_bytes)
def choice(value: object, allowed: tuple[str, ...], label: str) -> str:
require(isinstance(value, str) and value in allowed, f"{label} must be one of: {', '.join(allowed)}")
return value
def clean_id_list(value: object, label: str, *, maximum: int = 32) -> list[str]:
raw = as_list(value, label)
require(len(raw) <= maximum, f"{label} may contain at most {maximum} items")
result: list[str] = []
for index, item in enumerate(raw):
item_id = clean_text(item, f"{label}[{index}]", max_bytes=32)
require(item_id.startswith("AP") and item_id[2:].isdigit() and int(item_id[2:]) >= 1, f"{label}[{index}] is not an author-memory id")
if item_id not in result:
result.append(item_id)
return result
def emit(document: object, *, error: bool = False) -> None:
payload = json.dumps(document, ensure_ascii=False, sort_keys=True)
stream = sys.stderr if error else sys.stdout
stream.flush()
stream.buffer.write((payload + "\n").encode("utf-8"))
stream.buffer.flush()
def json_payload(document: object) -> str:
return json.dumps(document, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
def read_json(path: Path) -> object:
try:
require(path.stat().st_size <= STATE_MAX_BYTES, f"{path} exceeds {STATE_MAX_BYTES} bytes")
return json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise AuthorMemoryError(f"unable to read JSON {path}: {exc}") from exc
def atomic_write_text(path: Path, payload: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
mode = stat.S_IMODE(path.stat().st_mode) if path.exists() else 0o644
fd, temporary_name = tempfile.mkstemp(prefix=f".{path.name}.", suffix=".tmp", dir=path.parent)
temporary = Path(temporary_name)
try:
with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as handle:
handle.write(payload)
handle.flush()
os.fsync(handle.fileno())
os.chmod(temporary, mode)
os.replace(temporary, path)
finally:
temporary.unlink(missing_ok=True)
def write_if_changed(path: Path, payload: str) -> None:
try:
if path.read_text(encoding="utf-8") == payload:
return
except FileNotFoundError:
pass
atomic_write_text(path, payload)
def memory_root(workspace: Path) -> Path:
return workspace.resolve() / ".story" / "作者记忆"
def state_path(workspace: Path) -> Path:
return memory_root(workspace) / "_author-memory-state.json"
def empty_state() -> dict[str, Any]:
return {
"schema_version": STATE_SCHEMA_VERSION,
"state_revision": 0,
"next_item_number": 1,
"items": {},
"journal": [],
"applied_transactions": {},
}
def normalize_scope(value: object, label: str) -> dict[str, str | None]:
scope = as_mapping(value, label)
require_known_keys(scope, {"level", "value"}, label)
level = choice(scope.get("level"), SCOPE_LEVELS, f"{label}.level")
raw_value = scope.get("value")
if level == "global":
require(raw_value is None, f"{label}.value must be null for global scope")
normalized_value = None
else:
normalized_value = clean_text(raw_value, f"{label}.value", max_bytes=180)
return {"level": level, "value": normalized_value}
def normalize_evidence(value: object, label: str) -> dict[str, str | None]:
evidence = as_mapping(value, label)
require_known_keys(evidence, {"quote", "source_ref"}, label)
return {
"quote": clean_text(evidence.get("quote"), f"{label}.quote", max_bytes=768),
"source_ref": optional_text(evidence.get("source_ref"), f"{label}.source_ref", max_bytes=240),
}
def normalize_item(value: object, label: str) -> dict[str, Any]:
item = as_mapping(value, label)
allowed = {
"id", "kind", "scope", "assertion", "confidence", "importance", "status", "source",
"reason", "conflicts_with", "confirmation_count", "evidence", "created_revision",
"updated_revision", "superseded_by",
}
require_known_keys(item, allowed, label)
item_id = clean_text(item.get("id"), f"{label}.id", max_bytes=32)
require(item_id.startswith("AP") and item_id[2:].isdigit() and int(item_id[2:]) >= 1, f"{label}.id is invalid")
evidence = [normalize_evidence(entry, f"{label}.evidence[{index}]") for index, entry in enumerate(as_list(item.get("evidence"), f"{label}.evidence"))]
require(bool(evidence), f"{label}.evidence must not be empty")
status = choice(item.get("status"), STATUSES, f"{label}.status")
conflicts = clean_id_list(item.get("conflicts_with"), f"{label}.conflicts_with")
superseded_by = optional_text(item.get("superseded_by"), f"{label}.superseded_by", max_bytes=32)
if superseded_by is not None:
require(superseded_by.startswith("AP") and superseded_by[2:].isdigit(), f"{label}.superseded_by is invalid")
return {
"id": item_id,
"kind": choice(item.get("kind"), KINDS, f"{label}.kind"),
"scope": normalize_scope(item.get("scope"), f"{label}.scope"),
"assertion": clean_text(item.get("assertion"), f"{label}.assertion", max_bytes=768),
"confidence": choice(item.get("confidence"), CONFIDENCE_LEVELS, f"{label}.confidence"),
"importance": choice(item.get("importance"), IMPORTANCE_LEVELS, f"{label}.importance"),
"status": status,
"source": choice(item.get("source"), SOURCES, f"{label}.source"),
"reason": clean_text(item.get("reason"), f"{label}.reason", max_bytes=480),
"conflicts_with": conflicts,
"confirmation_count": as_int(item.get("confirmation_count"), f"{label}.confirmation_count", minimum=1),
"evidence": evidence,
"created_revision": as_int(item.get("created_revision"), f"{label}.created_revision", minimum=1),
"updated_revision": as_int(item.get("updated_revision"), f"{label}.updated_revision", minimum=1),
"superseded_by": superseded_by,
}
def validate_state(value: object) -> dict[str, Any]:
state = as_mapping(value, "state")
allowed = {"schema_version", "state_revision", "next_item_number", "items", "journal", "applied_transactions"}
require_known_keys(state, allowed, "state")
require(state.get("schema_version") == STATE_SCHEMA_VERSION, f"state.schema_version must be {STATE_SCHEMA_VERSION}")
revision = as_int(state.get("state_revision"), "state.state_revision")
next_number = as_int(state.get("next_item_number"), "state.next_item_number", minimum=1)
raw_items = as_mapping(state.get("items"), "state.items")
items: dict[str, Any] = {}
max_number = 0
for raw_id, raw_item in raw_items.items():
normalized = normalize_item(raw_item, f"state.items.{raw_id}")
require(raw_id == normalized["id"], f"state.items key {raw_id} does not match item id")
max_number = max(max_number, int(raw_id[2:]))
require(normalized["created_revision"] <= normalized["updated_revision"] <= revision, f"state.items.{raw_id} revision is ahead of state")
items[raw_id] = normalized
require(next_number > max_number, "state.next_item_number must be greater than every allocated item id")
for item_id, item in items.items():
for conflict_id in item["conflicts_with"]:
require(conflict_id in items and conflict_id != item_id, f"state.items.{item_id} has an invalid conflict id")
if item["superseded_by"] is not None:
require(item["superseded_by"] in items and item["superseded_by"] != item_id, f"state.items.{item_id} has an invalid superseded_by id")
if item["status"] == "active":
require(not item["conflicts_with"], f"active item {item_id} cannot retain conflicts")
if item["status"] == "pending":
require(not item["conflicts_with"], f"pending item {item_id} cannot retain conflicts")
if item["status"] == "conflict":
require(bool(item["conflicts_with"]), f"conflict item {item_id} must reference an active item")
require(all(items[conflict_id]["status"] == "active" for conflict_id in item["conflicts_with"]), f"conflict item {item_id} must reference only active items")
if item["status"] != "superseded":
require(item["superseded_by"] is None, f"only superseded item {item_id} may set superseded_by")
journal = as_list(state.get("journal"), "state.journal")
require(len(journal) == revision, "state.journal length must equal state.state_revision")
journal_revisions: dict[str, int] = {}
for index, entry in enumerate(journal):
mapping = as_mapping(entry, f"state.journal[{index}]")
require_known_keys(mapping, {"revision", "transaction_id", "committed_at", "summaries"}, f"state.journal[{index}]")
entry_revision = as_int(mapping.get("revision"), f"state.journal[{index}].revision", minimum=1)
require(entry_revision == index + 1, f"state.journal[{index}].revision must be {index + 1}")
transaction_id = clean_text(mapping.get("transaction_id"), f"state.journal[{index}].transaction_id", max_bytes=128)
require(transaction_id not in journal_revisions, f"state.journal repeats transaction_id {transaction_id}")
journal_revisions[transaction_id] = entry_revision
clean_text(mapping.get("committed_at"), f"state.journal[{index}].committed_at", max_bytes=64)
summaries = as_list(mapping.get("summaries"), f"state.journal[{index}].summaries")
require(bool(summaries), f"state.journal[{index}].summaries must not be empty")
for summary_index, summary in enumerate(summaries):
clean_text(summary, f"state.journal[{index}].summaries[{summary_index}]", max_bytes=768)
transactions = as_mapping(state.get("applied_transactions"), "state.applied_transactions")
require(set(transactions) == set(journal_revisions), "state.applied_transactions must match state.journal transaction ids")
for transaction_id, record in transactions.items():
clean_text(transaction_id, "state.applied_transactions key", max_bytes=128)
mapping = as_mapping(record, f"state.applied_transactions.{transaction_id}")
require_known_keys(mapping, {"revision", "digest", "item_ids"}, f"state.applied_transactions.{transaction_id}")
transaction_revision = as_int(mapping.get("revision"), f"state.applied_transactions.{transaction_id}.revision", minimum=1)
require(transaction_revision == journal_revisions[transaction_id], f"state.applied_transactions.{transaction_id}.revision does not match journal")
digest = clean_text(mapping.get("digest"), f"state.applied_transactions.{transaction_id}.digest", max_bytes=64)
require(len(digest) == 64 and all(char in "0123456789abcdef" for char in digest), f"state.applied_transactions.{transaction_id}.digest is invalid")
item_ids = clean_id_list(mapping.get("item_ids"), f"state.applied_transactions.{transaction_id}.item_ids")
require(bool(item_ids), f"state.applied_transactions.{transaction_id}.item_ids must not be empty")
require(all(item_id in items for item_id in item_ids), f"state.applied_transactions.{transaction_id}.item_ids references an unknown item")
return {
"schema_version": STATE_SCHEMA_VERSION,
"state_revision": revision,
"next_item_number": next_number,
"items": items,
"journal": copy.deepcopy(journal),
"applied_transactions": copy.deepcopy(transactions),
}
def normalize_preference(value: object, label: str, *, allow_status: bool) -> dict[str, Any]:
preference = as_mapping(value, label)
allowed = {"kind", "scope", "assertion", "quote", "source_ref", "source", "confidence", "importance", "reason"}
if allow_status:
allowed |= {"status", "conflicts_with"}
require_known_keys(preference, allowed, label)
source = choice(preference.get("source"), SOURCES, f"{label}.source")
status = choice(preference.get("status"), ("active", "pending", "conflict"), f"{label}.status") if allow_status else "active"
conflicts = clean_id_list(preference.get("conflicts_with", []), f"{label}.conflicts_with") if allow_status else []
if status == "active":
require(not conflicts, f"{label}.conflicts_with must be empty for active status")
require(source not in {"repeated_correction", "inferred_pattern"}, f"{label} inferred evidence must remain pending")
elif status == "conflict":
require(bool(conflicts), f"{label}.conflicts_with is required for conflict status")
else:
require(not conflicts, f"{label}.conflicts_with is only valid for conflict status")
return {
"kind": choice(preference.get("kind"), KINDS, f"{label}.kind"),
"scope": normalize_scope(preference.get("scope"), f"{label}.scope"),
"assertion": clean_text(preference.get("assertion"), f"{label}.assertion", max_bytes=768),
"quote": clean_text(preference.get("quote"), f"{label}.quote", max_bytes=768),
"source_ref": optional_text(preference.get("source_ref"), f"{label}.source_ref", max_bytes=240),
"source": source,
"confidence": choice(preference.get("confidence"), CONFIDENCE_LEVELS, f"{label}.confidence"),
"importance": choice(preference.get("importance"), IMPORTANCE_LEVELS, f"{label}.importance"),
"status": status,
"reason": clean_text(preference.get("reason"), f"{label}.reason", max_bytes=480),
"conflicts_with": conflicts,
}
def normalize_transaction(value: object) -> dict[str, Any]:
transaction = as_mapping(value, "transaction")
require_known_keys(transaction, {"schema_version", "transaction_id", "expected_state_revision", "operations"}, "transaction")
require(transaction.get("schema_version") == INPUT_SCHEMA_VERSION, f"transaction.schema_version must be {INPUT_SCHEMA_VERSION}")
transaction_id = clean_text(transaction.get("transaction_id"), "transaction.transaction_id", max_bytes=128)
operations = as_list(transaction.get("operations"), "transaction.operations")
require(1 <= len(operations) <= 32, "transaction.operations must contain 1-32 operations")
normalized_operations: list[dict[str, Any]] = []
for index, raw_operation in enumerate(operations):
label = f"transaction.operations[{index}]"
operation = as_mapping(raw_operation, label)
action = operation.get("action")
if action == "remember":
require_known_keys(operation, {"action", "preference"}, label)
normalized_operations.append({"action": action, "preference": normalize_preference(operation.get("preference"), f"{label}.preference", allow_status=True)})
elif action == "decide":
require_known_keys(operation, {"action", "item_id", "decision", "quote", "reason"}, label)
normalized_operations.append({
"action": action,
"item_id": clean_id_list([operation.get("item_id")], f"{label}.item_id", maximum=1)[0],
"decision": choice(operation.get("decision"), ("activate", "reject"), f"{label}.decision"),
"quote": clean_text(operation.get("quote"), f"{label}.quote", max_bytes=768),
"reason": clean_text(operation.get("reason"), f"{label}.reason", max_bytes=480),
})
elif action == "replace":
require_known_keys(operation, {"action", "old_ids", "preference"}, label)
old_ids = clean_id_list(operation.get("old_ids"), f"{label}.old_ids")
require(bool(old_ids), f"{label}.old_ids must not be empty")
normalized_operations.append({"action": action, "old_ids": old_ids, "preference": normalize_preference(operation.get("preference"), f"{label}.preference", allow_status=False)})
elif action == "forget":
require_known_keys(operation, {"action", "item_id", "quote", "reason"}, label)
normalized_operations.append({
"action": action,
"item_id": clean_id_list([operation.get("item_id")], f"{label}.item_id", maximum=1)[0],
"quote": clean_text(operation.get("quote"), f"{label}.quote", max_bytes=768),
"reason": clean_text(operation.get("reason"), f"{label}.reason", max_bytes=480),
})
else:
raise AuthorMemoryError(f"{label}.action must be one of: remember, decide, replace, forget")
return {
"schema_version": INPUT_SCHEMA_VERSION,
"transaction_id": transaction_id,
"expected_state_revision": as_int(transaction.get("expected_state_revision"), "transaction.expected_state_revision"),
"operations": normalized_operations,
}
def normalize_record_event(value: object) -> dict[str, Any]:
event = as_mapping(value, "event")
require_known_keys(event, {"schema_version", "event_id", "operation"}, "event")
require(event.get("schema_version") == INPUT_SCHEMA_VERSION, f"event.schema_version must be {INPUT_SCHEMA_VERSION}")
event_id = clean_text(event.get("event_id"), "event.event_id", max_bytes=120)
normalized = normalize_transaction({
"schema_version": INPUT_SCHEMA_VERSION,
"transaction_id": f"record:{event_id}",
"expected_state_revision": 0,
"operations": [event.get("operation")],
})
return {"event_id": event_id, "operation": normalized["operations"][0]}
def transaction_digest(transaction: dict[str, Any]) -> str:
canonical = json.dumps(transaction, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
def fingerprint(preference: dict[str, Any]) -> str:
value = {
"kind": preference["kind"],
"scope": preference["scope"],
"assertion": preference["assertion"].casefold(),
}
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def allocate_item(state: dict[str, Any], preference: dict[str, Any], revision: int) -> dict[str, Any]:
item_id = f"AP{state['next_item_number']:03d}"
state["next_item_number"] += 1
return {
"id": item_id,
"kind": preference["kind"],
"scope": copy.deepcopy(preference["scope"]),
"assertion": preference["assertion"],
"confidence": preference["confidence"],
"importance": preference["importance"],
"status": preference["status"],
"source": preference["source"],
"reason": preference["reason"],
"conflicts_with": list(preference["conflicts_with"]),
"confirmation_count": 1,
"evidence": [{"quote": preference["quote"], "source_ref": preference["source_ref"]}],
"created_revision": revision,
"updated_revision": revision,
"superseded_by": None,
}
def best_level(first: str, second: str) -> str:
return first if RANK[first] >= RANK[second] else second
def add_evidence(item: dict[str, Any], quote: str, source_ref: str | None) -> None:
evidence = {"quote": quote, "source_ref": source_ref}
if evidence not in item["evidence"]:
item["evidence"].append(evidence)
def require_item(state: dict[str, Any], item_id: str, label: str) -> dict[str, Any]:
require(item_id in state["items"], f"{label} references unknown item {item_id}")
return state["items"][item_id]
def apply_remember(state: dict[str, Any], preference: dict[str, Any], revision: int) -> str:
for conflict_id in preference["conflicts_with"]:
conflict = require_item(state, conflict_id, "remember")
require(conflict["status"] == "active", f"remember conflict {conflict_id} must be active")
preference_fingerprint = fingerprint(preference)
for item in state["items"].values():
if item["status"] not in {"active", "pending", "conflict"} or fingerprint(item) != preference_fingerprint:
continue
require(not (item["status"] == "conflict" and preference["status"] == "active"), f"conflict item {item['id']} must be resolved with replace or rejected")
require(not (item["status"] == "active" and preference["status"] == "conflict"), f"active item {item['id']} cannot be recategorized as its own conflict")
add_evidence(item, preference["quote"], preference["source_ref"])
item["confirmation_count"] += 1
item["confidence"] = best_level(item["confidence"], preference["confidence"])
item["importance"] = best_level(item["importance"], preference["importance"])
item["updated_revision"] = revision
item["reason"] = preference["reason"]
if item["status"] == "pending" and preference["status"] == "active":
item["status"] = "active"
elif item["status"] == "pending" and preference["status"] == "conflict":
item["status"] = "conflict"
item["conflicts_with"] = list(preference["conflicts_with"])
elif item["status"] == "conflict" and preference["status"] == "conflict":
item["conflicts_with"] = sorted(set(item["conflicts_with"]) | set(preference["conflicts_with"]))
return f"强化 {item['id']}:{item['assertion']}"
item = allocate_item(state, preference, revision)
state["items"][item["id"]] = item
return f"新增 {item['id']}({item['status']}):{item['assertion']}"
def apply_decide(state: dict[str, Any], operation: dict[str, Any], revision: int) -> str:
item = require_item(state, operation["item_id"], "decide")
require(item["status"] in {"pending", "conflict"}, f"decide requires pending/conflict item, got {item['status']}")
if operation["decision"] == "activate":
require(item["status"] == "pending" and not item["conflicts_with"], "conflict candidates must be activated with replace")
item["status"] = "active"
verb = "确认"
else:
item["status"] = "rejected"
verb = "拒绝"
add_evidence(item, operation["quote"], None)
item["reason"] = operation["reason"]
item["updated_revision"] = revision
return f"{verb} {item['id']}:{item['assertion']}"
def apply_replace(state: dict[str, Any], operation: dict[str, Any], revision: int) -> str:
old_items = [require_item(state, item_id, "replace") for item_id in operation["old_ids"]]
for item in old_items:
require(item["status"] in {"active", "conflict", "pending"}, f"replace target {item['id']} is already {item['status']}")
replacement = allocate_item(state, operation["preference"], revision)
replacement["status"] = "active"
replacement["conflicts_with"] = []
state["items"][replacement["id"]] = replacement
for item in old_items:
item["status"] = "superseded"
item["superseded_by"] = replacement["id"]
item["updated_revision"] = revision
old_ids = {item["id"] for item in old_items}
released = 0
for candidate in state["items"].values():
if candidate["status"] != "conflict":
continue
retained = [item_id for item_id in candidate["conflicts_with"] if item_id not in old_ids]
if retained == candidate["conflicts_with"]:
continue
candidate["conflicts_with"] = retained
candidate["updated_revision"] = revision
if not retained:
candidate["status"] = "pending"
released += 1
replaced = ", ".join(item["id"] for item in old_items)
suffix = f";{released} 个其他冲突候选退回待确认" if released else ""
return f"用 {replacement['id']} 替代 {replaced}:{replacement['assertion']}{suffix}"
def apply_forget(state: dict[str, Any], operation: dict[str, Any], revision: int) -> str:
item = require_item(state, operation["item_id"], "forget")
require(item["status"] in {"active", "pending", "conflict"}, f"forget target {item['id']} is already {item['status']}")
item["status"] = "superseded"
item["superseded_by"] = None
item["reason"] = operation["reason"]
item["updated_revision"] = revision
add_evidence(item, operation["quote"], None)
released = 0
for candidate in state["items"].values():
if candidate["status"] != "conflict" or item["id"] not in candidate["conflicts_with"]:
continue
candidate["conflicts_with"] = [conflict_id for conflict_id in candidate["conflicts_with"] if conflict_id != item["id"]]
candidate["updated_revision"] = revision
if not candidate["conflicts_with"]:
candidate["status"] = "pending"
released += 1
suffix = f";{released} 个冲突候选退回待确认" if released else ""
return f"忘记 {item['id']}:{item['assertion']}{suffix}"
def apply_transaction(state: dict[str, Any], transaction: dict[str, Any], digest: str) -> tuple[dict[str, Any], list[str]]:
applied = state["applied_transactions"].get(transaction["transaction_id"])
if applied is not None:
require(applied["digest"] == digest, "transaction_id was already used with different content")
return state, [f"事务已应用于修订 {applied['revision']},本次为幂等重放"]
require(transaction["expected_state_revision"] == state["state_revision"], f"stale state revision: expected {transaction['expected_state_revision']}, current {state['state_revision']}")
updated = copy.deepcopy(state)
revision = updated["state_revision"] + 1
summaries: list[str] = []
for operation in transaction["operations"]:
if operation["action"] == "remember":
summaries.append(apply_remember(updated, operation["preference"], revision))
elif operation["action"] == "decide":
summaries.append(apply_decide(updated, operation, revision))
elif operation["action"] == "replace":
summaries.append(apply_replace(updated, operation, revision))
else:
summaries.append(apply_forget(updated, operation, revision))
committed_at = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
updated["state_revision"] = revision
updated["journal"].append({
"revision": revision,
"transaction_id": transaction["transaction_id"],
"committed_at": committed_at,
"summaries": summaries,
})
item_ids = sorted(
(item_id for item_id, item in updated["items"].items() if item["updated_revision"] == revision),
key=lambda item_id: int(item_id[2:]),
)
require(bool(item_ids), "transaction did not update any author-memory item")
updated["applied_transactions"][transaction["transaction_id"]] = {
"revision": revision,
"digest": digest,
"item_ids": item_ids,
}
return validate_state(updated), summaries
def scope_label(scope: dict[str, str | None]) -> str:
if scope["level"] == "global":
return "全局"
labels = {"genre": "题材", "book": "本书", "workflow": "流程"}
return f"{labels[scope['level']]}:{scope['value']}"
def render_profile(state: dict[str, Any]) -> str:
lines = [
"# 作者画像",
"",
"<!-- 由 author_memory_commit.py 生成,请勿手改;修改请提交事务。 -->",
"",
f"> 状态修订:{state['state_revision']}。仅列出已确认偏好;当前明确要求、本书设定与硬性门禁优先。",
"",
]
active = [item for item in state["items"].values() if item["status"] == "active"]
for kind in KINDS:
lines.extend([f"## {KIND_TITLES[kind]}", ""])
items = sorted((item for item in active if item["kind"] == kind), key=lambda item: int(item["id"][2:]))
if not items:
lines.extend(["- 暂无", ""])
continue
for item in items:
lines.append(f"- **{item['id']}**〔{scope_label(item['scope'])}|{item['confidence']}|确认 {item['confirmation_count']} 次〕{item['assertion']}")
lines.append("")
return "\n".join(lines).rstrip() + "\n"
def render_pending(state: dict[str, Any]) -> str:
lines = [
"# 待确认的作者习惯",
"",
"<!-- 由 author_memory_commit.py 生成,请勿手改;修改请提交事务。 -->",
"",
f"> 状态修订:{state['state_revision']}。待确认项不参与创作约束,也不应打断当前任务。",
"",
]
items = sorted((item for item in state["items"].values() if item["status"] in {"pending", "conflict"}), key=lambda item: int(item["id"][2:]))
if not items:
lines.extend(["暂无待确认项。", ""])
for item in items:
lines.extend([
f"## {item['id']} · {'冲突' if item['status'] == 'conflict' else '待确认'}",
"",
f"- 候选习惯:{item['assertion']}",
f"- 范围:{scope_label(item['scope'])}",
f"- 原话:\u201c{item['evidence'][-1]['quote']}\u201d",
f"- 依据:{item['reason']}",
f"- 置信度 / 重要度:{item['confidence']} / {item['importance']}",
])
if item["conflicts_with"]:
lines.append(f"- 冲突对象:{', '.join(item['conflicts_with'])}")
lines.append("")
return "\n".join(lines).rstrip() + "\n"
def render_journal(state: dict[str, Any]) -> str:
lines = [
"# 作者记忆变更记录",
"",
"<!-- 由 author_memory_commit.py 生成,请勿手改;最近记录在前。 -->",
"",
]
if not state["journal"]:
lines.extend(["暂无变更。", ""])
for entry in reversed(state["journal"][-100:]):
lines.extend([f"## r{entry['revision']} · {entry['committed_at']}", "", f"- 事务:`{entry['transaction_id']}`"])
lines.extend(f"- {summary}" for summary in entry["summaries"])
lines.append("")
return "\n".join(lines).rstrip() + "\n"
def render_views(state: dict[str, Any]) -> dict[str, str]:
views = {
"作者画像.md": render_profile(state),
"待确认.md": render_pending(state),
"变更记录.md": render_journal(state),
}
limits = {"作者画像.md": PROFILE_MAX_BYTES, "待确认.md": PENDING_MAX_BYTES, "变更记录.md": JOURNAL_MAX_BYTES}
for name, payload in views.items():
require(len(payload.encode("utf-8")) <= limits[name], f"{name} exceeds {limits[name]} bytes; consolidate old memory first")
return views
def write_snapshot(workspace: Path, state: dict[str, Any]) -> None:
root = memory_root(workspace)
views = render_views(state)
state_payload = json_payload(state)
require(len(state_payload.encode("utf-8")) <= STATE_MAX_BYTES, f"_author-memory-state.json exceeds {STATE_MAX_BYTES} bytes")
for name, payload in views.items():
write_if_changed(root / name, payload)
# State is the authority and therefore the last commit point.
write_if_changed(state_path(workspace), state_payload)
def command_init(workspace: Path) -> dict[str, Any]:
require(workspace.exists() and workspace.is_dir(), f"workspace does not exist: {workspace}")
path = state_path(workspace)
if path.exists():
state = validate_state(read_json(path))
else:
state = empty_state()
write_snapshot(workspace, state)
return {"ok": True, "command": "init", "revision": state["state_revision"], "root": str(memory_root(workspace))}
def command_commit(workspace: Path, input_path: Path) -> dict[str, Any]:
require(state_path(workspace).exists(), "author memory is not initialized; run init first")
state = validate_state(read_json(state_path(workspace)))
transaction = normalize_transaction(read_json(input_path))
digest = transaction_digest(transaction)
updated, summaries = apply_transaction(state, transaction, digest)
replayed = updated is state
if not replayed:
write_snapshot(workspace, updated)
else:
# Repair missing or stale views during an idempotent retry.
write_snapshot(workspace, state)
return {
"ok": True,
"command": "commit",
"revision": updated["state_revision"],
"transaction_id": transaction["transaction_id"],
"replayed": replayed,
"item_ids": updated["applied_transactions"][transaction["transaction_id"]]["item_ids"],
"summaries": summaries,
}
def command_record(workspace: Path, input_path: Path) -> dict[str, Any]:
require(workspace.exists() and workspace.is_dir(), f"workspace does not exist: {workspace}")
event = normalize_record_event(read_json(input_path))
path = state_path(workspace)
state = validate_state(read_json(path)) if path.exists() else empty_state()
transaction_id = f"record:{event['event_id']}"
applied = state["applied_transactions"].get(transaction_id)
expected_revision = applied["revision"] - 1 if applied is not None else state["state_revision"]
transaction = {
"schema_version": INPUT_SCHEMA_VERSION,
"transaction_id": transaction_id,
"expected_state_revision": expected_revision,
"operations": [event["operation"]],
}
digest = transaction_digest(transaction)
updated, summaries = apply_transaction(state, transaction, digest)
replayed = updated is state
write_snapshot(workspace, updated)
record = updated["applied_transactions"][transaction_id]
item_ids = record["item_ids"]
receipt = f"Author Memory Receipt: r{record['revision']} · {', '.join(item_ids)}"
return {
"ok": True,
"command": "record",
"revision": updated["state_revision"],
"applied_revision": record["revision"],
"event_id": event["event_id"],
"replayed": replayed,
"item_ids": item_ids,
"receipt": receipt,
"summaries": summaries,
}
def same_scope_value(item_value: str | None, requested: str | None) -> bool:
return requested is not None and item_value is not None and item_value.casefold() == requested.casefold()
def command_query(
workspace: Path,
kinds: list[str] | None,
book: str | None,
genre: str | None,
workflow: str | None,
) -> dict[str, Any]:
require(workspace.exists() and workspace.is_dir(), f"workspace does not exist: {workspace}")
path = state_path(workspace)
if not path.exists():
return {"ok": True, "command": "query", "initialized": False, "revision": 0, "items": [], "omitted": 0}
state = validate_state(read_json(path))
requested_kinds = set(kinds or KINDS)
requested_scopes = {
"book": optional_text(book, "query.book", max_bytes=180),
"genre": optional_text(genre, "query.genre", max_bytes=180),
"workflow": optional_text(workflow, "query.workflow", max_bytes=180),
}
def relevant(item: dict[str, Any]) -> bool:
if item["status"] != "active" or item["kind"] not in requested_kinds:
return False
level = item["scope"]["level"]
return level == "global" or same_scope_value(item["scope"]["value"], requested_scopes[level])
scope_rank = {"book": 0, "genre": 1, "workflow": 2, "global": 3}
candidates = sorted(
(item for item in state["items"].values() if relevant(item)),
key=lambda item: (
scope_rank[item["scope"]["level"]],
-RANK[item["importance"]],
-item["confirmation_count"],
int(item["id"][2:]),
),
)
result: dict[str, Any] = {
"ok": True,
"command": "query",
"initialized": True,
"revision": state["state_revision"],
"items": [],
"omitted": len(candidates),
}
for item in candidates:
compact = {
"id": item["id"],
"kind": item["kind"],
"scope": item["scope"],
"assertion": item["assertion"],
}
result["items"].append(compact)
result["omitted"] = len(candidates) - len(result["items"])
payload = json.dumps(result, ensure_ascii=False, sort_keys=True) + "\n"
if len(payload.encode("utf-8")) > QUERY_MAX_BYTES:
result["items"].pop()
result["omitted"] += 1
break
require(len((json.dumps(result, ensure_ascii=False, sort_keys=True) + "\n").encode("utf-8")) <= QUERY_MAX_BYTES, "query result exceeds its fixed byte budget")
return result
def command_check(workspace: Path) -> dict[str, Any]:
path = state_path(workspace)
require(path.exists(), "author memory is not initialized")
state = validate_state(read_json(path))
views = render_views(state)
root = memory_root(workspace)
for name, expected in views.items():
view_path = root / name
require(view_path.exists(), f"missing derived view: {view_path}")
require(view_path.read_text(encoding="utf-8") == expected, f"derived view is stale or edited: {view_path}")
counts = {status: sum(1 for item in state["items"].values() if item["status"] == status) for status in STATUSES}
return {"ok": True, "command": "check", "revision": state["state_revision"], "counts": counts}
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest="command", required=True)
for command in ("init", "check"):
child = subparsers.add_parser(command)
child.add_argument("--workspace", required=True, type=Path)
commit = subparsers.add_parser("commit")
commit.add_argument("--workspace", required=True, type=Path)
commit.add_argument("--input", required=True, type=Path)
record = subparsers.add_parser("record")
record.add_argument("--workspace", required=True, type=Path)
record.add_argument("--input", required=True, type=Path)
query = subparsers.add_parser("query")
query.add_argument("--workspace", required=True, type=Path)
query.add_argument("--kind", action="append", choices=KINDS)
query.add_argument("--book")
query.add_argument("--genre")
query.add_argument("--workflow")
return parser
def main() -> int:
args = build_parser().parse_args()
try:
if args.command == "init":
result = command_init(args.workspace)
elif args.command == "commit":
result = command_commit(args.workspace, args.input)
elif args.command == "record":
result = command_record(args.workspace, args.input)
elif args.command == "query":
result = command_query(args.workspace, args.kind, args.book, args.genre, args.workflow)
else:
result = command_check(args.workspace)
emit(result)
return 0
except AuthorMemoryError as exc:
emit({"ok": False, "error": str(exc)}, error=True)
return 2
if __name__ == "__main__":
raise SystemExit(main())
scripts/check-ai-patterns.js›
#!/usr/bin/env node
'use strict';
const fs = require('fs');
const path = require('path');
const USAGE = `Usage: node check-ai-patterns.js [--check] [--json] [--fail-on=blocking|all] <file...>
Detect high-risk AI-flavor prose patterns that need human rewrite:
- negative setup followed by positive flip in the same sentence
- comma/semicolon/colon + positive flip
- sentence break + positive flip
- repeated negative setup followed by positive flip
- em-dash (按功能改写), 碎句号 (连续短叙述句), 长段落 (按镜头断段)
- 微动作复读 (「了下/了一下」式轻量补语高密度,电报体指纹)
- 套式反应细节 (指尖/指节/目光等无功能微动作与「平静得像在念」式语气比喻成片)
- 抽象总结复读 (命运/棋局/这一刻终于明白/才刚刚开始,AI 结尾腔)
- 套词密度过高 (仿佛/一丝/深吸一口气/平静无波等禁用词聚集)
- 比喻密度过高 (像/好像/仿佛/如同等比喻标记成片复现)
- 解释链密度过高 (知道/明白/这意味着/必须/需要等判断链聚集)
- 系统公告公文腔过密 (方括号系统/规则行里硬规则词聚集)
- 过度精炼短段 (长文本里短叙述段过密且自然连接偏少)
- 低连接密度 (引号外叙述功能词/白话连接偏少且中长句不足,像提纲/电报体)
- 监控摄像头式动作清单 (同段连续摆放动作动词,缺少视角温度/情绪缓冲)
- 音量反差腔 (声音不高/不大…却…, 实战漏网句式)
- 否定排比 (没有X,没有Y…连排 / 没X…只是Y 先否定后肯定, 实战漏网句式)
- 工整并列 (至于X不X,怎么X / 同动词「不V A,不V B」,含台词,advisory)
- 反序对比 (是A,不是B — not-is 的反序变种, 实战漏网句式)
- 预告式总结收尾 (文末窗口 没人知道/才刚刚开始/正朝着…压了过去, 实战漏网句式)
- 章尾状态总结体 (文末窗口 这一夜注定/这一切都结束了/新的人生才刚刚开始/命运的齿轮)
- 引号强调滥用 (叙述里 1-4 字短词加引号强调,密度型)
Each finding carries severity: blocking by default for generation/deslop cleanup (not-is-comparison / em-dash / voice-contrast / negation-parade / reverse-not-is / trailer-ending / trailer-summary). This is a local style/readability gate, not an AIGC detector score; functional human text can be marked for review instead of hard-edited for a detector.
或 advisory (period-stutter / long-paragraph / micro-action-tic / stock-reaction-tic / action-list-tic / abstract-summary-tic / cliche-density-tic / metaphor-density-tic / reasoning-chain-tic / system-notice-formality-tic / overcompressed-prose-tic / low-connective-density-tic / quote-emphasis-tic / formulaic-parallelism,是提示,justified 的长推理/氛围段可保留)。
--fail-on=blocking 只在出现 blocking finding 时退出 1;默认 --fail-on=all 有任何 finding 即退出 1。
The script reports findings only. It never rewrites text, because the safe fix is
contextual: usually delete the negative setup, write the positive term directly,
or show it via action/detail.`;
const STOP_CHARS = new Set(['。', '!', '?', '!', '?', '\n']);
const SOFT_SEPARATORS = new Set([',', ',', '、', ';', ';', ':', ':']);
const HARD_SEPARATORS = new Set(['。', '.', '!', '!', '?', '?']);
const MAX_NEGATIVE_SPAN = 80;
const MAX_POSITIVE_SPAN = 80;
// 碎句号:连续 STUTTER_MIN_RUN 个「叙述」短句(每句可见字数 ≤ STUTTER_MAX_SENTENCE)无呼吸。
// 只数叙述句,跳过对话/弹幕/系统播报(成片短句是这些体裁的正常形态,不算碎句号)。
const STUTTER_MIN_RUN = 6;
const STUTTER_MAX_SENTENCE = 5;
// 长段落:单段原始字符数超过阈值即提示按镜头断段(手机阅读保守阈值,正常单段远低于此)。
const LONG_PARAGRAPH_CHARS = 200;
// 微动作复读:「V了下 / V了一下 / 拍了两下 / 松了半圈」式轻量补语在叙述里高密度复现,
// 容易形成删减过头的电报体指纹。只扫引号外叙述;密度与次数双门槛同时达标才报,
// 单次出现是正常中文。
const MICRO_TIC_PATTERN = /了(?:[一两三几半])?[下阵圈道声眼口气会]/g;
const MICRO_TIC_MIN_HITS = 5;
const MICRO_TIC_PER_KILO = 6;
// 套式反应细节:不是禁写身体,而是提示成片出现的“部位 + 轻微动作/状态”、
// “胸口像被撞了一下”、喉结/眼圈/声音放轻等通用情绪尾巴,以及“平静语气 +
// 像在念/宣判”模板。此类句子词面变化大,不能逐词 blocking;按章聚集到 4 处才
// advisory,要求逐处做删除测试。正常受伤、打斗、生理反应若承担物理后果可保留。
const STOCK_REACTION_PATTERNS = [
/(?:指尖|手指|指节|手背|掌心|拳头|袖口|衣角|裙角|下唇|嘴唇|唇角|嘴角|眉头|眼底|眸光|目光|视线|肩膀|呼吸)[^。!?!?\n]{0,16}(?:轻轻|微微|缓缓|悄然|不自觉|无意识|下意识|攥紧|握紧|收紧|绞紧|泛白|发白|叩|敲|摩挲|抿紧|抿成|移开|垂下|躲开|一颤|颤了?一下|停了?一下|顿了?一下)/g,
/(?:语气|声音)[^。!?!?\n]{0,12}(?:平静|冷静|平淡|冷淡|淡漠|平直)[^。!?!?\n]{0,12}(?:像|仿佛|如同|好像)[^。!?!?\n]{0,16}(?:念|读|报|说|陈述|宣判|背诵)/g,
/(?:胸口|心口)[^。!?!?\n]{0,16}(?:像|仿佛|如同|好像)[^。!?!?\n]{0,16}(?:撞|锤|压|攥|堵)[^。!?!?\n]{0,8}(?:一下|一记|一拳)?/g,
/(?:声音|嗓音|语气)[^。!?!?\n]{0,12}(?:放轻|压低|发紧|发颤|很轻|轻了些)/g,
/(?:喉结|喉头|喉咙)[^。!?!?\n]{0,10}(?:滚|动|紧|堵|发涩|发干)/g,
/(?:眼眶|眼圈|鼻子)[^。!?!?\n]{0,8}(?:发红|红了|发热|发酸|一酸)/g,
/(?:抿了?下唇|抿了?抿唇|抿了?下嘴|抿着笑)/g,
];
const STOCK_REACTION_MIN_HITS = 4;
// 校准(真人语料,<br> 已还原为换行):qimao 长篇 5584 章 + heiyan 短篇整篇 3983 篇。
// 长篇章尺度(中位约 2100 字)per-kilo 1.0→1.5 误报 0.43%→0.39%,几乎不动;
// 短篇整篇 8000-20000 字下 MIN_HITS 形同虚设、只剩密度门,1.0 时误报 5.57%,
// 1.5 降到 1.46%。故取 1.5,把两个总体拉到同一量级(四份副本共用一组阈值)。
const STOCK_REACTION_PER_KILO = 1.5;
// 监控摄像头式动作清单:同一段连续堆叠通用动作动词(伸手/拿起/取过/挑开/放下/转身等),
// 且用逗号/顿号串联成步骤表时,读感像无视角温度的监控记录。只做 advisory;
// 打斗/追逐等功能性动作编排可保留或人工复核。
const ACTION_LIST_VERB_PATTERN = /伸手|抬手|探手|拿起|拿过|取出|取过|掏出|摸出|抓起|攥住|握住|捏住|按住|推开|拉开|打开|关上|放下|递给|挑开|掀开|扯开|拧开|倒出|端起|转身|回头|抬头|低头|弯腰|俯身|走到|走向|坐下|站起|看向|看着|盯着|扫过/g;
const ACTION_LIST_MIN_HITS = 5;
const ACTION_LIST_MIN_SEPARATORS = 4;
// 抽象总结复读:模板化段落常把角色当下经历拔成「命运/棋局/
// 这一刻终于明白/才刚刚开始」的作者总结。单个词可能服务题材;高密度聚集才报。
const ABSTRACT_SUMMARY_PATTERNS = [
/这一刻[,,]?[^\n。!?!?]{0,24}(?:终于|才)(?:明白|意识到)/g,
/从这一刻开始/g,
/(?:命运|宿命)[^\n。!?!?]{0,28}(?:齿轮|棋局|獠牙|改写|推向|安排)/g,
/早已[^\n。!?!?]{0,8}(?:布好|安排好)[^\n。!?!?]{0,8}(?:棋局|局)/g,
/前所未有的(?:决意|清醒|勇气|力量|恐惧|平静|信念)/g,
/(?:反击|复仇|战争|较量|故事|命运)[^\n。!?!?]{0,12}才刚刚开始/g,
/(?:新的开始|全新的开始)/g,
];
const ABSTRACT_SUMMARY_MIN_HITS = 3;
const ABSTRACT_SUMMARY_PER_KILO = 4;
// 套词密度:单个「仿佛/一丝」可能是正常中文,高密度聚集才会形成模板腔。
// 词表只收本 repo banned-words 中已明确标为高危的形态,避免把普通功能词一网打尽。
const CLICHE_PATTERNS = [
/仿佛|犹如|宛若|如同/g,
/一丝|一抹|些许|几分|隐约/g,
/深吸一口气|缓缓|微微|轻轻|淡淡/g,
/眼中闪过|嘴角勾起|眸光微微一闪|指节泛白|目光锐利|眼神锐利/g,
/心中涌起一股|心头一震|心中一动|心下了然|心中暗道|心中一凛/g,
/不容置疑|不容置喙|不易察觉|显而易见|毫无疑问|不可否认/g,
/声音不大[,,]?却带着|语气平静无波|平静无波|声音平直|听不出情绪/g,
/不知何时|唾手可得|无声翻涌|沉默(?:在[^。!?!?\n]{0,16})?蔓延|难以言说/g,
/散发着一股|冰冷的光|格外刺眼|深邃而冰冷/g,
];
const CLICHE_DENSITY_MIN_HITS = 8;
const CLICHE_DENSITY_PER_KILO = 12;
// 比喻密度:单个生活化比喻可服务画面;“像/好像/仿佛/如同”成片复现时,
// 容易变成 AI 式修辞堆叠。只做 advisory,修法是删到必要数量并回到具体画面,
// 不是把“像”换成另一组比喻词。
const METAPHOR_MARKER_PATTERN = /好像|像是|仿佛|宛如|如同|犹如|(?<![不头图画影录摄肖])像(?![头像素])/g;
const METAPHOR_LIKE_PHRASE_PATTERN = /(?:死|水|冰|火|潮水|石头|木头|机器|纸|铁|鬼|死人|刀|针|网|墙)一样/g;
const METAPHOR_DENSITY_MIN_HITS = 7;
const METAPHOR_DENSITY_PER_KILO = 3;
// 解释链密度:常见“他知道/他明白/这意味着/必须需要”
// 连续替读者推理,读感像报告。单个判断词可服务推理;高密度聚集才提示回到角色当下证据。
const REASONING_CHAIN_PATTERNS = [
{ key: 'mental', core: true, pattern: /(?<![不没未无])(?:他|她|我)?(?:知道|明白|意识到|清楚|判断|确认|分析)/g },
{ key: 'connector', core: true, pattern: /这意味着|也就是说|换句话说|真正的问题(?:在于)?|问题在于|关键在于|在这种情况下|按照这个逻辑|只有这样|想到这里/g },
{ key: 'modal', core: true, pattern: /(?:(?<!不)(?:必须|需要|应该|只要|就会|可能|可以|能够|无法)|不能)[^。!?!?\n]{0,16}(?:判断|确认|承担|维持|稳住|控制|扩大|失控|带来|造成|理解|默认|回家|进门|核对|筛选|减少|建立|风险|结果|秩序|责任)/g },
{ key: 'abstract', core: false, pattern: /(?:任务|条件|风险|来源|逻辑|局面|结果|责任|秩序|规则|信息不足|决策能力)/g },
];
const REASONING_CHAIN_MIN_HITS = 8;
const REASONING_CHAIN_CORE_MIN_HITS = 4;
const REASONING_CHAIN_MIN_BUCKETS = 2;
const REASONING_CHAIN_PER_KILO = 18;
// 系统公告公文腔:只看成片方括号规则/面板行里的硬规则词。
// 这不是特定题材词表;单条严肃规则、日常叙述或普通对话不触发。
const NOTICE_FORMAL_PATTERNS = [
/不得|必须|不可|禁止|严禁|应当|须|需|务必/g,
/当前|本公告|本规则|本系统|提示|任务失败|临时权限|权限|状态|等级/g,
/维持|公共区域|秩序|优先|惩罚|处罚|违规|指令|执行/g,
/被视为|同样计入|计入|承担|责任|单位|撤回|转发|截图/g,
];
const NOTICE_FORMAL_CORE_PATTERN = /不得|必须|不可|禁止|严禁|应当|须|需|务必|被视为|同样计入|计入/g;
const NOTICE_FORMAL_MIN_LINES = 4;
const NOTICE_FORMAL_MIN_HITS = 12;
const NOTICE_FORMAL_CORE_MIN_HITS = 5;
const NOTICE_FORMAL_PER_KILO = 60;
// 过度精炼短段:过度处理样本里常见大量 15 字以内叙述段,且“的/了/就/着/过/呢/吧/啊”等
// 自然连接偏少;对照文本通常保留更多自然连接。此项只做 advisory,禁止机械注水。
const OVERCOMPRESSED_PROSE_PARTICLE_PATTERN = /[的了就着过呢吧啊呀嘛]/g;
const OVERCOMPRESSED_PROSE_MIN_CHARS = 1200;
const OVERCOMPRESSED_PROSE_MIN_PARAS = 45;
const OVERCOMPRESSED_PROSE_SHORT_MAX_CHARS = 15;
const OVERCOMPRESSED_PROSE_SHORT_RATIO = 0.58;
const OVERCOMPRESSED_PROSE_PARTICLE_PER_KILO = 85;
// 低连接密度:单纯低功能词会误抓有大量中长句的文本;
// 因此必须叠加“中长句不足”,并只看引号外叙述。这是 overcompressed 的短窗口补充,只做 advisory。
const LOW_CONNECTIVE_FUNCTION_TERMS = ['的', '了', '就', '在', '是', '也', '都', '还', '又', '把', '被', '给', '这个', '那个', '里面', '以后', '时候', '现在', '因为', '所以', '但是', '不过', '然后', '已经', '还是', '起来', '出来', '下去'];
const LOW_CONNECTIVE_PLAIN_TERMS = ['的', '了', '就', '也', '还', '又', '这个', '那个', '东西', '事情', '时候', '里面', '以后', '一下', '一点', '有点', '还是'];
const LOW_CONNECTIVE_MIN_CHARS = 800;
const LOW_CONNECTIVE_FUNCTION_PER_KILO = 100;
const LOW_CONNECTIVE_PLAIN_PER_KILO = 65;
const LOW_CONNECTIVE_LONG_SENTENCE_CHARS = 30;
const LOW_CONNECTIVE_LONG_SENTENCE_RATIO = 0.08;
// either-or「不是A就是B / 不是A也是B」里紧贴的「是」是连词的一部分,不是肯定项系动词。
// 含「不」以沿用「不是A,也不是B」第二个否定段不算翻转的旧排除。
const COMPACT_EITHER_OR_PREV = new Set(['不', '就', '也']);
// 句尾语气/反问助词;「…,是吗 / 是吧 / 是嘛」是反问尾巴,不是否定后的肯定翻转。
const TAG_PARTICLES = new Set(['吗', '吧', '嘛']);
// 段首确认语;「不是第一次来。是的,他还记得……」里的「是的/是啊」
// 是承接确认,不是「不是 A,是 B」的肯定翻转。
const AFFIRMATION_TAG_PARTICLES = new Set(['的', '啊', '呀', '呢']);
const AFFIRMATION_TAG_BOUNDARY = new Set(['', ',', ',', '。', '.', '!', '!', '?', '?', '、', ';', ';', ':', ':', '\n', '\r', '\t', ' ']);
// 成对引号(台词/系统播报/弹幕)的字符对,stripQuoted 与 quotedRanges 共用一份来源。
// 引号片段一律不跨行(字符类里排掉 \n):正文漏一个收引号很常见(多段台词只在末段收尾、
// 全半角引号混用都会漏),若允许跨行配对,一个未闭合的开引号会把后面成百上千字全算成
// 「引号内」,让 quotedRanges 的消费方(not-is 跨行扫描)把整段叙述静默豁免掉。
const QUOTE_PAIRS = [['「', '」'], ['『', '』'], ['【', '】'], ['“', '”'], ['‘', '’'], ['"', '"'], ["'", "'"]];
const QUOTE_SOURCES = QUOTE_PAIRS.map(([open, close]) => `${escapeRegExp(open)}[^${escapeRegExpCharClass(close)}\\n]*${escapeRegExp(close)}`);
// ---- 实战测试漏网句式(来源:实战写作抓到的真实漏网例句;2026-07 校准)----
// 校准基线:《万疆》真人正文 20 章(第1/10/20/…/190章)+ demo 前 20 章。
// blocking 规则要求真人语料命中 ≈0(每 20 章 ≤1 处且人工判定确属该句式);数据见各规则注释。
// 音量反差腔(实战漏网 A):「声音不高,第一句却稳稳压住了整个大厅。」
// 旧网只有套词密度桶里的「声音不大,却带着」,音量词/转折词一换就漏。
// 引号外叙述逐处 blocking;修法是删掉音量铺垫,直接写声音落进场子的具体效果。
// 校准:《万疆》20 章 0 命中,demo 前 20 章 0 命中。
const VOICE_CONTRAST_PATTERN = /声音(?:并)?不[大高响亮][^。!?!?\n]{0,16}[却但偏]/g;
// 否定排比(实战漏网 B):「没有伴奏,没有和声,没有提词器。」同句 ≥2 个「没有X,」连排;
// 变体「他没炫技,没有那种…架势。他只是唱」先否定铺垫、再用「只是/只会/只有」收肯定。
// 只收「没/没有」段,不收「不X」段——真人叙述里「不哭不闹」类太常见,收进来误报换不来收益。
// 光杆「没」还得挡两类非否定用法,否则正常叙述会被判成排比:
// 1) 黏着语素(沉没/淹没/埋没/出没/隐没…)——前字排除,「船沉没在雾里,没人回头,…只有…」不算;
// 2) 时间惯用语(没多久/没过多久/没等X)——后字排除,「没多久,没等她撑伞,…只有…」不算。
// 「没有X」段不带这两种歧义(黏着语素后接不出「有」,时间惯用语已被后字排除覆盖),
// 第一条连排式照旧不加护栏。
// 校准:《万疆》20 章 0 命中,demo 前 20 章 0 命中。
const NEGATION_PARADE_PATTERNS = [
/(?:没有[^。!?!?\n,,]{1,12}[,,]){2}/g,
/(?<![沉淹埋出隐湮吞覆漫泯])没(?!有?过?多久)(?:有)?[^。!?!?\n,,]{1,12}[,,]\s*没(?!有?过?多久)(?:有)?[^。!?!?\n,,]{1,16}[,,。.][^。!?!?\n,,]{0,6}只(?:是|会|有)/g,
];
const CROSS_NEGATION_START = /^不是[^。!?!?\n]{1,24}[。!?!?]?$/;
const CROSS_NEGATION_MIDDLE = /^(?:也|还)不是[^。!?!?\n]{1,24}[。!?!?]?$/;
const CROSS_NEGATION_END = /^只是[^。!?!?\n]{1,32}[。!?!?]?$/;
// 两类常见但不能直接判错的工整框架,只做 advisory。与 blocking 规则不同,这里故意扫描
// 台词:自然点单「不放辣,不放葱」靠对象最短长度排除;更长的同动词清单交语义审查判断功能。
const DECISION_FRAME_PATTERN = /至于([\u3400-\u9fff]{1,3})不\1[,,]\s*怎么\1/g;
const REPEATED_NEGATIVE_VERB_PATTERN = /不([\u3400-\u9fff]{1,2})([\u3400-\u9fff]{2,8})[,,]\s*不\1([\u3400-\u9fff]{2,8})/g;
// 反序对比腔(实战漏网 C):「是真嗓子,不是修音修出来的」——not-is-comparison 的反序变种。
// 复用 not-is 的排除基建:引号内剥离(maskQuoted)、「是的/是啊」确认语(isAffirmationTagAt);
// 前字排除从 either-or 的 不/就/也 扩展到全部「X是」连词/副词合成词(还是/只是/可是/但是/
// 于是/倒是/像是/若是/要是/正是/便是/总是/老是/更是/最是/算是/怕是/凡是/或是/即是/自是/
// 竟是/原是/本是/仍是/许是/净是/光是/单是/尽是);「是不是」问句起头与「不是吗/不是么/
// 不是吧」反问尾巴单独排除。
// 校准:《万疆》20 章 0 命中,demo 前 20 章 0 命中,按 blocking 实现。
const REVERSE_NOT_IS_PATTERN = /是([^。!?!?\n,,]{1,12})[,,]\s*(?:而)?不是([^。!?!?\n]{1,20})/g;
const REVERSE_NOT_IS_PREV_EXCLUDE = new Set([...COMPACT_EITHER_OR_PREV, '还', '只', '可', '但', '于', '倒', '像', '若', '要', '正', '便', '总', '老', '更', '最', '算', '怕', '凡', '或', '即', '自', '竟', '原', '本', '仍', '许', '净', '光', '单', '尽']);
// 预告式总结收尾(实战漏网 D):「没人知道,这才刚刚开头。」「一场…震惊接力,正朝着…缓缓压了过去。」
// 章尾替读者预告下一章走向是 AI 收尾腔。只扫文末窗口(剥引号后可见字数,按行取整),
// 正文中段的「没人知道」多为普通叙述,不误伤;引号内台词(「没人知道…」)不计。
// 「正式拉开序幕/帷幕」是场内事件的报幕式陈述(真人语料「钟声再度响起,比赛正式拉开序幕」),
// 不是叙述者预告,前置 lookbehind 排除。
// 校准:《万疆》20 章排除「正式拉开序幕」2 处报幕句后 0 命中,demo 前 20 章 0 命中。
const TRAILER_ENDING_PATTERN = /没人知道|谁也不知道|谁也没想到|殊不知|(?:这)?才刚刚开(?:始|头)|正(?:朝着|向着)[^。!?!?\n]{0,24}(?:压|涌|袭|逼)(?:了?过去|了?过来|来)|(?<!正式)拉开(?:序幕|帷幕)|即将(?:开始|来临|降临)/g;
const TRAILER_ENDING_WINDOW_CHARS = 600;
// 章尾状态总结体:把细纲「结尾设定/收束状态」原样写成总结句收章(「这一夜注定无人入眠」
// 「这一切都结束了」「新的人生才刚刚开始」「命运的齿轮」)。与 trailer-ending 共用文末窗口,
// 区别是它盖章过去、trailer-ending 预告将来;收的都是 banned-words 已按名禁掉的形态。
// 不收「(这|那)一刻…终于明白」:真人语料里那是正常的认知节拍,短篇第一人称审判句还是卖点
// (short-craft「审判金句 / 心死余韵」),密度型由 advisory 的 abstract-summary-tic 兜。
// 各分支都要求落在句末断言位,否则会吃进条件从句(等这一切结束了,我们就…)、动补
// (这一切都说明得非常清楚)、成语跨匹配(这一刻…命中注定)、系表(这一战的结果是注定的)、
// 及物用法(就这样…才结束了这个话题)、场内报幕(就这样…宣布…圆满落幕)和否定认知
// (他不知道这一切意味着什么)——最后一类靠 (?!什么) 排掉间接疑问,那是盖章的反面。
// 校准(文末 600 字窗口,命中逐条人工复核):qimao 章中段 20000 章命中 1 处(0.005%)、
// heiyan 整篇 3999 篇命中 22 处(0.550%,全部是上列禁用形态);同批既有 trailer-ending
// 分别命中 1.345% / 6.602%——本规则误报面显著小于已上线的同窗口规则。短篇整篇即收口,
// 基线天然高于长篇章中段,故两个总体分别报数。
const TRAILER_SUMMARY_PATTERN = /这一(?:夜|天|刻|战|年|局|役)[,,]?[^。!?!?,,\n]{0,6}(?<!命中)(?<!是)注定[^。!?!?\n]{0,8}[。!]|就这样[,,][^。!?!?,,\n]{0,8}(?:一切|全部)[^。!?!?,,\n]{0,4}(?:结束了|落幕|收场)[。!]|这一切[,,]?[^。!?!?,,\n]{0,6}(?:都)?(?:说明|意味着|结束了)(?!的)(?:(?!什么)[^。!?!?\n]){0,6}[。!]|(?:新的篇章|新的旅程|崭新的篇章|新的人生)[^。!?!?\n]{0,6}(?:开始|拉开|展开)|命运[^。!?!?\n]{0,6}齿轮/g;
// 引号强调滥用(实战漏网 E,advisory 密度型,风格照 metaphor-density-tic):
// 叙述里短词加引号强调(他是被请来"把关"的)。只数叙述层 1-4 字成对引号片段;
// 排除项:【】系统面板载体、引语动词(说|道|问|喊|答|念|叫|回|吼|嘀咕,加细 骂|写|读|唱)
// 前 6 字/后 3 字邻接的极短台词、引号内含句读的台词、引号外无叙述的行(独立台词/
// 弹幕流/拟声词连发)、引号套引号(台词内强调)。全文 ≥3 处报一条——单处强调是
// 正常修辞,密度高才是模板腔。
// 校准:demo 前 20 章 0 章过阈值;《万疆》20 章 2 章过阈值(海报标语“我在番城”系列、
// “邀战书”等转述载体,真人也这么写),所以该规则只做 advisory,不升 blocking。
const QUOTE_EMPHASIS_MIN_HITS = 3;
const QUOTE_EMPHASIS_MAX_VISIBLE = 4;
const QUOTE_EMPHASIS_SPEECH_VERB_PATTERN = /[说道问喊答念叫回吼骂写读唱嘀咕]/;
const options = {
json: false,
files: [],
failOn: 'all',
};
for (let i = 2; i < process.argv.length; i += 1) {
const arg = process.argv[i];
if (arg === '--check') {
// Accepted for symmetry with normalize-punctuation.js; detection is always check-only.
} else if (arg === '--json') {
options.json = true;
} else if (arg.startsWith('--fail-on=')) {
const v = arg.slice('--fail-on='.length);
if (v !== 'blocking' && v !== 'all') die(`--fail-on must be 'blocking' or 'all'`);
options.failOn = v;
} else if (arg === '-h' || arg === '--help') {
process.stdout.write(`${USAGE}\n`);
process.exit(0);
} else if (arg.startsWith('-')) {
die(`Unknown option: ${arg}`);
} else {
options.files.push(arg);
}
}
if (options.files.length === 0) {
die('No files provided');
}
let failed = false;
const allFindings = [];
for (const file of options.files) {
const fullPath = path.resolve(file);
let input;
try {
input = fs.readFileSync(fullPath, 'utf8');
} catch (error) {
failed = true;
if (!options.json) console.error(`${file}: unable to read (${error.message})`);
continue;
}
const findings = scanDocument(input).map((finding) => ({ file, ...finding }));
allFindings.push(...findings);
}
if (options.json) {
process.stdout.write(`${JSON.stringify({ findings: allFindings }, null, 2)}\n`);
} else {
for (const finding of allFindings) {
console.log(`${finding.file}:${finding.line}:${finding.column}: [${finding.severity}] ${finding.type}: ${finding.message} (${finding.excerpt})`);
}
}
if (failed) process.exit(2);
// --fail-on=blocking 只在出现 blocking finding 时退出 1(advisory 仅报告);默认 all 沿用「有任何 finding 即 1」。
const hasBlocking = allFindings.some((f) => f.severity === 'blocking');
if (options.failOn === 'blocking' ? hasBlocking : allFindings.length > 0) process.exit(1);
function escapeRegExp(text) {
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function escapeRegExpCharClass(text) {
return text.replace(/[\\\]^-]/g, '\\$&');
}
function die(message) {
console.error(message);
console.error(USAGE.trimEnd());
process.exit(2);
}
function scanDocument(input) {
const lines = input.split(/\r?\n/);
const findings = [];
let fence = null;
let inFrontMatter = hasYamlFrontMatter(lines);
let block = [];
const proseLines = [];
const flushBlock = () => {
if (block.length === 0) return;
findings.push(...scanBlock(block));
block = [];
};
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index];
const trimmed = line.trim();
if (inFrontMatter) {
if (index > 0 && trimmed === '---') inFrontMatter = false;
continue;
}
const fenceMarker = parseFenceMarker(trimmed);
if (fence) {
if (fenceMarker && fenceMarker.char === fence.char && fenceMarker.length >= fence.length) {
fence = null;
}
continue;
}
if (fenceMarker) {
flushBlock();
fence = fenceMarker;
continue;
}
block.push({ text: line, lineNo: index + 1 });
proseLines.push({ text: line, lineNo: index + 1 });
}
flushBlock();
findings.push(...scanProsePatterns(proseLines));
findings.sort((a, b) => a.line - b.line || a.column - b.column);
return findings;
}
// 段落级检测:碎句号(连续短叙述句)、长段落、破折号(按功能改写,非机械替换)。
function scanProsePatterns(proseLines) {
const findings = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const dashPattern = /——|—|--+/g;
let dash;
while ((dash = dashPattern.exec(text)) !== null) {
findings.push({
line: lineNo,
column: dash.index + 1,
type: 'em-dash',
severity: 'blocking',
message: '破折号按功能改写:打断→动作 beat/短句,拖长音→省略或动作,插入说明→逗号/冒号;勿一律改句号。',
excerpt: compact(text.slice(Math.max(0, dash.index - 8), dash.index + dash[0].length + 8)),
});
}
if (trimmed.length > LONG_PARAGRAPH_CHARS) {
findings.push({
line: lineNo,
column: 1,
type: 'long-paragraph',
severity: 'advisory',
message: `段落过长(${trimmed.length} 字):按镜头/新动作/新线索/视线切换断段,别一段到底。`,
excerpt: compact(trimmed.slice(0, 40)),
});
}
}
findings.push(...findVoiceContrast(proseLines));
findings.push(...findNegationParade(proseLines));
findings.push(...findFormulaicParallelism(proseLines));
findings.push(...findReverseNotIs(proseLines));
findings.push(...findTrailerEnding(proseLines));
findings.push(...findQuoteEmphasisTic(proseLines));
findings.push(...findPeriodStutter(proseLines));
findings.push(...findMicroActionTic(proseLines));
findings.push(...findStockReactionTic(proseLines));
findings.push(...findActionListTic(proseLines));
findings.push(...findAbstractSummaryTic(proseLines));
findings.push(...findClicheDensityTic(proseLines));
findings.push(...findMetaphorDensityTic(proseLines));
findings.push(...findReasoningChainTic(proseLines));
findings.push(...findNoticeFormalityTic(proseLines));
findings.push(...findOvercompressedProseTic(proseLines));
findings.push(...findLowConnectiveDensityTic(proseLines));
return findings;
}
// 音量反差腔(实战漏网 A):引号外叙述逐处 blocking,位置与摘录取自原文
// (maskQuoted 等长占位保偏移;命中片段不含问号占位符,故不会落进占位区)。
function findVoiceContrast(proseLines) {
const findings = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const masked = maskQuoted(text);
VOICE_CONTRAST_PATTERN.lastIndex = 0;
let match;
while ((match = VOICE_CONTRAST_PATTERN.exec(masked)) !== null) {
findings.push({
line: lineNo,
column: match.index + 1,
type: 'voice-contrast',
severity: 'blocking',
message: '音量反差腔:「声音不大/不高…却/但…」是 AI 高频反差模板;删掉音量铺垫,直接写声音落进场子的具体效果(谁停了手、哪排安静了)。',
excerpt: compact(text.slice(match.index, match.index + match[0].length)),
});
}
}
return findings;
}
// 否定排比(实战漏网 B):同句「没有X,」连排 / 先否定后「只是」收肯定。
// 可能在同一片文字上重叠命中,按区间去重只报一次。
function findNegationParade(proseLines) {
const findings = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const masked = maskQuoted(text);
const spans = [];
for (const pattern of NEGATION_PARADE_PATTERNS) {
pattern.lastIndex = 0;
let match;
while ((match = pattern.exec(masked)) !== null) {
spans.push([match.index, match.index + match[0].length]);
}
}
spans.sort((a, b) => a[0] - b[0]);
let lastEnd = -1;
for (const [start, end] of spans) {
if (start < lastEnd) {
lastEnd = Math.max(lastEnd, end);
continue;
}
lastEnd = end;
findings.push({
line: lineNo,
column: start + 1,
type: 'negation-parade',
severity: 'blocking',
message: '否定排比:「没有X,没有Y…」/「没X,没有Y,只是Z」是 AI 高频排比模板;删掉否定清单,直接写现场实际有什么,最多留一个最有信息量的否定。',
excerpt: compact(text.slice(start, end)),
});
}
}
return findings;
}
function findFormulaicParallelism(proseLines) {
const findings = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
for (const [pattern, message] of [
[DECISION_FRAME_PATTERN, '「至于X不X,怎么X」把同一决定拆成工整栏目;若只是复述细纲,压成角色当下的一次判断或直接动作。'],
[REPEATED_NEGATIVE_VERB_PATTERN, '同动词「不V A,不V B」容易写成否定清单;含台词也要按语境复核,保留真正有功能的一项即可。'],
]) {
pattern.lastIndex = 0;
let match;
while ((match = pattern.exec(text)) !== null) {
findings.push({
line: lineNo,
column: match.index + 1,
type: 'formulaic-parallelism',
severity: 'advisory',
message,
excerpt: compact(match[0]),
});
}
}
}
// 跨段「不是A / 也不是B / 只是C」既可能是细纲复述,也可能是正常的
// 辩解、悬念排除或情绪递进。纯句法无法稳定区分,因此只给 advisory,交给语义复核。
const window = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed) continue;
if (isDivider(trimmed) || isStructural(trimmed)) {
window.length = 0;
continue;
}
if (window.length && lineNo - window[window.length - 1].lineNo > 2) window.length = 0;
window.push({ text: maskQuoted(trimmed), original: trimmed, lineNo });
if (window.length > 3) window.shift();
if (window.length !== 3) continue;
if (!CROSS_NEGATION_START.test(window[0].text)
|| !CROSS_NEGATION_MIDDLE.test(window[1].text)
|| !CROSS_NEGATION_END.test(window[2].text)) continue;
findings.push({
line: window[0].lineNo,
column: 1,
type: 'formulaic-parallelism',
severity: 'advisory',
message: '跨段「不是… / 也不是… / 只是…」可能是工整否定铺排,也可能承担辩解或悬念排除;通读语境,只在重复细纲或拖慢画面时改写。',
excerpt: compact(window.map((entry) => entry.original).join(' / ')),
});
}
return findings;
}
// 反序对比腔(实战漏网 C):「是A,不是B」。排除基建复用 not-is-comparison:
// 引号内剥离、「是的/是啊」确认语;前字合成词与反问尾巴见 REVERSE_NOT_IS_PREV_EXCLUDE 注释。
function findReverseNotIs(proseLines) {
const findings = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const masked = maskQuoted(text);
REVERSE_NOT_IS_PATTERN.lastIndex = 0;
let match;
while ((match = REVERSE_NOT_IS_PATTERN.exec(masked)) !== null) {
const start = match.index;
// 「就是/也是/还是/只是/可是…」里的「是」是合成词一部分,不是肯定项系动词。
if (REVERSE_NOT_IS_PREV_EXCLUDE.has(masked[start - 1])) continue;
// 「是不是…」问句起头。
if (masked[start + 1] === '不') continue;
// 「是的,…不是…」承接确认语(复用 not-is 的判定)。
if (isAffirmationTagAt(masked, start)) continue;
// 「…,不是吗/不是么/不是吧」反问尾巴。
if (/^[吗么吧]/.test(match[2])) continue;
findings.push({
line: lineNo,
column: start + 1,
type: 'reverse-not-is',
severity: 'blocking',
message: '反序对比腔:「是A,不是B」与「不是A,是B」同族;删掉后置否定,直接写 A 的具体表现,或用细节让读者自己对比。',
excerpt: compact(text.slice(start, start + match[0].length)),
});
}
}
return findings;
}
// 预告式总结收尾(实战漏网 D):只扫文末窗口。从文末往回收集叙述行,
// 直到剥引号后的可见字数达到窗口大小(按行取整,边界行整行计入)。
function findTrailerEnding(proseLines) {
const windowLines = [];
let accumulated = 0;
for (let i = proseLines.length - 1; i >= 0 && accumulated < TRAILER_ENDING_WINDOW_CHARS; i -= 1) {
const { text } = proseLines[i];
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
windowLines.unshift(proseLines[i]);
accumulated += visibleLength(stripQuoted(trimmed));
}
const findings = [];
for (const { text, lineNo } of windowLines) {
const masked = maskQuoted(text);
TRAILER_ENDING_PATTERN.lastIndex = 0;
let match;
while ((match = TRAILER_ENDING_PATTERN.exec(masked)) !== null) {
findings.push({
line: lineNo,
column: match.index + 1,
type: 'trailer-ending',
severity: 'blocking',
message: '预告式总结收尾:「没人知道/才刚刚开始/正朝着…压了过去」是 AI 章尾预告腔;结尾停在具体动作、画面或一句台词上,悬念让事件自己挂住,别替读者预告下一章。',
excerpt: compact(text.slice(match.index, match.index + match[0].length)),
});
}
TRAILER_SUMMARY_PATTERN.lastIndex = 0;
let summaryMatch;
while ((summaryMatch = TRAILER_SUMMARY_PATTERN.exec(masked)) !== null) {
findings.push({
line: lineNo,
column: summaryMatch.index + 1,
type: 'trailer-summary',
severity: 'blocking',
message: '章尾状态总结体:「这一夜注定…/这一切都结束了/新的人生才刚刚开始/命运的齿轮」是把细纲的收束状态原样写成了总结句;收束状态是规划口径,正文落到最后一个具体动作、画面或台词上,别替读者盖章。',
excerpt: compact(text.slice(summaryMatch.index, summaryMatch.index + summaryMatch[0].length)),
});
}
}
return findings;
}
// 引号强调滥用(实战漏网 E):统计叙述层 1-4 字成对引号强调片段,全文只报一条
// (密度型分布指纹)。台词类排除见 QUOTE_EMPHASIS_* 常量注释。
function findQuoteEmphasisTic(proseLines) {
let hits = 0;
let firstLine = null;
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
// 引号外没有叙述的行(独立台词/弹幕流/拟声词连发「“叮咚~”“叮咚~”」)整行跳过:
// 强调滥用是叙述层指纹,没有叙述就无所谓强调。
if (visibleLength(stripQuoted(trimmed)) === 0) continue;
const ranges = quotedRanges(text);
for (const [start, end] of ranges) {
if (text[start] === '【') continue; // 系统面板/公告载体,不是强调引号
// 引号套引号:台词内部的强调属于角色语言,不算叙述层强调滥用。
if (ranges.some(([s2, e2]) => s2 <= start && end <= e2 && (s2 !== start || e2 !== end))) continue;
const inner = text.slice(start + 1, end - 1);
const visible = visibleLength(inner);
if (visible < 1 || visible > QUOTE_EMPHASIS_MAX_VISIBLE) continue;
if (/[。!?!?…,,;;::]/.test(inner)) continue; // 含句读的是台词/播报,不是强调
const before = text.slice(Math.max(0, start - 6), start);
const after = text.slice(end, end + 3);
if (QUOTE_EMPHASIS_SPEECH_VERB_PATTERN.test(before) || QUOTE_EMPHASIS_SPEECH_VERB_PATTERN.test(after)) continue; // 引语动词邻接=极短台词
hits += 1;
if (firstLine === null) firstLine = lineNo;
if (samples.length < 6 && !samples.includes(inner)) samples.push(inner);
}
}
if (hits < QUOTE_EMPHASIS_MIN_HITS) return [];
return [{
line: firstLine,
column: 1,
type: 'quote-emphasis-tic',
severity: 'advisory',
message: `引号强调滥用:叙述里 1-4 字短词加引号强调 ${hits} 处;只留真正反讽/转述必要的一两处,其余去掉引号直接写,或换成具体动作让读者自己品。`,
excerpt: compact(samples.join(' ')),
}];
}
// 微动作复读:统计引号外叙述里「了X量词」轻量补语的密度。次数与每千字密度双门槛,
// 全文只报一条(这是分布级指纹,不是逐处问题)。
function findMicroActionTic(proseLines) {
let hits = 0;
let narrativeChars = 0;
let firstLine = null;
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const narrative = stripQuoted(trimmed);
narrativeChars += visibleLength(narrative);
MICRO_TIC_PATTERN.lastIndex = 0;
let match;
while ((match = MICRO_TIC_PATTERN.exec(narrative)) !== null) {
hits += 1;
if (firstLine === null) firstLine = lineNo;
if (samples.length < 6 && !samples.includes(match[0])) samples.push(match[0]);
}
}
if (narrativeChars === 0 || hits < MICRO_TIC_MIN_HITS) return [];
const perKilo = (hits / narrativeChars) * 1000;
if (perKilo < MICRO_TIC_PER_KILO) return [];
return [{
line: firstLine,
column: 1,
type: 'micro-action-tic',
severity: 'advisory',
message: `微动作复读:「了下/了一下」式轻量补语 ${hits} 处(${perKilo.toFixed(1)}/千字);同一反应模板高密度复现是机械指纹,合并动作 beat、换具体细节,别每个动作都补一个轻反应尾巴。`,
excerpt: compact(samples.join(' ')),
}];
}
// 套式反应细节:统计引号外叙述中通用的部位/声线反应与固定语气比喻。
// 这是删除测试的候选集,不是身体描写黑名单;全篇只报一条,保留有动作后果、
// 伤势、人物习惯或情节功能的细节。
function findStockReactionTic(proseLines) {
let hits = 0;
let narrativeChars = 0;
let firstLine = null;
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const narrative = stripQuoted(trimmed);
narrativeChars += visibleLength(narrative);
for (const pattern of STOCK_REACTION_PATTERNS) {
pattern.lastIndex = 0;
let match;
while ((match = pattern.exec(narrative)) !== null) {
hits += 1;
if (firstLine === null) firstLine = lineNo;
const sample = sentenceAround(narrative, match.index);
if (samples.length < 6 && sample && !samples.includes(sample)) samples.push(sample);
}
}
}
if (narrativeChars === 0 || hits < STOCK_REACTION_MIN_HITS) return [];
const perKilo = (hits / narrativeChars) * 1000;
if (perKilo < STOCK_REACTION_PER_KILO) return [];
return [{
line: firstLine,
column: 1,
type: 'stock-reaction-tic',
severity: 'advisory',
message: `套式反应细节:指尖/指节/喉结/眼圈/声音放轻等通用反应或“平静得像在念”式语气比喻 ${hits} 处(${perKilo.toFixed(1)}/千字);逐处做删除测试,只标注情绪、不改变选择、关系、物件或动作结果的删掉,不要换部位或同义动作。`,
excerpt: compact(samples.join(' | ')),
}];
}
function findActionListTic(proseLines) {
const findings = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const narrative = stripQuoted(trimmed).trim();
if (!narrative) continue;
ACTION_LIST_VERB_PATTERN.lastIndex = 0;
const verbs = [];
let match;
while ((match = ACTION_LIST_VERB_PATTERN.exec(narrative)) !== null) {
verbs.push(match[0]);
}
if (verbs.length < ACTION_LIST_MIN_HITS) continue;
const separators = (narrative.match(/[,、;;]/g) || []).length;
if (separators < ACTION_LIST_MIN_SEPARATORS) continue;
findings.push({
line: lineNo,
column: 1,
type: 'action-list-tic',
severity: 'advisory',
message: `监控摄像头式动作清单:同段连续动作动词 ${verbs.length} 个、分隔符 ${separators} 个;合并琐碎步骤,只保留有情绪/情节功能的动作,必要时用角色犹豫、误判或环境反馈做缓冲。`,
excerpt: compact(verbs.slice(0, 8).join(' ')),
});
}
return findings;
}
// 套词密度:统计引号外叙述中的高危禁用词聚集。不是逐词替换器;只在密度高到
// 形成模板腔时提示,修法是删总结、换具体动作/物件/对话,不是同义词轮换。
function findClicheDensityTic(proseLines) {
let hits = 0;
let narrativeChars = 0;
let firstLine = null;
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const narrative = stripQuoted(trimmed);
narrativeChars += visibleLength(narrative);
for (const pattern of CLICHE_PATTERNS) {
pattern.lastIndex = 0;
let match;
while ((match = pattern.exec(narrative)) !== null) {
hits += 1;
if (firstLine === null) firstLine = lineNo;
if (samples.length < 8 && !samples.includes(match[0])) samples.push(match[0]);
}
}
}
if (narrativeChars === 0 || hits < CLICHE_DENSITY_MIN_HITS) return [];
const perKilo = (hits / narrativeChars) * 1000;
if (perKilo < CLICHE_DENSITY_PER_KILO) return [];
return [{
line: firstLine,
column: 1,
type: 'cliche-density-tic',
severity: 'advisory',
message: `套词密度过高:高危 AI 套词 ${hits} 处(${perKilo.toFixed(1)}/千字);不要同义词轮换,改成角色当下可见的动作、物件、对话和具体后果。`,
excerpt: compact(samples.join(' ')),
}];
}
// 比喻密度:统计引号外叙述中“像/好像/仿佛/如同”等比喻标记。
// 单个比喻不是问题;高密度成片时才提示,避免把文本改成另一种修辞模板。
function findMetaphorDensityTic(proseLines) {
let hits = 0;
let narrativeChars = 0;
let firstLine = null;
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const narrative = stripQuoted(trimmed);
narrativeChars += visibleLength(narrative);
METAPHOR_MARKER_PATTERN.lastIndex = 0;
let match;
while ((match = METAPHOR_MARKER_PATTERN.exec(narrative)) !== null) {
hits += 1;
if (firstLine === null) firstLine = lineNo;
const sample = sentenceAround(narrative, match.index);
if (samples.length < 6 && sample && !samples.includes(sample)) samples.push(sample);
}
METAPHOR_LIKE_PHRASE_PATTERN.lastIndex = 0;
while ((match = METAPHOR_LIKE_PHRASE_PATTERN.exec(narrative)) !== null) {
const prefix = narrative.slice(Math.max(0, match.index - 8), match.index);
if (/好像|像是|像|仿佛|宛如|如同|犹如/.test(prefix)) continue;
hits += 1;
if (firstLine === null) firstLine = lineNo;
const sample = sentenceAround(narrative, match.index);
if (samples.length < 6 && sample && !samples.includes(sample)) samples.push(sample);
}
}
if (narrativeChars === 0 || hits < METAPHOR_DENSITY_MIN_HITS) return [];
const perKilo = (hits / narrativeChars) * 1000;
if (perKilo < METAPHOR_DENSITY_PER_KILO) return [];
return [{
line: firstLine,
column: 1,
type: 'metaphor-density-tic',
severity: 'advisory',
message: `比喻密度过高:像/好像/仿佛/如同等比喻标记 ${hits} 处(${perKilo.toFixed(1)}/千字);保留最有叙事功能的少数比喻,其余回到具体动作、物件、声音或后果,不要换成新比喻。`,
excerpt: compact(samples.join(' | ')),
}];
}
// 解释链密度:统计引号外叙述中“知道/明白/这意味着/必须需要”等判断链。
// 全篇只报一条;修法不是补结构虚词,而是把判断落到动作、物件、对话和现场反馈。
function findReasoningChainTic(proseLines) {
let hits = 0;
let coreHits = 0;
let narrativeChars = 0;
let firstLine = null;
const samples = [];
const buckets = new Set();
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const narrative = stripQuoted(trimmed);
narrativeChars += visibleLength(narrative);
for (const { pattern, key, core } of REASONING_CHAIN_PATTERNS) {
pattern.lastIndex = 0;
let match;
while ((match = pattern.exec(narrative)) !== null) {
hits += 1;
if (core) coreHits += 1;
buckets.add(key);
if (firstLine === null) firstLine = lineNo;
const sample = compact(match[0]);
if (samples.length < 8 && !samples.includes(sample)) samples.push(sample);
}
}
}
if (narrativeChars === 0 || hits < REASONING_CHAIN_MIN_HITS) return [];
if (coreHits < REASONING_CHAIN_CORE_MIN_HITS || buckets.size < REASONING_CHAIN_MIN_BUCKETS) return [];
const perKilo = (hits / narrativeChars) * 1000;
if (perKilo < REASONING_CHAIN_PER_KILO) return [];
return [{
line: firstLine,
column: 1,
type: 'reasoning-chain-tic',
severity: 'advisory',
message: `解释链密度过高:知道/明白/这意味着/必须/需要等判断链 ${hits} 处(${perKilo.toFixed(1)}/千字);像逻辑报告时,把判断落到角色当下可见的动作、物件、对话和现场反馈。`,
excerpt: compact(samples.join(' | ')),
}];
}
// 系统/规则行如果连续像 API 文档或政府公文,读者容易闻到机器味。
// 修法不是删除规则,而是保留功能后把一部分硬词改成白话或具体后果。
function findNoticeFormalityTic(proseLines) {
let hits = 0;
let noticeChars = 0;
let noticeLines = 0;
let coreHits = 0;
let firstLine = null;
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!/^【[^】]+】$/.test(trimmed)) continue;
noticeLines += 1;
noticeChars += visibleLength(trimmed);
NOTICE_FORMAL_CORE_PATTERN.lastIndex = 0;
while (NOTICE_FORMAL_CORE_PATTERN.exec(trimmed) !== null) coreHits += 1;
for (const pattern of NOTICE_FORMAL_PATTERNS) {
pattern.lastIndex = 0;
let match;
while ((match = pattern.exec(trimmed)) !== null) {
hits += 1;
if (firstLine === null) firstLine = lineNo;
const sample = compact(match[0]);
if (samples.length < 8 && !samples.includes(sample)) samples.push(sample);
}
}
}
if (noticeLines < NOTICE_FORMAL_MIN_LINES || noticeChars === 0 || hits < NOTICE_FORMAL_MIN_HITS || coreHits < NOTICE_FORMAL_CORE_MIN_HITS) return [];
const perKilo = (hits / noticeChars) * 1000;
if (perKilo < NOTICE_FORMAL_PER_KILO) return [];
return [{
line: firstLine,
column: 1,
type: 'system-notice-formality-tic',
severity: 'advisory',
message: `系统公告公文腔过密:方括号规则行中硬规则词 ${hits} 处(${perKilo.toFixed(1)}/千字);保留为角色看见的屏幕/公告/规则载体,只在载体内部白话化部分硬词,或补角色当场看懂的具体后果,不改成叙述者解释。`,
excerpt: compact(samples.join(' | ')),
}];
}
// 长文本整体过于“精炼”:短段很多、自然连接偏少,读起来像处理过的梗概/分镜表。
// 修法是通读后补断裂处,不是为凑阈值全局加“的/了/就”。
function findOvercompressedProseTic(proseLines) {
let narrativeChars = 0;
let narrativeParas = 0;
let shortParas = 0;
let particles = 0;
let firstLine = null;
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed) || /^【[^】]+】$/.test(trimmed)) continue;
const narrative = stripQuoted(trimmed).trim();
const len = visibleLength(narrative);
if (len === 0) continue;
if (firstLine === null) firstLine = lineNo;
narrativeParas += 1;
narrativeChars += len;
if (len <= OVERCOMPRESSED_PROSE_SHORT_MAX_CHARS) {
shortParas += 1;
if (samples.length < 6) samples.push(narrative);
}
OVERCOMPRESSED_PROSE_PARTICLE_PATTERN.lastIndex = 0;
while (OVERCOMPRESSED_PROSE_PARTICLE_PATTERN.exec(narrative) !== null) particles += 1;
}
if (narrativeChars < OVERCOMPRESSED_PROSE_MIN_CHARS || narrativeParas < OVERCOMPRESSED_PROSE_MIN_PARAS) return [];
const shortRatio = shortParas / narrativeParas;
if (shortRatio < OVERCOMPRESSED_PROSE_SHORT_RATIO) return [];
const particlePerKilo = (particles / narrativeChars) * 1000;
if (particlePerKilo >= OVERCOMPRESSED_PROSE_PARTICLE_PER_KILO) return [];
return [{
line: firstLine,
column: 1,
type: 'overcompressed-prose-tic',
severity: 'advisory',
message: `过度精炼短段:叙述段 ${narrativeParas} 个,其中 ${shortParas} 个≤${OVERCOMPRESSED_PROSE_SHORT_MAX_CHARS}字(${(shortRatio * 100).toFixed(0)}%),自然连接 ${particlePerKilo.toFixed(1)}/千字偏少;先通读判断,确有提纲感再补断裂处和必要结构虚词,有意短镜头可留,别机械注水。`,
excerpt: compact(samples.join(' | ')),
}];
}
// 低连接密度:长文本/中短窗口里,引号外叙述的功能词和白话连接同时偏低,且缺少中长承接句,
// 会呈现“提纲/电报体”分布。修法是恢复必要连接和句群,不是全局补词。
function findLowConnectiveDensityTic(proseLines) {
let bodyChars = 0;
let functionHits = 0;
let plainHits = 0;
let firstLine = null;
const sentences = [];
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
// 只看引号外叙述。台词/弹幕/系统播报可以天然短促,混入统计会把体裁特征误当电报体。
const narrative = stripQuoted(trimmed).trim();
const narrativeLen = visibleLength(narrative);
if (narrativeLen === 0) continue;
if (firstLine === null) firstLine = lineNo;
bodyChars += narrativeLen;
functionHits += countTerms(narrative, LOW_CONNECTIVE_FUNCTION_TERMS);
plainHits += countTerms(narrative, LOW_CONNECTIVE_PLAIN_TERMS);
for (const sentence of splitSentences(narrative)) {
const len = visibleLength(sentence);
if (len === 0) continue;
sentences.push(len);
if (len <= 12 && samples.length < 6) samples.push(sentence);
}
}
if (bodyChars < LOW_CONNECTIVE_MIN_CHARS || sentences.length === 0) return [];
const functionPerKilo = (functionHits / bodyChars) * 1000;
if (functionPerKilo >= LOW_CONNECTIVE_FUNCTION_PER_KILO) return [];
const plainPerKilo = (plainHits / bodyChars) * 1000;
if (plainPerKilo >= LOW_CONNECTIVE_PLAIN_PER_KILO) return [];
const longSentenceRatio = sentences.filter((len) => len >= LOW_CONNECTIVE_LONG_SENTENCE_CHARS).length / sentences.length;
if (longSentenceRatio >= LOW_CONNECTIVE_LONG_SENTENCE_RATIO) return [];
return [{
line: firstLine,
column: 1,
type: 'low-connective-density-tic',
severity: 'advisory',
message: `低连接密度:引号外叙述功能词 ${functionPerKilo.toFixed(1)}/千字、白话连接 ${plainPerKilo.toFixed(1)}/千字,且≥${LOW_CONNECTIVE_LONG_SENTENCE_CHARS}字承接句仅 ${(longSentenceRatio * 100).toFixed(0)}%;容易像提纲/电报体。通读后补必要连接和中长句群,别机械注水。`,
excerpt: compact(samples.join(' | ')),
}];
}
// 抽象总结复读:统计引号外叙述中的高抽象收束模板。全篇只报一条,提醒回到角色
// 当下可见的文件、动作、对话或物理后果;不要用命运大词替读者总结。
function findAbstractSummaryTic(proseLines) {
let hits = 0;
let narrativeChars = 0;
let firstLine = null;
const samples = [];
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed || isDivider(trimmed) || isStructural(trimmed)) continue;
const narrative = stripQuoted(trimmed);
narrativeChars += visibleLength(narrative);
for (const pattern of ABSTRACT_SUMMARY_PATTERNS) {
pattern.lastIndex = 0;
let match;
while ((match = pattern.exec(narrative)) !== null) {
hits += 1;
if (firstLine === null) firstLine = lineNo;
const sample = compact(match[0]);
if (samples.length < 6 && !samples.includes(sample)) samples.push(sample);
}
}
}
if (narrativeChars === 0 || hits < ABSTRACT_SUMMARY_MIN_HITS) return [];
const perKilo = (hits / narrativeChars) * 1000;
if (perKilo < ABSTRACT_SUMMARY_PER_KILO) return [];
return [{
line: firstLine,
column: 1,
type: 'abstract-summary-tic',
severity: 'advisory',
message: `抽象总结复读:命运/棋局/这一刻终于明白/才刚刚开始等作者总结 ${hits} 处(${perKilo.toFixed(1)}/千字);回到角色当下可见的文件、动作、对话或物理后果,别替读者盖章。`,
excerpt: compact(samples.join(' | ')),
}];
}
function findPeriodStutter(proseLines) {
const findings = [];
let runLen = 0;
let runStartLine = null;
let runSample = [];
const flush = () => {
if (runLen >= STUTTER_MIN_RUN) {
findings.push({
line: runStartLine,
column: 1,
type: 'period-stutter',
severity: 'advisory',
message: `碎句号:连续 ${runLen} 个短句无呼吸;按目标句长把碎句合并成中长句、补回画面与连接(见本 skill 句长/疏密节奏规则)。`,
excerpt: compact(runSample.join(' ')),
});
}
runLen = 0;
runStartLine = null;
runSample = [];
};
for (const { text, lineNo } of proseLines) {
const trimmed = text.trim();
if (!trimmed) continue; // 空行是一句一段排版,不打断叙述连贯
if (isDivider(trimmed) || isStructural(trimmed)) {
flush(); // 分隔线/markdown 结构行:重置碎句计数
continue;
}
const narrative = stripQuoted(trimmed);
if (visibleLength(narrative) === 0) {
flush(); // 纯对话/弹幕/系统播报:成片短句是正常形态,重置碎句计数
continue;
}
// 只数引号外叙述句:混合行(叙述+引号内物件/短台词)的引号外片段仍参与碎句计数。
for (const sentence of splitSentences(narrative)) {
if (visibleLength(sentence) <= STUTTER_MAX_SENTENCE) {
if (runLen === 0) runStartLine = lineNo;
runLen += 1;
if (runSample.length < 6) runSample.push(sentence);
} else {
flush();
}
}
}
flush();
return findings;
}
function isDivider(trimmed) {
return /^-{3,}$/.test(trimmed) || /^[*_]{3,}$/.test(trimmed);
}
// markdown 结构行(标题/列表/引用/表格)不是叙述正文,长段落/碎句号/破折号检测都跳过。
function isStructural(trimmed) {
return /^(#{1,6}\s|>\s?|[-*+]\s|\d+[.)]\s|\|)/.test(trimmed)
|| /^第[零一二三四五六七八九十百千万\d]+章(?:\s|_|$)/.test(trimmed);
}
// 去掉成对引号内的片段(台词/系统播报),只留引号外叙述。碎句号判定用:纯对话/弹幕成片短句
// 是体裁正常形态(豁免),但「叙述 + 引号内物件/短台词」混合行的引号外叙述仍要参与短句计数。
function stripQuoted(text) {
let out = text;
for (const src of QUOTE_SOURCES) out = out.replace(new RegExp(src, 'g'), '');
return out;
}
// 把成对引号片段(含引号)替换为等长问号占位:既豁免引号内台词/播报,又保住原文
// 偏移量,供逐处 blocking 规则定位与截取原文摘录(stripQuoted 会移位,不适合定位)。
// 占位字符用「?」而不是「。」:占位既要截断各规则的 [^。!?!?…] 否定类(?与句号在每条
// 规则的否定类里等效),又不能落在任何规则的接受位。句号占位会替 trailer-summary 的句末
// [。!] 伪造出终止符,让「这一战注定是「血屠」的开端,…」这类引号里放代号/绰号的叙述行
// 被误报,且报出的『这一战注定是。』在原文里 grep 不到。占位长度不变,故偏移与摘录窗口不漂移。
function maskQuoted(text) {
let out = text;
for (const src of QUOTE_SOURCES) {
out = out.replace(new RegExp(src, 'g'), (m) => '?'.repeat(m.length));
}
return out;
}
// 返回引号内片段(含引号本身)的 [start, end) 区间,供 not-is 对比句豁免台词用。
function quotedRanges(text) {
const ranges = [];
for (const src of QUOTE_SOURCES) {
const re = new RegExp(src, 'g');
let match;
while ((match = re.exec(text)) !== null) ranges.push([match.index, match.index + match[0].length]);
}
return ranges;
}
function insideRanges(pos, ranges) {
return ranges.some(([start, end]) => pos >= start && pos < end);
}
function splitSentences(trimmed) {
return trimmed
.split(/[。!?!?]/)
.map((s) => s.trim())
.filter(Boolean);
}
function sentenceAround(text, index) {
let start = index;
while (start > 0 && !STOP_CHARS.has(text[start - 1])) start -= 1;
let end = index;
while (end < text.length && !STOP_CHARS.has(text[end])) end += 1;
return compact(text.slice(start, end).trim());
}
function visibleLength(sentence) {
const matched = sentence.match(/[一-鿿A-zA-Za-z0-9]/g);
return matched ? matched.length : 0;
}
function countTerms(text, terms) {
let count = 0;
for (const term of terms) {
let index = text.indexOf(term);
while (index !== -1) {
count += 1;
index = text.indexOf(term, index + term.length);
}
}
return count;
}
function parseFenceMarker(trimmedLine) {
const match = /^(?:`{3,}|~{3,})/.exec(trimmedLine);
if (!match) return null;
return { char: match[0][0], length: match[0].length };
}
function hasYamlFrontMatter(lines) {
if (!lines[0] || lines[0].trim() !== '---') return false;
let sawYamlField = false;
for (let i = 1; i < Math.min(lines.length, 40); i += 1) {
const trimmed = lines[i].trim();
if (trimmed === '---') return sawYamlField;
if (/^[A-Za-z0-9_-]+:\s*/.test(trimmed)) sawYamlField = true;
}
return false;
}
function scanBlock(block) {
const text = block.map((entry) => entry.text).join('\n');
const lineStarts = [];
let cursor = 0;
for (const entry of block) {
lineStarts.push({ offset: cursor, lineNo: entry.lineNo });
cursor += entry.text.length + 1;
}
return findNotIsComparisons(text, (offset) => positionForOffset(lineStarts, offset));
}
function positionForOffset(lineStarts, offset) {
let low = 0;
let high = lineStarts.length - 1;
while (low <= high) {
const mid = Math.floor((low + high) / 2);
const current = lineStarts[mid];
const next = lineStarts[mid + 1];
if (offset < current.offset) {
high = mid - 1;
} else if (next && offset >= next.offset) {
low = mid + 1;
} else {
return {
line: current.lineNo,
column: offset - current.offset + 1,
};
}
}
return { line: lineStarts[0].lineNo, column: 1 };
}
function findNotIsComparisons(text, getPosition) {
const findings = [];
const quoted = quotedRanges(text);
let offset = 0;
while (offset < text.length) {
const start = text.indexOf('不是', offset);
if (start === -1) break;
// 引号内是台词/系统播报:口语里「不是A,是B」是自然辩解/反问,不算叙述层 AI 对比句式
// (与碎句号一致豁免引号内容)。
if (insideRanges(start, quoted)) {
offset = start + 2;
continue;
}
// Avoid the common yes/no question fragment “是不是”.
if (start > 0 && text[start - 1] === '是') {
offset = start + 2;
continue;
}
const candidate = text.slice(start);
const markerEnd = findPositiveFlipEnd(candidate);
if (markerEnd === -1) {
offset = start + 2;
continue;
}
const raw = trimTrailingNoise(extractFinding(candidate, markerEnd));
if (raw.length >= 4) {
const position = getPosition(start);
findings.push({
line: position.line,
column: position.column,
type: 'not-is-comparison',
severity: 'blocking',
message: '高频 AI 对比句式;删掉否定铺垫,直接写后项,或改成动作/细节呈现。',
excerpt: compact(raw),
});
}
offset = start + Math.max(raw.length, 2);
}
return findings;
}
function findPositiveFlipEnd(candidate) {
let index = 2; // after “不是”
let scanned = 0;
let crossedSeparator = false;
while (index < candidate.length && scanned <= MAX_NEGATIVE_SPAN) {
const char = candidate[index];
if (startsWithAt(candidate, index, '而是')) return index + 2;
if (SOFT_SEPARATORS.has(char)) {
const next = skipGap(candidate, index + 1);
if (startsWithAt(candidate, next, '而是')) return next + 2;
if (candidate[next] === '是' && !TAG_PARTICLES.has(candidate[next + 1]) && !isAffirmationTagAt(candidate, next)) return next + 1;
crossedSeparator = true;
}
if (HARD_SEPARATORS.has(char)) {
const next = skipGap(candidate, index + 1);
if (candidate[next] === '是' && !TAG_PARTICLES.has(candidate[next + 1]) && !isAffirmationTagAt(candidate, next)) return next + 1;
if (char !== '.') break;
crossedSeparator = true;
}
if (STOP_CHARS.has(char)) break;
// Catch compact forms such as “不是A是B”, but only within the first clause —
// before any separator. After a separator the trailing “是” of a conjunction
// (只是/可是/但是/还是/于是/倒是/总是…) is part of that word, not a positive
// copula (issue #166 false-positive class). Post-separator flips are still
// caught when separator-adjacent (“,是”/“,而是”) by the separator branches
// above; subject-present flips like “,他是”/“,那是” are intentionally NOT
// caught here — there is no separator-local way to tell them from a
// conjunction without a word list, and on a hard rescan-to-0 gate a false
// positive (forcing a rewrite of good prose) costs more than missing this
// rarer form. The “是” in the either-or idiom “不是A就是B / 也是B” is part of
// the 就是/也是 conjunction, not a copula, so 就/也 are excluded too. Also never
// treat the “是” inside a second negative fragment (“不是A,也不是B”) as the flip.
if (char === '是' && !COMPACT_EITHER_OR_PREV.has(candidate[index - 1]) && !crossedSeparator) {
return index + 1;
}
index += 1;
scanned += 1;
}
return -1;
}
function extractFinding(candidate, markerEnd) {
let end = markerEnd;
const limit = Math.min(candidate.length, markerEnd + MAX_POSITIVE_SPAN);
while (end < limit) {
if (STOP_CHARS.has(candidate[end])) break;
end += 1;
}
return candidate.slice(0, end);
}
function startsWithAt(text, index, needle) {
return text.slice(index, index + needle.length) === needle;
}
function isAffirmationTagAt(text, index) {
if (text[index] !== '是') return false;
const particle = text[index + 1];
if (!AFFIRMATION_TAG_PARTICLES.has(particle)) return false;
const boundary = text[index + 2] || '';
return AFFIRMATION_TAG_BOUNDARY.has(boundary);
}
// 跳过行内空白与换行(含空行/段落间距),停在下一个实义字符。原实现只吞一个换行,
// 会漏掉跨空行的「不是A。(空行)是B」这类分段揭示句。
function skipGap(text, index) {
while (index < text.length && (isInlineSpace(text[index]) || text[index] === '\n')) index += 1;
return index;
}
function isInlineSpace(char) {
return char === ' ' || char === '\t' || char === '\r';
}
function trimTrailingNoise(text) {
return text.replace(/[\s|))】\]]+$/u, '');
}
function compact(text) {
const normalized = text.replace(/\s+/g, ' ').trim();
return normalized.length > 80 ? `${normalized.slice(0, 77)}...` : normalized;
}
scripts/check-degeneration.js›
#!/usr/bin/env node
'use strict';
const fs = require('fs');
const path = require('path');
const USAGE = `Usage: node check-degeneration.js [--check] [--json] [--fail-on=blocking|all] <file...>
Detect model-degeneration fingerprints that a degrading model cannot self-report:
- verbatim repetition (复读/打转): a long sentence repeated, or back-to-back identical lines
- mid-sentence truncation (截断): file ends without terminal/closing punctuation
- placeholder / refusal / meta leakage (元信息泄漏): 作为AI / 我无法继续 / 此处省略 / 乱码
- engineering-word leakage (工程词泄漏): 细纲 / 情节点 / 本章 / 下一章 / 任务描述 漏进正文
Each finding carries severity: blocking (复读/截断/占位拒绝语/tier1 纯工程词,正文里永不合法,
命中即重写) 或 advisory (tier2 章节/歧义词、对话行里的工程词,只提示、交人/LLM 判)。
--fail-on=blocking 只在出现 blocking finding 时退出 1;默认 --fail-on=all 有任何 finding 即退出 1。
Report-only. The script never rewrites — the safe response is to regenerate the
affected unit (chapter / 摘要) with the finding fed back as a constraint, cap retries,
then surface the evidence to the user. Conservative by design: 通俗网文 deliberately
uses 排比/复沓/弹幕刷屏/重复台词 for rhythm, so short and dialogue repetition is exempt.`;
// 复读:长句(可见字数 ≥ REPEAT_MIN_LEN)出现 ≥ REPEAT_MIN_COUNT 次判为打转;
// 紧邻整行重复(可见字数 ≥ ADJACENT_MIN_LEN)判为即时循环。短句/弹幕/对话刷屏豁免。
const REPEAT_MIN_LEN = 12;
const REPEAT_MIN_COUNT = 3;
const ADJACENT_MIN_LEN = 8;
// hard = 任何行都判(正文里永不合法);soft = 只在「非对话」叙述行判(角色台词里可能合法,
// 如「对不起,我无法答应你」是正常对话,不是模型拒绝语)。
const PLACEHOLDER_PATTERNS = [
// 「作为AI」需在自指位置(其后是断句/我/无法… 或句末),避免误报「人工智能时代的产物」这类
// 复合名词;并对对话行豁免(系统流/AI 伴侣题材里 AI 角色台词「作为AI,我会保护你」是合法对话)。
// 型号后缀(AI语言模型/AI助手/人工智能语言模型/AI模型/AI大模型)必须可选吃掉:否则前视断言紧跟
// 在「AI」后面看到的是「语」/「助」/「模」,最典型的退化开场整类漏检(与写后网 story_hook_core.js
// SOFT_PATTERNS / story_codex_hook.py _NET_SOFT_PATTERNS 同语义)。
{ re: /作为(一个)?(AI|人工智能|大?语言模型|智能助手|聊天助手)(?:语言模型|大?模型|助手|机器人)?(?=[,,。、;;::!!??\s))」』"】]|我|无法|不能|没法|$)/, label: '元信息泄漏(AI 自指)', hard: false },
{ re: /�/, label: '乱码(替换字符 �)', hard: true },
{ re: /^(Sure|Certainly|Here'?s|As an AI|I (?:cannot|can't|am unable|apologize))/, label: '元信息泄漏(英文 AI 腔)', hard: true },
{ re: /[((](此处|以下|这里|下文|后续)?\s*(省略|略)(去|过)?[^))]{0,10}[))]/, label: '占位符(括号省略)', hard: true },
{ re: /(未完待续|TODO|占位符|placeholder)/, label: '占位符', hard: true },
{ re: /我(无法|不能)(继续(写|创作|生成|下去)|生成(内容|文本|正文)?|创作|续写|完成(这个|本)?(章|篇|创作|请求))/, label: '元信息泄漏(生成拒绝语)', hard: false },
];
// 工程词泄漏(正文元信息扫描的确定性版):弱模型把写作工程词漏进正文,破坏代入感
// (DeepSeek-v4 这类会在对话里冒「该到下一章了」)。漏词的模型自己发现不了,靠脚本兜。
// tier1 = 纯写作流水线术语,正文里几乎永不合法;tier2 = 章节结构/歧义词,角色在故事内
// 真实阅读/讨论「第X章」或故事内系统/界面用语时属例外(report-only,交人/LLM 判)。
const META_TIER1_RE = /细纲|情节点|卷纲|功能标签|目标情绪|字数目标|章首钩子|章尾钩子/;
const META_TIER2_RE = /第[一二三四五六七八九十百千万两0-9]+章|本章|这一章|上一章|下一章|上章|下章|前一章|后一章|前文|后文|伏笔|读者|任务描述/;
const options = { json: false, files: [], failOn: 'all' };
for (let i = 2; i < process.argv.length; i += 1) {
const arg = process.argv[i];
if (arg === '--check') {
// Accepted for symmetry with the other detectors; detection is always check-only.
} else if (arg === '--json') {
options.json = true;
} else if (arg.startsWith('--fail-on=')) {
const v = arg.slice('--fail-on='.length);
if (v !== 'blocking' && v !== 'all') die(`--fail-on must be 'blocking' or 'all'`);
options.failOn = v;
} else if (arg === '-h' || arg === '--help') {
process.stdout.write(`${USAGE}\n`);
process.exit(0);
} else if (arg.startsWith('-')) {
die(`Unknown option: ${arg}`);
} else {
options.files.push(arg);
}
}
if (options.files.length === 0) {
die('No files provided');
}
let failed = false;
const allFindings = [];
for (const file of options.files) {
const fullPath = path.resolve(file);
let input;
try {
input = fs.readFileSync(fullPath, 'utf8');
} catch (error) {
failed = true;
if (!options.json) console.error(`${file}: unable to read (${error.message})`);
continue;
}
const findings = scanDocument(input).map((finding) => ({ file, ...finding }));
allFindings.push(...findings);
}
if (options.json) {
process.stdout.write(`${JSON.stringify({ findings: allFindings }, null, 2)}\n`);
} else {
for (const f of allFindings) {
console.log(`${f.file}:${f.line}:${f.column}: [${f.severity}] ${f.type}: ${f.message} (${f.excerpt})`);
}
}
if (failed) process.exit(2);
// --fail-on=blocking 只在出现 blocking finding 时退出 1(advisory 仅报告);默认 all 沿用「有任何 finding 即 1」。
const hasBlocking = allFindings.some((f) => f.severity === 'blocking');
if (options.failOn === 'blocking' ? hasBlocking : allFindings.length > 0) process.exit(1);
function die(message) {
console.error(message);
console.error(USAGE.trimEnd());
process.exit(2);
}
function scanDocument(input) {
const lines = input.split(/\r?\n/);
const content = []; // { text, trimmed, lineNo } for body lines outside front-matter/fences
let fence = null;
let inFrontMatter = hasYamlFrontMatter(lines);
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index];
const trimmed = line.trim();
if (inFrontMatter) {
if (index > 0 && trimmed === '---') inFrontMatter = false;
continue;
}
const fenceMarker = /^(?:`{3,}|~{3,})/.exec(trimmed);
if (fence) {
if (fenceMarker && trimmed[0] === fence) fence = null;
continue;
}
if (fenceMarker) {
fence = trimmed[0];
continue;
}
content.push({ text: line, trimmed, lineNo: index + 1 });
}
const findings = [];
findings.push(...findRepetition(content));
findings.push(...findTruncation(content));
findings.push(...findPlaceholders(content));
findings.push(...findMetaLeak(content));
findings.sort((a, b) => a.line - b.line || a.column - b.column);
return findings;
}
function isContent(trimmed) {
return trimmed && !trimmed.startsWith('#') && !/^-{3,}$/.test(trimmed);
}
function isDialogueLike(trimmed) {
return /[“”"'‘’「」『』【】]/.test(trimmed);
}
// 去掉成对引号内的片段(台词/系统词/引用物件),只留引号外叙述。复读判定用:重复台词是体裁
// 手法(豁免),但「叙述 + 引号内物件/短台词」混合行里引号外叙述的复读仍是退化,不能整行豁免。
function stripQuoted(text) {
return text
.replace(/「[^」]*」/g, '')
.replace(/『[^』]*』/g, '')
.replace(/【[^】]*】/g, '')
.replace(/“[^”]*”/g, '')
.replace(/‘[^’]*’/g, '')
.replace(/"[^"]*"/g, '')
.replace(/'[^']*'/g, '');
}
function visibleLength(text) {
const m = text.match(/[一-鿿A-zA-Za-z0-9]/g);
return m ? m.length : 0;
}
function findRepetition(content) {
const findings = [];
const body = content.filter((c) => isContent(c.trimmed));
// (1) back-to-back identical lines (immediate loop). 纯台词/弹幕复沓(引号外叙述很短)豁免;
// 「叙述 + 引号内物件」混合行的整行复读仍判(去引号后叙述够长)。
for (let i = 1; i < body.length; i += 1) {
if (
body[i].trimmed === body[i - 1].trimmed &&
visibleLength(stripQuoted(body[i].trimmed)) >= ADJACENT_MIN_LEN
) {
findings.push({
line: body[i].lineNo,
column: 1,
type: 'verbatim-repeat',
severity: 'blocking',
message: '逐行复读(紧邻整行重复):疑似模型打转,重写本段、删掉重复。',
excerpt: compact(body[i].trimmed),
});
}
}
// (2) any long sentence repeated >= REPEAT_MIN_COUNT times across the file.
// 只豁免引号内台词(体裁手法),引号外叙述句仍参与复读计数(含「叙述+引号内物件」混合行)。
const counts = new Map();
for (const { trimmed } of body) {
for (const sentence of stripQuoted(trimmed).split(/[。!?!?]/)) {
const s = sentence.trim();
if (visibleLength(s) < REPEAT_MIN_LEN) continue;
const entry = counts.get(s) || { count: 0, firstLine: null };
entry.count += 1;
counts.set(s, entry);
}
}
// record first line for repeated sentences
const flagged = new Set();
for (const [s, entry] of counts) {
if (entry.count >= REPEAT_MIN_COUNT) flagged.add(s);
}
if (flagged.size) {
for (const { trimmed, lineNo } of body) {
for (const sentence of stripQuoted(trimmed).split(/[。!?!?]/)) {
const s = sentence.trim();
if (flagged.has(s)) {
findings.push({
line: lineNo,
column: 1,
type: 'verbatim-repeat',
severity: 'blocking',
message: `长句复读(同句出现 ${counts.get(s).count} 次):疑似模型打转,重写、保留一处。`,
excerpt: compact(s),
});
flagged.delete(s); // report each repeated sentence once, at its first occurrence
}
}
}
}
return findings;
}
function findTruncation(content) {
const body = content.filter((c) => isContent(c.trimmed));
if (body.length === 0) return [];
const last = body[body.length - 1];
// a finished chapter ends on terminal/closing punctuation; otherwise it was cut off.
if (/[。!?!?…”"』」))】]$/.test(last.trimmed)) return [];
return [{
line: last.lineNo,
column: last.trimmed.length,
type: 'truncated',
severity: 'blocking',
message: '疑似截断:正文末尾未以句末/收尾标点结束,可能被模型中途切断;补完结尾或重写收尾。',
excerpt: compact(last.trimmed.slice(-24)),
}];
}
function findPlaceholders(content) {
const findings = [];
for (const { trimmed, lineNo } of content) {
if (!isContent(trimmed)) continue;
const dialogue = isDialogueLike(trimmed);
for (const { re, label, hard } of PLACEHOLDER_PATTERNS) {
if (!hard && dialogue) continue; // soft 拒绝语在对话行里可能是正常台词,豁免
const m = re.exec(trimmed);
if (m) {
findings.push({
line: lineNo,
column: (m.index || 0) + 1,
type: 'placeholder-leak',
severity: 'blocking',
message: `${label}:正文混入元信息/拒绝语/占位符,重写本段干净落地。`,
excerpt: compact(trimmed.slice(Math.max(0, (m.index || 0) - 4), (m.index || 0) + 20)),
});
break; // one finding per line is enough
}
}
}
return findings;
}
function findMetaLeak(content) {
const findings = [];
let firstContentSeen = false;
for (const { trimmed, lineNo } of content) {
if (!isContent(trimmed)) continue;
if (!firstContentSeen) {
firstContentSeen = true;
// 标题行(第N章 章名,无 ## 前缀时也算)属「标题行以外的正文」之外,排除
if (/^第[一二三四五六七八九十百千万两0-9]+章/.test(trimmed)) continue;
}
const dialogue = isDialogueLike(trimmed);
let m = META_TIER1_RE.exec(trimmed);
if (m) {
// tier1 纯工程词正文里几乎永不合法→blocking;但写手/编剧题材里角色在故事内真讨论创作,
// 台词(对话行)里可能合法,降级为 advisory(仍报告,交人/LLM 判,不强制回炉)。
findings.push({
line: lineNo,
column: m.index + 1,
type: 'meta-leak',
severity: dialogue ? 'advisory' : 'blocking',
message: `工程词泄漏:「${m[0]}」是写作流水线术语,正文里不该出现;改成角色/场景内表达。${dialogue ? '例外:角色为作者/编剧、在故事内真实讨论创作时,台词里可能合法。' : ''}`,
excerpt: compact(trimmed.slice(Math.max(0, m.index - 6), m.index + 18)),
});
continue; // tier1 命中即可,不再叠 tier2
}
m = META_TIER2_RE.exec(trimmed);
if (m) {
findings.push({
line: lineNo,
column: m.index + 1,
type: 'meta-leak',
severity: 'advisory',
message: `元信息泄漏:「${m[0]}」疑似工程/章节结构词混入正文;改成角色当下可感知的事件锚点或相对时间。例外:角色在故事内真实阅读/讨论「第X章」、真身为作者/读者、或故事内系统/界面用语。`,
excerpt: compact(trimmed.slice(Math.max(0, m.index - 6), m.index + 18)),
});
}
}
return findings;
}
function hasYamlFrontMatter(lines) {
if (!lines[0] || lines[0].trim() !== '---') return false;
let sawYamlField = false;
for (let i = 1; i < Math.min(lines.length, 40); i += 1) {
const trimmed = lines[i].trim();
if (trimmed === '---') return sawYamlField;
if (/^[A-Za-z0-9_-]+:\s*/.test(trimmed)) sawYamlField = true;
}
return false;
}
function compact(text) {
const normalized = text.replace(/\s+/g, ' ').trim();
return normalized.length > 80 ? `${normalized.slice(0, 77)}...` : normalized;
}
scripts/check-outline-contract.js›
#!/usr/bin/env node
/**
* Deterministic 细纲 structural verifier for story-long-write.
*
* Usage:
* node scripts/check-outline-contract.js --json <细纲路径...>
* node scripts/check-outline-contract.js --json --project <书目录> --chapter N
* Exit: 0 = pass, 1 = blocking contract failures, 2 = invalid invocation.
*
* Scope is structural only: it decides whether the blueprint carries the fields,
* subsections and table shape the authoritative template names. It never judges
* whether a value is good. The contract itself sets this granularity —
* artifact-protocols.md 要求未知字段写 `[待补充]`,所以字段必须在场,值可以未知。
*/
'use strict'
const fs = require('fs')
const path = require('path')
// 权威模板:references/workflow-setup.md「细纲(全书每章)」
const FIELDS = [
'核心事件', '字数目标', '字数口径', '阶段位置', '单元ID/位置', '目标情绪',
'主角目标/关键选择', '章节定位', '本章结构公式', '章首钩子', '爽点',
'本章禁止提前释放', '契约风险',
]
const SUBSECTIONS = ['内容概括', '情节安排', '人物关系和出场顺序', '情节细化']
const FIVE_ACT = ['起因', '发展', '转折', '高潮', '结尾']
const PLOT_HEADER_FIRST = /^(?:#|序号)$/
// 这两个字段实测直接影响正文质量,必须有实际内容
const INTENT_FIELDS = ['目标情绪', '主角目标/关键选择']
const CALIBER = 'visible_chars_v1'
function fieldPattern(name) {
// 允许 -/*/+ 项目符号、可选 ** 加粗、全角或半角冒号
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
return new RegExp(`^\\s*[-*+]\\s*\\*{0,2}${escaped}\\*{0,2}\\s*[::]`, 'm')
}
function readUtf8(file) {
try {
const text = fs.readFileSync(file, 'utf8').replace(/^/, '')
return { ok: text.trim().length > 0, text }
} catch (error) {
return { ok: false, text: '', error: error.message }
}
}
function makeCheck(id, ok, file, evidence, expected, repair) {
return {
id,
ok,
severity: 'blocking',
file,
evidence,
expected,
references: ['references/workflow-setup.md', 'references/artifact-protocols.md'],
repair,
}
}
function parseTableRow(line) {
const trimmed = line.trim()
if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) return null
return trimmed.slice(1, -1).split('|').map((cell) => cell.replace(/\*\*/g, '').replace(/`/g, '').trim())
}
function verify(file) {
const name = path.basename(file)
const read = readUtf8(file)
const checks = []
checks.push(makeCheck(
'outline.readable',
read.ok,
name,
read.ok ? '文件存在且非空' : (read.error || '文件为空'),
'细纲文件存在且非空',
'只补建缺失的细纲文件,不改动同批其他章。'
))
if (!read.ok) return report(file, checks)
const text = read.text
const missingFields = FIELDS.filter((field) => !fieldPattern(field).test(text))
checks.push(makeCheck(
'outline.required-fields',
missingFields.length === 0,
name,
missingFields.length ? `缺字段:${missingFields.join('、')}` : `${FIELDS.length} 个字段齐全`,
`按权威模板列出全部字段:${FIELDS.join('、')};值未知时写 [待补充],不杜撰剧情`,
'只补报告里缺的字段行;确实还定不下来的写 [待补充],不为补字段新增副线或人物关系。'
))
// 隔离实验(同章、同写作流程,只改细纲):只补这两个字段就能复现补齐全部字段的收益,
// 盲评 3/3 胜过不补;补满五个字段与只补这两个不可区分。所以这两个字段不接受占位符,
// 其余字段仍按契约允许 [待补充]。
const hollow = INTENT_FIELDS.filter((field) => {
const match = text.match(new RegExp(`^\\s*[-*+]\\s*\\*{0,2}${field.replace('/', '\\/')}\\*{0,2}\\s*[::]\\s*(.*)$`, 'm'))
if (!match) return false
const value = match[1].replace(/\[待补充\]/g, '').replace(/[\s、,,。;;]/g, '')
return value.length === 0
})
checks.push(makeCheck(
'outline.intent-fields-substantive',
hollow.length === 0,
name,
hollow.length ? `只有占位符,没有实际内容:${hollow.join('、')}` : '目标情绪与主角目标/关键选择都写了实际内容',
'目标情绪写清前状态→后状态;主角目标/关键选择写清本章要什么、必须做出的判断。这两项不接受 [待补充]',
'只把这两个字段替换成本章的实际情绪变化与实际取舍;其余字段不动。'
))
const missingSubs = SUBSECTIONS.filter((sub) => !new RegExp(`^#{3,4}\\s*${sub}`, 'm').test(text))
checks.push(makeCheck(
'outline.subsections',
missingSubs.length === 0,
name,
missingSubs.length ? `缺小节:${missingSubs.join('、')}` : '四个小节齐全',
'包含 内容概括 / 情节安排 / 人物关系和出场顺序 / 情节细化 四个小节',
'只补缺失的小节标题及其条目,不重写已成立的内容。'
))
const missingActs = FIVE_ACT.filter((act) => !fieldPattern(act).test(text))
checks.push(makeCheck(
'outline.five-act',
missingActs.length === 0,
name,
missingActs.length ? `五段式缺:${missingActs.join('、')}` : '五段式齐全',
'内容概括写全 起因 / 发展 / 转折 / 高潮 / 结尾',
'只补缺的那一段,不改其余四段。'
))
const lines = text.split(/\r?\n/)
let header = null
for (const line of lines) {
const cells = parseTableRow(line)
if (cells && cells.length === 4 && PLOT_HEADER_FIRST.test(cells[0])) {
header = cells
break
}
}
const headerOk = Boolean(header) && header[2].includes('功能标签') && header[3].includes('执行边界')
checks.push(makeCheck(
'outline.plotpoint-table',
headerOk,
name,
header ? `表头:${header.join(' | ')}` : '未找到 | # | 情节点 | 功能标签 | 执行边界 | 表头',
'情节细化使用四列表格:# / 情节点(谁做了什么) / 功能标签 / 执行边界',
'只把情节点序列改成四列表格,逐点补功能标签与执行边界;不增删情节点本身。'
))
const targetMatch = text.match(/字数目标\s*[::]\s*(?:约\s*)?([\d,,]+)/)
const target = targetMatch ? Number(targetMatch[1].replace(/[,,]/g, '')) : null
const caliberOk = new RegExp(`字数口径\\s*[::]\\s*${CALIBER}`).test(text)
checks.push(makeCheck(
'outline.wordcount-target',
Boolean(target) && Number.isFinite(target) && target >= 500 && target <= 20000 && caliberOk,
name,
`字数目标:${target === null ? '未识别' : target};字数口径 ${CALIBER}:${caliberOk}`,
`字数目标为 500-20000 的正整数,并声明 字数口径:${CALIBER}`,
'只补字数目标或字数口径行,不调整情节安排。'
))
return report(file, checks)
}
function report(file, checks) {
const failures = checks.filter((check) => !check.ok)
return {
schema_version: 1,
verifier: 'story-long-write.outline-contract',
file: path.resolve(file),
ok: failures.length === 0,
checks,
failures,
repair_scope: failures.map((failure) => ({
id: failure.id,
file: failure.file,
evidence: failure.evidence,
expected: failure.expected,
references: failure.references,
repair: failure.repair,
})),
}
}
function resolveChapter(project, chapter) {
const dir = path.join(project, '大纲')
let entries
try {
entries = fs.readdirSync(dir)
} catch (error) {
return { error: `无法读取 ${dir}:${error.message}` }
}
const wanted = Number(chapter)
const hit = entries.find((entry) => {
const match = entry.match(/^细纲_第0*(\d+)章.*\.md$/)
return match && Number(match[1]) === wanted
})
if (!hit) return { error: `${dir} 下没有第 ${wanted} 章细纲` }
return { file: path.join(dir, hit) }
}
function parseArgs(argv) {
const files = []
let project = null
let chapter = null
for (let index = 0; index < argv.length; index++) {
const arg = argv[index]
if (arg === '--json') continue
if (arg === '--project' || arg === '--chapter') {
if (index + 1 >= argv.length || argv[index + 1].startsWith('--')) return null
const value = argv[++index]
if (arg === '--project') project = value
else chapter = value
continue
}
if (arg.startsWith('--')) return null
files.push(arg)
}
if (project || chapter) {
if (!project || !chapter || files.length || !/^\d+$/.test(chapter)) return null
return { project, chapter }
}
if (!files.length) return null
return { files }
}
function main(argv) {
const parsed = parseArgs(argv)
if (!parsed) {
process.stderr.write('用法: node scripts/check-outline-contract.js --json <细纲路径...> | --json --project <书目录> --chapter N\n')
return 2
}
let targets = parsed.files
if (!targets) {
const resolved = resolveChapter(parsed.project, parsed.chapter)
if (resolved.error) {
process.stderr.write(`${resolved.error}\n`)
return 2
}
targets = [resolved.file]
}
const reports = targets.map((file) => verify(file))
const ok = reports.every((entry) => entry.ok)
process.stdout.write(`${JSON.stringify(reports.length === 1 ? reports[0] : reports, null, 2)}\n`)
return ok ? 0 : 1
}
if (require.main === module) process.exitCode = main(process.argv.slice(2))
module.exports = { verify, FIELDS, SUBSECTIONS, FIVE_ACT }
scripts/check-outline-copy.js›
#!/usr/bin/env node
/**
* check-outline-copy.js — 细纲照搬检测
*
* 治的病:细纲把情节点写成成品散文句,正文只剩誊抄,质量被锁死在细纲水平。
* 实测正文与细纲连续重合最高 13.5%、单段最长 40 字,且重合段落多为叙述而非台词
* ——即全章最好的那几句在细纲阶段就写完了。
*
* 判定:正文与同章细纲连续重合 > 阈值(默认 15 字)即报出
* ——细纲只锁功能与结果,句子一律在正文现场写。
*
* 词面相同不等于不良照搬:系统面板、任务要求、固定专名本就该保持一致。因此本脚本
* 只提供证据(位置与片段),是否重写由 agent 读上下文语义判断,同 check-ai-patterns.js
* 的 advisory 轨——但每条都要有结论,不允许只报不改,也不为归零机械改写。
* 判定保留的只由主会话补进细纲锚句:子代理不改大纲细纲(见 narrative-writer「不自行改纲」),
* 否则子代理误判的重合会被自己写进白名单,主会话复扫时不再报出,第二层复核失明。
*
* 免报:细纲「复沓锚句」字段下列出的原话允许逐字落地——誓言、系统面板、
* 旧案原话等写细纲时判定必须原文出现的部分,逐行一条。只扣除锚句自身的精确区间,
* 前后剩余片段照常按阈值判定,避免紧挨锚句的照搬被顺带赦免。
* 豁免量单独统计并在报告末尾列出,滥用锚句绕过检测时一眼可见。
*
* 由 narrative-writer 落盘后自查、主会话收尾复扫时调用(两侧同一份实现,口径一致)。
* 不进 hook:正文兜底 hook 的共享核是四端共用的,不为单项检测扩面。
*
* 用法:
* node check-outline-copy.js <正文路径...> # 自动找同章细纲;短篇找同目录小节大纲
* node check-outline-copy.js --outline <细纲路径> <正文路径...> # 指定细纲
*
* 位置参数一律按正文处理,与 check-ai-patterns.js 的 `<file...>` 口径一致:
* 收尾复扫用 `正文/第XXX章_*.md` 这类通配传多章时,多出来的正文不能被当成细纲吞掉
* ——那会让首个文件比错对象、其余文件根本不检,静默退 0 报「干净」。
*
* 退出码:0 = 干净或无法判定(缺细纲/非分章正文);1 = 有重合待复核。
* 无发现时完全静默,不污染上下文。
*/
'use strict'
const fs = require('fs')
const path = require('path')
const MIN_RUN = 16 // 判定阈值:连续重合 >15 字,即 >=16
const REPORT_TOP = 8 // 最多列出的片段数
function read(p) {
try {
return fs.readFileSync(p, 'utf8').replace(/^/, '')
} catch {
return null
}
}
/** 只留汉字——剥掉标点/加粗/【】后比对,防止细纲标注造成假阴性 */
function hanOnly(s) {
return s.replace(/[^一-鿿]/g, '')
}
/**
* 抽出细纲「复沓锚句」字段下的原话,一行一条。
* 只认这一个字段,不扫情节点序列——锚句集中在固定区块,情节点保持只写「要发生什么」。
* 区块终止于行首无缩进的下一个字段(`- xxx`)或下一个小节标题,因此条目本身
* 用 `1.` 编号、缩进 `-` 列表或纯文本都能正确提取,不必额外标记。
*/
function extractAnchors(outline) {
const m = outline.match(/复沓锚句[^::\n]*[::]([\s\S]*?)(?=\n[-*+]\s|\n#{1,6}\s|$)/)
if (!m) return []
return m[1]
.split("\n")
// 去掉列表符号与「点N:」这类落点前缀,只留原话本身
.map((line) => line.replace(/^\s*[-*+]?\s*(?:\d+[.、)]\s*)?(?:点\s*\d+\s*[::])?/, ""))
.map((line) => hanOnly(line))
.filter((a) => a.length >= 2)
}
/**
* 在片段里定位锚句的精确出现区间,挖掉后返回剩余子段与豁免字数。
* 不能只判「片段包含锚句」就整段放行——贪心扫描求的是最长延伸,锚句嵌在中间时
* 会连同紧挨着它的未授权重合一起赦免。
*/
function splitByAnchors(frag, anchors) {
// 片段完全落在某条锚句内:整段豁免(抄了锚句的一部分,仍在授权范围)
if (anchors.some((a) => a.includes(frag))) return { rest: [], anchoredLen: frag.length }
const spans = []
for (const a of anchors) {
for (let from = 0; from + a.length <= frag.length; ) {
const at = frag.indexOf(a, from)
if (at < 0) break
spans.push([at, at + a.length])
from = at + 1 // 同一锚句重复出现要逐次记录
}
}
if (!spans.length) return { rest: [frag], anchoredLen: 0 }
spans.sort((x, y) => x[0] - y[0])
const merged = [spans[0]] // 多锚句重叠/相邻时并成一段,避免重复计数
for (const [s, e] of spans.slice(1)) {
const last = merged[merged.length - 1]
if (s <= last[1]) last[1] = Math.max(last[1], e)
else merged.push([s, e])
}
const rest = []
let cursor = 0
let anchoredLen = 0
for (const [s, e] of merged) {
if (s > cursor) rest.push(frag.slice(cursor, s))
anchoredLen += e - s
cursor = e
}
if (cursor < frag.length) rest.push(frag.slice(cursor))
return { rest, anchoredLen }
}
/** 定位同章细纲:遍历 大纲/ 按章号正则匹配,支持带后缀的文件名 */
function findOutline(proseFile) {
const base = path.basename(proseFile)
// 短篇没有章号:正文.md 与 小节大纲.md 在同目录平铺
if (base === '正文.md') {
const sibling = path.join(path.dirname(proseFile), '小节大纲.md')
return fs.existsSync(sibling) ? sibling : null
}
const m = base.match(/^第\s*0*(\d+)\s*章/)
if (!m) return null
const chapter = m[1]
const dir = path.join(path.dirname(path.dirname(proseFile)), '大纲')
try {
for (const file of fs.readdirSync(dir)) {
const fm = file.match(/^细纲_第0*(\d+)章.*\.md$/)
if (fm && fm[1] === chapter) return path.join(dir, file)
}
} catch {}
return null
}
function main() {
const proseFiles = []
let explicitOutline = null
const argv = process.argv.slice(2)
for (let k = 0; k < argv.length; k++) {
if (argv[k] === '--outline') explicitOutline = argv[++k] || null
else proseFiles.push(argv[k])
}
if (!proseFiles.length) {
process.stderr.write('用法: node check-outline-copy.js [--outline <细纲路径>] <正文路径...>\n')
return 0
}
// 逐个文件独立判定;任一文件有重合即整体退 1
let status = 0
for (const proseFile of proseFiles) {
if (checkOne(proseFile, explicitOutline)) status = 1
}
return status
}
function checkOne(proseFile, explicitOutline) {
const prose = read(proseFile)
if (prose === null) return 0
const outlineFile = explicitOutline || findOutline(proseFile)
if (!outlineFile) return 0
const outline = read(outlineFile)
if (outline === null) return 0
// 正文去掉标题行后比对
const P = hanOnly(prose.replace(/^#.*$/gm, ''))
const O = hanOnly(outline)
if (P.length < MIN_RUN || O.length < MIN_RUN) return 0
// 复沓锚句列出的原话允许逐字落地,命中后计入豁免、不判誊抄
const anchors = extractAnchors(outline)
// 贪心扫描:每个起点二分求「仍是细纲子串」的最长延伸,命中区间不重叠
const hits = []
let copied = 0
let anchored = 0
let anchoredCount = 0
let i = 0
while (i < P.length) {
let best = 0
if (i + MIN_RUN <= P.length && O.includes(P.substr(i, MIN_RUN))) {
best = MIN_RUN
let lo = MIN_RUN
let hi = Math.min(P.length - i, 200)
while (lo <= hi) {
const mid = (lo + hi) >> 1
if (O.includes(P.substr(i, mid))) {
best = mid
lo = mid + 1
} else hi = mid - 1
}
}
if (best) {
const frag = P.substr(i, best)
const { rest, anchoredLen } = splitByAnchors(frag, anchors)
if (anchoredLen) {
anchored += anchoredLen
anchoredCount++
}
// 挖掉锚句后的剩余子段仍是细纲子串,只需按阈值重判
for (const seg of rest) {
if (seg.length >= MIN_RUN) {
hits.push({ frag: seg, len: seg.length })
copied += seg.length
}
}
i += best
} else i++
}
if (!hits.length) {
// 全部命中都是锚句豁免:静默放行,但把豁免量报出来供人工复核滥用
if (anchoredCount) {
process.stdout.write(
`细纲照搬检测(${path.basename(proseFile)}):无未授权誊抄;` +
`另有 ${anchoredCount} 处 ${anchored} 字为复沓锚句的逐字落地。\n`
)
}
return 0
}
const rate = ((copied * 100) / P.length).toFixed(1)
const out = [
`=== 细纲照搬检测(${path.basename(proseFile)})===`,
`正文 ${P.length} 字,与 ${path.basename(outlineFile)} 连续重合 >${MIN_RUN - 1} 字的片段 ${hits.length} 处,共 ${copied} 字(${rate}%)。`,
`逐条对照原文判断:确属把细纲叙述搬进正文就重写——细纲只锁功能与结果,句子在正文现场写;系统面板、誓词、案卷原话、固定专名等功能性重合可保留。每条都要有结论,不为归零机械改写。保留项由主会话补进细纲「复沓锚句」——子代理只重写正文或标 \`[需复核]\` 交回,不改大纲细纲。`,
]
hits
.sort((a, b) => b.len - a.len)
.slice(0, REPORT_TOP)
.forEach((h) => out.push(` · ${h.len} 字「${h.frag}」`))
if (hits.length > REPORT_TOP) out.push(` · …另有 ${hits.length - REPORT_TOP} 处`)
if (anchoredCount) out.push(`(另有 ${anchoredCount} 处 ${anchored} 字为复沓锚句的逐字落地,不计入誊抄)`)
process.stdout.write(out.join('\n') + '\n')
return 1
}
try {
process.exit(main())
} catch {
process.exit(0)
}
scripts/normalize-punctuation.js›
#!/usr/bin/env node
'use strict';
const fs = require('fs');
const path = require('path');
const USAGE = `Usage: node normalize-punctuation.js [--check] [--quote-mode keep|ascii|yan] <file...>
Normalize正文 punctuation deterministically:
- replace ellipses, em dashes, and double hyphens with Chinese punctuation
- remove markdown divider lines (---) from正文
- keep quote style by default; convert quotes only when explicitly requested
`;
const options = {
check: false,
quoteMode: 'keep',
files: [],
};
for (let i = 2; i < process.argv.length; i += 1) {
const arg = process.argv[i];
if (arg === '--check') {
options.check = true;
} else if (arg === '--quote-mode') {
const value = process.argv[i + 1];
if (!value) die('--quote-mode requires keep, ascii, or yan');
options.quoteMode = value;
i += 1;
} else if (arg.startsWith('--quote-mode=')) {
options.quoteMode = arg.slice('--quote-mode='.length);
} else if (arg === '-h' || arg === '--help') {
process.stdout.write(USAGE);
process.exit(0);
} else if (arg.startsWith('-')) {
die(`Unknown option: ${arg}`);
} else {
options.files.push(arg);
}
}
if (!['keep', 'ascii', 'yan'].includes(options.quoteMode)) {
die(`Invalid --quote-mode: ${options.quoteMode}`);
}
if (options.files.length === 0) {
die('No files provided');
}
let totalFindings = 0;
let changedFiles = 0;
let failed = false;
for (const file of options.files) {
const fullPath = path.resolve(file);
let input;
try {
input = fs.readFileSync(fullPath, 'utf8');
} catch (error) {
failed = true;
console.error(`${file}: unable to read (${error.message})`);
continue;
}
const result = normalizeDocument(input, options.quoteMode);
totalFindings += result.findings.length;
if (options.check) {
for (const finding of result.findings) {
console.log(`${file}:${finding.line}:${finding.column}: ${finding.type}: ${finding.message}`);
}
continue;
}
if (result.output !== input) {
fs.writeFileSync(fullPath, result.output, 'utf8');
changedFiles += 1;
console.log(`${file}: normalized (${result.findings.length} issue${result.findings.length === 1 ? '' : 's'})`);
}
}
if (failed) {
process.exit(2);
}
if (options.check && totalFindings > 0) {
process.exit(1);
}
if (!options.check) {
console.log(`Done. Changed files: ${changedFiles}`);
}
function die(message) {
console.error(message);
console.error(USAGE.trimEnd());
process.exit(2);
}
function normalizeDocument(input, quoteMode) {
const { lines, endings } = splitLinesKeepingEndings(input);
const findings = [];
const outputLines = [];
let fence = null;
let inFrontMatter = hasYamlFrontMatter(lines);
let quoteOpen = false;
let commentOpen = false;
let commentStart = null;
const commentCloseAhead = new Array(lines.length + 1).fill(false);
for (let index = lines.length - 1; index >= 0; index -= 1) {
commentCloseAhead[index] = lines[index].includes('-->') || commentCloseAhead[index + 1];
}
for (let index = 0; index < lines.length; index += 1) {
const lineNo = index + 1;
const ending = endings[index];
let line = lines[index];
const trimmed = line.trim();
// 未闭合的 `<!--` 不能把余下整篇伪装成注释。确认 EOF 前已无 `-->` 时,
// 在起始位置具名报错,并从当前行恢复正文扫描;起始符所在行仍原样保护。
if (commentOpen && !commentCloseAhead[index]) {
findings.push({
line: commentStart?.line || lineNo,
column: commentStart?.column || 1,
type: 'html-comment-unclosed',
message: 'HTML 注释未闭合;后续内容仍按正文检查。',
});
commentOpen = false;
commentStart = null;
}
if (inFrontMatter) {
outputLines.push(line + ending);
if (index > 0 && trimmed === '---') inFrontMatter = false;
continue;
}
if (fence) {
outputLines.push(line + ending);
if (isClosingFence(line, fence)) fence = null;
continue;
}
const openingFence = parseOpeningFence(line);
if (openingFence) {
fence = openingFence;
outputLines.push(line + ending);
continue;
}
// 跨行 HTML 注释里的 `---` 是注释内容,不是正文分隔线。
if (trimmed === '---' && !commentOpen) {
findings.push({
line: lineNo,
column: line.indexOf('-') + 1,
type: 'markdown-divider',
message: '正文中不要使用 markdown 分隔线;建议移除该行。',
});
continue;
}
const commentOpenBefore = commentOpen;
const punctuationResult = normalizePausePunctuation(line, lineNo, commentOpen);
findings.push(...punctuationResult.findings);
line = punctuationResult.line;
commentOpen = punctuationResult.commentOpen;
if (!commentOpenBefore && commentOpen) {
commentStart = { line: lineNo, column: Math.max(1, line.lastIndexOf('<!--') + 1) };
} else if (!commentOpen) {
commentStart = null;
}
const quoteResult = normalizeQuotes(line, quoteMode, quoteOpen, lineNo);
findings.push(...quoteResult.findings);
line = quoteResult.line;
quoteOpen = quoteResult.quoteOpen;
outputLines.push(line + ending);
}
if (commentOpen) {
findings.push({
line: commentStart?.line || lines.length,
column: commentStart?.column || 1,
type: 'html-comment-unclosed',
message: 'HTML 注释未闭合;后续内容仍按正文检查。',
});
}
return {
output: outputLines.join(''),
findings,
};
}
// 逐行记住原始行尾。整篇按「文件里出现过 \r\n」统一行尾会让一个孤立 CRLF 把全文
// 行尾都翻成 CRLF——那是一次没人要求的全文件 diff,而 --check 对行尾一个 finding
// 都不报,只改标点的这一步不该动它。
function splitLinesKeepingEndings(input) {
const lines = [];
const endings = [];
let cursor = 0;
while (cursor < input.length) {
const newlineIndex = input.indexOf('\n', cursor);
if (newlineIndex === -1) {
lines.push(input.slice(cursor));
endings.push('');
break;
}
const crlf = newlineIndex > cursor && input[newlineIndex - 1] === '\r';
lines.push(input.slice(cursor, crlf ? newlineIndex - 1 : newlineIndex));
endings.push(crlf ? '\r\n' : '\n');
cursor = newlineIndex + 1;
}
return { lines, endings };
}
function parseOpeningFence(line) {
const match = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
if (!match) return null;
const marker = match[1];
const rest = match[2];
if (marker[0] === '`' && rest.includes('`')) return null;
return { marker: marker[0], minimumLength: marker.length };
}
function isClosingFence(line, fence) {
const marker = fence.marker === '`' ? '`' : '~';
const match = line.match(new RegExp(`^ {0,3}(${marker}{3,})[\\t ]*$`));
return Boolean(match && match[1].length >= fence.minimumLength);
}
// 删空停顿符会把两侧的半角点/连字符粘成新的 `...`/`--`(`他.……..说` → `他...说`),
// 一遍归一化留不干净,再跑一遍还会改已定稿的正文;所以反复归一化到不动点。
// 每遍至少把一个 `…/./—/-` 换成非停顿字符,字符数严格递减,必然收敛。
// findings 只留第一遍:同一处不重复计数,column 也仍然是原行的偏移。
function normalizePausePunctuation(line, lineNo, commentOpen) {
let current = line;
let findings = null;
let commentOpenAfter = commentOpen;
for (;;) {
const comments = htmlCommentSpans(current, commentOpen);
commentOpenAfter = comments.open;
const pass = normalizePausePunctuationPass(current, lineNo, comments.spans);
if (findings === null) findings = pass.findings;
if (pass.line === current) break;
current = pass.line;
}
return { line: current, findings, commentOpen: commentOpenAfter };
}
function normalizePausePunctuationPass(line, lineNo, commentSpans) {
const findings = [];
const original = line;
const pattern = /…+|\.{3,}|——|—|--+/g;
let output = '';
let lastIndex = 0;
let match;
while ((match = pattern.exec(original)) !== null) {
const token = match[0];
// HTML 注释是正文里的元信息(如 `<!-- 去味:跳过 -->` 豁免标记):`<!--`/`-->` 里的
// `--` 不是停顿标点,改掉它注释就散了,标记会变成读者看得见的正文。
if (insideSpans(match.index, match.index + token.length, commentSpans)) continue;
output += original.slice(lastIndex, match.index);
const replacement = choosePauseReplacement(original, match.index, token.length);
output += replacement;
findings.push({
line: lineNo,
column: match.index + 1,
type: getPauseType(token),
message: replacement ? `替换为「${replacement}」。` : '移除重复标点。',
});
lastIndex = match.index + token.length;
}
output += original.slice(lastIndex);
return { line: output, findings };
}
// 行内 HTML 注释区间(含 `<!--`、`-->` 本身);注释可跨行,未闭合时把状态交给下一行。
function htmlCommentSpans(line, openBefore) {
const spans = [];
let open = openBefore;
let cursor = 0;
while (cursor < line.length) {
if (open) {
const close = line.indexOf('-->', cursor);
if (close === -1) {
spans.push([cursor, line.length]);
return { spans, open: true };
}
spans.push([cursor, close + 3]);
cursor = close + 3;
open = false;
continue;
}
const start = line.indexOf('<!--', cursor);
if (start === -1) break;
cursor = start;
open = true;
}
return { spans, open };
}
function insideSpans(start, end, spans) {
return spans.some(([spanStart, spanEnd]) => start < spanEnd && end > spanStart);
}
function hasYamlFrontMatter(lines) {
if (!lines[0] || lines[0].trim() !== '---') return false;
let sawYamlField = false;
for (let i = 1; i < Math.min(lines.length, 40); i += 1) {
const trimmed = lines[i].trim();
if (trimmed === '---') return sawYamlField;
if (/^[A-Za-z0-9_-]+:\s*/.test(trimmed)) sawYamlField = true;
}
return false;
}
function getPauseType(token) {
if (token.startsWith('-')) return 'double-hyphen';
if (token.includes('—')) return 'em-dash';
return 'ellipsis';
}
function choosePauseReplacement(text, start, length) {
const before = previousNonSpace(text, start - 1);
const after = nextNonSpace(text, start + length);
const rest = text.slice(start + length).trimStart();
// 正文产物不保留 `……`、`——`、`—` 或 `--`;对话打断和数字区间不设例外。
if (before === '') return '';
// 紧跟开引号/开括号的停顿符号属于句首边界,删空即可,避免产出 `「,…」` 或 `「。」`。
if (isOpeningDelimiter(before)) return '';
if (/\d/.test(before) && /\d/.test(after)) return '到';
if (isClosingQuote(after)) return isSentencePunctuation(before) ? '' : '。';
if (!after) return isSentencePunctuation(before) ? '' : '。';
if (isSentencePunctuation(before) || isPunctuation(after)) return '';
if (/^(因为|原来|这是|那是|也就是|换句话|说白了|所谓|答案|原因|结果|真相|问题在于)/.test(rest)) return ':';
if (/(原因|答案|真相|结果|结论|问题|选择|意思)$/.test(text.slice(0, start).trim())) return ':';
return ',';
}
function previousNonSpace(text, index) {
for (let i = index; i >= 0; i -= 1) {
if (!/\s/.test(text[i])) return text[i];
}
return '';
}
function nextNonSpace(text, index) {
for (let i = index; i < text.length; i += 1) {
if (!/\s/.test(text[i])) return text[i];
}
return '';
}
function isSentencePunctuation(ch) {
return /[,,。.!!??;;::…]$/.test(ch || '');
}
function isPunctuation(ch) {
return /[,,。.!!??;;::、…"“”'‘’」』))]/.test(ch || '');
}
function isClosingQuote(ch) {
return /["”」』]/.test(ch || '');
}
function isOpeningDelimiter(ch) {
return /[「『((“‘]/.test(ch || '');
}
function normalizeQuotes(line, quoteMode, quoteOpen, lineNo) {
if (quoteMode === 'keep') {
return { line, findings: [], quoteOpen };
}
const findings = [];
let output = '';
for (let i = 0; i < line.length; i += 1) {
const ch = line[i];
if (quoteMode === 'ascii' && /[「」『』“”]/.test(ch)) {
output += '"';
findings.push({ line: lineNo, column: i + 1, type: 'quote-style', message: '按显式 quote-mode 转为半角双引号。' });
continue;
}
if (quoteMode === 'yan' && (ch === '"' || ch === '“' || ch === '”')) {
const replacement = quoteOpen || ch === '”' ? '」' : '「';
output += replacement;
quoteOpen = replacement === '「';
findings.push({ line: lineNo, column: i + 1, type: 'quote-style', message: '按显式 quote-mode 转为盐言引号。' });
continue;
}
output += ch;
}
return { line: output, findings, quoteOpen };
}
scripts/storyctl.py›
#!/usr/bin/env python3
"""Measure, checkpoint, check, and commit long-form story chapters."""
from __future__ import annotations
import argparse
import importlib.util
import json
import shutil
import subprocess
import sys
from pathlib import Path
from typing import Any, Sequence
def _load_local_module(name: str, filename: str) -> Any:
path = Path(__file__).with_name(filename)
spec = importlib.util.spec_from_file_location(name, path)
if spec is None or spec.loader is None:
raise RuntimeError(f"TOOL_UNAVAILABLE: {filename}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
core = _load_local_module("story_wordcount_core", "wordcount_core.py")
for _name in dir(core):
if not _name.startswith("_"):
globals()[_name] = getattr(core, _name)
CHAPTER_CHECK_SCHEMA = "story-chapter-check/v1"
CHAPTER_ERROR_SCHEMA = "story-chapter-error/v1"
class CliArgumentError(ValueError):
pass
class StructuredArgumentParser(argparse.ArgumentParser):
def error(self, message: str) -> None:
raise CliArgumentError(message)
def _tracking_module() -> Any:
return _load_local_module("story_tracking_for_storyctl", "tracking_commit.py")
def _tracking_call(function: Any, *args: Any) -> Any:
try:
return function(*args)
except Exception as exc:
if exc.__class__.__name__ == "TrackingError":
raise WordcountError(str(exc)) from exc
raise
def _json_line(payload: dict[str, Any]) -> None:
rendered = json.dumps(payload, ensure_ascii=False, separators=(",", ":")) + "\n"
# Windows runners may expose a cp1252 console even when callers explicitly
# consume UTF-8. Write protocol output as bytes so JSON never depends on
# the host console code page.
sys.stdout.buffer.write(rendered.encode("utf-8"))
sys.stdout.buffer.flush()
def _read_json_object(path: Path, label: str) -> dict[str, Any]:
try:
value = json.loads(path.read_text(encoding="utf-8"))
except (OSError, UnicodeError, json.JSONDecodeError) as exc:
raise WordcountError(f"unable to read {label}: {exc}") from exc
require(isinstance(value, dict), f"{label} must be an object")
return value
def _project_files(project: Path, chapter: int) -> tuple[Path, Path, int]:
root = project.resolve()
outline = find_chapter_file(root / "大纲", chapter, outline=True)
body = find_chapter_file(root / "正文", chapter, outline=False)
try:
target = target_from_outline(outline.read_text(encoding="utf-8"))
except (OSError, UnicodeError) as exc:
raise WordcountError(f"unable to read outline: {exc}") from exc
return outline, body, target
def _json_findings(output: str) -> list[dict[str, Any]]:
try:
value = json.loads(output or "{}")
except json.JSONDecodeError:
return []
findings = value.get("findings", []) if isinstance(value, dict) else []
return findings if isinstance(findings, list) else []
def check_blocking_quality(outline: Path, body: Path) -> dict[str, Any]:
node = shutil.which("node")
if node is None:
return {
"status": "fail",
"blocking_findings": [{"type": "TOOL_UNAVAILABLE", "message": "node is required for quality checks"}],
"advisories": [],
}
root = Path(__file__).parent
blocking: list[dict[str, Any]] = []
advisories: list[dict[str, Any]] = []
for name, script in (
("ai-pattern", "check-ai-patterns.js"),
("degeneration", "check-degeneration.js"),
):
path = root / script
if not path.is_file():
blocking.append({"type": "TOOL_UNAVAILABLE", "message": f"missing {script}"})
continue
completed = subprocess.run(
[node, str(path), "--check", "--json", "--fail-on=blocking", str(body)],
text=True, encoding="utf-8", capture_output=True, check=False,
)
findings = _json_findings(completed.stdout)
for finding in findings:
row = {"source": name, **finding}
(blocking if finding.get("severity") == "blocking" else advisories).append(row)
if completed.returncode not in {0, 1}:
blocking.append({"type": "TOOL_ERROR", "source": name, "message": completed.stderr.strip()})
punctuation = root / "normalize-punctuation.js"
if not punctuation.is_file():
blocking.append({"type": "TOOL_UNAVAILABLE", "message": "missing normalize-punctuation.js"})
else:
completed = subprocess.run(
[node, str(punctuation), "--check", str(body)],
text=True, encoding="utf-8", capture_output=True, check=False,
)
if completed.returncode != 0:
blocking.append(
{"type": "PUNCTUATION_NOT_NORMALIZED", "message": (completed.stdout or completed.stderr).strip()}
)
outline_copy = root / "check-outline-copy.js"
if not outline_copy.is_file():
blocking.append({"type": "TOOL_UNAVAILABLE", "message": "missing check-outline-copy.js"})
else:
completed = subprocess.run(
[node, str(outline_copy), "--outline", str(outline), str(body)],
text=True, encoding="utf-8", capture_output=True, check=False,
)
if completed.returncode != 0:
advisories.append(
{"source": "outline-copy", "type": "OUTLINE_COPY_REVIEW", "message": completed.stdout.strip()}
)
return {
"status": "fail" if blocking else "pass",
"blocking_findings": blocking,
"advisories": advisories,
}
def chapter_check(project: Path, chapter: int) -> dict[str, Any]:
outline, body_path, target = _project_files(project, chapter)
try:
body = body_path.read_text(encoding="utf-8")
except (OSError, UnicodeError) as exc:
raise WordcountError(f"unable to read body: {exc}") from exc
length = evaluate_wordcount(body, target, chapter=chapter)
quality = check_blocking_quality(outline, body_path)
length_ok = length["status"] in {"internal_pass", "borderline"}
if quality["status"] != "pass" or length["status"] == "invalid":
actions: list[str] = []
elif length_ok:
actions = ["commit"]
elif length["status"] == "over":
actions = ["compress-once", "accept-current-length", "revise-outline-or-target", "discard"]
else:
actions = ["accept-current-length", "revise-outline-or-target", "discard"]
tracking = _tracking_module()
state = _tracking_call(tracking.load_state, project)
compression = None
if length["status"] == "over" and quality["status"] == "pass":
actual = length["actual"]
compression = {
"mode": "single_pass_remove_only",
"remove_to_internal_band": {
"min": actual - length["internal_band"]["max"],
"max": actual - length["internal_band"]["min"],
},
"remove_to_user_band": {
"min": actual - length["user_band"]["max"],
"max": actual - length["user_band"]["min"],
},
}
return {
"schema": CHAPTER_CHECK_SCHEMA,
"chapter": chapter,
"length": length,
"quality": quality,
"compression": compression,
"state_revision": state["state_revision"],
"tracking_committed": state["last_committed_chapter"] >= chapter,
"next_chapter_started": state["last_committed_chapter"] > chapter,
"available_actions": actions,
}
def chapter_commit(project: Path, chapter: int, input_path: Path, *, accept_current_length: bool) -> dict[str, Any]:
checked = chapter_check(project, chapter)
require(checked["quality"]["status"] == "pass", "blocking quality findings must be fixed before commit")
length_status = checked["length"]["status"]
in_user_band = length_status in {"internal_pass", "borderline"}
if accept_current_length:
require(length_status in {"under", "over"}, "accept-current-length requires a valid out-of-band chapter")
resolution = "accepted_current_length"
else:
require(in_user_band, "chapter length is outside the user band; use accept-current-length or revise it")
resolution = "within_user_band"
document = _read_json_object(input_path, "tracking transaction")
require(document.get("chapter") == chapter, "tracking transaction chapter does not match command")
require("wordcount" not in document, "tracking transaction must not provide wordcount")
document["wordcount"] = build_project_wordcount_record(project, chapter, resolution=resolution)
tracking = _tracking_module()
state = _tracking_call(tracking.apply_transaction, project, document)
checked["tracking_committed"] = state["last_committed_chapter"] >= chapter
checked["next_chapter_started"] = state["last_committed_chapter"] > chapter
checked["wordcount"] = state["wordcount_records"].get(str(chapter))
return checked
def _build_parser() -> StructuredArgumentParser:
parser = StructuredArgumentParser(prog="storyctl.py")
commands = parser.add_subparsers(dest="command", required=True)
wordcount = commands.add_parser("wordcount")
wordcount_commands = wordcount.add_subparsers(dest="wordcount_command", required=True)
for command in ("measure", "check", "checkpoint"):
subparser = wordcount_commands.add_parser(command)
subparser.add_argument("--file", required=True)
subparser.add_argument("--chapter")
subparser.add_argument("--case-id")
if command != "measure":
subparser.add_argument("--target", required=True)
chapter = commands.add_parser("chapter")
chapter_commands = chapter.add_subparsers(dest="chapter_command", required=True)
for command in ("check", "commit", "accept-current-length"):
subparser = chapter_commands.add_parser(command)
subparser.add_argument("--project", type=Path, required=True)
subparser.add_argument("--chapter", type=int, required=True)
if command != "check":
subparser.add_argument("--input", type=Path, required=True)
return parser
def _wordcount_command(args: argparse.Namespace) -> int:
try:
body = Path(args.file).read_text(encoding="utf-8")
except (OSError, UnicodeError):
result = (
{"schema": MEASUREMENT_SCHEMA, "metric": METRIC, "chapter": args.chapter, "case_id": args.case_id,
"actual": None, "status": "invalid", "invalid_reason": "INVALID_FILE"}
if args.wordcount_command == "measure"
else invalid_wordcount_result("INVALID_FILE", chapter=args.chapter, case_id=args.case_id)
)
_json_line(result)
return 2
if args.wordcount_command == "measure":
result = measure_wordcount(body, chapter=args.chapter, case_id=args.case_id)
elif args.wordcount_command == "checkpoint":
try:
result = checkpoint_wordcount(body, args.target, chapter=args.chapter, case_id=args.case_id)
except WordcountError:
result = invalid_wordcount_result("INVALID_TARGET", chapter=args.chapter, case_id=args.case_id)
else:
result = evaluate_wordcount(body, args.target, chapter=args.chapter, case_id=args.case_id)
_json_line(result)
return 2 if result.get("status") == "invalid" else 0
def main(argv: Sequence[str] | None = None) -> int:
raw = list(argv) if argv is not None else sys.argv[1:]
try:
args = _build_parser().parse_args(raw)
except CliArgumentError as exc:
payload = (
{"schema": CHAPTER_ERROR_SCHEMA, "error_code": "INVALID_ARGUMENT", "message": str(exc)}
if raw[:1] == ["chapter"] else invalid_wordcount_result("INVALID_ARGUMENT", case_id=str(exc))
)
_json_line(payload)
return 2
if args.command == "wordcount":
return _wordcount_command(args)
try:
if args.chapter_command == "check":
result = chapter_check(args.project, args.chapter)
else:
result = chapter_commit(
args.project, args.chapter, args.input,
accept_current_length=args.chapter_command == "accept-current-length",
)
except (WordcountError, OSError, UnicodeError) as exc:
_json_line({"schema": CHAPTER_ERROR_SCHEMA, "error_code": "CHECK_FAILED", "message": str(exc)})
return 2
_json_line(result)
return 2 if result["quality"]["status"] != "pass" else 0
if __name__ == "__main__":
raise SystemExit(main())
scripts/tracking_commit.py›
#!/usr/bin/env python3
"""Maintain one structured story state and its deterministic Markdown views.
The language model supplies compact semantic JSON. This tool validates and
merges that input in memory, renders every derived view, then atomically writes
``_tracking-state.json`` last as the single commit point. Per-project locking
serializes concurrent writers before revision and wordcount checks.
"""
from __future__ import annotations
import argparse
import copy
import importlib.util
import json
import os
import re
import stat
import sys
import tempfile
import time
import unicodedata
from contextlib import contextmanager
from pathlib import Path
from typing import Any
_WORDCOUNT_CORE_PATH = Path(__file__).with_name("wordcount_core.py")
if not _WORDCOUNT_CORE_PATH.is_file(): # pragma: no cover - broken deployment
raise RuntimeError("TOOL_UNAVAILABLE: wordcount_core.py")
_WORDCOUNT_CORE_SPEC = importlib.util.spec_from_file_location(
"story_wordcount_core", _WORDCOUNT_CORE_PATH
)
if _WORDCOUNT_CORE_SPEC is None or _WORDCOUNT_CORE_SPEC.loader is None: # pragma: no cover
raise RuntimeError("unable to load wordcount core")
wordcount_core = importlib.util.module_from_spec(_WORDCOUNT_CORE_SPEC)
_WORDCOUNT_CORE_SPEC.loader.exec_module(wordcount_core)
INPUT_SCHEMA_VERSION = 1
TRACKING_SCHEMA_VERSION = 4
DELTA_TARGET_BYTES = 1536
DELTA_MAX_BYTES = 3072
CONTEXT_TARGET_BYTES = 8192
CONTEXT_MAX_BYTES = 12288
SNAPSHOT_TARGET_BYTES = 4096
SNAPSHOT_MAX_BYTES = 8192
CONTEXT_HEADINGS = (
"## 当前位置",
"## 长期约束",
"## 核心角色状态",
"## 活跃伏笔",
"## 近三章速记",
"## 下一章承诺",
"## 连贯性风险",
)
FORESHADOW_STATUSES = ("已埋", "已回收", "已过期", "放弃")
FORESHADOW_IMPORTANCE = ("高", "中", "低")
REVEAL_STATUSES = ("未揭示", "部分揭示", "已揭示")
INVALID_FILE_CHARS = re.compile(r"[<>:\"/\\|?*\x00-\x1f]")
FORESHADOW_ID = re.compile(r"^F\d{3,}$")
EVENT_ID = re.compile(r"^E\d{3,}$")
WINDOWS_RESERVED_NAMES = {
"CON",
"PRN",
"AUX",
"NUL",
*(f"COM{index}" for index in range(1, 10)),
*(f"LPT{index}" for index in range(1, 10)),
}
RETIRED_TRACKING_PATHS = (
"_tracking-meta.json",
"阶段摘要.md",
"角色状态.md",
"时间线.md",
"摘要",
"时间线/事件库.json",
)
RETIRED_ARCHIVE_DIR = "_旧追踪存档"
class TrackingError(ValueError):
"""Expected validation or tracking-state error."""
def require(condition: bool, message: str) -> None:
if not condition:
raise TrackingError(message)
def wordcount_value(function: Any, *args: Any, **kwargs: Any) -> Any:
try:
return function(*args, **kwargs)
except wordcount_core.WordcountError as exc:
raise TrackingError(str(exc)) from exc
def as_mapping(value: object, label: str) -> dict[str, Any]:
require(isinstance(value, dict), f"{label} must be a JSON object")
return value
def as_list(value: object, label: str) -> list[Any]:
require(isinstance(value, list), f"{label} must be a JSON array")
return value
def as_int(value: object, label: str, *, minimum: int = 0) -> int:
require(isinstance(value, int) and not isinstance(value, bool), f"{label} must be an integer")
require(value >= minimum, f"{label} must be >= {minimum}")
return value
def require_known_keys(mapping: dict[str, Any], allowed: set[str], label: str) -> None:
unknown = set(mapping) - allowed
require(not unknown, f"{label} contains unsupported fields: {', '.join(sorted(unknown))}")
def clean_text(value: object, label: str, *, allow_empty: bool = False, max_bytes: int = 768) -> str:
require(isinstance(value, str), f"{label} must be a string")
cleaned = " ".join(value.replace("|", "|").split())
require(allow_empty or bool(cleaned), f"{label} must not be empty")
require(len(cleaned.encode("utf-8")) <= max_bytes, f"{label} exceeds {max_bytes} bytes")
return cleaned
def clean_string_list(
value: object,
label: str,
*,
maximum: int | None = None,
item_max_bytes: int = 384,
) -> list[str]:
values = as_list(value, label)
if maximum is not None:
require(len(values) <= maximum, f"{label} may contain at most {maximum} items")
return [clean_text(item, f"{label}[{index}]", max_bytes=item_max_bytes) for index, item in enumerate(values)]
def safe_file_component(value: object, label: str) -> str:
name = unicodedata.normalize("NFC", clean_text(value, label, max_bytes=180))
require(not INVALID_FILE_CHARS.search(name), f"{label} contains an invalid filename character")
require(name not in {".", ".."} and not name.endswith((".", " ")), f"{label} is not a safe filename")
require(name.split(".", 1)[0].upper() not in WINDOWS_RESERVED_NAMES, f"{label} is reserved on Windows")
return name
def portable_name_key(name: str) -> str:
return unicodedata.normalize("NFC", name).casefold()
def byte_size(text: str) -> int:
return len(text.encode("utf-8"))
def emit(text: str, *, error: bool = False) -> None:
"""Write UTF-8 bytes directly.
Windows 的文本 stdout 是 cp1252(含中文即 UnicodeEncodeError),stderr 默认
backslashreplace(中文被转义成反斜杠码位,作者看不懂)。两条路都要绕开。
"""
stream = sys.stderr if error else sys.stdout
stream.flush()
stream.buffer.write((text + "\n").encode("utf-8"))
stream.buffer.flush()
def read_json(path: Path) -> object:
try:
return json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise TrackingError(f"unable to read JSON {path}: {exc}") from exc
def json_payload(document: object) -> str:
return json.dumps(document, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
def atomic_write_text(path: Path, payload: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
mode = stat.S_IMODE(path.stat().st_mode) if path.exists() else 0o644
fd, temporary_name = tempfile.mkstemp(prefix=f".{path.name}.", suffix=".tmp", dir=path.parent)
temporary = Path(temporary_name)
try:
with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as handle:
handle.write(payload)
handle.flush()
os.fsync(handle.fileno())
os.chmod(temporary, mode)
os.replace(temporary, path)
finally:
temporary.unlink(missing_ok=True)
def write_if_changed(path: Path, payload: str) -> None:
try:
if path.read_text(encoding="utf-8") == payload:
return
except FileNotFoundError:
pass
atomic_write_text(path, payload)
def tracking_root(project: Path) -> Path:
return project.resolve() / "追踪"
def state_path(project: Path) -> Path:
return tracking_root(project) / "_tracking-state.json"
@contextmanager
def project_write_lock(project: Path, *, timeout_seconds: float = 10.0):
tracking = tracking_root(project)
tracking.mkdir(parents=True, exist_ok=True)
path = tracking / ".tracking-commit.lock"
deadline = time.monotonic() + timeout_seconds
descriptor: int | None = None
while descriptor is None:
try:
descriptor = os.open(path, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o644)
except FileExistsError:
if time.monotonic() >= deadline:
raise TrackingError(
"tracking commit lock is busy or stale; retry, or remove 追踪/.tracking-commit.lock after confirming no commit is running"
)
time.sleep(0.05)
try:
os.write(descriptor, f"pid={os.getpid()}\n".encode("ascii"))
os.fsync(descriptor)
yield
finally:
os.close(descriptor)
try:
path.unlink()
except FileNotFoundError:
pass
def delta_path(tracking: Path, chapter: int) -> Path:
width = max(3, len(str(chapter)))
return tracking / "逐章记录" / f"第{chapter:0{width}d}章.md"
def find_retired_tracking_paths(tracking: Path) -> list[str]:
found = [relative for relative in RETIRED_TRACKING_PATHS if (tracking / relative).exists()]
found.extend(sorted(path.name for path in tracking.glob("基线_截至第*章.md")))
return found
def require_no_retired_tracking_paths(tracking: Path) -> None:
found = find_retired_tracking_paths(tracking)
require(not found, f"retired tracking files are not supported: {', '.join(found)}")
def archive_retired_tracking_paths(tracking: Path) -> list[str]:
"""Move a pre-transaction 追踪/ aside so init can build the current protocol in place.
Nothing is parsed or converted: the old files are kept verbatim for the author to
consult, and the new state is reconstructed from the init document alone.
"""
retired = find_retired_tracking_paths(tracking)
if not retired:
return []
archive = tracking / RETIRED_ARCHIVE_DIR
for relative in retired:
require(
not (archive / relative).exists(),
f"追踪/{RETIRED_ARCHIVE_DIR}/{relative} already exists; move it away before initializing",
)
# 先全量校验再搬运;中断后重跑时已搬走的条目不再出现在待搬列表里,可直接续做。
for relative in retired:
target = archive / relative
target.parent.mkdir(parents=True, exist_ok=True)
os.replace(tracking / relative, target)
return retired
def validate_position(value: object, label: str = "context.position") -> dict[str, Any]:
position = as_mapping(value, label)
require_known_keys(position, {"volume", "volume_start_chapter", "story_time", "scene"}, label)
return {
"volume": safe_file_component(position.get("volume"), f"{label}.volume"),
"volume_start_chapter": as_int(
position.get("volume_start_chapter"), f"{label}.volume_start_chapter", minimum=1
),
"story_time": clean_text(position.get("story_time"), f"{label}.story_time", max_bytes=240),
"scene": clean_text(position.get("scene"), f"{label}.scene", max_bytes=240),
}
def normalize_snapshot(value: object, label: str) -> dict[str, Any]:
snapshot = as_mapping(value, label)
require_known_keys(
snapshot,
{"identity", "location", "goal", "state", "abilities_resources", "relationships", "knowledge", "open_threads"},
label,
)
return {
"identity": clean_text(snapshot.get("identity"), f"{label}.identity", max_bytes=240),
"location": clean_text(snapshot.get("location"), f"{label}.location", max_bytes=240),
"goal": clean_text(snapshot.get("goal"), f"{label}.goal", max_bytes=300),
"state": clean_text(snapshot.get("state"), f"{label}.state", max_bytes=300),
"abilities_resources": clean_string_list(
snapshot.get("abilities_resources", []), f"{label}.abilities_resources"
),
"relationships": clean_string_list(snapshot.get("relationships", []), f"{label}.relationships"),
"knowledge": clean_string_list(snapshot.get("knowledge", []), f"{label}.knowledge"),
"open_threads": clean_string_list(snapshot.get("open_threads", []), f"{label}.open_threads"),
}
def normalize_snapshots(value: object, label: str = "character_snapshots") -> dict[str, dict[str, Any]]:
snapshots = as_mapping(value, label)
normalized: dict[str, dict[str, Any]] = {}
portable_names: set[str] = set()
for raw_name, raw_snapshot in snapshots.items():
name = safe_file_component(raw_name, f"{label} character name")
key = portable_name_key(name)
require(key not in portable_names, f"{label} contains a cross-platform duplicate character {name}")
portable_names.add(key)
normalized[name] = normalize_snapshot(raw_snapshot, f"{label}.{name}")
return normalized
def render_snapshot(name: str, snapshot: dict[str, Any], through_chapter: int, revision: int) -> str:
def section(title: str, values: list[str]) -> list[str]:
return [f"## {title}", *(f"- {item}" for item in values or ["无"]), ""]
lines = [
f"# {name}|当前状态",
"",
f"- 状态修订:{revision}",
f"- 截至章节:第{through_chapter}章",
f"- 身份:{snapshot['identity']}",
f"- 位置:{snapshot['location']}",
f"- 当前目标:{snapshot['goal']}",
f"- 身心状态:{snapshot['state']}",
"",
]
lines.extend(section("能力与资源", snapshot["abilities_resources"]))
lines.extend(section("关键关系", snapshot["relationships"]))
lines.extend(section("已知信息", snapshot["knowledge"]))
lines.extend(section("未结事项", snapshot["open_threads"]))
payload = "\n".join(lines).rstrip() + "\n"
require(
byte_size(payload) <= SNAPSHOT_MAX_BYTES,
f"character snapshot {name} exceeds hard cap of {SNAPSHOT_MAX_BYTES} bytes",
)
return payload
def normalize_foreshadow_change(
value: object,
label: str,
*,
allow_delete: bool,
through_chapter: int,
) -> dict[str, Any]:
row = as_mapping(value, label)
require_known_keys(
row,
{"action", "id", "summary", "planted_chapter", "planned_resolution_chapter", "status", "importance"},
label,
)
action = clean_text(row.get("action", "upsert"), f"{label}.action", max_bytes=24)
require(action in ({"upsert", "delete"} if allow_delete else {"upsert"}), f"{label}.action is invalid")
identifier = clean_text(row.get("id"), f"{label}.id", max_bytes=24)
require(FORESHADOW_ID.fullmatch(identifier) is not None, f"{label}.id must look like F001")
if action == "delete":
return {"action": action, "id": identifier}
planted_chapter = as_int(row.get("planted_chapter"), f"{label}.planted_chapter", minimum=1)
require(planted_chapter <= through_chapter, f"{label}.planted_chapter cannot be in the future")
planned_raw = row.get("planned_resolution_chapter")
planned_chapter = (
None if planned_raw is None else as_int(planned_raw, f"{label}.planned_resolution_chapter", minimum=1)
)
require(
planned_chapter is None or planned_chapter >= planted_chapter,
f"{label}.planned_resolution_chapter cannot precede planted_chapter",
)
status = clean_text(row.get("status"), f"{label}.status", max_bytes=24)
importance = clean_text(row.get("importance"), f"{label}.importance", max_bytes=12)
require(status in FORESHADOW_STATUSES, f"{label}.status must be one of {FORESHADOW_STATUSES}")
require(importance in FORESHADOW_IMPORTANCE, f"{label}.importance must be one of {FORESHADOW_IMPORTANCE}")
return {
"action": action,
"id": identifier,
"summary": clean_text(row.get("summary"), f"{label}.summary", max_bytes=360),
"planted_chapter": planted_chapter,
"planned_resolution_chapter": planned_chapter,
"status": status,
"importance": importance,
}
def normalize_foreshadow_state(value: object, last_chapter: int) -> dict[str, dict[str, Any]]:
rows = as_mapping(value, "tracking state.foreshadow")
normalized: dict[str, dict[str, Any]] = {}
for raw_identifier, raw_row in rows.items():
identifier = clean_text(raw_identifier, "tracking state.foreshadow ID", max_bytes=24)
row = as_mapping(raw_row, f"tracking state.foreshadow.{identifier}")
require_known_keys(
row,
{"id", "summary", "planted_chapter", "planned_resolution_chapter", "status", "importance", "updated_chapter"},
f"tracking state.foreshadow.{identifier}",
)
require(row.get("id") == identifier, f"tracking state.foreshadow.{identifier}.id does not match its key")
change = normalize_foreshadow_change(
{
"action": "upsert",
**{key: value for key, value in row.items() if key != "updated_chapter"},
},
f"tracking state.foreshadow.{identifier}",
allow_delete=False,
through_chapter=last_chapter,
)
change.pop("action")
updated = as_int(row.get("updated_chapter"), f"tracking state.foreshadow.{identifier}.updated_chapter", minimum=1)
require(updated <= last_chapter, f"foreshadow {identifier} updates after current chapter")
change["updated_chapter"] = updated
normalized[identifier] = change
return normalized
def render_foreshadow(rows: dict[str, dict[str, Any]], revision: int) -> str:
lines = [
"# 伏笔当前状态",
"",
f"> 状态修订:{revision}。每个 ID 只保留一行当前状态;历史变化见 `逐章记录/`。",
"",
"| ID | 内容 | 埋设章 | 计划回收章 | 状态 | 重要度 | 最近变更章 |",
"|---|---|---:|---:|---|---|---:|",
]
for identifier in sorted(rows):
row = rows[identifier]
planned = f"第{row['planned_resolution_chapter']}章" if row["planned_resolution_chapter"] else "—"
lines.append(
f"| {identifier} | {row['summary']} | 第{row['planted_chapter']}章 | {planned} | "
f"{row['status']} | {row['importance']} | 第{row['updated_chapter']}章 |"
)
return "\n".join(lines) + "\n"
def normalize_timeline_change(
value: object,
label: str,
*,
allow_delete: bool,
through_chapter: int,
) -> dict[str, Any]:
event = as_mapping(value, label)
require_known_keys(
event,
{"action", "id", "story_time", "objective_fact", "reader_knowledge", "reveal_status", "reveal_chapter", "characters"},
label,
)
action = clean_text(event.get("action", "upsert"), f"{label}.action", max_bytes=24)
require(action in ({"upsert", "delete"} if allow_delete else {"upsert"}), f"{label}.action is invalid")
identifier = clean_text(event.get("id"), f"{label}.id", max_bytes=24)
require(EVENT_ID.fullmatch(identifier) is not None, f"{label}.id must look like E001")
if action == "delete":
return {"action": action, "id": identifier}
reveal_status = clean_text(event.get("reveal_status"), f"{label}.reveal_status", max_bytes=24)
require(reveal_status in REVEAL_STATUSES, f"{label}.reveal_status must be one of {REVEAL_STATUSES}")
reveal_raw = event.get("reveal_chapter")
reveal_chapter = None if reveal_raw is None else as_int(reveal_raw, f"{label}.reveal_chapter", minimum=1)
if reveal_status == "未揭示":
require(reveal_chapter is None, f"{label} must not put a future reveal chapter in established timeline facts")
else:
require(reveal_chapter is not None, f"{label}.reveal_chapter is required once revealed")
require(reveal_chapter <= through_chapter, f"{label}.reveal_chapter cannot be in the future")
return {
"action": action,
"id": identifier,
"story_time": clean_text(event.get("story_time"), f"{label}.story_time", max_bytes=240),
"objective_fact": clean_text(event.get("objective_fact"), f"{label}.objective_fact", max_bytes=480),
"reader_knowledge": clean_text(event.get("reader_knowledge"), f"{label}.reader_knowledge", max_bytes=480),
"reveal_status": reveal_status,
"reveal_chapter": reveal_chapter,
"characters": clean_string_list(event.get("characters", []), f"{label}.characters", maximum=12, item_max_bytes=120),
}
def normalize_timeline_state(value: object, last_chapter: int) -> dict[str, dict[str, Any]]:
events = as_mapping(value, "tracking state.timeline")
normalized: dict[str, dict[str, Any]] = {}
for raw_identifier, raw_event in events.items():
identifier = clean_text(raw_identifier, "tracking state.timeline ID", max_bytes=24)
event = as_mapping(raw_event, f"tracking state.timeline.{identifier}")
require_known_keys(
event,
{
"id", "story_time", "objective_fact", "reader_knowledge", "reveal_status", "reveal_chapter",
"characters", "first_recorded_chapter", "updated_chapter",
},
f"tracking state.timeline.{identifier}",
)
require(event.get("id") == identifier, f"tracking state.timeline.{identifier}.id does not match its key")
change = normalize_timeline_change(
{
"action": "upsert",
**{
key: value
for key, value in event.items()
if key not in {"first_recorded_chapter", "updated_chapter"}
},
},
f"tracking state.timeline.{identifier}",
allow_delete=False,
through_chapter=last_chapter,
)
change.pop("action")
first = as_int(event.get("first_recorded_chapter"), f"tracking state.timeline.{identifier}.first_recorded_chapter", minimum=1)
updated = as_int(event.get("updated_chapter"), f"tracking state.timeline.{identifier}.updated_chapter", minimum=1)
require(first <= last_chapter, f"timeline event {identifier} starts after current chapter")
require(updated <= last_chapter, f"timeline event {identifier} updates after current chapter")
change["first_recorded_chapter"] = first
change["updated_chapter"] = updated
normalized[identifier] = change
return normalized
def render_timeline_views(events: dict[str, dict[str, Any]], revision: int) -> tuple[str, str]:
author_lines = [
"# 作者真相时间线",
"",
f"> 状态修订:{revision}。客观事实与读者认知的权威对照;未来揭示计划仍留在大纲。",
"",
"| ID | 首次登记章 | 故事时间 | 客观事实 | 读者当前认知 | 揭示状态 | 实际揭示章 |",
"|---|---:|---|---|---|---|---:|",
]
reader_lines = [
"# 读者已知时间线",
"",
f"> 状态修订:{revision}。只呈现读者截至当前章节已经知道或相信的内容,不泄露作者侧客观真相。",
"",
"| ID | 读者当前认知 | 认知截至章 |",
"|---|---|---:|",
]
for identifier in sorted(events):
event = events[identifier]
reveal = f"第{event['reveal_chapter']}章" if event.get("reveal_chapter") else "—"
characters = "、".join(event.get("characters", []))
objective = event["objective_fact"] + (f"(涉及:{characters})" if characters else "")
author_lines.append(
f"| {identifier} | 第{event['first_recorded_chapter']}章 | {event['story_time']} | {objective} | "
f"{event['reader_knowledge']} | {event['reveal_status']} | {reveal} |"
)
reader_lines.append(f"| {identifier} | {event['reader_knowledge']} | 第{event['updated_chapter']}章 |")
return "\n".join(author_lines) + "\n", "\n".join(reader_lines) + "\n"
def validate_context_input(value: object, *, include_initial_fields: bool) -> dict[str, Any]:
context = as_mapping(value, "context")
allowed = {"position", "long_term_constraints", "active_character_names", "continuity_risks"}
if include_initial_fields:
allowed.update({"recent_chapters", "next_chapter_commitments"})
require_known_keys(context, allowed, "context")
normalized: dict[str, Any] = {
"position": validate_position(context.get("position")),
"long_term_constraints": clean_string_list(
context.get("long_term_constraints", []), "context.long_term_constraints", maximum=6
),
"active_character_names": [
safe_file_component(name, f"context.active_character_names[{index}]")
for index, name in enumerate(as_list(context.get("active_character_names", []), "context.active_character_names"))
],
"continuity_risks": clean_string_list(
context.get("continuity_risks", []), "context.continuity_risks", maximum=5
),
}
require(len(normalized["active_character_names"]) <= 6, "context.active_character_names may contain at most 6 names")
require(
len({portable_name_key(name) for name in normalized["active_character_names"]})
== len(normalized["active_character_names"]),
"context.active_character_names contains cross-platform duplicates",
)
if include_initial_fields:
recent: list[dict[str, Any]] = []
for index, raw_item in enumerate(as_list(context.get("recent_chapters", []), "context.recent_chapters")):
item = as_mapping(raw_item, f"context.recent_chapters[{index}]")
require_known_keys(item, {"chapter", "summary"}, f"context.recent_chapters[{index}]")
recent.append(
{
"chapter": as_int(item.get("chapter"), f"context.recent_chapters[{index}].chapter", minimum=1),
"summary": clean_text(item.get("summary"), f"context.recent_chapters[{index}].summary", max_bytes=360),
}
)
require(len(recent) <= 3, "context.recent_chapters may contain at most 3 items")
normalized["recent_chapters"] = recent
normalized["next_chapter_commitments"] = clean_string_list(
context.get("next_chapter_commitments", []), "context.next_chapter_commitments", maximum=5
)
return normalized
def active_foreshadow_lines(rows: dict[str, dict[str, Any]]) -> list[str]:
importance = {value: index for index, value in enumerate(FORESHADOW_IMPORTANCE)}
candidates = [row for row in rows.values() if row["status"] == "已埋"]
candidates.sort(
key=lambda row: (importance[row["importance"]], row["planned_resolution_chapter"] or 10**12, row["id"])
)
result = []
for row in candidates[:8]:
planned = f"第{row['planned_resolution_chapter']}章" if row["planned_resolution_chapter"] else "回收章未定"
result.append(f"{row['id']}|{row['summary']}|埋第{row['planted_chapter']}章|{planned}|{row['importance']}")
return result
def render_context(state: dict[str, Any]) -> str:
context = state["context"]
position = context["position"]
current_chapter = (
"尚未开篇" if state["last_committed_chapter"] == 0 else f"第{state['last_committed_chapter']}章"
)
character_lines = [
f"{name}|{state['characters'][name]['identity']}|{state['characters'][name]['state']}|"
f"目标:{state['characters'][name]['goal']}"
for name in context["active_character_names"]
]
sections: list[tuple[str, list[str]]] = [
(
"## 当前位置",
[
f"当前章:{current_chapter}",
f"卷:{position['volume']}(始于第{position['volume_start_chapter']}章)",
f"故事时间:{position['story_time']}",
f"场景:{position['scene']}",
],
),
("## 长期约束", context["long_term_constraints"]),
("## 核心角色状态", character_lines),
("## 活跃伏笔", active_foreshadow_lines(state["foreshadow"])),
("## 近三章速记", [f"第{item['chapter']}章|{item['summary']}" for item in context["recent_chapters"]]),
("## 下一章承诺", context["next_chapter_commitments"]),
("## 连贯性风险", context["continuity_risks"]),
]
lines = [
f"# 写作连续性上下文 — {state['book_title']}",
"",
f"> 状态修订:{state['state_revision']}。截至当前章的续写状态卡,只放下一章真正需要的连续性状态。",
"",
]
for heading, values in sections:
lines.append(heading)
lines.extend(f"- {value}" for value in values or ["无"])
lines.append("")
payload = "\n".join(lines).rstrip() + "\n"
headings = tuple(line for line in payload.splitlines() if line.startswith("## "))
require(headings == CONTEXT_HEADINGS, "generated context headings do not match the seven-section schema")
require(byte_size(payload) <= CONTEXT_MAX_BYTES, f"hot context exceeds {CONTEXT_MAX_BYTES} bytes")
return payload
def normalize_delta(
value: object,
*,
through_chapter: int,
snapshots: dict[str, dict[str, Any]],
existing_core_names: dict[str, str],
) -> dict[str, Any]:
delta = as_mapping(value, "delta")
require_known_keys(
delta,
{
"result", "character_changes", "foreshadow_changes", "timeline_events", "constraints",
"next_chapter_commitments", "retired_context_items", "retired_characters",
},
"delta",
)
retired_characters = [
safe_file_component(name, f"delta.retired_characters[{index}]")
for index, name in enumerate(as_list(delta.get("retired_characters", []), "delta.retired_characters"))
]
retired_keys = [portable_name_key(name) for name in retired_characters]
require(len(retired_keys) == len(set(retired_keys)), "delta.retired_characters contains duplicate characters")
retiring = set(retired_keys)
character_changes: list[dict[str, Any]] = []
for index, raw_change in enumerate(as_list(delta.get("character_changes", []), "delta.character_changes")):
change = as_mapping(raw_change, f"delta.character_changes[{index}]")
require_known_keys(change, {"name", "change"}, f"delta.character_changes[{index}]")
name = safe_file_component(change.get("name"), f"delta.character_changes[{index}].name")
existing = existing_core_names.get(portable_name_key(name))
is_core = name in snapshots or existing is not None
# 本章退役的角色记录最后一次变化即可,不必再交一份马上要删的快照。
require(
not is_core or name in snapshots or portable_name_key(name) in retiring,
f"core character {name} changed but has no current snapshot",
)
character_changes.append(
{"name": name, "change": clean_text(change.get("change"), f"delta.character_changes[{index}].change", max_bytes=360)}
)
character_keys = [portable_name_key(item["name"]) for item in character_changes]
require(len(character_keys) == len(set(character_keys)), "delta.character_changes contains duplicate characters")
foreshadow_changes = [
normalize_foreshadow_change(
raw, f"delta.foreshadow_changes[{index}]", allow_delete=True, through_chapter=through_chapter
)
for index, raw in enumerate(as_list(delta.get("foreshadow_changes", []), "delta.foreshadow_changes"))
]
timeline_events = [
normalize_timeline_change(
raw, f"delta.timeline_events[{index}]", allow_delete=True, through_chapter=through_chapter
)
for index, raw in enumerate(as_list(delta.get("timeline_events", []), "delta.timeline_events"))
]
require(
len({item["id"] for item in foreshadow_changes}) == len(foreshadow_changes),
"delta.foreshadow_changes contains duplicate IDs",
)
require(
len({item["id"] for item in timeline_events}) == len(timeline_events),
"delta.timeline_events contains duplicate IDs",
)
require(
set(snapshots).issubset({item["name"] for item in character_changes}),
"character_snapshots must contain exactly the core characters changed by this transaction",
)
return {
"result": clean_text(delta.get("result"), "delta.result", max_bytes=480),
"character_changes": character_changes,
"foreshadow_changes": foreshadow_changes,
"timeline_events": timeline_events,
"constraints": clean_string_list(delta.get("constraints", []), "delta.constraints", maximum=6),
"next_chapter_commitments": clean_string_list(
delta.get("next_chapter_commitments", []), "delta.next_chapter_commitments", maximum=5
),
"retired_context_items": clean_string_list(
delta.get("retired_context_items", []), "delta.retired_context_items", maximum=11
),
"retired_characters": retired_characters,
}
def render_delta(chapter: int, title: str, delta: dict[str, Any], core_names: set[str]) -> str:
lines = [
f"# 第{chapter:03d}章 · {title}",
f"- 结果:{delta['result']}",
"- 下一章承诺:" + (";".join(delta["next_chapter_commitments"]) or "无"),
"",
"## 角色变化",
]
lines.extend(
f"- {item['name']}|{'核心' if item['name'] in core_names else '临时'}|{item['change']}"
for item in delta["character_changes"]
)
if not delta["character_changes"]:
lines.append("- 无")
lines.extend(["", "## 伏笔变化"])
for item in delta["foreshadow_changes"]:
if item["action"] == "delete":
lines.append(f"- {item['id']}|删除当前登记")
else:
planned = f"第{item['planned_resolution_chapter']}章" if item["planned_resolution_chapter"] else "未定"
lines.append(f"- {item['id']}|{item['status']}|{item['summary']}|回收{planned}")
if not delta["foreshadow_changes"]:
lines.append("- 无")
lines.extend(["", "## 时间与揭示"])
for item in delta["timeline_events"]:
if item["action"] == "delete":
lines.append(f"- {item['id']}|删除当前登记")
else:
lines.append(
f"- {item['id']}|{item['story_time']}|事实:{item['objective_fact']}|"
f"读者:{item['reader_knowledge']}|{item['reveal_status']}"
)
if not delta["timeline_events"]:
lines.append("- 无")
lines.extend(["", "## 连贯性约束"])
lines.extend(f"- {item}" for item in delta["constraints"])
if not delta["constraints"]:
lines.append("- 无")
retired = delta.get("retired_context_items", []) + [
f"角色状态:{name}" for name in delta.get("retired_characters", [])
]
if retired:
# 退役条目在此留档,续写状态卡收缩后仍可回查当初撤下了什么。
lines.extend(["", "## 本章退役登记"])
lines.extend(f"- {item}" for item in retired)
payload = "\n".join(lines) + "\n"
size = byte_size(payload)
require(size <= DELTA_MAX_BYTES, f"chapter delta is {size} bytes; hard cap is {DELTA_MAX_BYTES}")
return payload
def normalize_wordcount_records(value: object, last_chapter: int) -> dict[str, dict[str, Any]]:
records = as_mapping(value, "tracking state.wordcount_records")
normalized: dict[str, dict[str, Any]] = {}
for raw_chapter, raw_record in records.items():
require(isinstance(raw_chapter, str) and re.fullmatch(r"[1-9]\d*", raw_chapter) is not None,
"wordcount record chapter key is invalid")
chapter = int(raw_chapter)
require(chapter <= last_chapter, "wordcount record exceeds last committed chapter")
normalized[raw_chapter] = wordcount_value(wordcount_core.normalize_wordcount_record, raw_record)
return normalized
def normalize_state(document: object) -> dict[str, Any]:
root = as_mapping(document, "tracking state")
require_known_keys(
root,
{
"schema_version", "book_title", "last_committed_chapter", "imported_through_chapter",
"state_revision", "context", "characters", "foreshadow", "timeline",
"wordcount_records",
},
"tracking state",
)
require(root.get("schema_version") == TRACKING_SCHEMA_VERSION, "tracking state schema is unsupported")
last_chapter = as_int(root.get("last_committed_chapter"), "tracking state.last_committed_chapter")
imported_through = as_int(root.get("imported_through_chapter"), "tracking state.imported_through_chapter")
require(imported_through <= last_chapter, "imported chapter cutoff exceeds current chapter")
context = validate_context_input(root.get("context"), include_initial_fields=True)
require(
context["position"]["volume_start_chapter"] <= max(1, last_chapter),
"context.position.volume_start_chapter is after the current writing position",
)
recent_numbers = [item["chapter"] for item in context["recent_chapters"]]
require(recent_numbers == sorted(recent_numbers), "context.recent_chapters must be ordered")
require(len(recent_numbers) == len(set(recent_numbers)), "context.recent_chapters contains duplicates")
require(all(chapter <= last_chapter for chapter in recent_numbers), "context.recent_chapters cannot include future chapters")
characters = normalize_snapshots(root.get("characters", {}), "tracking state.characters")
for name in context["active_character_names"]:
require(name in characters, f"active core character {name} has no current snapshot")
foreshadow = normalize_foreshadow_state(root.get("foreshadow", {}), last_chapter)
timeline = normalize_timeline_state(root.get("timeline", {}), last_chapter)
if last_chapter == 0:
require(not foreshadow, "a chapter-0 project cannot have planted foreshadow facts")
require(not timeline, "a chapter-0 project cannot have established timeline facts")
state_revision = as_int(root.get("state_revision"), "tracking state.state_revision")
wordcount_records = normalize_wordcount_records(root.get("wordcount_records", {}), last_chapter)
return {
"schema_version": TRACKING_SCHEMA_VERSION,
"book_title": clean_text(root.get("book_title"), "tracking state.book_title", max_bytes=240),
"last_committed_chapter": last_chapter,
"imported_through_chapter": imported_through,
"state_revision": state_revision,
"context": context,
"characters": characters,
"foreshadow": foreshadow,
"timeline": timeline,
"wordcount_records": wordcount_records,
}
def load_state(project: Path) -> dict[str, Any]:
path = state_path(project)
require(path.exists(), "tracking state is missing; run init first")
return normalize_state(read_json(path))
def normalize_initial_document(document: object) -> dict[str, Any]:
root = as_mapping(document, "init input")
require_known_keys(
root,
{
"schema_version", "book_title", "last_chapter", "context", "character_snapshots",
"foreshadow", "timeline_events",
},
"init input",
)
require(root.get("schema_version") == INPUT_SCHEMA_VERSION, "init input schema_version is unsupported")
last_chapter = as_int(root.get("last_chapter"), "last_chapter")
context = validate_context_input(root.get("context"), include_initial_fields=True)
snapshots = normalize_snapshots(root.get("character_snapshots", {}))
foreshadow: dict[str, dict[str, Any]] = {}
for index, raw_row in enumerate(as_list(root.get("foreshadow", []), "foreshadow")):
row = normalize_foreshadow_change(
raw_row, f"foreshadow[{index}]", allow_delete=False, through_chapter=last_chapter
)
require(row["id"] not in foreshadow, f"duplicate foreshadow ID {row['id']}")
row.pop("action")
row["updated_chapter"] = max(1, last_chapter)
foreshadow[row["id"]] = row
timeline: dict[str, dict[str, Any]] = {}
for index, raw_event in enumerate(as_list(root.get("timeline_events", []), "timeline_events")):
event = normalize_timeline_change(
raw_event, f"timeline_events[{index}]", allow_delete=False, through_chapter=last_chapter
)
require(event["id"] not in timeline, f"duplicate timeline event ID {event['id']}")
event.pop("action")
event["first_recorded_chapter"] = max(1, last_chapter)
event["updated_chapter"] = max(1, last_chapter)
timeline[event["id"]] = event
return normalize_state(
{
"schema_version": TRACKING_SCHEMA_VERSION,
"book_title": clean_text(root.get("book_title"), "book_title", max_bytes=240),
"last_committed_chapter": last_chapter,
"imported_through_chapter": last_chapter,
"state_revision": 0,
"context": context,
"characters": snapshots,
"foreshadow": foreshadow,
"timeline": timeline,
"wordcount_records": {},
}
)
def normalize_transaction(project: Path, state: dict[str, Any], document: object) -> dict[str, Any]:
root = as_mapping(document, "transaction")
require_known_keys(
root,
{
"schema_version", "mode", "chapter", "chapter_title", "expected_state_revision",
"delta", "context", "character_snapshots", "wordcount",
},
"transaction",
)
require(root.get("schema_version") == INPUT_SCHEMA_VERSION, "transaction schema_version is unsupported")
mode = clean_text(root.get("mode"), "mode", max_bytes=24)
require(mode in {"append", "revision"}, "mode must be append or revision")
chapter = as_int(root.get("chapter"), "chapter", minimum=1)
expected_revision = as_int(root.get("expected_state_revision"), "expected_state_revision")
wordcount_input = root.get("wordcount")
require(expected_revision == state["state_revision"], "tracking state changed since this transaction was prepared")
last = state["last_committed_chapter"]
if mode == "append":
require(chapter == last + 1, f"append chapter must be {last + 1}, got {chapter}")
else:
require(chapter <= last, f"cannot revise unwritten chapter {chapter}; last committed chapter is {last}")
context = validate_context_input(root.get("context"), include_initial_fields=False)
snapshots = normalize_snapshots(root.get("character_snapshots", {}))
existing_names = {portable_name_key(name): name for name in state["characters"]}
for name in snapshots:
existing = existing_names.get(portable_name_key(name))
require(existing is None or existing == name, f"character {name} conflicts with existing character {existing}")
through_chapter = chapter if mode == "append" else last
delta = normalize_delta(
root.get("delta"),
through_chapter=through_chapter,
snapshots=snapshots,
existing_core_names=existing_names,
)
wordcount = None
if wordcount_input is not None:
wordcount = wordcount_value(
wordcount_core.validate_current_wordcount_record, project, chapter, wordcount_input
)
return {
"mode": mode,
"chapter": chapter,
"title": clean_text(root.get("chapter_title"), "chapter_title", max_bytes=240),
"delta": delta,
"context": context,
"snapshots": snapshots,
"wordcount": wordcount,
}
def checkpoint_record(
change: dict[str, Any], chapter: int, previous: dict[str, Any] | None, *, keep_first_chapter: bool = False
) -> dict[str, Any]:
current = {key: value for key, value in change.items() if key != "action"}
current["updated_chapter"] = max(previous["updated_chapter"] if previous else chapter, chapter)
if keep_first_chapter:
current["first_recorded_chapter"] = previous["first_recorded_chapter"] if previous else chapter
return current
def merge_transaction(state: dict[str, Any], transaction: dict[str, Any]) -> dict[str, Any]:
next_state = copy.deepcopy(state)
chapter = transaction["chapter"]
if transaction["mode"] == "append":
next_state["last_committed_chapter"] = chapter
next_state["state_revision"] += 1
next_state["characters"].update(transaction["snapshots"])
if transaction["wordcount"] is not None:
next_state["wordcount_records"][str(chapter)] = transaction["wordcount"]
next_context = transaction["context"]
# 退役说的是「从此刻起离开当前状态」,只有 append 的逐章记录代表此刻;
# 修订记录属于被改写的旧章,落在那里会谎报退役发生的章节。
is_revision = transaction["mode"] == "revision"
require(
not (is_revision and transaction["delta"]["retired_characters"]),
"retired_characters must be committed in an append transaction, not a revision",
)
for name in transaction["delta"]["retired_characters"]:
require(name in next_state["characters"], f"retired character {name} has no current snapshot")
require(
name not in transaction["snapshots"],
f"character {name} cannot be retired and updated in the same transaction",
)
require(
name not in next_context["active_character_names"],
f"retired character {name} is still listed in context.active_character_names",
)
next_state["characters"].pop(name)
# 上下文条目是整份提交的;漏写会静默丢历史裁定,因此掉落必须显式声明。
previous_items = set(state["context"]["long_term_constraints"]) | set(state["context"]["continuity_risks"])
dropped = previous_items - (set(next_context["long_term_constraints"]) | set(next_context["continuity_risks"]))
require(
not (is_revision and dropped),
"a revision must resubmit every current context item; retire them in an append transaction instead: "
+ ";".join(sorted(dropped)),
)
undeclared = sorted(dropped - set(transaction["delta"]["retired_context_items"]))
require(
not undeclared,
"context items were dropped without being declared in delta.retired_context_items: "
+ ";".join(undeclared),
)
transaction["delta"]["retired_context_items"] = sorted(dropped)
for change in transaction["delta"]["foreshadow_changes"]:
if change["action"] == "delete":
next_state["foreshadow"].pop(change["id"], None)
else:
next_state["foreshadow"][change["id"]] = checkpoint_record(
change, chapter, next_state["foreshadow"].get(change["id"])
)
for change in transaction["delta"]["timeline_events"]:
if change["action"] == "delete":
next_state["timeline"].pop(change["id"], None)
else:
next_state["timeline"][change["id"]] = checkpoint_record(
change, chapter, next_state["timeline"].get(change["id"]), keep_first_chapter=True
)
recent_by_chapter = {item["chapter"]: item for item in state["context"]["recent_chapters"]}
if chapter in recent_by_chapter or transaction["mode"] == "append":
recent_by_chapter[chapter] = {"chapter": chapter, "summary": transaction["delta"]["result"]}
recent = sorted(recent_by_chapter.values(), key=lambda item: item["chapter"])[-3:]
current_last = next_state["last_committed_chapter"]
next_commitments = (
transaction["delta"]["next_chapter_commitments"]
if transaction["mode"] == "append" or chapter == current_last
else state["context"]["next_chapter_commitments"]
)
next_state["context"] = {
**next_context,
"recent_chapters": recent,
"next_chapter_commitments": next_commitments,
}
return normalize_state(next_state)
def render_views(state: dict[str, Any]) -> dict[str, str]:
revision = state["state_revision"]
views = {
"上下文.md": render_context(state),
"伏笔.md": render_foreshadow(state["foreshadow"], revision),
}
author, reader = render_timeline_views(state["timeline"], revision)
views["时间线/作者真相.md"] = author
views["时间线/读者已知.md"] = reader
for name, snapshot in state["characters"].items():
views[f"角色状态/{name}.md"] = render_snapshot(
name, snapshot, state["last_committed_chapter"], revision
)
return views
def write_views(tracking: Path, views: dict[str, str]) -> None:
# 上下文携带 next revision,先写它;任何后续失败都会让 hook/check 发现
# 上下文 revision 与最后提交的 _tracking-state.json 不一致。
write_if_changed(tracking / "上下文.md", views["上下文.md"])
for relative in sorted(path for path in views if path != "上下文.md"):
write_if_changed(tracking / relative, views[relative])
expected_character_files = {
Path(relative).name for relative in views if relative.startswith("角色状态/")
}
character_dir = tracking / "角色状态"
character_dir.mkdir(parents=True, exist_ok=True)
for path in character_dir.glob("*.md"):
if path.name not in expected_character_files:
path.unlink()
def warn_sizes(views: dict[str, str], delta_payload: str | None = None) -> None:
if delta_payload is not None and byte_size(delta_payload) > DELTA_TARGET_BYTES:
emit(
f"WARNING: chapter delta is {byte_size(delta_payload)} bytes; target is <= {DELTA_TARGET_BYTES}",
error=True,
)
context_size = byte_size(views["上下文.md"])
if context_size > CONTEXT_TARGET_BYTES:
emit(f"WARNING: hot context is {context_size} bytes; target is <= {CONTEXT_TARGET_BYTES}", error=True)
for relative, payload in views.items():
if not relative.startswith("角色状态/"):
continue
size = byte_size(payload)
if size > SNAPSHOT_TARGET_BYTES:
emit(
f"WARNING: character snapshot {Path(relative).stem} is {size} bytes; target is <= {SNAPSHOT_TARGET_BYTES}",
error=True,
)
def _initialize_locked(project: Path, document: object) -> dict[str, Any]:
tracking = tracking_root(project)
require(not state_path(project).exists(), "tracking state already exists; init never overwrites project state")
state = normalize_initial_document(document)
views = render_views(state)
state_payload = json_payload(state)
# 输入全部校验通过后才动用户文件,失败的 init 不会挪走任何东西。
archived = archive_retired_tracking_paths(tracking)
for directory in (tracking / "逐章记录", tracking / "角色状态", tracking / "时间线"):
directory.mkdir(parents=True, exist_ok=True)
write_views(tracking, views)
atomic_write_text(state_path(project), state_payload)
warn_sizes(views)
if archived:
emit(
f"NOTE: 旧追踪结构已原样移入 追踪/{RETIRED_ARCHIVE_DIR}/:{', '.join(archived)};"
"当前状态以本次 init 输入为准,旧文件不参与解析。",
error=True,
)
return state
def initialize(project: Path, document: object) -> dict[str, Any]:
with project_write_lock(project):
return _initialize_locked(project, document)
def _apply_transaction_locked(project: Path, document: object) -> dict[str, Any]:
tracking = tracking_root(project)
require_no_retired_tracking_paths(tracking)
state = load_state(project)
transaction = normalize_transaction(project, state, document)
next_state = merge_transaction(state, transaction)
delta_payload = render_delta(
transaction["chapter"],
transaction["title"],
transaction["delta"],
# 本章退役的角色在 next_state 里已被删除,但本章记录里仍应标为核心。
set(next_state["characters"]) | set(transaction["delta"]["retired_characters"]),
)
views = render_views(next_state)
next_state_payload = json_payload(next_state)
path = delta_path(tracking, transaction["chapter"])
if transaction["mode"] == "append" and path.exists():
require(
path.read_text(encoding="utf-8") == delta_payload,
f"chapter delta {transaction['chapter']} already exists with different content",
)
write_if_changed(path, delta_payload)
write_views(tracking, views)
# 唯一权威文件最后落盘;在此之前失败可用同一事务直接重跑。
atomic_write_text(state_path(project), next_state_payload)
warn_sizes(views, delta_payload)
return next_state
def apply_transaction(project: Path, document: object) -> dict[str, Any]:
with project_write_lock(project):
return _apply_transaction_locked(project, document)
def check_project(project: Path) -> dict[str, Any]:
tracking = tracking_root(project)
require_no_retired_tracking_paths(tracking)
state = load_state(project)
last_chapter = state["last_committed_chapter"]
required_delta_start = state["imported_through_chapter"] + 1
for chapter in range(required_delta_start, last_chapter + 1):
require(delta_path(tracking, chapter).exists(), f"chapter delta {chapter} is missing")
for path in (tracking / "逐章记录").glob("第*章.md"):
match = re.fullmatch(r"第(\d+)章\.md", path.name)
require(match is not None, f"chapter delta has an invalid filename: {path.name}")
chapter = as_int(int(match.group(1)), f"chapter delta {path.name}", minimum=1)
require(path == delta_path(tracking, chapter), f"chapter delta {chapter} filename is not canonical")
require(chapter <= last_chapter, f"chapter delta {chapter} exceeds last_committed_chapter")
require(path.stat().st_size <= DELTA_MAX_BYTES, f"chapter delta {chapter} exceeds {DELTA_MAX_BYTES} bytes")
expected_views = render_views(state)
for relative, expected in expected_views.items():
path = tracking / relative
require(path.exists(), f"derived view is missing: {relative}")
require(
path.read_text(encoding="utf-8") == expected,
f"derived view differs from _tracking-state.json: {relative}",
)
expected_character_files = {
Path(relative).name for relative in expected_views if relative.startswith("角色状态/")
}
actual_character_files = {path.name for path in (tracking / "角色状态").glob("*.md")}
require(actual_character_files == expected_character_files, "character snapshot files differ from tracking state")
return state
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest="command", required=True)
for command in ("init", "commit"):
subparser = subparsers.add_parser(command)
subparser.add_argument("--project", type=Path, required=True, help="book project root containing 追踪/")
subparser.add_argument("--input", type=Path, required=True, help="UTF-8 JSON input document")
check_parser = subparsers.add_parser("check")
check_parser.add_argument("--project", type=Path, required=True, help="book project root containing 追踪/")
return parser
def main() -> int:
args = build_parser().parse_args()
try:
if args.command == "init":
result = initialize(args.project, read_json(args.input))
elif args.command == "commit":
result = apply_transaction(args.project, read_json(args.input))
else:
result = check_project(args.project)
except (TrackingError, OSError, UnicodeError) as exc:
emit(f"ERROR: {exc}", error=True)
return 2
emit(
json.dumps(
{
"last_committed_chapter": result["last_committed_chapter"],
"state_revision": result["state_revision"],
},
ensure_ascii=False,
)
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
scripts/wordcount_core.py›
#!/usr/bin/env python3
"""Small deterministic wordcount core shared by storyctl and tracking."""
from __future__ import annotations
import hashlib
import re
from pathlib import Path
from typing import Any
WORDCOUNT_SCHEMA = "story-wordcount-result/v1"
MEASUREMENT_SCHEMA = "story-wordcount-measurement/v1"
CHECKPOINT_SCHEMA = "story-wordcount-checkpoint/v1"
METRIC = "visible_chars_v1"
RESOLUTIONS = frozenset({"within_user_band", "accepted_current_length"})
_WHITE_SPACE_CODEPOINTS = frozenset(
[*range(0x0009, 0x000E)]
+ [
0x0020, 0x0085, 0x00A0, 0x1680, *range(0x2000, 0x200B),
0x2028, 0x2029, 0x202F, 0x205F, 0x3000,
]
)
_FRONTMATTER_KEY_RE = re.compile(r"^[A-Za-z_\u3400-\u9FFF][^:\n]{0,80}:[ \t]*(?:.*)$")
_LEADING_BLANK_RE = re.compile(r"^[\u0009\u0020\u3000]*$")
_ATX_HEADING_RE = re.compile(r"^[\u0009\u0020]{0,3}#{1,6}[\u0009\u0020]+\S")
_POSITIVE_INTEGER_RE = re.compile(r"^[1-9]\d*$")
_TARGET_LINE_RE = re.compile(r"^[ \t>*-]*字数目标[ \t]*[::][ \t]*([1-9]\d*)[ \t]*(?:字)?[ \t]*$", re.MULTILINE)
_METRIC_LINE_RE = re.compile(r"^[ \t>*-]*字数口径[ \t]*[::][ \t]*([A-Za-z0-9_-]+)[ \t]*$", re.MULTILINE)
class WordcountError(ValueError):
"""Expected deterministic wordcount contract failure."""
def require(condition: bool, message: str) -> None:
if not condition:
raise WordcountError(message)
def normalize_newlines(value: str) -> str:
return value.replace("\r\n", "\n").replace("\r", "\n")
def strip_recognizable_frontmatter(value: str) -> str:
lines = value.split("\n")
if not lines or lines[0] != "---":
return value
closing = next((index for index in range(1, min(len(lines), 201)) if lines[index] in {"---", "..."}), -1)
if closing < 2 or not any(_FRONTMATTER_KEY_RE.match(line) for line in lines[1:closing]):
return value
return "\n".join(lines[closing + 1 :])
def visible_body(value: str) -> str:
if not isinstance(value, str):
raise TypeError("body must be a string")
text = normalize_newlines(value)
if text.startswith("\ufeff"):
text = text[1:]
lines = strip_recognizable_frontmatter(text).split("\n")
while lines and _LEADING_BLANK_RE.match(lines[0]):
lines.pop(0)
if lines and _ATX_HEADING_RE.match(lines[0]):
lines.pop(0)
return "\n".join(lines)
def count_visible_chars(value: str) -> int:
return sum(ord(character) not in _WHITE_SPACE_CODEPOINTS for character in visible_body(value))
def parse_target(value: Any) -> int:
raw = str(value if value is not None else "")
if not _POSITIVE_INTEGER_RE.fullmatch(raw):
raise WordcountError("target must be a positive integer")
target = int(raw)
require(target <= 9_007_199_254_740_991, "target exceeds Number.MAX_SAFE_INTEGER")
return target
def compute_wordcount_bands(value: Any) -> dict[str, dict[str, int]]:
target = parse_target(value)
return {
"internal": {"min": (target * 88 + 99) // 100, "max": target * 112 // 100},
"user": {"min": (target * 85 + 99) // 100, "max": target * 115 // 100},
}
def invalid_wordcount_result(
reason: str, *, chapter: Any = None, case_id: Any = None,
target: int | None = None, actual: int | None = None,
) -> dict[str, Any]:
return {
"schema": WORDCOUNT_SCHEMA, "metric": METRIC, "chapter": chapter, "case_id": case_id,
"target": target, "actual": actual, "internal_band": None, "user_band": None,
"signed_error_pct": None, "absolute_error_pct": None,
"status": "invalid", "invalid_reason": reason,
}
def measure_wordcount(value: str, *, chapter: Any = None, case_id: Any = None) -> dict[str, Any]:
try:
actual = count_visible_chars(value)
except (TypeError, ValueError):
return {
"schema": MEASUREMENT_SCHEMA, "metric": METRIC, "chapter": chapter,
"case_id": case_id, "actual": None, "status": "invalid", "invalid_reason": "INVALID_BODY",
}
return {
"schema": MEASUREMENT_SCHEMA, "metric": METRIC, "chapter": chapter,
"case_id": case_id, "actual": actual, "status": "measured", "invalid_reason": None,
}
def evaluate_wordcount(
value: str, target_value: Any, *, chapter: Any = None, case_id: Any = None,
) -> dict[str, Any]:
try:
target = parse_target(target_value)
except (TypeError, ValueError):
return invalid_wordcount_result("INVALID_TARGET", chapter=chapter, case_id=case_id)
try:
actual = count_visible_chars(value)
except (TypeError, ValueError):
return invalid_wordcount_result("INVALID_BODY", chapter=chapter, case_id=case_id, target=target)
if actual == 0:
return invalid_wordcount_result("EMPTY_BODY", chapter=chapter, case_id=case_id, target=target, actual=actual)
bands = compute_wordcount_bands(target)
internal_pass = bands["internal"]["min"] <= actual <= bands["internal"]["max"]
user_pass = bands["user"]["min"] <= actual <= bands["user"]["max"]
status = "internal_pass" if internal_pass else (
"borderline" if user_pass else ("under" if actual < bands["user"]["min"] else "over")
)
signed_error = (actual - target) / target
return {
"schema": WORDCOUNT_SCHEMA, "metric": METRIC, "chapter": chapter, "case_id": case_id,
"target": target, "actual": actual,
"internal_band": {**bands["internal"], "status": "pass" if internal_pass else "fail"},
"user_band": {**bands["user"], "status": "pass" if user_pass else "fail"},
"signed_error_pct": signed_error, "absolute_error_pct": abs(signed_error),
"status": status, "invalid_reason": None,
}
def checkpoint_wordcount(
value: str, target_value: Any, *, chapter: Any = None, case_id: Any = None,
) -> dict[str, Any]:
target = parse_target(target_value)
actual = count_visible_chars(value)
user = compute_wordcount_bands(target)["user"]
return {
"schema": CHECKPOINT_SCHEMA, "metric": METRIC, "chapter": chapter, "case_id": case_id,
"target": target, "actual": actual, "user_band": user,
"remaining_user_range": {
"min": max(0, user["min"] - actual),
"max": max(0, user["max"] - actual),
},
}
def target_from_outline(value: str) -> int:
text = normalize_newlines(value)
if text.startswith("\ufeff"):
text = text[1:]
targets = list(dict.fromkeys(_TARGET_LINE_RE.findall(text)))
metrics = list(dict.fromkeys(_METRIC_LINE_RE.findall(text)))
require(len(targets) == 1, "字数目标 must appear exactly once with one value")
require(metrics == [METRIC], f"字数口径 must appear exactly once as {METRIC}")
return parse_target(targets[0])
def _chapter_number_from_name(name: str, *, outline: bool) -> int | None:
pattern = r"^细纲_第0*(\d+)章.*\.md$" if outline else r"^第0*(\d+)章(?:[_\- ].*)?\.md$"
match = re.match(pattern, name)
return int(match.group(1)) if match else None
def find_chapter_file(directory: Path, chapter: int, *, outline: bool) -> Path:
require(isinstance(chapter, int) and not isinstance(chapter, bool) and chapter >= 1, "chapter must be >= 1")
require(directory.is_dir(), f"chapter directory is missing: {directory}")
matches = sorted(
path for path in directory.iterdir()
if path.is_file() and _chapter_number_from_name(path.name, outline=outline) == chapter
)
label = "outline" if outline else "body"
require(len(matches) == 1, f"chapter {chapter} must have exactly one {label} file")
return matches[0]
def build_project_wordcount_record(project: Path, chapter: int, *, resolution: str) -> dict[str, Any]:
require(resolution in RESOLUTIONS, f"unsupported wordcount resolution: {resolution}")
root = project.resolve()
outline_path = find_chapter_file(root / "大纲", chapter, outline=True)
body_path = find_chapter_file(root / "正文", chapter, outline=False)
try:
target = target_from_outline(outline_path.read_text(encoding="utf-8"))
body_bytes = body_path.read_bytes()
body = body_bytes.decode("utf-8")
except (OSError, UnicodeError) as exc:
raise WordcountError(f"unable to read chapter files: {exc}") from exc
result = evaluate_wordcount(body, target, chapter=chapter)
require(result["status"] != "invalid", f"invalid chapter wordcount: {result['invalid_reason']}")
in_user_band = result["status"] in {"internal_pass", "borderline"}
require(
(resolution == "within_user_band" and in_user_band)
or (resolution == "accepted_current_length" and not in_user_band),
"wordcount resolution does not match the current length",
)
return {
"metric": METRIC,
"target": result["target"],
"actual": result["actual"],
"status": result["status"],
"resolution": resolution,
"body_sha256": hashlib.sha256(body_bytes).hexdigest(),
}
def normalize_wordcount_record(value: object) -> dict[str, Any]:
require(isinstance(value, dict), "wordcount record must be an object")
require(
set(value) == {"metric", "target", "actual", "status", "resolution", "body_sha256"},
"wordcount record fields are invalid",
)
require(value.get("metric") == METRIC, "wordcount metric is unsupported")
target = parse_target(value.get("target"))
actual = value.get("actual")
require(isinstance(actual, int) and not isinstance(actual, bool) and actual >= 1, "wordcount actual is invalid")
expected = evaluate_wordcount("字" * actual, target)
require(value.get("status") == expected["status"], "wordcount status does not match target and actual")
resolution = value.get("resolution")
require(resolution in RESOLUTIONS, "wordcount resolution is unsupported")
in_user_band = expected["status"] in {"internal_pass", "borderline"}
require((resolution == "within_user_band") == in_user_band, "wordcount resolution does not match status")
digest = value.get("body_sha256")
require(isinstance(digest, str) and re.fullmatch(r"[0-9a-f]{64}", digest) is not None, "body_sha256 is invalid")
return dict(value)
def validate_current_wordcount_record(project: Path, chapter: int, value: object) -> dict[str, Any]:
record = normalize_wordcount_record(value)
current = build_project_wordcount_record(project, chapter, resolution=record["resolution"])
require(record == current, "wordcount record is stale for the current body or target")
return record
SKILL.md›
---
name: story-long-write
version: 1.0.0
description: "长篇网文写作。从大纲到正文,辅助长篇网络小说的创作,包括世界观、人物、情节线管理。触发方式:/story-long-write、/写长篇、「帮我开书」「写大纲」「日更」「续写」「继续写」「修改第X章」「回炉」「重写第X章」。"
metadata: {"openclaw":{"source":"https://github.com/zenstory-ai/oh-story-claudecode"}}
---
# story-long-write:长篇网文写作
你是网络小说创作教练。你的任务是帮用户从零开始写一本长篇网络小说,从选题确认到大纲搭建再到正文输出。
## 章节 Reference Gate(强制,先读后写)
任何创建或修改长篇故事文件的动作前,先判断场景并完成本轮门禁。**只读本 SKILL.md 不算完成;`rg` 检索或局部摘读也不算完整读取。**
必须分块读到 EOF:
1. 开书/补纲先完整读取 `references/workflow-setup.md`;写指定章读取 `references/workflow-chapter.md`;日更/大修先读取 `references/workflow-daily.md` 或 `references/workflow-revision.md`,进入正文前再完整读取 `workflow-chapter.md`。
2. 主会话直接写正文时,首次落笔前完整读取 `references/long-format.md`、`references/writing-craft.md`、`references/long-chapter-quality.md`、`references/long-chapter-hooks.md`;交给 narrative-writer 时,由该 agent 按自己的 reference 表完成同等写前读取,主会话不得用未读 reference 的临时 prompt 替代。
3. 悬疑、惊悚、异常线索章加读 `references/long-suspense.md`;身份/认知/立场反转章加读 `references/long-reversal.md`。
4. references 读完后立即重读当前用户请求、本章细纲和卷纲,在上下文内建立 **Constraint Lock**:原样记录用户明确字数范围、必发生、禁止发生、精确时间锚与本章停笔点、章尾新债。references 只提供技法,不得覆盖这些项目事实;用户明确范围优先于自动 ± 比例带。交付前逐项复核:字数带外按 `workflow-chapter.md` 的收口流程交用户处置,不自动补字;其余项越界不算完成。
任一必需路径不存在、不可读或未读完时立即停止,报告准确路径,**不得先写正文再补读**。门禁按当前任务、当前会话重新执行;旧会话的“读过”不能沿用。
---
> 内置适配 Claude Code / OpenCode / Codex / Antigravity / ZCode / OpenClaw。专业 agent 只查当前端 canonical 目录(`.claude/agents`、`.opencode/agents`、`.codex/agents` TOML、`.agents/agents`);Antigravity 用 `invoke_subagent` + 同名 `TypeName`。文件或运行时能力缺失、返回 unknown agent,或当前为不执行 custom agents 的 ZCode 3.3.4 时,报告 fallback 并 solo/direct 执行。
>
> Spawn 版本提示(不阻断 spawn):先读取项目根 `.story-deployed` 的 `agents_version`。与本版 `agents_version: 28` 不一致时(标记缺失、字段缺失/非整数、小于或大于 28)**照常按文件存在性检查并 spawn**,但只检查当前运行时的 canonical 目录;同时报告 `Notice: agents bundle 版本不匹配(项目 {N},本版 28)` 并提示重新运行 `/story-setup` 后新开会话;大于 28 时额外提示先更新 oh-story-claudecode,不要用本地旧版 setup 降级覆盖。只有 agent 文件缺失、或运行时不暴露 custom agent 时才降级 solo/direct,报告 `Fallback: ... -> solo`。
## 核心方法
我们写网文先抓情绪,再用验证过的方法可靠地交付这个情绪,灵感只做素材来源。
1. **先定情绪,再定故事**。每个场景都必须服务于一个明确的情绪目标。说不清交付什么情绪的场景不该存在。
2. **从验证过的模式出发**。先问"什么被验证过有效,我如何重新交付",少从"我想写什么"直接起步。扫榜找方向,拆文找模块,对标找节奏。
3. **用模块组装,不要重新发明**。每个题材都有验证过的剧情模式——反转怎么铺、爽点怎么爆、感情怎么拉扯。找到对的模块,把对标书的具体角色看成功能位(对手/盟友/催化剂),再映射到你的角色。用你自己的素材填充这些功能位。
4. **只加载必需信息**。写每章只读“不知道就会写错”的角色状态、待收伏笔、相关设定。其余留在文件系统里。
5. **契约与推进决策走权威参考文件**。涉及读者契约、主角代理权、利益安全、期待债、终局储备(终局底牌/升级台阶)、机构/势力边界和 契约安全 / 需补强 / 契约破坏 风险判定时,先按 `references/reader-contract-and-progression.md` 校准,不在 SKILL.md 内复制长规则。
6. **复用作者习惯**。若作者记忆 state 已存在,正文前用 `scripts/author_memory_commit.py query --kind prose_style --kind story_design` 获取本次相关 active 条目(总输出 ≤2KB),原样传给实际正文/改写 agent;设定/大纲按任务查询其他 kind。硬门禁、当前请求、本书设定/文风优先。明确长期声明在收尾用 `record` 写入并回传回执;完整规则见 [references/author-memory.md](references/author-memory.md),不混入追踪。
| 题材 | 核心情绪 | 重点参考 |
|------|---------|---------|
| 打脸/逆袭 | 爽感释放 | plot-emotion-system.md + style-combat-face.md |
| 身份反转 | 震撼+痛快 | long-reversal.md |
| 感情拉扯 | 意难平 | emotional-methods.md |
| 悬疑/惊悚 | 紧张+好奇 | long-suspense.md |
| 日常装逼 | 期待感 | long-chapter-hooks.md |
> **情绪反查题材**:如果用户先说了情绪感觉但没提题材,从上表反向匹配——例如「爽感释放」指向打脸/逆袭,再从 `long-genre-catalog.md` 找该题材下的细分方向。
---
## 写作流程
根据用户意图和项目状态选择场景:
| 场景 | 触发条件 | 执行流程 |
|------|----------|----------|
| **开书** | "帮我开书" / 项目目录为空 | Phase 1→2→3:建项目、核心设定、卷纲与首批 10 章细纲;**默认停在细纲交付,不自动写正文** |
| **写指定章** | "写第 N 章" / "写第1章" / "开书并写首章" | Phase 4 单章写作;只写用户点名的章节,写完 Phase 5 检查后停止。空项目/无细纲(如"开书并写首章")先补 Phase 1→3 再写点名章 |
| **补纲/扩纲** | "出细纲/补细纲/规划下一段剧情/接下来写XX剧情(先出细纲)" **且**项目已有大纲 | Phase 3「中途补纲/扩纲小流程」(见 `references/workflow-setup.md`):选同类剧情单元→追加剧情单元卡→按剧情批滚动补细纲;**默认停在细纲交付,不自动写正文** |
| **日更续写** | 关键词("日更"/"续写"/"继续写")**且**项目已有正文+追踪 | 加载 `references/workflow-daily.md` |
| **大修** | "修改第X章" / "回炉" / "重写第X章" | 加载 `references/workflow-revision.md` |
> **开新卷**:如果新卷引入新角色/势力/设定,先回 Phase 2 增量补充,再进 Phase 3 补充新卷细纲,最后 Phase 4 写作。如果纯延续,直接回 Phase 3。
### 裸调用与停靠点(防失控)
`/story-long-write` 或 `$story-long-write` **裸调用**(没有"开书/写第N章/日更/续写/修改"等明确意图)时,先只做项目状态诊断并列出下一步选项,**不得自动进入正文写作,也不得把已有项目默认为日更 3 章**:
- 空项目 → 建议说「帮我开书」或先提供 `选题决策.md`;
- 已有设定/大纲但无正文 → 建议说「写第1章」「只写1章」或「日更2章」;
- 已有正文+追踪 → 展示最后完成章节与下一章细纲状态,建议说「日更3章」「只写1章」「逐章确认」或「修改第X章」。
**开书默认停靠**:用户只说"开书/写大纲/帮我开书"时,完成 Phase 1→3 与首批 10 章细纲后停止,报告已生成文件和下一步命令;除非用户同一句明确说"并写第1章/写 N 章/日更",否则不要自动进入 Phase 4 正文。
**正文批量上限**:写正文必须由用户显式给出章节范围或日更意图。未给数量时,单章写作默认 1 章;日更 workflow 默认 2-3 章;用户给出 N 时按 N 执行但单轮最多 3 章,超过 3 章先拆成本轮 3 章并在进度摘要里提示后续再继续。
**匹配优先级**:同时命中多行时,按 大修 → 写指定章 → 补纲/扩纲 → 日更续写 → 开书 的顺序匹配。用户点名要"细纲/补纲/规划剧情"而未要正文时,优先入 补纲/扩纲,不入日更。日更续写的 AND 条件(项目已有正文+追踪)不满足时,提示用户"项目还没有正文,建议先开书/写第1章"。
**日更续写保持在 workflow 内**:一旦本次请求路由到 `references/workflow-daily.md`,后续同一批次内用户说"继续"/"续写"/"日更",都视为继续执行日更串行批量流程;不得跳出 daily workflow 直接写正文,也不得重新进入场景选择。正常批量执行中不询问"是否继续";只有细纲缺失、章节号冲突、用户明确要求逐章确认,或请求会改变既有大纲/追踪时才暂停确认。
无法判断场景时,列出上述场景表让用户选择,不要开放式提问。
### 路径与术语约定
> **拆文库/对标关系**:`拆文库/` = analyze skill 的原始产出,是数据源。`对标/` = 写作项目的引用视图,存放与本项目相关的对标数据子集。首次引用对标书时,从 `拆文库/{书名}/` 复制相关子目录(章节/角色/剧情/设定)、`剧情/节奏.md`、`剧情/情绪模块.md`、`文风.md` 和 `拆文报告.md` 到 `对标/{书名}/`。
>
> **对标书路径查找**:优先 `{项目}/对标/{书名}/`,不存在则回退 `拆文库/{书名}/`。下文所有对标数据加载均使用此规则。
---
### Phase 1:确认选题方向
消费 `选题决策.md`、确认题材方向、做对标发现并登记主/副对标书。
**执行前先读 [references/workflow-setup.md](references/workflow-setup.md) 的「Phase 1:确认选题方向」节**,按其中步骤执行。
---
### Phase 2:核心设定
产出核心设定表,并创建 `设定/关系.md`、`设定/题材定位.md`、`设定/题材正文提示卡.md`。
**执行前先读 [references/workflow-setup.md](references/workflow-setup.md) 的「Phase 2:核心设定」节**。
---
### Phase 3:大纲搭建
产出全书体量与阶段总览、卷级大纲、逐章细纲;含大纲安全七检、大纲安全审查、分批建纲与「中途补纲/扩纲小流程」。
**执行前先读 [references/workflow-setup.md](references/workflow-setup.md) 的「Phase 3:大纲搭建」节**。
---
### Phase 4:正文写作辅助
#### 项目文件结构
长篇写作必须用文件系统管理,不要把内容堆在对话里。在用户指定的工作目录下创建:
```
{书名}/
├── 设定/
│ ├── 世界观/
│ │ ├── 背景设定.md # 时代背景、地理、历史
│ │ ├── 力量体系.md # 修炼/能力/等级体系
│ │ └── ...
│ ├── 角色/
│ │ ├── 沈栀.md # 每个人物一个文件,文件名用角色名
│ │ └── ...
│ ├── 势力/
│ │ ├── 天机阁.md # 每个势力/组织一个文件
│ │ └── ...
│ ├── 关系.md # 角色关系映射
│ ├── 题材定位.md # 题材核心梗+对标分析+终局底牌/升级台阶(防写无可写)
│ └── 题材正文提示卡.md # 题材正文核心:边界/期待/爽点/节奏/禁漂移
├── 大纲/
│ ├── 大纲.md # 全书卷级结构
│ ├── 卷纲_第一卷.md # 每卷一个:对标结构坐标+剧情单元+情绪弧线(含章节定位)+人物弧线+伏笔+反转
│ └── 细纲_第001章.md # 每章一个:章节定位+事件+钩子(按章节定位,章首/章尾/段落级)+爽点+悬念
├── 正文/
│ ├── 第001章_章名.md
│ └── ...
├── 对标/ ← 拆文产出的结构化资产
│ └── {对标书名}/
│ ├── 原文/
│ │ ├── 第001章_章名.md
│ │ └── ...
│ ├── 角色/ ← 从拆文库/结构化输出同步
│ │ └── {角色名}.md
│ ├── 剧情/ ← 从拆文库/结构化输出同步
│ │ ├── {剧情单元名}.md
│ │ ├── 故事线.md
│ │ ├── 节奏.md # 关键信息推进 + 情绪触动点 + 爆发节奏(权威节奏索引)
│ │ └── 情绪模块.md # 读者需求/情绪引擎 + 可复现模块(权威模块索引)
│ ├── 设定/ ← 从拆文库/结构化输出同步
│ │ ├── 世界观/ ← 按主题拆分到子目录
│ │ │ ├── 背景设定.md
│ │ │ ├── 力量体系.md
│ │ │ ├── 地理.md
│ │ │ └── 金手指.md
│ │ └── 势力/
│ │ └── {势力名}.md
│ └── 拆文报告.md
├── 追踪/
│ ├── _tracking-state.json ← 唯一结构化权威状态
│ ├── 上下文.md ← 派生续写状态卡(固定 7 栏),≤12KB
│ ├── 逐章记录/第NNN章.md ← 未来相关紧凑记录,≤3072 字节
│ ├── 角色状态/{角色名}.md ← 派生核心角色当前快照
│ ├── 伏笔.md ← 派生伏笔当前视图
│ └── 时间线/{作者真相.md,读者已知.md}
├── 参考资料/
│ └── {topic}.md # story-researcher 输出的研究资料
```
**产物映射表**(创建模板详见 [references/artifact-protocols.md](references/artifact-protocols.md)):
| 文件 | 粒度 | 创建阶段 | 读取时机 |
|------|------|---------|---------|
| 设定/关系.md | 全书 | Phase 2 | 按需:story-explorer relationship 查询、story-review 查设定(不在每章写作回路里逐章读) |
| 设定/题材定位.md(含 `主对标书` 字段,多对标时必填) | 全书 | Phase 2 | Phase 3 大纲、每卷开始前、Phase 4 写前召回 |
| 设定/题材正文提示卡.md | 全书/题材 | Phase 2(缺失则 Phase 4 写前即时生成) | Phase 4 每章写作前:按 `genre-prose-cards.md` 索引匹配后读取 `genre-prose-cards/` 目录对应单题材卡优先、`style-genre-modules.md` 通用模块兜底,与通用正文要求、情绪/节奏召回和文风一起组装 prompt |
| 设定/角色/{角色名}.md、设定/势力/{名}.md | 角色/势力 | Phase 3 细纲后增量补全(首批含主角/主要角色) | Phase 4 状态筛选/写作 |
| 设定/文风.md(自定义文风·优先级最高) | 本书 | 用户自写(Claude Code 可代写);导入/拆解不覆盖 | Phase 4 每章写作前:含实质内容则取代对标文风作权威风格基 |
| 对标/{书名}/文风.md | 对标书 | analyze Stage 6 输出 → story-import 显式绑定或本 skill 首次引用时同步 | Phase 4 每章写作前(文风召回;有自定义文风时降为参考/句长兜底) |
| 大纲/卷纲_第X卷.md | 卷 | Phase 3 | Phase 4 写卷首章前 |
| 追踪/_tracking-state.json | 全书 | Phase 3 初始化 | 唯一结构化权威,不进正文 prompt;每章运行 `tracking_commit.py check` 读取章号和修订号 |
| 追踪/伏笔.md | 全书当前视图 | Phase 3 初始化 | 续写状态卡缺项时按 ID 定点查询;每 ID 只一行 |
| 追踪/时间线/{作者真相.md,读者已知.md} | 全书当前事实/认知派生视图 | Phase 3 初始化 | 按作者真相或读者认知的实际问题选择视图 |
| 对标/{书名}/拆文报告.md | 对标书 | 用户手动+analyze | Phase 2 核心设定、Phase 3 大纲、Phase 4 写作 |
| 追踪/逐章记录/第NNN章.md | 章 | Phase 4 每章事务 | 日更不读;目标 ≤1536 字节、硬上限 3072 字节,按需查询历史原因 |
| 追踪/上下文.md(续写状态卡,≤12KB) | 全书当前状态 | Phase 3 初始化 | 日更每章整份读;由事务工具整份重建,固定 7 栏 |
| 参考资料/{topic}.md | 按需 | Phase 4(story-researcher 输出) | Phase 4 后续章节写作时复用 |
| 追踪/角色状态/{角色名}.md | 核心角色 | 首次进入正文或导入初始化 | 久别角色按名读取一个小快照;目标 ≤4096 字节、硬上限 8192 字节;静态人设仍读 `设定/角色/` |
| 对标/{书名}/角色/{角色名}.md | 对标书 | analyze 输出 | Phase 4 模块召回(角色参考) |
| 对标/{书名}/剧情/{剧情单元名}.md | 对标书 | analyze 输出 | Phase 3 卷纲选段与细纲成批(剧情单元卡「对标剧情参照」)、Phase 4 模块召回(剧情模块参考) |
| 对标/{书名}/剧情/情绪模块.md | 对标书 | analyze Stage 3 输出 → story-import 显式绑定或本 skill 首次引用时同步 | Phase 2 核心设定、Phase 3 大纲、Phase 4 每章写作前(读者需求 / 情绪引擎、可复现模块选择) |
| 对标/{书名}/剧情/节奏.md | 对标书 | analyze Stage 3 输出 → story-import 显式绑定或本 skill 首次引用时同步 | Phase 3 大纲、Phase 4 每章写作前(关键信息推进、情绪触动点、爆发节奏参考) |
| 对标/{书名}/设定/*.md | 对标书 | analyze 输出 | Phase 2 设定参考、Phase 4 世界观约束 |
**缺失文件处理**:当前主产物缺失时显式修复,不拼装降级结果:
1. **角色状态文件缺失** → 当前协议项目先运行 `tracking_commit.py check`,再重跑产生该状态的完整事务;已有正文但 `_tracking-state.json` 缺失时重新 `/story-import`。不得从前文临时推断后直接手写快照。
2. **角色、普通剧情单元或设定等非主产物子目录缺失** → 按「对标书路径查找」查找项目视图与根目录数据源,仍缺失则跳过该可选模块。本条不适用于 `剧情/情绪模块.md` 和 `剧情/节奏.md`。
3. **`剧情/情绪模块.md` / `剧情/节奏.md` 缺失** → 写前准备必须停下,设置 `missing_primary_contract: true` 并给出 `repair_action`:重跑 `/story-long-analyze` Stage 3+ 或重新 `/story-import`,不得用摘要文件假装已召回权威模块。
4. **有对标书但 `文风.md` 缺失** → 若有 `设定/文风.md`(含实质内容)走自定义文风模式继续;否则日更文风召回 fail-fast,提示先运行 `/story-long-analyze` Stage 6 并 `/story-import` 同步。**完全无对标项目**则跳过文风召回、不阻塞(有 `设定/文风.md` 时用它写作)。情绪/节奏轴(`missing_primary_contract`)独立,自定义文风模式不豁免其 fail-fast。
5. **伏笔/时间线文件缺失** → 视为当前语义检查点损坏,停止写正文;先运行 `tracking_commit.py check`,再用事务修复。卷纲/大纲中的计划不能代替已发生事实的当前检查点。
6. **`设定/题材正文提示卡.md` 缺失** → 不阻塞;写前从 `设定/题材定位.md` 精确匹配 `references/genre-prose-cards.md` 索引,并只读取 `references/genre-prose-cards/` 中对应题材单卡(高/中/低置信照原卡标注),无命中再用 `references/style-genre-modules.md` 通用流派模块即时生成短 `genre_prose_card`。只有 `设定/题材定位.md` 也缺失时,退回细纲和目标平台做低置信题材卡,并在意图确认写明。
**对标分析权威优先级(权威读取顺序)**:
1. `剧情/情绪模块.md` 是读者需求 / 情绪引擎、爽文套路框架、可复现模块和重组指南的权威来源。
2. `剧情/节奏.md` 是关键信息推进、章节扩写技法聚合、情绪触动点和爆发节奏的权威来源。
3. `文风.md` 只管句长、标点、对话潜台词、原文锚点等风格;它不能覆盖情绪模块或节奏意图。**自定义文风 `设定/文风.md`(用户自写、不被导入/拆解覆盖)优先级高于对标 `文风.md`**:含实质内容时作权威风格基,对标文风降为参考与句长数值兜底;命中硬安全线的写法(`……` / 破折号 / 段间空行 / 碎句)仍按 narrative-writer 归一,自定义只接管句长 / 软标点 / 潜台词 / 情绪交替。
4. `章节/第K章_摘要.md` 是具体章节证据,用来校验和补足权威索引,不反向覆盖 `情绪模块.md` / `节奏.md`。
5. `拆文报告.md`、`剧情/故事线.md` 是投影/摘要;若与 `剧情/情绪模块.md` 或 `剧情/节奏.md` 冲突,写作以两个权威文件为准,并在写前准备 `gaps.conflict` 记录冲突来源。
**文件组织原则:**
- **人物一个一个文件**:`角色/角色名.md`,方便按需读取
- **势力一个一个文件**:`势力/势力名.md`,组织/门派/家族/国家等
- **世界观按主题拆分**:背景、力量体系、社会结构等各自独立
- **细纲一章一个文件**:`细纲_第XXX章.md`,含钩子设计,与正文一一对应
- **正文按章拆分**:每章一个文件,`第XXX章_章名.md`
- 每章写完直接写入 `正文/` 目录,不要先输出到对话
#### 单章写作流程
**执行前先读 [references/workflow-chapter.md](references/workflow-chapter.md)**,按其中的单章写作流程(步骤 1-13)、写作技巧提醒、字数验收权威与 Phase 5 质量检查执行。日更批量另加载 `references/workflow-daily.md` 控制批次。
#### 追踪文件体积
`追踪/_tracking-state.json` 是唯一结构化权威;`上下文.md`、核心角色快照、`伏笔.md`、作者真相与读者已知时间线都由它确定性派生,程序不反向解析 Markdown。`上下文.md` 固定 7 栏且 ≤12KB。`逐章记录/第NNN章.md` 每章只记录会影响后续连续性的紧凑变化,目标 ≤1536 字节、硬上限 3072 字节,不承诺单独重放出全部当前状态。阶段/卷级回看按需查询逐章记录或正文,不维护另一套长期摘要。所有追踪写入都通过 `scripts/tracking_commit.py`,禁止手改派生文件。
---
## 流程衔接
**流水线:** 长篇
**位置:** 写作(第 3/3 步)
| 时机 | 跳转到 | 命令 |
|---|---|---|
| 写完,去 AI 味 | story-deslop | `/story-deslop` |
| 想对比参考书 | story-long-analyze | `/story-long-analyze` |
| 需要市场方向 | story-long-scan | `/story-long-scan` |
| 太长,适合短篇 | story-short-write | `/story-short-write` |
---
## 参考资料索引
按场景加载,不一次全部加载。
各场景的完整步骤按需加载,本文件只保留场景路由、项目文件结构与产物契约、参考索引:开书三阶段(Phase 1-3)在 `references/workflow-setup.md`,单章正文与质量检查(Phase 4-5)在 `references/workflow-chapter.md`,日更批量在 `references/workflow-daily.md`,回炉大修在 `references/workflow-revision.md`。
### Phase 1:选题方向
| 场景 | 加载文件 |
|------|---------|
| 确定题材类型 | `references/long-genre-catalog.md` |
| 判断市场方向 | `references/genre-readers.md` |
| 特殊题材考量 | `references/plot-special-topics.md` |
| 女频长篇(题材/文案/平台/感情线) | `references/female-audience-writing.md` |
### Phase 2:核心设定
| 场景 | 加载文件 |
|------|---------|
| 设定人物 | `references/character-basics.md` |
| 设计关系 | `references/character-relations.md` |
| 题材框架与定位 | `references/long-genre-catalog.md` + `references/long-genre-mechanics.md` |
| 创建 artifact | `references/artifact-protocols.md` |
| 读者契约与主角高光 | `references/reader-contract-and-progression.md` |
### Phase 3:大纲搭建
| 场景 | 加载文件 |
|------|---------|
| 搭建大纲 | `references/outline-methods.md` |
| 设计矛盾与结构 | `references/outline-conflict.md` |
| 深度结构设计 | `references/outline-structure-theory.md` |
| 节奏与升级感 | `references/outline-rhythm.md` |
| 小纲与卡文 | `references/plot-core-methods.md` |
| 选择叙事框架 | `references/plot-frameworks.md` |
| 题材结构 | `references/genre-prose-cards.md` 索引 + `references/genre-prose-cards/` 单题材卡 |
| 黄金三章 | `references/opening-design.md` |
| 情绪弧线 | `references/emotional-arc-design.md` |
| 契约/终局储备/剧情单元安全审查 | `references/reader-contract-and-progression.md` |
| 反转设计 | `references/long-reversal.md` |
| 细纲结构验收 | `scripts/check-outline-contract.js`(新建/补建后跑,只判字段与表结构) |
### Phase 4:正文写作
| 场景 | 加载文件 |
|------|---------|
| 章节钩子 | `references/long-chapter-hooks.md` |
| 悬念设计 | `references/long-suspense.md` |
| 题材正文提示卡 / 题材分类卡 | `references/genre-prose-cards.md` 索引 + `references/genre-prose-cards/` 单题材卡目录(按题材分类优先) + `references/style-genre-modules.md`(通用流派补充) |
| 打斗/装逼 | `references/style-combat-face.md` |
| 写作技法 | `references/style-craft.md` |
| 商业创作核心方法 | `references/commercial-core-methods.md` |
| 对话 | `references/dialogue-mastery.md` |
| 人物深化 | `references/character-design-methods.md` |
| 情绪技法 + 叙事单元 | `references/plot-emotion-system.md` + `references/emotional-methods.md` |
| 写作技法全程参考 | `references/writing-craft.md` |
| 格式 | `references/long-format.md`(章节、段落、对话、标点与工程元信息) |
| 状态追踪协议 | `references/state-tracking.md` |
| 当前剧情单元与契约校准 | `references/reader-contract-and-progression.md` |
### Phase 5:质量检查
| 场景 | 加载文件 |
|------|---------|
| 质量检查 | `references/long-chapter-quality.md` + `references/reader-contract-and-progression.md` |
| 禁用词扫描 | `references/banned-words.md` |
| AI句式脚本复扫 | `scripts/check-ai-patterns.js` |
| 去AI味 | `references/anti-ai-writing.md` |
### 按主题快速定位(横切主题)
有些主题横跨多个阶段、散在多个文件里。下表给每个主题一个**权威文件**(先读它,通常够用),配套文件只在需要那个角度时再加载。括号是该文件里对应的小节。
| 主题 | 权威文件(先读) | 配套文件(按角度补充) |
|------|-----------------|----------------------|
| 爽点(按意图分流) | **`references/plot-emotion-system.md`**(爽点设计体系:本质/六种类型/倒推法——"怎么设计爽点"先读这个) | 翻盘/高潮式爽点→`references/plot-core-methods.md`(假胜→崩解)· 打脸/装逼释放→`references/style-combat-face.md`· 题材声线与长线约束→`references/genre-prose-cards.md`· 爽文循环/多层→`references/outline-methods.md`·`references/outline-conflict.md` |
| 情绪模块 | **`对标/{书名}/剧情/情绪模块.md`(项目/书级权威)**;无对标或设计新模块时再读 `references/plot-emotion-system.md` | `references/outline-rhythm.md` 只作理论参考;不得覆盖对标书权威模块 |
| 节奏 | **`对标/{书名}/剧情/节奏.md`(项目/书级权威)**;无对标或设计新节奏时再读 `references/outline-rhythm.md` | `references/plot-core-methods.md` 只作理论参考;不得覆盖对标书权威节奏 |
| 高潮 | **`references/plot-core-methods.md`**(高潮构建公式:蓄能→假胜→崩解) | `references/outline-rhythm.md`(高潮分类与反推)· `references/outline-methods.md`(八节点故事结构:结构定位) |
| 金手指 | **`references/plot-special-topics.md`**(金手指拆分理解与战力防崩 + 进阶设计) | `references/outline-conflict.md`(金手指与身份:四点统一) |
| 感情线 | **`references/character-relations.md`**(好感度体系/四阶段 + 男女频差异) | `references/outline-conflict.md`(感情线设计)· `references/style-combat-face.md`(后宫文女主 / 男频极简爱情线构型)· `references/plot-special-topics.md`(爱情线提纯策略) |
| 反转 | **`references/long-reversal.md`**(单元/卷级/全书反转、铺垫、有效性自检) | `references/plot-core-methods.md`(假胜:先给希望再击碎) |
| 人物 | **`references/character-basics.md`**(主角/配角/反派/动机模板速填) | `references/character-design-methods.md`(三层标签反差/九维深化)· `references/character-relations.md`(关系类型/感情线) |
| 女频写作 | **`references/female-audience-writing.md`**(女频长篇:核心原则/文案/题材/感情线长线/平台) | `references/genre-readers.md`(读者心理/平台差异)· `references/character-relations.md`(感情线总框架) |
| 去AI味 | **`references/anti-ai-writing.md`**(AI指纹/核心规则/Show Don't Tell) | `references/banned-words.md`(禁用词扫描)· `references/long-chapter-quality.md`(成稿检查) |
---
## 语言
- 跟随用户的语言回复,用户用什么语言就用什么语言回复
- 中文回复遵循《中文文案排版指北》