2026跨年3D粒子特效代码

该文章已生成可运行项目,

哈喽,各位小伙伴👋!马上就要迎来 2026 年跨年啦,小熊必须用代码给大家整一个有排面的跨年特效!今天给大家带来的是基于HTML+CSS+JAVASCRIPT开发的 3D 粒子跨年盛典页面,包含倒计时粒子动画、物理烟花效果、3D 分层蛋糕、动态祝福语气泡等炫酷功能,源码获取在文末!!

🎇 效果预览

2026年跨年倒计时代码祝福!

  • 倒计时动画:5→4→3→2→1→2026,全程 3D 粒子数字呈现,缓动动画丝滑过渡
  • 3D 蛋糕特效:三层彩色粒子蛋糕 + 动态闪烁蜡烛,无冗余文字干扰,视觉更纯粹
  • 物理烟花效果:随机生成彩色烟花,模拟重力 + 阻力物理运动,淡出效果更真实
  • 祝福语气泡:100 句新年祝福语随机生成,金色渐变气泡向上漂浮,氛围感拉满
  • 交互体验:支持鼠标 / 手指拖动旋转视角、滚轮缩放,适配 PC + 移动端

🛠 技术栈

  • 核心:HTML5 + CSS3 + 原生 JavaScript
  • 3D 引擎:Three.js r128(WebGL 渲染,CDN 引入无需本地依赖)
  • 动画:CSS3 keyframes + requestAnimationFrame 帧动画
  • 适配:响应式布局,适配移动端 / PC 端不同屏幕尺寸

🚀 实现思路(核心要点)

Three.js 核心场景初始化

// 场景初始化
initScene() {
    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color(0x0a0a2a); // 深蓝星空背景
    this.scene.fog = new THREE.Fog(0x0a0a2a, 10, 100); // 雾化增强3D感
}

// 相机+渲染器初始化
initCamera() {
    this.camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 2000);
    this.updateCameraPosition(); // 绑定旋转/缩放逻辑
}

initRenderer() {
    this.renderer = new THREE.WebGLRenderer({
        canvas: canvas,
        antialias: true, // 抗锯齿
        alpha: true
    });
    this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // 高清屏适配
}

1. 倒计时粒子动画

基于 8x8 点阵定义数字轮廓,每个数字点位生成多粒子提升密度,通过缓动算法(1 - Math.pow (1 - progress, 3))实现粒子从随机位置向数字形状平滑过渡,倒计时结束自动触发烟花和蛋糕效果。

// 粒子动画到指定数字
animateToNumber(number) {
    return new Promise(resolve => {
        const positions = this.particles.geometry.attributes.position.array;
        const numberPoints = this.getNumberPoints(number);
        
        // 为每个粒子分配目标位置
        for (let i = 0; i < positions.length / 3; i++) {
            const pointIndex = i % numberPoints.length;
            const point = numberPoints[pointIndex];
            
            this.targetPositions[i * 3] = point.x;
            this.targetPositions[i * 3 + 1] = point.y;
            this.targetPositions[i * 3 + 2] = 0;
        }
        
        // 缓动动画(1 - Math.pow(1 - progress, 3) 实现缓出效果)
        const duration = 1500;
        const startTime = Date.now();
        
        const animate = () => {
            const elapsed = Date.now() - startTime;
            const progress = Math.min(elapsed / duration, 1);
            const easeProgress = 1 - Math.pow(1 - progress, 3); // 缓出算法
            
            // 更新粒子位置
            for (let i = 0; i < positions.length; i += 3) {
                positions[i] = this.originalPositions[i] + (this.targetPositions[i] - this.originalPositions[i]) * easeProgress;
                positions[i + 1] = this.originalPositions[i + 1] + (this.targetPositions[i + 1] - this.originalPositions[i + 1]) * easeProgress;
                positions[i + 2] = this.originalPositions[i + 2] + (this.targetPositions[i + 2] - this.originalPositions[i + 2]) * easeProgress;
            }
            
            this.particles.geometry.attributes.position.needsUpdate = true;
            
            if (progress < 1) {
                requestAnimationFrame(animate);
            } else {
                this.originalPositions = positions.slice();
                resolve();
            }
        };
        
        animate();
    });
}

