WEBLEB
Accueil
Éditeur
Connexion
Pro
Français
English
Français
Español
Português
Deutsch
Italiano
हिंदी
Feux d'artifice avec la souris
3365
Andev.web
Ouvrir dans l'éditeur
Video
Publiez votre code
11
Recommandé
15 December 2025
Bouton HTML léger avec icône et texte
23 August 2025
Code HTML et CSS de la page de connexion turque
5 July 2025
Panneau de connexion et d'inscription Glassy V2 de TheDoc
HTML
Copy
Andev Web
CSS
Copy
*{ box-sizing: border-box; } html, body{ height: 100%; } body{ overflow: hidden; display: grid; color: white; background: black; }
JS
Copy
class PointerParticle { constructor(spread, speed, component) { const { ctx, pointer, hue } = component; this.ctx = ctx; this.x = pointer.x; this.y = pointer.y; this.mx = pointer.mx * 0.1; this.my = pointer.my * 0.1; this.size = Math.random() + 1; this.decay = 0.01; this.speed = speed * 0.08; this.spread = spread * this.speed; this.spreadX = (Math.random() - 0.5) * this.spread - this.mx; this.spreadY = (Math.random() - 0.5) * this.spread - this.my; this.color = `hsl(${hue}, 90%, 60%)`; } draw() { this.ctx.fillStyle = this.color; this.ctx.beginPath(); this.ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); this.ctx.fill(); } collapse() { this.size -= this.decay; } trail() { this.x += this.spreadX * this.size; this.y += this.spreadY * this.size; } update() { this.draw(); this.trail(); this.collapse(); } } class PointerParticles extends HTMLElement { static register(tag = "pointer-particles") { if ("customElements" in window) { customElements.define(tag, this); } } static css = ` :host { display: grid; width: 100%; height: 100%; user-select: none; } `; constructor() { super(); this.canvas; this.ctx; this.fps = 60; this.msPerFrame = 1000 / this.fps; this.timePrevious; this.particles = []; this.pointer = { x: 0, y: 0, mx: 0, my: 0 }; this.hue = 0; } connectedCallback() { const canvas = document.createElement("canvas"); const sheet = new CSSStyleSheet(); this.shadowroot = this.attachShadow({ mode: "open" }); sheet.replaceSync(PointerParticles.css); this.shadowroot.adoptedStyleSheets = [sheet]; this.shadowroot.append(canvas); this.canvas = this.shadowroot.querySelector("canvas"); this.ctx = this.canvas.getContext("2d"); this.setCanvasDimensions(); this.setupEvents(); this.timePrevious = performance.now(); this.animateParticles(); } createParticles(event, { count, speed, spread }) { this.setPointerValues(event); for (let i = 0; i < count; i++) { this.particles.push(new PointerParticle(spread, speed, this)); } } setPointerValues(event) { this.pointer.x = event.x - this.offsetLeft; this.pointer.y = event.y - this.offsetTop; this.pointer.mx = event.movementX; this.pointer.my = event.movementY; } setupEvents() { const parent = this.parentNode; parent.addEventListener("click", (event) => { this.createParticles(event, { count: 300, speed: Math.random() + 1, spread: Math.random() + 50 }); }); parent.addEventListener("pointermove", (event) => { this.createParticles(event, { count: 20, speed: this.getSpeed(event), spread: 1 }); }); window.addEventListener("resize", () => this.setCanvasDimensions()); } getSpeed(event) { const a = event.movementX; const b = event.movementY; const c = Math.floor(Math.sqrt(a * a + b * b)); return c; } handleParticles() { for (let i = 0; i < this.particles.length; i++) { this.particles[i].update(); if (this.particles[i].size <= 0.1) { this.particles.splice(i, 1); i--; } } } setCanvasDimensions() { const rect = this.parentNode.getBoundingClientRect(); this.canvas.width = rect.width; this.canvas.height = rect.height; } animateParticles() { requestAnimationFrame(() => this.animateParticles()); const timeNow = performance.now(); const timePassed = timeNow - this.timePrevious; if (timePassed < this.msPerFrame) return; const excessTime = timePassed % this.msPerFrame; this.timePrevious = timeNow - excessTime; this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); this.hue = this.hue > 360 ? 0 : (this.hue += 3); this.handleParticles(); } } PointerParticles.register();