Animating Netflix Pre-Roll Animations with WebGL Fragment Shaders

Last Updated On 27 Feb 2020 by

In this tutorial you'll learn how to create video-like animations, using WebGL fragment shaders and HTML canvas.

This is the last part of a series of 4 articles - if you jut landed here you may want to start there instead

When animating in 2D there are a couple major tools you will likely want on your belt: scale and rotation.

Enter the matrix!

In GLSL, rotation and scale are processed very efficiently using matrices. Let's first define them:

Rotation Matrix

mat2 rotate2d(float _angle){
  return mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle));

Scale Matrix

mat2 scale2D(vec2 _scale){
  return mat2(_scale.x, 0.0, 0.0, _scale.y);

See it in action

Here is how we would downScale the scene by 2.2 with an anchor point at the middle of the screen:

float downScale = 2.2;
st -= vec2(0.5);
st = scale2D(vec2(downScale)) * st;
st += vec2(0.5);

More tools for your belt

  • floor find the nearest integer less than or equal to the parameter,
  • fract compute the fractional part of the argument,
  • mod compute value of one parameter modulo another.

Putting it all together

With this knowledge in hand we can now better understand how the background texture is generated and applied to the shapes.

##create the background

vec3 makeBackground (vec2 st, float angle, float progress) {
  // apply the rotation around the center
  st -= vec2(0.5, 0.5);
  st = rotate2d(angle) * st;
  st += vec2(0.5, 0.5);
  // scale st up to create a repeated pattern
  st.x *= 100.0;
  // get the fractional coords
  vec2 ipos = fract(st);  
  // use sin with the x position on screen to progressively change the background
  st.x += sin(st.x) * sin(25.0 + progress * 150.0) * 4.0;
  // get the integer coords 
  ipos = floor(st);
  if (random(ipos) < 0.2) {
    return vec3(0);
  // use random to vary the output
  return vec3(
    mod(random(ipos+ 1.0)*4.0, 1.0) * 0.5, 
    mod(random(ipos+ 1.0)*8.0, 1.0) * 0.25, 
    mod(random(ipos+ 1.0)*16.0, 1.0) * 0.75

Once the color is computed, we apply it to our shape, for example on the right bar of the letter N, we apply the color starting at 4 second, and fully visible by 6 seconds.

nRight = mix(
  makeBackground(st, 0.0, 0.5), 
  mapTime(4.0, 6.0, u_time + st.y / 2.0)

Notice how we apply an angle of 0.42 radians on the oblique bar of the letter N:

nMid = mix(
  makeBackground(st, 0.42, 0.5), 
  mapTime(4.25, 6.25, u_time - st.y / 2.0)

Just like a lego project, we build our creation combining one piece after another.

That’s it for today!

This concludes this series of articles on animating in a fragment shader, hopefully you learned something and are now feeling creative!

Revisit other chapters:

  • Intro
    We'll go over the basics and project setup.
  • Hulu
    Next we'll look into drawing shapes and controlling time in animation.
  • HBO
    We'll reiterate these techniques and take a dive into noise functions.
  • checkout full source

Hope you enjoyed this tutorial! The stuff I write about is a way for me to improve my learnings - probably just like you right now. So please if you catch any issue or want to suggest an edit, use the section below or reach out on twitter. Cheers!

About The Author

Headshot of Michael Iriarte aka Mika

Hi, I'm Michael aka Mika. I'm a software engineer with years of experience in frontend development. Thank you for visiting I hope you learned something fun today! You can follow me on Twitter, see some of my work on GitHub, or read more about me on my website.