2. 3D 分层粒子蛋糕

  • 三层不同颜色 / 尺寸的粒子蛋糕体(红 + 青 + 蓝渐变),随机粒子分布模拟蛋糕纹理
  • 6 根动态闪烁蜡烛,实现上下晃动 + 亮度变化双动画,还原真实蜡烛效果
  • 移除了蛋糕顶部冗余文字,仅保留纯粹的蛋糕粒子视觉效果
// 创建分层蛋糕
createCake() {
    // 三层蛋糕配置(半径/高度/位置/颜色)
    const cakeLayers = [
        { radius: 8, height: 2, y: 0, color: 0xff6b6b },    // 底层红
        { radius: 6, height: 2, y: 2.5, color: 0x4ecdc4 },  // 中层青
        { radius: 4, height: 2, y: 5, color: 0x45b7d1 }     // 顶层蓝
    ];
    
    // 生成每层蛋糕
    cakeLayers.forEach(layer => this.createCakeLayer(layer.radius, layer.height, layer.y, layer.color));
    // 生成蜡烛
    this.createCandles();
}

// 创建单一层蛋糕
createCakeLayer(radius, height, y, color) {
    const particleCount = window.innerWidth > 768 ? 800 : 400;
    const geometry = new THREE.BufferGeometry();
    const positions = new Float32Array(particleCount * 3);
    const colors = new Float32Array(particleCount * 3);
    
    for (let i = 0; i < particleCount; i++) {
        const angle = Math.random() * Math.PI * 2;
        const r = Math.sqrt(Math.random()) * radius;
        const idx = i * 3;
        
        // 随机分布粒子模拟蛋糕纹理
        positions[idx] = Math.cos(angle) * r;
        positions[idx + 1] = y + Math.random() * height;
        positions[idx + 2] = Math.sin(angle) * r;
        
        // 蛋糕层颜色赋值
        colors[idx] = (color >> 16 & 255) / 255;
        colors[idx + 1] = (color >> 8 & 255) / 255;
        colors[idx + 2] = (color & 255) / 255;
    }
    
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
    
    const material = new THREE.PointsMaterial({
        size: 3,
        vertexColors: true,
        transparent: true,
        opacity: 0.9,
        blending: THREE.AdditiveBlending // 叠加模式增强亮度
    });
    
    const layer = new THREE.Points(geometry, material);
    this.scene.add(layer);
    this.cakeParticles.push(layer);
}

// 蜡烛闪烁动画(模拟火焰晃动+亮度变化)
animateCandle(candle) {
    let time = 0;
    const originalSizes = [];
    const positions = candle.geometry.attributes.position.array;
    
    // 存储原始Y坐标
    for (let i = 1; i < positions.length; i += 3) {
        originalSizes.push(positions[i]);
    }
    
    const animate = () => {
        if (!candle.parent) return;
        
        time += 0.1;
        // 蜡烛上下晃动
        for (let i = 0; i < positions.length / 3; i++) {
            const idx = i * 3 + 1;
            positions[idx] = originalSizes[i] + Math.sin(time + i) * 0.3;
        }
        
        candle.geometry.attributes.position.needsUpdate = true;
        candle.material.opacity = 0.7 + Math.sin(time) * 0.3; // 亮度闪烁
        requestAnimationFrame(animate);
    };
    
    animate();
}

3. 物理烟花效果

  • 每 800ms 自动生成烟花,初始 3 发烟花瞬间引爆氛围
  • 模拟真实物理运动:随机初始速度 + 重力加速度 + 空气阻力,2 秒后自然淡出
  • 随机 HSL 颜色生成,每一发烟花都有独特视觉效果
