Fire Effect
Particules de feu 2D canvas — dégradé jaune→orange→rouge piloté par la durée de vie, traînée fumée via fond semi-transparent, 3 spawns par frame depuis la base.
Vous aurez accès à la démo interactive avec un compte gratuit.
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Atmosphère comprend 57 effets, dont 10 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
À chaque frame, le canvas n'est pas effacé avec clearRect : un ctx.fillRect semi-transparent rgba(10,10,15,0.15) est appliqué à la place. Les frames précédentes persistent avec 85 % d'opacité restante, créant la traînée de fumée sans aucun stockage de tampon supplémentaire.
3 nouvelles particules sont spawnnées à chaque frame depuis le bas du canvas (y = hauteur − 20 px), à une position x aléatoire ± 20 px autour du centre (t.w/2 + 40*(Math.random()−0.5)). Vitesse verticale initiale : −2 à −6 px/frame (montée) ; dérive horizontale : ±1 px/frame. La décélération est quasi nulle : vy *= 0.99 — les particules montent à vitesse quasi constante avant de disparaître par épuisement de leur durée de vie.
Le dégradé de couleur est calculé par vie restante : R = 255, G = floor(200 × life), B = floor(50 × life). Fraîche (life = 1) → jaune-orange (255, 200, 50) ; à mi-vie (0,5) → orange (255, 100, 25) ; en fin de vie → rouge pur qui s'efface. Taille et alpha décroissent en parallèle : size *= 0.98 par frame, alpha = 0.8 × life. Chaque particule vit entre 33 et 100 frames (decay aléatoire 0,01–0,03).
L'effet utilise un requestAnimationFrame non conditionnel : la boucle tourne en permanence, sans IntersectionObserver ni vérification de visibilité. Il n'y a ni API publique, ni gestion du redimensionnement du canvas après l'initialisation — setupCanvas lit les dimensions du parent une seule fois au chargement.
Accessibilité
- prefers-reduced-motion absent : l'effet ne consulte pas cette préférence OS. L'animation tourne toujours, même si l'utilisateur a activé « Réduire le mouvement ». À traiter manuellement avec
window.matchMedia('(prefers-reduced-motion:reduce)').matchesavant de lancer le RAF. - Le
<canvas>ne porte niaria-hidden, nirole, niaria-labeldans le code fourni — les lecteurs d'écran peuvent l'annoncer comme un élément interactif vide. Ajoutezaria-hidden="true"sur le canvas et unrole="img"+aria-labelsur le conteneur. - Aucune interaction clavier ou pointeur : l'effet est purement contemplatif. Il n'interfère pas avec la navigation au clavier du reste de la page.
- Les particules les plus vives (jaune-orange sur fond #0a0a0f quasi-noir) dépassent un ratio de contraste 7:1 — lisibilité visuelle élevée.
- L'information portée (cycle vie = couleur) est exclusivement chromatique : aucune alternative non-colorée n'est fournie. L'effet étant purement décoratif, l'absence d'alternative est acceptable.
Compatibilité navigateur
Nécessite Canvas 2D, requestAnimationFrame et les template literals ES6 — tous les navigateurs modernes depuis 2016.
Sans Canvas 2D, le <code><canvas></code> reste vide et silencieux — aucune erreur JS fatale. Le conteneur <code>.ps-canvas-wrap</code> occupe son espace ; ajoutez un fond CSS de secours (ex. dégradé orange→rouge) si la visibilité à l'écran est requise.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="demo-preview" role="img"
aria-label="Animation de feu montant en particules jaune-orange-rouge">
<div class="ps-canvas-wrap">
<canvas class="ps-canvas" id="psFire"
aria-hidden="true">
</canvas>
</div>
</div>
HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
| Spawn rate (JS : boucle for) | 3 par frame | for (let n = 0; n < 3; n++) — augmentez à 5–8 pour une flamme dense et large, descendez à 1–2 pour un feu léger et intermittent. |
| Spread horizontal (JS : 40) | ±20 px du centre | 40 * (Math.random() − .5) — doublez à 80 pour une flamme large, réduisez à 10 pour une colonne fine centrée sur un bouton. |
| Vitesse de montée (JS : vy) | -2 à -6 px/frame | 4 * -Math.random() - 2 — augmentez le multiplicateur (4→6) pour des particules plus rapides ; augmentez le décalage (2→3) pour une vitesse minimale plus élevée. |
| Taille initiale (JS : size) | 3–9 px | 6 * Math.random() + 3 — premier terme = amplitude de la variation, second = taille minimale. Ex. grosses braises : 10 * Math.random() + 6. |
| Durée de vie (JS : decay) | 0,01–0,03 par frame | .02 * Math.random() + .01 — abaissez pour des particules longues qui montent haut (flamme haute) ; augmentez pour une flamme courte et intense près de la source. |
| Traînée fumée (JS : fillStyle fond) | rgba(10,10,15,0.15) | Fond semi-transparent remplaçant le clearRect. Abaissez l'alpha (0,06–0,10) pour une longue traînée vaporeuse ; montez-le (0,30–0,50) pour couper la fumée et garder seulement les particules fraîches. |
| Palette couleur (JS : formule RGB) | jaune→orange→rouge | Remplacez rgba(${a},${l},${c},…) — feu bleu-blanc : rgba(${Math.floor(200*i.life)},${Math.floor(200*i.life)},255,…) ; feu vert : rgba(0,255,${Math.floor(200*i.life)},…). |
FAQ
psFire au chargement — une seule instance tourne nativement. Pour plusieurs flammes, extrayez la logique dans une fonction paramétrée par id : function initFire(id){ const t = setupCanvas(id); const e = []; (function n(){…requestAnimationFrame(n)})(); } puis appelez initFire('feu1'), initFire('feu2'), etc. setupCanvas est une fonction globale réutilisable.requestAnimationFrame(n) dans une variable externe (let rafId = requestAnimationFrame(n)) et annulez avec cancelAnimationFrame(rafId). Pour relancer, réappellez simplement la fonction de tick.setupCanvas lit les dimensions du parent via getBoundingClientRect() une seule fois à l'initialisation. Si le conteneur change de taille (resize de fenêtre, panneau accordéon), recalibrez manuellement : canvas.width = wrap.offsetWidth; canvas.height = wrap.offsetHeight; et mettez à jour t.w et t.h. Ajoutez un ResizeObserver sur .ps-canvas-wrap pour automatiser ce recalibrage.