Compare commits

..
49 Commits
Author SHA1 Message Date
Super_Z 5bed2599f5 v0.16: 解码阈值叙事事件 + loreLayer 已读标记 + idleHistory 详情 + 移动端适配
- 5 个解码阈值叙事里程碑(ms_5/12/25/40/60)+ 全屏碎片释放叠层
- loreLayer 已读标记(readLoreLayers + 点击文本标记 + 已读/未读视觉区分)
- idleProjectHistory 详情展开(倒序最近 5 条 + 相对时间)
- 新建 format.ts formatRelativeTime 工具函数
- 移动端 375px 适配审计(4 组件字号 9→10px + flex-wrap + 响应式 padding)
- 严格 4 色全息,lint 零错误,agent-browser 端到端验证通过
2026-06-24 23:45:34 +00:00
Super_Z 174d1227c0 68f373b9-921a-4acf-844c-ab7e89ffb727 2026-06-24 22:50:18 +00:00
Z.ai Code 774ddaf9d1 docs: v0.15 部署记录 + main 分叉说明 2026-06-24 22:47:11 +00:00
Super_Z 22588425cf 48c8e466-e804-444f-9f6d-4a2d34b3379a 2026-06-24 12:34:05 +00:00
Super_Z 96748d726f v0.15: 叙事深化 + 放置平衡 + UX 增强
- loreLayers 多层碎片文本(8 碎片 × 2 层 = 16 层深层叙事,5 条暗线交织)
- 永久加成 softcap(≤30 全额 / 30-100 ×0.5 / >100 ×0.25,防滚雪球)
- 批量领取全部工程 + 工程完成 toast 通知
- StatsPanel 独立组件 + idle 统计行(永久加成/完成工程/产出晶体/历史)
- Codex 分层渲染(L0 emerald 表层 / L1 amber 隐秘注脚 / L2 fuchsia 深层回响)
- 修复 v0.14 双重计算 bug(idleTotalPerSec)
- 严格 4 色全息,lint 零错误,agent-browser 端到端验证通过
2026-06-24 12:32:56 +00:00
Super_Z 20dc1f252f docs: v0.14 README + 放置系统设计文档 + worklog 更新 2026-06-24 10:23:08 +00:00
Super_Z 17820b1f28 v0.14: 放置系统 (Idle Operations) — 采矿无人机舰队 + 6放置工程 + 永久产能加成 + idle徽章 2026-06-24 10:19:40 +00:00
Super_Z 1701a908c9 docs: worklog 更新 v0.8.1 P1 完成记录 2026-06-23 22:35:30 +00:00
Super_Z 71ca5b48a9 v0.8.1: 探险平衡 + 信标系统扩展(周挑战 + 信标链)
P1-a 探险 BOSS 胜率平衡 + 能量恢复(expedition.ts + config.ts + gameStore.ts + ExpeditionPanel.tsx):
- combatWinRate: scale 8→4, floor 0.25→0.35(基础力10对BOSS胜率 25%→35-45%)
- BOSS 难度 5-7→3-5(配合新公式基础胜率达 45-55%)
- computeEnergyRegenInterval(state): 动态恢复间隔
  - exp_2 解锁 -30%, exp_3 解锁 -20%, 探索力属性 -最高30%
  - 下限 12s(原固定 45s)
- computeEnergyRegen 接受 intervalSec 参数
- gameStore tick 传入动态间隔
- config.ts: exp_2/exp_3 描述加'能量恢复 +30%/+20%'
- ExpeditionPanel: 显示实际恢复速度 + '已加速'标记

P1-b 信标系统扩展(beacon.ts + BeaconPanel.tsx + gameStore.ts)[subagent 9-b]:
- 周挑战: getWeekKey ISO 8601 + FNV-1a 种子确定性生成
  - 难度强制 anomaly 60%/singular 40%, goal 日挑战×3-5倍
  - 完整进度/领奖/排行榜推送(isWeekly标记)
- 信标链: 4里程碑(3/7/14/30天) + grace续命机制(每链1次)
  - recordChainCompletion 核心断链/续命逻辑
  - 奖励 50→680洞见递增
- BeaconPanel: 周挑战fuchsia主题 + 信标链amber→rose渐变里程碑节点
- gameStore: trackBeacon升级 + claimWeeklyBeacon/claimChainReward actions
- VLM 8/10, lint零错误, 5场景bun测试全PASS
2026-06-23 22:34:52 +00:00
Super_Z a3aa381656 docs: worklog 更新 v0.8 完成记录 + 工单修正 + cron 228357 2026-06-23 21:31:26 +00:00
Super_Z 494bc5ff64 v0.8: 巡航玩法大增强 - BOSS 战 + 道具掉落 + 事件选择节点
- cruise.ts (+1487行): BossEntity/BossPhase/BulletEntity/PowerupEntity/UpgradeCard 类型
  - BOSS 三阶段攻击(直射/散射/追踪弹+召唤), HP=100+lvl×20
  - 飞船射击系统(空格/射击按钮, 能量消耗5/发, 150ms冷却)
  - 5种道具掉落(shield/energy/rapid/overdrive/magnet)
  - 10种升级牌(速度/护盾/能量/火力/吸引/无敌等), 每关3选1
  - shootShip/applyUpgradeCard/rollUpgradeChoices 函数
  - generateLevel: level%5===0 生成BOSS关
- CruiseMode.tsx (+858行): BOSS多层环+HP条+触手绘制, 子弹尾焰, 道具六边形+图标
  - buff状态指示器, 选择升级阶段3张玻璃卡牌翻转
  - 射击按钮(移动端右下), BOSS HP条(顶部), buff列表(左侧)
  - 修复 lint: isTouch/stats 改用 useState initializer
- page.tsx: 版本号 v0.7 → v0.8
- worklog.md: 工单修正(标注v0.7已完成), cron job_id 228357重建
2026-06-23 21:30:43 +00:00
Super_Z 43dfc2d41b docs: README 添加在线游玩链接 + v0.7 状态更新 2026-06-23 21:10:47 +00:00
Super_Z 3d916a1574 0804500b-ffe8-4b5f-8419-5e7aafd9fc73 2026-06-23 21:01:32 +00:00
Super_Z 4545fe380b v0.7: CrystalOrb Canvas 粒子系统升级 + 角色属性系统(四维)
CrystalOrb 升级(P0 视觉震撼):
- 从 CSS 动画重写为 Canvas 2D 粒子系统
- 环绕能量粒子(3层32个,emerald/fuchsia/rose,带拖尾)
- 环境星尘(40个,闪烁漂移)
- 点击爆发粒子 + 冲击波环(连击解锁更多层)
- 晶核辉光呼吸 + 3层六边形纹理 + 鼠标视差
- VLM 视觉评分 8/10

角色属性系统(P1 RPG 深度):
- 新增 attributes.ts 逻辑层 + AttributesPanel UI
- 四维属性:探索力/智慧/勇气/灵感(emerald/fuchsia/amber/rose)
- 两区加成公式(0-50线性,50-100递减)
- 飞升获得属性点(ascensions×2+1),手动分配
- 完成活动获得属性经验,自动升级
- 接入 pulse/clickNode/resolveCurrentNode/grantCruiseReward/tickTide
- 旧存档兼容(migrateAttributes)
- 新增 2 项成就 + 第 8 个标签页「角色」
- VLM 视觉评分 7-8/10

lint 零错误;HTTP 200
2026-06-23 21:00:42 +00:00
Super_Z 8474f4caa7 0c799010-d26c-48d2-8c38-f465011f59d8 2026-06-23 20:32:33 +00:00
Super_Z c0535e6ebe d3c86ebe-91f4-4f29-a530-6cb46cab2abc 2026-06-23 20:19:46 +00:00
Super_Z 7111e154b2 906d0c00-e2bc-4edd-ae26-665c03a1ba37 2026-06-23 20:10:42 +00:00
Super_Z 72e1f3fc3c da4fe2ad-c3b9-41fc-82e7-336a69a7947c 2026-06-23 19:51:59 +00:00
Super_Z fafa2ee20a v0.6: 深空巡航 Canvas 2D 实时玩法 + UI 偏移重叠修复
## 玩法拓展(回应用户: 玩法太单调/全是点点点)
- 新增「深空巡航」Canvas 2D 全屏实时玩法
  - 飞船操控(WASD/方向键/移动端虚拟摇杆)
  - 实时躲避陨石/虚空风暴,收集晶体/洞见/信标
  - 到达星门通关,护盾归零失败
  - 3层视差星空 + 粒子系统(尾焰/收集/碰撞/烟花) + 辉光 + 屏幕震动
  - 奖励同步主游戏(grantCruiseReward)
  - 独立 localStorage 记录最高分/通关数

## UI 修复(回应用户: 解析球左上偏移/成就小屏重叠)
- DecodeArray 节点: 移除 Tailwind translate 与 inline transform 冲突
- AchievementsPanel: 移除固定 max-h, 改 flex-1 min-h-0 自适应
- page.tsx 布局: 小屏减小 min-h, 避免挤压重叠

## 集成
- gameStore 新增 grantCruiseReward action
- header 新增 amber 主题「巡航」按钮 + 全屏 CruiseMode 渲染

## 文件
- src/lib/game/cruise.ts (新增, ~1008行)
- src/components/game/CruiseMode.tsx (新增, ~1350行)
- src/app/page.tsx (集成巡航入口)
- src/store/gameStore.ts (grantCruiseReward action)
- src/components/game/DecodeArray.tsx (节点偏移修复)
- src/components/game/AchievementsPanel.tsx (小屏重叠修复)

QA: lint 零错误; agent-browser+VLM 验证主界面无偏移+巡航玩法正常运行
2026-06-23 19:33:51 +00:00
Super_Z fcf94b6c3f docs: update worklog for v0.5.2 (offline report + persist fix) 2026-06-23 17:04:58 +00:00
Super_Z 296c609479 v0.5.2: offline report + tab UI + persist race fix
- New: Offline earnings report dialog (welcome back popup with gain/duration/rate/progress)
  - src/lib/game/offlineReport.ts: module-level store + custom event
  - src/components/game/OfflineReportDialog.tsx: Radix Dialog UI
  - gameStore.init: setPendingOfflineReport before set()
- Fix: useGameLoop waits for persist.hasHydrated() before init
  - Root cause: Zustand persist rehydrate is async (Promise.resolve wrapper)
  - Before fix: init read INITIAL_STATE (lastTick=undefined), skipped offline branch
  - After fix: init waits for rehydrate, correctly reads saved lastTick
- UI: Tab bar redesign with per-tab accent colors + flex-col layout
- Version: v0.5 -> v0.5.2
2026-06-23 17:04:28 +00:00
Super_Z bd28219b65 docs: update worklog for v0.5.1 (Gitea Pages deploy + tutorial + UI) 2026-06-23 16:38:44 +00:00
Super_Z 8605f9bb5f chore: remove QA screenshots from repo + gitignore
- Remove qa-static-*.png and qa-tut-01.png (temporary QA artifacts)
- Add qa-*.png to .gitignore
2026-06-23 16:37:49 +00:00
Super_Z 00a46a0bf9 Deploy: v0.5.1 static export
- New: Tutorial system (7-step onboarding with spotlight + action detection)
- UI: ResourceBar spacing optimization (gap, dividers, tabular-nums)
- UI: SettingsDialog adds tutorial replay + online play link
- Anim: tutorial pulse + pop-in keyframes
2026-06-23 16:34:00 +00:00
Super_Z 084387174b 69e481d9-d5e1-44d1-9561-71b5173e04bb 2026-06-23 15:25:33 +00:00
Super_Z ab511fe9e0 chore: update docs submodule ref (v0.5 beacon docs) 2026-06-23 15:24:51 +00:00
Super_Z 60445abd42 v0.5: 深空信标系统 + 编年史历史 BUG 修复
新功能:深空信标(Deep Space Beacon)
- 每日挑战:UTC 日期种子确定性生成,5 种类型 × 3 档难度
- 本地排行榜 Top 20,奖牌图标 + 难度色点 + 今日高亮
- 进度追踪独立 localStorage,不污染 GameState
- 倒计时 + 领取奖励发放到游戏状态

BUG 修复:编年史历史条目显示原始 tide 键名
- 新增 regenerateLoreFromEntry(),显示时重新生成 lore
- 修复 v0.4 之前条目 lore 中 tide_ruins 等原始键名

UI:第 7 标签页「信标」+ 统计面板「信标最高分」行
版本号 v0.4 → v0.5

详见 docs/10-深空信标系统-v0.5.md
2026-06-23 15:24:51 +00:00
Super_Z 04f6a398f4 735ccca3-a163-4b49-8cb2-c04c3a043ee7 2026-06-23 15:24:51 +00:00
Super_Z a02b6191c5 fix: websocket example eslint set-state-in-effect 2026-06-23 15:24:24 +00:00
Super_Z 5bc041ac0b docs: v0.5 深空信标系统文档 2026-06-23 15:24:24 +00:00
Super_Z 697e1f360a docs: 更新 worklog 至 v0.4 完成 2026-06-23 14:48:15 +00:00
Super_Z e6ec22132e docs: v0.4 回响编年史系统设计文档 2026-06-23 14:46:06 +00:00
Super_Z e69c48ba69 feat(v0.4): 回响编年史 — 跨周目叙事时间轴系统
- 新增 ChronicleEntry / RunStartSnapshot 类型与 GameState 字段
- 新建 chronicle.ts: 5 纪元名生成、模板化叙事、里程碑检测、run delta 计算
- engine.ts performPrestige 构建编年史条目并重置 runStart
- gameStore: init 兼容旧存档 + tickTide 记录星潮 + resolveCurrentNode 计 BOSS 击杀
- chooseConstellationPerk 回填最近一条 entry 的 perksThisAscension
- 新建 ChronicleDialog.tsx: 时间轴 UI + 5 纪元循环色 + 入场动画
- 新增 6 项成就: 首部编年/三纪元回响/五纪元闭环/首杀维度/维度猎手/星潮亲历者
- 新增 chronicle / chronicleOpen 程序化音效
- 修复关键 BUG: PrestigeDialog disabled 逻辑错误导致玩家永远无法飞升
- 修复 UX: newBp=0 时不再永久禁用飞升按钮(v0.3.1 星图+v0.4 编年史已提供动机)
- 统计面板新增 BOSS 击破/星潮亲历/编年史条目 3 行
- 版本号升至 v0.4
2026-06-23 14:45:38 +00:00
Super_Z 98fbbf1634 docs: 更新 worklog v0.3.1 收尾记录 2026-06-23 14:15:57 +00:00
Super_Z 9a17849859 chore: 清理未用变量 + 新增星图天赋目标提示 + ignore skills/ 2026-06-23 14:15:29 +00:00
Super_Z cc02fc2e7f Merge branch 'main' of https://git.atdunbg.xyz/Super_Z/echo-nexus
# Conflicts:
#	.gitignore
2026-06-23 14:13:30 +00:00
Super_Z 9f4d839c6b feat(v0.3.1): 星图天文台元进程天赋系统 — 18 天赋 / 3 选 1 draft / Canvas 动态星图
- 新增 src/lib/game/constellation.ts:6 类别 × 3 天赋 = 18 个永久天赋,
  constellationBonuses() 聚合 19 项修饰器,rollPerkChoices() 保证不同类别
- 状态扩展:GameState.constellation / pendingPerkChoices
- engine.ts: recomputeStats 聚合三层加成(技术+蓝图+成就+星图),
  performPrestige 触发天赋选择 + 飞升礼包补偿,新增 rollCrystalTierWithBonus
- expedition.ts: 探险力/生命应用星座修饰器
- gameStore.ts: 新增 chooseConstellationPerk + rerollPerkChoices 动作,
  全链路接入(tickTide/autoDecodeTick/clickNode 等用点)
- 新增 ConstellationPanel.tsx: Canvas 动态星图(六边形 6 星座 × 3 星点,
  闪烁/光晕/十字光线/连接线/中心星核呼吸)+ Hover 提示 + 类别图例
- 新增 ConstellationDialog.tsx: 飞升后自动弹出,3 卡片 draft + 重新抽取
- PrestigeDialog: 增加「星图觉醒预告」卡片
- page.tsx: 6 列标签栏 + 顶部「觉醒」按钮 + 统计面板加星图天赋
- audio.ts: 新增 constellation SFX(上升琶音 + 高频闪光)
- achievements.ts: 新增「星图初绘」「六分星辉」2 项成就
- QA: agent-browser + VLM 全流程通过;lint 零错误;编译 < 200ms
- 二次回应 Issue #1:从「连连看」扩展为 6 大玩法层 + 元进程 draft
2026-06-23 14:12:37 +00:00
Super_Z 433c19cc73 docs: v0.3.1 星图天文台元进程天赋系统设计文档 2026-06-23 14:12:19 +00:00
Super_Z f3d2e53e4f 42773b7e-7147-4ad5-828d-da7fcf0290b8 2026-06-23 13:52:13 +00:00
Super_Z 27bb1555e5 feat(v0.3): 星潮事件系统 - 6种周期性全局玩法修饰
- 6种星潮: 晶体潮(产能x2)/谐振风暴(解码x1.6)/遗迹共振(探险+5力+30血)/虚空低语(洞见x2)/星核悸动(接触x3脉冲x2)/寂静期(产能x0.5,结束补偿洞见)
- 触发: 首次30s, 常规间隙40s, 持续75s, 权重抽取, 飞升重置
- UI: 顶部指示器芯片(倒计时) + 全屏背景叠层(色带+呼吸光) + Toast通知 + Footer联动
- 音效: tideStart(神秘扫频) + tideEnd(柔和消退), 程序化合成
- 修饰器: 产能/脉冲/解码奖励即时乘, 洞见/接触率进缓存, 探险力/血量即时加
- QA: agent-browser全流程通过(触发/指示器/叠层/寂静期补偿), VLM视觉确认, lint零错误
2026-06-23 13:51:32 +00:00
Super_Z da18f32df2 3d8566bc-063f-41e8-8934-68c9ac5b8211 2026-06-23 13:38:23 +00:00
Super_Z 51714d2532 feat(v0.2.1): 程序化音频系统 + 14项成就系统 + 脉冲粒子打磨
- 音频: Web Audio API 程序化合成 15 种音效(脉冲/解码/探险/飞升/成就), 零资源文件
- 成就: 14项成就, 跨周目永久产能/洞见加成, Toast通知+专属音效
- 视觉: 脉冲粒子爆发, 扩散环, 浮动数字按连击变色
- UI: 标签栏5列(+成就页), 统计面板扩展, 设置页音效试听
- 兼容: 旧存档自动补全 achievements 字段
2026-06-23 13:36:44 +00:00
Super_Z 674775be0e 6f5491c0-6c94-4f8e-8ad3-136d04ab862f 2026-06-23 13:04:15 +00:00
Super_Z 84749c218a feat(v0.2): 遗迹探险肉鸽系统 + 仓库满仓警告
新增 v0.2 旗舰功能 - 遗迹探险肉鸽系统:
- 能量系统: 3初始/5上限, 每45秒恢复1点
- 探险力/生命: 由技术树+飞升蓝图计算
- 6种节点类型: 战斗/宝藏/抉择/解谜/休整/BOSS
- 程序化路径: 5-7节点线性, 末位BOSS
- 实时奖励入账, 失败保留奖励, 可主动撤退
- 探险日志(最近30条)

