├── .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 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
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 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
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 | 
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 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
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 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
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 |
--------------------------------------------------------------------------------