Blob Morph
Un blob SVG organique à 8 sommets radiaux se déforme en temps réel sur un flux audio simulé — courbes cubiques Catmull-Rom et halo CSS drop-shadow, sans canvas ni dépendance.
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
L'effet anime un unique <path> SVG dont l'attribut d est recalculé à chaque tick requestAnimationFrame. Huit sommets sont répartis à angle égal autour du centre (50, 50) du viewBox 100×100. À chaque frame, chacun reçoit un rayon compris entre 30 et 45 unités SVG selon le signal audio simulé.
Le générateur getSimulatedAudio superpose deux sinusoïdes pour chaque sommet : sin(t × freq × 0,002) × 0,5 + sin(t × freq × 0,003 + i) × 0,3, plus un bruit aléatoire à 20 %. La fréquence propre de chaque sommet croît de 0,5 par indice (baseFreq + i × 0,5, avec baseFreq = 0,3) — les sommets oscillent à des rythmes légèrement différents, simulant une réponse spectrale multi-bande.
Les 8 points calculés sont reliés par des cubiques Bézier dont les points de contrôle sont dérivés d'une formule Catmull-Rom avec tension 0,2 : cp1 = p0 + (p1 − p_{i−1}) × 0,2, cp2 = p1 − (p_{i+2} − p0) × 0,2. La boucle se referme sur le premier sommet (Z), garantissant une silhouette continue sans rupture ni angle mort.
Le rendu visuel utilise fill: url(#blobGradient) (dégradé radial à définir dans les <defs> du SVG) et filter: drop-shadow(rgba(99, 102, 241, 0,5) 0 0 20px) en CSS — le halo suit exactement le contour recalculé à chaque frame sans coût de redraw canvas.
Accessibilité
- prefers-reduced-motion absent — l'animation tourne en boucle perpétuelle même si l'OS signale une préférence de réduction de mouvement. Ajouter
if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;avant le premierrequestAnimationFrame. - Le
<svg>et son<path>n'ont niaria-hiddenni rôle sémantique — les lecteurs d'écran exposent l'élément avec un très long attributd. Ajouteraria-hidden="true"sur le SVG. - Aucune interaction clavier ni focus natif — l'effet réagit au RAF uniquement, aucun événement utilisateur n'est géré ni documenté.
- Le dégradé indigo-violet sur fond sombre offre une luminosité perçue correcte pour un élément purement décoratif ; aucun texte n'est superposé dans la démo de base, WCAG 1.4.3 ne s'applique pas.
- Le gradient
#blobGradientest référencé par URL mais non défini dans le snippet fourni — sans bloc<defs>dans le SVG, le fill tombe à noir. Toujours déclarer le<radialGradient>avant usage.
Compatibilité navigateur
Nécessite SVG inline, CSS filter: drop-shadow et requestAnimationFrame — aucun canvas, aucune dépendance externe.
Si JavaScript est désactivé, le blob reste figé dans la forme initiale définie dans l'attribut <code>d</code> du HTML — aucune erreur JS, la silhouette SVG reste visible.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="blob-morph" id="blobMorph">
<svg viewBox="0 0 100 100" aria-hidden="true">
<defs>
<radialGradient id="blobGradient" cx="38%" cy="35%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#4f46e5"/>
</radialGradient>
</defs>
<path id="blobPath" d="…"/>
</svg>
</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 |
|---|---|---|
| points = 8 | 8 | Nombre de sommets radiaux (constante JS). 5–6 = blob très rond, 10–12 = silhouette plus complexe et détaillée. |
| baseRadius = 30 | 30 | Rayon de repos en unités SVG (viewBox 100). 20 = compact, 40 = volumineux (risque de débordement hors viewBox). |
| data[i] * 15 | 15 | Amplitude maximale de déformation en unités SVG. 8 = subtil, 25 = très expressif. |
| baseFreq = 0.3 | 0.3 | 3e argument de getSimulatedAudio — fréquence de base des oscillations. 0,1 = lent et organique, 0,8 = rapide et nerveux. |
| * 0.2 (tension Catmull-Rom) | 0.2 | Facteur de tension des points de contrôle Bézier. 0,1 = très lisse, 0,4 = courbes plus angulaires. |
| .blob-morph { width / height } | 120px | Taille de la boîte de rendu via CSS. Le SVG se met à l'échelle proportionnellement — aucune modification JS nécessaire. |
| fill: url(#blobGradient) | gradient indigo | Couleur du blob via <radialGradient> dans les <defs> SVG. Modifiez stop-color pour votre palette. |
| filter: drop-shadow(…) | rgba(99,102,241,.5) 0 0 20px | Couleur et rayon du halo CSS. Alignez la couleur RGBA sur votre dégradé de base pour un ensemble cohérent. |
FAQ
getSimulatedAudio par une lecture de l'AnalyserNode Web Audio API : analyser.getByteFrequencyData(dataArray), puis normalisez (dataArray[i] / 255). Passez ce tableau à la place des valeurs simulées — la mécanique Bézier reste identique.getElementById('blobPath') cible un unique élément. Pour plusieurs instances, donnez à chaque <path> un id distinct (blobPath2, blobPath3…) et refactorisez animateBlobMorph pour accepter l'élément en paramètre plutôt qu'en référence globale.let rafId; rafId = requestAnimationFrame(animate); et appelez cancelAnimationFrame(rafId) pour stopper. Alternativement, la garde if (!blobPath) return; interrompt le cycle si vous supprimez l'élément #blobPath du DOM.