Taotajima.jp WebGL deconstruction

I love decompiling stuff, i did that for facebook 3D photos recently, but this time it will be about marvelous Tao Tajima website. Go check it out first.

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!

Homepage effect

See the background transition effect

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)

Surprise! 😮

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 createTHREE.PlaneBufferGeometry(1,1) and put it right in front of camera to fill all visible space:

I intentionally added more vertices and colored them as UV coordinates.

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 slideProgress uniform that will run from 0 to 1. We’ll be setting this one in our javascript. Now we can create a smooth animated gradient with fragment shader :

float colorProgress = uv.y + slideProgress;
Not so cool yet, just a moving gradient

But if you add uv.x component to colorProgress and play with some numbers, you can get this nicer result:

smth like: slideProgress*X - uv.y*Y + uv.x*Z + W

Now, let’s add some images, and mix them:

gl_FragColor = mix(texture1,texture2,colorProgress);
Starting look good now! But misses “folding”, looks plain

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));
Because of the texture movement, fold line looks dynamic now.

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?

Scroll-slide idea

Usually all kinds of those slide-section transitions work boringly like fullpage.js:

you start scroll, then scroll is hijacked, and you wait until animation finishes. You can’t scroll 3 sections.

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.

try to scroll it yourself

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 -0.5.

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 texturescurrentSlide = 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:

It works! Notice scale on the left, with actual values.

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:

The effect is now in place! 🎉🎉🎉

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! ;-)

curious guy at riverco.de frontend agency