// 创建烟花(物理运动+淡出效果)
createFirework() {
    const fireworkCount = 300;
    const geometry = new THREE.BufferGeometry();
    const positions = new Float32Array(fireworkCount * 3);
    const velocities = new Float32Array(fireworkCount * 3);
    const colors = new Float32Array(fireworkCount * 3);
    
    // 烟花初始位置(随机分布)
    const x = (Math.random() - 0.5) * 100;
    const y = Math.random() * 30;
    const z = (Math.random() - 0.5) * 100;
    
    // 随机HSL颜色
    const color = new THREE.Color();
    color.setHSL(Math.random(), 1, 0.7);
    
    // 初始化烟花粒子
    for (let i = 0; i < fireworkCount; i++) {
        const idx = i * 3;
        
        // 初始位置
        positions[idx] = x;
        positions[idx + 1] = y;
        positions[idx + 2] = z;
        
        // 随机球面速度(向四周扩散)
        const speed = 0.5 + Math.random() * 1.5;
        const phi = Math.random() * Math.PI * 2;
        const theta = Math.random() * Math.PI;
        
        velocities[idx] = Math.sin(theta) * Math.cos(phi) * speed;
        velocities[idx + 1] = Math.cos(theta) * speed;
        velocities[idx + 2] = Math.sin(theta) * Math.sin(phi) * speed;
        
        // 颜色赋值
        colors[idx] = color.r;
        colors[idx + 1] = color.g;
        colors[idx + 2] = color.b;
    }
    
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
    
    const material = new THREE.PointsMaterial({
        size: 2,
        vertexColors: true,
        transparent: true,
        opacity: 1,
        blending: THREE.AdditiveBlending
    });
    
    const firework = new THREE.Points(geometry, material);
    this.scene.add(firework);
    
    // 物理运动参数
    const gravity = -0.01; // 重力加速度
    const life = 2000; // 烟花生命周期(2秒)
    const startTime = Date.now();
    
    // 烟花动画逻辑
    const animateFirework = () => {
        const elapsed = Date.now() - startTime;
        if (elapsed > life) {
            // 清理烟花(释放内存)
            this.scene.remove(firework);
            geometry.dispose();
            material.dispose();
            return;
        }
        
        const positions = firework.geometry.attributes.position.array;
        
        // 更新粒子位置(重力+阻力)
        for (let i = 0; i < fireworkCount; i++) {
            const idx = i * 3;
            
            positions[idx] += velocities[idx];
            positions[idx + 1] += velocities[idx + 1];
            positions[idx + 2] += velocities[idx + 2];
            
            // 叠加重力
            velocities[idx + 1] += gravity;
            // 空气阻力(速度衰减)
            velocities[idx] *= 0.99;
            velocities[idx + 1] *= 0.99;
            velocities[idx + 2] *= 0.99;
        }
        
        firework.geometry.attributes.position.needsUpdate = true;
        material.opacity = 1 - (elapsed / life); // 逐渐淡出
        requestAnimationFrame(animateFirework);
    };
    
    animateFirework();
}

4. 动态祝福语气泡

  • 内置 100 句新年祝福语,每 30ms 随机生成一个气泡
  • 金色渐变背景 + 文字阴影,适配移动端字体大小
  • 限制最大气泡数量(50 个),自动清理过期气泡,避免性能损耗
// 显示随机祝福语气泡
showRandomBlessing() {
    // 限制最大气泡数量(避免性能损耗)
    if (this.blessingElements.length >= this.maxBlessings) {
        const oldest = this.blessingElements.shift();
        oldest && oldest.remove();
    }
    
    // 随机选择祝福语(内置100句)
    const blessingText = BLESSINGS[Math.floor(Math.random() * BLESSINGS.length)];
    const bubble = document.createElement('div');
    bubble.className = 'blessing-bubble';
    bubble.textContent = blessingText;
    
    // 随机位置(避免边缘)
    const x = 10 + Math.random() * 80;
    const y = 10 + Math.random() * 80;
    bubble.style.left = `${x}%`;
    bubble.style.top = `${y}%`;
    
    // 随机大小+金色渐变背景
    const size = 0.8 + Math.random() * 0.4;
    bubble.style.transform = `translate(-50%, -50%) scale(${size})`;
    const hue = Math.random() * 60;
    bubble.style.background = `linear-gradient(135deg, hsla(${hue}, 100%, 60%, 0.9), hsla(${hue + 20}, 100%, 50%, 0.9))`;
    
    // 添加到页面并管理生命周期
    document.getElementById('blessings-container').appendChild(bubble);
    this.blessingElements.push(bubble);
    
    // 3秒后自动移除
    setTimeout(() => {
        bubble.style.opacity = 0;
        setTimeout(() => bubble.remove(), 300);
        const index = this.blessingElements.indexOf(bubble);
        index > -1 && this.blessingElements.splice(index, 1);
    }, 3000);
}

