8.3 KiB
Executable File
v0.15 — 叙事深化(loreLayers)+ 放置平衡(softcap)+ UX 增强
回响星核 / Echo Nexus · v0.15 设计文档 对应 worklog
Task ID: v0.15-release
一、动机
v0.14 上线了完整的放置系统(6 工程 + 永久加成 + idle 徽章),但留下两个问题:
- 平衡性漏洞:
idle_resonance工程每次完成 +8/s 永久加成,玩家可反复派遣导致滚雪球,几小时后产能爆炸。 - 叙事单薄:8 个记忆碎片只有一层
echo文本,解锁后即"读完",缺乏 Dark Souls / Outer Wilds 式的碎片叙事深度——这是项目的差异化竞争力。
v0.15 用两个并行子代理一次性解决:
- 2-a(平衡 + UX):永久加成 softcap + 批量领取 + 完成 toast + StatsPanel idle 统计
- 2-b(叙事深化):8 碎片 × 2 层 = 16 层 loreLayers 多层文本 + Codex 分层渲染
二、平衡:永久加成 Softcap
公式
export function applyIdleSoftcap(bonus: number): number {
if (bonus <= 30) return bonus; // 全额
if (bonus <= 100) return 30 + (bonus - 30) * 0.5; // 超出部分 ×0.5
return 65 + (bonus - 100) * 0.25; // 超出部分 ×0.25
}
临界值
| 原始 bonus | 有效 bonus | 衰减率 |
|---|---|---|
| 30 | 30 | 0% |
| 50 | 40 | 20% |
| 100 | 65 | 35% |
| 200 | 90 | 55% |
| 500 | 152.5 | 69.5% |
设计意图
- 30 以下不衰减:新手期 + 偶尔完成
idle_refine(+0.3/s)不受惩罚 - 30-100 线性半衰:中段玩家反复完成
idle_drones(+2/s)开始感到边际递减 - 100 以上严重衰减:硬核玩家刷
idle_resonance(+8/s)收益大幅缩水,但仍非零(保留进度感) - 永不归零:
applyIdleSoftcap(bonus) → ∞时仍趋向无穷,只是增速极慢——避免"刷到上限"的挫败感
UI 展示
IdleOperationsPanel Section 1「永久加成」StatTile:
- 有效值永远显示(如
+40/s) - 当
有效 < 原始时,下方加 amber 副行:有效 +40/s(原始 +50/s · 衰减中)
三、叙事深化:loreLayers 多层碎片文本
类型扩展
export interface FragmentLoreLayer {
layer: 1 | 2; // 1=中层,2=深层
title: string; // "隐秘注脚" / "深层回响"
text: string; // 60-150 字叙事文本
unlockHint: string; // "飞升 1 次后揭示"
unlock: FragmentLoreUnlock;
}
export interface FragmentLoreUnlock {
kind: "ascensions" | "totalDecoded" | "contact" | "fragmentCount" | "bossKills";
value: number;
}
5 种解锁条件
| kind | 含义 | 典型阈值 |
|---|---|---|
ascensions |
飞升次数 | 1 / 2 / 3 |
totalDecoded |
累计解码晶体数 | 20 / 40 / 60 |
contact |
接触进度 | 50 / 80 |
fragmentCount |
已解锁碎片数 | 4 / 6 |
bossKills |
累计击杀 BOSS | 3 / 8 |
5 条叙事暗线(贯穿 16 层)
- 追逐者:以太族并非自然消亡,而是被虚空中"某种东西"追逐而集体飞升
- 回响同源:玩家舰载 AI"回响"的频段直接复制自以太族议会档案——玩家其实是以太族的延续/入口
- 信任即引诱:第一纪元的"信任后来者"实为"引诱后来者替他们完成未竟之事"
- 飞升是单向门:每次飞升都在消耗什么,不是奖赏
- 回归的不是他们:接触进度满 80 时回归的,是"借他们形状的某种东西",请玩家别回应
示例(f1_1 第一缕谐振)
L0 表层(默认):
在被称作「寂灭前夜」的年代,以太族第一次捕捉到来自虚空深处的谐振——那不是声音,而是存在的回声。他们将之记录在第一颗记忆晶体里。
L1 隐秘注脚(飞升 ≥1):
档案的边缘有一行几乎被擦去的批注:「那并非来自虚空——而是来自我们身后。我们一直不敢回头。」
L2 深层回响(累计解码 ≥40):
你终于明白:那缕谐振的频率,与你的舰载 AI「回响」的核心频段完全一致。你不是在考古——你是在被召唤。而你身后的东西,一直在等。
Codex 分层渲染
| 层级 | 颜色 | 标题 | 未解锁状态 |
|---|---|---|---|
| L0 表层 | emerald | 表层回响 | 永远显示 |
| L1 中层 | amber | 隐秘注脚 | ??? + blur-sm 全息乱码 + 🔒 unlockHint |
| L2 深层 | fuchsia | 深层回响 | ??? + blur-sm 全息乱码 + 🔒 unlockHint |
顶部统计:深层叙事 X / 16 已解锁
列表卡片:已解锁深层文本的碎片标题旁显示 amber/fuchsia glow 小圆点
四、UX 增强
4.1 批量领取全部
claimAllIdleProjects() action:
- 遍历 3 槽位,对所有
completed === true执行奖励逻辑 - 单次
set()+ 单次syncStats()(避免多次 re-render) - 无可领取 → 直接 return(不弹 toast)
- 成功 → 汇总 toast
✦ 批量领取完成 · 共领取 N 项工程 · +X 晶体 · +Y 洞见 · ...
UI:Section 3 标题右侧,当存在 completed slot 时显示 emerald「✓ 领取全部」按钮(h-5 px-2 text-[10px])
4.2 工程完成 toast
tickIdleProjects 检测状态转变瞬间(旧 !completed → 新 completed):
- 收集
justCompletedProjects数组 - 循环外单次
toast({ title: "✦ 放置工程完成", description: "${icon} ${name} · 可前往「放置」标签领取" }) - 避免每 250ms tick 重复弹窗
4.3 StatsPanel idle 统计
从 page.tsx 内联函数抽出为独立组件 StatsPanel.tsx:
useShallow精细订阅 24 字段- 新增 idle 统计行:
- 放置永久加成
+X /s - 完成放置工程
N 项 - 放置产出晶体
formatNum(N) - 放置工程历史
N 条(最近 50 条,跨周目)
- 放置永久加成
五、技术实现
修改文件清单(8 个)
子代理 2-a(5 文件):
src/lib/game/engine.ts— 新增applyIdleSoftcap导出 +recomputeStats调用src/store/gameStore.ts—GameActions加claimAllIdleProjects签名 +tickIdleProjects改写 + 新增 actionsrc/components/game/IdleOperationsPanel.tsx— softcap 副行 + 领取全部按钮 + StatTile 扩展src/components/game/StatsPanel.tsx— 新建独立组件src/app/page.tsx— 最小集成(删除内联 + import)
子代理 2-b(3 文件):
src/lib/game/types.ts—FragmentLoreLayer/FragmentLoreUnlock接口 +Fragment.loreLayers字段src/lib/game/config.ts— FRAGMENTS 全部填充 loreLayers +isLoreLayerUnlocked函数src/components/game/Codex.tsx— useShallow + 顶部统计 + 列表小圆点 + 3 层分层渲染弹层
并行零冲突
两个子代理修改文件严格不重叠:
- 2-a 不碰
types.ts/config.ts/Codex.tsx - 2-b 不碰
engine.ts/gameStore.ts/IdleOperationsPanel.tsx/StatsPanel.tsx
六、验证
- ✅
bun run lint零错误零警告 - ✅ HTTP 200,dev.log 无运行时错误
- ✅ agent-browser 端到端 smoke test:
- softcap:permBonus=50 → 有效 40,UI 显示"衰减中" ✓
- 批量领取:permBonus 0→0.3, projectsCompleted 1→2 ✓
- 完成 toast:tickIdleProjects 触发 ✓
- Codex 分层:L0 显示 / L1·L2 模糊 → ascensions=1 解锁 L1 → totalDecoded=50 解锁 L2 ✓
- 深层叙事计数 0→2→6 随条件递增 ✓
- StatsPanel idle 4 行统计全显示 ✓
七、哲学
碎片叙事的留白
回响星核的叙事不靠过场动画或长篇对话,而是让玩家自己拼凑。每个碎片的多层文本设计遵循:
- 表层温和:第一遍读像抒情散文,不带压迫感
- 中层矛盾:揭示表层没说的东西,制造认知裂缝
- 深层颠覆:推翻表层认知,但留有解读空间(不直接说"怪物是谁")
平衡与保留
softcap 的设计哲学:衰减但不封顶。
- 衰减:防止滚雪球破坏游戏节奏
- 不封顶:尊重硬核玩家的投入,即使边际收益递减,进度感始终存在
这与飞升系统的"单向门"叙事呼应——每次进步都有代价,但绝非徒劳。
八、下一步(v0.16+)
- 🟡 loreLayer "已读"标记(需改 gameStore,本轮避开边界冲突)
- 🟡 解码阈值释放叙事碎片 + 星潮三频段切换
- 🟡 健康设计:每日软上限 + "星核建议休眠"提醒
- 🟡 移动端 375px Codex 弹层可读性实测