我要js,给了我一个html
(function() {
// --- 创建全屏 Canvas ---
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const W = window.innerWidth;
const H = window.innerHeight;
canvas.width = W;
canvas.height = H;
canvas.style.cssText = `
position: fixed;
top: 0; left: 0;
width: 100vw; height: 100vh;
z-index: 2147483647;
pointer-events: none;
background: transparent;
`;
document.body.appendChild(canvas);
// --- 全局状态 ---
const particles = []; // 所有粒子
const rockets = []; // 飞行中的火箭
const flashes = []; // 爆炸闪光
let lastTime = performance.now();
let allFireworksLaunched = false;
let launchIndex = 0;
let cleanupTimer = null;
// --- 绚丽的颜色主题 ---
const colorThemes = [
{ hue: 5, name: '经典红' }, // 正红
{ hue: 30, name: '金橙' }, // 金橙色
{ hue: 50, name: '璀璨金' }, // 金色
{ hue: 330, name: '玫红' }, // 玫红
{ hue: 280, name: '紫罗兰' }, // 紫色
{ hue: 180, name: '青蓝' }, // 青色
{ hue: 15, name: '橘红' }, // 橘红
{ hue: 340, name: '粉红' }, // 粉红
{ hue: 45, name: '琥珀金' }, // 琥珀金
{ hue: 260, name: '薰衣草紫' }, // 薰衣草紫
{ hue: 200, name: '天蓝' }, // 天蓝色
{ hue: 355, name: '深红' }, // 深红
];
// --- 工具函数:HSL 转 CSS 颜色字符串 ---
function hslToColor(h, s, l, a = 1) {
return `hsla(${h}, ${s}%, ${l}%, ${a})`;
}
// --- 创建爆炸粒子 ---
function createExplosion(x, y, themeHue, particleCount = 120) {
// 闪光效果
flashes.push({
x,
y,
radius: 0,
maxRadius: 60 + Math.random() * 40,
life: 1.0,
decay: 4.5 + Math.random() * 3,
});
// 爆炸粒子
for (let i = 0; i < particleCount; i++) {
const angle = (Math.PI * 2 * i) / particleCount;
// 添加随机偏移让爆炸更自然
const angleOffset = (Math.random() - 0.5) * 0.25;
const finalAngle = angle + angleOffset;
const speed = 280 + Math.random() * 520; // 像素/秒
const speedVariation = 1 + (Math.random() - 0.5) * 0.6;
const vx = Math.cos(finalAngle) * speed * speedVariation;
const vy = Math.sin(finalAngle) * speed * speedVariation;
// 粒子颜色在主题色周围变化
const hueShift = (Math.random() - 0.5) * 40;
const h = (themeHue + hueShift + 360) % 360;
const s = 75 + Math.random() * 25;
const l = 50 + Math.random() * 30;
particles.push({
x,
y,
vx,
vy,
life: 1.0,
maxLife: 1.4 + Math.random() * 1.6, // 秒
color: hslToColor(h, s, l, 1),
size: 1.8 + Math.random() * 3.5,
type: 'spark',
gravity: 160 + Math.random() * 80, // 重力加速度 px/s²
friction: 0.3 + Math.random() * 0.5,
twinkle: Math.random() < 0.25, // 25%的粒子会闪烁
twinkleSpeed: 8 + Math.random() * 25,
});
}
// 额外添加一些"金色雨"慢速粒子
const glitterCount = Math.floor(particleCount * 0.3);
for (let i = 0; i < glitterCount; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = 60 + Math.random() * 180;
const vx = Math.cos(angle) * speed;
const vy = Math.sin(angle) * speed - 40;
const h = 40 + Math.random() * 25; // 金色范围
const s = 80 + Math.random() * 20;
const l = 55 + Math.random() * 35;
particles.push({
x,
y,
vx,
vy,
life: 1.0,
maxLife: 2.0 + Math.random() * 2.5, // 金色雨持续更久
color: hslToColor(h, s, l, 1),
size: 1.2 + Math.random() * 2.2,
type: 'glitter',
gravity: 60 + Math.random() * 50,
friction: 0.6 + Math.random() * 0.35,
twinkle: true,
twinkleSpeed: 12 + Math.random() * 20,
});
}
}
// --- 创建火箭尾焰粒子 ---
function createTrailParticle(x, y, themeHue) {
const h = 25 + Math.random() * 35; // 尾焰偏橙黄
particles.push({
x: x + (Math.random() - 0.5) * 8,
y: y + (Math.random() - 0.5) * 6,
vx: (Math.random() - 0.5) * 30,
vy: 30 + Math.random() * 60,
life: 1.0,
maxLife: 0.3 + Math.random() * 0.5,
color: hslToColor(h, 90, 55 + Math.random() * 30, 1),
size: 1.5 + Math.random() * 3,
type: 'trail',
gravity: 20,
friction: 0.8,
twinkle: false,
twinkleSpeed: 0,
});
}
// --- 发射烟花 ---
function launchFirework(themeHue, delayMs = 0) {
const startX = W * 0.15 + Math.random() * W * 0.7;
const startY = H + 20;
const targetY = H * 0.18 + Math.random() * H * 0.45;
const targetX = startX + (Math.random() - 0.5) * W * 0.35;
const dx = targetX - startX;
const dy = targetY - startY;
const distance = Math.sqrt(dx * dx + dy * dy);
const flightTime = 0.7 + Math.random() * 0.6; // 飞行时间(秒)
const speed = distance / flightTime;
const vx = (dx / distance) * speed;
const vy = (dy / distance) * speed;
const rocket = {
x: startX,
y: startY,
vx,
vy,
targetY,
targetX,
themeHue,
alive: true,
trailTimer: 0,
trailInterval: 0.015, // 每0.015秒产生一个尾焰粒子
};
if (delayMs > 0) {
// 延迟发射
rocket.delayed = true;
rocket.launchAt = performance.now() + delayMs;
rocket.x = startX;
rocket.y = startY;
// 在延迟期间不更新位置
rocket._vx = vx;
rocket._vy = vy;
rocket.vx = 0;
rocket.vy = 0;
}
rockets.push(rocket);
}
// --- 发射计划:分波次发射 ---
function scheduleFireworks() {
const now = performance.now();
const schedule = [
// [延迟ms, 主题索引]
[0, 0],
[80, 5],
[200, 2],
[350, 8],
[500, 3],
[600, 10],
[750, 1],
[900, 7],
[1050, 4],
[1150, 11],
[1300, 6],
[1450, 9],
[1600, 0],
[1700, 2],
[1850, 5],
[2000, 3],
[2150, 8],
[2300, 1],
[2500, 10],
[2650, 7],
[2800, 4],
[3000, 11],
[3200, 0],
[3350, 6],
[3500, 2],
];
schedule.forEach(([delay, themeIdx]) => {
const theme = colorThemes[themeIdx % colorThemes.length];
launchFirework(theme.hue, delay);
});
// 设置全部发射完毕标志(在最后一个发射后)
const maxDelay = schedule[schedule.length - 1][0] + 2000;
setTimeout(() => {
allFireworksLaunched = true;
}, maxDelay);
}
// --- 更新粒子 ---
function updateParticles(dt) {
for (let i = particles.length - 1; i >= 0; i--) {
const p = particles[i];
p.life -= dt / p.maxLife;
if (p.life <= 0) {
particles.splice(i, 1);
continue;
}
// 物理更新
p.vy += p.gravity * dt;
p.vx *= (1 - p.friction * dt * 3);
p.vy *= (1 - p.friction * dt * 3);
p.x += p.vx * dt;
p.y += p.vy * dt;
}
}
// --- 更新火箭 ---
function updateRockets(dt, now) {
for (let i = rockets.length - 1; i >= 0; i--) {
const r = rockets[i];
// 处理延迟发射
if (r.delayed) {
if (now >= r.launchAt) {
r.delayed = false;
r.vx = r._vx;
r.vy = r._vy;
r._vx = undefined;
r._vy = undefined;
} else {
continue; // 还在等待发射
}
}
// 更新位置
r.x += r.vx * dt;
r.y += r.vy * dt;
// 产生尾焰
r.trailTimer += dt;
while (r.trailTimer >= r.trailInterval) {
r.trailTimer -= r.trailInterval;
createTrailParticle(r.x, r.y, r.themeHue);
}
// 检查是否到达目标高度
if (r.y <= r.targetY || r.y <= H * 0.08) {
// 爆炸!
createExplosion(r.x, r.y, r.themeHue, 100 + Math.floor(Math.random() * 80));
rockets.splice(i, 1);
}
// 安全检查:如果火箭飞出屏幕
if (r.y < -200 || r.x < -200 || r.x > W + 200) {
rockets.splice(i, 1);
}
}
}
// --- 更新闪光 ---
function updateFlashes(dt) {
for (let i = flashes.length - 1; i >= 0; i--) {
const f = flashes[i];
f.life -= f.decay * dt;
f.radius += (f.maxRadius - f.radius) * 6 * dt;
if (f.life <= 0) {
flashes.splice(i, 1);
}
}
}
// --- 渲染 ---
function render() {
ctx.clearRect(0, 0, W, H);
// 使用 additive 混合让烟花更绚丽
ctx.globalCompositeOperation = 'lighter';
// 绘制闪光
flashes.forEach(f => {
const alpha = f.life;
const gradient = ctx.createRadialGradient(f.x, f.y, 0, f.x, f.y, f.radius);
gradient.addColorStop(0, `rgba(255,255,240,${alpha * 0.9})`);
gradient.addColorStop(0.3, `rgba(255,240,200,${alpha * 0.5})`);
gradient.addColorStop(0.7, `rgba(255,180,100,${alpha * 0.15})`);
gradient.addColorStop(1, `rgba(255,150,50,0)`);
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(f.x, f.y, f.radius, 0, Math.PI * 2);
ctx.fill();
});
// 绘制粒子
particles.forEach(p => {
const alpha = p.life;
let size = p.size * (0.4 + 0.6 * p.life);
// 闪烁粒子
if (p.twinkle) {
const twinkleFactor = 0.5 + 0.5 * Math.sin(p.life * p.twinkleSpeed * Math.PI * 2);
size *= (0.6 + 0.4 * twinkleFactor);
}
if (size < 0.3) return;
// 光晕
const glowRadius = size * 3;
const gradient = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, glowRadius);
const baseColor = p.color.replace(/[\d.]+\)$/, '');
gradient.addColorStop(0, p.color.replace(/[\d.]+\)$/, `${Math.min(1, alpha)})`));
gradient.addColorStop(0.35, baseColor + `${alpha * 0.55})`);
gradient.addColorStop(0.7, baseColor + `${alpha * 0.1})`);
gradient.addColorStop(1, baseColor + '0)');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(p.x, p.y, glowRadius, 0, Math.PI * 2);
ctx.fill();
// 核心亮点
ctx.fillStyle = `rgba(255,255,255,${alpha * 0.8})`;
ctx.beginPath();
ctx.arc(p.x, p.y, size * 0.5, 0, Math.PI * 2);
ctx.fill();
});
// 绘制火箭(小亮点)
ctx.globalCompositeOperation = 'lighter';
rockets.forEach(r => {
if (r.delayed) return;
const gradient = ctx.createRadialGradient(r.x, r.y, 0, r.x, r.y, 8);
gradient.addColorStop(0, 'rgba(255,255,240,0.95)');
gradient.addColorStop(0.4, 'rgba(255,200,100,0.6)');
gradient.addColorStop(1, 'rgba(255,100,30,0)');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(r.x, r.y, 8, 0, Math.PI * 2);
ctx.fill();
});
// 恢复默认混合模式
ctx.globalCompositeOperation = 'source-over';
}
// --- 检查是否应该清理 ---
function shouldCleanup() {
return allFireworksLaunched &&
rockets.length === 0 &&
particles.length === 0 &&
flashes.length === 0;
}
// --- 执行清理 ---
function cleanup() {
if (canvas.parentNode) {
// 淡出效果
canvas.style.transition = 'opacity 0.8s ease-out';
canvas.style.opacity = '0';
setTimeout(() => {
if (canvas.parentNode) {
canvas.parentNode.removeChild(canvas);
}
}, 800);
}
}
// --- 主循环 ---
function mainLoop(timestamp) {
let dt = (timestamp - lastTime) / 1000; // 转换为秒
lastTime = timestamp;
// 防止大的时间跳跃(如标签页切换)
if (dt > 0.2) dt = 0.2;
if (dt <= 0) dt = 0.016;
const now = performance.now();
updateRockets(dt, now);
updateParticles(dt);
updateFlashes(dt);
render();
if (shouldCleanup()) {
if (!cleanupTimer) {
cleanupTimer = setTimeout(cleanup, 400);
}
}
if (!cleanupTimer || particles.length > 0 || rockets.length > 0 || flashes.length > 0) {
requestAnimationFrame(mainLoop);
} else if (cleanupTimer && particles.length === 0 && rockets.length === 0 && flashes.length ===
0) {
// 已经触发清理,不再请求新帧
// 但再检查一次以防万一
if (!canvas.parentNode) return;
// 如果清理还没执行,继续循环
if (canvas.style.opacity !== '0') {
requestAnimationFrame(mainLoop);
}
}
}
// --- 启动 ---
scheduleFireworks();
lastTime = performance.now();
requestAnimationFrame(mainLoop);
// --- 安全超时:15秒后强制清理 ---
setTimeout(() => {
if (canvas.parentNode && !cleanupTimer) {
allFireworksLaunched = true;
// 快速衰减所有粒子
particles.forEach(p => { p.maxLife *= 0.3;
p.life = Math.min(p.life, 0.3); });
rockets.length = 0;
cleanupTimer = setTimeout(cleanup, 600);
if (!cleanupTimer._set) {
// 确保清理最终执行
setTimeout(cleanup, 2000);
}
}
}, 15000);
console.log('🎆 礼花绽放!欣赏表演吧~(约6-8秒)');
})();
这是Gpt-5.4的(没开思考)
(() => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
Object.assign(canvas.style, {
position: 'fixed',
left: '0',
top: '0',
width: '100vw',
height: '100vh',
pointerEvents: 'none',
zIndex: '999999'
});
let w = canvas.width = window.innerWidth;
let h = canvas.height = window.innerHeight;
const particles = [];
const colors = ['#ff4d4d', '#ffd24d', '#4dff88', '#4db8ff', '#b84dff', '#ffffff', '#ff7fd1'];
window.addEventListener('resize', () => {
w = canvas.width = window.innerWidth;
h = canvas.height = window.innerHeight;
});
function createFirework(x, y) {
const count = 80 + Math.random() * 40;
for (let i = 0; i < count; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = Math.random() * 6 + 2;
particles.push({
x,
y,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed,
life: 60 + Math.random() * 30,
maxLife: 90,
color: colors[Math.floor(Math.random() * colors.length)],
size: Math.random() * 3 + 1
});
}
}
function animate() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.18)';
ctx.fillRect(0, 0, w, h);
for (let i = particles.length - 1; i >= 0; i--) {
const p = particles[i];
p.x += p.vx;
p.y += p.vy;
p.vy += 0.05;
p.vx *= 0.99;
p.vy *= 0.99;
p.life--;
const alpha = Math.max(p.life / p.maxLife, 0);
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fillStyle = hexToRgba(p.color, alpha);
ctx.fill();
if (p.life <= 0) particles.splice(i, 1);
}
if (particles.length > 0 || running) {
requestAnimationFrame(animate);
} else {
setTimeout(() => canvas.remove(), 500);
}
}
function hexToRgba(hex, alpha) {
const c = hex.replace('#', '');
const bigint = parseInt(c, 16);
const r = (bigint >> 16) & 255;
const g = (bigint >> 8) & 255;
const b = bigint & 255;
return `rgba(${r},${g},${b},${alpha})`;
}
let running = true;
let times = 0;
const timer = setInterval(() => {
createFirework(
Math.random() * w * 0.8 + w * 0.1,
Math.random() * h * 0.5 + h * 0.1
);
times++;
if (times >= 10) {
clearInterval(timer);
running = false;
}
}, 500);
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(0, 0, w, h);
animate();
})();
个人总结:deepseek思考时间长,效果不如gpt5.4
5 个帖子 - 3 位参与者