配套修复:
- HP clamp(休整不超上限)
- 探险奖励绕过仓库上限(仅闲置产能受限)
- 仓库满仓UX警告(底部状态栏琥珀色脉冲)
- 技术树探险分支增强(探险力/生命加成)

UI: 探险标签页(入口态/进行态), 节点路径图, 事件卡, 生命/能量条
验证: 全流程通过, 奖励绕过cap验证(101>50)
2026-06-23 13:02:45 +00:00
Super_Z f73b96026c d9404a31-1970-4e79-ac9a-f4f9db60350b 2026-06-23 12:47:49 +00:00
Super_Z 5eb303c389 fix(decode): 修复解码谜题大量无解问题 (v0.1.1)
核心问题: generatePuzzle 随机填色未保证有解, 导致大量死局

修复:
- 路径构造法生成器: 主动构造一条保证可解的路径, 100%可解率
- isSolvable DFS精确判定: 检测此路不通, 提示撤销
- undoStep 撤销功能: 走错单步回退, 无需整局重排
- 卡死提示横幅: 局面无解时醒目提示+快捷撤销
- canStartFrom 可行起点高亮: 选起点阶段标记可行/死起点
- 旧存档兼容: init时清理不可解的遗留谜题

验证: 3000/3000可解, agent-browser T1/T2端到端通过
2026-06-23 12:46:35 +00:00
Super_Z 9e520a34c6 docs: 初始化游戏调研、设计文档与技术架构 (v0.1 设计定稿)
- 01-调研报告: 浏览器/HTML5市场、独立游戏品类、放置品类、留存洞察、技术选型
- 02-游戏设计文档: 世界观、核心循环、六大系统、MVP范围、路线图
- 03-技术架构: 栈选型、目录结构、状态模型、解码引擎、Canvas策略
- README: 项目概览
2026-06-23 12:05:10 +00:00
Super_Z 1e706b2ec0 Initial commit 2026-06-23 20:02:20 +08:00
Z User e193530f24 Initial commit 2026-06-23 11:50:15 +00:00
155 changed files with 4480 additions and 12787 deletions
View File
+1 -1
View File
@@ -1 +1 @@
12512
1061
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
+92 -25
View File
@@ -1,9 +1,11 @@
# 回响星核 / Echo Nexus
> 原创深空考古放置策略游戏 · Original deep-space archaeology idle strategy game
> 原创深空考古 **放置策略**游戏 · Original deep-space archaeology **idle strategy** game
你是一名深空考古指挥官,驾驶自治勘探舰回收已「飞升」的以太文明遗留的记忆晶体,解码碎片拼凑出他们的故事,并最终跨越维度发起「接触」。
**关掉浏览器,星核仍在为你工作**——采矿无人机舰队 24h 不间断采矿,放置工程在离线时持续推进,回来后一键领取积累的奖励。
---
## 🎮 在线游玩
@@ -16,7 +18,7 @@
## 项目状态
- **版本****v0.7** — CrystalOrb Canvas 粒子系统 + 四维角色属性
- **版本****v0.16** — 解码阈值叙事事件(全屏碎片释放叠层)+ loreLayer 已读标记 + idleHistory 详情展开 + 移动端 375px 适配审计
- **栈**Next.js 16 (App Router) · TypeScript · Tailwind CSS 4 · shadcn/ui · Canvas 2D · Zustand · Web Audio API
- **仓库**[https://git.atdunbg.xyz/Super_Z/echo-nexus](https://git.atdunbg.xyz/Super_Z/echo-nexus)
- **在线版**[https://gitea-pages.atdunbg.xyz/Super_Z/echo-nexus/](https://gitea-pages.atdunbg.xyz/Super_Z/echo-nexus/)
@@ -26,29 +28,60 @@
## 核心特色
- **解码共振谜题**:把放置游戏的「等待」变成有节奏的主动小谜题(路径构造法生成器,100% 可解
- **碎片涌现叙事**:故事从解码中自然浮现,5 纪元循环命名 + 模板化 lore,不打断玩法
- **深空全息美学**:晶体 + Canvas 粒子 + 共振波纹的差异化视觉(严格 emerald/rose/amber/fuchsia 四色全息色谱,零蓝色/靛色)
- **飞升多周目**:终局「接触」后保留蓝图开启新周目,星图天文台 18 个天赋跨周目永久生效
- **实时巡航玩法**Canvas 2D 飞船操控 + 8 种实体 + 3 层视差星空,打破纯放置节奏
- **角色 RPG 深度**:四维属性(探索力/智慧/勇气/灵感)影响所有游戏系统
- **📡 采矿无人机舰队**:每解锁一个采矿分支技术,就有一台自动采矿无人机加入舰队,24h 持续产出晶体(无需点击
- **⚙️ 放置工程项目**:6 种工程,派遣后**离线/在线自动推进**,完成领取奖励(晶体/洞见/能量/永久产能加成/随机碎片)
- **🔓 离线收益**:关闭浏览器后产能按 `offlineEff × crystalsPerSec` 持续累积(上限 8h),重新打开弹窗结算「沉睡期间」收益
- **🎯 始终可见的放置徽章**:Header 永远显示「放置中 +X/s」徽章,悬停查看产能构成明细——一眼就知道这是个 idle game
- **🔍 解码共振谜题**:把放置游戏的「等待」变成有节奏的主动小谜题(路径构造法生成器,100% 可解)
- **📜 碎片涌现叙事**:故事从解码中自然浮现,5 纪元循环命名 + 模板化 lore,不打断玩法
- **💎 深空全息美学**:晶体 + Canvas 粒子 + 共振波纹的差异化视觉(严格 emerald/rose/amber/fuchsia 四色全息色谱,零蓝色/靛色)
- **🔄 飞升多周目**:终局「接触」后保留蓝图开启新周目,星图天文台 18 个天赋跨周目永久生效
- **🚀 实时巡航玩法**Canvas 2D 飞船操控 + 8 种实体 + 3 层视差星空,打破纯放置节奏
- **🧬 角色 RPG 深度**:四维属性(探索力/智慧/勇气/灵感)影响所有游戏系统
---
## 游戏系统(10 大系统)
## 游戏系统(11 大系统)
| # | 系统 | 简介 |
|---|------|------|
| 1 | 放置采矿 | 中央晶体球 Canvas 粒子系统 + 主动脉冲 + 连击加成 |
| 2 | 谐振解码 | 原创路径谜题,100% 可解率 |
| 3 | 技术树 | 三层科技解锁,提升产能/解码/探险 |
| 4 | 遗迹探险 | 肉鸽系统,6 种节点 + 程序化路径 + BOSS |
| 5 | 星潮事件 | 6 种动态事件,全屏叠层 + 程序化音效 |
| 6 | 星图天文台 | 飞升后 3 选 1 天赋 draft,18 个跨周目天赋 |
| 7 | 回响编年史 | 跨周目叙事时间轴,5 纪元循环命名 |
| 8 | 深空信标 | 每日挑战 + 本地排行榜 Top20 |
| 9 | 深空巡航 | Canvas 2D 实时玩法,飞船操控/陨石躲避/星门通关 |
| 10 | 角色属性 | 四维属性(探索力/智慧/勇气/灵感),飞升获得属性点 |
| # | 系统 | 简介 | 类型 |
|---|------|------|------|
| 1 | **📡 放置采矿** | 中央晶体球 Canvas 粒子系统 + 主动脉冲 + 连击加成 + **自动采矿无人机舰队** | 放置 |
| 2 | **⚙️ 放置工程** | 6 种工程 × 3 槽位,**离线/在线自动推进**,完成领取奖励 | **放置** |
| 3 | **🔓 离线收益** | 关闭浏览器后产能按 `eff × cps` 累积(8h 上限),重新打开结算 | **放置** |
| 4 | 谐振解码 | 原创路径谜题,100% 可解率 | 主动 |
| 5 | 技术树 | 三层科技解锁,提升产能/解码/探险 | 主动 |
| 6 | 遗迹探险 | 肉鸽系统,6 种节点 + 程序化路径 + BOSS | 主动 |
| 7 | 星潮事件 | 6 种动态事件,全屏叠层 + 程序化音效 | 被动 |
| 8 | 星图天文台 | 飞升后 3 选 1 天赋 draft,18 个跨周目天赋 | 元进程 |
| 9 | 回响编年史 | 跨周目叙事时间轴,5 纪元循环命名 | 元进程 |
| 10 | 深空信标 | 每日挑战 + 本地排行榜 Top20 | 每日 |
| 11 | 深空巡航 | Canvas 2D 实时玩法,飞船操控/陨石躲避/星门通关 | 实时 |
| 12 | 角色属性 | 四维属性(探索力/智慧/勇气/灵感),飞升获得属性点 | 元进程 |
---
## 放置系统设计哲学(v0.14 + v0.15 平衡)
回响星核的「放置」不是简单地把数字挂机增长,而是分层呈现 **3 种 idle 节奏**
### 节奏 1:被动产能(最慢,最持续)
- 采矿无人机舰队 = 你已解锁的采矿技术节点
- 每台无人机 24h 持续产出晶体,无需任何操作
- 晶体进入仓库(受 `crystalCap` 限制),仓库满后停止产出(防溢出)
- **永远在线,离线也累积**
### 节奏 2:放置工程(中等周期,需要决策)
- 6 种工程,时长 1min ~ 1h 不等
- 玩家选择派遣到 3 个槽位之一 → 启动后**离线/在线自动推进**
- 完成后必须**手动领取**(防玩家错过奖励时机)
- 奖励类型多样:晶体 / 洞见 / 能量 / 永久产能加成 / 随机碎片
- **核心 idle loop:派遣 → 离开 → 回来 → 领取 → 再派遣**
### 节奏 3:离线收益(最长周期,回归奖励)
- 关闭浏览器后,被动产能按 `offlineEff`(默认 50%,可通过技术提升至 100%)继续累积
- 上限 8 小时(防极端挂机)
- 重新打开页面弹窗结算:「你离开了 X 小时,星核为你产出 Y 颗晶体」
- **回归玩家的"啊我回来了"瞬间**
---
@@ -67,9 +100,13 @@
| v0.5.1 | Gitea Pages 静态部署 + 新手教程 | ✅ |
| v0.5.2 | 离线收益报告 + 标签页 UI 重设计 | ✅ |
| v0.6 | 深空巡航 Canvas 2D 实时玩法 | ✅ |
| **v0.7** | **CrystalOrb Canvas 粒子系统 + 四维角色属性** | ✅ |
| v0.8 | 巡航玩法增强 / BOSS 关卡 / 道具掉落 | 🔜 |
| v0.9 | 云存档 + 云排行榜 | 🔜 |
| v0.7 | CrystalOrb Canvas 粒子系统 + 四维角色属性 | ✅ |
| v0.8 | 巡航玩法增强 / BOSS 关卡 / 道具掉落 | |
| v0.8.1 | 探险平衡 + 信标系统扩展(周挑战 + 信标链) | |
| **v0.14** | **放置系统:采矿无人机舰队 + 6 种放置工程 + 永久产能加成 + 始终可见 idle 徽章** | ✅ |
| **v0.15** | **叙事深化(8 碎片 × 2 层 = 16 层 loreLayers+ 永久加成 softcap + 批量领取 + 完成 toast + StatsPanel idle 统计** | ✅ |
| **v0.16** | **解码阈值叙事事件(5 里程碑全屏叠层)+ loreLayer 已读标记 + idleHistory 详情展开 + 移动端 375px 适配审计** | ✅ |
| v0.17 | 星潮三频段切换 + 健康设计(每日软上限 + 星核建议休眠) | 🔜 |
| v1.0 | 全 5 纪元手写叙事 + 多人同步星潮 | 🔜 |
---
@@ -86,6 +123,9 @@
- [`docs/08-星图天文台系统-v0.3.1.md`](docs/08-星图天文台系统-v0.3.1.md) — v0.3.1 天文台
- [`docs/09-回响编年史系统-v0.4.md`](docs/09-回响编年史系统-v0.4.md) — v0.4 编年史
- [`docs/10-深空信标系统-v0.5.md`](docs/10-深空信标系统-v0.5.md) — v0.5 信标
- [`docs/11-放置系统-v0.14.md`](docs/11-放置系统-v0.14.md) — **v0.14 放置系统(idle operations**
- [`docs/12-叙事深化-v0.15.md`](docs/12-叙事深化-v0.15.md) — **v0.15 loreLayers 多层碎片文本 + softcap + 批量领取**
- [`docs/13-叙事事件-v0.16.md`](docs/13-叙事事件-v0.16.md) — **v0.16 解码阈值里程碑叠层 + loreLayer 已读 + 移动端适配**
---
@@ -118,7 +158,7 @@ BUILD_EXPORT=true bun run build:static
cd out
git init && git checkout -b gh-pages
git add -A
git commit -m "deploy: v0.7"
git commit -m "deploy: v0.16"
git remote add origin https://git.atdunbg.xyz/Super_Z/echo-nexus.git
git push -f origin gh-pages
```
@@ -127,4 +167,31 @@ Gitea Pages 会自动从 `gh-pages` 分支提供静态网站服务。
---
## 灵感来源(Inspired by
- **Antimatter Dimensions** — 数值膨胀美学 + 终端 UI
- **Universal Paperclips** — 叙事驱动的放置游戏(Frank Lantz
- **A Dark Room** — 极简文字放置游戏(Michael Townsend
- **Melvor Idle** — 离线收益 + 多技能树
- **Outer Wilds** — 知识解锁式考古
- **Cookie Clicker** — Orteil 的放置游戏范式定义
---
## 健康游戏设计声明
放置游戏天然具有"低投入高回报"的成瘾性,可能对学业/工作压力大的青年造成时间碎片化风险。回响星核主动采取以下健康设计:
-**离线收益上限 8h**——防止 24h 挂机
-**工程完成需手动领取**——避免"打开就有奖励"的条件反射
-**无广告、无内购**——纯粹的单机体验
- 🔜 **v0.17 计划**:每日软上限 + "星核建议休眠"提醒(每 1 小时主动提示休息)
参考学术研究:
- Frank Lantz GDC 2018 "This Is Your Brain on Games"
- Reuters 2025 "Cozy video games can quell stress and anxiety"
- DOI:10.3389/fpsyg.2026.1774030 TikTok 时代学术倦怠研究
---
© Super_Z · 持续开发中
-9
View File
@@ -1,9 +0,0 @@
1:"$Sreact.fragment"
2:I[47257,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"ClientPageRoot"]
3:I[52683,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","/Super_Z/echo-nexus/_next/static/chunks/38c9b86c7986e4d2.js","/Super_Z/echo-nexus/_next/static/chunks/dad63bc31a306c06.js","/Super_Z/echo-nexus/_next/static/chunks/868e0df8b5a7f188.js","/Super_Z/echo-nexus/_next/static/chunks/421819b51db6b69f.js"],"default"]
6:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"OutletBoundary"]
7:"$Sreact.suspense"
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","rsc":["$","$1","c",{"children":[["$","$L2",null,{"Component":"$3","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@4","$@5"]}}],[["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/38c9b86c7986e4d2.js","async":true}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/dad63bc31a306c06.js","async":true}],["$","script","script-2",{"src":"/Super_Z/echo-nexus/_next/static/chunks/868e0df8b5a7f188.js","async":true}],["$","script","script-3",{"src":"/Super_Z/echo-nexus/_next/static/chunks/421819b51db6b69f.js","async":true}]],["$","$L6",null,{"children":["$","$7",null,{"name":"Next.MetadataOutlet","children":"$@8"}]}]]}],"loading":null,"isPartial":false}
4:{}
5:"$0:rsc:props:children:0:props:serverProvidedParams:params"
8:null
-23
View File
@@ -1,23 +0,0 @@
1:"$Sreact.fragment"
2:I[39756,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"default"]
3:I[37457,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"default"]
4:I[77855,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"Toaster"]
5:I[47257,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"ClientPageRoot"]
6:I[52683,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","/Super_Z/echo-nexus/_next/static/chunks/38c9b86c7986e4d2.js","/Super_Z/echo-nexus/_next/static/chunks/dad63bc31a306c06.js","/Super_Z/echo-nexus/_next/static/chunks/868e0df8b5a7f188.js","/Super_Z/echo-nexus/_next/static/chunks/421819b51db6b69f.js"],"default"]
9:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"OutletBoundary"]
a:"$Sreact.suspense"
c:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"ViewportBoundary"]
e:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"MetadataBoundary"]
10:I[68027,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"default"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/media/0acc7fdf55eb3220-s.p.532ccaa1.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
:HL["/Super_Z/echo-nexus/_next/static/media/797e433ab948586e-s.p.29207c2f.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
:HL["/Super_Z/echo-nexus/_next/static/media/caa3a2e1cccd8315-s.p.3b6cae6d.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
0:{"P":null,"b":"yNvWrGxQ0RM8HHWxdOJQM","c":["",""],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"zh-CN","suppressHydrationWarning":true,"className":"dark","children":["$","body",null,{"className":"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable orbitron_da1c3699-module__wSKb_W__variable antialiased bg-background text-foreground","children":[["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}],["$","$L4",null,{}]]}]}]]}],{"children":[["$","$1","c",{"children":[["$","$L5",null,{"Component":"$6","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@7","$@8"]}}],[["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/38c9b86c7986e4d2.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/dad63bc31a306c06.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/Super_Z/echo-nexus/_next/static/chunks/868e0df8b5a7f188.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/Super_Z/echo-nexus/_next/static/chunks/421819b51db6b69f.js","async":true,"nonce":"$undefined"}]],["$","$L9",null,{"children":["$","$a",null,{"name":"Next.MetadataOutlet","children":"$@b"}]}]]}],{},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$Lc",null,{"children":"$Ld"}],["$","div",null,{"hidden":true,"children":["$","$Le",null,{"children":["$","$a",null,{"name":"Next.Metadata","children":"$Lf"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$10",[]],"S":true}
7:{}
8:"$0:f:0:1:1:children:0:props:children:0:props:serverProvidedParams:params"
d:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
11:I[27201,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"IconMark"]
b:null
f:[["$","title","0",{"children":"回响星核 · Echo Nexus"}],["$","meta","1",{"name":"description","content":"原创深空考古放置策略游戏 — 解码记忆晶体,拼凑以太文明的回响,跨越维度发起接触。"}],["$","meta","2",{"name":"author","content":"Super_Z"}],["$","meta","3",{"name":"keywords","content":"Echo Nexus,回响星核,idle game,browser game,放置游戏,解谜,深空考古"}],["$","meta","4",{"property":"og:title","content":"回响星核 · Echo Nexus"}],["$","meta","5",{"property":"og:description","content":"原创深空考古放置策略游戏"}],["$","meta","6",{"property":"og:site_name","content":"Echo Nexus"}],["$","meta","7",{"property":"og:type","content":"website"}],["$","meta","8",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","9",{"name":"twitter:title","content":"回响星核 · Echo Nexus"}],["$","meta","10",{"name":"twitter:description","content":"原创深空考古放置策略游戏"}],["$","link","11",{"rel":"icon","href":"https://z-cdn.chatglm.cn/z-ai/static/logo.svg"}],["$","$L11","12",{}]]
-6
View File
@@ -1,6 +0,0 @@
1:"$Sreact.fragment"
2:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"ViewportBoundary"]
3:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"MetadataBoundary"]
4:"$Sreact.suspense"
5:I[27201,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"IconMark"]
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[["$","title","0",{"children":"回响星核 · Echo Nexus"}],["$","meta","1",{"name":"description","content":"原创深空考古放置策略游戏 — 解码记忆晶体,拼凑以太文明的回响,跨越维度发起接触。"}],["$","meta","2",{"name":"author","content":"Super_Z"}],["$","meta","3",{"name":"keywords","content":"Echo Nexus,回响星核,idle game,browser game,放置游戏,解谜,深空考古"}],["$","meta","4",{"property":"og:title","content":"回响星核 · Echo Nexus"}],["$","meta","5",{"property":"og:description","content":"原创深空考古放置策略游戏"}],["$","meta","6",{"property":"og:site_name","content":"Echo Nexus"}],["$","meta","7",{"property":"og:type","content":"website"}],["$","meta","8",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","9",{"name":"twitter:title","content":"回响星核 · Echo Nexus"}],["$","meta","10",{"name":"twitter:description","content":"原创深空考古放置策略游戏"}],["$","link","11",{"rel":"icon","href":"https://z-cdn.chatglm.cn/z-ai/static/logo.svg"}],["$","$L5","12",{}]]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false}
-7
View File
@@ -1,7 +0,0 @@
1:"$Sreact.fragment"
2:I[39756,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"default"]
3:I[37457,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"default"]
4:I[77855,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"Toaster"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","style"]
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","rsc":["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","precedence":"next"}],["$","link","1",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","precedence":"next"}],["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","async":true}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","async":true}]],["$","html",null,{"lang":"zh-CN","suppressHydrationWarning":true,"className":"dark","children":["$","body",null,{"className":"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable orbitron_da1c3699-module__wSKb_W__variable antialiased bg-background text-foreground","children":[["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}],"notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]]}],["$","$L4",null,{}]]}]}]]}],"loading":null,"isPartial":false}
-6
View File
@@ -1,6 +0,0 @@
:HL["/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/media/0acc7fdf55eb3220-s.p.532ccaa1.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
:HL["/Super_Z/echo-nexus/_next/static/media/797e433ab948586e-s.p.29207c2f.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
:HL["/Super_Z/echo-nexus/_next/static/media/caa3a2e1cccd8315-s.p.3b6cae6d.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","tree":{"name":"","paramType":null,"paramKey":"","hasRuntimePrefetch":false,"slots":{"children":{"name":"__PAGE__","paramType":null,"paramKey":"__PAGE__","hasRuntimePrefetch":false,"slots":null,"isRootLayout":false}},"isRootLayout":true},"staleTime":300}
@@ -1,11 +0,0 @@
self.__BUILD_MANIFEST = {
"__rewrites": {
"afterFiles": [],
"beforeFiles": [],
"fallback": []
},
"sortedPages": [
"/_app",
"/_error"
]
};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()
@@ -1 +0,0 @@
[]
@@ -1 +0,0 @@
self.__SSG_MANIFEST=new Set([]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
@@ -1,11 +0,0 @@
self.__BUILD_MANIFEST = {
"__rewrites": {
"afterFiles": [],
"beforeFiles": [],
"fallback": []
},
"sortedPages": [
"/_app",
"/_error"
]
};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()
@@ -1 +0,0 @@
[]
@@ -1 +0,0 @@
self.__SSG_MANIFEST=new Set([]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-2
View File
@@ -1,2 +0,0 @@
@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/fef07dbb0973bf53-s.518e079e.woff2)format("woff2");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/8a480f0b521d4e75-s.ea323500.woff2)format("woff2");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/53b9e256198e5412-s.853d50a3.woff2)format("woff2");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/7178b3e590c64307-s.55554cd0.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/caa3a2e1cccd8315-s.p.3b6cae6d.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Geist Fallback;src:local(Arial);ascent-override:95.94%;descent-override:28.16%;line-gap-override:0.0%;size-adjust:104.76%}.geist_a71539c9-module__T19VSG__className{font-family:Geist,Geist Fallback;font-style:normal}.geist_a71539c9-module__T19VSG__variable{--font-geist-sans:"Geist","Geist Fallback"}
@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/5ce348bf30bf5439-s.56c1f21e.woff2)format("woff2");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/4fa387ec64143e14-s.3b336396.woff2)format("woff2");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/6306c77e7c8268e4-s.e3369375.woff2)format("woff2");unicode-range:U+2000-2001,U+2004-2008,U+200A,U+23B8-23BD,U+2500-259F}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/7d817b4c03b0c5f1-s.a40b9a8b.woff2)format("woff2");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/bbc41e54d2fcbd21-s.fe42ddf4.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/797e433ab948586e-s.p.29207c2f.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Geist Mono Fallback;src:local(Arial);ascent-override:74.67%;descent-override:21.92%;line-gap-override:0.0%;size-adjust:134.59%}.geist_mono_8d43a2aa-module__8Li5zG__className{font-family:Geist Mono,Geist Mono Fallback;font-style:normal}.geist_mono_8d43a2aa-module__8Li5zG__variable{--font-geist-mono:"Geist Mono","Geist Mono Fallback"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-3
View File
@@ -1,3 +0,0 @@
@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/fef07dbb0973bf53-s.518e079e.woff2)format("woff2");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/8a480f0b521d4e75-s.ea323500.woff2)format("woff2");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/53b9e256198e5412-s.853d50a3.woff2)format("woff2");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/7178b3e590c64307-s.55554cd0.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/caa3a2e1cccd8315-s.p.3b6cae6d.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Geist Fallback;src:local(Arial);ascent-override:95.94%;descent-override:28.16%;line-gap-override:0.0%;size-adjust:104.76%}.geist_a71539c9-module__T19VSG__className{font-family:Geist,Geist Fallback;font-style:normal}.geist_a71539c9-module__T19VSG__variable{--font-geist-sans:"Geist","Geist Fallback"}
@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/5ce348bf30bf5439-s.56c1f21e.woff2)format("woff2");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/4fa387ec64143e14-s.3b336396.woff2)format("woff2");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/6306c77e7c8268e4-s.e3369375.woff2)format("woff2");unicode-range:U+2000-2001,U+2004-2008,U+200A,U+23B8-23BD,U+2500-259F}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/7d817b4c03b0c5f1-s.a40b9a8b.woff2)format("woff2");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/bbc41e54d2fcbd21-s.fe42ddf4.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Geist Mono;font-style:normal;font-weight:100 900;font-display:swap;src:url(../media/797e433ab948586e-s.p.29207c2f.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Geist Mono Fallback;src:local(Arial);ascent-override:74.67%;descent-override:21.92%;line-gap-override:0.0%;size-adjust:134.59%}.geist_mono_8d43a2aa-module__8Li5zG__className{font-family:Geist Mono,Geist Mono Fallback;font-style:normal}.geist_mono_8d43a2aa-module__8Li5zG__variable{--font-geist-mono:"Geist Mono","Geist Mono Fallback"}
@font-face{font-family:Orbitron;font-style:normal;font-weight:400;font-display:swap;src:url(../media/0acc7fdf55eb3220-s.p.532ccaa1.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Orbitron;font-style:normal;font-weight:500;font-display:swap;src:url(../media/0acc7fdf55eb3220-s.p.532ccaa1.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Orbitron;font-style:normal;font-weight:600;font-display:swap;src:url(../media/0acc7fdf55eb3220-s.p.532ccaa1.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Orbitron;font-style:normal;font-weight:700;font-display:swap;src:url(../media/0acc7fdf55eb3220-s.p.532ccaa1.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Orbitron;font-style:normal;font-weight:900;font-display:swap;src:url(../media/0acc7fdf55eb3220-s.p.532ccaa1.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Orbitron Fallback;src:local(Arial);ascent-override:81.5%;descent-override:19.59%;line-gap-override:0.0%;size-adjust:124.05%}.orbitron_da1c3699-module__wSKb_W__className{font-family:Orbitron,Orbitron Fallback;font-style:normal}.orbitron_da1c3699-module__wSKb_W__variable{--font-display:"Orbitron","Orbitron Fallback"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,95203,e=>{"use strict";var s=e.i(43476),t=e.i(71645),l=e.i(76639),a=e.i(19455),o=e.i(18533),r=e.i(43625),n=e.i(31334),i=e.i(83086),d=e.i(16715);function c({open:e,onOpenChange:c}){let x=(0,o.useGameStore)(e=>e.pendingPerkChoices),h=(0,o.useGameStore)(e=>e.constellation??[]),m=(0,o.useGameStore)(e=>e.chooseConstellationPerk),u=(0,o.useGameStore)(e=>e.rerollPerkChoices),[f,g]=(0,t.useState)(null);if((0,t.useEffect)(()=>{e||g(null)},[e]),(0,t.useEffect)(()=>{x&&x.length>0&&!e&&c(!0),(!x||0===x.length)&&e&&c(!1)},[x,e,c]),!x||0===x.length)return null;let p=(0,r.constellationProgress)(h);return(0,s.jsx)(l.Dialog,{open:e,onOpenChange:c,children:(0,s.jsxs)(l.DialogContent,{className:"max-w-md border-fuchsia-400/30 bg-gradient-to-br from-[#0a0820]/95 to-[#1a0f30]/95 backdrop-blur-md",children:[(0,s.jsxs)(l.DialogHeader,{children:[(0,s.jsxs)(l.DialogTitle,{className:"flex items-center gap-2 text-fuchsia-200",children:[(0,s.jsx)(i.Sparkles,{className:"h-4 w-4"}),"星图觉醒"]}),(0,s.jsxs)(l.DialogDescription,{className:"text-muted-foreground text-xs",children:["飞升带来的回响在星图上凝聚。从 3 道星辉中选择 1 道,永久获得其加成。",(0,s.jsx)("br",{}),(0,s.jsxs)("span",{className:"text-fuchsia-300/80",children:["当前已觉醒 ",p.unlocked,"/",p.total]})]})]}),(0,s.jsx)("div",{className:"grid grid-cols-1 gap-2 mt-1",children:x.map(e=>{let t=(0,r.getPerk)(e);if(!t)return null;let l=r.CONSTELLATION_CATEGORY_META[t.category],a=f===e;return(0,s.jsxs)("button",{onClick:()=>{g(e),m(e)&&((0,n.sfx)("constellation"),setTimeout(()=>c(!1),500))},disabled:!!f,className:`group relative w-full text-left rounded-lg border px-3 py-2.5 transition-all overflow-hidden ${a?"border-fuchsia-400/80 bg-fuchsia-500/10 scale-[1.02]":f?"border-white/5 opacity-40":"border-white/10 hover:border-white/30 hover:bg-white/5"}`,style:{boxShadow:a?`0 0 20px ${l.glow}`:void 0},children:[(0,s.jsx)("div",{className:"absolute left-0 top-0 bottom-0 w-1",style:{background:l.hex,boxShadow:`0 0 8px ${l.hex}`}}),(0,s.jsxs)("div",{className:"pl-2 flex items-start gap-3",children:[(0,s.jsx)("div",{className:"flex-shrink-0 mt-0.5 h-8 w-8 rounded-full flex items-center justify-center text-sm font-bold",style:{background:`${l.hex}20`,color:l.hex,border:`1px solid ${l.hex}40`},children:l.name.charAt(0)}),(0,s.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,s.jsxs)("div",{className:"flex items-center gap-2 mb-0.5",children:[(0,s.jsx)("span",{className:"text-sm font-bold text-foreground",children:t.name}),(0,s.jsx)("span",{className:"text-[9px] px-1 py-0.5 rounded font-mono",style:{background:`${l.hex}20`,color:l.hex},children:l.name})]}),(0,s.jsx)("div",{className:"text-[11px] text-muted-foreground",children:t.desc})]})]}),a&&(0,s.jsx)("div",{className:"absolute inset-0 pointer-events-none",children:[...Array(8)].map((e,t)=>(0,s.jsx)("span",{className:"absolute h-1 w-1 rounded-full animate-ping",style:{background:l.hex,left:`${20+8*t}%`,top:`${30+t%3*20}%`,animationDelay:`${50*t}ms`,animationDuration:"800ms"}},t))})]},e)})}),(0,s.jsxs)("div",{className:"flex items-center justify-between mt-3 pt-2 border-t border-white/5",children:[(0,s.jsxs)(a.Button,{variant:"ghost",size:"sm",onClick:()=>{u(),(0,n.sfx)("uiClick")},disabled:!!f,className:"text-muted-foreground hover:text-foreground h-7 text-[11px]",children:[(0,s.jsx)(d.RefreshCw,{className:"h-3 w-3 mr-1"}),"重新抽取"]}),(0,s.jsx)("span",{className:"text-[10px] text-muted-foreground/60",children:"✦ 选择后永久保留,跨周目生效"})]})]})})}e.s(["ConstellationDialog",()=>c])},76103,e=>{e.n(e.i(95203))}]);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,11 +0,0 @@
self.__BUILD_MANIFEST = {
"__rewrites": {
"afterFiles": [],
"beforeFiles": [],
"fallback": []
},
"sortedPages": [
"/_app",
"/_error"
]
};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()
@@ -1 +0,0 @@
[]
@@ -1 +0,0 @@
self.__SSG_MANIFEST=new Set([]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
-16
View File
@@ -1,16 +0,0 @@
1:"$Sreact.fragment"
2:I[39756,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
3:I[37457,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
4:I[77855,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"Toaster"]
5:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"OutletBoundary"]
6:"$Sreact.suspense"
8:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"ViewportBoundary"]
a:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"MetadataBoundary"]
c:I[68027,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","style"]
0:{"P":null,"b":"yNvWrGxQ0RM8HHWxdOJQM","c":["","_not-found",""],"q":"","i":false,"f":[[["",{"children":["/_not-found",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"zh-CN","suppressHydrationWarning":true,"className":"dark","children":["$","body",null,{"className":"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable orbitron_da1c3699-module__wSKb_W__variable antialiased bg-background text-foreground","children":[["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}],["$","$L4",null,{}]]}]}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":"$0:f:0:1:0:props:children:1:props:children:props:children:0:props:notFound:0:1:props:style","children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":"$0:f:0:1:0:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:1:props:style","children":404}],["$","div",null,{"style":"$0:f:0:1:0:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:style","children":["$","h2",null,{"style":"$0:f:0:1:0:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:children:props:style","children":"This page could not be found."}]}]]}]}]],null,["$","$L5",null,{"children":["$","$6",null,{"name":"Next.MetadataOutlet","children":"$@7"}]}]]}],{},null,false,false]},null,false,false]},null,false,false],["$","$1","h",{"children":[["$","meta",null,{"name":"robots","content":"noindex"}],["$","$L8",null,{"children":"$L9"}],["$","div",null,{"hidden":true,"children":["$","$La",null,{"children":["$","$6",null,{"name":"Next.Metadata","children":"$Lb"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$c","$undefined"],"S":true}
9:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
d:I[27201,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"IconMark"]
7:null
b:[["$","title","0",{"children":"回响星核 · Echo Nexus"}],["$","meta","1",{"name":"description","content":"原创深空考古放置策略游戏 — 解码记忆晶体,拼凑以太文明的回响,跨越维度发起接触。"}],["$","meta","2",{"name":"author","content":"Super_Z"}],["$","meta","3",{"name":"keywords","content":"Echo Nexus,回响星核,idle game,browser game,放置游戏,解谜,深空考古"}],["$","meta","4",{"property":"og:title","content":"回响星核 · Echo Nexus"}],["$","meta","5",{"property":"og:description","content":"原创深空考古放置策略游戏"}],["$","meta","6",{"property":"og:site_name","content":"Echo Nexus"}],["$","meta","7",{"property":"og:type","content":"website"}],["$","meta","8",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","9",{"name":"twitter:title","content":"回响星核 · Echo Nexus"}],["$","meta","10",{"name":"twitter:description","content":"原创深空考古放置策略游戏"}],["$","link","11",{"rel":"icon","href":"https://z-cdn.chatglm.cn/z-ai/static/logo.svg"}],["$","$Ld","12",{}]]
-6
View File
@@ -1,6 +0,0 @@
1:"$Sreact.fragment"
2:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"ViewportBoundary"]
3:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"MetadataBoundary"]
4:"$Sreact.suspense"
5:I[27201,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"IconMark"]
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","rsc":["$","$1","h",{"children":[["$","meta",null,{"name":"robots","content":"noindex"}],["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[["$","title","0",{"children":"回响星核 · Echo Nexus"}],["$","meta","1",{"name":"description","content":"原创深空考古放置策略游戏 — 解码记忆晶体,拼凑以太文明的回响,跨越维度发起接触。"}],["$","meta","2",{"name":"author","content":"Super_Z"}],["$","meta","3",{"name":"keywords","content":"Echo Nexus,回响星核,idle game,browser game,放置游戏,解谜,深空考古"}],["$","meta","4",{"property":"og:title","content":"回响星核 · Echo Nexus"}],["$","meta","5",{"property":"og:description","content":"原创深空考古放置策略游戏"}],["$","meta","6",{"property":"og:site_name","content":"Echo Nexus"}],["$","meta","7",{"property":"og:type","content":"website"}],["$","meta","8",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","9",{"name":"twitter:title","content":"回响星核 · Echo Nexus"}],["$","meta","10",{"name":"twitter:description","content":"原创深空考古放置策略游戏"}],["$","link","11",{"rel":"icon","href":"https://z-cdn.chatglm.cn/z-ai/static/logo.svg"}],["$","$L5","12",{}]]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false}
-7
View File
@@ -1,7 +0,0 @@
1:"$Sreact.fragment"
2:I[39756,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
3:I[37457,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
4:I[77855,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"Toaster"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","style"]
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","rsc":["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","precedence":"next"}],["$","link","1",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","precedence":"next"}],["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","async":true}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","async":true}],["$","script","script-2",{"src":"/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","async":true}]],["$","html",null,{"lang":"zh-CN","suppressHydrationWarning":true,"className":"dark","children":["$","body",null,{"className":"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable orbitron_da1c3699-module__wSKb_W__variable antialiased bg-background text-foreground","children":[["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}],"notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]]}],["$","$L4",null,{}]]}]}]]}],"loading":null,"isPartial":false}
@@ -1,5 +0,0 @@
1:"$Sreact.fragment"
2:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"OutletBoundary"]
3:"$Sreact.suspense"
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","rsc":["$","$1","c",{"children":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],null,["$","$L2",null,{"children":["$","$3",null,{"name":"Next.MetadataOutlet","children":"$@4"}]}]]}],"loading":null,"isPartial":false}
4:null
-4
View File
@@ -1,4 +0,0 @@
1:"$Sreact.fragment"
2:I[39756,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
3:I[37457,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","rsc":["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","template":["$","$L3",null,{}]}]]}],"loading":null,"isPartial":false}
-3
View File
@@ -1,3 +0,0 @@
:HL["/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","style"]
0:{"buildId":"yNvWrGxQ0RM8HHWxdOJQM","tree":{"name":"","paramType":null,"paramKey":"","hasRuntimePrefetch":false,"slots":{"children":{"name":"/_not-found","paramType":null,"paramKey":"/_not-found","hasRuntimePrefetch":false,"slots":{"children":{"name":"__PAGE__","paramType":null,"paramKey":"__PAGE__","hasRuntimePrefetch":false,"slots":null,"isRootLayout":false}},"isRootLayout":false}},"isRootLayout":true},"staleTime":300}
File diff suppressed because one or more lines are too long
-16
View File
@@ -1,16 +0,0 @@
1:"$Sreact.fragment"
2:I[39756,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
3:I[37457,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
4:I[77855,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"Toaster"]
5:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"OutletBoundary"]
6:"$Sreact.suspense"
8:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"ViewportBoundary"]
a:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"MetadataBoundary"]
c:I[68027,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"default"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","style"]
0:{"P":null,"b":"yNvWrGxQ0RM8HHWxdOJQM","c":["","_not-found",""],"q":"","i":false,"f":[[["",{"children":["/_not-found",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"zh-CN","suppressHydrationWarning":true,"className":"dark","children":["$","body",null,{"className":"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable orbitron_da1c3699-module__wSKb_W__variable antialiased bg-background text-foreground","children":[["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}],["$","$L4",null,{}]]}]}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":"$0:f:0:1:0:props:children:1:props:children:props:children:0:props:notFound:0:1:props:style","children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":"$0:f:0:1:0:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:1:props:style","children":404}],["$","div",null,{"style":"$0:f:0:1:0:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:style","children":["$","h2",null,{"style":"$0:f:0:1:0:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:children:props:style","children":"This page could not be found."}]}]]}]}]],null,["$","$L5",null,{"children":["$","$6",null,{"name":"Next.MetadataOutlet","children":"$@7"}]}]]}],{},null,false,false]},null,false,false]},null,false,false],["$","$1","h",{"children":[["$","meta",null,{"name":"robots","content":"noindex"}],["$","$L8",null,{"children":"$L9"}],["$","div",null,{"hidden":true,"children":["$","$La",null,{"children":["$","$6",null,{"name":"Next.Metadata","children":"$Lb"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$c","$undefined"],"S":true}
9:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
d:I[27201,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"IconMark"]
7:null
b:[["$","title","0",{"children":"回响星核 · Echo Nexus"}],["$","meta","1",{"name":"description","content":"原创深空考古放置策略游戏 — 解码记忆晶体,拼凑以太文明的回响,跨越维度发起接触。"}],["$","meta","2",{"name":"author","content":"Super_Z"}],["$","meta","3",{"name":"keywords","content":"Echo Nexus,回响星核,idle game,browser game,放置游戏,解谜,深空考古"}],["$","meta","4",{"property":"og:title","content":"回响星核 · Echo Nexus"}],["$","meta","5",{"property":"og:description","content":"原创深空考古放置策略游戏"}],["$","meta","6",{"property":"og:site_name","content":"Echo Nexus"}],["$","meta","7",{"property":"og:type","content":"website"}],["$","meta","8",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","9",{"name":"twitter:title","content":"回响星核 · Echo Nexus"}],["$","meta","10",{"name":"twitter:description","content":"原创深空考古放置策略游戏"}],["$","link","11",{"rel":"icon","href":"https://z-cdn.chatglm.cn/z-ai/static/logo.svg"}],["$","$Ld","12",{}]]
-91
View File
@@ -1,91 +0,0 @@
# Task ID: 10-a — 限时挑战 + 星潮类型深化
**Agent**: full-stack-developer
**Task**: 工单 #5 限时挑战 + 工单 #3 星潮类型深化
## Work Log
### 前置准备
- 阅读 `worklog.md` 了解 v0.8.1 项目状态(10 大系统,四色全息 emerald/rose/amber/fuchsia
- 精读 `beacon.ts`(873 行,日挑战+周挑战+信标链)、`BeaconPanel.tsx`753 行)、`starTide.ts`209 行,6 种星潮)、`gameStore.ts` trackBeacon~170 行)+ tickTide~440 行)
- 确认现有 UI 均动态读取 `TIDE_EVENTS[type]`,新增类型自动生效
### 工单 #5:限时挑战(Timed Challenge
**beacon.ts 扩展**873 → 1162 行,+289 行):
- `BeaconScoreEntry` 新增 `isTimed?: boolean` 字段
- `BeaconTimedChallenge` 接口:slotKey / type / difficulty(固定 routine) / goal / rewardInsight / rewardContact / seed / title / desc / expiresAt
- `BeaconTimedProgress` 接口:slotKey / progress / startedAt / completedAt / claimed / durationSec
- `TIMED_SLOT_MS = 4h``BEACON_TIMED_KEY = "echo-nexus-beacon-timed-v1"`
- `getTimedSlotKey(now)`UTC 0/4/8/12/16/20 点切分,格式 "timed_YYYY-MM-DD_HH"
- `timedSlotKeyToSeed`FNV-1a 哈希
- `generateTimedChallenge(now)`:确定性生成,难度 routinegoal = 日基准 ×0.3-0.5,5 种类型各有公式
- `msUntilNextTimedSlot(now)`:距离下个 4 小时时段的毫秒数
- `loadTimedProgress` / `saveTimedProgress` / `addTimedProgress` / `claimTimedReward`(推送排行榜,entry 加 isTimed: true
**gameStore.ts 集成**
- import 扩展:generateTimedChallenge / loadTimedProgress / addTimedProgress / claimTimedReward + 类型
- `trackBeacon` 返回值新增 `timedJustCompleted`:日/限时/周三类进度同时更新
- 新增 `claimTimedBeacon` actionGameActions 接口同步)
- 新增 `timedJustCompleted` 到 trackBeacon 返回类型
**BeaconPanel.tsx UI**753 → 944 行):
- import 扩展:generateTimedChallenge / loadTimedProgress / getTimedSlotKey / msUntilNextTimedSlot / Hourglass 图标
- 新增 timedChallenge/timedProgress/timedCountdown state
- 每秒刷新 timedProgress + timedCountdown
- 新增 handleClaimTimed 回调
- **限时挑战区块**(amber 主题,插入日挑战与周挑战之间):
- Hourglass 图标 + "限时挑战 · TIMED" 标题 + slotKey + 倒计时
- 难度/类型标签 + 标题 + 描述 + 进度条 + 奖励 + 领取按钮(emerald 主题)
- **紧急状态**:距时段结束 <30min 时切换 rose 脉冲动画 + "即将结束"徽章
- 2 个新动画:timed-glowamber 呼吸)/ timed-urgentrose 急促脉冲)
- 排行榜 entry 区分 TIMEDamber 徽章)/ WEEKfuchsia 徽章)
- 空状态提示更新为"完成限时、每日或本周信标即可登榜"
### 工单 #3:星潮类型深化
**starTide.ts 扩展**209 → 289 行):
- `TideType` 新增 3 种:surge / eclipse / prism
- `TideModifiers` 新增 3 个可选字段:targetLenBonus / bossWinRateBonus / autoDecodeIntervalMult
- `TIDE_EVENTS` 新增 3 种元信息(name/desc/color/glow/icon/negative):
- surge(涌动星潮,emerald #34d399,⇈):产能 ×2.5 但解码目标 +2
- eclipse(蚀相星潮,rose #fb7185,◐):BOSS 胜率 +20% 但产能 -30%
- prism(棱镜星潮,fuchsia #e879f9,◬):洞见 ×2 + 自动解码周期 -30%
- `TIDE_WEIGHTS` 新增 surge/eclipse/prism 各 12(总权重 136
- `getTideModifiers` 新增 3 个 case + null 分支补全新字段
- 注释更新:"6 种类型" → "9 种类型"
**decode.ts 扩展**
- `generatePuzzle` 新增第 3 参数 `targetLenBonus`(默认 0
- targetLen = cfg.targetLen + targetLenBonusstepLimitBase 同步增加
- 路径构造法自动适配更长目标序列(300 次尝试 + 线性兜底)
**gameStore.ts 集成**3 处修饰器应用):
- `startDecode`surge 星潮时传入 `tideMod.targetLenBonus` → 谜题更长
- `autoDecodeTick`prism 星潮时 `interval *= tideMod.autoDecodeIntervalMult`(×0.7
- `resolveCurrentNode`eclipse 星潮时 `b = am.bossWinRateBonus + tideMod.bossWinRateBonus`+20%
**achievements.ts**`ach_tides_all` 阈值 6 → 9,描述"经历全部 9 种星潮事件"
**page.tsx**StatsPanel "星潮亲历" 显示 `/ 9`
### QA 验证
1. **lint**`bun run lint` 零错误(exit 0
2. **dev 服务器**HTTP 200,编译 < 30ms
3. **BeaconPanel VLM 评分**
- 首屏 8.5/10:限时挑战 TIMED 区块可见、四色一致、倒计时/进度/标题/奖励/按钮清晰
- 最终截图 9/10:4 个挑战区块齐全、限时区块带倒计时、无蓝色
4. **新星潮 VLM 评分**localStorage 注入 + reload 触发):
- surgeemerald 绿):8/10,横幅 + 全屏绿色微光
- prismfuchsia 紫):7/10,横幅 + 全屏紫色微光
- eclipserose 粉):8/10(单图),横幅 + 全屏粉色微光
5. **不破坏现有功能**:日挑战/周挑战/信标链/6 旧星潮全部保留,排行榜正常
## Stage Summary
- ✅ 工单 #5 限时挑战完成:beacon.ts +289 行 + gameStore claimTimedBeacon + BeaconPanel amber 区块
- ✅ 工单 #3 星潮深化完成:starTide.ts +80 行(3 新类型)+ decode.ts targetLenBonus + gameStore 3 处修饰器
- ✅ 确定性生成:限时挑战同时段同种子同结果(FNV-1a slotKey 哈希)
- ✅ 严格四色规范:限时 amber、surge emerald、eclipse rose、prism fuchsia,零蓝色/靛色
- ✅ 紧急状态设计:限时挑战 <30min 时 rose 脉冲 + "即将结束"徽章
- ✅ lint 零错误 + dev HTTP 200 + VLM ≥7/10(信标 9/10、surge 8/10、prism 7/10、eclipse 8/10
- ✅ 现有日/周/信标链/6 旧星潮全部保留,无回归
-207
View File
@@ -1,207 +0,0 @@
# Task 10-b · full-stack-developer · P2/#4 云排行榜 mini-service
> 本文件为本 agent 在 Task 10-b 的工作记录,供后续 agent 查阅。
## 任务概述
为「回响星核 / Echo Nexus」v0.8.2 实现 P2/#4 工单:把信标本机排行榜(纯 localStorage)升级为云端 Top100,让玩家间可以比较分数。
## 阅读的前置工作
- `/home/z/my-project/worklog.md`(v0.8.1 项目状态,10 大系统,四色全息规范)
- `/home/z/my-project/src/lib/game/beacon.ts`(实际 1161 行 — worklog 信息滞后,v0.8.2 已加限时挑战 `claimTimedReward`
- `/home/z/my-project/src/components/game/BeaconPanel.tsx`(实际 953 行 — 已含限时挑战 amber 主题)
- `/home/z/my-project/src/store/gameStore.ts`1241 行 — trackBeacon + 3 个 claim actiongrantBeaconReward/claimWeeklyBeacon/claimTimedBeacon/claimChainReward
- `/home/z/my-project/Caddyfile`:81 网关,按 ?XTransformPort=* 转发到对应端口)
- `/home/z/my-project/examples/websocket/server.ts` + `frontend.tsx`mini-service + 前端连接参考)
- `/home/z/my-project/.zscripts/dev.sh`mini-service 自动扫描启动逻辑,发现 mini-services 目录下子服务自动 `bun run dev`
- `/home/z/my-project/agent-ctx/9-b-full-stack-developer.md`(前一个 agent 的信标系统扩展记录)
- `/home/z/my-project/mini-services/star-tide-service/`(已存在的 P3 #10-c 服务,端口 3031
## 实现细节
### 1. mini-service`mini-services/leaderboard-service/`
**目录结构**
```
mini-services/leaderboard-service/
├── package.json # 独立 bun 项目,type=module
├── index.ts # Hono 入口(182 行)
├── bun.lock # 自动生成
├── node_modules/ # hono 独立安装
└── README.md # API 文档
```
**package.json**
- `"dev": "bun --hot index.ts"`(规范要求的热重载脚本)
- `"start": "bun index.ts"`(无热重载,用于稳定运行)
- 依赖:hono ^4.6.14
**index.ts 设计要点**
- Hono + `cors()` 中间件,origin: * 全开放(前端跨端口必须)
- 内存数组 `entries: BeaconScoreEntry[]`,最多 1000 条,按 score 降序
- 同分排序:先看用时短,再看提交早
- 防刷:`lastSubmitAt: Map<dateKey|challenge, ts>`,10 秒内只接受 1 次,返回 429 + retryAfterMs
- 4 个路由:
- `GET /` → 健康检查 `{service, version, ok, uptime}`
- `GET /api/leaderboard` → Top100 `{entries, total}`
- `POST /api/leaderboard` body `{entry}` → schema 校验 → 推入 → 排序 → `{entries, total, rank}`
- `GET /api/leaderboard/stats``{totalSubmissions, uniquePlayers, topScore}`
- OPTIONS 预检由 hono/cors 自动处理,返回 204 + 完整 CORS 头
- 端口固定 3030`export default { port, fetch }` 标准 bun 模式
**启动调试经验**
- `bun --hot` 在本沙盒环境下不稳定,多次启动后约 5-10s 内被 kill(即使 setsid + nohup
- 解决方案:用 `bun index.ts`(无 --hot+ 双 fork 模式:`( bun index.ts >/tmp/log 2>&1 & )`
- 双 fork 后 PPID=1reparent 到 init),进程脱离原 bash sessionuptime 4+ 分钟稳定
### 2. beacon.ts 扩展(1161 → 1290 行,+129 行)
**三个 claim 函数返回值扩展(非破坏性)**:
- `claimBeaconReward` 返回值新增 `entry: BeaconScoreEntry`
- `claimWeeklyReward` 返回值新增 `entry: BeaconScoreEntry`
- `claimTimedReward` 返回值新增 `entry: BeaconScoreEntry`
- 用途:让前端 / gameStore 能拿到完整 entry 提交到云端
**新增云排行榜模块**
- `BEACON_CLOUD_PORT = 3030` 常量
- `BEACON_CLOUD_LAST_SUBMIT_KEY = "echo-nexus-beacon-cloud-last-submit-v1"` localStorage key
- 3 个响应接口:`CloudLeaderboardResponse` / `CloudSubmitResponse` / `CloudStatsResponse`
- `loadLastCloudSubmitTimestamp()` / `saveLastCloudSubmitTimestamp(ts)`
- `fetchCloudLeaderboard(): Promise<BeaconScoreEntry[]>` — GET `/api/leaderboard?XTransformPort=3030`
- `submitCloudScore(entry): Promise<number>` — POST,成功返回 rank ≥ 1,失败返回 -1,自动记录 ts
- `fetchCloudStats(): Promise<CloudStatsResponse | null>`
- **所有 fetch 用相对路径 + ?XTransformPort=3030,禁止 localhost:3030**
- try-catch 包裹,失败时静默返回空/null,不抛异常
### 3. gameStore.ts 集成
- import 新增 `submitCloudScore`
- `claimWeeklyBeacon` action:领奖成功后 `void submitCloudScore(res.entry)`fire-and-forget,不 await,不阻塞)
- `claimTimedBeacon` action:同上
- `claimBeaconReward` (daily) 由 BeaconPanel 直接调用,不通过 gameStore
### 4. BeaconPanel.tsx 重写(953 → 1170 行,+217 行)
**新增 import**
- `fetchCloudLeaderboard` / `submitCloudScore` / `loadLastCloudSubmitTimestamp` from beacon
- 4 个 lucide 图标:`RefreshCw` / `Globe` / `WifiOff` / `Loader2`
- `useRef` from react
**新增状态**
- `lbTab: 'local' | 'global'`(默认 local
- `cloudEntries: BeaconScoreEntry[]`
- `cloudLoading: boolean`
- `cloudError: string | null`
- `cloudFetched: boolean`
- `mySubmitTs: number`
- `cloudFetchingRef` (防并发)
**新增逻辑**
- `refreshCloudLeaderboard` callback:拉取云端榜 + 防并发 + 空 entries 时显示"成为首位登顶者"
- useEffect:切到全球 tab 自动拉取(仅首次)+ 初始化读取 mySubmitTs
- `handleClaimDaily`:领奖后 `void submitCloudScore(res.entry).then(rank => ...)` — 若用户在全球 tab 自动刷新
- `handleClaimTimed` / `handleClaimWeekly`:领奖后更新 mySubmitTs + 若在全球 tab 自动刷新
**排行榜 UI 重写为双 tab**
- 顶部 tab 切换:「本地」(amber 主题) / 「全球」(emerald 主题) — 用 `<button aria-pressed>` 实现可访问性
- 全球 tab 专属刷新按钮(RefreshCwloading 时 animate-spin
- 子标题:本地"本机 Top N · 离线可用" / 全球"全球 Top N · 已同步 / 同步中…"
- 本地榜:保留原 v0.8.2 渲染(max-h-200px overflow-y-auto
- 全球榜:
- 加载中:Loader2 spinner + "正在拉取全球榜…"
- 空榜 + 错误:WifiOff 图标 + 错误文案 + 重试按钮
- 空榜 + 无错:Globe 图标 + "尚无全球记录。完成挑战并领取即可登顶全球榜!"
- 有数据:渲染前 100 条,每条带排名(1-3 名用 Crown/Medal/Award 图标)/ 难度色 / WEEK·TIMED 徽章 / 用时 / 分数
- **玩家自己的记录高亮**:通过 `entry.timestamp === mySubmitTs` 匹配
- emerald 边框 (`border-emerald-500/40`)
- emerald 阴影 (`shadow-[0_0_12px_rgba(52,211,153,0.25)]`)
- YOU 徽章 (`bg-emerald-500/25 text-emerald-200 border-emerald-500/50`)
- emerald 分数色 (`color: #34d399`)
- 加粗排名
### 5. eslint 配置
- `eslint.config.mjs` 新增 ignores `"mini-services/**"`
- 原因:mini-service 是独立 bun 项目,有自己的 TypeScript 配置和 lint 规范,不应参与主项目 lint
## QA 验证结果
### 1. lint
- `bun run lint` 零错误零警告
### 2. dev 服务器
- dev.log 全程无错误,所有编译 < 300ms
- 注:dev.log 中显示 `/api/leaderboard?XTransformPort=3030 404` 是预期行为 — 通过 :3000 直接访问时 Next.js 没有 /api/leaderboard 路由;通过 :81 网关访问时 Caddy 转发到 :3030 正常返回 200
### 3. mini-service curl 全通过
- `GET /` → 200 `{"service":"echo-nexus-leaderboard","version":"v0.8.2","ok":true,"uptime":N}`
- `GET /api/leaderboard` (空) → 200 `{"entries":[],"total":0}`
- `POST /api/leaderboard` → 200 `{"entries":[...],"total":1,"rank":1}`
- `GET /api/leaderboard` (有数据) → 200 `{"entries":[...],"total":N}`
- `GET /api/leaderboard/stats` → 200 `{"totalSubmissions":N,"uniquePlayers":M,"topScore":X}`
- `OPTIONS /api/leaderboard` 预检 → 204 + 完整 CORS 头(Allow-Origin: *
- 重复 POST(同 dateKey+challenge 10s 内)→ 429 `{"error":"Rate limited","retryAfterMs":N}`
### 4. 网关路由验证
- Caddy :81 → localhost:3030 通过 `?XTransformPort=3030` 正确转发,返回 JSON 200
### 5. agent-browser 集成测试
- 通过 :81 端口访问(绕过 Next.js :3000 的 404
- 信标 tab 选中(用 KeyboardEvent Enter 激活 Radix Tabs — 因 pointerdown 被覆盖层拦截)
- 切到「全球」tab → 自动拉取 → 显示"全球 Top 6 · 已同步" → 渲染 6 条记录
- 刷新按钮可点击,旋转动画正常
- POST 测试:浏览器 fetch 提交 score=9999 → 返回 rank=1 → 刷新后榜首显示 10.00K
- YOU 高亮:手动设置 localStorage[BEACON_CLOUD_LAST_SUBMIT_KEY] 后刷新 → 榜首显示 emerald 边框 + YOU 徽章
### 6. VLM 视觉评分(目标 ≥7/10)
- 全球榜含 YOU 高亮:**8/10**
- VLM 评语:"双tab切换清晰,全球榜记录完整,难度色与标签规范,视觉层次佳,但「YOU」徽章未突出显示"
- 本地榜:**8/10**
- VLM 评语:"双tab切换逻辑清晰,本地tab内容完整呈现;四色规范应用,视觉区分度高;信息层级合理"
## 修改的文件
1. `mini-services/leaderboard-service/package.json`(新建)
2. `mini-services/leaderboard-service/index.ts`(新建,182 行)
3. `mini-services/leaderboard-service/README.md`(新建)
4. `src/lib/game/beacon.ts` — 1161 → 1290 行(+129 行:3 个 claim 返回 entry + 云排行榜模块)
5. `src/store/gameStore.ts` — 1235 → 1252 行(+17 行:import + 2 个 claim action 加 submitCloudScore
6. `src/components/game/BeaconPanel.tsx` — 953 → 1170 行(+217 行:双 tab UI + 云端拉取 + 提交 + YOU 高亮)
7. `eslint.config.mjs` — ignores 新增 "mini-services/**"
## 不破坏的现有功能
- 本地排行榜(`loadLeaderboard` / `pushLeaderboardEntry`)完整保留作为离线 fallback
- 日挑战 / 周挑战 / 限时挑战 / 信标链流程全部保留
- 现有 localStorage keysecho-nexus-beacon-lb-v1 / -prog-v1 / -weekly-v1 / -chain-v1 / -timed-v1)全部保留
- 主项目 package.json 不变(hono 装在 mini-service 子项目内)
## 新增的 localStorage keys
- `echo-nexus-beacon-cloud-last-submit-v1`(上次成功提交到云端的 entry timestamp,用于全球榜高亮)
## 四色全息规范遵循
- 本地 tabamber (#fbbf24)
- 全球 tabemerald (#34d399) — 与"在线/同步"语义一致
- 玩家高亮:emerald 边框 + emerald YOU 徽章 + emerald 分数色
- 难度色保留:routine emerald / anomaly amber / singular rose
- 周挑战徽章:fuchsia
- 限时挑战徽章:amber
- 错误状态:rose (#fb7185)
- **零蓝色/靛色违规**
## 截图资产
- `/home/z/my-project/agent-ctx/beacon-global-leaderboard.png` — 全球榜初始视图(6 条记录)
- `/home/z/my-project/agent-ctx/beacon-global-with-you.png` — 全球榜含 YOU 高亮(7 条记录,榜首是玩家)
- `/home/z/my-project/agent-ctx/beacon-local-leaderboard.png` — 本地榜视图
## 重要注意事项(供后续 agent)
1. **前端访问端口**:用户通过 Preview Panel 看到的是 Caddy 网关 :81,不是 Next.js :3000。所以 `fetch('/api/leaderboard?XTransformPort=3030')` 在用户视角下能正常路由。如果直接访问 :3000 会 404(这是预期行为)。
2. **mini-service 启动方式**:用 `bun index.ts`(无 --hot+ 双 fork `( ... & )` 模式启动。`bun --hot` 在沙盒下不稳定。
3. **mini-service 已被 .zscripts/dev.sh 自动扫描**:下次容器重启会自动启动。但当前会话需手动启动一次。
4. **localStorage key 命名**`echo-nexus-beacon-cloud-last-submit-v1` 而非 `echo-nexus-beacon-cloud-lb-v1`,前者存的是单个 timestamp(用于高亮),后者若需要存全球榜快照可用后者(目前未实现,按需拉取)。
5. **star-tide-service 端口 3031**:另一个 P3 工单已存在的服务,本服务的端口 3030 与之互不冲突。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

+89
View File
@@ -0,0 +1,89 @@
---
Task ID: 2-b
Agent: full-stack-developer
Task: v0.16 完善 — loreLayer 已读标记 + idleProjectHistory 详情展开 + 移动端 375px 适配审计
Work Log:
- 必读上下文:worklog v0.15-release 段 + Codex.tsxv0.15 loreLayers 分层渲染)+ StatsPanel.tsxv0.15 抽出独立组件)+ types.ts GameState + config.ts FRAGMENTS/loreLayers/isLoreLayerUnlocked + gameStore.tsactions + persist migrate+ IdleOperationsPanel.tsx + BeaconPanel.tsx + ExpeditionPanel.tsx
- 子任务 1loreLayer 已读标记
- 新建 `src/lib/game/format.ts` 导出 `formatRelativeTime(ts)` 工具函数(<60s "刚刚" / <60m "X 分钟前" / <24h "X 小时前" / <7d "X 天前" / 否则具体日期)
- `types.ts`GameState 接口新增 `readLoreLayers: string[]`(位置:v0.14 idle 字段之后、元字段之前,注释标 v0.16 loreLayer 已读)
- `engine.ts`
* `createInitialState` 末尾加 `readLoreLayers: []`(在 idleStats 之后)
* `performPrestige` 返回对象加 `readLoreLayers: Array.isArray(state.readLoreLayers) ? state.readLoreLayers : []`(跨周目永久保留,与 idle 永久字段同一区域)
- `gameStore.ts`
* GameActions 接口加 `markLoreLayerRead: (fragmentId: string, layer: 1 | 2) => void`(在 tickIdleProjects 之后)
* 实现该 action:构造 key `${fragmentId}_L${layer}`,已存在则 no-op,否则 set 新数组
* persist migrate 函数末尾加 `readLoreLayers: Array.isArray(s.readLoreLayers) ? s.readLoreLayers : []`(不改 version,仍是 1
- `Codex.tsx`
* useShallow 订阅新增 `readLoreLayers``markLoreLayerRead`
* LoreLayerBlock 接收 `isRead` + `onMarkRead` props
- 已读:层标题旁加 muted "✓ 已读" 标记 + 边框从 amber/fuchsia 高亮降级为 `border-white/10`
- 未读但已解锁:保持 v0.15 高亮 + 标题旁加 `animate-pulse` 脉冲小圆点 + "新" 字提示
- 文本区域包成 `<button>` 元素,点击调用 `onMarkRead`(自然交互,不另设按钮)
- 未读时下方加一行 muted "▸ 点击文本标记已读" 引导文字
* 列表卡片标题旁小圆点:未读时 `animate-pulse` + glow,已读时 `bg-*-400/30` 静态
* 顶部统计从单行"深层叙事 X/Y 已解锁"扩展为两行(移动端 stack / 桌面并排):深层叙事 X/Y 已解锁 + 已读 A/B(A=已读数,B=已解锁层数)
* 弹层 padding 从 `p-5``p-4 sm:p-5`,标题 `text-lg``text-base sm:text-lg`,外层 backdrop padding 从 `p-4``p-3 sm:p-4`375px 适配)
- 子任务 2idleProjectHistory 详情展开
- `StatsPanel.tsx`
* useShallow 订阅新增 `idleProjectHistory` 数组与 `idleProjectSlots`(用于详情中潜在"进行中"状态参考)
* 删除原"放置工程历史 N 条"的简单行,改为 `col-span-2` 可展开按钮:
- 左侧 label + "(最近 5 条可展开)" 提示(仅 historyLen > 0 时显示)
- 右侧 "N 条" + ChevronDown/ChevronUp 图标(lucide-react
* 展开后渲染 `col-span-2` 卡片:
- 空历史 → "暂无放置工程完成记录 · 前往「放置」标签派遣工程"
- 非空 → 倒序最近 5 条:每行 = 工程图标 + 工程名(truncate+ 相对时间(formatRelativeTime
- 最近一条用 `bg-fuchsia-500/5` 高亮
- 历史超 5 条时底部加 "仅展示最近 5 条 · 共 N 条历史" 提示
* 展开状态用本地 `useState<boolean>`
* useMemo 派生 `recentHistory`(避免每次渲染重切)
- 子任务 3:移动端 375px 适配审计
- 审计范围:Codex / IdleOperationsPanel / StatsPanel / BeaconPanel / ExpeditionPanel
- 修复点:
* `IdleOperationsPanel.tsx`:所有 `text-[9px]``text-[10px]`(11 处,符合"移动端字号最小 10px"规范)
* `BeaconPanel.tsx`:所有 `text-[9px]``text-[10px]`7 处);信标链底部统计行 `flex items-center justify-between gap-2``flex flex-wrap items-center justify-between gap-x-2 gap-y-1`(防 3 组数据在 375px 溢出)
* `Codex.tsx`:弹层 padding + 标题字号响应式(见子任务 1);顶部统计区 `flex flex-col sm:flex-row`(移动端纵向堆叠)
* `StatsPanel.tsx`detail 区 `text-[9px]``text-[10px]`2 处)
- 审计通过(无需改):
* `ExpeditionPanel.tsx`:节点路径已用 `overflow-x-auto` 自适应窄屏;事件卡 p-3 padding 合理;按钮组 `flex-1` + abort 收起;能量条文字 `text-[10px]` 已达标;路径节点 `h-9 w-9` 36px 足够小且可横向滚动
* `BeaconPanel.tsx`4 个里程碑节点 `w-12 h-12`48px)× 4 = 192px + flex-1 分布,375px 下可容纳;日/周挑战卡 padding p-3 合理;周挑战+信标链已用 `grid-cols-1 lg:grid-cols-2` 移动单列
* `IdleOperationsPanel.tsx`4 个 section 已用 `grid-cols-1 sm:grid-cols-N` / `grid-cols-2 sm:grid-cols-3` 响应式降级;DispatchCard 槽位按钮 `h-5 w-7` × 3 在单列布局下不溢出
* `Codex.tsx` 列表 `grid-cols-2 gap-2`:每卡片约 165px 宽,aspect-[4/3] + p-2 + text-[11px]/text-[9px](已升 text-[10px])在 375px 下可读
- 严格 4 色全息:emerald / rose / amber / fuchsia,未引入 blue / indigo
- useShallow:所有 store 订阅用 useShallowCodex / StatsPanel 均已用)
- 持久化兼容:persist version 仍为 1,新字段 `readLoreLayers` 靠 migrate 兜底,旧存档加载时自动补 `[]`
- 与子代理 A 文件边界:types.ts/engine.ts/gameStore.ts 三个共享文件,A 的 `triggeredMilestones` / `pendingMilestone` / `dismissMilestone` 字段已落地,与本子代理的 `readLoreLayers` / `markLoreLayerRead` 完全无冲突(不同字段、不同 action、不同 migrate 行)
Stage Summary:
- ✅ 子任务 1:loreLayer 已读标记完整实现
- 类型 + store + UI 三层联动;点击层文本即可标记已读
- 视觉区分:已读 = muted "✓ 已读" + 边框降级为 border-white/10;未读 = 高亮 + 脉冲小圆点 + "新" 字
- 顶部统计新增"已读 A/B"行(A=已读数 / B=已解锁层数)
- 跨周目永久保留(performPrestige 不重置)
- ✅ 子任务 2idleProjectHistory 详情展开完整实现
- "放置工程历史" 行可点击展开/收起
- 展开后显示最近 5 条倒序历史(图标 + 工程名 + 相对时间)
- 空态友好提示,超 5 条底部加"仅展示最近 5 条"说明
- ✅ 子任务 3:移动端 375px 适配审计完成
- 审 5 个组件,修 4 个(Codex / IdleOps / StatsPanel / Beacon),ExpeditionPanel 无需改
- 主要修复:text-[9px] → text-[10px](共 20 处,符合"移动端字号最小 10px"规范)
- 信标链底部统计加 flex-wrap 防 3 组数据溢出
- Codex 弹层 padding + 标题字号响应式
- Codex 顶部统计区移动端纵向堆叠
- ✅ 新建文件:`/home/z/my-project/src/lib/game/format.ts`
- ✅ 修改文件清单(绝对路径):
- `/home/z/my-project/src/lib/game/types.ts`+readLoreLayers 字段)
- `/home/z/my-project/src/lib/game/engine.ts`createInitialState 默认 + performPrestige 保留)
- `/home/z/my-project/src/store/gameStore.ts`GameActions 签名 + action 实现 + migrate 补全)
- `/home/z/my-project/src/components/game/Codex.tsx`(已读标记 + 点击逻辑 + 顶部统计 + 弹层响应式)
- `/home/z/my-project/src/components/game/StatsPanel.tsx`idleHistory 展开 + 相对时间 + 字号升级)
- `/home/z/my-project/src/components/game/IdleOperationsPanel.tsx`(字号 9→10px 升级)
- `/home/z/my-project/src/components/game/BeaconPanel.tsx`(字号 9→10px 升级 + 信标链底部 flex-wrap
- ✅ bun run lint 零错误零警告
- ✅ HTTP 200dev.log 无运行时错误(compile 11ms / render 33ms
- ✅ 与子代理 A 文件边界完全无冲突(不同字段/action/migrate 行)
- ⚠️ 未做 agent-browser 端到端验证(按工单由主控完成)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

+139
View File
@@ -0,0 +1,139 @@
# Task ID: v0.14-reimpl
# Agent: full-stack-developer
# Task: 放置系统 (Idle Operations) — 采矿无人机舰队 + 6放置工程 + 永久产能加成 + idle徽章
## Work Log
### 1. 类型扩展 (`src/lib/game/types.ts`)
- 新增 `IdleProjectDef` 接口(id/name/desc/durationSec/reward/minAscensions/minCrystalsPerSec/icon/color/order
- 新增 `IdleProjectSlot` 接口(projectId/startedAt/finishesAt/remainingSec/completed
- 在 `GameState` 接口 `pendingAttrPoints` 后新增 4 个字段:
- `idleProjectSlots: (IdleProjectSlot | null)[]`
- `idleProjectHistory: { projectId: string; finishedAt: number }[]`
- `idlePermanentBonus: number`
- `idleStats: { projectsCompleted: number; crystalsFromIdle: number }`
### 2. 新建 `src/lib/game/idle.ts` (~290 行)
- 定义 6 个放置工程(按 order 排序):
| id | name | duration | reward | icon | color | unlock |
|----|------|----------|--------|------|-------|--------|
| idle_scan | 深空勘探扫描 | 60s | insights +8 | 🛰️ | emerald | cps≥0.5 |
| idle_refine | 晶体精炼阵列校准 | 180s | permBonus +0.3/s | ⚙️ | rose | cps≥1 |
| idle_archive | 遗迹碎片整理 | 600s | randomFragment + insights +20 | 📜 | amber | asc≥1 OR cps≥5 |
| idle_anchor | 维度锚点部署 | 1200s | energy +2 + contact +5 | ⚓ | fuchsia | asc≥1 |
| idle_drones | 无人机群扩编 | 1800s | permBonus +2/s + crystals +500 | 🛸 | emerald | cps≥10 |
| idle_resonance | 跨维度谐振标定 | 3600s | permBonus +8/s + contact +15 + insights +100 | 🌌 | fuchsia | asc≥2 |
- 导出:`IDLE_PROJECTS`, `IDLE_SLOT_COUNT=3`, `getIdleProject`, `getUnlockedIdleProjects`, `getLockedIdleProjects`, `isIdleProjectUnlocked` (OR 逻辑:满足任一已设置条件即可解锁), `formatRemaining` (12s/3m 45s/1h 12m), `formatDuration`, `formatReward`, `deriveMinerFleet` (派生 min_1..min_5 采矿无人机,无任何采矿技术时返回休眠 min_1)
- 导出颜色映射 `IDLE_COLOR_CLASSES` (text/border/bg/bgSoft/glow/ring/dot) + `COLOR_HEX` (用于 inline style,绕过 Tailwind 动态类限制)
### 3. 引擎集成 (`src/lib/game/engine.ts`)
- `recomputeStats()` 末尾 `crystalsPerSec += state.idlePermanentBonus ?? 0` (放置永久加成叠加到产能)
- `performPrestige()` 在返回对象中:
- 清空 `idleProjectSlots: [null, null, null]` (飞升中断当前周目放置工程)
- 保留 `idleProjectHistory`, `idlePermanentBonus`, `idleStats` (跨周目永久)
- `recomputeStats` 调用传入 `idlePermanentBonus` 以确保飞升后立即应用永久加成
- `createInitialState()` 新增 4 字段默认值
### 4. Store actions (`src/store/gameStore.ts`)
- 新增 4 个 action
- `startIdleProject(slotIndex, projectId)`: 校验槽位空 + 项目已解锁 + 未在他处运行;写入 `{ projectId, startedAt, finishesAt, remainingSec, completed:false }`
- `cancelIdleProject(slotIndex)`: 置槽位为 null
- `claimIdleProject(slotIndex)`: 校验已完成 → 应用奖励(crystals 限 crystalCapenergy 限 energyMaxcontact 限 100permBonus 累加到 idlePermanentBonus + 重算 statsrandomFragment 从未解锁碎片中随机一个)→ 追加 history (slice -50) → idleStats.projectsCompleted++ → Toast 提示
- `tickIdleProjects(now)`: 遍历非空非完成槽位,更新 remainingSec,归零时标记 completed
- **persist migrate 函数**persist 配置增加 `version: 1` + `migrate` 函数,自动补全 idleProjectSlots/idleProjectHistory/idlePermanentBonus/idleStats 4 字段,旧存档加载不崩溃
- 全部 14 处 syncStats 调用更新为传入 `idlePermanentBonus: s.idlePermanentBonus ?? 0`,确保 recomputeStats 计算时纳入永久加成
- `init()` 中也补全 4 个 idle 字段(defense in depth
### 5. 主循环 (`src/hooks/useGameLoop.ts`)
- 新增 `tickIdleProjects` 选择器
- setInterval 回调中 `autoDecodeTick()` 后调用 `tickIdleProjects(now)`
- visibilitychange 回调中也调用 `tickIdleProjects(now)`
### 6. 新建 `src/components/game/IdleOperationsPanel.tsx` (~490 行)
- 主「放置」标签内容,4 个 section 在 `max-h-[520px] overflow-y-auto` 容器中:
1. **放置收益概览**3 stat tiles (放置产能 / 永久加成 / 完成工程) + 离线效率 progress bar + 累计放置晶体统计
2. **采矿无人机舰队**grid 展示 deriveMinerFleet(state),每张卡:emoji + name + Lv + output/s + 状态点(active=emerald ping 脉冲,dormant=灰)
3. **放置工程槽位**:3 张槽位卡(空槽=虚线占位,运行中=大字号倒计时+自定义进度条+取消按钮,已完成=奖励预览+领取按钮带 glow 辉光)
4. **可派遣工程**:2 列 grid 展示已解锁工程(icon+name+duration+desc+reward+3 个数字派遣按钮 1/2/3),下方列出未解锁工程及解锁条件
- 使用 `useShallow` 订阅多个 store 字段
- 本地 `now` state 每 1s 刷新倒计时
- 严格 4 色全息(emerald/rose/amber/fuchsia),无蓝/靛
- 自定义滚动条样式 (fuchsia 主题)
### 7. 新建 `src/components/game/IdleStatusBadge.tsx` (~100 行)
- 紧凑徽章:脉冲点 (emerald 若 cps>0,否则灰) + "放置中 +X/s" (或 "休眠中")
- Tooltip 悬停展示分解:基础产能 / 永久加成 / 运行中工程 / 待领取工程数
- `h-8 px-2.5 text-[11px]`,点击切换到放置标签
- `data-tut="idle-status-badge"` 锚点
### 8. 新建 `src/components/game/IdleProjectBar.tsx` (~90 行)
- 晶体球下方的细长进度条
- 显示最多 3 个运行/已完成工程为 mini pill:`[icon] name 12s ▓▓▓░░`
- 完成时显示 "✓ 待领取" + glow 辉光
- 无工程时返回 null
- 本地 `now` state 每 1s 刷新倒计时
- 进度条颜色用 inline style 控制(COLOR_HEX 映射)
### 9. 主页面集成 (`src/app/page.tsx`)
- 引入 3 个新组件 + `Clock` 图标 + `getUnlockedIdleProjects`
- 新增 `idleProjectSlots` / `createdAt` store 订阅
- 新增 `activeTab` / `tabInited` statecontrolled Tabs`<Tabs value={activeTab} onValueChange={setActiveTab}>`
- 挂载后 useEffect 一次性设置默认 tabhasActiveExpedition → "expedition"hasPendingPerk → "constellation",否则 → "idle"
- 版本号 v0.8 → v0.14
- Header 在 StarTideIndicator 后加 IdleStatusBadge
- 左侧 CrystalOrb 后加 IdleProjectBar
- TabsList grid-cols-8 → grid-cols-9,新增 `value="idle"` 的 TabsTrigger 作为第一个 tabClock 图标,emerald 主题,待领取时显示数量红点)
- 新增 TabsContent value="idle" 渲染 IdleOperationsPanel
- 新增 idle 相关 goal 提示(高优先级):
- 待领取 > 0 → "✦ 放置工程已完成 X 项,请前往「放置」标签领取奖励"
- 全空 + 有解锁 + 时长 > 60s → "「放置」标签可派遣工程项目,离线自动产出"
- StatsPanel 新增 3 行:放置永久加成 / 完成放置工程 / 放置产出晶体
### 10. 教程更新 (`src/lib/game/tutorial.ts`)
- TUTORIAL_STEPS 在 decode 与 tech 之间插入新步骤:
- id: "idle", target: "tab-idle", placement: "top"
- 标题 "③ 放置工程 · 离线产出"
- 介绍放置标签的工程派遣 + 顶部徽章 + 晶体球下方进度条
- 原 tech/expedition/prestige 步骤编号顺延为 ④⑤⑥
## QA 验证
### Lint
- `bun run lint` → 零错误零警告 ✅
### HTTP
- `curl http://localhost:3000/` → 200 OK ✅
### Dev log
- 全程无 runtime error,所有请求 200 OK,编译 < 250ms ✅
### agent-browser 烟雾测试
1. ✅ 版本标签 "v0.14" 可见
2. ✅ 默认 tab 是 "放置"data-state="active" 在第一个 tab
3. ✅ 头部 idle 徽章可见("放置中 +0.4/s" 或 "休眠中"
4. ✅ IdleOperationsPanel 4 个 section 全部可见(放置收益概览 / 采矿无人机舰队 / 放置工程槽位 / 可派遣工程 / 未解锁工程)
5. ✅ 采矿无人机舰队在无采矿技术时显示休眠 min_1(emoji ⛏️ + 灰色状态点)
6. ✅ 设置 insights=50 → buyTech('min_1') → crystalsPerSec 0.4→1.0 → 解锁 idle_scan + idle_refine
7. ✅ 点击 idle_scan 派遣按钮 → 槽位 0 写入 { projectId: "idle_scan", finishesAt: now+60000 } → 倒计时正确递减
8. ✅ 60s 后自动标记 completed=true → 槽位卡显示 "✓ 完成" + 领取按钮
9. ✅ 点击领取 → Toast "✦ 工程奖励已领取 · 深空勘探扫描 · +8 洞见" → insights 8→16 → history 追加 → idleStats.projectsCompleted 0→1
10. ✅ 派遣 idle_refine (180s) → 强制完成 → 领取 → crystalsPerSec 1.0→1.3 → idlePermanentBonus 0→0.3 ✅ 永久产能加成正确应用
11. ✅ IdleProjectBar 在晶体球下方显示:`🛰️ 深空勘探扫描 55s ▓▓▓░░`
12. ✅ Footer goal 文字根据状态动态切换为放置相关提示
13. ✅ Footer 产能显示 "产能 1.3/s" (含 idle 永久加成)
### Migration 测试
- 旧存档(无 idle 字段)通过 migrate 函数自动补全为默认值,加载不崩溃 ✅
## Stage Summary
- ✅ 类型层:新增 IdleProjectDef + IdleProjectSlot + 4 GameState 字段
- ✅ 逻辑层:新建 idle.ts (~290 行),6 工程定义 + 派生函数 + 颜色映射
- ✅ 引擎层:recomputeStats / performPrestige / createInitialState 全部接入 idle 永久加成
- ✅ Store 层:4 新 action + persist migrate (version 1) + 14 处 syncStats 调用全部传 idlePermanentBonus
- ✅ 主循环:tickIdleProjects 接入 setInterval + visibilitychange
- ✅ UI 层:3 新组件 (IdleOperationsPanel ~490 行 / IdleStatusBadge ~100 行 / IdleProjectBar ~90 行)
- ✅ 主页面:默认放置 tab + 头部徽章 + 晶体球下方进度条 + 版本 v0.14 + 9 标签页
- ✅ 教程:新增 idle 步骤 (③ 放置工程)
- ✅ 严格 4 色全息 (emerald/rose/amber/fuchsia),零蓝/靛
- ✅ lint 零错误 + HTTP 200 + agent-browser 全流程烟雾测试通过
- ✅ 5 秒内可见三要素:头部徽章 + 默认放置 tab + 晶体球下方进度条(派遣后)
Regular → Executable
-40
View File
@@ -63,8 +63,6 @@
"react-syntax-highlighter": "^15.6.1",
"recharts": "^2.15.4",
"sharp": "^0.34.3",
"socket.io": "^4.8.3",
"socket.io-client": "^4.8.3",
"sonner": "^2.0.6",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
@@ -602,8 +600,6 @@
"@schummar/icu-type-parser": ["@schummar/icu-type-parser@1.21.5", "https://registry.npmjs.com/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz", {}, "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw=="],
"@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="],
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "https://registry.npmjs.com/@standard-schema/spec/-/spec-1.1.0.tgz", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "https://registry.npmjs.com/@standard-schema/utils/-/utils-0.3.0.tgz", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
@@ -678,8 +674,6 @@
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "https://registry.npmjs.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@types/cors": ["@types/cors@2.8.19", "", { "dependencies": { "@types/node": "*" } }, "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg=="],
"@types/d3-array": ["@types/d3-array@3.2.2", "https://registry.npmjs.com/@types/d3-array/-/d3-array-3.2.2.tgz", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
"@types/d3-color": ["@types/d3-color@3.1.3", "https://registry.npmjs.com/@types/d3-color/-/d3-color-3.1.3.tgz", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
@@ -722,8 +716,6 @@
"@types/unist": ["@types/unist@3.0.3", "https://registry.npmjs.com/@types/unist/-/unist-3.0.3.tgz", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.53.0", "https://registry.npmjs.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.53.0", "@typescript-eslint/type-utils": "8.53.0", "@typescript-eslint/utils": "8.53.0", "@typescript-eslint/visitor-keys": "8.53.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.53.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.53.0", "https://registry.npmjs.com/@typescript-eslint/parser/-/parser-8.53.0.tgz", { "dependencies": { "@typescript-eslint/scope-manager": "8.53.0", "@typescript-eslint/types": "8.53.0", "@typescript-eslint/typescript-estree": "8.53.0", "@typescript-eslint/visitor-keys": "8.53.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg=="],
@@ -784,8 +776,6 @@
"@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "https://registry.npmjs.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="],
"accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="],
"acorn": ["acorn@8.15.0", "https://registry.npmjs.com/acorn/-/acorn-8.15.0.tgz", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "https://registry.npmjs.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
@@ -834,8 +824,6 @@
"base64-js": ["base64-js@1.5.1", "https://registry.npmjs.com/base64-js/-/base64-js-1.5.1.tgz", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.15", "https://registry.npmjs.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.15.tgz", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg=="],
"brace-expansion": ["brace-expansion@1.1.12", "https://registry.npmjs.com/brace-expansion/-/brace-expansion-1.1.12.tgz", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
@@ -910,8 +898,6 @@
"cookie": ["cookie@0.7.2", "https://registry.npmjs.com/cookie/-/cookie-0.7.2.tgz", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
"cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
"crelt": ["crelt@1.0.6", "https://registry.npmjs.com/crelt/-/crelt-1.0.6.tgz", {}, "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="],
"cross-spawn": ["cross-spawn@7.0.6", "https://registry.npmjs.com/cross-spawn/-/cross-spawn-7.0.6.tgz", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
@@ -1008,12 +994,6 @@
"empathic": ["empathic@2.0.0", "https://registry.npmjs.com/empathic/-/empathic-2.0.0.tgz", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="],
"engine.io": ["engine.io@6.6.9", "", { "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "@types/ws": "^8.5.12", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.21.0" } }, "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg=="],
"engine.io-client": ["engine.io-client@6.6.6", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.21.0", "xmlhttprequest-ssl": "~2.1.1" } }, "sha512-iY6QdftLQ9pyiPoX082bpf/u1UewnOaJrtJIF9T0++QB34lZrj0uP+Q/bj8AlUsAxqhnkTV2BS8SBZSxOmoV5Q=="],
"engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="],
"enhanced-resolve": ["enhanced-resolve@5.18.4", "https://registry.npmjs.com/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="],
"es-abstract": ["es-abstract@1.24.1", "https://registry.npmjs.com/es-abstract/-/es-abstract-1.24.1.tgz", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw=="],
@@ -1472,8 +1452,6 @@
"mime-db": ["mime-db@1.54.0", "https://registry.npmjs.com/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"minimatch": ["minimatch@3.1.2", "https://registry.npmjs.com/minimatch/-/minimatch-3.1.2.tgz", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"minimist": ["minimist@1.2.8", "https://registry.npmjs.com/minimist/-/minimist-1.2.8.tgz", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
@@ -1690,14 +1668,6 @@
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "https://registry.npmjs.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
"socket.io": ["socket.io@4.8.3", "", { "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.4.1", "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" } }, "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A=="],
"socket.io-adapter": ["socket.io-adapter@2.5.8", "", { "dependencies": { "debug": "~4.4.1", "ws": "~8.21.0" } }, "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw=="],
"socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="],
"socket.io-parser": ["socket.io-parser@4.2.6", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg=="],
"sonner": ["sonner@2.0.7", "https://registry.npmjs.com/sonner/-/sonner-2.0.7.tgz", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
"source-map-js": ["source-map-js@1.2.1", "https://registry.npmjs.com/source-map-js/-/source-map-js-1.2.1.tgz", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
@@ -1826,8 +1796,6 @@
"uvu": ["uvu@0.5.6", "https://registry.npmjs.com/uvu/-/uvu-0.5.6.tgz", { "dependencies": { "dequal": "^2.0.0", "diff": "^5.0.0", "kleur": "^4.0.3", "sade": "^1.7.3" }, "bin": { "uvu": "bin.js" } }, "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA=="],
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
"vaul": ["vaul@1.1.2", "https://registry.npmjs.com/vaul/-/vaul-1.1.2.tgz", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="],
"vfile": ["vfile@6.0.3", "https://registry.npmjs.com/vfile/-/vfile-6.0.3.tgz", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
@@ -1850,10 +1818,6 @@
"word-wrap": ["word-wrap@1.2.5", "https://registry.npmjs.com/word-wrap/-/word-wrap-1.2.5.tgz", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
"ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="],
"xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.1.2", "", {}, "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="],
"xtend": ["xtend@4.0.2", "https://registry.npmjs.com/xtend/-/xtend-4.0.2.tgz", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
"yallist": ["yallist@4.0.0", "https://registry.npmjs.com/yallist/-/yallist-4.0.0.tgz", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
@@ -1936,8 +1900,6 @@
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "https://registry.npmjs.com/minimatch/-/minimatch-9.0.5.tgz", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
"downshift/react-is": ["react-is@17.0.2", "https://registry.npmjs.com/react-is/-/react-is-17.0.2.tgz", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
"eslint-import-resolver-node/debug": ["debug@3.2.7", "https://registry.npmjs.com/debug/-/debug-3.2.7.tgz", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
@@ -1968,8 +1930,6 @@
"micromatch/picomatch": ["picomatch@2.3.1", "https://registry.npmjs.com/picomatch/-/picomatch-2.3.1.tgz", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"next/postcss": ["postcss@8.4.31", "https://registry.npmjs.com/postcss/-/postcss-8.4.31.tgz", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
"next-auth/uuid": ["uuid@8.3.2", "https://registry.npmjs.com/uuid/-/uuid-8.3.2.tgz", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
+309
View File
@@ -0,0 +1,309 @@
# 回响星核 v0.14 — 放置系统(Idle Operations)设计文档
> 版本:v0.14 · 日期:2026-01-25
> 核心目标:让玩家打开游戏 **5 秒内** 就能看出这是个 idle game
---
## 1. 设计动机
### 1.1 用户反馈
> "你的这个我没有看到任何可放置的功能" —— 玩家反馈
虽然 v0.8 已有 `crystalsPerSec` 在后台自动累积,但 **没有任何 UI 元素明示这一事实**
- 没有「放置中」徽章
- 没有可视化自动采矿机
- 没有定时工程项目
- 离线收益弹窗只在重新加载页面时触发,玩家日常游玩看不到
放置游戏的灵魂是「关掉也在进步」。如果玩家看不到这一点,就等于没有放置玩法。
### 1.2 设计目标
1. **可见性**5 秒内让玩家意识到 idle 属性
2. **决策性**:放置不只是数字增长,要有玩家选择
3. **节奏感**:3 层 idle 节奏(被动产能 / 放置工程 / 离线收益)协同
4. **健康性**:避免 24h 挂机的极端沉迷
---
## 2. 三层 Idle 节奏
### 节奏 1:被动产能(Passive Generation
- **载体**:采矿无人机舰队(Miner Fleet)
- **来源**:每解锁一个采矿分支技术节点 → 加入一架无人机
- **行为**24h 持续产出晶体,无需任何操作
- **限制**:受 `crystalCap` 限制,仓库满后停止
- **离线**:按 `offlineEff`(默认 50%)持续累积,上限 8h
#### 采矿分支技术 → 无人机映射
| 技术节点 | 无人机名 | 输出/s | 解锁成本(洞见) |
|---------|---------|--------|-----------------|
| `min_1` | ⛏️ 谐振钻头 | +0.6 | 5 |
| `min_2` | 🌋 深层矿脉 | +1.6 | 24 |
| `min_3` | 🤖 自治机群 | +5 | 120 |
| `min_4` | 💠 量子采掘矩阵 | +12 | 400 |
| `min_5` | ☀️ 戴森星核 | +30 | 1200 |
无采矿技术时显示「谐振钻头(休眠中)」占位卡片,引导玩家解锁采矿分支。
---
### 节奏 2:放置工程(Idle Projects
#### 2.1 工程列表
| ID | 名称 | 时长 | 奖励 | 解锁条件 | 图标 | 色 |
|----|------|------|------|---------|------|-----|
| `idle_scan` | 深空勘探扫描 | 60s | ✦ +8 洞见 | 产能 ≥ 0.5/s | 🛰️ | emerald |
| `idle_refine` | 晶体精炼阵列校准 | 180s | ⇪ +0.3/s 永久 | 产能 ≥ 1/s | ⚙️ | rose |
| `idle_archive` | 遗迹碎片整理 | 600s | ✦ +20 洞见 + 📜 随机碎片 | 飞升 ≥ 1 OR 产能 ≥ 5/s | 📜 | amber |
| `idle_anchor` | 维度锚点部署 | 1200s | ⚡ +2 能量 + ☄ +5 接触进度 | 飞升 ≥ 1 | ⚓ | fuchsia |
| `idle_drones` | 无人机群扩编 | 1800s | 💎 +500 晶体 + ⇪ +2/s 永久 | 产能 ≥ 10/s | 🛸 | emerald |
| `idle_resonance` | 跨维度谐振标定 | 3600s | ✦ +100 洞见 + ☄ +15 接触 + ⇪ +8/s 永久 | 飞升 ≥ 2 | 🌌 | fuchsia |
#### 2.2 槽位机制
- **3 个并行槽位**:可同时运行 3 个工程
- **不重复**:同一工程不能在多个槽位同时运行
- **完成需手动领取**:避免"打开就有奖励"的条件反射
- **取消不退时间**:误取消的代价
- **离线推进**:关闭浏览器后工程继续倒计时
#### 2.3 奖励类型说明
| 奖励 | 含义 | 设计意图 |
|------|------|---------|
| 晶体 | 立即加到 `crystals` | 短期反馈 |
| 洞见 | 立即加到 `insights` | 用于解锁技术 |
| 能量 | 加到 `energy`(受 `energyMax` 上限) | 探险资源 |
| 接触进度 | 加到 `contact`0-100 | 推进飞升 |
| **永久产能加成** | 加到 `idlePermanentBonus`,影响 `recomputeStats` | 长期投资 |
| 随机碎片 | 从 `FRAGMENTS` 中随机解锁一个未拥有 | 叙事推进 |
---
### 节奏 3:离线收益(Offline Gains
#### 3.1 公式
```
gain = crystalsPerSec × elapsed × offlineEff
elapsed = min(realElapsed, 8h)
```
#### 3.2 解锁路径
- 初始 `offlineEff = 0.5`50% 离线效率)
- 通过技术树 `offlineEff` 类效果提升
- 通过星图天赋 `offlineEffBonus` 提升
- 上限 100%
#### 3.3 8h 上限理由
- 参考 GDC 2016 Anthony Pecorella "Quest for Progress"Egg Inc 2h 硬 cap 导致玩家流失
- 但完全无 cap 会导致 24h 挂机成为最优策略,破坏短会话体验
- 8h 折中:覆盖一个工作日/一夜,但不鼓励全天挂机
#### 3.4 离线报告弹窗
重新加载页面时,若 `elapsed > 60s`,弹出 `OfflineReportDialog`
- 「你离开了 X 小时 Y 分」
- 「星核为你产出 Z 颗晶体」
- 「产能 /s · 离线效率 N%」
- 「是否触达 8h 上限」标志
---
## 3. UI 设计
### 3.1 始终可见的 Idle 徽章(Header
位置:顶部 Header,紧邻「巡航」按钮左侧
状态:
- 产能 > 0`● 放置中 +X.X/s`(绿点脉动)
- 产能 = 0`○ 休眠中`(灰点静止)
悬停 Tooltip 显示明细:
```
基础产能 8.2/s
永久加成 +1.5/s
离线效率 75%
完成工程 12 次
```
点击徽章 → 切换到「放置」标签。
### 3.2 默认标签页 = 放置
首次打开游戏,默认 tab 是「放置」(v0.13 前是「探险」或「技术」)。
返回玩家若有进行中探险或待选天赋,自动切回原默认。
### 3.3 放置标签页四段式布局
```
┌─────────────────────────────────────────┐
│ Section 1: 放置收益概览 │
│ [放置产能] [永久加成] [完成工程] │
│ [━━━━━━━ 离线效率 50% · 上限 8h ━━━━━━] │
├─────────────────────────────────────────┤
│ Section 2: 采矿无人机舰队 │
│ [⛏️ 钻头] [🌋 矿脉] [🤖 机群] ... │
├─────────────────────────────────────────┤
│ Section 3: 放置工程槽位 │
│ [槽位1: 运行中 47s ▓▓▓░] [槽位2: 空] [槽位3: 空] │
├─────────────────────────────────────────┤
│ Section 4: 可派遣工程 │
│ [🛰️ 深空勘探扫描 1m +8] [⚙️ 精炼校准 3m +0.3/s] │
│ [📜 碎片整理 10m +20] │
│ │
│ 未解锁工程(3): │
│ ⚓ 维度锚点部署 · 需 飞升≥1 │
│ 🛸 无人机群扩编 · 需 产能≥10/s │
│ 🌌 跨维度谐振标定 · 需 飞升≥2 │
└─────────────────────────────────────────┘
```
### 3.4 IdleProjectBar(晶体球下方)
位置:左侧晶体球区,`CrystalYieldPanel` 下方
显示:当前运行的工程迷你 pill
```
🛰️ 深空勘探扫描 47s ▓▓▓░░░░░
⚙️ 晶体精炼校准 2m 13s ▓▓░░░░░░
```
无运行工程时返回 `null`(不占位)。
---
## 4. 技术实现
### 4.1 数据结构
```typescript
// types.ts
interface IdleProjectDef {
id: string;
name: string;
desc: string;
durationSec: number;
reward: { crystals?; insights?; energy?; contact?; crystalsPerSecPermanent?; randomFragment?; };
minAscensions?: number;
minCrystalsPerSec?: number;
icon: string;
color: "emerald" | "rose" | "amber" | "fuchsia";
order: number;
}
interface IdleProjectSlot {
projectId: string;
startedAt: number;
finishesAt: number;
remainingSec: number;
completed: boolean;
}
// GameState 新增 4 字段
idleProjectSlots: (IdleProjectSlot | null)[]; // 3 槽
idleProjectHistory: { projectId: string; finishedAt: number }[]; // 最近 50 条
idlePermanentBonus: number;
idleStats: { projectsCompleted: number; crystalsFromIdle: number };
```
### 4.2 Store actions
- `startIdleProject(slotIndex, projectId)` — 校验 + 创建槽位
- `cancelIdleProject(slotIndex)` — 置空槽位
- `claimIdleProject(slotIndex)` — 应用奖励 + toast + 置空槽位
- `tickIdleProjects(now)` — 推进剩余时间,标记完成
### 4.3 引擎集成
`recomputeStats()` 末尾添加:
```typescript
crystalsPerSec += state.idlePermanentBonus ?? 0;
```
这让永久产能加成真正生效。
### 4.4 飞升处理
`performPrestige()` 重置 `idleProjectSlots = [null, null, null]`(不跨周目继承进行中工程),但保留 `idlePermanentBonus` / `idleProjectHistory` / `idleStats`(跨周目永久)。
### 4.5 存档迁移
persist 添加 `version: 1` + `migrate` 函数,为旧存档补全 4 个新字段:
```typescript
idleProjectSlots: (s.idleProjectSlots as unknown[]) ?? [null, null, null],
idleProjectHistory: (s.idleProjectHistory as unknown[]) ?? [],
idlePermanentBonus: (s.idlePermanentBonus as number) ?? 0,
idleStats: (s.idleStats as unknown) ?? { projectsCompleted: 0, crystalsFromIdle: 0 },
```
旧存档零崩溃风险。
### 4.6 主循环集成
`useGameLoop` 每 250ms tick
1. `tick(now)` — 产能 + 自动产晶体
2. `autoDecodeTick()` — 自动解码
3. `tickTide(now)` — 星潮事件
4. **`tickIdleProjects(now)` — v0.14 放置工程进度**(新增)
5. `checkAchievements()` — 每秒一次
页面可见性切回时也调用 `tickIdleProjects(now)`
---
## 5. 平衡考虑
### 5.1 永久产能加成可能过强
- `idle_resonance` +8/s 永久,多次完成可能让玩家飞快积累
- **v0.15 待办**:加飞升次数 softcap,例如 `effectiveBonus = idlePermanentBonus × sqrt(ascensions + 1) / (ascensions + 1)`
### 5.2 工程时长曲线
- 60s / 180s / 600s / 1200s / 1800s / 3600s
- 短工程奖励低但灵活(适合短会话)
- 长工程奖励高但需等待(适合过夜挂机)
- 玩家自主选择节奏
### 5.3 解锁条件
- 0 飞升 + 0.5/s:新手 5 分钟内可解锁第一个
- 1 飞升:玩家完成首次飞升后解锁中段
- 2 飞升 + 10/s:长线目标
---
## 6. 验证记录
### 6.1 Lint
- ✅ 零错误零警告
### 6.2 Dev 服务器
- ✅ HTTP 200
- ✅ 无运行时错误
### 6.3 Agent Browser 端到端测试
1. ✅ 默认 tab 是「放置」
2. ✅ Header 显示「放置中 +0.4/s」徽章
3. ✅ 4 段面板完整渲染
4. ✅ 买 min_1+min_2 后产能 2.6/s,解锁 idle_scan + idle_refine
5. ✅ 点击「派遣至槽位 1」→ 槽位显示运行中 60s + 进度条 + 取消按钮
6. ✅ IdleProjectBar 同步显示迷你 pill
7. ✅ 快进完成后标记 completed=true
8. ✅ 领取后 insights +8、projectsCompleted 0→1、槽位清空
### 6.4 Sticky Footer 验证
- ✅ Header `position: sticky; top: 0`
- ✅ Footer `position: sticky; bottom: 0; margin-top: auto`
- ✅ 内容超出视口时 footer 被自然推下(无浮动空隙)
---
## 7. 未解决问题 / 后续
- 🟡 `crystalsFromIdle` / `idleProjectHistory` 已在 store 累加但 UI 未展示——v0.15 可在统计 tab 补
- 🟡 永久产能加成可能需要飞升次数 softcap
- 🟡 缺「批量领取全部」按钮(玩家有 3 个槽位都完成时方便)
- 🟡 缺工程完成 toast 通知(目前只能在面板内看到「待领取」标志)
- 🟢 v0.15 可加 Dark Souls 式 loreFragments 多层文本,让"遗迹碎片整理"工程的随机碎片奖励更有叙事感
---
## 8. 设计哲学总结
> "Incremental games are very raw. They're about relating to a process and becoming obsessed with its growth, like watching something you planted in the ground, through a time-lapse camera, grow into a tree." —— Clark (via Frank Lantz, New Yorker 2019)
回响星核 v0.14 的放置系统不只是把数字挂机增长,而是让玩家**看到**这个过程:
- 采矿无人机像植物在土里生长
- 放置工程像种子在发芽
- 离线收益像收获时节
玩家不再只是「数字变大」,而是「亲手布置了一个会自动运转的考古基地,然后离开,让它在自己不在的时候继续工作」。
这是 idle game 的本质:**让玩家信任系统会在他不在时为他工作**。
+214
View File
@@ -0,0 +1,214 @@
# 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 洞见 · ...`
UISection 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-a5 文件):**
- `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-b3 文件):**
- `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 200dev.log 无运行时错误
- ✅ agent-browser 端到端 smoke test
- softcappermBonus=50 → 有效 40UI 显示"衰减中" ✓
- 批量领取:permBonus 0→0.3, projectsCompleted 1→2 ✓
- 完成 toasttickIdleProjects 触发 ✓
- 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 弹层可读性实测
+231
View File
@@ -0,0 +1,231 @@
# v0.16 — 解码阈值叙事事件 + loreLayer 已读 + idleHistory 详情 + 移动端适配
> 回响星核 / Echo Nexus · v0.16 设计文档
> 对应 worklog `Task ID: 2-a` + `2-b` + `v0.16-release`
---
## 一、动机
v0.15 上线了 loreLayers 多层碎片文本,但存在三个未完善点:
1. **解锁瞬间缺乏仪式感** — 碎片静默出现在图谱,没有"叙事涌现"的高光时刻
2. **loreLayer 没有已读标记** — 玩家无法区分"新解锁未读"和"已读",缺乏进度感
3. **idleProjectHistory 只显示计数** — 无法查看具体完成了哪些工程、何时完成
4. **移动端 375px 未实测** — v0.15 的 Codex 分层弹层在小屏可读性未知
v0.16 用两个并行子代理一次性解决:
- **2-a**:5 个解码阈值叙事里程碑 + 全屏"碎片释放"叠层
- **2-b**loreLayer 已读标记 + idleHistory 详情展开 + 移动端适配审计
---
## 二、解码阈值叙事里程碑(2-a
### 设计哲学
回响星核的核心卖点是**"解码驱动叙事涌现"**。v0.15 的 loreLayers 让每个碎片有 3 层文本,但解锁是静默的。v0.16 在 `totalDecoded` 达到 5/12/25/40/60 时触发**全屏叙事叠层**——不是解锁新碎片,而是对已解锁碎片的**回顾性咏叹**,类似游戏中的"过场回忆"。
5 个阈值与 FRAGMENTS 的 threshold1/3/6/10/15/22/32/45**错开**,是额外的叙事节奏点。
### 5 个里程碑
| threshold | id | title | color | 主题 |
|---|---|---|---|---|
| 5 | ms_5 | 回响 · 初鸣 | emerald | 身份觉醒(你是回响) |
| 12 | ms_12 | 代价 · 锚痕渐浅 | rose | 代价感知(解码在消耗锚痕) |
| 25 | ms_25 | 信任 · 钩上的光 | amber | 信任的重量("信任"实为引诱) |
| 40 | ms_40 | 身后 · 整齐的虚空 | fuchsia | 身后的东西(追逐者逼近) |
| 60 | ms_60 | 回归 · 借形之物 | emerald | 回归的预兆(接触满溢借形回归) |
每段 body 文本 150-250 字,与 v0.15 loreLayers 的 5 条暗线呼应:
1. 追逐者(以太族被虚空追逐者逼迫飞升)
2. 回响同源(玩家 AI 频段与以太族议会档案同源)
3. 信任即引诱("信任后来者"实为"引诱替他们完成未竟之事")
4. 飞升单向门(每次飞升都在消耗什么)
5. 回归非他们(接触满 80 时回归的是"借形之物")
### 技术实现
**新建 `src/lib/game/narrativeMilestones.ts`**
- `NarrativeMilestone` 接口(threshold/id/title/subtitle/body/color
- `NARRATIVE_MILESTONES` 数组(5 个里程碑)
- `findMilestoneForTotal(total, triggered)` 纯函数(返回未触发的里程碑)
**GameState 扩展**
- `triggeredMilestones: string[]` — 已触发的 milestone id 集合(跨周目永久)
- `pendingMilestone: NarrativeMilestone | null` — 待展示的里程碑(叠层读取)
**Store 集成**
- 两个解码完成点(`clickNode` line 596 + `autoDecodeTick` line 711)检测 `findMilestoneForTotal(newTotal, triggered)`
- 命中则加入 `triggeredMilestones` + 设置 `pendingMilestone`
- `dismissMilestone()` action 清空 `pendingMilestone`
- persist migrate 补全两字段(version 仍为 1)
- `performPrestige` 保留 `triggeredMilestones`(不重复看过场)+ 清空 `pendingMilestone`
### 全屏叠层组件
**新建 `src/components/game/NarrativeMilestoneOverlay.tsx`**
- `fixed inset-0 z-50` + `bg-black/80 backdrop-blur-sm`(高于 StarTideOverlay 的 z-0
- **粒子边框**:全屏 4 色主题色 inset box-shadow120px + 240px 双层)+ `narrative-breathe` 3.5s 呼吸循环
- **中央卡片**max-w-2xl4 色主题渐变背景 + 主题色 border + 60px glow
- **排版层级**
- 副标题 `text-[10px] sm:text-xs font-mono tracking-[0.3em] uppercase`
- 大标题 `text-3xl sm:text-4xl md:text-5xl font-serif font-bold` + textShadow glow
- 装饰分隔线 `linear-gradient`
- 主体文本 `text-sm sm:text-base md:text-lg leading-relaxed whitespace-pre-line`
- **入场动画**`narrative-fade-in` 300msopacity 0→1+ `narrative-scale-in` 300ms cubic-bezierscale 1.05→1
- **逐字浮现**30ms/字 setTimeout 推进 + inline-block 光标 `narrative-cursor` 1s steps(2) 闪烁
- **交互**
- 未完全显示时:点击 → skip 到全文(底部提示"点击跳过逐字显示")
- 完全显示后:点击/Esc → `dismissMilestone()`(底部提示"点击任意处或按 Esc 继续")
- **移动端 375px**:卡片 px-4 py-6 / 标题 text-3xl / 正文 text-sm / 光标 h-4
- **结构巧思**:外层订阅 + 内层 `key={milestone.id}` 重挂,state lazy init 为 0,规避 React 19 `react-hooks/set-state-in-effect` 规则
---
## 三、loreLayer 已读标记(2-b
### 类型扩展
`GameState.readLoreLayers: string[]` — 格式 `["f1_1_L1", "f1_1_L2", ...]`
### Store
- `markLoreLayerRead(fragmentId, layer)` action:构造 key `${fragmentId}_L${layer}`,已存在则 no-op
- persist migrate 补全 `readLoreLayers: []`
- `performPrestige` 保留(跨周目永久,已读不重置)
### Codex 分层渲染增强
- **已读层**:标题旁 muted "✓ 已读" + 边框降级为 `border-white/10`
- **未读但已解锁层**:保持 v0.15 高亮(amber/fuchsia 边框 + glow+ 标题旁 `animate-pulse` 脉冲小圆点 + "新" 字 + "▸ 点击文本标记已读" 引导
- **触发方式**:点击层文本区域(`<button>` 元素)即调用 `markLoreLayerRead`,无需额外按钮
- **顶部统计**:从单行扩展为两行(移动端 stack / 桌面并排):`深层叙事 X/Y 已解锁` + `已读 A/B`
- **列表卡片小圆点**:未读 pulse + glow,已读静态降亮
---
## 四、idleProjectHistory 详情展开(2-b
### StatsPanel 增强
- "放置工程历史" 行改为 `col-span-2` 可展开按钮:左侧 label + "(最近 N 条可展开)",右侧 "N 条" + ChevronDown/ChevronUp
- 展开后渲染倒序最近 5 条:每行 = 工程 icon + 工程名(truncate+ 相对时间
- 最近一条用 `bg-fuchsia-500/5` 高亮
- 超 5 条时底部加"仅展示最近 5 条 · 共 N 条历史"
- 空态友好文案
### 新建 `src/lib/game/format.ts`
`formatRelativeTime(ts: number): string`
- `< 60s` → "刚刚"
- `< 60m` → "X 分钟前"
- `< 24h` → "X 小时前"
- `< 7d` → "X 天前"
- 否则 → 具体日期
独立文件便于后续复用(编年史时间轴、探险日志等)。
---
## 五、移动端 375px 适配审计(2-b)
### 审计结果
审了 5 个组件,修了 4 个:
| 组件 | 问题 | 修复 |
|------|------|------|
| `IdleOperationsPanel.tsx` | 11 处 `text-[9px]` 低于最小字号 | `text-[9px]``text-[10px]` |
| `BeaconPanel.tsx` | 7 处 `text-[9px]` + 信标链底部统计行 375px 溢出 | 字号升级 + `flex-wrap + gap-y-1` |
| `Codex.tsx` | 弹层 padding + 标题 + 顶部统计在小屏拥挤 | `p-5``p-4 sm:p-5` / 标题 `text-lg``text-base sm:text-lg` / 顶部统计 `flex flex-col sm:flex-row` |
| `StatsPanel.tsx` | 2 处 `text-[9px]` | `text-[10px]` |
**无需改**
- `ExpeditionPanel.tsx` — 节点路径已用 `overflow-x-auto` 自适应,按钮 `flex-1`,路径节点 36px 足够小
- BeaconPanel 4 里程碑节点 `w-12 h-12` × 4 = 192px 在 375px 可容纳
- IdleOperationsPanel 4 section 已用 `grid-cols-1 sm:grid-cols-N` 响应式降级
### 移动端字号规范
- 最小 `text-[10px]`9px 在高 DPI 屏可读性差)
- 标题最大 `text-2xl`(移动端)/ `text-3xl`(桌面)
- 优先用 `sm:` `md:` 响应式前缀,不删桌面端样式
---
## 六、技术实现
### 修改文件清单(11 个)
**子代理 2-a6 文件):**
- 新建 `src/lib/game/narrativeMilestones.ts`
- 新建 `src/components/game/NarrativeMilestoneOverlay.tsx`
- 修改 `src/lib/game/types.ts`(加 triggeredMilestones + pendingMilestone
- 修改 `src/lib/game/engine.ts`createInitialState + performPrestige
- 修改 `src/store/gameStore.ts`2 解码点检测 + dismissMilestone + migrate
- 修改 `src/app/page.tsx`(挂载叠层 + 版本号)
**子代理 2-b(8 文件,2 个与 2-a 共享):**
- 新建 `src/lib/game/format.ts`
- 修改 `src/lib/game/types.ts`(加 readLoreLayers,与 2-a 共存)
- 修改 `src/lib/game/engine.ts`createInitialState + performPrestige,与 2-a 共存)
- 修改 `src/store/gameStore.ts`markLoreLayerRead + migrate,与 2-a 共存)
- 修改 `src/components/game/Codex.tsx`(已读标记 + 点击逻辑 + 顶部统计)
- 修改 `src/components/game/StatsPanel.tsx`idleHistory 展开 + 字号)
- 修改 `src/components/game/IdleOperationsPanel.tsx`(字号 9→10px
- 修改 `src/components/game/BeaconPanel.tsx`(字号 + flex-wrap
### 并行零冲突
两个子代理在 3 个共享文件(types.ts / engine.ts / gameStore.ts)中:
- 字段名不冲突(`triggeredMilestones`/`pendingMilestone` vs `readLoreLayers`
- action 不冲突(`dismissMilestone` vs `markLoreLayerRead`
- migrate 补全各行独立
- 2-b 不动解码逻辑(line 575-720),那是 2-a 的领地
---
## 七、验证
- ✅ `bun run lint` 零错误零警告
- ✅ HTTP 200dev.log 无运行时错误
- ✅ agent-browser 端到端 smoke test
- 里程碑叠层:setState pendingMilestone=ms_5 → 全屏 dialog "回响 · 初鸣" + "点击任意处或按 Esc 继续" → 点击 → pending 清空 + triggered 保留 ✓
- loreLayer 已读:解锁 f1_1 + ascensions=1 → L1 "隐秘注脚" 显示 "新" + "标记为已读" 按钮 → 点击 → readLoreLayers=["f1_1_L1"] + L1 显示 "已读" + 顶部统计更新 ✓
- idleHistory 展开:设置 3 条历史 → 统计 tab "放置工程历史(最近 3 条可展开)" → 点击展开 → 倒序显示 3 行(icon + 工程名 + 相对时间)✓
---
## 八、哲学
### 仪式感与节奏
v0.16 的里程碑叠层不是"奖励",而是**节奏标记**。放置游戏容易陷入"数字增长麻木"5 个阈值(5/12/25/40/60)在玩家的解码旅程中设置了 5 个"停下来看一看"的节点:
- **ms_5**:新手期结束,确认身份
- **ms_12**:开始感知代价
- **ms_25**:中期转折,信任的重量
- **ms_40**:后期紧迫,追逐者逼近
- **ms_60**:终局预兆,回归的借形之物
每个里程碑的 body 文本都是**回顾性咏叹**——不是新剧情,而是对已解锁碎片的重新诠释。这让玩家在数字增长中保持对叙事的敏感。
### 已读标记的心理学
loreLayer 已读标记解决了一个细微的 UX 问题:玩家解锁深层文本后,如果不标记"已读",每次打开图谱都被高亮提示淹没,反而会**忽略真正的新内容**。已读标记让"新"保持稀缺,让玩家的注意力聚焦在真正未读的层上。
这与健康游戏设计呼应——**进度感不等于信息过载**。标记已读是一种"我处理过了"的仪式,让玩家心安。
---
## 九、下一步(v0.17+
- 🟡 星潮三频段切换(星潮系统增强)
- 🟡 健康设计:每日软上限 + "星核建议休眠"提醒
- 🟡 loreLayer 已读标记可扩展到碎片本身(fragment 级别的已读)
- 🟡 里程碑叠层的音效(程序化生成,与星潮音效区分)
- 🟡 format.ts 复用到编年史时间轴 + 探险日志
+1 -1
View File
@@ -44,7 +44,7 @@ const eslintConfig = [...nextCoreWebVitals, ...nextTypescript, {
"no-useless-escape": "off",
},
}, {
ignores: ["node_modules/**", ".next/**", "out/**", "build/**", "next-env.d.ts", "examples/**", "skills", "mini-services/**"]
ignores: ["node_modules/**", ".next/**", "out/**", "build/**", "next-env.d.ts", "examples/**", "skills"]
}];
export default eslintConfig;
-1
View File
File diff suppressed because one or more lines are too long
-23
View File
@@ -1,23 +0,0 @@
1:"$Sreact.fragment"
2:I[39756,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"default"]
3:I[37457,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"default"]
4:I[77855,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js"],"Toaster"]
5:I[47257,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"ClientPageRoot"]
6:I[52683,["/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","/Super_Z/echo-nexus/_next/static/chunks/38c9b86c7986e4d2.js","/Super_Z/echo-nexus/_next/static/chunks/dad63bc31a306c06.js","/Super_Z/echo-nexus/_next/static/chunks/868e0df8b5a7f188.js","/Super_Z/echo-nexus/_next/static/chunks/421819b51db6b69f.js"],"default"]
9:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"OutletBoundary"]
a:"$Sreact.suspense"
c:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"ViewportBoundary"]
e:I[97367,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"MetadataBoundary"]
10:I[68027,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"default"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","style"]
:HL["/Super_Z/echo-nexus/_next/static/media/0acc7fdf55eb3220-s.p.532ccaa1.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
:HL["/Super_Z/echo-nexus/_next/static/media/797e433ab948586e-s.p.29207c2f.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
:HL["/Super_Z/echo-nexus/_next/static/media/caa3a2e1cccd8315-s.p.3b6cae6d.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
0:{"P":null,"b":"yNvWrGxQ0RM8HHWxdOJQM","c":["",""],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/59368da722d2753f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/Super_Z/echo-nexus/_next/static/chunks/7bbd6f879a3901f6.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/3059a9b053b6a3de.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/4d383bb4be112933.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"zh-CN","suppressHydrationWarning":true,"className":"dark","children":["$","body",null,{"className":"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable orbitron_da1c3699-module__wSKb_W__variable antialiased bg-background text-foreground","children":[["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}],["$","$L4",null,{}]]}]}]]}],{"children":[["$","$1","c",{"children":[["$","$L5",null,{"Component":"$6","serverProvidedParams":{"searchParams":{},"params":{},"promises":["$@7","$@8"]}}],[["$","script","script-0",{"src":"/Super_Z/echo-nexus/_next/static/chunks/38c9b86c7986e4d2.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/Super_Z/echo-nexus/_next/static/chunks/dad63bc31a306c06.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/Super_Z/echo-nexus/_next/static/chunks/868e0df8b5a7f188.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/Super_Z/echo-nexus/_next/static/chunks/421819b51db6b69f.js","async":true,"nonce":"$undefined"}]],["$","$L9",null,{"children":["$","$a",null,{"name":"Next.MetadataOutlet","children":"$@b"}]}]]}],{},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$Lc",null,{"children":"$Ld"}],["$","div",null,{"hidden":true,"children":["$","$Le",null,{"children":["$","$a",null,{"name":"Next.Metadata","children":"$Lf"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$10",[]],"S":true}
7:{}
8:"$0:f:0:1:1:children:0:props:children:0:props:serverProvidedParams:params"
d:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
11:I[27201,["/Super_Z/echo-nexus/_next/static/chunks/33d3f2c0cda968c7.js"],"IconMark"]
b:null
f:[["$","title","0",{"children":"回响星核 · Echo Nexus"}],["$","meta","1",{"name":"description","content":"原创深空考古放置策略游戏 — 解码记忆晶体,拼凑以太文明的回响,跨越维度发起接触。"}],["$","meta","2",{"name":"author","content":"Super_Z"}],["$","meta","3",{"name":"keywords","content":"Echo Nexus,回响星核,idle game,browser game,放置游戏,解谜,深空考古"}],["$","meta","4",{"property":"og:title","content":"回响星核 · Echo Nexus"}],["$","meta","5",{"property":"og:description","content":"原创深空考古放置策略游戏"}],["$","meta","6",{"property":"og:site_name","content":"Echo Nexus"}],["$","meta","7",{"property":"og:type","content":"website"}],["$","meta","8",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","9",{"name":"twitter:title","content":"回响星核 · Echo Nexus"}],["$","meta","10",{"name":"twitter:description","content":"原创深空考古放置策略游戏"}],["$","link","11",{"rel":"icon","href":"https://z-cdn.chatglm.cn/z-ai/static/logo.svg"}],["$","$L11","12",{}]]

Some files were not shown because too many files have changed in this diff Show More