├── .editorconfig ├── .gitignore ├── InifniteAutoScrollingGallery ├── 62f64d5233f6333080c87c81a9a35f9d.png ├── images │ ├── demo-1 │ │ ├── 1.jpg │ │ ├── 10.jpg │ │ ├── 11.jpg │ │ ├── 12.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ ├── 6.jpg │ │ ├── 7.jpg │ │ ├── 8.jpg │ │ └── 9.jpg │ ├── demo-2 │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ ├── 6.jpg │ │ └── 7.jpg │ └── grain.png ├── index.html ├── index2.html ├── main.aa1e6c08c8704276560a.js └── main.d263f564555a055f4d35.css ├── LICENSE ├── README.md ├── app ├── demo-1.js ├── demo-1 │ ├── Media.js │ ├── fragment.glsl │ └── vertex.glsl ├── demo-2.js ├── demo-2 │ ├── Media.js │ ├── fragment.glsl │ ├── post.glsl │ └── vertex.glsl ├── index.js └── utils │ └── math.js ├── cover.jpg ├── favicon.ico ├── images ├── demo-1 │ ├── 1.jpg │ ├── 10.jpg │ ├── 11.jpg │ ├── 12.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.jpg ├── demo-2 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ └── 7.jpg └── grain.png ├── index.html ├── index2.html ├── package.json ├── styles ├── base │ ├── base.scss │ ├── frame.scss │ └── loader.scss ├── demos │ ├── demo-1.scss │ └── demo-2.scss ├── index.scss ├── mixins │ └── links.scss └── utils │ └── variables.scss ├── webpack.config.build.js ├── webpack.config.development.js └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /.cache 3 | package-lock.json -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/62f64d5233f6333080c87c81a9a35f9d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/62f64d5233f6333080c87c81a9a35f9d.png -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/1.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/10.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/11.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/12.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/2.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/3.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/4.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/5.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/6.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/7.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/8.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-1/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-1/9.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-2/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-2/1.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-2/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-2/2.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-2/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-2/3.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-2/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-2/4.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-2/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-2/5.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-2/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-2/6.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/demo-2/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/demo-2/7.jpg -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/images/grain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/InifniteAutoScrollingGallery/images/grain.png -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Infinite WebGL Gallery | Demo 1 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |

Infinite WebGL Scrolling Gallery

20 |

using OGL with shaders

21 |
22 | 23 | 28 | 29 |
30 | Demo 1 31 | Demo 2 32 |
33 |
34 | 35 |
36 |
37 |

38 | Planete Elevene 39 |

40 |
41 | 42 | 91 |
92 |
93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Infinite WebGL Gallery | Demo 2 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |

Infinite WebGL Scrolling Gallery

20 |

using OGL with shaders

21 |
22 | 23 | 28 | 29 |
30 | Demo 1 31 | Demo 2 32 |
33 |
34 | 35 |
36 |
37 |

38 | Electric 39 |

