排行榜烟火(冠 / 亚 / 季不同效果)
排行榜揭晓或「进入前三」时,用 canvas-confetti(或等价粒子)放出三种可区分的烟火:第一名最隆重,第二、第三递减但各自造型不同。只做视觉庆祝,不拦截点击。
何时使用
- 排行榜、积分榜、PK 结果展示前三名
- 「冠军烟花」「一二三名不同礼花」
- 需要比普通成交礼花更有「名次仪式感」
硬约束
- 三种效果必须肉眼可区分(颜色、喷发形状、强度都不能雷同)。
- 礼花层
pointer-events: none,不得挡按钮/列表点击。 - 仅在「展示名次 / 揭晓成功」时触发;失败、空榜不放烟火。
prefers-reduced-motion: reduce时跳过粒子,可用简短 Toast:「恭喜获得第 N 名」。- 动画约 1.5~3.5s 自然结束;不要无限循环吵闹。
- 可与榜单 UI 并存:先高亮名次卡片,再放对应烟火。
名次效果规格(必须落实)
| 名次 | 气质 | 建议实现(canvas-confetti) |
|---|---|---|
| 第一名 | 加冕、最亮 | 金色系 #FFD700/#FFF4C1/#FFA500;顶部中心大爆发 + 左右两侧斜喷;particleCount 高(如 160~220);可二次延迟连放「加冕」小爆 |
| 第二名 | 利落银光 | 银色/冷白 #E8EEF5/#C0C8D4/#9AA8B8;左右双炮对称喷(origin x=0.2 与 0.8);强度中等(90~130) |
| 第三名 | 温暖轻绽 | 铜色/琥珀 #CD7F32/#E8A05A/#F0C090;底部中央单次上喷或小范围 spread 偏小;粒子更少(60~90),短促 |
不要三种都只改 particleCount 而颜色形状相同。
推荐 API
import confetti from 'canvas-confetti'
export type PodiumRank = 1 | 2 | 3
function reduced() {
return window.matchMedia('(prefers-reduced-motion: reduce)').matches
}
function ensureCanvas(): confetti.CreateTypes {
const fire = confetti.create(undefined, { resize: true, useWorker: true })
// 库生成的 canvas 需保证不挡点击(多数版本默认如此;自建时设 pointer-events:none)
return fire
}
export function firePodiumRank(rank: PodiumRank) {
if (reduced()) return { ok: true as const, skipped: true as const }
const fire = ensureCanvas()
if (rank === 1) {
const gold = ['#FFD700', '#FFF4C1', '#FFA500', '#FFE566']
fire({ particleCount: 120, spread: 70, origin: { x: 0.5, y: 0.25 }, colors: gold, startVelocity: 55 })
fire({ particleCount: 70, angle: 60, spread: 55, origin: { x: 0, y: 0.45 }, colors: gold })
fire({ particleCount: 70, angle: 120, spread: 55, origin: { x: 1, y: 0.45 }, colors: gold })
window.setTimeout(() => {
fire({ particleCount: 80, spread: 100, origin: { x: 0.5, y: 0.35 }, colors: gold, ticks: 200 })
}, 280)
return { ok: true as const, rank }
}
if (rank === 2) {
const silver = ['#E8EEF5', '#C0C8D4', '#9AA8B8', '#FFFFFF']
fire({ particleCount: 100, angle: 60, spread: 55, origin: { x: 0.18, y: 0.55 }, colors: silver, startVelocity: 45 })
fire({ particleCount: 100, angle: 120, spread: 55, origin: { x: 0.82, y: 0.55 }, colors: silver, startVelocity: 45 })
return { ok: true as const, rank }
}
// 第三名
const bronze = ['#CD7F32', '#E8A05A', '#F0C090', '#A05A2C']
fire({
particleCount: 75,
spread: 48,
origin: { x: 0.5, y: 0.7 },
colors: bronze,
startVelocity: 35,
gravity: 1.1,
})
return { ok: true as const, rank }
}
/** 同时庆祝前三:错开时间,避免糊成一团 */
export function firePodiumTop3(order: PodiumRank[] = [1, 2, 3]) {
if (reduced()) return
order.forEach((rank, i) => {
window.setTimeout(() => firePodiumRank(rank), i * 450)
})
}
与成交礼花的分工
- 成交礼花:单次成功爆发,无名词仪式。
- 排行榜烟火:按 1/2/3 分支,金色加冕 / 银色双喷 / 铜色轻绽。
Agent 步骤
- 安装
canvas-confetti,封装firePodiumRank/ 可选firePodiumTop3。 - 榜单 UI 在渲染第 N 名高亮后调用对应 API。
- 自测:三种效果颜色与喷法可区分;动画中列表仍可滚动点击;减动效时无粒子。
不要做
- 三种名次共用同一段 confetti 配置。
- 全屏遮罩、强制静音外放音效(若加音效必须可关且默认轻/关)。
- 把四五名及以后也做成同等烟火(可无动效或极弱闪一下)。
附加
- README.md · reference.md · templates/usage.md