├── .gitignore
├── LICENSE
├── README.md
├── css
└── style.css
├── favicon.ico
├── img
├── bg.jpg
├── bg2.jpg
├── bg3.jpg
├── bg4.jpg
├── bg5.jpg
├── bg6.jpg
└── bg7.jpg
├── index.html
├── index2.html
├── index3.html
├── index4.html
├── index5.html
├── js
└── app.js
├── package-lock.json
├── package.json
├── shaders_circle
├── fragment.glsl
└── vertex.glsl
└── videos
├── 1.mp4
├── 2.mp4
├── 3.mp4
├── 4.mp4
├── 5.mp4
├── 6.mp4
├── 7.mp4
└── averyimportantvideo.mp4
/.gitignore:
--------------------------------------------------------------------------------
1 | .cache/
2 | node_modules/
3 | dist/
4 |
--------------------------------------------------------------------------------
/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 | # Experimental Video Transitions with WebGL
2 |
3 | Some experimental video transitions using Curtain.js and shaders.
4 |
5 | 
6 |
7 | [Article on Codrops](https://tympanus.net/codrops/?p=51333)
8 |
9 | [Demo](https://github.com/akella/videoTransitions/)
10 |
11 |
12 | ## Installation
13 |
14 | To run demo you will need [Parcel](https://parceljs.org/), either install it
15 | ```
16 | npm install -g parcel-bundler
17 | parcel index.html
18 | ```
19 | Or run without installation:
20 | ```
21 | npx parcel index.html
22 | ```
23 | After that the demo should be available on http://localhost:1234.
24 |
25 |
26 | ## Credits
27 |
28 | - Videos from [MixKit](https://mixkit.co/free-stock-video/) and [Coverr](https://coverr.co/)
29 | - Play icon by [Smashicons](https://www.flaticon.com/authors/smashicons)
30 | - [Curtains.js](https://www.curtainsjs.com/) by [Martin Laxenaire](https://twitter.com/webdesign_ml)
31 |
32 | ## Misc
33 |
34 | Follow Yuriy: [Twitter](http://twitter.com/akella), [GitHub](https://github.com/akella)
35 |
36 | 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/)
37 |
38 | ## License
39 | [MIT](LICENSE)
40 |
41 | Made with :blue_heart: by [Codrops](http://www.codrops.com)
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 | *,
2 | *::after,
3 | *::before {
4 | box-sizing: border-box;
5 | }
6 |
7 | :root {
8 | font-size: 15px;
9 | }
10 |
11 | body {
12 | margin: 0;
13 | --color-text: #fff;
14 | --color-bg: #111;
15 | --color-link: #fff;
16 | --color-link-hover: #fff;
17 | color: var(--color-text);
18 | background-color: var(--color-bg);
19 | font-family: navigo, sans-serif;
20 | -webkit-font-smoothing: antialiased;
21 | -moz-osx-font-smoothing: grayscale;
22 | overflow: hidden;
23 | background-image: linear-gradient(rgba(120,120,120,0.2),rgba(120,120,120,0.2)), url(../img/bg.jpg);
24 | background-size: cover;
25 | }
26 |
27 | .demo-2 {
28 | background-image: linear-gradient(rgba(120,120,120,0.2),rgba(120,120,120,0.2)), url(../img/bg2.jpg);
29 | }
30 |
31 | .demo-3 {
32 | background-image: linear-gradient(rgba(0,0,0,0.3),rgba(0,0,0,0.3)), url(../img/bg3.jpg);
33 | }
34 |
35 | .demo-4 {
36 | background-image: linear-gradient(rgba(120,120,120,0.2),rgba(120,120,120,0.2)), url(../img/bg7.jpg);
37 | }
38 |
39 | .demo-5 {
40 | background-image: linear-gradient(rgba(120,120,120,0.2),rgba(120,120,120,0.2)), url(../img/bg5.jpg);
41 | }
42 |
43 | /* Page Loader */
44 | .js .loading::before,
45 | .js .loading::after {
46 | content: '';
47 | position: fixed;
48 | z-index: 1000;
49 | }
50 |
51 | .js .loading::before {
52 | top: 0;
53 | left: 0;
54 | width: 100%;
55 | height: 100%;
56 | background: var(--color-bg);
57 | }
58 |
59 | .js .loading::after {
60 | top: 50%;
61 | left: 50%;
62 | width: 60px;
63 | height: 60px;
64 | margin: -30px 0 0 -30px;
65 | border-radius: 50%;
66 | opacity: 0.4;
67 | background: var(--color-link);
68 | animation: loaderAnim 0.7s linear infinite alternate forwards;
69 |
70 | }
71 |
72 | @keyframes loaderAnim {
73 | to {
74 | opacity: 1;
75 | transform: scale3d(0.5,0.5,1);
76 | }
77 | }
78 |
79 | a {
80 | text-decoration: none;
81 | color: var(--color-link);
82 | outline: none;
83 | opacity: 0.7;
84 | }
85 |
86 | a:hover,
87 | a:focus {
88 | color: var(--color-link-hover);
89 | outline: none;
90 | text-decoration: underline;
91 | opacity: 1;
92 | }
93 |
94 | .frame {
95 | padding: 3rem 5vw;
96 | text-align: center;
97 | z-index: 1000;
98 | position: fixed;
99 | top: 0;
100 | left: 0;
101 | width: 100%;
102 | height: 100vh;
103 | }
104 |
105 | .frame__title {
106 | font-size: 1rem;
107 | margin: 0 0 1rem;
108 | font-weight: normal;
109 | }
110 |
111 | .frame__links {
112 | display: inline;
113 | }
114 |
115 | .frame__links a:not(:last-child),
116 | .frame__demos a:not(:last-child) {
117 | margin-right: 1rem;
118 | }
119 |
120 | .frame__demos {
121 | margin: 1rem 0;
122 | }
123 |
124 | .frame__demos-text {
125 | margin-right: 2rem;
126 | }
127 |
128 | .frame__demo--current,
129 | .frame__demo--current:hover {
130 | color: var(--color-text);
131 | opacity: 0.5;
132 | text-decoration: underline;
133 | }
134 |
135 | .frame__button {
136 | background: none;
137 | border: 0;
138 | margin: 0;
139 | padding: 0;
140 | -moz-appearance: none;
141 | -webkit-appearance: none;
142 | fill: #fff;
143 | width: 60px;
144 | height: 60px;
145 | cursor: pointer;
146 | -webkit-touch-callout: none;
147 | -webkit-user-select: none;
148 | -moz-user-select: none;
149 | -ms-user-select: none;
150 | user-select: none;
151 | }
152 |
153 | .frame__button:focus {
154 | outline: none;
155 | opacity: 0.9;
156 | }
157 |
158 | .frame__content {
159 | text-align: center;
160 | }
161 |
162 | .frame__content-title {
163 | margin: 0;
164 | padding-bottom: 1rem;
165 | line-height: 1;
166 | font-size: 8vw;
167 | font-weight: 300;
168 | font-family: ivypresto-headline, serif;
169 | color: #fff;
170 | position: relative;
171 | text-shadow: 0 1px 6px rgba(0,0,0,0.1);
172 | }
173 |
174 | .frame__content-title::after {
175 | content: '';
176 | position: absolute;
177 | width: 20%;
178 | height: 1px;
179 | background: #fff;
180 | left: 40%;
181 | top: 100%;
182 | }
183 |
184 | .frame__content-text {
185 | max-width: 600px;
186 | font-size: 1rem;
187 | margin: 2rem auto 3rem;
188 | }
189 |
190 | .frame__switch-item {
191 | cursor: pointer;
192 | padding: 0.85rem 1.25rem;
193 | border: 1px solid #fff;
194 | font-family: ivypresto-headline, serif;
195 | font-weight: 300;
196 | font-size: 1.85rem;
197 | margin: 0 1rem;
198 | transition: opacity 0.3s;
199 | display: inline-block;
200 | margin-bottom: 1rem;
201 | }
202 |
203 | .frame__switch-item--current,
204 | .frame__switch-item:hover,
205 | .frame__switch-item:focus {
206 | text-decoration: none;
207 | }
208 |
209 | .frame__switch-item--current {
210 | pointer-events: none;
211 | opacity: 1;
212 | }
213 |
214 | .frame__content-text,
215 | .frame__switch {
216 | opacity: 0;
217 | transition: opacity 0.3s;
218 | }
219 |
220 | .video-started .frame__content-text,
221 | .video-started .frame__switch {
222 | opacity: 1;
223 | }
224 |
225 | .video {
226 | pointer-events: none;
227 | }
228 |
229 | #canvas {
230 | position: absolute;
231 | top: 0;
232 | right: 0;
233 | bottom: 0;
234 | left: 0;
235 | }
236 |
237 | .wrapper {
238 | width: 100%;
239 | height: 100vh;
240 | display: flex;
241 | pointer-events: none;
242 | }
243 |
244 | .plane {
245 | width: 100vw;
246 | height: 100vh;
247 | position: relative;
248 | z-index: 100;
249 | }
250 |
251 | .plane video {
252 | position: absolute;
253 | left: 0;
254 | top: 0;
255 | width: 100px;
256 | display: none;
257 | }
258 |
259 | @media screen and (min-width: 53em) {
260 | .frame {
261 | text-align: left;
262 | display: grid;
263 | padding: 3rem;
264 | pointer-events: none;
265 | grid-template-columns: 25% 50% 25%;
266 | grid-template-areas: 'title links links'
267 | '... play ...'
268 | 'content content content'
269 | '... demos demos';
270 | }
271 | .frame__title {
272 | margin: 0;
273 | grid-area: title;
274 | }
275 | .frame__button {
276 | grid-area: play;
277 | align-self: end;
278 | justify-self: center;
279 | }
280 | .frame__content {
281 | grid-area: content;
282 | align-self: end;
283 | justify-self: center;
284 | }
285 | .frame__tagline {
286 | position: relative;
287 | margin: 0 0 0 1rem;
288 | padding: 0 0 0 1rem;
289 | opacity: 0.5;
290 | }
291 | .frame__demos {
292 | margin: 0;
293 | grid-area: demos;
294 | justify-self: end;
295 | align-self: end;
296 | }
297 | .frame__links {
298 | grid-area: links;
299 | padding: 0;
300 | justify-self: end;
301 | }
302 | .frame a,
303 | .frame button {
304 | pointer-events: auto;
305 | }
306 | }
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/favicon.ico
--------------------------------------------------------------------------------
/img/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/img/bg.jpg
--------------------------------------------------------------------------------
/img/bg2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/img/bg2.jpg
--------------------------------------------------------------------------------
/img/bg3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/img/bg3.jpg
--------------------------------------------------------------------------------
/img/bg4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/img/bg4.jpg
--------------------------------------------------------------------------------
/img/bg5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/img/bg5.jpg
--------------------------------------------------------------------------------
/img/bg6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/img/bg6.jpg
--------------------------------------------------------------------------------
/img/bg7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/img/bg7.jpg
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebGL Video Transitions | Demo 1 | Codrops
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
89 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/index2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebGL Video Transitions | Demo 2 | Codrops
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
89 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/index3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebGL Video Transitions | Demo 3 | Codrops
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
89 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/index4.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebGL Video Transitions | Demo 4 | Codrops
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
89 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/index5.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebGL Video Transitions | Demo 5 | Codrops
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
90 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 | import { Curtains, Plane } from "curtainsjs";
2 | import fragment from "../shaders_circle/fragment.glsl";
3 | import vertex from "../shaders_circle/vertex.glsl";
4 | import gsap from "gsap";
5 |
6 | let activeTexture = 0;
7 | let currentTexture = 0;
8 | let transitionTimer = 0;
9 | let timer = 0;
10 | let isRunning = 0;
11 |
12 | window.addEventListener("load", () => {
13 | // set up our WebGL context and append the canvas to our wrapper
14 | const curtains = new Curtains({
15 | container: "canvas",
16 | alpha: true,
17 | pixelRatio: Math.min(1.5, window.devicePixelRatio), // limit pixel ratio for performance
18 | });
19 |
20 | // get our plane element
21 | const planeElements = [...document.getElementsByClassName("plane")];
22 | const navElements = [...document.getElementsByClassName("js-nav")];
23 | const duration = planeElements[0].getAttribute("data-duration") || 2;
24 | // set our initial parameters (basic uniforms)
25 | const params = {
26 | vertexShaderID: "vert",
27 | fragmentShaderID: "frag",
28 | uniforms: {
29 | transitionTimer: {
30 | name: "uTransitionTimer",
31 | type: "1f",
32 | value: 0,
33 | },
34 | fadeIn: {
35 | name: "uFadeIn",
36 | type: "1f",
37 | value: 0,
38 | },
39 | timer: {
40 | name: "uTimer",
41 | type: "1f",
42 | value: 0,
43 | },
44 | to: {
45 | name: "uTo",
46 | type: "1f",
47 | value: 0,
48 | },
49 | from: {
50 | name: "uFrom",
51 | type: "1f",
52 | value: 0,
53 | },
54 | },
55 | };
56 |
57 | const multiTexturesPlane = new Plane(curtains, planeElements[0], params);
58 |
59 | // set up our basic methods
60 | multiTexturesPlane
61 | .onReady(() => {
62 | // display the button
63 |
64 | document.body.classList.add("curtains-ready");
65 | let length = multiTexturesPlane.videos.length;
66 |
67 | // planeElements[0].addEventListener("click", () => {
68 | // gsap.to(multiTexturesPlane.uniforms.transitionTimer, {
69 | // duration: duration,
70 | // value: currentTexture + 1,
71 | // easing: 'power2.in',
72 | // onStart: () => {
73 | // multiTexturesPlane.videos[(currentTexture + 1) % length].play();
74 | // currentTexture = currentTexture + 1;
75 | // },
76 | // onComplete: () => {
77 | // multiTexturesPlane.videos[
78 | // (currentTexture + length - 1) % length
79 | // ].pause();
80 | // multiTexturesPlane.videos[
81 | // (currentTexture + length + 1) % length
82 | // ].pause();
83 | // },
84 | // });
85 | // });
86 |
87 | navElements.forEach(nav=>{
88 | nav.addEventListener('click',(event)=>{
89 | let to = event.target.getAttribute('data-nav');
90 | if(isRunning || to==currentTexture) return;
91 | var elems = document.querySelectorAll(".frame__switch-item");
92 | [].forEach.call(elems, function(el) {
93 | el.classList.remove("frame__switch-item--current");
94 | });
95 | event.target.classList.add('frame__switch-item--current')
96 | isRunning = true
97 |
98 | multiTexturesPlane.uniforms.to.value = to;
99 |
100 | let fake = {progress:0}
101 | gsap.to(fake, {
102 | duration: duration,
103 | progress: 1,
104 | easing: 'power2.in',
105 | onStart: () => {
106 | multiTexturesPlane.videos[to].play();
107 | currentTexture = to;
108 | },
109 | onUpdate:()=>{
110 | if(fake.progress===1){
111 | multiTexturesPlane.uniforms.from.value = to;
112 | }
113 | multiTexturesPlane.uniforms.transitionTimer.value = fake.progress
114 | },
115 | onComplete: () => {
116 | multiTexturesPlane.uniforms.from.value = to;
117 | multiTexturesPlane.videos[
118 | (currentTexture + length - 1) % length
119 | ].pause();
120 | multiTexturesPlane.videos[
121 | (currentTexture + length + 1) % length
122 | ].pause();
123 | isRunning = false;
124 | },
125 | });
126 |
127 | })
128 | })
129 |
130 | // click to play the videos
131 | document.getElementById("intro").addEventListener(
132 | "click",
133 | () => {
134 | // fade out animation
135 | gsap.to('#intro',{duration:0.1,autoAlpha:0.})
136 | document.body.classList.add("video-started");
137 |
138 | gsap.to(multiTexturesPlane.uniforms.fadeIn,{
139 | duration: 1,
140 | value: 1
141 | })
142 |
143 | // play all videos to force uploading the first frame of each texture
144 | multiTexturesPlane.playVideos();
145 |
146 | // wait a tick and pause the rest of videos (the ones that are hidden)
147 | curtains.nextRender(() => {
148 | multiTexturesPlane.videos[1].pause();
149 | multiTexturesPlane.videos[2].pause();
150 | });
151 | },
152 | false
153 | );
154 | })
155 | .onRender(() => {
156 | timer += 0.001;
157 | multiTexturesPlane.uniforms.timer.value = timer;
158 | });
159 | });
160 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "requires": true,
3 | "lockfileVersion": 1,
4 | "dependencies": {
5 | "@choojs/findup": {
6 | "version": "0.2.1",
7 | "resolved": "https://registry.npmjs.org/@choojs/findup/-/findup-0.2.1.tgz",
8 | "integrity": "sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw==",
9 | "dev": true,
10 | "requires": {
11 | "commander": "^2.15.1"
12 | }
13 | },
14 | "commander": {
15 | "version": "2.20.3",
16 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
17 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
18 | "dev": true
19 | },
20 | "core-util-is": {
21 | "version": "1.0.2",
22 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
23 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
24 | "dev": true
25 | },
26 | "curtainsjs": {
27 | "version": "7.1.0",
28 | "resolved": "https://registry.npmjs.org/curtainsjs/-/curtainsjs-7.1.0.tgz",
29 | "integrity": "sha512-p8sy/apUOUVitdOd6BFOO9e2YDgfsNWcY73yhHp1NEdWT+a0XMQPR6T5MK3jlyg4NnLT73wqO6da93GuIBZnqg=="
30 | },
31 | "events": {
32 | "version": "1.1.1",
33 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
34 | "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
35 | "dev": true
36 | },
37 | "glsl-inject-defines": {
38 | "version": "1.0.3",
39 | "resolved": "https://registry.npmjs.org/glsl-inject-defines/-/glsl-inject-defines-1.0.3.tgz",
40 | "integrity": "sha1-3RqswsF/yyvT/DJBHGYz0Ne2D9Q=",
41 | "dev": true,
42 | "requires": {
43 | "glsl-token-inject-block": "^1.0.0",
44 | "glsl-token-string": "^1.0.1",
45 | "glsl-tokenizer": "^2.0.2"
46 | }
47 | },
48 | "glsl-resolve": {
49 | "version": "0.0.1",
50 | "resolved": "https://registry.npmjs.org/glsl-resolve/-/glsl-resolve-0.0.1.tgz",
51 | "integrity": "sha1-iUvvc5ENeSyBtRQxgANdCnivdtM=",
52 | "dev": true,
53 | "requires": {
54 | "resolve": "^0.6.1",
55 | "xtend": "^2.1.2"
56 | },
57 | "dependencies": {
58 | "resolve": {
59 | "version": "0.6.3",
60 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz",
61 | "integrity": "sha1-3ZV5gufnNt699TtYpN2RdUV13UY=",
62 | "dev": true
63 | }
64 | }
65 | },
66 | "glsl-token-assignments": {
67 | "version": "2.0.2",
68 | "resolved": "https://registry.npmjs.org/glsl-token-assignments/-/glsl-token-assignments-2.0.2.tgz",
69 | "integrity": "sha1-pdgqt4SZwuimuDy2lJXm5mXOAZ8=",
70 | "dev": true
71 | },
72 | "glsl-token-defines": {
73 | "version": "1.0.0",
74 | "resolved": "https://registry.npmjs.org/glsl-token-defines/-/glsl-token-defines-1.0.0.tgz",
75 | "integrity": "sha1-y4kqqVmTYjFyhHDU90AySJaX+p0=",
76 | "dev": true,
77 | "requires": {
78 | "glsl-tokenizer": "^2.0.0"
79 | }
80 | },
81 | "glsl-token-depth": {
82 | "version": "1.1.2",
83 | "resolved": "https://registry.npmjs.org/glsl-token-depth/-/glsl-token-depth-1.1.2.tgz",
84 | "integrity": "sha1-I8XjDuK9JViEtKKLyFC495HpXYQ=",
85 | "dev": true
86 | },
87 | "glsl-token-descope": {
88 | "version": "1.0.2",
89 | "resolved": "https://registry.npmjs.org/glsl-token-descope/-/glsl-token-descope-1.0.2.tgz",
90 | "integrity": "sha1-D8kKsyYYa4L1l7LnfcniHvzTIHY=",
91 | "dev": true,
92 | "requires": {
93 | "glsl-token-assignments": "^2.0.0",
94 | "glsl-token-depth": "^1.1.0",
95 | "glsl-token-properties": "^1.0.0",
96 | "glsl-token-scope": "^1.1.0"
97 | }
98 | },
99 | "glsl-token-inject-block": {
100 | "version": "1.1.0",
101 | "resolved": "https://registry.npmjs.org/glsl-token-inject-block/-/glsl-token-inject-block-1.1.0.tgz",
102 | "integrity": "sha1-4QFfWYDBCRgkraomJfHf3ovQADQ=",
103 | "dev": true
104 | },
105 | "glsl-token-properties": {
106 | "version": "1.0.1",
107 | "resolved": "https://registry.npmjs.org/glsl-token-properties/-/glsl-token-properties-1.0.1.tgz",
108 | "integrity": "sha1-SD3D2Dnw1LXGFx0VkfJJvlPCip4=",
109 | "dev": true
110 | },
111 | "glsl-token-scope": {
112 | "version": "1.1.2",
113 | "resolved": "https://registry.npmjs.org/glsl-token-scope/-/glsl-token-scope-1.1.2.tgz",
114 | "integrity": "sha1-oXKOeN8kRE+cuT/RjvD3VQOmQ7E=",
115 | "dev": true
116 | },
117 | "glsl-token-string": {
118 | "version": "1.0.1",
119 | "resolved": "https://registry.npmjs.org/glsl-token-string/-/glsl-token-string-1.0.1.tgz",
120 | "integrity": "sha1-WUQdL4V958NEnJRWZgIezjWOSOw=",
121 | "dev": true
122 | },
123 | "glsl-token-whitespace-trim": {
124 | "version": "1.0.0",
125 | "resolved": "https://registry.npmjs.org/glsl-token-whitespace-trim/-/glsl-token-whitespace-trim-1.0.0.tgz",
126 | "integrity": "sha1-RtHf6Yx1vX1QTAXX0RsbPpzJOxA=",
127 | "dev": true
128 | },
129 | "glsl-tokenizer": {
130 | "version": "2.1.5",
131 | "resolved": "https://registry.npmjs.org/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz",
132 | "integrity": "sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA==",
133 | "dev": true,
134 | "requires": {
135 | "through2": "^0.6.3"
136 | }
137 | },
138 | "glslify-bundle": {
139 | "version": "5.1.1",
140 | "resolved": "https://registry.npmjs.org/glslify-bundle/-/glslify-bundle-5.1.1.tgz",
141 | "integrity": "sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A==",
142 | "dev": true,
143 | "requires": {
144 | "glsl-inject-defines": "^1.0.1",
145 | "glsl-token-defines": "^1.0.0",
146 | "glsl-token-depth": "^1.1.1",
147 | "glsl-token-descope": "^1.0.2",
148 | "glsl-token-scope": "^1.1.1",
149 | "glsl-token-string": "^1.0.1",
150 | "glsl-token-whitespace-trim": "^1.0.0",
151 | "glsl-tokenizer": "^2.0.2",
152 | "murmurhash-js": "^1.0.0",
153 | "shallow-copy": "0.0.1"
154 | }
155 | },
156 | "glslify-deps": {
157 | "version": "1.3.1",
158 | "resolved": "https://registry.npmjs.org/glslify-deps/-/glslify-deps-1.3.1.tgz",
159 | "integrity": "sha512-Ogm179MCazwIRyEqs3g3EOY4Y3XIAa0yl8J5RE9rJC6QH1w8weVOp2RZu0mvnYy/2xIas1w166YR2eZdDkWQxg==",
160 | "dev": true,
161 | "requires": {
162 | "@choojs/findup": "^0.2.0",
163 | "events": "^1.0.2",
164 | "glsl-resolve": "0.0.1",
165 | "glsl-tokenizer": "^2.0.0",
166 | "graceful-fs": "^4.1.2",
167 | "inherits": "^2.0.1",
168 | "map-limit": "0.0.1",
169 | "resolve": "^1.0.0"
170 | }
171 | },
172 | "graceful-fs": {
173 | "version": "4.2.4",
174 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
175 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
176 | "dev": true
177 | },
178 | "gsap": {
179 | "version": "3.5.1",
180 | "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.5.1.tgz",
181 | "integrity": "sha512-EMV0RSUKZNeTUzLKAizGlwxVOUyif3/g8I3S1aA/hf3gbqwBvmQ02x1RdTBQNQMOpHCVBv9y/vaHwfctoAg8zw=="
182 | },
183 | "inherits": {
184 | "version": "2.0.4",
185 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
186 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
187 | "dev": true
188 | },
189 | "isarray": {
190 | "version": "0.0.1",
191 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
192 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
193 | "dev": true
194 | },
195 | "map-limit": {
196 | "version": "0.0.1",
197 | "resolved": "https://registry.npmjs.org/map-limit/-/map-limit-0.0.1.tgz",
198 | "integrity": "sha1-63lhAxwPDo0AG/LVb6toXViCLzg=",
199 | "dev": true,
200 | "requires": {
201 | "once": "~1.3.0"
202 | }
203 | },
204 | "murmurhash-js": {
205 | "version": "1.0.0",
206 | "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz",
207 | "integrity": "sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E=",
208 | "dev": true
209 | },
210 | "once": {
211 | "version": "1.3.3",
212 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
213 | "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=",
214 | "dev": true,
215 | "requires": {
216 | "wrappy": "1"
217 | }
218 | },
219 | "path-parse": {
220 | "version": "1.0.6",
221 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
222 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
223 | "dev": true
224 | },
225 | "readable-stream": {
226 | "version": "1.0.34",
227 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
228 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
229 | "dev": true,
230 | "requires": {
231 | "core-util-is": "~1.0.0",
232 | "inherits": "~2.0.1",
233 | "isarray": "0.0.1",
234 | "string_decoder": "~0.10.x"
235 | }
236 | },
237 | "resolve": {
238 | "version": "1.17.0",
239 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
240 | "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
241 | "dev": true,
242 | "requires": {
243 | "path-parse": "^1.0.6"
244 | }
245 | },
246 | "shallow-copy": {
247 | "version": "0.0.1",
248 | "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz",
249 | "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=",
250 | "dev": true
251 | },
252 | "string_decoder": {
253 | "version": "0.10.31",
254 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
255 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
256 | "dev": true
257 | },
258 | "through2": {
259 | "version": "0.6.5",
260 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
261 | "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
262 | "dev": true,
263 | "requires": {
264 | "readable-stream": ">=1.0.33-1 <1.1.0-0",
265 | "xtend": ">=4.0.0 <4.1.0-0"
266 | },
267 | "dependencies": {
268 | "xtend": {
269 | "version": "4.0.2",
270 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
271 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
272 | "dev": true
273 | }
274 | }
275 | },
276 | "wrappy": {
277 | "version": "1.0.2",
278 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
279 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
280 | "dev": true
281 | },
282 | "xtend": {
283 | "version": "2.2.0",
284 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.2.0.tgz",
285 | "integrity": "sha1-7vax8ZjByN6vrYsXZaBNrUoBxak=",
286 | "dev": true
287 | }
288 | }
289 | }
290 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "curtainjs": "^1.0.2",
4 | "curtainsjs": "^7.1.0",
5 | "gsap": "^3.5.1",
6 | "jquery": "^3.5.1"
7 | },
8 | "devDependencies": {
9 | "cssnano": "^4.1.10",
10 | "glslify-bundle": "^5.1.1",
11 | "glslify-deps": "^1.3.1"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/shaders_circle/fragment.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 |
3 | varying vec3 vVertexPosition;
4 | varying vec2 vTextureCoord;
5 | varying vec2 vFirstTextureCoord;
6 | varying vec2 vSecondTextureCoord;
7 |
8 | // custom uniforms
9 | uniform float uTransitionTimer;
10 | uniform float uTimer;
11 | uniform float uTo;
12 | uniform float uFrom;
13 |
14 | // our textures samplers
15 | uniform sampler2D firstTexture;
16 | uniform sampler2D secondTexture;
17 | uniform sampler2D thirdTexture;
18 | uniform sampler2D displacement;
19 |
20 | vec4 getTextureByIndex(float index, vec2 vUv){
21 | vec4 result;
22 | if(index==0.){
23 | result = texture2D(firstTexture,vUv);
24 | }
25 | if(index==1.){
26 | result = texture2D(secondTexture,vUv);
27 | }
28 | if(index==2.){
29 | result = texture2D(thirdTexture,vUv);
30 | }
31 | return result;
32 | }
33 | float circle (in vec2 uv, in float radius, in float sharpness) {
34 | float dist = length(uv - vec2(0.5));
35 | return 1. - smoothstep(radius-sharpness,radius,dist);
36 | }
37 | void main() {
38 | float progress = fract(uTransitionTimer);
39 |
40 | vec2 center = vec2(0.5);
41 | vec2 centerVector = vFirstTextureCoord - center;
42 | vec2 vUv = vFirstTextureCoord;
43 |
44 | float circleProgress = circle(vTextureCoord, progress*0.9, 0.2);
45 | float ease = progress*(2. - progress);
46 | vec2 nextUV = vUv + centerVector * (circleProgress - 1.0) + centerVector * ( 1. - ease) * 0.;
47 | vec2 currentUV = vUv - centerVector * circleProgress*0.5 - centerVector * progress * 0.2;
48 |
49 | float currentTexture = mod(uFrom,3.);
50 | float nextTexture = mod(uTo, 3.);
51 |
52 | vec4 current = getTextureByIndex(currentTexture, currentUV);
53 | vec4 next = getTextureByIndex(nextTexture, nextUV);
54 |
55 | gl_FragColor = mix(current,next,circleProgress);
56 | }
--------------------------------------------------------------------------------
/shaders_circle/vertex.glsl:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 |
3 | // default mandatory variables
4 | attribute vec3 aVertexPosition;
5 | attribute vec2 aTextureCoord;
6 |
7 | uniform mat4 uMVMatrix;
8 | uniform mat4 uPMatrix;
9 |
10 | // our texture matrices
11 | // displacement texture does not need to use them
12 | uniform mat4 firstTextureMatrix;
13 | uniform mat4 secondTextureMatrix;
14 |
15 | // custom variables
16 | varying vec3 vVertexPosition;
17 | varying vec2 vTextureCoord;
18 | varying vec2 vFirstTextureCoord;
19 | varying vec2 vSecondTextureCoord;
20 |
21 | // custom uniforms
22 | uniform float uTransitionTimer;
23 |
24 | void main() {
25 | gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
26 |
27 | // varyings
28 | // use original texture coords for our displacement
29 | vTextureCoord = aTextureCoord;
30 | // use texture matrices for our videos
31 | vFirstTextureCoord = (firstTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;
32 | vSecondTextureCoord = (secondTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;
33 | vVertexPosition = aVertexPosition;
34 | }
--------------------------------------------------------------------------------
/videos/1.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/videos/1.mp4
--------------------------------------------------------------------------------
/videos/2.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/videos/2.mp4
--------------------------------------------------------------------------------
/videos/3.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/videos/3.mp4
--------------------------------------------------------------------------------
/videos/4.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/videos/4.mp4
--------------------------------------------------------------------------------
/videos/5.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/videos/5.mp4
--------------------------------------------------------------------------------
/videos/6.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/videos/6.mp4
--------------------------------------------------------------------------------
/videos/7.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/videos/7.mp4
--------------------------------------------------------------------------------
/videos/averyimportantvideo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/videoTransitions/9b214109e8b9e5764e0cb57fff9149d135c2b79a/videos/averyimportantvideo.mp4
--------------------------------------------------------------------------------