215 lines
8.3 KiB
Markdown
Executable File
215 lines
8.3 KiB
Markdown
Executable File
# v0.15 — 叙事深化(loreLayers)+ 放置平衡(softcap)+ UX 增强
|
||
|
||
> 回响星核 / Echo Nexus · v0.15 设计文档
|
||
> 对应 worklog `Task ID: v0.15-release`
|
||
|
||
---
|
||
|
||
## 一、动机
|
||
|
||
v0.14 上线了完整的放置系统(6 工程 + 永久加成 + idle 徽章),但留下两个问题:
|
||
|
||
1. **平衡性漏洞**:`idle_resonance` 工程每次完成 +8/s 永久加成,玩家可反复派遣导致滚雪球,几小时后产能爆炸。
|
||
2. **叙事单薄**:8 个记忆碎片只有一层 `echo` 文本,解锁后即"读完",缺乏 Dark Souls / Outer Wilds 式的碎片叙事深度——这是项目的**差异化竞争力**。
|
||
|
||
v0.15 用两个并行子代理一次性解决:
|
||
|
||
- **2-a(平衡 + UX)**:永久加成 softcap + 批量领取 + 完成 toast + StatsPanel idle 统计
|
||
- **2-b(叙事深化)**:8 碎片 × 2 层 = 16 层 loreLayers 多层文本 + Codex 分层渲染
|
||
|
||
---
|
||
|
||
## 二、平衡:永久加成 Softcap
|
||
|
||
### 公式
|
||
|
||
```ts
|
||
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 多层碎片文本
|
||
|
||
### 类型扩展
|
||
|
||
```ts
|
||
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 层)
|
||
|
||
1. **追逐者**:以太族并非自然消亡,而是被虚空中"某种东西"追逐而集体飞升
|
||
2. **回响同源**:玩家舰载 AI"回响"的频段直接复制自以太族议会档案——玩家其实是以太族的延续/入口
|
||
3. **信任即引诱**:第一纪元的"信任后来者"实为"引诱后来者替他们完成未竟之事"
|
||
4. **飞升是单向门**:每次飞升都在消耗什么,不是奖赏
|
||
5. **回归的不是他们**:接触进度满 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` 改写 + 新增 action
|
||
- `src/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 行统计全显示 ✓
|
||
|
||
---
|
||
|
||
## 七、哲学
|
||
|
||
### 碎片叙事的留白
|
||
|
||
回响星核的叙事不靠过场动画或长篇对话,而是**让玩家自己拼凑**。每个碎片的多层文本设计遵循:
|
||
|
||
1. **表层温和**:第一遍读像抒情散文,不带压迫感
|
||
2. **中层矛盾**:揭示表层没说的东西,制造认知裂缝
|
||
3. **深层颠覆**:推翻表层认知,但留有解读空间(不直接说"怪物是谁")
|
||
|
||
### 平衡与保留
|
||
|
||
softcap 的设计哲学:**衰减但不封顶**。
|
||
- 衰减:防止滚雪球破坏游戏节奏
|
||
- 不封顶:尊重硬核玩家的投入,即使边际收益递减,进度感始终存在
|
||
|
||
这与飞升系统的"单向门"叙事呼应——每次进步都有代价,但绝非徒劳。
|
||
|
||
---
|
||
|
||
## 八、下一步(v0.16+)
|
||
|
||
- 🟡 loreLayer "已读"标记(需改 gameStore,本轮避开边界冲突)
|
||
- 🟡 解码阈值释放叙事碎片 + 星潮三频段切换
|
||
- 🟡 健康设计:每日软上限 + "星核建议休眠"提醒
|
||
- 🟡 移动端 375px Codex 弹层可读性实测
|