Mesh Distortion AI
Un treillis de 13 × 13 points reliés par des lignes fines, dessiné sur canvas, qui ondule doucement tout seul ; dans un rayon de 100 px autour de la souris, les points sont attirés vers elle jusqu'à 20 px et le filet se pince sous le curseur, lignes comprises. Teinte qui glisse du bleu au violet, canvas net sur Retina, boucle arrêtée hors écran, filet immobile qui s'éclaire sous la souris si l'utilisateur réduit les animations. Un filet de points, pas un dégradé maillé ; aucune intelligence artificielle.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Liquid comprend 31 effets, dont 6 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Le cadre .fx-0420-root fait 300 px de haut sur toute la largeur et le canvas s'y cale (display: block, 100 % × 100 %) ; taille interne = taille affichée × devicePixelRatio, dessin en pixels CSS par setTransform (mesuré : 1280 × 600 pour 640 × 300 à densité 2). Le treillis couvre tout le canvas : 12 intervalles dans chaque sens, soit environ 53 × 25 px de maille sur 640 × 300, les points du bord posés sur le bord. Un ResizeObserver suit le cadre, le treillis aussi.
Chaque image se dessine en deux passes. D'abord, la position de chaque point : sa place dans la grille, plus une ondulation de ±3 px (3 sin(a + 0,5 × colonne) en largeur, 3 cos(a + 0,5 × rangée) en hauteur, a avançant de 0,015 par image, un cycle en 7 s environ à 60 images/s), plus, si la souris est à moins de 100 px, un déplacement vers elle de 20 × (1 − distance / 100) px. Ensuite, les lignes de 1 px qui relient chaque point déformé à ses voisins de droite et du dessous, déformés eux aussi, puis les points de 2 px de rayon par-dessus. Les points proches du curseur se resserrent sur lui : vu de dessus, le filet se creuse comme sous une pression. La teinte suit 240 + 30 sin(a + 0,3 × (colonne + rangée)) : une bande violette traverse le bleu en diagonale.
La souris est lue par mousemove sur le conteneur. Tant qu'elle n'est pas entrée, et dès qu'elle sort (mouseleave), sa position est rangée très loin du cadre : aucun point n'est attiré et le filet revient à sa seule ondulation. Le canvas est effacé à chaque image, son fond est donc celui de la racine, ou celui de votre page si la racine est transparente. La boucle requestAnimationFrame s'arrête quand un IntersectionObserver voit le canvas sortir de l'écran (mesuré : 0 image par seconde hors écran contre 120 à l'écran) et repart à son retour.
Accessibilité
- Mouvement réduit : sous
prefers-reduced-motion: reduce, le filet ne s'anime plus et n'est plus attiré ; il est redessiné seulement quand la souris bouge, et les points à moins de 100 px s'éclaircissent et virent au rose, leurs lignes plus opaques, sans se déplacer. Mesuré dans Chromium 151, Firefox 153 et WebKit 26 : 0 % de pixels changés au repos, la zone sous la souris s'éclaire au passage. - Clavier et lecteurs d'écran : le filet ne réagit qu'à la souris et ne porte aucune information. Si la déformation illustre un propos (la solidité d'un filet, la souplesse d'une toile), dites-le en texte à côté, comme dans les exemples.
- Toucher : sans survol, un tap envoie un seul
mousemove: le filet se pince au point touché et y reste jusqu'au tap suivant, l'ondulation continue. Pour suivre le doigt, voir la FAQ. - Contraste : les lignes sont à 15 % d'opacité, de simples traits d'ambiance sur fond sombre ; ce sont les points qui portent la forme. Sur un décor clair ou chargé, montez l'opacité des lignes (voir Personnaliser).
Compatibilité navigateur
Canvas 2D + 2,9 Ko de JavaScript, aucune dépendance. Mesuré dans Chromium 151, Firefox 153 et WebKit 26 : même ondulation, même pincement sous la souris, retour à la sortie, taille interne doublée à densité 2, hauteur stable après 20 redimensionnements, boucle à l'arrêt hors écran, filet immobile sous mouvement réduit. Coût mesuré : 0,2 ms de JavaScript par image dans Chromium, environ 1 ms dans Firefox. ResizeObserver existe depuis Chrome 64, Firefox 69 et Safari 13.1.
Sans JavaScript, le cadre reste noir bleuté, sans filet. Sans IntersectionObserver, la boucle tourne aussi hors écran ; sans ResizeObserver, le treillis suit le redimensionnement de la fenêtre seulement.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :
<div class="fx-0420-root">
<div class="ai-mesh-container">
<canvas class="ai-mesh-canvas" width="393" height="280"></canvas>
</div>
</div>
Paiement unique, sans abonnement — le code est à toi pour toujours
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Densité (JS — const h = 12) |
12 intervalles : 13 × 13 = 169 points | 20 donne 441 points et un filet fin ; 8, 81 points et une grosse maille. Le coût suit le nombre de points. |
Rayon et force (JS — m = 100 et 20 * (1 - g / m)) |
100 px, jusqu'à 20 px d'attraction | 160 px et 30 px pour un creux large et profond ; 60 px et 10 px pour une pression du bout du doigt. |
Sens (JS — u += r / g * t, M += d / g * t) |
attraction vers la souris | Remplacez les deux += par -= : les points fuient le curseur et le filet se bombe autour de lui. |
Ondulation (JS — 3 * Math.sin(a + .5 * n), 3 * Math.cos(a + .5 * t) et a += .015) |
±3 px, cycle de 7 s environ | Mettez 0 à la place des deux 3 pour un filet parfaitement immobile au repos ; 0,03 pour a double la vitesse. |
Couleurs (JS — 240 + 30 * Math.sin(…), hsla(${k}, 70%, ${L}%, 0.8)) |
teinte de 210 à 270, saturation 70 %, clarté 60 % | Teinte 34 et clarté 78 % donnent un sable ; saturation 0 et clarté 94 % un filet blanc. Les lignes ont leur propre hsla(${k}, 60%, 50%, ${A}). |
Opacité des lignes (JS — A = .15) |
15 % | 0,4 à 0,5 rend le filet lisible sur un décor clair ou chargé, comme dans les trois exemples. |
Hauteur et fond (CSS — .fx-0420-root { height: 300px; background: #0a0a0f }) |
300 px, noir bleuté | Le canvas est effacé à chaque image : background: transparent pose le filet sur votre décor. |
FAQ
pointermove et pointerleave au lieu de mousemove et mouseleave (mêmes coordonnées clientX / clientY), et ajoutez touch-action: none sur le conteneur : le doigt pince le filet en glissant, mais la page ne défile plus quand le doigt est dessus. Gardez donc un cadre qui ne couvre pas tout l'écran.