v0.13: 性能重构+数值平衡+字体资源落地

性能(调研 7-A 落地):
- 新增 AnimatedNumber 组件(useRef + rAF lerp,60fps 平滑过渡,不触发 React re-render)
- CrystalOrb 拆 OrbStats 子组件:主体(Canvas+button)不再每 tick 重渲染
  crystals/crystalCap/crystalsPerSec 订阅下沉到 OrbStats,用 AnimatedNumber 平滑
- page.tsx StatsPanel: shallow → useShallow(修复 zustand v5 getSnapshot 崩溃)

数值平衡(调研 7-A 落地,防速通):
- 新增 src/lib/game/softcap.ts:applySoftcap/applyCostSoftcap/effectiveDecodedForPrestige
- 飞升蓝图公式改 sqrt softcap(阈值 40,power 0.5)
  前 2 蓝图照常给(新手友好),3-6 蓝图需更多解码(防速通)
  - totalDecoded=40 → 2 蓝图(与旧一致)
  - totalDecoded=80 → 2 蓝图(旧=4)
  - totalDecoded=360 → 6 蓝图(封顶)

非商用资源落地(调研 7-B):
- 安装 @fontsource/share-tech-mono + @fontsource/vt323(SIL OFL 自托管)
- globals.css 加 --font-tech / --font-terminal 变量
- ResourceBar 数值用 font-tech(Share Tech Mono 星舰仪表盘感)
- ArchaeoLogTicker 文本用 font-terminal(VT323 终端绿字)+ GiScrollUnfurled 图标
- 安装 react-icons,引入 game-icons.net 子集(MIT)

交互优化:
- ExpeditionPanel 加探险目的说明(3 资源卡片)+ 节点类型图例(issue #3 反馈)
- BeaconPanel 布局微调

验证:
- lint 零错误
- VLM 首页 QA 8.5/10(字体/配色/页脚贴底均良好)
- 点击脉冲交互正常(数值增加、浮动数字正确消失)
- dev.log 无运行时错误
This commit is contained in:
2026-06-24 04:02:45 +00:00
parent cfc87ca3a1
commit 93195f9b88
14 changed files with 287 additions and 170 deletions
+38 -8
View File
@@ -111,7 +111,7 @@ export function ExpeditionPanel() {
// v0.10 工单 #2 修复:探险结束自动清空 activeExpedition,无需 justFinished 判断
if (!activeExpedition || activeExpedition.finished) {
return (
<div className="flex flex-col gap-3 h-full">
<div className="h-full overflow-y-auto echo-scroll space-y-3 pr-0.5">
<div className="flex items-center justify-between">
<h3 className="text-sm font-semibold flex items-center gap-1.5">
<Rocket className="h-4 w-4 text-amber-400" />
@@ -186,27 +186,57 @@ export function ExpeditionPanel() {
</div>
{/* 出发按钮 */}
<div className="flex-1 flex flex-col items-center justify-center gap-3 rounded-2xl border border-dashed border-amber-400/20 bg-black/30 p-4 relative overflow-hidden">
<div className="flex flex-col items-center justify-center gap-3 rounded-2xl border border-dashed border-amber-400/20 bg-black/30 p-4 py-5 relative">
<div className="absolute -top-10 -right-10 h-32 w-32 rounded-full bg-amber-500/10 blur-2xl" />
<div className="relative">
<div className={`h-16 w-16 rounded-full bg-gradient-to-br from-amber-500/30 to-rose-500/20 flex items-center justify-center mx-auto ${canStart ? "animate-pulse" : ""}`} style={{ boxShadow: "0 0 30px rgba(251,191,36,0.3)" }}>
<Rocket className="h-7 w-7 text-amber-300" />
<div className={`h-14 w-14 rounded-full bg-gradient-to-br from-amber-500/30 to-rose-500/20 flex items-center justify-center mx-auto ${canStart ? "animate-pulse" : ""}`} style={{ boxShadow: "0 0 30px rgba(251,191,36,0.3)" }}>
<Rocket className="h-6 w-6 text-amber-300" />
</div>
</div>
<div className="text-center space-y-1">
<p className="text-sm font-medium text-amber-100"></p>
<p className="text-[11px] text-muted-foreground/80 max-w-[220px]">
沿 BOSS
<p className="text-[11px] text-muted-foreground/80 max-w-[260px] leading-relaxed">
5-7 //// BOSS
</p>
</div>
{/* v0.13 探险目的说明(issue #3 反馈"不知道有啥用" */}
<div className="w-full grid grid-cols-3 gap-1.5 text-[10px]">
<div className="rounded-md border border-emerald-400/20 bg-emerald-950/15 px-1.5 py-1 text-center">
<div className="text-emerald-300 font-semibold">/</div>
<div className="text-muted-foreground/60 text-[9px] mt-0.5">线</div>
</div>
<div className="rounded-md border border-fuchsia-400/20 bg-fuchsia-950/15 px-1.5 py-1 text-center">
<div className="text-fuchsia-300 font-semibold"></div>
<div className="text-muted-foreground/60 text-[9px] mt-0.5"></div>
</div>
<div className="rounded-md border border-amber-400/20 bg-amber-950/15 px-1.5 py-1 text-center">
<div className="text-amber-300 font-semibold"></div>
<div className="text-muted-foreground/60 text-[9px] mt-0.5">BOSS </div>
</div>
</div>
<Button
onClick={handleStart}
disabled={!canStart}
className="bg-gradient-to-r from-amber-600 to-rose-500 hover:from-amber-500 hover:to-rose-400 text-white border-0"
className="bg-gradient-to-r from-amber-600 to-rose-500 hover:from-amber-500 hover:to-rose-400 text-white border-0 w-full"
>
<Rocket className="h-4 w-4 mr-1.5" />
{canStart ? `出发(消耗 ${EXPEDITION_CONFIG.energyCost} 能量)` : `能量不足(${nextEnergyInSec}s 后恢复)`}
</Button>
{/* v0.13 节点类型图例(让玩家知道 6 种节点) */}
<div className="w-full flex items-center justify-center gap-2 flex-wrap text-[9px] text-muted-foreground/60 pt-1 border-t border-white/5">
{Object.entries(NODE_META).map(([key, meta]) => {
const Icon = meta.icon;
return (
<span key={key} className="inline-flex items-center gap-0.5">
<Icon className="h-2.5 w-2.5" style={{ color: meta.color }} />
{meta.label}
</span>
);
})}
</div>
</div>
{/* 探险日志 */}
@@ -234,7 +264,7 @@ export function ExpeditionPanel() {
const pathProgress = ((exp.currentNode + (currentNode.cleared ? 1 : 0)) / exp.nodes.length) * 100;
return (
<div className="flex flex-col gap-2.5 h-full">
<div className="h-full overflow-y-auto echo-scroll space-y-2.5 pr-0.5">
{/* 头部:生命 + 路径进度 */}
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-1.5">