# Task 2-b · full-stack-developer · v0.15 叙事深化 — Fragment loreLayers 多层文本 ## 上下文 / 接收到的任务 - Task ID: **2-b** - 任务: 为 Fragment 增加 loreLayers(L1 中层 / L2 深层),实现 Dark Souls 式碎片叙事 - 必读上下文已加载(worklog v0.14-reimpl 段落 + FRAGMENTS 数组 + Fragment 接口 + Codex.tsx + gameStore 导出) - 与并行子代理 A 的边界:不动 engine.ts / gameStore.ts / IdleOperationsPanel.tsx / StatsPanel.tsx / idle.ts / persist version ## 修改的文件(绝对路径) 1. `/home/z/my-project/src/lib/game/types.ts` 2. `/home/z/my-project/src/lib/game/config.ts` 3. `/home/z/my-project/src/components/game/Codex.tsx` ## 实现细节 ### types.ts - 新增 `FragmentLoreUnlockKind` 联合类型(5 种解锁维度) - 新增 `FragmentLoreUnlock` 接口(kind + value) - 新增 `FragmentLoreLayer` 接口(layer 1|2 + title + text + unlockHint + unlock) - `Fragment` 接口新增可选字段 `loreLayers?: FragmentLoreLayer[]` - 现有 `echo` 字段注释明确为 "L0 表层文本",保持向后兼容 ### config.ts - 顶部 import 扩展 `FragmentLoreUnlock` + `GameState` 类型 - **为全部 8 个 FRAGMENTS 撰写了 loreLayers**(≥6 目标超额完成,每碎片 2 层) - 解锁条件分布: - ascensions 1 ×2 (f1_1, f1_4) / 2 ×2 (f1_3, f1_6) / 3 ×2 (f1_7, f1_8) - totalDecoded 40 ×2 (f1_1, f1_7) / 60 ×1 (f1_4) - contact 50 ×1 (f1_2) / 80 ×2 (f1_5, f1_8) - fragmentCount 4 ×1 (f1_2) / 6 ×1 (f1_5) - bossKills 3 ×1 (f1_3) / 8 ×1 (f1_6) - 新增导出函数 `isLoreLayerUnlocked(unlock, state)` 纯函数判定 - GameState 通过 `Pick<>` 类型约束,只取需要的 5 字段(ascensions / totalDecoded / contact / fragments / bossKills) ### 叙事暗线设计(5 条贯穿主线) 1. **追逐者线** — 以太族不是自然消亡,是被虚空中的"追逐者"逼迫集体飞升(f1_1, f1_2, f1_5, f1_8) 2. **回响 AI 同源线** — 玩家舰载 AI 的频段直接复制自以太族议会档案,玩家即是以太族的延续/载体(f1_1, f1_6) 3. **"信任"即"利用"线** — 第一纪元的"信任后来者"实为"引诱后来者完成未竟之事"(f1_4, f1_8) 4. **飞升代价线** — 飞升不是奖赏而是单向门 + 替以太族还债(f1_4, f1_7, f1_8) 5. **满溢回归线** — 接触进度满 80 时回归的不是"他们",是"借他们形状的某种东西"——警示玩家(f1_8) ### Codex.tsx 重构 - 用 `useShallow` 一次性订阅 5 字段(fragments / totalDecoded / ascensions / contact / bossKills) - 顶部新增"深层叙事 X / Y 已解锁"统计行(amber 数字 + mono 字体) - 列表卡片:当某碎片有 loreLayer 已解锁时,标题旁显示彩色小圆点(L1 amber / L2 fuchsia),带 glow shadow - 详情弹层重构为分层渲染: - **L0 表层回响**(永远显示,emerald 主题,bg-emerald-950/20) - **L1 隐秘注脚**(amber 主题,未解锁时乱码占位 + blur-sm + 🔒 unlockHint) - **L2 深层回响**(fuchsia 主题,未解锁时同样乱码占位 + blur-sm + 🔒 unlockHint) - 锁定层用 `▓░▒` 全息方块字 + `blur-sm select-none pointer-events-none aria-hidden` 保密 - 弹层 Card 加 `max-h-[88vh] overflow-y-auto` + 自定义 scrollbar 颜色(fuchsia) - 每层之间用 `border-t border-white/5` 细分隔线 - 移动端 375px 适配:text-[12px] 行距宽松,padding p-3,长 unlockHint 在极窄屏隐藏(`hidden xs:inline sm:inline`) ## 验证 - ✅ `bun run lint` 零错误零警告(首次有 1 个 unused eslint-disable 警告,已修复) - ✅ dev 服务器 HTTP 200,编译 142-257ms 范围 - ✅ dev.log 末尾连续多次"✓ Compiled"无运行时错误 - ✅ 严格 4 色全息:emerald / amber / fuchsia / rose(rose 仅在背景 used);零蓝/靛 - ✅ useShallow 用于多字段订阅 - ✅ 未修改 persist version / engine / gameStore(与子代理 A 零冲突) ## 需要主控注意的点 1. **loreLayers 已为全部 8 个碎片填充**(不止 6 个),叙事密度最高。如果主控希望平衡节奏,可考虑给 1-2 个"基础"碎片只留 L0(去掉 loreLayers 字段即可,UI 会自动显示"此碎片暂无更深层叙事"占位)。 2. **未做端到端 agent-browser 验证**(按工单第 5 步要求,由主控完成)。建议主控验证:① 初始进入无飞升状态,所有 L1/L2 应处于锁定态(模糊乱码 + 🔒 图标);② 用 `window.__gameStore.setState({ascensions:1})` 模拟飞升后,f1_1 / f1_4 的 L1 应自动解锁;③ 列表卡片标题旁应出现 amber/fuchsia 小圆点。 3. **未持久化 loreLayer 解锁进度**——这是纯派生状态(由现有 5 字段实时计算),无需新增持久化字段。如主控希望加"已读"标记(防止玩家错过新解锁的深层文本),可后续在 GameState 加 `readLoreLayers: Record`,但需要改 gameStore(与子代理 A 边界冲突),故本轮未做。 4. 叙事文本长度 60-130 字,符合"碎片感 + 留白"美学要求;没有说教,多用引号 + 反转 + 留白。