This project creates a stunning interactive 3D Christmas tree rendered entirely on an HTML canvas. The tree is built from thousands of animated particle lights and falling snow, giving it a magical, glowing holiday look. Users can control the speed, size, light mode, and color theme through a sleek UI placed above the canvas. The experience blends physics, particle systems, perspective projection, and performance-optimized rendering. Overall, it’s a visually rich and deeply interactive festive animation designed to feel alive and responsive.
HTML
<!-- Mode -->
<div class="flex flex-col items-center">
<label
class="text-[9px] text-yellow-100/60 tracking-widest uppercase mb-1"
>Mode</label
>
<select
id="lightModeBtn"
class="bg-white/5 hover:bg-white/10 text-yellow-100/90 text-[10px] rounded border border-white/10 px-2 py-1 outline-none cursor-pointer transition focus:bg-white/20 focus:border-yellow-500/30"
>
<option value="sparkle" class="text-black">
Sparkle
</option>
<option value="steady" class="text-black">
Steady
</option>
<option value="off" class="text-black">Off</option>
</select>
</div>The HTML file provides a very minimal but purposeful structure: everything revolves around the <canvas> element, where the entire 3D Christmas tree is rendered. Above this, a UI overlay is positioned absolutely so it sits on top of the animation without interfering visually. This UI includes sliders for speed and size, a dropdown for light mode, and a button to switch color themes. TailwindCSS is loaded to style the controls, while custom classes in the stylesheet refine details like shimmer effects and blur backgrounds. The canvas is placed at the root of the document so it can stretch across the entire screen. The UI layer uses pointer-events: none to avoid blocking the canvas interaction except for the control panel, which selectively re-enables pointer events. Finally, the HTML loads the script.js file at the end to initialize the rendering engine and begin the animation loop.
CSS
.slider {
-webkit-appearance: none;
width: 100%;
height: 4px;
background: rgba(255, 255, 255, 0.2);
border-radius: 2px;
outline: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 12px;
height: 12px;
border-radius: 50%;
background: #ffd700;
cursor: pointer;
}The CSS begins by setting the entire page to fill the browser window, using a deep black background to make the glowing tree pop visually. The canvas is set to display as a block element so it smoothly spans the full viewport without scrollbars. The #ui-layer is absolutely positioned and allowed to float above the canvas, but most of it is non-interactive thanks to pointer-events: none, ensuring the controls don’t interfere except where allowed. The control panel uses a frosted-glass style via backdrop-filter: blur(5px) and a semi-transparent dark background for a sleek winter aesthetic. Slider inputs are custom-styled, giving them golden thumb knobs to match the Christmas theme. The shimmering title at the top uses a gradient background clipped into the text, animated with keyframes to create a glowing motion effect. Overall, the CSS provides a polished, festive user interface that complements the heavy canvas animation underneath.
JavaScript
function generateSprites() {
const colors = new Set(PALETTES.flatMap((p) => p.colors));
colors.add("#ffffff"); // Snow
colors.forEach((color) => {
const sCanvas = document.createElement("canvas");
const size = 32; // Texture size
sCanvas.width = size;
sCanvas.height = size;
const sCtx = sCanvas.getContext("2d");
const center = size / 2;
// Radial gradient for soft glow
const g = sCtx.createRadialGradient(
center,
center,
0,
center,
center,
center
);
g.addColorStop(0, color);
g.addColorStop(0.2, color); // Solid core
g.addColorStop(0.4, adjustAlpha(color, 0.5));
g.addColorStop(1, "transparent");
sCtx.fillStyle = g;
sCtx.fillRect(0, 0, size, size);
sprites[color] = sCanvas;
});
}The JavaScript file is the heart of the project, where the 3D tree, lights, snow, and animations are generated. It starts by selecting the canvas and setting up its 2D drawing context, disabling alpha for performance. The script defines a configuration object controlling particle count, speed, size scaling, rotation, and light behavior. It also contains themed color palettes that users can cycle through. Pre-rendered glow sprites are created on off-screen canvases to dramatically optimize rendering of thousands of lights. Classes such as Point, TreeLight, and Snow model 3D objects which are projected into 2D space using perspective math. User interactions — mouse movement, touch, clicking, and UI inputs — all update rotation, pulsing effects, light modes, and theme changes. An animation loop uses requestAnimationFrame, updating rotations, pulsing, particle positions, depth sorting, and then drawing each element with additive blending for a magical glowing effect. Finally, a star is dynamically drawn at the top of the tree, completing the scene. (Licence)