40 |
41 | 42 | 71 |
72 |
73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/main.aa1e6c08c8704276560a.js: -------------------------------------------------------------------------------- 1 | !function(t){var e={};function i(s){if(e[s])return e[s].exports;var r=e[s]={i:s,l:!1,exports:{}};return t[s].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=t,i.c=e,i.d=function(t,e,s){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:s})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var s=Object.create(null);if(i.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)i.d(s,r,function(e){return t[e]}.bind(null,r));return s},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=2)}([function(t,e,i){t.exports=i(3)},,function(t,e,i){i(8),t.exports=i(7)},function(t,e,i){"use strict";var s=i(4),r=i(5);function n(t){var e=0,i=0,s=0,r=0;return"detail"in t&&(i=t.detail),"wheelDelta"in t&&(i=-t.wheelDelta/120),"wheelDeltaY"in t&&(i=-t.wheelDeltaY/120),"wheelDeltaX"in t&&(e=-t.wheelDeltaX/120),"axis"in t&&t.axis===t.HORIZONTAL_AXIS&&(e=i,i=0),s=10*e,r=10*i,"deltaY"in t&&(r=t.deltaY),"deltaX"in t&&(s=t.deltaX),(s||r)&&t.deltaMode&&(1==t.deltaMode?(s*=40,r*=40):(s*=800,r*=800)),s&&!e&&(e=s<1?-1:1),r&&!i&&(i=r<1?-1:1),{spinX:e,spinY:i,pixelX:s,pixelY:r}}n.getEventType=function(){return s.firefox()?"DOMMouseScroll":r("wheel")?"wheel":"mousewheel"},t.exports=n},function(t,e){var i,s,r,n,h,a,o,l,u,c,d,g,p,m,f,w=!1;function v(){if(!w){w=!0;var t=navigator.userAgent,e=/(?:MSIE.(\d+\.\d+))|(?:(?:Firefox|GranParadiso|Iceweasel).(\d+\.\d+))|(?:Opera(?:.+Version.|.)(\d+\.\d+))|(?:AppleWebKit.(\d+(?:\.\d+)?))|(?:Trident\/\d+\.\d+.*rv:(\d+\.\d+))/.exec(t),v=/(Mac OS X)|(Windows)|(Linux)/.exec(t);if(g=/\b(iPhone|iP[ao]d)/.exec(t),p=/\b(iP[ao]d)/.exec(t),c=/Android/i.exec(t),m=/FBAN\/\w+;/i.exec(t),f=/Mobile/i.exec(t),d=!!/Win64/.exec(t),e){(i=e[1]?parseFloat(e[1]):e[5]?parseFloat(e[5]):NaN)&&document&&document.documentMode&&(i=document.documentMode);var x=/(?:Trident\/(\d+.\d+))/.exec(t);a=x?parseFloat(x[1])+4:i,s=e[2]?parseFloat(e[2]):NaN,r=e[3]?parseFloat(e[3]):NaN,(n=e[4]?parseFloat(e[4]):NaN)?(e=/(?:Chrome\/(\d+\.\d+))/.exec(t),h=e&&e[1]?parseFloat(e[1]):NaN):h=NaN}else i=s=r=h=n=NaN;if(v){if(v[1]){var b=/(?:Mac OS X (\d+(?:[._]\d+)?))/.exec(t);o=!b||parseFloat(b[1].replace("_","."))}else o=!1;l=!!v[2],u=!!v[3]}else o=l=u=!1}}var x={ie:function(){return v()||i},ieCompatibilityMode:function(){return v()||a>i},ie64:function(){return x.ie()&&d},firefox:function(){return v()||s},opera:function(){return v()||r},webkit:function(){return v()||n},safari:function(){return x.webkit()},chrome:function(){return v()||h},windows:function(){return v()||l},osx:function(){return v()||o},linux:function(){return v()||u},iphone:function(){return v()||g},mobile:function(){return v()||g||p||c||f},nativeApp:function(){return v()||m},android:function(){return v()||c},ipad:function(){return v()||p}};t.exports=x},function(t,e,i){"use strict";var s,r=i(6);r.canUseDOM&&(s=document.implementation&&document.implementation.hasFeature&&!0!==document.implementation.hasFeature("","")) 2 | /** 3 | * Checks if an event is supported in the current execution environment. 4 | * 5 | * NOTE: This will not work correctly for non-generic events such as `change`, 6 | * `reset`, `load`, `error`, and `select`. 7 | * 8 | * Borrows from Modernizr. 9 | * 10 | * @param {string} eventNameSuffix Event name, e.g. "click". 11 | * @param {?boolean} capture Check if the capture phase is supported. 12 | * @return {boolean} True if the event is supported. 13 | * @internal 14 | * @license Modernizr 3.0.0pre (Custom Build) | MIT 15 | */,t.exports=function(t,e){if(!r.canUseDOM||e&&!("addEventListener"in document))return!1;var i="on"+t,n=i in document;if(!n){var h=document.createElement("div");h.setAttribute(i,"return;"),n="function"==typeof h[i]}return!n&&s&&"wheel"===t&&(n=document.implementation.hasFeature("Events.wheel","3.0")),n}},function(t,e,i){"use strict";var s=!("undefined"==typeof window||!window.document||!window.document.createElement),r={canUseDOM:s,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:s&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:s&&!!window.screen,isInWorker:!s};t.exports=r},function(t,e,i){"use strict";i.r(e)},function(t,e,i){"use strict";i.r(e);function s(t){let e=t[0],i=t[1],s=t[2];return Math.sqrt(e*e+i*i+s*s)}function r(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function n(t,e,i){return t[0]=e[0]+i[0],t[1]=e[1]+i[1],t[2]=e[2]+i[2],t}function h(t,e,i){return t[0]=e[0]-i[0],t[1]=e[1]-i[1],t[2]=e[2]-i[2],t}function a(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i,t}function o(t){let e=t[0],i=t[1],s=t[2];return e*e+i*i+s*s}function l(t,e){let i=e[0],s=e[1],r=e[2],n=i*i+s*s+r*r;return n>0&&(n=1/Math.sqrt(n)),t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t}function u(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function c(t,e,i){let s=e[0],r=e[1],n=e[2],h=i[0],a=i[1],o=i[2];return t[0]=r*o-n*a,t[1]=n*h-s*o,t[2]=s*a-r*h,t}const d=function(){const t=[0,0,0],e=[0,0,0];return function(i,s){r(t,i),r(e,s),l(t,t),l(e,e);let n=u(t,e);return n>1?0:n<-1?Math.PI:Math.acos(n)}}();class g extends Array{constructor(t=0,e=t,i=t){return super(t,e,i),this}get x(){return this[0]}get y(){return this[1]}get z(){return this[2]}set x(t){this[0]=t}set y(t){this[1]=t}set z(t){this[2]=t}set(t,e=t,i=t){return t.length?this.copy(t):(function(t,e,i,s){t[0]=e,t[1]=i,t[2]=s}(this,t,e,i),this)}copy(t){return r(this,t),this}add(t,e){return e?n(this,t,e):n(this,this,t),this}sub(t,e){return e?h(this,t,e):h(this,this,t),this}multiply(t){var e,i,s;return t.length?(i=this,s=t,(e=this)[0]=i[0]*s[0],e[1]=i[1]*s[1],e[2]=i[2]*s[2]):a(this,this,t),this}divide(t){var e,i,s;return t.length?(i=this,s=t,(e=this)[0]=i[0]/s[0],e[1]=i[1]/s[1],e[2]=i[2]/s[2]):a(this,this,1/t),this}inverse(t=this){var e,i;return i=t,(e=this)[0]=1/i[0],e[1]=1/i[1],e[2]=1/i[2],this}len(){return s(this)}distance(t){return t?function(t,e){let i=e[0]-t[0],s=e[1]-t[1],r=e[2]-t[2];return Math.sqrt(i*i+s*s+r*r)}(this,t):s(this)}squaredLen(){return o(this)}squaredDistance(t){return t?function(t,e){let i=e[0]-t[0],s=e[1]-t[1],r=e[2]-t[2];return i*i+s*s+r*r}(this,t):o(this)}negate(t=this){var e,i;return i=t,(e=this)[0]=-i[0],e[1]=-i[1],e[2]=-i[2],this}cross(t,e){return e?c(this,t,e):c(this,this,t),this}scale(t){return a(this,this,t),this}normalize(){return l(this,this),this}dot(t){return u(this,t)}equals(t){return i=t,(e=this)[0]===i[0]&&e[1]===i[1]&&e[2]===i[2];var e,i}applyMatrix4(t){return function(t,e,i){let s=e[0],r=e[1],n=e[2],h=i[3]*s+i[7]*r+i[11]*n+i[15];h=h||1,t[0]=(i[0]*s+i[4]*r+i[8]*n+i[12])/h,t[1]=(i[1]*s+i[5]*r+i[9]*n+i[13])/h,t[2]=(i[2]*s+i[6]*r+i[10]*n+i[14])/h}(this,this,t),this}scaleRotateMatrix4(t){return function(t,e,i){let s=e[0],r=e[1],n=e[2],h=i[3]*s+i[7]*r+i[11]*n+i[15];h=h||1,t[0]=(i[0]*s+i[4]*r+i[8]*n)/h,t[1]=(i[1]*s+i[5]*r+i[9]*n)/h,t[2]=(i[2]*s+i[6]*r+i[10]*n)/h}(this,this,t),this}applyQuaternion(t){return function(t,e,i){let s=e[0],r=e[1],n=e[2],h=i[0],a=i[1],o=i[2],l=a*n-o*r,u=o*s-h*n,c=h*r-a*s,d=a*c-o*u,g=o*l-h*c,p=h*u-a*l,m=2*i[3];l*=m,u*=m,c*=m,d*=2,g*=2,p*=2,t[0]=s+l+d,t[1]=r+u+g,t[2]=n+c+p}(this,this,t),this}angle(t){return d(this,t)}lerp(t,e){return function(t,e,i,s){let r=e[0],n=e[1],h=e[2];t[0]=r+s*(i[0]-r),t[1]=n+s*(i[1]-n),t[2]=h+s*(i[2]-h)}(this,this,t,e),this}clone(){return new g(this[0],this[1],this[2])}fromArray(t,e=0){return this[0]=t[e],this[1]=t[e+1],this[2]=t[e+2],this}toArray(t=[],e=0){return t[e]=this[0],t[e+1]=this[1],t[e+2]=this[2],t}transformDirection(t){const e=this[0],i=this[1],s=this[2];return this[0]=t[0]*e+t[4]*i+t[8]*s,this[1]=t[1]*e+t[5]*i+t[9]*s,this[2]=t[2]*e+t[6]*i+t[10]*s,this.normalize()}}const p=new g;let m=1;class f{constructor({canvas:t=document.createElement("canvas"),width:e=300,height:i=150,dpr:s=1,alpha:r=!1,depth:n=!0,stencil:h=!1,antialias:a=!1,premultipliedAlpha:o=!1,preserveDrawingBuffer:l=!1,powerPreference:u="default",autoClear:c=!0,webgl:d=2}={}){const g={alpha:r,depth:n,stencil:h,antialias:a,premultipliedAlpha:o,preserveDrawingBuffer:l,powerPreference:u};this.dpr=s,this.alpha=r,this.color=!0,this.depth=n,this.stencil=h,this.premultipliedAlpha=o,this.autoClear=c,this.id=m++,2===d&&(this.gl=t.getContext("webgl2",g)),this.isWebgl2=!!this.gl,this.gl||(this.gl=t.getContext("webgl",g)||t.getContext("experimental-webgl",g)),this.gl.renderer=this,this.setSize(e,i),this.state={},this.state.blendFunc={src:this.gl.ONE,dst:this.gl.ZERO},this.state.blendEquation={modeRGB:this.gl.FUNC_ADD},this.state.cullFace=null,this.state.frontFace=this.gl.CCW,this.state.depthMask=!0,this.state.depthFunc=this.gl.LESS,this.state.premultiplyAlpha=!1,this.state.flipY=!1,this.state.unpackAlignment=4,this.state.framebuffer=null,this.state.viewport={width:null,height:null},this.state.textureUnits=[],this.state.activeTextureUnit=0,this.state.boundBuffer=null,this.state.uniformLocations=new Map,this.extensions={},this.isWebgl2?(this.getExtension("EXT_color_buffer_float"),this.getExtension("OES_texture_float_linear")):(this.getExtension("OES_texture_float"),this.getExtension("OES_texture_float_linear"),this.getExtension("OES_texture_half_float"),this.getExtension("OES_texture_half_float_linear"),this.getExtension("OES_element_index_uint"),this.getExtension("OES_standard_derivatives"),this.getExtension("EXT_sRGB"),this.getExtension("WEBGL_depth_texture"),this.getExtension("WEBGL_draw_buffers")),this.vertexAttribDivisor=this.getExtension("ANGLE_instanced_arrays","vertexAttribDivisor","vertexAttribDivisorANGLE"),this.drawArraysInstanced=this.getExtension("ANGLE_instanced_arrays","drawArraysInstanced","drawArraysInstancedANGLE"),this.drawElementsInstanced=this.getExtension("ANGLE_instanced_arrays","drawElementsInstanced","drawElementsInstancedANGLE"),this.createVertexArray=this.getExtension("OES_vertex_array_object","createVertexArray","createVertexArrayOES"),this.bindVertexArray=this.getExtension("OES_vertex_array_object","bindVertexArray","bindVertexArrayOES"),this.deleteVertexArray=this.getExtension("OES_vertex_array_object","deleteVertexArray","deleteVertexArrayOES"),this.drawBuffers=this.getExtension("WEBGL_draw_buffers","drawBuffers","drawBuffersWEBGL"),this.parameters={},this.parameters.maxTextureUnits=this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),this.parameters.maxAnisotropy=this.getExtension("EXT_texture_filter_anisotropic")?this.gl.getParameter(this.getExtension("EXT_texture_filter_anisotropic").MAX_TEXTURE_MAX_ANISOTROPY_EXT):0}setSize(t,e){this.width=t,this.height=e,this.gl.canvas.width=t*this.dpr,this.gl.canvas.height=e*this.dpr,Object.assign(this.gl.canvas.style,{width:t+"px",height:e+"px"})}setViewport(t,e){this.state.viewport.width===t&&this.state.viewport.height===e||(this.state.viewport.width=t,this.state.viewport.height=e,this.gl.viewport(0,0,t,e))}enable(t){!0!==this.state[t]&&(this.gl.enable(t),this.state[t]=!0)}disable(t){!1!==this.state[t]&&(this.gl.disable(t),this.state[t]=!1)}setBlendFunc(t,e,i,s){this.state.blendFunc.src===t&&this.state.blendFunc.dst===e&&this.state.blendFunc.srcAlpha===i&&this.state.blendFunc.dstAlpha===s||(this.state.blendFunc.src=t,this.state.blendFunc.dst=e,this.state.blendFunc.srcAlpha=i,this.state.blendFunc.dstAlpha=s,void 0!==i?this.gl.blendFuncSeparate(t,e,i,s):this.gl.blendFunc(t,e))}setBlendEquation(t,e){t=t||this.gl.FUNC_ADD,this.state.blendEquation.modeRGB===t&&this.state.blendEquation.modeAlpha===e||(this.state.blendEquation.modeRGB=t,this.state.blendEquation.modeAlpha=e,void 0!==e?this.gl.blendEquationSeparate(t,e):this.gl.blendEquation(t))}setCullFace(t){this.state.cullFace!==t&&(this.state.cullFace=t,this.gl.cullFace(t))}setFrontFace(t){this.state.frontFace!==t&&(this.state.frontFace=t,this.gl.frontFace(t))}setDepthMask(t){this.state.depthMask!==t&&(this.state.depthMask=t,this.gl.depthMask(t))}setDepthFunc(t){this.state.depthFunc!==t&&(this.state.depthFunc=t,this.gl.depthFunc(t))}activeTexture(t){this.state.activeTextureUnit!==t&&(this.state.activeTextureUnit=t,this.gl.activeTexture(this.gl.TEXTURE0+t))}bindFramebuffer({target:t=this.gl.FRAMEBUFFER,buffer:e=null}={}){this.state.framebuffer!==e&&(this.state.framebuffer=e,this.gl.bindFramebuffer(t,e))}getExtension(t,e,i){return e&&this.gl[e]?this.gl[e].bind(this.gl):(this.extensions[t]||(this.extensions[t]=this.gl.getExtension(t)),e?this.extensions[t]?this.extensions[t][i].bind(this.extensions[t]):null:this.extensions[t])}sortOpaque(t,e){return t.renderOrder!==e.renderOrder?t.renderOrder-e.renderOrder:t.program.id!==e.program.id?t.program.id-e.program.id:t.zDepth!==e.zDepth?t.zDepth-e.zDepth:e.id-t.id}sortTransparent(t,e){return t.renderOrder!==e.renderOrder?t.renderOrder-e.renderOrder:t.zDepth!==e.zDepth?e.zDepth-t.zDepth:e.id-t.id}sortUI(t,e){return t.renderOrder!==e.renderOrder?t.renderOrder-e.renderOrder:t.program.id!==e.program.id?t.program.id-e.program.id:e.id-t.id}getRenderList({scene:t,camera:e,frustumCull:i,sort:s}){let r=[];if(e&&i&&e.updateFrustum(),t.traverse(t=>{if(!t.visible)return!0;t.draw&&(i&&t.frustumCulled&&e&&!e.frustumIntersectsMesh(t)||r.push(t))}),s){const t=[],i=[],s=[];r.forEach(r=>{r.program.transparent?r.program.depthTest?i.push(r):s.push(r):t.push(r),r.zDepth=0,0===r.renderOrder&&r.program.depthTest&&e&&(r.worldMatrix.getTranslation(p),p.applyMatrix4(e.projectionViewMatrix),r.zDepth=p.z)}),t.sort(this.sortOpaque),i.sort(this.sortTransparent),s.sort(this.sortUI),r=t.concat(i,s)}return r}render({scene:t,camera:e,target:i=null,update:s=!0,sort:r=!0,frustumCull:n=!0,clear:h}){null===i?(this.bindFramebuffer(),this.setViewport(this.width*this.dpr,this.height*this.dpr)):(this.bindFramebuffer(i),this.setViewport(i.width,i.height)),(h||this.autoClear&&!1!==h)&&(!this.depth||i&&!i.depth||(this.enable(this.gl.DEPTH_TEST),this.setDepthMask(!0)),this.gl.clear((this.color?this.gl.COLOR_BUFFER_BIT:0)|(this.depth?this.gl.DEPTH_BUFFER_BIT:0)|(this.stencil?this.gl.STENCIL_BUFFER_BIT:0))),s&&t.updateMatrixWorld(),e&&e.updateMatrixWorld();this.getRenderList({scene:t,camera:e,frustumCull:n,sort:r}).forEach(t=>{t.draw({camera:e})})}}function w(t,e,i){let s=e[0],r=e[1],n=e[2],h=e[3],a=i[0],o=i[1],l=i[2],u=i[3];return t[0]=s*u+h*a+r*l-n*o,t[1]=r*u+h*o+n*a-s*l,t[2]=n*u+h*l+s*o-r*a,t[3]=h*u-s*a-r*o-n*l,t}const v=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},x=function(t,e,i,s,r){return t[0]=e,t[1]=i,t[2]=s,t[3]=r,t},b=function(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]},E=function(t,e){let i=e[0],s=e[1],r=e[2],n=e[3],h=i*i+s*s+r*r+n*n;return h>0&&(h=1/Math.sqrt(h)),t[0]=i*h,t[1]=s*h,t[2]=r*h,t[3]=n*h,t};class M extends Array{constructor(t=0,e=0,i=0,s=1){return super(t,e,i,s),this.onChange=()=>{},this}get x(){return this[0]}get y(){return this[1]}get z(){return this[2]}get w(){return this[3]}set x(t){this[0]=t,this.onChange()}set y(t){this[1]=t,this.onChange()}set z(t){this[2]=t,this.onChange()}set w(t){this[3]=t,this.onChange()}identity(){var t;return(t=this)[0]=0,t[1]=0,t[2]=0,t[3]=1,this.onChange(),this}set(t,e,i,s){return t.length?this.copy(t):(x(this,t,e,i,s),this.onChange(),this)}rotateX(t){return function(t,e,i){i*=.5;let s=e[0],r=e[1],n=e[2],h=e[3],a=Math.sin(i),o=Math.cos(i);t[0]=s*o+h*a,t[1]=r*o+n*a,t[2]=n*o-r*a,t[3]=h*o-s*a}(this,this,t),this.onChange(),this}rotateY(t){return function(t,e,i){i*=.5;let s=e[0],r=e[1],n=e[2],h=e[3],a=Math.sin(i),o=Math.cos(i);t[0]=s*o-n*a,t[1]=r*o+h*a,t[2]=n*o+s*a,t[3]=h*o-r*a}(this,this,t),this.onChange(),this}rotateZ(t){return function(t,e,i){i*=.5;let s=e[0],r=e[1],n=e[2],h=e[3],a=Math.sin(i),o=Math.cos(i);t[0]=s*o+r*a,t[1]=r*o-s*a,t[2]=n*o+h*a,t[3]=h*o-n*a}(this,this,t),this.onChange(),this}inverse(t=this){return function(t,e){let i=e[0],s=e[1],r=e[2],n=e[3],h=i*i+s*s+r*r+n*n,a=h?1/h:0;t[0]=-i*a,t[1]=-s*a,t[2]=-r*a,t[3]=n*a}(this,t),this.onChange(),this}conjugate(t=this){var e,i;return i=t,(e=this)[0]=-i[0],e[1]=-i[1],e[2]=-i[2],e[3]=i[3],this.onChange(),this}copy(t){return v(this,t),this.onChange(),this}normalize(t=this){return E(this,t),this.onChange(),this}multiply(t,e){return e?w(this,t,e):w(this,this,t),this.onChange(),this}dot(t){return b(this,t)}fromMatrix3(t){return function(t,e){let i,s=e[0]+e[4]+e[8];if(s>0)i=Math.sqrt(s+1),t[3]=.5*i,i=.5/i,t[0]=(e[5]-e[7])*i,t[1]=(e[6]-e[2])*i,t[2]=(e[1]-e[3])*i;else{let s=0;e[4]>e[0]&&(s=1),e[8]>e[3*s+s]&&(s=2);let r=(s+1)%3,n=(s+2)%3;i=Math.sqrt(e[3*s+s]-e[3*r+r]-e[3*n+n]+1),t[s]=.5*i,i=.5/i,t[3]=(e[3*r+n]-e[3*n+r])*i,t[r]=(e[3*r+s]+e[3*s+r])*i,t[n]=(e[3*n+s]+e[3*s+n])*i}}(this,t),this.onChange(),this}fromEuler(t){return function(t,e,i="YXZ"){let s=Math.sin(.5*e[0]),r=Math.cos(.5*e[0]),n=Math.sin(.5*e[1]),h=Math.cos(.5*e[1]),a=Math.sin(.5*e[2]),o=Math.cos(.5*e[2]);"XYZ"===i?(t[0]=s*h*o+r*n*a,t[1]=r*n*o-s*h*a,t[2]=r*h*a+s*n*o,t[3]=r*h*o-s*n*a):"YXZ"===i?(t[0]=s*h*o+r*n*a,t[1]=r*n*o-s*h*a,t[2]=r*h*a-s*n*o,t[3]=r*h*o+s*n*a):"ZXY"===i?(t[0]=s*h*o-r*n*a,t[1]=r*n*o+s*h*a,t[2]=r*h*a+s*n*o,t[3]=r*h*o-s*n*a):"ZYX"===i?(t[0]=s*h*o-r*n*a,t[1]=r*n*o+s*h*a,t[2]=r*h*a-s*n*o,t[3]=r*h*o+s*n*a):"YZX"===i?(t[0]=s*h*o+r*n*a,t[1]=r*n*o+s*h*a,t[2]=r*h*a-s*n*o,t[3]=r*h*o-s*n*a):"XZY"===i&&(t[0]=s*h*o-r*n*a,t[1]=r*n*o-s*h*a,t[2]=r*h*a+s*n*o,t[3]=r*h*o+s*n*a)}(this,t,t.order),this}fromAxisAngle(t,e){return function(t,e,i){i*=.5;let s=Math.sin(i);t[0]=s*e[0],t[1]=s*e[1],t[2]=s*e[2],t[3]=Math.cos(i)}(this,t,e),this}slerp(t,e){return function(t,e,i,s){let r,n,h,a,o,l=e[0],u=e[1],c=e[2],d=e[3],g=i[0],p=i[1],m=i[2],f=i[3];n=l*g+u*p+c*m+d*f,n<0&&(n=-n,g=-g,p=-p,m=-m,f=-f),1-n>1e-6?(r=Math.acos(n),h=Math.sin(r),a=Math.sin((1-s)*r)/h,o=Math.sin(s*r)/h):(a=1-s,o=s),t[0]=a*l+o*g,t[1]=a*u+o*p,t[2]=a*c+o*m,t[3]=a*d+o*f}(this,this,t,e),this}fromArray(t,e=0){return this[0]=t[e],this[1]=t[e+1],this[2]=t[e+2],this[3]=t[e+3],this}toArray(t=[],e=0){return t[e]=this[0],t[e+1]=this[1],t[e+2]=this[2],t[e+3]=this[3],t}}function y(t,e,i){let s=e[0],r=e[1],n=e[2],h=e[3],a=e[4],o=e[5],l=e[6],u=e[7],c=e[8],d=e[9],g=e[10],p=e[11],m=e[12],f=e[13],w=e[14],v=e[15],x=i[0],b=i[1],E=i[2],M=i[3];return t[0]=x*s+b*a+E*c+M*m,t[1]=x*r+b*o+E*d+M*f,t[2]=x*n+b*l+E*g+M*w,t[3]=x*h+b*u+E*p+M*v,x=i[4],b=i[5],E=i[6],M=i[7],t[4]=x*s+b*a+E*c+M*m,t[5]=x*r+b*o+E*d+M*f,t[6]=x*n+b*l+E*g+M*w,t[7]=x*h+b*u+E*p+M*v,x=i[8],b=i[9],E=i[10],M=i[11],t[8]=x*s+b*a+E*c+M*m,t[9]=x*r+b*o+E*d+M*f,t[10]=x*n+b*l+E*g+M*w,t[11]=x*h+b*u+E*p+M*v,x=i[12],b=i[13],E=i[14],M=i[15],t[12]=x*s+b*a+E*c+M*m,t[13]=x*r+b*o+E*d+M*f,t[14]=x*n+b*l+E*g+M*w,t[15]=x*h+b*u+E*p+M*v,t}function A(t,e){let i=e[0],s=e[1],r=e[2],n=e[4],h=e[5],a=e[6],o=e[8],l=e[9],u=e[10];return t[0]=Math.hypot(i,s,r),t[1]=Math.hypot(n,h,a),t[2]=Math.hypot(o,l,u),t}const S=function(){const t=[0,0,0];return function(e,i){let s=t;A(s,i);let r=1/s[0],n=1/s[1],h=1/s[2],a=i[0]*r,o=i[1]*n,l=i[2]*h,u=i[4]*r,c=i[5]*n,d=i[6]*h,g=i[8]*r,p=i[9]*n,m=i[10]*h,f=a+c+m,w=0;return f>0?(w=2*Math.sqrt(f+1),e[3]=.25*w,e[0]=(d-p)/w,e[1]=(g-l)/w,e[2]=(o-u)/w):a>c&&a>m?(w=2*Math.sqrt(1+a-c-m),e[3]=(d-p)/w,e[0]=.25*w,e[1]=(o+u)/w,e[2]=(g+l)/w):c>m?(w=2*Math.sqrt(1+c-a-m),e[3]=(g-l)/w,e[0]=(o+u)/w,e[1]=.25*w,e[2]=(d+p)/w):(w=2*Math.sqrt(1+m-a-c),e[3]=(o-u)/w,e[0]=(g+l)/w,e[1]=(d+p)/w,e[2]=.25*w),e}}();class T extends Array{constructor(t=1,e=0,i=0,s=0,r=0,n=1,h=0,a=0,o=0,l=0,u=1,c=0,d=0,g=0,p=0,m=1){return super(t,e,i,s,r,n,h,a,o,l,u,c,d,g,p,m),this}get x(){return this[12]}get y(){return this[13]}get z(){return this[14]}get w(){return this[15]}set x(t){this[12]=t}set y(t){this[13]=t}set z(t){this[14]=t}set w(t){this[15]=t}set(t,e,i,s,r,n,h,a,o,l,u,c,d,g,p,m){return t.length?this.copy(t):(function(t,e,i,s,r,n,h,a,o,l,u,c,d,g,p,m,f){t[0]=e,t[1]=i,t[2]=s,t[3]=r,t[4]=n,t[5]=h,t[6]=a,t[7]=o,t[8]=l,t[9]=u,t[10]=c,t[11]=d,t[12]=g,t[13]=p,t[14]=m,t[15]=f}(this,t,e,i,s,r,n,h,a,o,l,u,c,d,g,p,m),this)}translate(t,e=this){return function(t,e,i){let s,r,n,h,a,o,l,u,c,d,g,p,m=i[0],f=i[1],w=i[2];e===t?(t[12]=e[0]*m+e[4]*f+e[8]*w+e[12],t[13]=e[1]*m+e[5]*f+e[9]*w+e[13],t[14]=e[2]*m+e[6]*f+e[10]*w+e[14],t[15]=e[3]*m+e[7]*f+e[11]*w+e[15]):(s=e[0],r=e[1],n=e[2],h=e[3],a=e[4],o=e[5],l=e[6],u=e[7],c=e[8],d=e[9],g=e[10],p=e[11],t[0]=s,t[1]=r,t[2]=n,t[3]=h,t[4]=a,t[5]=o,t[6]=l,t[7]=u,t[8]=c,t[9]=d,t[10]=g,t[11]=p,t[12]=s*m+a*f+c*w+e[12],t[13]=r*m+o*f+d*w+e[13],t[14]=n*m+l*f+g*w+e[14],t[15]=h*m+u*f+p*w+e[15])}(this,e,t),this}rotate(t,e,i=this){return function(t,e,i,s){let r,n,h,a,o,l,u,c,d,g,p,m,f,w,v,x,b,E,M,y,A,S,T,_,F=s[0],R=s[1],P=s[2],C=Math.hypot(F,R,P);Math.abs(C)<1e-6||(C=1/C,F*=C,R*=C,P*=C,r=Math.sin(i),n=Math.cos(i),h=1-n,a=e[0],o=e[1],l=e[2],u=e[3],c=e[4],d=e[5],g=e[6],p=e[7],m=e[8],f=e[9],w=e[10],v=e[11],x=F*F*h+n,b=R*F*h+P*r,E=P*F*h-R*r,M=F*R*h-P*r,y=R*R*h+n,A=P*R*h+F*r,S=F*P*h+R*r,T=R*P*h-F*r,_=P*P*h+n,t[0]=a*x+c*b+m*E,t[1]=o*x+d*b+f*E,t[2]=l*x+g*b+w*E,t[3]=u*x+p*b+v*E,t[4]=a*M+c*y+m*A,t[5]=o*M+d*y+f*A,t[6]=l*M+g*y+w*A,t[7]=u*M+p*y+v*A,t[8]=a*S+c*T+m*_,t[9]=o*S+d*T+f*_,t[10]=l*S+g*T+w*_,t[11]=u*S+p*T+v*_,e!==t&&(t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]))}(this,i,t,e),this}scale(t,e=this){return function(t,e,i){let s=i[0],r=i[1],n=i[2];t[0]=e[0]*s,t[1]=e[1]*s,t[2]=e[2]*s,t[3]=e[3]*s,t[4]=e[4]*r,t[5]=e[5]*r,t[6]=e[6]*r,t[7]=e[7]*r,t[8]=e[8]*n,t[9]=e[9]*n,t[10]=e[10]*n,t[11]=e[11]*n,t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]}(this,e,"number"==typeof t?[t,t,t]:t),this}multiply(t,e){return e?y(this,t,e):y(this,this,t),this}identity(){var t;return(t=this)[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}copy(t){var e,i;return i=t,(e=this)[0]=i[0],e[1]=i[1],e[2]=i[2],e[3]=i[3],e[4]=i[4],e[5]=i[5],e[6]=i[6],e[7]=i[7],e[8]=i[8],e[9]=i[9],e[10]=i[10],e[11]=i[11],e[12]=i[12],e[13]=i[13],e[14]=i[14],e[15]=i[15],this}fromPerspective({fov:t,aspect:e,near:i,far:s}={}){return function(t,e,i,s,r){let n=1/Math.tan(e/2),h=1/(s-r);t[0]=n/i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=(r+s)*h,t[11]=-1,t[12]=0,t[13]=0,t[14]=2*r*s*h,t[15]=0}(this,t,e,i,s),this}fromOrthogonal({left:t,right:e,bottom:i,top:s,near:r,far:n}){return function(t,e,i,s,r,n,h){let a=1/(e-i),o=1/(s-r),l=1/(n-h);t[0]=-2*a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*l,t[11]=0,t[12]=(e+i)*a,t[13]=(r+s)*o,t[14]=(h+n)*l,t[15]=1}(this,t,e,i,s,r,n),this}fromQuaternion(t){return function(t,e){let i=e[0],s=e[1],r=e[2],n=e[3],h=i+i,a=s+s,o=r+r,l=i*h,u=s*h,c=s*a,d=r*h,g=r*a,p=r*o,m=n*h,f=n*a,w=n*o;t[0]=1-c-p,t[1]=u+w,t[2]=d-f,t[3]=0,t[4]=u-w,t[5]=1-l-p,t[6]=g+m,t[7]=0,t[8]=d+f,t[9]=g-m,t[10]=1-l-c,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1}(this,t),this}setPosition(t){return this.x=t[0],this.y=t[1],this.z=t[2],this}inverse(t=this){return function(t,e){let i=e[0],s=e[1],r=e[2],n=e[3],h=e[4],a=e[5],o=e[6],l=e[7],u=e[8],c=e[9],d=e[10],g=e[11],p=e[12],m=e[13],f=e[14],w=e[15],v=i*a-s*h,x=i*o-r*h,b=i*l-n*h,E=s*o-r*a,M=s*l-n*a,y=r*l-n*o,A=u*m-c*p,S=u*f-d*p,T=u*w-g*p,_=c*f-d*m,F=c*w-g*m,R=d*w-g*f,P=v*R-x*F+b*_+E*T-M*S+y*A;P&&(P=1/P,t[0]=(a*R-o*F+l*_)*P,t[1]=(r*F-s*R-n*_)*P,t[2]=(m*y-f*M+w*E)*P,t[3]=(d*M-c*y-g*E)*P,t[4]=(o*T-h*R-l*S)*P,t[5]=(i*R-r*T+n*S)*P,t[6]=(f*b-p*y-w*x)*P,t[7]=(u*y-d*b+g*x)*P,t[8]=(h*F-a*T+l*A)*P,t[9]=(s*T-i*F-n*A)*P,t[10]=(p*M-m*b+w*v)*P,t[11]=(c*b-u*M-g*v)*P,t[12]=(a*S-h*_-o*A)*P,t[13]=(i*_-s*S+r*A)*P,t[14]=(m*x-p*E-f*v)*P,t[15]=(u*E-c*x+d*v)*P)}(this,t),this}compose(t,e,i){return function(t,e,i,s){let r=e[0],n=e[1],h=e[2],a=e[3],o=r+r,l=n+n,u=h+h,c=r*o,d=r*l,g=r*u,p=n*l,m=n*u,f=h*u,w=a*o,v=a*l,x=a*u,b=s[0],E=s[1],M=s[2];t[0]=(1-(p+f))*b,t[1]=(d+x)*b,t[2]=(g-v)*b,t[3]=0,t[4]=(d-x)*E,t[5]=(1-(c+f))*E,t[6]=(m+w)*E,t[7]=0,t[8]=(g+v)*M,t[9]=(m-w)*M,t[10]=(1-(c+p))*M,t[11]=0,t[12]=i[0],t[13]=i[1],t[14]=i[2],t[15]=1}(this,t,e,i),this}getRotation(t){return S(t,this),this}getTranslation(t){var e,i;return i=this,(e=t)[0]=i[12],e[1]=i[13],e[2]=i[14],this}getScaling(t){return A(t,this),this}getMaxScaleOnAxis(){return function(t){let e=t[0],i=t[1],s=t[2],r=t[4],n=t[5],h=t[6],a=t[8],o=t[9],l=t[10];const u=e*e+i*i+s*s,c=r*r+n*n+h*h,d=a*a+o*o+l*l;return Math.sqrt(Math.max(u,c,d))}(this)}lookAt(t,e,i){return function(t,e,i,s){let r=e[0],n=e[1],h=e[2],a=s[0],o=s[1],l=s[2],u=r-i[0],c=n-i[1],d=h-i[2],g=u*u+c*c+d*d;0===g?d=1:(g=1/Math.sqrt(g),u*=g,c*=g,d*=g);let p=o*d-l*c,m=l*u-a*d,f=a*c-o*u;g=p*p+m*m+f*f,0===g&&(l?a+=1e-6:o?l+=1e-6:o+=1e-6,p=o*d-l*c,m=l*u-a*d,f=a*c-o*u,g=p*p+m*m+f*f),g=1/Math.sqrt(g),p*=g,m*=g,f*=g,t[0]=p,t[1]=m,t[2]=f,t[3]=0,t[4]=c*f-d*m,t[5]=d*p-u*f,t[6]=u*m-c*p,t[7]=0,t[8]=u,t[9]=c,t[10]=d,t[11]=0,t[12]=r,t[13]=n,t[14]=h,t[15]=1}(this,t,e,i),this}determinant(){return function(t){let e=t[0],i=t[1],s=t[2],r=t[3],n=t[4],h=t[5],a=t[6],o=t[7],l=t[8],u=t[9],c=t[10],d=t[11],g=t[12],p=t[13],m=t[14],f=t[15];return(e*h-i*n)*(c*f-d*m)-(e*a-s*n)*(u*f-d*p)+(e*o-r*n)*(u*m-c*p)+(i*a-s*h)*(l*f-d*g)-(i*o-r*h)*(l*m-c*g)+(s*o-r*a)*(l*p-u*g)}(this)}fromArray(t,e=0){return this[0]=t[e],this[1]=t[e+1],this[2]=t[e+2],this[3]=t[e+3],this[4]=t[e+4],this[5]=t[e+5],this[6]=t[e+6],this[7]=t[e+7],this[8]=t[e+8],this[9]=t[e+9],this[10]=t[e+10],this[11]=t[e+11],this[12]=t[e+12],this[13]=t[e+13],this[14]=t[e+14],this[15]=t[e+15],this}toArray(t=[],e=0){return t[e]=this[0],t[e+1]=this[1],t[e+2]=this[2],t[e+3]=this[3],t[e+4]=this[4],t[e+5]=this[5],t[e+6]=this[6],t[e+7]=this[7],t[e+8]=this[8],t[e+9]=this[9],t[e+10]=this[10],t[e+11]=this[11],t[e+12]=this[12],t[e+13]=this[13],t[e+14]=this[14],t[e+15]=this[15],t}}const _=new T;class F extends Array{constructor(t=0,e=t,i=t,s="YXZ"){return super(t,e,i),this.order=s,this.onChange=()=>{},this}get x(){return this[0]}get y(){return this[1]}get z(){return this[2]}set x(t){this[0]=t,this.onChange()}set y(t){this[1]=t,this.onChange()}set z(t){this[2]=t,this.onChange()}set(t,e=t,i=t){return t.length?this.copy(t):(this[0]=t,this[1]=e,this[2]=i,this.onChange(),this)}copy(t){return this[0]=t[0],this[1]=t[1],this[2]=t[2],this.onChange(),this}reorder(t){return this.order=t,this.onChange(),this}fromRotationMatrix(t,e=this.order){return function(t,e,i="YXZ"){"XYZ"===i?(t[1]=Math.asin(Math.min(Math.max(e[8],-1),1)),Math.abs(e[8])<.99999?(t[0]=Math.atan2(-e[9],e[10]),t[2]=Math.atan2(-e[4],e[0])):(t[0]=Math.atan2(e[6],e[5]),t[2]=0)):"YXZ"===i?(t[0]=Math.asin(-Math.min(Math.max(e[9],-1),1)),Math.abs(e[9])<.99999?(t[1]=Math.atan2(e[8],e[10]),t[2]=Math.atan2(e[1],e[5])):(t[1]=Math.atan2(-e[2],e[0]),t[2]=0)):"ZXY"===i?(t[0]=Math.asin(Math.min(Math.max(e[6],-1),1)),Math.abs(e[6])<.99999?(t[1]=Math.atan2(-e[2],e[10]),t[2]=Math.atan2(-e[4],e[5])):(t[1]=0,t[2]=Math.atan2(e[1],e[0]))):"ZYX"===i?(t[1]=Math.asin(-Math.min(Math.max(e[2],-1),1)),Math.abs(e[2])<.99999?(t[0]=Math.atan2(e[6],e[10]),t[2]=Math.atan2(e[1],e[0])):(t[0]=0,t[2]=Math.atan2(-e[4],e[5]))):"YZX"===i?(t[2]=Math.asin(Math.min(Math.max(e[1],-1),1)),Math.abs(e[1])<.99999?(t[0]=Math.atan2(-e[9],e[5]),t[1]=Math.atan2(-e[2],e[0])):(t[0]=0,t[1]=Math.atan2(e[8],e[10]))):"XZY"===i&&(t[2]=Math.asin(-Math.min(Math.max(e[4],-1),1)),Math.abs(e[4])<.99999?(t[0]=Math.atan2(e[6],e[5]),t[1]=Math.atan2(e[8],e[0])):(t[0]=Math.atan2(-e[9],e[10]),t[1]=0))}(this,t,e),this}fromQuaternion(t,e=this.order){return _.fromQuaternion(t),this.fromRotationMatrix(_,e)}}class R{constructor(){this.parent=null,this.children=[],this.visible=!0,this.matrix=new T,this.worldMatrix=new T,this.matrixAutoUpdate=!0,this.position=new g,this.quaternion=new M,this.scale=new g(1),this.rotation=new F,this.up=new g(0,1,0),this.rotation.onChange=()=>this.quaternion.fromEuler(this.rotation),this.quaternion.onChange=()=>this.rotation.fromQuaternion(this.quaternion)}setParent(t,e=!0){e&&this.parent&&t!==this.parent&&this.parent.removeChild(this,!1),this.parent=t,e&&t&&t.addChild(this,!1)}addChild(t,e=!0){~this.children.indexOf(t)||this.children.push(t),e&&t.setParent(this,!1)}removeChild(t,e=!0){~this.children.indexOf(t)&&this.children.splice(this.children.indexOf(t),1),e&&t.setParent(null,!1)}updateMatrixWorld(t){this.matrixAutoUpdate&&this.updateMatrix(),(this.worldMatrixNeedsUpdate||t)&&(null===this.parent?this.worldMatrix.copy(this.matrix):this.worldMatrix.multiply(this.parent.worldMatrix,this.matrix),this.worldMatrixNeedsUpdate=!1,t=!0);for(let e=0,i=this.children.length;e{if(!this.attributes[e])return void console.warn(`active attribute ${e} not being supplied`);const s=this.attributes[e];this.gl.bindBuffer(s.target,s.buffer),this.glState.boundBuffer=s.buffer;let r=1;35674===i&&(r=2),35675===i&&(r=3),35676===i&&(r=4);const n=s.size/r,h=1===r?0:r*r*r,a=1===r?0:r*r;for(let e=0;e{const i=this.attributes[e];i.needsUpdate&&this.updateAttribute(i)}),this.isInstanced?this.attributes.index?this.gl.renderer.drawElementsInstanced(e,this.drawRange.count,this.attributes.index.type,this.attributes.index.offset+2*this.drawRange.start,this.instancedCount):this.gl.renderer.drawArraysInstanced(e,this.drawRange.start,this.drawRange.count,this.instancedCount):this.attributes.index?this.gl.drawElements(e,this.drawRange.count,this.attributes.index.type,this.attributes.index.offset+2*this.drawRange.start):this.gl.drawArrays(e,this.drawRange.start,this.drawRange.count)}getPositionArray(){const t=this.attributes.position;return t.data?t.data:B?void 0:(console.warn("No position buffer data found to compute bounds"),B=!0)}computeBoundingBox(t){t||(t=this.getPositionArray()),this.bounds||(this.bounds={min:new g,max:new g,center:new g,scale:new g,radius:1/0});const e=this.bounds.min,i=this.bounds.max,s=this.bounds.center,r=this.bounds.scale;e.set(1/0),i.set(-1/0);for(let s=0,r=t.length;s65536?new Uint32Array(l):new Uint16Array(l);z.buildPlane(u,c,d,g,e,i,0,h,a),Object.assign(n,{position:{size:3,data:u},normal:{size:3,data:c},uv:{size:2,data:d},index:{data:g}}),super(t,n)}static buildPlane(t,e,i,s,r,n,h,a,o,l=0,u=1,c=2,d=1,g=-1,p=0,m=0){const f=p,w=r/a,v=n/o;for(let x=0;x<=o;x++){let b=x*v-n/2;for(let n=0;n<=a;n++,p++){let v=n*w-r/2;if(t[3*p+l]=v*d,t[3*p+u]=b*g,t[3*p+c]=h/2,e[3*p+l]=0,e[3*p+u]=0,e[3*p+c]=h>=0?1:-1,i[2*p]=n/a,i[2*p+1]=1-x/o,x===o||n===a)continue;let E=f+n+x*(a+1),M=f+n+(x+1)*(a+1),y=f+n+(x+1)*(a+1)+1,A=f+n+x*(a+1)+1;s[6*m]=E,s[6*m+1]=M,s[6*m+2]=A,s[6*m+3]=M,s[6*m+4]=y,s[6*m+5]=A,m++}}}}var G=i(0),X=i.n(G);function q(t,e,i){return t+(e-t)*i}const Y=new Uint8Array(4);function V(t){return 0==(t&t-1)}let W=1;class j{constructor(t,{image:e,target:i=t.TEXTURE_2D,type:s=t.UNSIGNED_BYTE,format:r=t.RGBA,internalFormat:n=r,wrapS:h=t.CLAMP_TO_EDGE,wrapT:a=t.CLAMP_TO_EDGE,generateMipmaps:o=!0,minFilter:l=(o?t.NEAREST_MIPMAP_LINEAR:t.LINEAR),magFilter:u=t.LINEAR,premultiplyAlpha:c=!1,unpackAlignment:d=4,flipY:g=i==t.TEXTURE_2D,anisotropy:p=0,level:m=0,width:f,height:w=f}={}){this.gl=t,this.id=W++,this.image=e,this.target=i,this.type=s,this.format=r,this.internalFormat=n,this.minFilter=l,this.magFilter=u,this.wrapS=h,this.wrapT=a,this.generateMipmaps=o,this.premultiplyAlpha=c,this.unpackAlignment=d,this.flipY=g,this.anisotropy=Math.min(p,this.gl.renderer.parameters.maxAnisotropy),this.level=m,this.width=f,this.height=w,this.texture=this.gl.createTexture(),this.store={image:null},this.glState=this.gl.renderer.state,this.state={},this.state.minFilter=this.gl.NEAREST_MIPMAP_LINEAR,this.state.magFilter=this.gl.LINEAR,this.state.wrapS=this.gl.REPEAT,this.state.wrapT=this.gl.REPEAT,this.state.anisotropy=0}bind(){this.glState.textureUnits[this.glState.activeTextureUnit]!==this.id&&(this.gl.bindTexture(this.target,this.texture),this.glState.textureUnits[this.glState.activeTextureUnit]=this.id)}update(t=0){const e=!(this.image===this.store.image&&!this.needsUpdate);if((e||this.glState.textureUnits[t]!==this.id)&&(this.gl.renderer.activeTexture(t),this.bind()),e){if(this.needsUpdate=!1,this.flipY!==this.glState.flipY&&(this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,this.flipY),this.glState.flipY=this.flipY),this.premultiplyAlpha!==this.glState.premultiplyAlpha&&(this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL,this.premultiplyAlpha),this.glState.premultiplyAlpha=this.premultiplyAlpha),this.unpackAlignment!==this.glState.unpackAlignment&&(this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,this.unpackAlignment),this.glState.unpackAlignment=this.unpackAlignment),this.minFilter!==this.state.minFilter&&(this.gl.texParameteri(this.target,this.gl.TEXTURE_MIN_FILTER,this.minFilter),this.state.minFilter=this.minFilter),this.magFilter!==this.state.magFilter&&(this.gl.texParameteri(this.target,this.gl.TEXTURE_MAG_FILTER,this.magFilter),this.state.magFilter=this.magFilter),this.wrapS!==this.state.wrapS&&(this.gl.texParameteri(this.target,this.gl.TEXTURE_WRAP_S,this.wrapS),this.state.wrapS=this.wrapS),this.wrapT!==this.state.wrapT&&(this.gl.texParameteri(this.target,this.gl.TEXTURE_WRAP_T,this.wrapT),this.state.wrapT=this.wrapT),this.anisotropy&&this.anisotropy!==this.state.anisotropy&&(this.gl.texParameterf(this.target,this.gl.renderer.getExtension("EXT_texture_filter_anisotropic").TEXTURE_MAX_ANISOTROPY_EXT,this.anisotropy),this.state.anisotropy=this.anisotropy),this.image){if(this.image.width&&(this.width=this.image.width,this.height=this.image.height),this.target===this.gl.TEXTURE_CUBE_MAP)for(let t=0;t<6;t++)this.gl.texImage2D(this.gl.TEXTURE_CUBE_MAP_POSITIVE_X+t,this.level,this.internalFormat,this.format,this.type,this.image[t]);else if(ArrayBuffer.isView(this.image))this.gl.texImage2D(this.target,this.level,this.internalFormat,this.width,this.height,0,this.format,this.type,this.image);else if(this.image.isCompressedTexture)for(let t=0;t{let s=i.uniformName,r=this.uniforms[s];if(i.isStruct&&(r=r[i.structProperty],s+="."+i.structProperty),i.isStructArray&&(r=r[i.structIndex][i.structProperty],s+=`[${i.structIndex}].${i.structProperty}`),!r)return J(`Active uniform ${s} has not been supplied`);if(r&&void 0===r.value)return J(s+" uniform is missing a value parameter");if(r.value.texture)return e+=1,r.value.update(e),$(this.gl,i.type,t,e);if(r.value.length&&r.value[0].texture){const s=[];return r.value.forEach(t=>{e+=1,t.update(e),s.push(e)}),$(this.gl,i.type,t,s)}$(this.gl,i.type,t,r.value)}),this.applyState(),t&&this.gl.renderer.setFrontFace(this.frontFace===this.gl.CCW?this.gl.CW:this.gl.CCW)}remove(){this.gl.deleteProgram(this.program)}}function $(t,e,i,s){s=s.length?function(t){const e=t.length,i=t[0].length;if(void 0===i)return t;const s=e*i;let r=H[s];r||(H[s]=r=new Float32Array(s));for(let s=0;s100||(console.warn(t),K++,K>100&&console.warn("More than 100 program warnings - stopping logs."))}function tt(t,e,i){let s=e[0],r=e[1],n=e[2],h=e[3],a=e[4],o=e[5],l=e[6],u=e[7],c=e[8],d=i[0],g=i[1],p=i[2],m=i[3],f=i[4],w=i[5],v=i[6],x=i[7],b=i[8];return t[0]=d*s+g*h+p*l,t[1]=d*r+g*a+p*u,t[2]=d*n+g*o+p*c,t[3]=m*s+f*h+w*l,t[4]=m*r+f*a+w*u,t[5]=m*n+f*o+w*c,t[6]=v*s+x*h+b*l,t[7]=v*r+x*a+b*u,t[8]=v*n+x*o+b*c,t}class et extends Array{constructor(t=1,e=0,i=0,s=0,r=1,n=0,h=0,a=0,o=1){return super(t,e,i,s,r,n,h,a,o),this}set(t,e,i,s,r,n,h,a,o){return t.length?this.copy(t):(function(t,e,i,s,r,n,h,a,o,l){t[0]=e,t[1]=i,t[2]=s,t[3]=r,t[4]=n,t[5]=h,t[6]=a,t[7]=o,t[8]=l}(this,t,e,i,s,r,n,h,a,o),this)}translate(t,e=this){return function(t,e,i){let s=e[0],r=e[1],n=e[2],h=e[3],a=e[4],o=e[5],l=e[6],u=e[7],c=e[8],d=i[0],g=i[1];t[0]=s,t[1]=r,t[2]=n,t[3]=h,t[4]=a,t[5]=o,t[6]=d*s+g*h+l,t[7]=d*r+g*a+u,t[8]=d*n+g*o+c}(this,e,t),this}rotate(t,e=this){return function(t,e,i){let s=e[0],r=e[1],n=e[2],h=e[3],a=e[4],o=e[5],l=e[6],u=e[7],c=e[8],d=Math.sin(i),g=Math.cos(i);t[0]=g*s+d*h,t[1]=g*r+d*a,t[2]=g*n+d*o,t[3]=g*h-d*s,t[4]=g*a-d*r,t[5]=g*o-d*n,t[6]=l,t[7]=u,t[8]=c}(this,e,t),this}scale(t,e=this){return function(t,e,i){let s=i[0],r=i[1];t[0]=s*e[0],t[1]=s*e[1],t[2]=s*e[2],t[3]=r*e[3],t[4]=r*e[4],t[5]=r*e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8]}(this,e,t),this}multiply(t,e){return e?tt(this,t,e):tt(this,this,t),this}identity(){var t;return(t=this)[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,this}copy(t){var e,i;return i=t,(e=this)[0]=i[0],e[1]=i[1],e[2]=i[2],e[3]=i[3],e[4]=i[4],e[5]=i[5],e[6]=i[6],e[7]=i[7],e[8]=i[8],this}fromMatrix4(t){var e,i;return i=t,(e=this)[0]=i[0],e[1]=i[1],e[2]=i[2],e[3]=i[4],e[4]=i[5],e[5]=i[6],e[6]=i[8],e[7]=i[9],e[8]=i[10],this}fromQuaternion(t){return function(t,e){let i=e[0],s=e[1],r=e[2],n=e[3],h=i+i,a=s+s,o=r+r,l=i*h,u=s*h,c=s*a,d=r*h,g=r*a,p=r*o,m=n*h,f=n*a,w=n*o;t[0]=1-c-p,t[3]=u-w,t[6]=d+f,t[1]=u+w,t[4]=1-l-p,t[7]=g-m,t[2]=d-f,t[5]=g+m,t[8]=1-l-c}(this,t),this}fromBasis(t,e,i){return this.set(t[0],t[1],t[2],e[0],e[1],e[2],i[0],i[1],i[2]),this}inverse(t=this){return function(t,e){let i=e[0],s=e[1],r=e[2],n=e[3],h=e[4],a=e[5],o=e[6],l=e[7],u=e[8],c=u*h-a*l,d=-u*n+a*o,g=l*n-h*o,p=i*c+s*d+r*g;p&&(p=1/p,t[0]=c*p,t[1]=(-u*s+r*l)*p,t[2]=(a*s-r*h)*p,t[3]=d*p,t[4]=(u*i-r*o)*p,t[5]=(-a*i+r*n)*p,t[6]=g*p,t[7]=(-l*i+s*o)*p,t[8]=(h*i-s*n)*p)}(this,t),this}getNormalMatrix(t){return function(t,e){let i=e[0],s=e[1],r=e[2],n=e[3],h=e[4],a=e[5],o=e[6],l=e[7],u=e[8],c=e[9],d=e[10],g=e[11],p=e[12],m=e[13],f=e[14],w=e[15],v=i*a-s*h,x=i*o-r*h,b=i*l-n*h,E=s*o-r*a,M=s*l-n*a,y=r*l-n*o,A=u*m-c*p,S=u*f-d*p,T=u*w-g*p,_=c*f-d*m,F=c*w-g*m,R=d*w-g*f,P=v*R-x*F+b*_+E*T-M*S+y*A;P&&(P=1/P,t[0]=(a*R-o*F+l*_)*P,t[1]=(o*T-h*R-l*S)*P,t[2]=(h*F-a*T+l*A)*P,t[3]=(r*F-s*R-n*_)*P,t[4]=(i*R-r*T+n*S)*P,t[5]=(s*T-i*F-n*A)*P,t[6]=(m*y-f*M+w*E)*P,t[7]=(f*b-p*y-w*x)*P,t[8]=(p*M-m*b+w*v)*P)}(this,t),this}}let it=0;class st extends R{constructor(t,{geometry:e,program:i,mode:s=t.TRIANGLES,frustumCulled:r=!0,renderOrder:n=0}={}){super(),t.canvas||console.error("gl not passed as first argument to Mesh"),this.gl=t,this.id=it++,this.geometry=e,this.program=i,this.mode=s,this.frustumCulled=r,this.renderOrder=n,this.modelViewMatrix=new T,this.normalMatrix=new et,this.beforeRenderCallbacks=[],this.afterRenderCallbacks=[]}onBeforeRender(t){return this.beforeRenderCallbacks.push(t),this}onAfterRender(t){return this.afterRenderCallbacks.push(t),this}draw({camera:t}={}){this.beforeRenderCallbacks.forEach(e=>e&&e({mesh:this,camera:t})),t&&(this.program.uniforms.modelMatrix||Object.assign(this.program.uniforms,{modelMatrix:{value:null},viewMatrix:{value:null},modelViewMatrix:{value:null},normalMatrix:{value:null},projectionMatrix:{value:null},cameraPosition:{value:null}}),this.program.uniforms.projectionMatrix.value=t.projectionMatrix,this.program.uniforms.cameraPosition.value=t.worldPosition,this.program.uniforms.viewMatrix.value=t.viewMatrix,this.modelViewMatrix.multiply(t.viewMatrix,this.worldMatrix),this.normalMatrix.getNormalMatrix(this.modelViewMatrix),this.program.uniforms.modelMatrix.value=this.worldMatrix,this.program.uniforms.modelViewMatrix.value=this.modelViewMatrix,this.program.uniforms.normalMatrix.value=this.normalMatrix);let e=this.program.cullFace&&this.worldMatrix.determinant()<0;this.program.use({flipFaces:e}),this.geometry.draw({mode:this.mode,program:this.program}),this.afterRenderCallbacks.forEach(e=>e&&e({mesh:this,camera:t}))}}class rt{constructor(t,{width:e=t.canvas.width,height:i=t.canvas.height,target:s=t.FRAMEBUFFER,color:r=1,depth:n=!0,stencil:h=!1,depthTexture:a=!1,wrapS:o=t.CLAMP_TO_EDGE,wrapT:l=t.CLAMP_TO_EDGE,minFilter:u=t.LINEAR,magFilter:c=u,type:d=t.UNSIGNED_BYTE,format:g=t.RGBA,internalFormat:p=g,unpackAlignment:m,premultiplyAlpha:f}={}){this.gl=t,this.width=e,this.height=i,this.depth=n,this.buffer=this.gl.createFramebuffer(),this.target=s,this.gl.bindFramebuffer(this.target,this.buffer),this.textures=[];const w=[];for(let s=0;s1&&this.gl.renderer.drawBuffers(w),this.texture=this.textures[0],a&&(this.gl.renderer.isWebgl2||this.gl.renderer.getExtension("WEBGL_depth_texture"))?(this.depthTexture=new j(t,{width:e,height:i,minFilter:this.gl.NEAREST,magFilter:this.gl.NEAREST,format:this.gl.DEPTH_COMPONENT,internalFormat:t.renderer.isWebgl2?this.gl.DEPTH_COMPONENT16:this.gl.DEPTH_COMPONENT,type:this.gl.UNSIGNED_INT}),this.depthTexture.update(),this.gl.framebufferTexture2D(this.target,this.gl.DEPTH_ATTACHMENT,this.gl.TEXTURE_2D,this.depthTexture.texture,0)):(n&&!h&&(this.depthBuffer=this.gl.createRenderbuffer(),this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,this.depthBuffer),this.gl.renderbufferStorage(this.gl.RENDERBUFFER,this.gl.DEPTH_COMPONENT16,e,i),this.gl.framebufferRenderbuffer(this.target,this.gl.DEPTH_ATTACHMENT,this.gl.RENDERBUFFER,this.depthBuffer)),h&&!n&&(this.stencilBuffer=this.gl.createRenderbuffer(),this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,this.stencilBuffer),this.gl.renderbufferStorage(this.gl.RENDERBUFFER,this.gl.STENCIL_INDEX8,e,i),this.gl.framebufferRenderbuffer(this.target,this.gl.STENCIL_ATTACHMENT,this.gl.RENDERBUFFER,this.stencilBuffer)),n&&h&&(this.depthStencilBuffer=this.gl.createRenderbuffer(),this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,this.depthStencilBuffer),this.gl.renderbufferStorage(this.gl.RENDERBUFFER,this.gl.DEPTH_STENCIL,e,i),this.gl.framebufferRenderbuffer(this.target,this.gl.DEPTH_STENCIL_ATTACHMENT,this.gl.RENDERBUFFER,this.depthStencilBuffer))),this.gl.bindFramebuffer(this.target,null)}}class nt extends O{constructor(t,{attributes:e={}}={}){Object.assign(e,{position:{size:2,data:new Float32Array([-1,-1,3,-1,-1,3])},uv:{size:2,data:new Float32Array([0,0,2,0,0,2])}}),super(t,e)}}class ht{constructor(t,{width:e,height:i,dpr:s,wrapS:r=t.CLAMP_TO_EDGE,wrapT:n=t.CLAMP_TO_EDGE,minFilter:h=t.LINEAR,magFilter:a=t.LINEAR,geometry:o=new nt(t),targetOnly:l=null}={}){this.gl=t,this.options={wrapS:r,wrapT:n,minFilter:h,magFilter:a},this.passes=[],this.geometry=o,this.uniform={value:null},this.targetOnly=l;const u=this.fbo={read:null,write:null,swap:()=>{let t=u.read;u.read=u.write,u.write=t}};this.resize({width:e,height:i,dpr:s})}addPass({vertex:t=at,fragment:e=ot,uniforms:i={},textureUniform:s="tMap",enabled:r=!0}={}){i[s]={value:this.fbo.read.texture};const n=new Z(this.gl,{vertex:t,fragment:e,uniforms:i}),h={mesh:new st(this.gl,{geometry:this.geometry,program:n}),program:n,uniforms:i,enabled:r,textureUniform:s};return this.passes.push(h),h}resize({width:t,height:e,dpr:i}={}){i&&(this.dpr=i),t&&(this.width=t,this.height=e||t),i=this.dpr||this.gl.renderer.dpr,t=(this.width||this.gl.renderer.width)*i,e=(this.height||this.gl.renderer.height)*i,this.options.width=t,this.options.height=e,this.fbo.read=new rt(this.gl,this.options),this.fbo.write=new rt(this.gl,this.options)}render({scene:t,camera:e,target:i=null,update:s=!0,sort:r=!0,frustumCull:n=!0}){const h=this.passes.filter(t=>t.enabled);this.gl.renderer.render({scene:t,camera:e,target:h.length||!i&&this.targetOnly?this.fbo.write:i,update:s,sort:r,frustumCull:n}),this.fbo.swap(),h.forEach((t,e)=>{t.mesh.program.uniforms[t.textureUniform].value=this.fbo.read.texture,this.gl.renderer.render({scene:t.mesh,target:e!==h.length-1||!i&&this.targetOnly?this.fbo.write:i,clear:!0}),this.fbo.swap()}),this.uniform.value=this.fbo.read.texture}}const at="\n attribute vec2 uv;\n attribute vec2 position;\n\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = vec4(position, 0, 1);\n }\n",ot="\n precision highp float;\n\n uniform sampler2D tMap;\n varying vec2 vUv;\n\n void main() {\n gl_FragColor = texture2D(tMap, vUv);\n }\n";function lt(t,e,i){return t[0]=e[0]+i[0],t[1]=e[1]+i[1],t}function ut(t,e,i){return t[0]=e[0]-i[0],t[1]=e[1]-i[1],t}function ct(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t}function dt(t){var e=t[0],i=t[1];return Math.sqrt(e*e+i*i)}function gt(t,e){return t[0]*e[1]-t[1]*e[0]}class pt extends Array{constructor(t=0,e=t){return super(t,e),this}get x(){return this[0]}get y(){return this[1]}set x(t){this[0]=t}set y(t){this[1]=t}set(t,e=t){return t.length?this.copy(t):(function(t,e,i){t[0]=e,t[1]=i}(this,t,e),this)}copy(t){var e,i;return i=t,(e=this)[0]=i[0],e[1]=i[1],this}add(t,e){return e?lt(this,t,e):lt(this,this,t),this}sub(t,e){return e?ut(this,t,e):ut(this,this,t),this}multiply(t){var e,i,s;return t.length?(i=this,s=t,(e=this)[0]=i[0]*s[0],e[1]=i[1]*s[1]):ct(this,this,t),this}divide(t){var e,i,s;return t.length?(i=this,s=t,(e=this)[0]=i[0]/s[0],e[1]=i[1]/s[1]):ct(this,this,1/t),this}inverse(t=this){var e,i;return i=t,(e=this)[0]=1/i[0],e[1]=1/i[1],this}len(){return dt(this)}distance(t){return t?(e=this,s=(i=t)[0]-e[0],r=i[1]-e[1],Math.sqrt(s*s+r*r)):dt(this);var e,i,s,r}squaredLen(){return this.squaredDistance()}squaredDistance(t){return t?(e=this,s=(i=t)[0]-e[0],r=i[1]-e[1],s*s+r*r):function(t){var e=t[0],i=t[1];return e*e+i*i}(this);var e,i,s,r}negate(t=this){var e,i;return i=t,(e=this)[0]=-i[0],e[1]=-i[1],this}cross(t,e){return e?gt(t,e):gt(this,t)}scale(t){return ct(this,this,t),this}normalize(){var t,e,i,s,r;return t=this,i=(e=this)[0],s=e[1],(r=i*i+s*s)>0&&(r=1/Math.sqrt(r)),t[0]=e[0]*r,t[1]=e[1]*r,this}dot(t){return i=t,(e=this)[0]*i[0]+e[1]*i[1];var e,i}equals(t){return i=t,(e=this)[0]===i[0]&&e[1]===i[1];var e,i}applyMatrix3(t){var e,i,s,r,n;return e=this,s=t,r=(i=this)[0],n=i[1],e[0]=s[0]*r+s[3]*n+s[6],e[1]=s[1]*r+s[4]*n+s[7],this}applyMatrix4(t){return function(t,e,i){let s=e[0],r=e[1];t[0]=i[0]*s+i[4]*r+i[12],t[1]=i[1]*s+i[5]*r+i[13]}(this,this,t),this}lerp(t,e){!function(t,e,i,s){var r=e[0],n=e[1];t[0]=r+s*(i[0]-r),t[1]=n+s*(i[1]-n)}(this,this,t,e)}clone(){return new pt(this[0],this[1])}fromArray(t,e=0){return this[0]=t[e],this[1]=t[e+1],this}toArray(t=[],e=0){return t[e]=this[0],t[e+1]=this[1],t}}new([class{constructor(){this.scroll={ease:.05,current:0,target:0,last:0},this.speed=2,this.createRenderer(),this.createCamera(),this.createScene(),this.createGallery(),this.onResize(),this.createGeometry(),this.createMedias(),this.update(),this.addEventListeners()}createGallery(){this.gallery=document.querySelector(".demo-1__gallery")}createRenderer(){this.renderer=new f({alpha:!0}),this.gl=this.renderer.gl,document.body.appendChild(this.gl.canvas)}createCamera(){this.camera=new I(this.gl),this.camera.fov=45,this.camera.position.z=5}createScene(){this.scene=new R}createGeometry(){this.planeGeometry=new z(this.gl,{heightSegments:10})}createMedias(){this.mediasElements=document.querySelectorAll(".demo-1__gallery__figure"),this.medias=Array.from(this.mediasElements).map(t=>new class{constructor({element:t,geometry:e,gl:i,height:s,scene:r,screen:n,viewport:h}){this.element=t,this.image=this.element.querySelector("img"),this.extra=0,this.height=s,this.geometry=e,this.gl=i,this.scene=r,this.screen=n,this.viewport=h,this.createMesh(),this.createBounds(),this.onResize()}createMesh(){const t=new Image,e=new j(this.gl,{generateMipmaps:!1});t.src=this.image.src,t.onload=s=>{i.uniforms.uImageSizes.value=[t.naturalWidth,t.naturalHeight],e.image=t};const i=new Z(this.gl,{fragment:"precision highp float;\n#define GLSLIFY 1\n\nuniform vec2 uImageSizes;\nuniform vec2 uPlaneSizes;\nuniform sampler2D tMap;\n\nvarying vec2 vUv;\n\nvoid main() {\n vec2 ratio = vec2(\n min((uPlaneSizes.x / uPlaneSizes.y) / (uImageSizes.x / uImageSizes.y), 1.0),\n min((uPlaneSizes.y / uPlaneSizes.x) / (uImageSizes.y / uImageSizes.x), 1.0)\n );\n\n vec2 uv = vec2(\n vUv.x * ratio.x + (1.0 - ratio.x) * 0.5,\n vUv.y * ratio.y + (1.0 - ratio.y) * 0.5\n );\n\n gl_FragColor.rgb = texture2D(tMap, uv).rgb;\n gl_FragColor.a = 1.0;\n}\n",vertex:"#define PI 3.1415926535897932384626433832795\n\nprecision highp float;\nprecision highp int;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute vec2 uv;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\n\nuniform float uStrength;\nuniform vec2 uViewportSizes;\n\nvarying vec2 vUv;\n\nvoid main() {\n vec4 newPosition = modelViewMatrix * vec4(position, 1.0);\n\n newPosition.z += sin(newPosition.y / uViewportSizes.y * PI + PI / 2.0) * -uStrength;\n\n vUv = uv;\n\n gl_Position = projectionMatrix * newPosition;\n}\n",uniforms:{tMap:{value:e},uPlaneSizes:{value:[0,0]},uImageSizes:{value:[0,0]},uViewportSizes:{value:[this.viewport.width,this.viewport.height]},uStrength:{value:0}},transparent:!0});this.plane=new st(this.gl,{geometry:this.geometry,program:i}),this.plane.setParent(this.scene)}createBounds(){this.bounds=this.element.getBoundingClientRect(),this.updateScale(),this.updateX(),this.updateY(),this.plane.program.uniforms.uPlaneSizes.value=[this.plane.scale.x,this.plane.scale.y]}updateScale(){this.plane.scale.x=this.viewport.width*this.bounds.width/this.screen.width,this.plane.scale.y=this.viewport.height*this.bounds.height/this.screen.height}updateX(t=0){this.plane.position.x=-this.viewport.width/2+this.plane.scale.x/2+(this.bounds.left-t)/this.screen.width*this.viewport.width}updateY(t=0){this.plane.position.y=this.viewport.height/2-this.plane.scale.y/2-(this.bounds.top-t)/this.screen.height*this.viewport.height-this.extra}update(t,e){this.updateScale(),this.updateX(),this.updateY(t.current);const i=this.plane.scale.y/2,s=this.viewport.height/2;this.isBefore=this.plane.position.y+i<-s,this.isAfter=this.plane.position.y-i>s,"up"===e&&this.isBefore&&(this.extra-=this.height,this.isBefore=!1,this.isAfter=!1),"down"===e&&this.isAfter&&(this.extra+=this.height,this.isBefore=!1,this.isAfter=!1),this.plane.program.uniforms.uStrength.value=(t.current-t.last)/this.screen.width*10}onResize(t){if(this.extra=0,t){const{height:e,screen:i,viewport:s}=t;e&&(this.height=e),i&&(this.screen=i),s&&(this.viewport=s,this.plane.program.uniforms.uViewportSizes.value=[this.viewport.width,this.viewport.height])}this.createBounds()}}({element:t,geometry:this.planeGeometry,gl:this.gl,height:this.galleryHeight,scene:this.scene,screen:this.screen,viewport:this.viewport}))}onTouchDown(t){this.isDown=!0,this.scroll.position=this.scroll.current,this.start=t.touches?t.touches[0].clientY:t.clientY}onTouchMove(t){if(!this.isDown)return;const e=t.touches?t.touches[0].clientY:t.clientY,i=2*(this.start-e);this.scroll.target=this.scroll.position+i}onTouchUp(t){this.isDown=!1}onWheel(t){const e=X()(t).pixelY;this.scroll.target+=.5*e}onResize(){this.screen={height:window.innerHeight,width:window.innerWidth},this.renderer.setSize(this.screen.width,this.screen.height),this.camera.perspective({aspect:this.gl.canvas.width/this.gl.canvas.height});const t=this.camera.fov*(Math.PI/180),e=2*Math.tan(t/2)*this.camera.position.z,i=e*this.camera.aspect;this.viewport={height:e,width:i},this.galleryBounds=this.gallery.getBoundingClientRect(),this.galleryHeight=this.viewport.height*this.galleryBounds.height/this.screen.height,this.medias&&this.medias.forEach(t=>t.onResize({height:this.galleryHeight,screen:this.screen,viewport:this.viewport}))}update(){this.scroll.target+=this.speed,this.scroll.current=q(this.scroll.current,this.scroll.target,this.scroll.ease),this.scroll.current>this.scroll.last?(this.direction="down",this.speed=2):this.scroll.currentt.update(this.scroll,this.direction)),this.renderer.render({scene:this.scene,camera:this.camera}),this.scroll.last=this.scroll.current,window.requestAnimationFrame(this.update.bind(this))}addEventListeners(){window.addEventListener("resize",this.onResize.bind(this)),window.addEventListener("mousewheel",this.onWheel.bind(this)),window.addEventListener("wheel",this.onWheel.bind(this)),window.addEventListener("mousedown",this.onTouchDown.bind(this)),window.addEventListener("mousemove",this.onTouchMove.bind(this)),window.addEventListener("mouseup",this.onTouchUp.bind(this)),window.addEventListener("touchstart",this.onTouchDown.bind(this)),window.addEventListener("touchmove",this.onTouchMove.bind(this)),window.addEventListener("touchend",this.onTouchUp.bind(this))}},class{constructor(){this.scroll={ease:.05,current:0,target:0,last:0},this.speed=2,this.createRenderer(),this.createCamera(),this.createScene(),this.createGallery(),this.createPost(),this.onResize(),this.createGeometry(),this.createMedias(),this.update(),this.addEventListeners()}createGallery(){this.gallery=document.querySelector(".demo-2__gallery")}createRenderer(){this.renderer=new f({alpha:!0}),this.gl=this.renderer.gl,document.body.appendChild(this.gl.canvas)}createCamera(){this.camera=new I(this.gl),this.camera.fov=45,this.camera.position.z=5}createScene(){this.scene=new R}createPost(){this.post=new ht(this.gl),this.pass=this.post.addPass({fragment:"precision highp float;\n#define GLSLIFY 1\n\nuniform sampler2D tMap;\n\nuniform vec2 uResolution;\nuniform float uStrength;\n\nvarying vec2 vUv;\n\nvoid main() {\n vec3 color;\n\n color.r = texture2D(tMap, vec2(vUv.x + uStrength, vUv.y)).r;\n color.g = texture2D(tMap, vUv).g;\n color.b = texture2D(tMap, vec2(vUv.x - uStrength, vUv.y)).b;\n\n gl_FragColor = vec4(color, 1.0);\n}\n",uniforms:{uResolution:this.resolution,uStrength:{value:0}}}),this.resolution={value:new pt}}createGeometry(){this.planeGeometry=new z(this.gl,{widthSegments:20})}createMedias(){this.mediasElements=document.querySelectorAll(".demo-2__gallery__figure"),this.medias=Array.from(this.mediasElements).map(t=>new class{constructor({element:t,geometry:e,gl:i,scene:s,screen:r,viewport:n,width:h}){this.element=t,this.image=this.element.querySelector("img"),this.extra=0,this.geometry=e,this.gl=i,this.scene=s,this.screen=r,this.viewport=n,this.width=h,this.createMesh(),this.createBounds(),this.onResize()}createMesh(){const t=new Image,e=new j(this.gl,{generateMipmaps:!1});t.src=this.image.src,t.onload=s=>{i.uniforms.uImageSizes.value=[t.naturalWidth,t.naturalHeight],e.image=t};const i=new Z(this.gl,{fragment:"precision highp float;\n#define GLSLIFY 1\n\nuniform vec2 uImageSizes;\nuniform vec2 uPlaneSizes;\nuniform sampler2D tMap;\n\nvarying vec2 vUv;\n\nvoid main() {\n vec2 ratio = vec2(\n min((uPlaneSizes.x / uPlaneSizes.y) / (uImageSizes.x / uImageSizes.y), 1.0),\n min((uPlaneSizes.y / uPlaneSizes.x) / (uImageSizes.y / uImageSizes.x), 1.0)\n );\n\n vec2 uv = vec2(\n vUv.x * ratio.x + (1.0 - ratio.x) * 0.5,\n vUv.y * ratio.y + (1.0 - ratio.y) * 0.5\n );\n\n gl_FragColor.rgb = texture2D(tMap, uv).rgb;\n gl_FragColor.a = 1.0;\n}\n",vertex:"#define PI 3.1415926535897932384626433832795\n\nprecision highp float;\nprecision highp int;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute vec2 uv;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\n\nuniform float uStrength;\nuniform vec2 uViewportSizes;\n\nvarying vec2 vUv;\n\nvoid main() {\n vec4 newPosition = modelViewMatrix * vec4(position, 1.0);\n\n newPosition.z += -abs(sin(newPosition.x / uViewportSizes.x * PI + PI / 2.0) * uStrength);\n\n vUv = uv;\n\n gl_Position = projectionMatrix * newPosition;\n}\n",uniforms:{tMap:{value:e},uPlaneSizes:{value:[0,0]},uImageSizes:{value:[0,0]},uViewportSizes:{value:[this.viewport.width,this.viewport.height]},uStrength:{value:0}},transparent:!0});this.plane=new st(this.gl,{geometry:this.geometry,program:i}),this.plane.setParent(this.scene)}createBounds(){this.bounds=this.element.getBoundingClientRect(),this.updateScale(),this.updateX(),this.updateY(),this.plane.program.uniforms.uPlaneSizes.value=[this.plane.scale.x,this.plane.scale.y]}updateScale(){this.plane.scale.x=this.viewport.width*this.bounds.width/this.screen.width,this.plane.scale.y=this.viewport.height*this.bounds.height/this.screen.height}updateX(t=0){this.plane.position.x=-this.viewport.width/2+this.plane.scale.x/2+(this.bounds.left-t)/this.screen.width*this.viewport.width-this.extra}updateY(t=0){this.plane.position.y=this.viewport.height/2-this.plane.scale.y/2-(this.bounds.top-t)/this.screen.height*this.viewport.height}update(t,e){this.updateScale(),this.updateX(t.current),this.updateY();const i=this.plane.scale.x/2,s=this.viewport.width/2;this.isBefore=this.plane.position.x+i<-s,this.isAfter=this.plane.position.x-i>s,"down"===e&&this.isBefore&&(this.extra-=this.width,this.isBefore=!1,this.isAfter=!1),"up"===e&&this.isAfter&&(this.extra+=this.width,this.isBefore=!1,this.isAfter=!1),this.plane.program.uniforms.uStrength.value=(t.current-t.last)/this.screen.width*5}onResize(t){if(this.extra=0,t){const{width:e,screen:i,viewport:s}=t;e&&(this.width=e),i&&(this.screen=i),s&&(this.viewport=s,this.plane.program.uniforms.uViewportSizes.value=[this.viewport.width,this.viewport.height])}this.createBounds()}}({element:t,geometry:this.planeGeometry,gl:this.gl,scene:this.scene,screen:this.screen,viewport:this.viewport,width:this.galleryWidth}))}onTouchDown(t){this.isDown=!0,this.scroll.position=this.scroll.current,this.start=t.touches?t.touches[0].clientX:t.clientX}onTouchMove(t){if(!this.isDown)return;const e=t.touches?t.touches[0].clientX:t.clientX,i=2*(this.start-e);this.scroll.target=this.scroll.position+i}onTouchUp(t){this.isDown=!1}onWheel(t){const e=X()(t).pixelY;this.scroll.target+=.5*e}onResize(){this.screen={height:window.innerHeight,width:window.innerWidth},this.renderer.setSize(this.screen.width,this.screen.height),this.camera.perspective({aspect:this.gl.canvas.width/this.gl.canvas.height});const t=this.camera.fov*(Math.PI/180),e=2*Math.tan(t/2)*this.camera.position.z,i=e*this.camera.aspect;this.viewport={height:e,width:i},this.post.resize(),this.resolution.value.set(this.gl.canvas.width,this.gl.canvas.height),this.galleryBounds=this.gallery.getBoundingClientRect(),this.galleryWidth=this.viewport.width*this.galleryBounds.width/this.screen.width,this.medias&&this.medias.forEach(t=>t.onResize({screen:this.screen,viewport:this.viewport,width:this.galleryWidth}))}update(){this.scroll.target+=this.speed,this.scroll.current=q(this.scroll.current,this.scroll.target,this.scroll.ease),this.scroll.current>this.scroll.last?(this.direction="down",this.speed=2):this.scroll.currentt.update(this.scroll,this.direction)),this.pass.uniforms.uStrength.value=(this.scroll.current-this.scroll.last)/this.screen.width*.5,this.post.render({scene:this.scene,camera:this.camera}),this.scroll.last=this.scroll.current,window.requestAnimationFrame(this.update.bind(this))}addEventListeners(){window.addEventListener("resize",this.onResize.bind(this)),window.addEventListener("mousewheel",this.onWheel.bind(this)),window.addEventListener("wheel",this.onWheel.bind(this)),window.addEventListener("mousedown",this.onTouchDown.bind(this)),window.addEventListener("mousemove",this.onTouchMove.bind(this)),window.addEventListener("mouseup",this.onTouchUp.bind(this)),window.addEventListener("touchstart",this.onTouchDown.bind(this)),window.addEventListener("touchmove",this.onTouchMove.bind(this)),window.addEventListener("touchend",this.onTouchUp.bind(this))}}][document.body.getAttribute("data-id")]),document.documentElement.classList.remove("no-js"),document.documentElement.classList.add("js");const mt=document.querySelectorAll('img:not([src*="https://tympanus.net/codrops/wp-content/banners/"])');let ft=0;Array.from(mt).forEach(t=>{const e=new Image;e.src=t.src,e.onload=t=>{ft+=1,ft===mt.length&&(document.documentElement.classList.remove("loading"),document.documentElement.classList.add("loaded"))}})}]); -------------------------------------------------------------------------------- /InifniteAutoScrollingGallery/main.d263f564555a055f4d35.css: -------------------------------------------------------------------------------- 1 | *{margin:0;padding:0}*,*::after,*::before{box-sizing:border-box}html{background:#0c0c0c;color:#fff;font-size:calc(100vw / 1920 * 10);height:100%;left:0;position:fixed;top:0;user-select:none;width:100%}body{font-family:'halyard-display', sans-serif;font-size:15px;margin:0;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;overscroll-behavior-y:none}body:after{animation:grain 6s steps(10) infinite;background-image:url(62f64d5233f6333080c87c81a9a35f9d.png);background-repeat:repeat;content:'';height:300%;left:-100%;opacity:0;pointer-events:none;position:fixed;top:-100%;transition:opacity 0.4s ease;width:300%;will-change:transform;z-index:3}.loaded body:after{opacity:0.06}body #cdawrap{--cda-bottom: 3rem;--cda-left: 3rem;--cda-width: 400px;--cda-footer-fontsize: initial;--cda-footer-color: rgba(255,255,255,0.5)}body #cdawrap a:hover{text-decoration:none;opacity:0.7}img{display:block}canvas{height:100%;left:0;opacity:0;position:fixed;top:0;transition:opacity 1s ease;width:100%}.loaded canvas{opacity:1}a{color:#fff;outline:none;text-decoration:none}a:hover,a:focus{outline:none}@keyframes grain{0%{transform:translate(20%, -15%)}10%{transform:translate(-20%, -15%)}20%{transform:translate(20%, -5%)}30%{transform:translate(-20%, -5%)}40%{transform:translate(20%, 5%)}50%{transform:translate(-20%, 5%)}60%{transform:translate(20%, 15%)}70%{transform:translate(-20%, 15%)}80%{transform:translate(20%, 5%)}90%{transform:translate(-20%, 5%)}100%{transform:translate(20%, -5%)}}.frame{font-size:15px;padding:3rem;text-align:center;position:relative;z-index:1000}.frame__title{font-size:15px;margin:0 0 15px;font-weight:normal}.frame__links{margin-top:15px}.frame__links a:not(:last-child),.frame__demos a:not(:last-child){margin-right:15px}.frame__demos{margin:15px 0}@media screen and (min-width: 53em){.frame{position:fixed;text-align:left;z-index:100;top:0;left:0;display:grid;align-content:space-between;width:100%;max-width:none;height:100vh;padding:3rem;pointer-events:none;grid-template-columns:75% 25%;grid-template-rows:auto auto auto;grid-template-areas:'title links' '... ...' 'credits demos'}.frame__title-wrap{grid-area:title;display:flex}.frame__title{margin:0}.frame__tagline{position:relative;margin:0 0 0 1rem;padding:0 0 0 1rem;opacity:0.5}.frame__demos{margin:0;grid-area:demos;justify-self:end}.frame__links{grid-area:links;padding:0;margin:0;justify-self:end;white-space:nowrap}.frame a{pointer-events:auto}.frame__credits{grid-area:credits}}html::after{content:'';position:fixed;z-index:1000;top:50%;left:50%;width:60px;height:60px;margin:-30px 0 0 -30px;border-radius:50%;opacity:0.4;background:#fff;animation:loaderAnim 0.7s linear infinite alternate forwards;transition:opacity 0.4s ease}html.loaded::after{animation-play-state:paused;opacity:0 !important}@keyframes loaderAnim{to{opacity:1;transform:scale3d(0.5, 0.5, 1)}}.frame__demo--current,.frame__demo--current:hover,a{display:inline-block;overflow:hidden;position:relative;vertical-align:top}.frame__demo--current:after,.frame__demo--current:hover:after,a:after{background:currentColor;bottom:0;content:'';height:1px;left:0;position:absolute;transition:transform 0.4s ease;width:100%}.frame__demo--current:after,.frame__demo--current:hover:after,a:hover:after{transform:scaleX(1);transform-origin:left center}.frame__demo--current:hover:after,a:after{transform:scaleX(0);transform-origin:right center}.frame__demo--current,.frame__demo--current:hover{display:inline-block}a{display:inline-block}.demo-1{height:100%;left:0;overflow:hidden;position:fixed;top:0;width:100%;z-index:1}.demo-1__header{align-items:center;display:flex;flex-direction:column;height:100%;justify-content:center;left:0;opacity:0;position:fixed;top:0;width:100%;z-index:2}.loaded .demo-1__header{opacity:1;transition:opacity 0.4s ease}.demo-1__title{font:800 20rem/1 'moret', serif}.demo-1__description{font-size:2rem;margin-top:-1rem;opacity:0.75}.demo-1__gallery{height:295rem;position:relative;visibility:hidden}@media (max-width: 1200px){.demo-1__gallery{height:650rem}}.demo-1__gallery__figure{position:absolute}.demo-1__gallery__figure:nth-child(1){height:40rem;width:70rem}.demo-1__gallery__figure:nth-child(2){height:50rem;left:85rem;top:30rem;width:40rem}.demo-1__gallery__figure:nth-child(3){height:50rem;left:15rem;top:60rem;width:60rem}.demo-1__gallery__figure:nth-child(4){height:30rem;right:0;top:10rem;width:50rem}.demo-1__gallery__figure:nth-child(5){height:60rem;right:15rem;top:55rem;width:40rem}.demo-1__gallery__figure:nth-child(6){height:75rem;left:5rem;top:120rem;width:57.5rem}.demo-1__gallery__figure:nth-child(7){height:70rem;right:0;top:130rem;width:50rem}.demo-1__gallery__figure:nth-child(8){height:50rem;left:85rem;top:95rem;width:40rem}.demo-1__gallery__figure:nth-child(9){height:65rem;left:75rem;top:155rem;width:50rem}.demo-1__gallery__figure:nth-child(10){height:43rem;right:0;top:215rem;width:30rem}.demo-1__gallery__figure:nth-child(11){height:50rem;left:70rem;top:235rem;width:80rem}.demo-1__gallery__figure:nth-child(12){left:0;top:210rem;height:70rem;width:50rem}@media (max-width: 1200px){.demo-1__gallery__figure:nth-child(1){height:60rem;width:100rem}.demo-1__gallery__figure:nth-child(2){height:110rem;left:auto;right:0;top:25rem;width:70rem}.demo-1__gallery__figure:nth-child(3){height:80rem;left:12rem;top:80rem;width:89rem}.demo-1__gallery__figure:nth-child(4){height:60rem;right:0;top:153rem;width:60rem}.demo-1__gallery__figure:nth-child(5){height:110rem;left:0;right:auto;top:180rem;width:70rem}.demo-1__gallery__figure:nth-child(6){height:135rem;left:95rem;top:230rem;width:87.5rem}.demo-1__gallery__figure:nth-child(7){height:110rem;left:0;right:auto;top:310rem;width:80rem}.demo-1__gallery__figure:nth-child(8){height:50rem;left:auto;right:0;top:385rem;width:80rem}.demo-1__gallery__figure:nth-child(9){height:100rem;left:110rem;top:450rem;width:70rem}.demo-1__gallery__figure:nth-child(10){height:50rem;left:20rem;right:auto;top:440rem;width:55rem}.demo-1__gallery__figure:nth-child(11){height:70rem;left:auto;right:0;top:570rem;width:70rem}.demo-1__gallery__figure:nth-child(12){left:0;top:515rem;height:100rem;width:90rem}}.demo-1__gallery__image{height:100%;left:0;object-fit:cover;position:absolute;top:0;width:100%}.demo-2{height:100%;left:0;position:fixed;top:0;width:100%;z-index:1}.demo-2__header{align-items:center;display:flex;flex-direction:column;height:100%;justify-content:center;left:0;opacity:0;position:fixed;top:0;width:100%;z-index:2}.loaded .demo-2__header{opacity:1;transition:opacity 0.4s ease}.demo-2__title{font:800 20rem/1 'moret', serif}.demo-2__description{font-size:2rem;margin-top:-1rem;opacity:0.75}.demo-2__gallery{height:100%;position:relative;width:520rem;visibility:hidden}.demo-2__gallery__figure{position:absolute}.demo-2__gallery__figure:nth-child(1){height:80rem;left:0;top:0;width:53rem}.demo-2__gallery__figure:nth-child(2){height:70rem;left:73rem;bottom:0;width:47rem}.demo-2__gallery__figure:nth-child(3){height:90rem;left:140rem;top:10rem;width:60rem}.demo-2__gallery__figure:nth-child(4){height:75rem;left:220rem;top:0;width:50rem}.demo-2__gallery__figure:nth-child(5){bottom:0;height:75rem;left:290rem;width:50rem}.demo-2__gallery__figure:nth-child(6){height:75rem;left:360rem;top:20rem;width:50rem}.demo-2__gallery__figure:nth-child(7){height:75rem;left:430rem;top:30rem;width:70rem}.demo-2__gallery__image{height:100%;left:0;object-fit:cover;position:absolute;top:0;width:100%} 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2009 - 2020 [Codrops](https://tympanus.net/codrops) 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Infinite WebGL Images 2 | 3 | A tutorial explaining how to build an infinite scrolling gallery using WebGL with OGL and GLSL Shaders. 4 | 5 | ![Final Result](cover.jpg) 6 | 7 | [Article on Codrops](https://tympanus.net/codrops/?p=52634) 8 | 9 | [Demo](http://tympanus.net/Development/.../) 10 | 11 | ## Installation 12 | 13 | Install dependencies: 14 | 15 | ``` 16 | npm install 17 | ``` 18 | 19 | Compile the code for development and start a local server: 20 | 21 | ``` 22 | npm start 23 | ``` 24 | 25 | Create the build: 26 | 27 | ``` 28 | npm run build 29 | ``` 30 | 31 | ## Credits 32 | 33 | - https://unsplash.com/@planeteelevene 34 | - https://unsplash.com/@jayson_hinrichsen 35 | 36 | ## Misc 37 | 38 | Follow Luis Henrique Bizarro: [Website](https://bizar.ro/), [Twitter](https://twitter.com/lhbizarro), [GitHub](https://github.com/lhbizarro) 39 | 40 | Follow Codrops: [Twitter](http://www.twitter.com/codrops), [Facebook](http://www.facebook.com/codrops), [GitHub](https://github.com/codrops), [Instagram](https://www.instagram.com/codropsss/) 41 | 42 | ## License 43 | [MIT](LICENSE) 44 | 45 | Made with :blue_heart: by [Codrops](http://www.codrops.com) 46 | -------------------------------------------------------------------------------- /app/demo-1.js: -------------------------------------------------------------------------------- 1 | import { Renderer, Camera, Transform, Plane } from 'ogl' 2 | import NormalizeWheel from 'normalize-wheel' 3 | 4 | import { lerp } from 'utils/math' 5 | 6 | import Media from './demo-1/Media' 7 | 8 | export default class App { 9 | constructor () { 10 | this.scroll = { 11 | ease: 0.05, 12 | current: 0, 13 | target: 0, 14 | last: 0 15 | } 16 | 17 | this.speed = 2 18 | 19 | this.createRenderer() 20 | this.createCamera() 21 | this.createScene() 22 | this.createGallery() 23 | 24 | this.onResize() 25 | 26 | this.createGeometry() 27 | this.createMedias() 28 | 29 | this.update() 30 | 31 | this.addEventListeners() 32 | } 33 | 34 | createGallery () { 35 | this.gallery = document.querySelector('.demo-1__gallery') 36 | } 37 | 38 | createRenderer () { 39 | this.renderer = new Renderer({ 40 | alpha: true 41 | }) 42 | 43 | this.gl = this.renderer.gl 44 | 45 | document.body.appendChild(this.gl.canvas) 46 | } 47 | 48 | createCamera () { 49 | this.camera = new Camera(this.gl) 50 | this.camera.fov = 45 51 | this.camera.position.z = 5 52 | } 53 | 54 | createScene () { 55 | this.scene = new Transform() 56 | } 57 | 58 | createGeometry () { 59 | this.planeGeometry = new Plane(this.gl, { 60 | heightSegments: 10 61 | }) 62 | } 63 | 64 | createMedias () { 65 | this.mediasElements = document.querySelectorAll('.demo-1__gallery__figure') 66 | this.medias = Array.from(this.mediasElements).map(element => { 67 | let media = new Media({ 68 | element, 69 | geometry: this.planeGeometry, 70 | gl: this.gl, 71 | height: this.galleryHeight, 72 | scene: this.scene, 73 | screen: this.screen, 74 | viewport: this.viewport 75 | }) 76 | 77 | return media 78 | }) 79 | } 80 | 81 | /** 82 | * Events. 83 | */ 84 | onTouchDown (event) { 85 | this.isDown = true 86 | 87 | this.scroll.position = this.scroll.current 88 | this.start = event.touches ? event.touches[0].clientY : event.clientY 89 | } 90 | 91 | onTouchMove (event) { 92 | if (!this.isDown) return 93 | 94 | const y = event.touches ? event.touches[0].clientY : event.clientY 95 | const distance = (this.start - y) * 2 96 | 97 | this.scroll.target = this.scroll.position + distance 98 | } 99 | 100 | onTouchUp (event) { 101 | this.isDown = false 102 | } 103 | 104 | onWheel (event) { 105 | const normalized = NormalizeWheel(event) 106 | const speed = normalized.pixelY 107 | 108 | this.scroll.target += speed * 0.5 109 | } 110 | 111 | /** 112 | * Resize. 113 | */ 114 | onResize () { 115 | this.screen = { 116 | height: window.innerHeight, 117 | width: window.innerWidth 118 | } 119 | 120 | this.renderer.setSize(this.screen.width, this.screen.height) 121 | 122 | this.camera.perspective({ 123 | aspect: this.gl.canvas.width / this.gl.canvas.height 124 | }) 125 | 126 | const fov = this.camera.fov * (Math.PI / 180) 127 | const height = 2 * Math.tan(fov / 2) * this.camera.position.z 128 | const width = height * this.camera.aspect 129 | 130 | this.viewport = { 131 | height, 132 | width 133 | } 134 | 135 | this.galleryBounds = this.gallery.getBoundingClientRect() 136 | this.galleryHeight = this.viewport.height * this.galleryBounds.height / this.screen.height 137 | 138 | if (this.medias) { 139 | this.medias.forEach(media => media.onResize({ 140 | height: this.galleryHeight, 141 | screen: this.screen, 142 | viewport: this.viewport 143 | })) 144 | } 145 | } 146 | 147 | /** 148 | * Update. 149 | */ 150 | update () { 151 | this.scroll.target += this.speed 152 | 153 | this.scroll.current = lerp(this.scroll.current, this.scroll.target, this.scroll.ease) 154 | 155 | if (this.scroll.current > this.scroll.last) { 156 | this.direction = 'down' 157 | this.speed = 2 158 | } else if (this.scroll.current < this.scroll.last) { 159 | this.direction = 'up' 160 | this.speed = -2 161 | } 162 | 163 | if (this.medias) { 164 | this.medias.forEach(media => media.update(this.scroll, this.direction)) 165 | } 166 | 167 | this.renderer.render({ 168 | scene: this.scene, 169 | camera: this.camera 170 | }) 171 | 172 | this.scroll.last = this.scroll.current 173 | 174 | window.requestAnimationFrame(this.update.bind(this)) 175 | } 176 | 177 | /** 178 | * Listeners. 179 | */ 180 | addEventListeners () { 181 | window.addEventListener('resize', this.onResize.bind(this)) 182 | 183 | window.addEventListener('mousewheel', this.onWheel.bind(this)) 184 | window.addEventListener('wheel', this.onWheel.bind(this)) 185 | 186 | window.addEventListener('mousedown', this.onTouchDown.bind(this)) 187 | window.addEventListener('mousemove', this.onTouchMove.bind(this)) 188 | window.addEventListener('mouseup', this.onTouchUp.bind(this)) 189 | 190 | window.addEventListener('touchstart', this.onTouchDown.bind(this)) 191 | window.addEventListener('touchmove', this.onTouchMove.bind(this)) 192 | window.addEventListener('touchend', this.onTouchUp.bind(this)) 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /app/demo-1/Media.js: -------------------------------------------------------------------------------- 1 | import { Mesh, Program, Texture } from 'ogl' 2 | 3 | import fragment from './fragment.glsl' 4 | import vertex from './vertex.glsl' 5 | 6 | export default class { 7 | constructor ({ element, geometry, gl, height, scene, screen, viewport }) { 8 | this.element = element 9 | this.image = this.element.querySelector('img') 10 | 11 | this.extra = 0 12 | this.height = height 13 | this.geometry = geometry 14 | this.gl = gl 15 | this.scene = scene 16 | this.screen = screen 17 | this.viewport = viewport 18 | 19 | this.createMesh() 20 | this.createBounds() 21 | 22 | this.onResize() 23 | } 24 | 25 | createMesh () { 26 | const image = new Image() 27 | const texture = new Texture(this.gl, { 28 | generateMipmaps: false 29 | }) 30 | 31 | image.src = this.image.src 32 | image.onload = _ => { 33 | program.uniforms.uImageSizes.value = [image.naturalWidth, image.naturalHeight] 34 | texture.image = image 35 | } 36 | 37 | const program = new Program(this.gl, { 38 | fragment, 39 | vertex, 40 | uniforms: { 41 | tMap: { value: texture }, 42 | uPlaneSizes: { value: [0, 0] }, 43 | uImageSizes: { value: [0, 0] }, 44 | uViewportSizes: { value: [this.viewport.width, this.viewport.height] }, 45 | uStrength: { value: 0 } 46 | }, 47 | transparent: true 48 | }) 49 | 50 | this.plane = new Mesh(this.gl, { 51 | geometry: this.geometry, 52 | program 53 | }) 54 | 55 | this.plane.setParent(this.scene) 56 | } 57 | 58 | createBounds () { 59 | this.bounds = this.element.getBoundingClientRect() 60 | 61 | this.updateScale() 62 | this.updateX() 63 | this.updateY() 64 | 65 | this.plane.program.uniforms.uPlaneSizes.value = [this.plane.scale.x, this.plane.scale.y] 66 | } 67 | 68 | updateScale () { 69 | this.plane.scale.x = this.viewport.width * this.bounds.width / this.screen.width 70 | this.plane.scale.y = this.viewport.height * this.bounds.height / this.screen.height 71 | } 72 | 73 | updateX (x = 0) { 74 | this.plane.position.x = -(this.viewport.width / 2) + (this.plane.scale.x / 2) + ((this.bounds.left - x) / this.screen.width) * this.viewport.width 75 | } 76 | 77 | updateY (y = 0) { 78 | this.plane.position.y = ((this.viewport.height / 2) - (this.plane.scale.y / 2) - ((this.bounds.top - y) / this.screen.height) * this.viewport.height) - this.extra 79 | } 80 | 81 | update (y, direction) { 82 | this.updateScale() 83 | this.updateX() 84 | this.updateY(y.current) 85 | 86 | const planeOffset = this.plane.scale.y / 2 87 | const viewportOffset = this.viewport.height / 2 88 | 89 | this.isBefore = this.plane.position.y + planeOffset < -viewportOffset 90 | this.isAfter = this.plane.position.y - planeOffset > viewportOffset 91 | 92 | if (direction === 'up' && this.isBefore) { 93 | this.extra -= this.height 94 | 95 | this.isBefore = false 96 | this.isAfter = false 97 | } 98 | 99 | if (direction === 'down' && this.isAfter) { 100 | this.extra += this.height 101 | 102 | this.isBefore = false 103 | this.isAfter = false 104 | } 105 | 106 | this.plane.program.uniforms.uStrength.value = ((y.current - y.last) / this.screen.width) * 10 107 | } 108 | 109 | /** 110 | * Events. 111 | */ 112 | onResize (sizes) { 113 | this.extra = 0 114 | 115 | if (sizes) { 116 | const { height, screen, viewport } = sizes 117 | 118 | if (height) this.height = height 119 | if (screen) this.screen = screen 120 | if (viewport) { 121 | this.viewport = viewport 122 | 123 | this.plane.program.uniforms.uViewportSizes.value = [this.viewport.width, this.viewport.height] 124 | } 125 | } 126 | 127 | this.createBounds() 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/demo-1/fragment.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec2 uImageSizes; 4 | uniform vec2 uPlaneSizes; 5 | uniform sampler2D tMap; 6 | 7 | varying vec2 vUv; 8 | 9 | void main() { 10 | vec2 ratio = vec2( 11 | min((uPlaneSizes.x / uPlaneSizes.y) / (uImageSizes.x / uImageSizes.y), 1.0), 12 | min((uPlaneSizes.y / uPlaneSizes.x) / (uImageSizes.y / uImageSizes.x), 1.0) 13 | ); 14 | 15 | vec2 uv = vec2( 16 | vUv.x * ratio.x + (1.0 - ratio.x) * 0.5, 17 | vUv.y * ratio.y + (1.0 - ratio.y) * 0.5 18 | ); 19 | 20 | gl_FragColor.rgb = texture2D(tMap, uv).rgb; 21 | gl_FragColor.a = 1.0; 22 | } 23 | -------------------------------------------------------------------------------- /app/demo-1/vertex.glsl: -------------------------------------------------------------------------------- 1 | #define PI 3.1415926535897932384626433832795 2 | 3 | precision highp float; 4 | precision highp int; 5 | 6 | attribute vec3 position; 7 | attribute vec2 uv; 8 | 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 projectionMatrix; 11 | 12 | uniform float uStrength; 13 | uniform vec2 uViewportSizes; 14 | 15 | varying vec2 vUv; 16 | 17 | void main() { 18 | vec4 newPosition = modelViewMatrix * vec4(position, 1.0); 19 | 20 | newPosition.z += sin(newPosition.y / uViewportSizes.y * PI + PI / 2.0) * -uStrength; 21 | 22 | vUv = uv; 23 | 24 | gl_Position = projectionMatrix * newPosition; 25 | } 26 | -------------------------------------------------------------------------------- /app/demo-2.js: -------------------------------------------------------------------------------- 1 | import { Renderer, Camera, Transform, Plane, Post, Vec2 } from 'ogl' 2 | import NormalizeWheel from 'normalize-wheel' 3 | 4 | import { lerp } from 'utils/math' 5 | 6 | import fragment from './demo-2/post.glsl' 7 | import Media from './demo-2/Media' 8 | 9 | export default class App { 10 | constructor () { 11 | this.scroll = { 12 | ease: 0.05, 13 | current: 0, 14 | target: 0, 15 | last: 0 16 | } 17 | 18 | this.speed = 2 19 | 20 | this.createRenderer() 21 | this.createCamera() 22 | this.createScene() 23 | this.createGallery() 24 | this.createPost() 25 | 26 | this.onResize() 27 | 28 | this.createGeometry() 29 | this.createMedias() 30 | 31 | this.update() 32 | 33 | this.addEventListeners() 34 | } 35 | 36 | createGallery () { 37 | this.gallery = document.querySelector('.demo-2__gallery') 38 | } 39 | 40 | createRenderer () { 41 | this.renderer = new Renderer({ 42 | alpha: true 43 | }) 44 | 45 | this.gl = this.renderer.gl 46 | 47 | document.body.appendChild(this.gl.canvas) 48 | } 49 | 50 | createCamera () { 51 | this.camera = new Camera(this.gl) 52 | this.camera.fov = 45 53 | this.camera.position.z = 5 54 | } 55 | 56 | createScene () { 57 | this.scene = new Transform() 58 | } 59 | 60 | createPost () { 61 | this.post = new Post(this.gl) 62 | 63 | this.pass = this.post.addPass({ 64 | fragment, 65 | uniforms: { 66 | uResolution: this.resolution, 67 | uStrength: { value: 0 } 68 | } 69 | }) 70 | 71 | this.resolution = { 72 | value: new Vec2() 73 | } 74 | } 75 | 76 | createGeometry () { 77 | this.planeGeometry = new Plane(this.gl, { 78 | widthSegments: 20 79 | }) 80 | } 81 | 82 | createMedias () { 83 | this.mediasElements = document.querySelectorAll('.demo-2__gallery__figure') 84 | this.medias = Array.from(this.mediasElements).map(element => { 85 | let media = new Media({ 86 | element, 87 | geometry: this.planeGeometry, 88 | gl: this.gl, 89 | scene: this.scene, 90 | screen: this.screen, 91 | viewport: this.viewport, 92 | width: this.galleryWidth 93 | }) 94 | 95 | return media 96 | }) 97 | } 98 | 99 | /** 100 | * Events. 101 | */ 102 | onTouchDown (event) { 103 | this.isDown = true 104 | 105 | this.scroll.position = this.scroll.current 106 | this.start = event.touches ? event.touches[0].clientX : event.clientX 107 | } 108 | 109 | onTouchMove (event) { 110 | if (!this.isDown) return 111 | 112 | const x = event.touches ? event.touches[0].clientX : event.clientX 113 | const distance = (this.start - x) * 2 114 | 115 | this.scroll.target = this.scroll.position + distance 116 | } 117 | 118 | onTouchUp (event) { 119 | this.isDown = false 120 | } 121 | 122 | onWheel (event) { 123 | const normalized = NormalizeWheel(event) 124 | const speed = normalized.pixelY 125 | 126 | this.scroll.target += speed * 0.5 127 | } 128 | 129 | /** 130 | * Resize. 131 | */ 132 | onResize () { 133 | this.screen = { 134 | height: window.innerHeight, 135 | width: window.innerWidth 136 | } 137 | 138 | this.renderer.setSize(this.screen.width, this.screen.height) 139 | 140 | this.camera.perspective({ 141 | aspect: this.gl.canvas.width / this.gl.canvas.height 142 | }) 143 | 144 | const fov = this.camera.fov * (Math.PI / 180) 145 | const height = 2 * Math.tan(fov / 2) * this.camera.position.z 146 | const width = height * this.camera.aspect 147 | 148 | this.viewport = { 149 | height, 150 | width 151 | } 152 | 153 | this.post.resize() 154 | 155 | this.resolution.value.set(this.gl.canvas.width, this.gl.canvas.height) 156 | 157 | this.galleryBounds = this.gallery.getBoundingClientRect() 158 | this.galleryWidth = this.viewport.width * this.galleryBounds.width / this.screen.width 159 | 160 | if (this.medias) { 161 | this.medias.forEach(media => media.onResize({ 162 | screen: this.screen, 163 | viewport: this.viewport, 164 | width: this.galleryWidth 165 | })) 166 | } 167 | } 168 | 169 | /** 170 | * Update. 171 | */ 172 | update () { 173 | this.scroll.target += this.speed 174 | 175 | this.scroll.current = lerp(this.scroll.current, this.scroll.target, this.scroll.ease) 176 | 177 | if (this.scroll.current > this.scroll.last) { 178 | this.direction = 'down' 179 | this.speed = 2 180 | } else if (this.scroll.current < this.scroll.last) { 181 | this.direction = 'up' 182 | this.speed = -2 183 | } 184 | 185 | if (this.medias) { 186 | this.medias.forEach(media => media.update(this.scroll, this.direction)) 187 | } 188 | 189 | this.pass.uniforms.uStrength.value = (this.scroll.current - this.scroll.last) / this.screen.width * 0.5 190 | 191 | this.post.render({ 192 | scene: this.scene, 193 | camera: this.camera 194 | }) 195 | 196 | this.scroll.last = this.scroll.current 197 | 198 | window.requestAnimationFrame(this.update.bind(this)) 199 | } 200 | 201 | /** 202 | * Listeners. 203 | */ 204 | addEventListeners () { 205 | window.addEventListener('resize', this.onResize.bind(this)) 206 | 207 | window.addEventListener('mousewheel', this.onWheel.bind(this)) 208 | window.addEventListener('wheel', this.onWheel.bind(this)) 209 | 210 | window.addEventListener('mousedown', this.onTouchDown.bind(this)) 211 | window.addEventListener('mousemove', this.onTouchMove.bind(this)) 212 | window.addEventListener('mouseup', this.onTouchUp.bind(this)) 213 | 214 | window.addEventListener('touchstart', this.onTouchDown.bind(this)) 215 | window.addEventListener('touchmove', this.onTouchMove.bind(this)) 216 | window.addEventListener('touchend', this.onTouchUp.bind(this)) 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /app/demo-2/Media.js: -------------------------------------------------------------------------------- 1 | import { Mesh, Program, Texture } from 'ogl' 2 | 3 | import fragment from './fragment.glsl' 4 | import vertex from './vertex.glsl' 5 | 6 | export default class { 7 | constructor ({ element, geometry, gl, scene, screen, viewport, width }) { 8 | this.element = element 9 | this.image = this.element.querySelector('img') 10 | 11 | this.extra = 0 12 | this.geometry = geometry 13 | this.gl = gl 14 | this.scene = scene 15 | this.screen = screen 16 | this.viewport = viewport 17 | this.width = width 18 | 19 | this.createMesh() 20 | this.createBounds() 21 | 22 | this.onResize() 23 | } 24 | 25 | createMesh () { 26 | const image = new Image() 27 | const texture = new Texture(this.gl, { 28 | generateMipmaps: false 29 | }) 30 | 31 | image.src = this.image.src 32 | image.onload = _ => { 33 | program.uniforms.uImageSizes.value = [image.naturalWidth, image.naturalHeight] 34 | texture.image = image 35 | } 36 | 37 | const program = new Program(this.gl, { 38 | fragment, 39 | vertex, 40 | uniforms: { 41 | tMap: { value: texture }, 42 | uPlaneSizes: { value: [0, 0] }, 43 | uImageSizes: { value: [0, 0] }, 44 | uViewportSizes: { value: [this.viewport.width, this.viewport.height] }, 45 | uStrength: { value: 0 } 46 | }, 47 | transparent: true 48 | }) 49 | 50 | this.plane = new Mesh(this.gl, { 51 | geometry: this.geometry, 52 | program 53 | }) 54 | 55 | this.plane.setParent(this.scene) 56 | } 57 | 58 | createBounds () { 59 | this.bounds = this.element.getBoundingClientRect() 60 | 61 | this.updateScale() 62 | this.updateX() 63 | this.updateY() 64 | 65 | this.plane.program.uniforms.uPlaneSizes.value = [this.plane.scale.x, this.plane.scale.y] 66 | } 67 | 68 | updateScale () { 69 | this.plane.scale.x = this.viewport.width * this.bounds.width / this.screen.width 70 | this.plane.scale.y = this.viewport.height * this.bounds.height / this.screen.height 71 | } 72 | 73 | updateX (x = 0) { 74 | this.plane.position.x = (-(this.viewport.width / 2) + (this.plane.scale.x / 2) + ((this.bounds.left - x) / this.screen.width) * this.viewport.width) - this.extra 75 | } 76 | 77 | updateY (y = 0) { 78 | this.plane.position.y = (this.viewport.height / 2) - (this.plane.scale.y / 2) - ((this.bounds.top - y) / this.screen.height) * this.viewport.height 79 | } 80 | 81 | update (x, direction) { 82 | this.updateScale() 83 | this.updateX(x.current) 84 | this.updateY() 85 | 86 | const planeOffset = this.plane.scale.x / 2 87 | const viewportOffset = this.viewport.width / 2 88 | 89 | this.isBefore = this.plane.position.x + planeOffset < -viewportOffset 90 | this.isAfter = this.plane.position.x - planeOffset > viewportOffset 91 | 92 | if (direction === 'down' && this.isBefore) { 93 | this.extra -= this.width 94 | 95 | this.isBefore = false 96 | this.isAfter = false 97 | } 98 | 99 | if (direction === 'up' && this.isAfter) { 100 | this.extra += this.width 101 | 102 | this.isBefore = false 103 | this.isAfter = false 104 | } 105 | 106 | this.plane.program.uniforms.uStrength.value = ((x.current - x.last) / this.screen.width) * 5 107 | } 108 | 109 | /** 110 | * Events. 111 | */ 112 | onResize (sizes) { 113 | this.extra = 0 114 | 115 | if (sizes) { 116 | const { width, screen, viewport } = sizes 117 | 118 | if (width) this.width = width 119 | if (screen) this.screen = screen 120 | if (viewport) { 121 | this.viewport = viewport 122 | 123 | this.plane.program.uniforms.uViewportSizes.value = [this.viewport.width, this.viewport.height] 124 | } 125 | } 126 | 127 | this.createBounds() 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/demo-2/fragment.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec2 uImageSizes; 4 | uniform vec2 uPlaneSizes; 5 | uniform sampler2D tMap; 6 | 7 | varying vec2 vUv; 8 | 9 | void main() { 10 | vec2 ratio = vec2( 11 | min((uPlaneSizes.x / uPlaneSizes.y) / (uImageSizes.x / uImageSizes.y), 1.0), 12 | min((uPlaneSizes.y / uPlaneSizes.x) / (uImageSizes.y / uImageSizes.x), 1.0) 13 | ); 14 | 15 | vec2 uv = vec2( 16 | vUv.x * ratio.x + (1.0 - ratio.x) * 0.5, 17 | vUv.y * ratio.y + (1.0 - ratio.y) * 0.5 18 | ); 19 | 20 | gl_FragColor.rgb = texture2D(tMap, uv).rgb; 21 | gl_FragColor.a = 1.0; 22 | } 23 | -------------------------------------------------------------------------------- /app/demo-2/post.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D tMap; 4 | 5 | uniform vec2 uResolution; 6 | uniform float uStrength; 7 | 8 | varying vec2 vUv; 9 | 10 | void main() { 11 | vec3 color; 12 | 13 | color.r = texture2D(tMap, vec2(vUv.x + uStrength, vUv.y)).r; 14 | color.g = texture2D(tMap, vUv).g; 15 | color.b = texture2D(tMap, vec2(vUv.x - uStrength, vUv.y)).b; 16 | 17 | gl_FragColor = vec4(color, 1.0); 18 | } 19 | -------------------------------------------------------------------------------- /app/demo-2/vertex.glsl: -------------------------------------------------------------------------------- 1 | #define PI 3.1415926535897932384626433832795 2 | 3 | precision highp float; 4 | precision highp int; 5 | 6 | attribute vec3 position; 7 | attribute vec2 uv; 8 | 9 | uniform mat4 modelViewMatrix; 10 | uniform mat4 projectionMatrix; 11 | 12 | uniform float uStrength; 13 | uniform vec2 uViewportSizes; 14 | 15 | varying vec2 vUv; 16 | 17 | void main() { 18 | vec4 newPosition = modelViewMatrix * vec4(position, 1.0); 19 | 20 | newPosition.z += -abs(sin(newPosition.x / uViewportSizes.x * PI + PI / 2.0) * uStrength); 21 | 22 | vUv = uv; 23 | 24 | gl_Position = projectionMatrix * newPosition; 25 | } 26 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | import One from './demo-1' 2 | import Two from './demo-2' 3 | 4 | const demos = [One, Two] 5 | const demo = document.body.getAttribute('data-id') 6 | 7 | new demos[demo]() 8 | 9 | document.documentElement.classList.remove('no-js') 10 | document.documentElement.classList.add('js') 11 | 12 | const images = document.querySelectorAll('img:not([src*="https://tympanus.net/codrops/wp-content/banners/"])') 13 | let imagesIndex = 0 14 | 15 | Array.from(images).forEach(element => { 16 | const image = new Image() 17 | 18 | image.src = element.src 19 | image.onload = _ => { 20 | imagesIndex += 1 21 | 22 | if (imagesIndex === images.length) { 23 | document.documentElement.classList.remove('loading') 24 | document.documentElement.classList.add('loaded') 25 | } 26 | } 27 | }) 28 | -------------------------------------------------------------------------------- /app/utils/math.js: -------------------------------------------------------------------------------- 1 | export function lerp (p1, p2, t) { 2 | return p1 + (p2 - p1) * t 3 | } 4 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/cover.jpg -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/favicon.ico -------------------------------------------------------------------------------- /images/demo-1/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/1.jpg -------------------------------------------------------------------------------- /images/demo-1/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/10.jpg -------------------------------------------------------------------------------- /images/demo-1/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/11.jpg -------------------------------------------------------------------------------- /images/demo-1/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/12.jpg -------------------------------------------------------------------------------- /images/demo-1/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/2.jpg -------------------------------------------------------------------------------- /images/demo-1/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/3.jpg -------------------------------------------------------------------------------- /images/demo-1/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/4.jpg -------------------------------------------------------------------------------- /images/demo-1/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/5.jpg -------------------------------------------------------------------------------- /images/demo-1/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/6.jpg -------------------------------------------------------------------------------- /images/demo-1/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/7.jpg -------------------------------------------------------------------------------- /images/demo-1/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/8.jpg -------------------------------------------------------------------------------- /images/demo-1/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-1/9.jpg -------------------------------------------------------------------------------- /images/demo-2/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-2/1.jpg -------------------------------------------------------------------------------- /images/demo-2/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-2/2.jpg -------------------------------------------------------------------------------- /images/demo-2/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-2/3.jpg -------------------------------------------------------------------------------- /images/demo-2/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-2/4.jpg -------------------------------------------------------------------------------- /images/demo-2/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-2/5.jpg -------------------------------------------------------------------------------- /images/demo-2/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-2/6.jpg -------------------------------------------------------------------------------- /images/demo-2/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/demo-2/7.jpg -------------------------------------------------------------------------------- /images/grain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bizarro/infinite-webl-gallery/7cb03cc6ee9c0de34a364ef2f74444d00c8f7643/images/grain.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Infinite WebGL Gallery | Demo 1 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |

Infinite WebGL Scrolling Gallery

20 |

using OGL with shaders

21 |
22 | 23 | 28 | 29 |
30 | Demo 1 31 | Demo 2 32 |
33 |
34 | 35 |
36 |
37 |

38 | Planete Elevene 39 |

40 |
41 | 42 | 91 |
92 |
93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Infinite WebGL Gallery | Demo 2 | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |

Infinite WebGL Scrolling Gallery

20 |

using OGL with shaders

21 |
22 | 23 | 28 | 29 |
30 | Demo 1 31 | Demo 2 32 |
33 |
34 | 35 |
36 |
37 |

38 | Electric 39 |

40 |
41 | 42 | 71 |
72 |
73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "infinite-webgl-gallery", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "start": "npm run development", 6 | "build": "webpack -p --progress --config webpack.config.build.js", 7 | "development": "cross-env NODE_ENV=dev webpack-dev-server --progress --config webpack.config.development.js" 8 | }, 9 | "devDependencies": { 10 | "@babel/core": "^7.4.5", 11 | "auto-bind": "^4.0.0", 12 | "babel-loader": "^8.0.6", 13 | "browser-sync": "^2.26.7", 14 | "browser-sync-webpack-plugin": "^2.2.2", 15 | "clean-webpack-plugin": "^3.0.0", 16 | "copy-webpack-plugin": "^5.0.3", 17 | "cross-env": "^5.2.0", 18 | "css-loader": "^5.0.1", 19 | "file-loader": "^4.0.0", 20 | "glslify-loader": "^2.0.0", 21 | "html-webpack-plugin": "^3.2.0", 22 | "mini-css-extract-plugin": "^1.3.1", 23 | "node-sass": "^4.12.0", 24 | "normalize-wheel": "^1.0.1", 25 | "ogl": "0.0.60", 26 | "postcss": "^8.2.2", 27 | "postcss-loader": "^4.1.0", 28 | "raw-loader": "^3.0.0", 29 | "sass-loader": "^10.1.0", 30 | "webpack": "^4.33.0", 31 | "webpack-cli": "^3.3.4", 32 | "webpack-dev-server": "^3.7.1", 33 | "webpack-merge": "^4.2.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /styles/base/base.scss: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | *, 7 | *::after, 8 | *::before { 9 | box-sizing: border-box; 10 | } 11 | 12 | html { 13 | background: $color-black; 14 | color: $color-white; 15 | font-size: calc(100vw / 1920 * 10); 16 | height: 100%; 17 | left: 0; 18 | position: fixed; 19 | top: 0; 20 | user-select: none; 21 | width: 100%; 22 | } 23 | 24 | body { 25 | font-family: 'halyard-display', sans-serif; 26 | font-size: 15px; 27 | margin: 0; 28 | -moz-osx-font-smoothing: grayscale; 29 | -webkit-font-smoothing: antialiased; 30 | overscroll-behavior-y: none; 31 | 32 | &:after { 33 | animation: grain 6s steps(10) infinite; 34 | background-image: url('../images/grain.png'); 35 | background-repeat: repeat; 36 | content: ''; 37 | height: 300%; 38 | left: -100%; 39 | opacity: 0; 40 | pointer-events: none; 41 | position: fixed; 42 | top: -100%; 43 | transition: opacity 0.4s ease; 44 | width: 300%; 45 | will-change: transform; 46 | z-index: 3; 47 | } 48 | 49 | .loaded &:after { 50 | opacity: 0.06; 51 | } 52 | } 53 | 54 | body #cdawrap { 55 | --cda-bottom: 3rem; 56 | --cda-left: 3rem; 57 | --cda-width: 400px; 58 | --cda-footer-fontsize: initial; 59 | --cda-footer-color: rgba(255,255,255,0.5); 60 | } 61 | 62 | body #cdawrap a:hover { 63 | text-decoration: none; 64 | opacity: 0.7; 65 | } 66 | 67 | img { 68 | display: block; 69 | } 70 | 71 | canvas { 72 | height: 100%; 73 | left: 0; 74 | opacity: 0; 75 | position: fixed; 76 | top: 0; 77 | transition: opacity 1s ease; 78 | width: 100%; 79 | 80 | .loaded & { 81 | opacity: 1 82 | } 83 | } 84 | 85 | a { 86 | @extend %link--hidden; 87 | 88 | color: $color-white; 89 | outline: none; 90 | text-decoration: none; 91 | 92 | &:hover, 93 | &:focus { 94 | outline: none; 95 | } 96 | } 97 | 98 | @keyframes grain { 99 | 0% { transform: translate(20%, -15%) } 100 | 10% { transform: translate(-20%, -15%) } 101 | 20% { transform: translate(20%, -5%) } 102 | 30% { transform: translate(-20%, -5%) } 103 | 40% { transform: translate(20%, 5%) } 104 | 50% { transform: translate(-20%, 5%) } 105 | 60% { transform: translate(20%, 15%) } 106 | 70% { transform: translate(-20%, 15%) } 107 | 80% { transform: translate(20%, 5%) } 108 | 90% { transform: translate(-20%, 5%) } 109 | 100% { transform: translate(20%, -5%) } 110 | } 111 | -------------------------------------------------------------------------------- /styles/base/frame.scss: -------------------------------------------------------------------------------- 1 | .frame { 2 | font-size: 15px; 3 | padding: 3rem; 4 | text-align: center; 5 | position: relative; 6 | z-index: 1000; 7 | } 8 | 9 | .frame__title { 10 | font-size: 15px; 11 | margin: 0 0 15px; 12 | font-weight: normal; 13 | } 14 | 15 | .frame__links { 16 | margin-top: 15px; 17 | } 18 | 19 | .frame__links a:not(:last-child), 20 | .frame__demos a:not(:last-child) { 21 | margin-right: 15px; 22 | } 23 | 24 | .frame__demos { 25 | margin: 15px 0; 26 | } 27 | 28 | .frame__demo--current, 29 | .frame__demo--current:hover { 30 | @extend %link; 31 | } 32 | 33 | @media screen and (min-width: 53em) { 34 | .frame { 35 | position: fixed; 36 | text-align: left; 37 | z-index: 100; 38 | top: 0; 39 | left: 0; 40 | display: grid; 41 | align-content: space-between; 42 | width: 100%; 43 | max-width: none; 44 | height: 100vh; 45 | padding: 3rem; 46 | pointer-events: none; 47 | grid-template-columns: 75% 25%; 48 | grid-template-rows: auto auto auto; 49 | grid-template-areas: 'title links' 50 | '... ...' 51 | 'credits demos'; 52 | } 53 | 54 | .frame__title-wrap { 55 | grid-area: title; 56 | display: flex; 57 | } 58 | 59 | .frame__title { 60 | margin: 0; 61 | } 62 | 63 | .frame__tagline { 64 | position: relative; 65 | margin: 0 0 0 1rem; 66 | padding: 0 0 0 1rem; 67 | opacity: 0.5; 68 | } 69 | 70 | .frame__demos { 71 | margin: 0; 72 | grid-area: demos; 73 | justify-self: end; 74 | } 75 | 76 | .frame__links { 77 | grid-area: links; 78 | padding: 0; 79 | margin: 0; 80 | justify-self: end; 81 | white-space: nowrap; 82 | } 83 | 84 | .frame a { 85 | pointer-events: auto; 86 | } 87 | 88 | .frame__credits { 89 | grid-area: credits; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /styles/base/loader.scss: -------------------------------------------------------------------------------- 1 | /* Page Loader */ 2 | html::after { 3 | content: ''; 4 | position: fixed; 5 | z-index: 1000; 6 | top: 50%; 7 | left: 50%; 8 | width: 60px; 9 | height: 60px; 10 | margin: -30px 0 0 -30px; 11 | border-radius: 50%; 12 | opacity: 0.4; 13 | background: $color-white; 14 | animation: loaderAnim 0.7s linear infinite alternate forwards; 15 | transition: opacity 0.4s ease; 16 | } 17 | 18 | html.loaded::after { 19 | animation-play-state: paused; 20 | opacity: 0 !important; 21 | } 22 | 23 | @keyframes loaderAnim { 24 | to { 25 | opacity: 1; 26 | transform: scale3d(0.5,0.5,1); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /styles/demos/demo-1.scss: -------------------------------------------------------------------------------- 1 | .demo-1 { 2 | height: 100%; 3 | left: 0; 4 | overflow: hidden; 5 | position: fixed; 6 | top: 0; 7 | width: 100%; 8 | z-index: 1; 9 | } 10 | 11 | .demo-1__header { 12 | align-items: center; 13 | display: flex; 14 | flex-direction: column; 15 | height: 100%; 16 | justify-content: center; 17 | left: 0; 18 | opacity: 0; 19 | position: fixed; 20 | top: 0; 21 | width: 100%; 22 | z-index: 2; 23 | 24 | .loaded & { 25 | opacity: 1; 26 | transition: opacity 0.4s ease; 27 | } 28 | } 29 | 30 | .demo-1__title { 31 | font: 800 20rem/1 'moret', serif; 32 | } 33 | 34 | .demo-1__description { 35 | font-size: 2rem; 36 | margin-top: -1rem; 37 | opacity: 0.75; 38 | } 39 | 40 | .demo-1__gallery { 41 | height: 295rem; 42 | position: relative; 43 | visibility: hidden; 44 | 45 | @media (max-width: 1200px) { 46 | height: 650rem; 47 | } 48 | } 49 | 50 | .demo-1__gallery__figure { 51 | position: absolute; 52 | 53 | &:nth-child(1) { 54 | height: 40rem; 55 | width: 70rem; 56 | } 57 | 58 | &:nth-child(2) { 59 | height: 50rem; 60 | left: 85rem; 61 | top: 30rem; 62 | width: 40rem; 63 | } 64 | 65 | &:nth-child(3) { 66 | height: 50rem; 67 | left: 15rem; 68 | top: 60rem; 69 | width: 60rem; 70 | } 71 | 72 | &:nth-child(4) { 73 | height: 30rem; 74 | right: 0; 75 | top: 10rem; 76 | width: 50rem; 77 | } 78 | 79 | &:nth-child(5) { 80 | height: 60rem; 81 | right: 15rem; 82 | top: 55rem; 83 | width: 40rem; 84 | } 85 | 86 | &:nth-child(6) { 87 | height: 75rem; 88 | left: 5rem; 89 | top: 120rem; 90 | width: 57.5rem; 91 | } 92 | 93 | &:nth-child(7) { 94 | height: 70rem; 95 | right: 0; 96 | top: 130rem; 97 | width: 50rem; 98 | } 99 | 100 | &:nth-child(8) { 101 | height: 50rem; 102 | left: 85rem; 103 | top: 95rem; 104 | width: 40rem; 105 | } 106 | 107 | &:nth-child(9) { 108 | height: 65rem; 109 | left: 75rem; 110 | top: 155rem; 111 | width: 50rem; 112 | } 113 | 114 | &:nth-child(10) { 115 | height: 43rem; 116 | right: 0; 117 | top: 215rem; 118 | width: 30rem; 119 | } 120 | 121 | &:nth-child(11) { 122 | height: 50rem; 123 | left: 70rem; 124 | top: 235rem; 125 | width: 80rem; 126 | } 127 | 128 | &:nth-child(12) { 129 | left: 0; 130 | top: 210rem; 131 | height: 70rem; 132 | width: 50rem; 133 | } 134 | 135 | @media (max-width: 1200px) { 136 | &:nth-child(1) { 137 | height: 60rem; 138 | width: 100rem; 139 | } 140 | 141 | &:nth-child(2) { 142 | height: 110rem; 143 | left: auto; 144 | right: 0; 145 | top: 25rem; 146 | width: 70rem; 147 | } 148 | 149 | &:nth-child(3) { 150 | height: 80rem; 151 | left: 12rem; 152 | top: 80rem; 153 | width: 89rem; 154 | } 155 | 156 | &:nth-child(4) { 157 | height: 60rem; 158 | right: 0; 159 | top: 153rem; 160 | width: 60rem; 161 | } 162 | 163 | &:nth-child(5) { 164 | height: 110rem; 165 | left: 0; 166 | right: auto; 167 | top: 180rem; 168 | width: 70rem; 169 | } 170 | 171 | &:nth-child(6) { 172 | height: 135rem; 173 | left: 95rem; 174 | top: 230rem; 175 | width: 87.5rem; 176 | } 177 | 178 | &:nth-child(7) { 179 | height: 110rem; 180 | left: 0; 181 | right: auto; 182 | top: 310rem; 183 | width: 80rem; 184 | } 185 | 186 | &:nth-child(8) { 187 | height: 50rem; 188 | left: auto; 189 | right: 0; 190 | top: 385rem; 191 | width: 80rem; 192 | } 193 | 194 | &:nth-child(9) { 195 | height: 100rem; 196 | left: 110rem; 197 | top: 450rem; 198 | width: 70rem; 199 | } 200 | 201 | &:nth-child(10) { 202 | height: 50rem; 203 | left: 20rem; 204 | right: auto; 205 | top: 440rem; 206 | width: 55rem; 207 | } 208 | 209 | &:nth-child(11) { 210 | height: 70rem; 211 | left: auto; 212 | right: 0; 213 | top: 570rem; 214 | width: 70rem; 215 | } 216 | 217 | &:nth-child(12) { 218 | left: 0; 219 | top: 515rem; 220 | height: 100rem; 221 | width: 90rem; 222 | } 223 | } 224 | } 225 | 226 | .demo-1__gallery__image { 227 | height: 100%; 228 | left: 0; 229 | object-fit: cover; 230 | position: absolute; 231 | top: 0; 232 | width: 100%; 233 | } 234 | -------------------------------------------------------------------------------- /styles/demos/demo-2.scss: -------------------------------------------------------------------------------- 1 | .demo-2 { 2 | height: 100%; 3 | left: 0; 4 | position: fixed; 5 | top: 0; 6 | width: 100%; 7 | z-index: 1; 8 | } 9 | 10 | .demo-2__header { 11 | align-items: center; 12 | display: flex; 13 | flex-direction: column; 14 | height: 100%; 15 | justify-content: center; 16 | left: 0; 17 | opacity: 0; 18 | position: fixed; 19 | top: 0; 20 | width: 100%; 21 | z-index: 2; 22 | 23 | .loaded & { 24 | opacity: 1; 25 | transition: opacity 0.4s ease; 26 | } 27 | } 28 | 29 | .demo-2__title { 30 | font: 800 20rem/1 'moret', serif; 31 | } 32 | 33 | .demo-2__description { 34 | font-size: 2rem; 35 | margin-top: -1rem; 36 | opacity: 0.75; 37 | } 38 | 39 | .demo-2__gallery { 40 | height: 100%; 41 | position: relative; 42 | width: 520rem; 43 | visibility: hidden; 44 | } 45 | 46 | .demo-2__gallery__figure { 47 | position: absolute; 48 | 49 | &:nth-child(1) { 50 | height: 80rem; 51 | left: 0; 52 | top: 0; 53 | width: 53rem; 54 | } 55 | 56 | &:nth-child(2) { 57 | height: 70rem; 58 | left: 73rem; 59 | bottom: 0; 60 | width: 47rem; 61 | } 62 | 63 | &:nth-child(3) { 64 | height: 90rem; 65 | left: 140rem; 66 | top: 10rem; 67 | width: 60rem; 68 | } 69 | 70 | &:nth-child(4) { 71 | height: 75rem; 72 | left: 220rem; 73 | top: 0; 74 | width: 50rem; 75 | } 76 | 77 | &:nth-child(5) { 78 | bottom: 0; 79 | height: 75rem; 80 | left: 290rem; 81 | width: 50rem; 82 | } 83 | 84 | &:nth-child(6) { 85 | height: 75rem; 86 | left: 360rem; 87 | top: 20rem; 88 | width: 50rem; 89 | } 90 | 91 | &:nth-child(7) { 92 | height: 75rem; 93 | left: 430rem; 94 | top: 30rem; 95 | width: 70rem; 96 | } 97 | } 98 | 99 | .demo-2__gallery__image { 100 | height: 100%; 101 | left: 0; 102 | object-fit: cover; 103 | position: absolute; 104 | top: 0; 105 | width: 100%; 106 | } 107 | -------------------------------------------------------------------------------- /styles/index.scss: -------------------------------------------------------------------------------- 1 | @import './utils/variables.scss'; 2 | 3 | @import './base/base.scss'; 4 | @import './base/frame.scss'; 5 | @import './base/loader.scss'; 6 | 7 | @import './mixins/links.scss'; 8 | 9 | @import './demos/demo-1.scss'; 10 | @import './demos/demo-2.scss'; 11 | -------------------------------------------------------------------------------- /styles/mixins/links.scss: -------------------------------------------------------------------------------- 1 | %link__wrapper { 2 | display: inline-block; 3 | overflow: hidden; 4 | position: relative; 5 | vertical-align: top; 6 | } 7 | 8 | %link__line { 9 | background: currentColor; 10 | bottom: 0; 11 | content: ''; 12 | height: 1px; 13 | left: 0; 14 | position: absolute; 15 | transition: transform 0.4s ease; 16 | width: 100%; 17 | } 18 | 19 | %link__line--visible { 20 | transform: scaleX(1); 21 | transform-origin: left center; 22 | } 23 | 24 | %link__line--hidden { 25 | transform: scaleX(0); 26 | transform-origin: right center; 27 | } 28 | 29 | %link { 30 | @extend %link__wrapper; 31 | 32 | display: inline-block; 33 | 34 | &:after { 35 | @extend %link__line; 36 | @extend %link__line--visible; 37 | } 38 | 39 | &:hover { 40 | &:after { 41 | @extend %link__line--hidden; 42 | } 43 | } 44 | } 45 | 46 | %link--hidden { 47 | @extend %link__wrapper; 48 | 49 | display: inline-block; 50 | 51 | &:after { 52 | @extend %link__line; 53 | @extend %link__line--hidden; 54 | } 55 | 56 | &:hover { 57 | &:after { 58 | @extend %link__line--visible; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /styles/utils/variables.scss: -------------------------------------------------------------------------------- 1 | $color-black: #0c0c0c; 2 | $color-white: #fff; -------------------------------------------------------------------------------- /webpack.config.build.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 4 | 5 | const merge = require('webpack-merge') 6 | const config = require('./webpack.config') 7 | 8 | module.exports = merge(config, { 9 | mode: 'production', 10 | 11 | output: { 12 | path: path.join(__dirname, 'InifniteAutoScrollingGallery') 13 | }, 14 | 15 | plugins: [ 16 | new CleanWebpackPlugin() 17 | ] 18 | }) 19 | -------------------------------------------------------------------------------- /webpack.config.development.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge') 2 | const path = require('path') 3 | 4 | const config = require('./webpack.config') 5 | 6 | module.exports = merge(config, { 7 | mode: 'development', 8 | 9 | devtool: 'inline-source-map', 10 | 11 | devServer: { 12 | writeToDisk: true 13 | }, 14 | 15 | output: { 16 | path: path.join(__dirname, 'InifniteAutoScrollingGallery') 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | 4 | const HtmlWebpackPlugin = require('html-webpack-plugin') 5 | const CopyWebpackPlugin = require('copy-webpack-plugin') 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 7 | 8 | const IS_DEVELOPMENT = process.env.NODE_ENV === 'dev' 9 | 10 | const dirApp = path.join(__dirname, 'app') 11 | const dirAssets = path.join(__dirname, 'assets') 12 | const dirStyles = path.join(__dirname, 'styles') 13 | const dirNode = 'node_modules' 14 | 15 | module.exports = { 16 | entry: [ 17 | path.join(dirApp, 'index.js'), 18 | path.join(dirStyles, 'index.scss') 19 | ], 20 | 21 | output: { 22 | filename: '[name].[contenthash].js' 23 | }, 24 | 25 | resolve: { 26 | modules: [ 27 | dirApp, 28 | dirAssets, 29 | dirNode 30 | ] 31 | }, 32 | 33 | plugins: [ 34 | new webpack.DefinePlugin({ 35 | IS_DEVELOPMENT 36 | }), 37 | 38 | new webpack.ProvidePlugin({ 39 | 40 | }), 41 | 42 | new HtmlWebpackPlugin({ 43 | filename: 'index.html', 44 | template: path.join(__dirname, 'index.html') 45 | }), 46 | 47 | new HtmlWebpackPlugin({ 48 | filename: 'index2.html', 49 | template: path.join(__dirname, 'index2.html') 50 | }), 51 | 52 | new CopyWebpackPlugin([ 53 | { 54 | from: './images', 55 | to: 'images' 56 | } 57 | ]), 58 | 59 | new MiniCssExtractPlugin({ 60 | filename: '[name].[hash].css', 61 | chunkFilename: '[id].css' 62 | }) 63 | ], 64 | 65 | module: { 66 | rules: [ 67 | { 68 | test: /\.js$/, 69 | use: { 70 | loader: 'babel-loader' 71 | } 72 | }, 73 | 74 | { 75 | test: /\.(sa|sc|c)ss$/, 76 | use: [ 77 | MiniCssExtractPlugin.loader, 78 | { 79 | loader: 'css-loader', 80 | options: { 81 | sourceMap: IS_DEVELOPMENT 82 | } 83 | }, 84 | { 85 | loader: 'postcss-loader', 86 | options: { 87 | sourceMap: IS_DEVELOPMENT 88 | } 89 | }, 90 | { 91 | loader: 'sass-loader', 92 | options: { 93 | sourceMap: IS_DEVELOPMENT 94 | } 95 | } 96 | ] 97 | }, 98 | 99 | { 100 | test: /\.(jpe?g|png|gif|svg|woff2?|fnt|webp)$/, 101 | loader: 'file-loader', 102 | options: { 103 | name (file) { 104 | return '[hash].[ext]' 105 | } 106 | } 107 | }, 108 | 109 | { 110 | test: /\.(glsl|frag|vert)$/, 111 | loader: 'raw-loader', 112 | exclude: /node_modules/ 113 | }, 114 | 115 | { 116 | test: /\.(glsl|frag|vert)$/, 117 | loader: 'glslify-loader', 118 | exclude: /node_modules/ 119 | } 120 | ] 121 | } 122 | } 123 | --------------------------------------------------------------------------------