v0.1.13: 金碧山河(SVG/Canvas 素材 + 动效系统 + 舞美重装)
【素材生成(零外部资源)】 - scripts/gen-art.mjs 程序化产出 5 枚 SVG 资产:金碧山水全景(山脊/金乌/雁阵/水纹)、 祥云纹带、回纹角饰、仙鹤、星辰层 → src/renderer/assets/gen/,npm run gen:art 可重跑 【Canvas 动效系统(单 RAF)】 - ui/fx-canvas.ts:灵雾粒子流(常驻随季色)/金砂喷发(spark)/刀光(blade)/涟漪(ripple), 单实例防重入、防膨胀 cap、GPU 友好、visibility 自停 - ui/fx.ts + core/fxqueue.ts:FxGate 统一发射闸——档位过滤(柔/标/全)、 reduced-motion 降级、单帧批处理防竞态、deltas 纯函数(漂字差分) 【舞美】 - 金碧背景层 bg-scene(全页面,随季节 hue-rotate 色温渐变) - 顶栏时辰司:季节印(春·熏风/夏·蝉鸣/秋·霜叶/冬·雪静)+年月进度环(SVG 弧段)+节气名 - 成员卡:闭关 aura 三点浮动 + 修为流光 shimmer - 消息流:good 事件(突破/获宝/落槌)→金砂喷发,战事→刀光扫过战报 - Boot 卷轴展开过渡;drift 漂字层(独立节点队列不覆盖,8 条裁剪) - 设置页动效三档(柔和/标准/全开) 【竞态规避】 - RAF 单循环 guard、particles cap 裁剪、FxGate draining 互斥、漂字节点附加不覆盖、 visibility 自动降级、advance in-flight 闸沿用 【测试】937→967(timesense 矩阵 15 + FxGate 竞态/档位/deltas 15) 全量 35 套件通过;金钟罩零漂移(纯 UI/素材层);typecheck/build 通过
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
interface DriftItem { id: number; text: string; cls: string }
|
||||
|
||||
/** 资源漂字层:每次 fx:drift 事件追加独立节点(互不覆盖),超 8 条自动修剪尾部 */
|
||||
export function DriftLayer() {
|
||||
const [items, setItems] = useState<DriftItem[]>([])
|
||||
useEffect(() => {
|
||||
const onDrift = (e: Event) => {
|
||||
const detail = (e as CustomEvent).detail as Record<string, number>
|
||||
const now = Date.now()
|
||||
const next: DriftItem[] = []
|
||||
for (const [k, v] of Object.entries(detail)) {
|
||||
if (v === 0 || !Number.isFinite(v)) continue
|
||||
next.push({ id: now + Math.random() + k.length, text: `${v > 0 ? '+' : ''}${v}`, cls: v > 0 ? 'pos' : 'neg' })
|
||||
}
|
||||
if (next.length === 0) return
|
||||
setItems((old) => [...old, ...next].slice(-8))
|
||||
}
|
||||
window.addEventListener('fx:drift', onDrift)
|
||||
const timer = setInterval(() => setItems((old) => old.slice(0)), 2600) // 到期清理由 CSS fade 承担
|
||||
return () => {
|
||||
window.removeEventListener('fx:drift', onDrift)
|
||||
clearInterval(timer)
|
||||
}
|
||||
}, [])
|
||||
return (
|
||||
<div className="drift-layer">
|
||||
{items.map((it) => (
|
||||
<span key={it.id} className={`drift ${it.cls}`}>{it.text}</span>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -47,9 +47,10 @@ export function MemberCard({ c }: { c: Character }) {
|
||||
</div>
|
||||
{!dead && (
|
||||
<div className="mc-foot">
|
||||
<div className="bar" title="灵气修为" style={{ height: 6 }}>
|
||||
<div className={`bar ${c.state === 'meditation' ? 'shimmer' : ''}`} title="灵气修为" style={{ height: 6 }}>
|
||||
<div style={{ width: `${c.realmProgress}%` }} />
|
||||
</div>
|
||||
{c.state === 'meditation' && <div className="aura-dots"><i></i><i></i><i></i></div>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user