├── .DS_Store ├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── dist ├── .DS_Store ├── hover-effect.es.js ├── hover-effect.es.js.map ├── hover-effect.js ├── hover-effect.js.map ├── hover-effect.modern.mjs ├── hover-effect.modern.mjs.map ├── hover-effect.umd.js └── hover-effect.umd.js.map ├── example ├── .DS_Store ├── css │ └── base.css ├── favicon.ico ├── img │ ├── Img1.jpg │ ├── Img10.jpg │ ├── Img11.jpg │ ├── Img12.jpg │ ├── Img13.jpg │ ├── Img14.jpg │ ├── Img15.jpg │ ├── Img16.jpg │ ├── Img17.jpg │ ├── Img18.jpg │ ├── Img19.jpg │ ├── Img2.jpg │ ├── Img20.jpg │ ├── Img21.jpg │ ├── Img22.jpg │ ├── Img23.jpg │ ├── Img24.jpg │ ├── Img25.jpg │ ├── Img26.jpg │ ├── Img3.jpg │ ├── Img4.jpg │ ├── Img5.jpg │ ├── Img6.jpg │ ├── Img7.jpg │ ├── Img8.jpg │ ├── Img9.jpg │ └── displacement │ │ ├── 1.jpg │ │ ├── 10.jpg │ │ ├── 11.jpg │ │ ├── 12.jpg │ │ ├── 13.jpg │ │ ├── 14.jpg │ │ ├── 15.jpg │ │ ├── 16.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.jpg │ │ ├── 7.jpg │ │ ├── 8.jpg │ │ └── 9.jpg ├── index.html └── js │ ├── .DS_Store │ ├── gsap.min.js │ ├── imagesloaded.pkgd.min.js │ └── three.min.js ├── gifs ├── 1.gif ├── 2.gif └── alex_brown.gif ├── images ├── balloon.jpg ├── balloon2.jpg ├── dot.jpg ├── fluid.jpg ├── heightMap.png ├── hover.jpg ├── ice.jpg ├── ice2.jpg ├── ny-info.jpg ├── ny.jpg ├── ramen.jpg ├── rect.png ├── strip.png ├── stripe1.png ├── stripe1mul.png ├── submit.jpg └── submit.png ├── index.html ├── package-lock.json ├── package.json ├── readme.md ├── src └── hover-effect.js └── videos ├── .DS_Store ├── video.mp4 └── video2.mp4 /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robin-dela/hover-effect/1938cbff22a0379c5c5f17355550961374e7754c/.DS_Store -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | liberapay: robin-dela 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Robin Delaporte, Aarni Koskela 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robin-dela/hover-effect/1938cbff22a0379c5c5f17355550961374e7754c/dist/.DS_Store -------------------------------------------------------------------------------- /dist/hover-effect.es.js: -------------------------------------------------------------------------------- 1 | import*as e from"three";import t from"gsap";function i(i){function n(){for(var e=0;e 2 | 3 | 4 | 5 | 6 | Distortion Hover Effect | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 29 |
30 |
Some message for mobile if needed.
31 |
32 |
33 |
34 | 39 |

Distortion Hover Effect

40 |
41 |
42 |
43 |
44 | Image 45 | Image 46 |
47 |
48 | California 49 |

Jumping Around

50 |

51 | California's last empty jump spots 52 | Discover more 53 |

54 |
55 |
56 |
57 |
58 | Image 59 | Image 60 |
61 |
62 | Italy 63 |

Calm Serenity

64 |

65 | Italy's secret meadows and fields 66 | Check them out 67 |

68 |
69 |
70 |
71 |
72 | 77 |

Qualm Inspiration for Everybody

78 |

Muse about, something incredible is waiting to be known, courage of our questions tesseract hearts of the stars great turbulent clouds the only home.

79 | Read more 80 |
81 |
82 |
83 |
84 | 88 |

Bangkok's Hidden Foodstalls

89 |

Tingling of the spine, network of wormholes preserve and cherish that pale blue dot cosmic ocean encyclopaedia galactica.

90 | Read more 91 |
92 |
93 |
94 |
95 | Image 96 | Image Alt 97 |
98 |
99 | Sweden 100 |

Build it forever

101 |

102 | Sweden's famous furniture 103 | Discover more 104 |

105 |
106 |
107 |
108 |
109 | Image 110 | Image Alt 111 |
112 |
113 | Spain 114 |

Water Wonders

115 |

116 | Spain's amazingly colorful lakes 117 | Check them out 118 |

119 |
120 |
121 |
122 |
123 | 128 |

The Rise of Moroccan Reggae

129 |

Concept of the number one two ghostly white figures in coveralls and helmets are soflty dancing.

130 | Read more 131 |
132 |
133 |
134 |
135 | 140 |

Stories from Landlocked Lands

141 |

Drake Equation science Hypatia the ash of stellar alchemy. Circumnavigated gathered by gravity.

142 | Read more 143 |
144 |
145 |
146 |
147 | Image 148 | Image Alt 149 |
150 |
151 | Germany 152 |

Holy House

153 |

154 | Germany's amazing architecture 155 | Check it out 156 |

157 |
158 |
159 |
160 |
161 | Image 162 | Image Alt 163 |
164 |
165 | Denmark 166 |

Future Proof

167 |

168 | Building for the future 169 | Learn more 170 |

171 |
172 |
173 |
174 |
175 | 180 |

China's Last Wild Bears

181 |

Descended from astronomers emerged into consciousness? Encyclopaedia galactica. Extraordinary claims require extraordinary.

182 | Read more 183 |
184 |
185 | 186 |
187 |
188 | 193 |

Travel Tips for South Africa

194 |

Venture something incredible is waiting to be known Orion's sword white dwarf rogue tendrils of gossamer.

195 | Read more 196 |
197 |
198 |
199 |
200 | Image 201 | Image Alt 202 |
203 |
204 | Florida 205 |

Cool and Fresh

206 |

207 | Discover Florida's best beaches 208 | Check them out 209 |

210 |
211 |
212 |
213 |
214 | Image 215 | Image Alt 216 |
217 |
218 | Europe 219 |

My Cup of Coffee

220 |

221 | The best coffe houses in Europe 222 | Check them out 223 |

224 |
225 |
226 |
227 |
228 | 233 |

Cold Winters and Warm Hearts

234 |

Drake Equation science Hypatia the ash of stellar alchemy. Circumnavigated gathered.

235 | Read more 236 |
237 |
238 |
239 |
240 | 245 |

Polka Dots Everywhere

246 |

Quasar billions upon billions rich in heavy atoms the only home we've ever known Cambrian explosion cosmic fugue? Galaxies, at the edge of forever.

247 | Read more 248 |
249 |
250 |
251 |
252 | Image 253 | Image Alt 254 |
255 |
256 | Bulgaria 257 |

Doors and Rooftops

258 |

259 | Experience fantastic buildings 260 | Check them out 261 |

262 |
263 |
264 |
265 |
266 | Image 267 | Image Alt 268 |
269 |
270 | France 271 |

French Geometry

272 |

273 | France's geometric wonders 274 | Check them out 275 |

276 |
277 |
278 |
279 |
280 | 285 |

What Rudolf Steiner Envisioned

286 |

Drake Equation science Hypatia the ash of stellar alchemy. Circumnavigated gathered.

287 | Read more 288 |
289 |
290 |
291 |
292 | 297 |

More on Dracula's Heritage

298 |

Emerged into consciousness extraplanetary, a still more glorious dawn awaits, Orion's sword network of wormholes vanquish the impossible the sky.

299 | Read more 300 |
301 |
302 |
303 |
304 | Image 305 | Image Alt 306 |
307 |
308 | Dublin 309 |

Facades and Bikes

310 |

311 | The parking habits of the Irish 312 | Read more 313 |

314 |
315 |
316 |
317 |
318 | 319 | 320 | 321 | 322 | 342 | 343 | 344 | -------------------------------------------------------------------------------- /example/js/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robin-dela/hover-effect/1938cbff22a0379c5c5f17355550961374e7754c/example/js/.DS_Store -------------------------------------------------------------------------------- /example/js/gsap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * GSAP 3.11.4 3 | * https://greensock.com 4 | * 5 | * @license Copyright 2022, GreenSock. All rights reserved. 6 | * Subject to the terms at https://greensock.com/standard-license or for Club GreenSock members, the agreement issued with that membership. 7 | * @author: Jack Doyle, jack@greensock.com 8 | */ 9 | 10 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).window=t.window||{})}(this,function(e){"use strict";function _inheritsLoose(t,e){t.prototype=Object.create(e.prototype),(t.prototype.constructor=t).__proto__=e}function _assertThisInitialized(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function r(t){return"string"==typeof t}function s(t){return"function"==typeof t}function t(t){return"number"==typeof t}function u(t){return void 0===t}function v(t){return"object"==typeof t}function w(t){return!1!==t}function x(){return"undefined"!=typeof window}function y(t){return s(t)||r(t)}function P(t){return(i=yt(t,ot))&&Ce}function Q(t,e){return console.warn("Invalid property",t,"set to",e,"Missing plugin? gsap.registerPlugin()")}function R(t,e){return!e&&console.warn(t)}function S(t,e){return t&&(ot[t]=e)&&i&&(i[t]=e)||ot}function T(){return 0}function ea(t){var e,r,i=t[0];if(v(i)||s(i)||(t=[t]),!(e=(i._gsap||{}).harness)){for(r=gt.length;r--&&!gt[r].targetTest(i););e=gt[r]}for(r=t.length;r--;)t[r]&&(t[r]._gsap||(t[r]._gsap=new jt(t[r],e)))||t.splice(r,1);return t}function fa(t){return t._gsap||ea(Ot(t))[0]._gsap}function ga(t,e,r){return(r=t[e])&&s(r)?t[e]():u(r)&&t.getAttribute&&t.getAttribute(e)||r}function ha(t,e){return(t=t.split(",")).forEach(e)||t}function ia(t){return Math.round(1e5*t)/1e5||0}function ja(t){return Math.round(1e7*t)/1e7||0}function ka(t,e){var r=e.charAt(0),i=parseFloat(e.substr(2));return t=parseFloat(t),"+"===r?t+i:"-"===r?t-i:"*"===r?t*i:t/i}function la(t,e){for(var r=e.length,i=0;t.indexOf(e[i])<0&&++ia;)s=s._prev;return s?(e._next=s._next,s._next=e):(e._next=t[r],t[r]=e),e._next?e._next._prev=e:t[i]=e,e._prev=s,e.parent=e._dp=t,e}function ya(t,e,r,i){void 0===r&&(r="_first"),void 0===i&&(i="_last");var n=e._prev,a=e._next;n?n._next=a:t[r]===e&&(t[r]=a),a?a._prev=n:t[i]===e&&(t[i]=n),e._next=e._prev=e.parent=null}function za(t,e){!t.parent||e&&!t.parent.autoRemoveChildren||t.parent.remove(t),t._act=0}function Aa(t,e){if(t&&(!e||e._end>t._dur||e._start<0))for(var r=t;r;)r._dirty=1,r=r.parent;return t}function Ca(t,e,r,i){return t._startAt&&(B?t._startAt.revert(ht):t.vars.immediateRender&&!t.vars.autoRevert||t._startAt.render(e,!0,i))}function Ea(t){return t._repeat?Tt(t._tTime,t=t.duration()+t._rDelay)*t:0}function Ga(t,e){return(t-e._start)*e._ts+(0<=e._ts?0:e._dirty?e.totalDuration():e._tDur)}function Ha(t){return t._end=ja(t._start+(t._tDur/Math.abs(t._ts||t._rts||V)||0))}function Ia(t,e){var r=t._dp;return r&&r.smoothChildTiming&&t._ts&&(t._start=ja(r._time-(0V)&&e.render(r,!0)),Aa(t,e)._dp&&t._initted&&t._time>=t._dur&&t._ts){if(t._dur(n=Math.abs(n))&&(a=i,o=n);return a}function tb(t){return za(t),t.scrollTrigger&&t.scrollTrigger.kill(!!B),t.progress()<1&&Ct(t,"onInterrupt"),t}function yb(t,e,r){return(6*(t+=t<0?1:1>16,e>>8&At,e&At]:0:St.black;if(!p){if(","===e.substr(-1)&&(e=e.substr(0,e.length-1)),St[e])p=St[e];else if("#"===e.charAt(0)){if(e.length<6&&(e="#"+(n=e.charAt(1))+n+(a=e.charAt(2))+a+(s=e.charAt(3))+s+(5===e.length?e.charAt(4)+e.charAt(4):"")),9===e.length)return[(p=parseInt(e.substr(1,6),16))>>16,p>>8&At,p&At,parseInt(e.substr(7),16)/255];p=[(e=parseInt(e.substr(1),16))>>16,e>>8&At,e&At]}else if("hsl"===e.substr(0,3))if(p=d=e.match(tt),r){if(~e.indexOf("="))return p=e.match(et),i&&p.length<4&&(p[3]=1),p}else o=+p[0]%360/360,u=p[1]/100,n=2*(h=p[2]/100)-(a=h<=.5?h*(u+1):h+u-h*u),3=U?u.endTime(!1):t._dur;return r(e)&&(isNaN(e)||e in o)?(a=e.charAt(0),s="%"===e.substr(-1),n=e.indexOf("="),"<"===a||">"===a?(0<=n&&(e=e.replace(/=/,"")),("<"===a?u._start:u.endTime(0<=u._repeat))+(parseFloat(e.substr(1))||0)*(s?(n<0?u:i).totalDuration()/100:1)):n<0?(e in o||(o[e]=h),o[e]):(a=parseFloat(e.charAt(n-1)+e.substr(n+1)),s&&i&&(a=a/100*($(i)?i[0]:i).totalDuration()),1=r&&te)return i;i=i._next}else for(i=t._last;i&&i._start>=r;){if("isPause"===i.data&&i._start=n._start)&&n._ts&&h!==n){if(n.parent!==this)return this.render(t,e,r);if(n.render(0=this.totalDuration()||!v&&_)&&(f!==this._start&&Math.abs(l)===Math.abs(this._ts)||this._lock||(!t&&g||!(v===m&&0=i&&(a instanceof Gt?e&&n.push(a):(r&&n.push(a),t&&n.push.apply(n,a.getChildren(!0,e,r)))),a=a._next;return n},e.getById=function getById(t){for(var e=this.getChildren(1,1,1),r=e.length;r--;)if(e[r].vars.id===t)return e[r]},e.remove=function remove(t){return r(t)?this.removeLabel(t):s(t)?this.killTweensOf(t):(ya(this,t),t===this._recent&&(this._recent=this._last),Aa(this))},e.totalTime=function totalTime(t,e){return arguments.length?(this._forcing=1,!this._dp&&this._ts&&(this._start=ja(Et.time-(0r:!r||s.isActive())&&n.push(s):(i=s.getTweensOf(a,r)).length&&n.push.apply(n,i),s=s._next;return n},e.tweenTo=function tweenTo(t,e){e=e||{};var r,i=this,n=xt(i,t),a=e.startAt,s=e.onStart,o=e.onStartParams,u=e.immediateRender,h=Gt.to(i,qa({ease:e.ease||"none",lazy:!1,immediateRender:!1,time:n,overwrite:"auto",duration:e.duration||Math.abs((n-(a&&"time"in a?a.time:i._time))/i.timeScale())||V,onStart:function onStart(){if(i.pause(),!r){var t=e.duration||Math.abs((n-(a&&"time"in a?a.time:i._time))/i.timeScale());h._dur!==t&&Ra(h,t,0,1).render(h._time,!0,!0),r=1}s&&s.apply(h,o||[])}},e));return u?h.render(0):h},e.tweenFromTo=function tweenFromTo(t,e,r){return this.tweenTo(e,qa({startAt:{time:xt(this,t)}},r))},e.recent=function recent(){return this._recent},e.nextLabel=function nextLabel(t){return void 0===t&&(t=this._time),rb(this,xt(this,t))},e.previousLabel=function previousLabel(t){return void 0===t&&(t=this._time),rb(this,xt(this,t),1)},e.currentLabel=function currentLabel(t){return arguments.length?this.seek(t,!0):this.previousLabel(this._time+V)},e.shiftChildren=function shiftChildren(t,e,r){void 0===r&&(r=0);for(var i,n=this._first,a=this.labels;n;)n._start>=r&&(n._start+=t,n._end+=t),n=n._next;if(e)for(i in a)a[i]>=r&&(a[i]+=t);return Aa(this)},e.invalidate=function invalidate(t){var e=this._first;for(this._lock=0;e;)e.invalidate(t),e=e._next;return i.prototype.invalidate.call(this,t)},e.clear=function clear(t){void 0===t&&(t=!0);for(var e,r=this._first;r;)e=r._next,this.remove(r),r=e;return this._dp&&(this._time=this._tTime=this._pTime=0),t&&(this.labels={}),Aa(this)},e.totalDuration=function totalDuration(t){var e,r,i,n=0,a=this,s=a._last,o=U;if(arguments.length)return a.timeScale((a._repeat<0?a.duration():a.totalDuration())/(a.reversed()?-t:t));if(a._dirty){for(i=a.parent;s;)e=s._prev,s._dirty&&s.totalDuration(),o<(r=s._start)&&a._sort&&s._ts&&!a._lock?(a._lock=1,Ka(a,s,r-s._delay,1)._lock=0):o=r,r<0&&s._ts&&(n-=r,(!i&&!a._dp||i&&i.smoothChildTiming)&&(a._start+=r/a._ts,a._time-=r,a._tTime-=r),a.shiftChildren(-r,!1,-Infinity),o=0),s._end>n&&s._ts&&(n=s._end),s=e;Ra(a,a===L&&a._time>n?a._time:n,1,1),a._dirty=0}return a._tDur},Timeline.updateRoot=function updateRoot(t){if(L._ts&&(na(L,Ga(t,L)),f=Et.frame),Et.frame>=mt){mt+=j.autoSleep||120;var e=L._first;if((!e||!e._ts)&&j.autoSleep&&Et._listeners.length<2){for(;e&&!e._ts;)e=e._next;e||Et.sleep()}}},Timeline}(qt);qa(Ut.prototype,{_lock:0,_hasPause:0,_forcing:0});function _b(t,e,i,n,a,o){var u,h,l,f;if(pt[t]&&!1!==(u=new pt[t]).init(a,u.rawVars?e[t]:function _processVars(t,e,i,n,a){if(s(t)&&(t=Qt(t,a,e,i,n)),!v(t)||t.style&&t.nodeType||$(t)||J(t))return r(t)?Qt(t,a,e,i,n):t;var o,u={};for(o in t)u[o]=Qt(t[o],a,e,i,n);return u}(e[t],n,a,o,i),i,n,o)&&(i._pt=h=new pe(i._pt,a,t,0,1,u.render,u,0,u.priority),i!==c))for(l=i._ptLookup[i._targets.indexOf(a)],f=u._props.length;f--;)l[u._props[f]]=h;return u}function fc(t,r,e,i){var n,a,s=r.ease||i||"power1.inOut";if($(r))a=e[t]||(e[t]=[]),r.forEach(function(t,e){return a.push({t:e/(r.length-1)*100,v:t,e:s})});else for(n in r)a=e[n]||(e[n]=[]),"ease"===n||a.push({t:parseFloat(t),v:r[n],e:s})}var Vt,Wt,Xt=function _addPropTween(t,e,i,n,a,o,u,h,l,f){s(n)&&(n=n(a||0,t,o));var c,d=t[e],p="get"!==i?i:s(d)?l?t[e.indexOf("set")||!s(t["get"+e.substr(3)])?e:"get"+e.substr(3)](l):t[e]():d,_=s(d)?l?ee:$t:Jt;if(r(n)&&(~n.indexOf("random(")&&(n=ob(n)),"="===n.charAt(1)&&(!(c=ka(p,n)+(Ya(p)||0))&&0!==c||(n=c))),!f||p!==n||Wt)return isNaN(p*n)||""===n?(d||e in t||Q(e,n),function _addComplexStringPropTween(t,e,r,i,n,a,s){var o,u,h,l,f,c,d,p,_=new pe(this._pt,t,e,0,1,se,null,n),m=0,g=0;for(_.b=r,_.e=i,r+="",(d=~(i+="").indexOf("random("))&&(i=ob(i)),a&&(a(p=[r,i],t,e),r=p[0],i=p[1]),u=r.match(it)||[];o=it.exec(i);)l=o[0],f=i.substring(m,o.index),h?h=(h+1)%5:"rgba("===f.substr(-5)&&(h=1),l!==u[g++]&&(c=parseFloat(u[g-1])||0,_._pt={_next:_._pt,p:f||1===g?f:",",s:c,c:"="===l.charAt(1)?ka(c,l)-c:parseFloat(l)-c,m:h&&h<4?Math.round:0},m=it.lastIndex);return _.c=m")}),s.duration();else{for(l in u={},x)"ease"===l||"easeEach"===l||fc(l,x[l],u,x.easeEach);for(l in u)for(A=u[l].sort(function(t,e){return t.t-e.t}),o=E=0;o=t._tDur||e<0)&&t.ratio===u&&(u&&za(t,1),r||B||(Ct(t,u?"onComplete":"onReverseComplete",!0),t._prom&&t._prom()))}else t._zTime||(t._zTime=e)}(this,t,e,r);return this},e.targets=function targets(){return this._targets},e.invalidate=function invalidate(t){return t&&this.vars.runBackwards||(this._startAt=0),this._pt=this._op=this._onUpdate=this._lazy=this.ratio=0,this._ptLookup=[],this.timeline&&this.timeline.invalidate(t),z.prototype.invalidate.call(this,t)},e.resetTo=function resetTo(t,e,r,i){d||Et.wake(),this._ts||this.play();var n,a=Math.min(this._dur,(this._dp._time-this._start)*this._ts);return this._initted||Ht(this,a),n=this._ease(a/this._dur),function _updatePropTweens(t,e,r,i,n,a,s){var o,u,h,l,f=(t._pt&&t._ptCache||(t._ptCache={}))[e];if(!f)for(f=t._ptCache[e]=[],h=t._ptLookup,l=t._targets.length;l--;){if((o=h[l][e])&&o.d&&o.d._pt)for(o=o.d._pt;o&&o.p!==e&&o.fp!==e;)o=o._next;if(!o)return Wt=1,t.vars[e]="+=0",Ht(t,s),Wt=0,1;f.push(o)}for(l=f.length;l--;)(o=(u=f[l])._pt||u).s=!i&&0!==i||n?o.s+(i||0)+a*o.c:i,o.c=r-o.s,u.e&&(u.e=ia(r)+Ya(u.e)),u.b&&(u.b=o.s+Ya(u.b))}(this,t,e,r,i,n,a)?this.resetTo(t,e,r,i):(Ia(this,0),this.parent||xa(this._dp,this,"_first","_last",this._dp._sort?"_start":0),this.render(0))},e.kill=function kill(t,e){if(void 0===e&&(e="all"),!(t||e&&"all"!==e))return this._lazy=this._pt=0,this.parent?tb(this):this;if(this.timeline){var i=this.timeline.totalDuration();return this.timeline.killTweensOf(t,e,Vt&&!0!==Vt.vars.overwrite)._first||tb(this),this.parent&&i!==this.timeline.totalDuration()&&Ra(this,this._dur*this.timeline._tDur/i,0,1),this}var n,a,s,o,u,h,l,f=this._targets,c=t?Ot(t):f,d=this._ptLookup,p=this._pt;if((!e||"all"===e)&&function _arraysMatch(t,e){for(var r=t.length,i=r===e.length;i&&r--&&t[r]===e[r];);return r<0}(f,c))return"all"===e&&(this._pt=0),tb(this);for(n=this._op=this._op||[],"all"!==e&&(r(e)&&(u={},ha(e,function(t){return u[t]=1}),e=u),e=function _addAliasesToVars(t,e){var r,i,n,a,s=t[0]?fa(t[0]).harness:0,o=s&&s.aliases;if(!o)return e;for(i in r=yt({},e),o)if(i in r)for(n=(a=o[i].split(",")).length;n--;)r[a[n]]=r[i];return r}(f,e)),l=f.length;l--;)if(~c.indexOf(f[l]))for(u in a=d[l],"all"===e?(n[l]=e,o=a,s={}):(s=n[l]=n[l]||{},o=e),o)(h=a&&a[u])&&("kill"in h.d&&!0!==h.d.kill(u)||ya(this,h,"_pt"),delete a[u]),"all"!==s&&(s[u]=1);return this._initted&&!this._pt&&p&&tb(this),this},Tween.to=function to(t,e,r){return new Tween(t,e,r)},Tween.from=function from(t,e){return Va(1,arguments)},Tween.delayedCall=function delayedCall(t,e,r,i){return new Tween(e,0,{immediateRender:!1,lazy:!1,overwrite:!1,delay:t,onComplete:e,onReverseComplete:e,onCompleteParams:r,onReverseCompleteParams:r,callbackScope:i})},Tween.fromTo=function fromTo(t,e,r){return Va(2,arguments)},Tween.set=function set(t,e){return e.duration=0,e.repeatDelay||(e.repeat=0),new Tween(t,e)},Tween.killTweensOf=function killTweensOf(t,e,r){return L.killTweensOf(t,e,r)},Tween}(qt);qa(Gt.prototype,{_targets:[],_lazy:0,_startAt:0,_op:0,_onInit:0}),ha("staggerTo,staggerFrom,staggerFromTo",function(r){Gt[r]=function(){var t=new Ut,e=Mt.call(arguments,0);return e.splice("staggerFromTo"===r?5:4,0,0),t[r].apply(t,e)}});function nc(t,e,r){return t.setAttribute(e,r)}function vc(t,e,r,i){i.mSet(t,e,i.m.call(i.tween,r,i.mt),i)}var Jt=function _setterPlain(t,e,r){return t[e]=r},$t=function _setterFunc(t,e,r){return t[e](r)},ee=function _setterFuncWithParam(t,e,r,i){return t[e](i.fp,r)},re=function _getSetter(t,e){return s(t[e])?$t:u(t[e])&&t.setAttribute?nc:Jt},ne=function _renderPlain(t,e){return e.set(e.t,e.p,Math.round(1e6*(e.s+e.c*t))/1e6,e)},ae=function _renderBoolean(t,e){return e.set(e.t,e.p,!!(e.s+e.c*t),e)},se=function _renderComplexString(t,e){var r=e._pt,i="";if(!t&&e.b)i=e.b;else if(1===t&&e.e)i=e.e;else{for(;r;)i=r.p+(r.m?r.m(r.s+r.c*t):Math.round(1e4*(r.s+r.c*t))/1e4)+i,r=r._next;i+=e.c}e.set(e.t,e.p,i,e)},oe=function _renderPropTweens(t,e){for(var r=e._pt;r;)r.r(t,r.d),r=r._next},le=function _addPluginModifier(t,e,r,i){for(var n,a=this._pt;a;)n=a._next,a.p===i&&a.modifier(t,e,r),a=n},fe=function _killPropTweensOf(t){for(var e,r,i=this._pt;i;)r=i._next,i.p===t&&!i.op||i.op===t?ya(this,i,"_pt"):i.dep||(e=1),i=r;return!e},de=function _sortPropTweensByPriority(t){for(var e,r,i,n,a=t._pt;a;){for(e=a._next,r=i;r&&r.pr>a.pr;)r=r._next;(a._prev=r?r._prev:n)?a._prev._next=a:i=a,(a._next=r)?r._prev=a:n=a,a=e}t._pt=i},pe=(PropTween.prototype.modifier=function modifier(t,e,r){this.mSet=this.mSet||this.set,this.set=vc,this.m=t,this.mt=r,this.tween=e},PropTween);function PropTween(t,e,r,i,n,a,s,o,u){this.t=e,this.s=i,this.c=n,this.p=r,this.r=a||ne,this.d=s||this,this.set=o||Jt,this.pr=u||0,(this._next=t)&&(t._prev=this)}ha(vt+"parent,duration,ease,delay,overwrite,runBackwards,startAt,yoyo,immediateRender,repeat,repeatDelay,data,paused,reversed,lazy,callbackScope,stringFilter,id,yoyoEase,stagger,inherit,repeatRefresh,keyframes,autoRevert,scrollTrigger",function(t){return ft[t]=1}),ot.TweenMax=ot.TweenLite=Gt,ot.TimelineLite=ot.TimelineMax=Ut,L=new Ut({sortChildren:!1,defaults:q,autoRemoveChildren:!0,id:"root",smoothChildTiming:!0}),j.stringFilter=Eb;function Cc(t){return(Te[t]||we).map(function(t){return t()})}function Dc(){var t=Date.now(),o=[];2 2 | 3 | 4 | 5 | title 6 | 58 | 59 | 60 | 61 | 62 | 63 |
64 |
65 | 66 | 67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | MY BUTTON 75 |
76 |
77 |
78 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hover-effect", 3 | "version": "1.2.0", 4 | "source": "src/hover-effect.js", 5 | "module": "dist/hover-effect.es.js", 6 | "main": "dist/hover-effect.js", 7 | "umd:main": "dist/hover-effect.umd.js", 8 | "devDependencies": { 9 | "microbundle": "^0.15.1", 10 | "prettier": "^2.8.4", 11 | "uglify-es": "^3.3.9" 12 | }, 13 | "scripts": { 14 | "build": "microbundle build --globals three=THREE,gsap=gsap", 15 | "watch": "microbundle watch --globals three=THREE,gsap=gsap", 16 | "publish": "npm publish --access public", 17 | "minify": "uglifyjs --mangle --compress -- js/hover.js > js/hover.min.js", 18 | "prettify": "prettier --trailing-comma=es5 --single-quote --print-width=120 --write ./js/hover.js" 19 | }, 20 | "files": [ 21 | "dist" 22 | ], 23 | "dependencies": { 24 | "gsap": "^3.11.4", 25 | "three": "^0.149.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Hover effect 2 | 3 | Javascript library to draw and animate images on hover. 4 | 5 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ZGDNS5D28SFWQ) 6 | 7 | [**DEMO**](https://tympanus.net/Development/DistortionHoverEffect/) 8 | 9 | [**ARTICLE**](https://tympanus.net/codrops/2018/04/10/webgl-distortion-hover-effects/) 10 | 11 | ## Example 12 |

13 | example 1 14 | example 2 15 |

16 | 17 | ## Use locally 18 | To load the images you'll need to view the demo via a web server, simply go to the demo's folder location and type `python -m SimpleHTTPServer 8000` in your terminal. Then access the demo in your browser by typing: `localhost:8000` 19 | 20 | ## Basic usage 21 | 22 | This helper needs [Three.js](https://threejs.org) and [gsap](https://greensock.com/) to do the transition, so you need to include it before this little helper. 23 | 24 | Then you only need a `div` element in HTML to start animating things with a piece of code like this: 25 | 26 | ```html 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 44 | ``` 45 | 46 | ## Node JS usage 47 | 48 | This helper can also be used in node js environments. Three.js and TweenMax scripts are included as dependencies in the package so you don't need to manually include them. 49 | 50 | ### Install 51 | 52 | ``` 53 | npm install hover-effect 54 | ``` 55 | 56 | ### Import 57 | 58 | ```js 59 | import hoverEffect from 'hover-effect' 60 | ``` 61 | 62 | ### Init 63 | 64 | Initialize just as you would in the basic usage example above. 65 | 66 | ## Options 67 | 68 | ### Mandatory parameters 69 | 70 | | Name | Type | Default | Description | 71 | |-------------------------|-----------------|-----------------|-------------| 72 | |`parent` | `Dom element` | `null` | The DOM element where the animation will be injected. The images of the animation will take the parent's size. | 73 | |`image1` | `Image` | `null` | The first `Image` of the animation. | 74 | |`image2` | `Image` | `null` | The second `Image` of the animation. | 75 | |`displacementImage` | `Image` | `null` | The `Image` used to do the transition between the 2 main images. | 76 | 77 | ### Optional parameters 78 | 79 | | Name | Type | Default | Description | 80 | |-------------------------|-----------|-----------------|-------------| 81 | |`intensity` | `Float` | `1` | Used to determine the intensity of the distortion effect. 0 is no effect and 1 is full distortion. | 82 | |`intensity1` | `Float` | `intensity` | Overrides the distortion intensity of the first image. | 83 | |`intensity2` | `Float` | `intensity` | Overrides the distortion intensity of the second image. | 84 | |`angle` | `Float` | `Math.PI / 4` | Angle of the distortion effect in Radians. Defaults to Pi / 4 (45 degrees). | 85 | |`angle1` | `Float` | `angle` | Overrides the distortion angle for the first image. | 86 | |`angle2` | `Float` | `-angle * 3` | Overrides the distortion angle for the second image. | 87 | |`speedIn` | `Float` | `1.6` | Speed of the inbound animation (in seconds). | 88 | |`speedOut` | `Float` | `1.2` | Speed of the outbound animation (in seconds). | 89 | |`hover` | `Boolean` | `true` | if set to false the animation will not be triggered on hover (see `next` and `previous` function to interact) | 90 | |`easing` | `String` | `Expo.easeOut` | Easing of the transition, see [greensock easing](https://greensock.com/ease-visualizer)| 91 | |`video` | `Boolean` | `false` | Defines if you want to use videos instead of images (note: you need 2 videos, it doesn't work with one image and one video.) | 92 | |`imagesRatio` | `Float` | `1` | Specify a value if you want a `background: cover` type of behaviour, otherwise it will apply a square aspect ratio. usage: `image height / image width` example: `1080 / 1920` | 93 | 94 | ### Methods 95 | 96 | | Name | Description | 97 | |-------------------------|-------------------------| 98 | |`next` | Transition to the second image. | 99 | |`previous` | Transition to the first image. | 100 | 101 | ## Credits 102 | Thanks to : 103 | - [Codrops](https://twitter.com/crnacura) for the creation of the example 104 | - [Aarni Koskela](https://github.com/akx/) for the improvements 105 | - [Celso White](https://github.com/celsowhite) for the multiple module formats 106 | 107 | ## Made with it 108 |

109 | Alex Brown demo 110 |

111 | 112 | - [Codepen demo](https://codepen.io/alxrbrown/pen/GxVQLr) and [Medium article](https://medium.com/@alxrbrown/create-a-distortion-hover-effect-using-webgl-32fc1ab50d24) by Alex Brown 113 | - [https://stimmt.digital/en/](https://stimmt.digital/en/) 114 | - [https://www.fabiofantolino.com/en](https://www.fabiofantolino.com/en) 115 | - [Youtube tutorial](https://www.youtube.com/watch?v=o0zlX1E7l0A) 116 | - [https://www.youtube.com/watch?v=9kcOQdJHyIo](https://www.youtube.com/watch?v=9kcOQdJHyIo) 117 | - [https://www.estudionk.com/en](https://www.estudionk.com/en) 118 | - [https://github.com/AlbanCrepel/vue-displacement-slideshow](https://github.com/AlbanCrepel/vue-displacement-slideshow) 119 | - [https://digitalpresent.io/about](https://digitalpresent.io/about) 120 | - [https://www.couleecreative.com/](https://www.couleecreative.com/) 121 | - [https://two.zero.nyc/](https://two.zero.nyc/) 122 | - [https://www.danilodemarco.com/](https://www.danilodemarco.com/) 123 | - [https://lsce.com/](https://lsce.com/) 124 | - [http://vadimtyurin.com/](http://vadimtyurin.com/) 125 | -------------------------------------------------------------------------------- /src/hover-effect.js: -------------------------------------------------------------------------------- 1 | import * as THREE from "three"; 2 | import gsap from "gsap"; 3 | 4 | export default function(opts) { 5 | var vertex = ` 6 | varying vec2 vUv; 7 | void main() { 8 | vUv = uv; 9 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 10 | } 11 | `; 12 | 13 | var fragment = ` 14 | varying vec2 vUv; 15 | 16 | uniform float dispFactor; 17 | uniform float dpr; 18 | uniform sampler2D disp; 19 | 20 | uniform sampler2D texture1; 21 | uniform sampler2D texture2; 22 | uniform float angle1; 23 | uniform float angle2; 24 | uniform float intensity1; 25 | uniform float intensity2; 26 | uniform vec4 res; 27 | uniform vec2 parent; 28 | 29 | mat2 getRotM(float angle) { 30 | float s = sin(angle); 31 | float c = cos(angle); 32 | return mat2(c, -s, s, c); 33 | } 34 | 35 | void main() { 36 | vec4 disp = texture2D(disp, vUv); 37 | vec2 dispVec = vec2(disp.r, disp.g); 38 | 39 | vec2 uv = 0.5 * gl_FragCoord.xy / (res.xy) ; 40 | vec2 myUV = (uv - vec2(0.5))*res.zw + vec2(0.5); 41 | 42 | 43 | vec2 distortedPosition1 = myUV + getRotM(angle1) * dispVec * intensity1 * dispFactor; 44 | vec2 distortedPosition2 = myUV + getRotM(angle2) * dispVec * intensity2 * (1.0 - dispFactor); 45 | vec4 _texture1 = texture2D(texture1, distortedPosition1); 46 | vec4 _texture2 = texture2D(texture2, distortedPosition2); 47 | gl_FragColor = mix(_texture1, _texture2, dispFactor); 48 | } 49 | `; 50 | 51 | // please respect authorship and do not remove 52 | console.log( 53 | "%c Hover effect by Robin Delaporte: https://github.com/robin-dela/hover-effect ", 54 | "color: #bada55; font-size: 0.8rem" 55 | ); 56 | 57 | function firstDefined() { 58 | for (var i = 0; i < arguments.length; i++) { 59 | if (arguments[i] !== undefined) return arguments[i]; 60 | } 61 | } 62 | 63 | var parent = opts.parent; 64 | var dispImage = opts.displacementImage; 65 | var image1 = opts.image1; 66 | var image2 = opts.image2; 67 | var imagesRatio = firstDefined(opts.imagesRatio, 1.0); 68 | var intensity1 = firstDefined(opts.intensity1, opts.intensity, 1); 69 | var intensity2 = firstDefined(opts.intensity2, opts.intensity, 1); 70 | var commonAngle = firstDefined(opts.angle, Math.PI / 4); // 45 degrees by default, so grayscale images work correctly 71 | var angle1 = firstDefined(opts.angle1, commonAngle); 72 | var angle2 = firstDefined(opts.angle2, -commonAngle * 3); 73 | var speedIn = firstDefined(opts.speedIn, opts.speed, 1.6); 74 | var speedOut = firstDefined(opts.speedOut, opts.speed, 1.2); 75 | var userHover = firstDefined(opts.hover, true); 76 | var easing = firstDefined(opts.easing, "expo.out"); 77 | var video = firstDefined(opts.video, false); 78 | 79 | if (!parent) { 80 | console.warn("Parent missing"); 81 | return; 82 | } 83 | 84 | if (!(image1 && image2 && dispImage)) { 85 | console.warn("One or more images are missing"); 86 | return; 87 | } 88 | 89 | var scene = new THREE.Scene(); 90 | var camera = new THREE.OrthographicCamera( 91 | parent.offsetWidth / -2, 92 | parent.offsetWidth / 2, 93 | parent.offsetHeight / 2, 94 | parent.offsetHeight / -2, 95 | 1, 96 | 1000 97 | ); 98 | 99 | camera.position.z = 1; 100 | 101 | var renderer = new THREE.WebGLRenderer({ 102 | antialias: false, 103 | alpha: true 104 | }); 105 | 106 | renderer.setPixelRatio(2.0); 107 | renderer.setClearColor(0xffffff, 0.0); 108 | renderer.setSize(parent.offsetWidth, parent.offsetHeight); 109 | parent.appendChild(renderer.domElement); 110 | 111 | var render = function() { 112 | // This will be called by the TextureLoader as well as Gsap. 113 | renderer.render(scene, camera); 114 | }; 115 | 116 | var loader = new THREE.TextureLoader(); 117 | loader.crossOrigin = ""; 118 | 119 | var disp = loader.load(dispImage, render); 120 | disp.magFilter = disp.minFilter = THREE.LinearFilter; 121 | 122 | if (video) { 123 | var animate = function() { 124 | requestAnimationFrame(animate); 125 | 126 | renderer.render(scene, camera); 127 | }; 128 | animate(); 129 | 130 | var video = document.createElement("video"); 131 | video.autoplay = true; 132 | video.loop = true; 133 | video.muted = true; 134 | video.src = image1; 135 | video.load(); 136 | 137 | var video2 = document.createElement("video"); 138 | video2.autoplay = true; 139 | video2.loop = true; 140 | video2.muted = true; 141 | video2.src = image2; 142 | video2.load(); 143 | 144 | var texture1 = new THREE.VideoTexture(video); 145 | var texture2 = new THREE.VideoTexture(video2); 146 | texture1.magFilter = texture2.magFilter = THREE.LinearFilter; 147 | texture1.minFilter = texture2.minFilter = THREE.LinearFilter; 148 | 149 | video2.addEventListener( 150 | "loadeddata", 151 | function() { 152 | video2.play(); 153 | 154 | texture2 = new THREE.VideoTexture(video2); 155 | texture2.magFilter = THREE.LinearFilter; 156 | texture2.minFilter = THREE.LinearFilter; 157 | 158 | mat.uniforms.texture2.value = texture2; 159 | }, 160 | false 161 | ); 162 | 163 | video.addEventListener( 164 | "loadeddata", 165 | function() { 166 | video.play(); 167 | 168 | texture1 = new THREE.VideoTexture(video); 169 | 170 | texture1.magFilter = THREE.LinearFilter; 171 | texture1.minFilter = THREE.LinearFilter; 172 | 173 | mat.uniforms.texture1.value = texture1; 174 | }, 175 | false 176 | ); 177 | } else { 178 | var texture1 = loader.load(image1, render); 179 | var texture2 = loader.load(image2, render); 180 | 181 | texture1.magFilter = texture2.magFilter = THREE.LinearFilter; 182 | texture1.minFilter = texture2.minFilter = THREE.LinearFilter; 183 | } 184 | 185 | let a1, a2; 186 | var imageAspect = imagesRatio; 187 | if (parent.offsetHeight / parent.offsetWidth < imageAspect) { 188 | a1 = 1; 189 | a2 = parent.offsetHeight / parent.offsetWidth / imageAspect; 190 | } else { 191 | a1 = (parent.offsetWidth / parent.offsetHeight) * imageAspect; 192 | a2 = 1; 193 | } 194 | 195 | var mat = new THREE.ShaderMaterial({ 196 | uniforms: { 197 | intensity1: { 198 | type: "f", 199 | value: intensity1 200 | }, 201 | intensity2: { 202 | type: "f", 203 | value: intensity2 204 | }, 205 | dispFactor: { 206 | type: "f", 207 | value: 0.0 208 | }, 209 | angle1: { 210 | type: "f", 211 | value: angle1 212 | }, 213 | angle2: { 214 | type: "f", 215 | value: angle2 216 | }, 217 | texture1: { 218 | type: "t", 219 | value: texture1 220 | }, 221 | texture2: { 222 | type: "t", 223 | value: texture2 224 | }, 225 | disp: { 226 | type: "t", 227 | value: disp 228 | }, 229 | res: { 230 | type: "vec4", 231 | value: new THREE.Vector4( 232 | parent.offsetWidth, 233 | parent.offsetHeight, 234 | a1, 235 | a2 236 | ) 237 | }, 238 | dpr: { 239 | type: "f", 240 | value: window.devicePixelRatio 241 | } 242 | }, 243 | 244 | vertexShader: vertex, 245 | fragmentShader: fragment, 246 | transparent: true, 247 | opacity: 1.0 248 | }); 249 | 250 | var geometry = new THREE.PlaneGeometry( 251 | parent.offsetWidth, 252 | parent.offsetHeight, 253 | 1 254 | ); 255 | var object = new THREE.Mesh(geometry, mat); 256 | scene.add(object); 257 | 258 | function transitionIn() { 259 | gsap.to(mat.uniforms.dispFactor, { 260 | duration: speedIn, 261 | value: 1, 262 | ease: easing, 263 | onUpdate: render, 264 | onComplete: render 265 | }); 266 | } 267 | 268 | function transitionOut() { 269 | gsap.to(mat.uniforms.dispFactor, { 270 | duration: speedOut, 271 | value: 0, 272 | ease: easing, 273 | onUpdate: render, 274 | onComplete: render 275 | }); 276 | } 277 | 278 | if (userHover) { 279 | parent.addEventListener("mouseenter", transitionIn); 280 | parent.addEventListener("touchstart", transitionIn); 281 | parent.addEventListener("mouseleave", transitionOut); 282 | parent.addEventListener("touchend", transitionOut); 283 | } 284 | 285 | window.addEventListener("resize", function(e) { 286 | if (parent.offsetHeight / parent.offsetWidth < imageAspect) { 287 | a1 = 1; 288 | a2 = parent.offsetHeight / parent.offsetWidth / imageAspect; 289 | } else { 290 | a1 = (parent.offsetWidth / parent.offsetHeight) * imageAspect; 291 | a2 = 1; 292 | } 293 | object.material.uniforms.res.value = new THREE.Vector4( 294 | parent.offsetWidth, 295 | parent.offsetHeight, 296 | a1, 297 | a2 298 | ); 299 | renderer.setSize(parent.offsetWidth, parent.offsetHeight); 300 | 301 | render(); 302 | }); 303 | 304 | this.next = transitionIn; 305 | this.previous = transitionOut; 306 | } 307 | -------------------------------------------------------------------------------- /videos/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robin-dela/hover-effect/1938cbff22a0379c5c5f17355550961374e7754c/videos/.DS_Store -------------------------------------------------------------------------------- /videos/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robin-dela/hover-effect/1938cbff22a0379c5c5f17355550961374e7754c/videos/video.mp4 -------------------------------------------------------------------------------- /videos/video2.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robin-dela/hover-effect/1938cbff22a0379c5c5f17355550961374e7754c/videos/video2.mp4 --------------------------------------------------------------------------------