[{"data":1,"prerenderedAt":179},["ShallowReactive",2],{"case-\u002Fcases\u002Fshader-image-survol":3},{"id":4,"title":5,"body":6,"description":166,"extension":167,"meta":168,"navigation":174,"path":175,"seo":176,"stem":177,"__hash__":178},"content\u002Fcases\u002Fshader-image-survol.md","Shader d'image au survol",{"type":7,"value":8,"toc":159},"minimark",[9,13,17,20,25,33,55,59,144,148],[10,11,5],"h1",{"id":12},"shader-dimage-au-survol",[14,15,16],"p",{},"Trois paysages de montagne. Passe la souris (ou le focus clavier) sur une image : elle se déforme autour du curseur, se sépare en canaux rouge \u002F vert \u002F bleu, puis se dissout vers une seconde photo. Au clavier, le focus déclenche exactement le même effet.",[18,19],"shader-image-hover",{},[21,22,24],"h2",{"id":23},"démarche","Démarche",[14,26,27,28,32],{},"Un ",[29,30,31],"strong",{},"fragment shader GLSL"," fait tout le travail, un vertex shader minimal pose juste un quad plein écran. Trois effets superposés :",[34,35,36,43,49],"ul",{},[37,38,39,42],"li",{},[29,40,41],{},"Déformation liquide"," — une poussée radiale autour du pointeur, modulée par la vitesse de la souris et un léger tremblement de bruit.",[37,44,45,48],{},[29,46,47],{},"Chromatic aberration"," — les canaux R et B sont échantillonnés à des offsets opposés du canal V, proportionnels à la distance au curseur.",[37,50,51,54],{},[29,52,53],{},"Dissolution organique"," — un bruit fractal (fBM, 4 octaves) décide quels pixels basculent les premiers vers l'image d'arrivée, pour un seuillage doux.",[21,56,58],{"id":57},"détails-techniques","Détails techniques",[34,60,61,72,82,95,120,130],{},[37,62,63,66,67,71],{},[29,64,65],{},"Lissage exponentiel"," indépendant du framerate pour la souris, la vitesse et la progression — la courbe ",[68,69,70],"code",{},"1 - exp(-dt * k)"," donne un suivi qui reste cohérent même si le navigateur drop des frames.",[37,73,74,77,78,81],{},[29,75,76],{},"Mise en veille"," quand la carte sort du viewport (",[68,79,80],{},"IntersectionObserver",") et quand elle est au repos (plus rien ne bouge), pour épargner le GPU.",[37,83,84,90,91,94],{},[29,85,86,87],{},"Respect de ",[68,88,89],{},"prefers-reduced-motion"," — un uniforme ",[68,92,93],{},"uReduit"," désactive la déformation et la dissolution bruitée, il reste un simple fondu entre les deux images.",[37,96,97,100,101,104,105,108,109,112,113,108,116,119],{},[29,98,99],{},"Accessibilité clavier"," — ",[68,102,103],{},"tabindex=\"0\""," sur chaque carte, ",[68,106,107],{},"focus"," \u002F ",[68,110,111],{},"blur"," déclenchent la même animation que ",[68,114,115],{},"pointerenter",[68,117,118],{},"pointerleave",", avec la souris centrée.",[37,121,122,125,126,129],{},[29,123,124],{},"Chargement non bloquant"," — les textures sont chargées en parallèle via ",[68,127,128],{},"Promise.all",", chaque carte s'initialise dès que ses deux images sont prêtes.",[37,131,132,135,136,139,140,143],{},[29,133,134],{},"Fallback sans WebGL"," — si ",[68,137,138],{},"getContext('webgl')"," renvoie null, on tombe sur un simple ",[68,141,142],{},"drawImage"," 2D de l'image de départ.",[21,145,147],{"id":146},"pile","Pile",[14,149,150,151,158],{},"WebGL 1 brut (pas de lib), ES modules, Vue 3 pour l'intégration dans le portfolio. Images : photos de paysages de montagne libres de droits ",[152,153,157],"a",{"href":154,"rel":155},"https:\u002F\u002Funsplash.com",[156],"nofollow","Unsplash",", redimensionnées en 1024 × 1280 (ratio 4:5).",{"title":160,"searchDepth":161,"depth":161,"links":162},"",2,[163,164,165],{"id":23,"depth":161,"text":24},{"id":57,"depth":161,"text":58},{"id":146,"depth":161,"text":147},"Trois paysages de montagne se déforment, se décalent en RGB et se dissolvent vers une image d'arrivée quand le curseur les frôle.","md",{"tags":169},[170,171,172,173],"webgl","glsl","shader","interaction",true,"\u002Fcases\u002Fshader-image-survol",{"title":5,"description":166},"cases\u002Fshader-image-survol","JbRDX_XJBGQ7d9KCfmHuaDyzZ1K4q5nHjW1h_5DOR2I",1794436389541]