Taotajima.jp WebGL deconstruction
The website has been done by Homunculus studio from Japan, and the developer of the website is Yuichiroh Arai. I want this case study to honor his skills and ideas he implemented on this beautiful website, as well as his team. Thank you guys for creating one of the best and smoothest user experiences with WebGL out there, ありがとう. Hope they will read that :-).
Let’s see how it all works!
So your first thought might be: it is definitely something in 3D, some mesh being folded and unfolded like a manuscript. Some clever vertex shader morphing. Let’s investigate.
The website is featured on the three.js homepage, so it’s obviously using this library. My first idea was to reveal the vertices behind this smooth transition, to see the magic. That worked well in my facebook case.
Downloaded the website, found mesh material in JS, changed its
wireframe property to
true. (i had to actually change wireframe for all materials on website, because you don’t know which is which)
Turns out, there is no real 3D going on. It’s all done in a fragment shader!
So let’s see step by step how Yuichiroh achieved this illusion. First of all, lets create
THREE.PlaneBufferGeometry(1,1) and put it right in front of camera to fill all visible space:
I’m assuming you know shaders, so if you are not familiar with them yet, go read amazing Book Of Shaders.
First, let’s add some
float colorProgress = uv.y + slideProgress;
But if you add
uv.x component to
colorProgress and play with some numbers, you can get this nicer result:
Now, let’s add some images, and
gl_FragColor = mix(texture1,texture2,colorProgress);
Next step: moving textures vertically while we mix them:
texture1 = texture2D(sampler1, vec2(uv.x, uv.y + slideProgress));
texture2 = texture2D(sampler2, vec2(uv.x, uv.y + slideProgress - 1));
Well, here we are, just a couple of simple steps! There is a little more, a bit of distortion, mirroring, nice easing function, but effect is already in place.
Or is it?
Only half of it really, what about the dynamics of the scroll? Did you try to scroll website really hard?
Usually all kinds of those slide-section transitions work boringly like fullpage.js:
What we see in taotajima.jp is different, more dynamic, it doesn’t really matter how much you scroll and how fast you do that, it will go with you infinitely.
The idea is very simple, yet, a brilliant one.
Imagine, there is a number, which means how much you scrolled up or down. In the usual page case, it is just scrollTop position. But let’s say in our case, if you scroll down hard, its
+1.0, if you scroll up a bit, it’s
What if we just take fractional part of this number as a
slideProgress and integer part as a current slide number.
Codewise, it looks like this:
let slides = [texture1,texture2,...]; // THREE.js textures
currentSlide = Math.floor(progress); // integer part
nextSlide = Math.floor(progress + 1);
material.uniforms.texture1.value = slides[currentSlide];
material.uniforms.texture2.value = slides[nextSlide];
material.uniforms.scrollProgress.value = scrollProgress;
And in fragment shader we can get fractional part:
// fragment shader
float slideProgress = fract(scrollProgress); // fractional part
The reason we can get away with this: you can only see two slides at any moment. No matter how fast you are. Just two slides. With this code in place, you’ll see:
Almost there! Now we just need slides to stick to whole numbers like 1,2,3. That can be done by finding closest integer and this formula:
slideProgress += (closestInteger - slideProgress)*0.01;
If we run it on each frame,
slideProgress will gravitate to whole numbers. See this illustrated in my demo:
This idea is not specific to .glsl, we might use it to build some cool DOM sliders as well. Let me know if you used it before! Let’s share ideas.
So here we are, two brilliant ideas from one transition effect on the website.
In the end
Of course, there is much more to this website than it’s homepage, and i highly recommend of going to the sources of websites you love. As we can see, one might always learn something new. I learned a lot from Yuichiroh’s project, even though we never met.
Hope you liked this deconstruction, and i wish you a good day! :-)
P.S.: i am currently open for a WebGL or html/css/js/vuejs projects, ping me if you have something to code! ;-)