5. 多端交互适配

  • 鼠标 / 触摸拖动:实现 3D 视角旋转,支持任意角度查看蛋糕 / 烟花
  • 滚轮缩放:调整视角距离,放大查看细节 / 缩小看全局
  • 响应式布局:适配 768px 以下移动端,自动调整粒子数量 / 字体大小
// 绑定交互事件(鼠标/触摸/缩放)
bindEvents() {
    // 窗口适配
    window.addEventListener('resize', () => {
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(window.innerWidth, window.innerHeight);
    });
    
    // 鼠标/触摸拖动旋转
    const onPointerDown = (e) => {
        this.isDragging = true;
        this.previousPosition = {
            x: e.clientX || e.touches[0].clientX,
            y: e.clientY || e.touches[0].clientY
        };
    };
    
    const onPointerMove = (e) => {
        if (!this.isDragging) return;
        
        const currentX = e.clientX || e.touches[0].clientX;
        const currentY = e.clientY || e.touches[0].clientY;
        
        const deltaX = currentX - this.previousPosition.x;
        const deltaY = currentY - this.previousPosition.y;
        
        // 更新旋转角度(限制X轴旋转范围)
        this.cameraRotation.y += deltaX * 0.01;
        this.cameraRotation.x -= deltaY * 0.01;
        this.cameraRotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, this.cameraRotation.x));
        
        this.updateCameraPosition();
        this.previousPosition = { x: currentX, y: currentY };
    };
    

交互事件绑定

// 拖动旋转视角
const onPointerMove = (e) => {
    if (!this.isDragging) return;
    const deltaX = currentX - this.previousPosition.x;
    const deltaY = currentY - this.previousPosition.y;
    this.cameraRotation.y += deltaX * 0.01;
    this.cameraRotation.x -= deltaY * 0.01;
    this.updateCameraPosition();
};

// 滚轮缩放
canvas.addEventListener('wheel', (e) => {
    e.preventDefault();
    this.cameraDistance = Math.max(10, Math.min(50, this.cameraDistance + e.deltaY * 0.01));
    this.updateCameraPosition();
});

📝 使用说明

1. 运行环境

  • 浏览器:推荐 Chrome/Edge 最新版(需支持 WebGL)
  • 移动端:支持微信 / QQ 内置浏览器、手机 Chrome 等

2. 操作方式

  1. 直接打开 HTML 文件即可运行(Three.js 通过 CDN 引入,无需本地安装依赖)
  2. 拖动鼠标 / 手指:旋转 3D 视角,查看蛋糕 / 烟花不同角度
  3. 滚轮缩放:放大 / 缩小视角,调整查看距离

3. 注意事项

  • 若提示 “浏览器不支持 3D 特效”,请升级 Chrome/Edge 浏览器后重试
  • 低配设备可能出现粒子卡顿,可适当减少粒子数量(代码中 particleCount 参数)
  • 移动端建议横屏查看,体验更佳

📥 源码获取

本文展示的是核心实现思路,完整可运行的源码已上传至我的 CSDN 主页资源库👉 小熊的资源库,需要的小伙伴可以到我的主页资源库中下载,直接开箱即用!

🎉 跨年祝福

最后,小熊祝各位小伙伴 2026 新年快乐🎆!所求皆如愿,所行皆坦途,新的一年代码无 bug,薪资节节高,保持热爱,奔赴山海!

如果觉得这个跨年特效还不错,记得点赞 + 收藏 + 关注哦~你的支持就是我创作的最大动力!评论区留下你的新年愿望,2026 我们一起加油💪!


✨ 我是小熊,关注我,获取更多炫酷前端特效 / 后端实战教程~

本文章已经生成可运行项目
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值