Matrix Rain Experiments in JavaScript (tutorial)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
matrix rain is one of the most iconic unique and recognizable effects do you want to feel like a hacker today then join me and let's use our coding skills to build it completely from scratch with html css javascript and object-oriented programming in this class we are diving deep into the code to unlock the secrets of canvas animation and creative coding to make sure we really understand how it works under the hood sometimes web animations are more fun with colors html canvas offers two built-in methods to draw gradients create linear gradient takes four arguments starting x and y coordinates and ending x and y coordinates it will create an imaginary line between these two points to determine size and direction of linear gradient create radial gradient takes six arguments x and y of center point of the inner circle and its radius and x and y of center point of outer circle and its radius gradient will be drawn in the space between these two circles let's use it in a project the original effect is made out of collection of mirrored japanese katakana characters mixed with flipped latin letters and numeral symbols but it will also work with other unicode symbols and emojis this effect is relatively lightweight and easy to code which makes it a perfect project for beginner creative hackers like you and me i set up my canvas i create an instance of 2d context object which we can use to change canvas settings and call all built-in drawing methods i set width and height to cover browser window and i make my canvas transparent i can write code in so-called procedural way where i simply declare variables and functions step by step in the order i want them to be executed it's the most basic way to write code in this case i will write the code using object-oriented program in paradigm which means i will wrap my functions and variables in objects there are many ways to create objects in javascript in modern javascript we usually use so-called classes class is a special kind of function used to create many similar objects class syntax is relatively new it was introduced in 2015 and it's just so-called syntactical sugar simplified syntax built on native javascript prototype functionality one of the four main principles of object-oriented programming is encapsulation which means we will wrap variables and related functions that operate on them in objects encapsulation helps us to keep our code organized and also could be used to protect the data inside objects from outside interference in this project i will encapsulate data into two custom classes the first class will be called for example symbol its job will be to create and draw individual symbol objects that make up the rain effect the second class can be called for example effect it will be the main wrapper for the entire rain effect this is where we put all functionality to create update and draw all symbols so symbol class will create and manage individual symbols effect class will manage the entire effect all of the symbols at once each class will have this special constructor method which will be automatically triggered when we call class using the new keyword whenever we use the new keyword constructor we'll create one new blank object and it will fill it with values and properties based on the class blueprint inside we can also give our classes other customer methods i will explain these as we write the code the last piece we need is animation loop custom function i call for example animate will run 60 times per second updating and drawing our effect over and over to create animation nice let's write blueprint for effect class the effect needs to always be aware of canvas size so it can spread symbols all around the available canvas area we will pass it current canvas width and height as arguments when we create the effect then we take these arguments and convert them into class properties like this here i'm saying canvas with property on this instance of effect class we are creating right now is equal to canvas with argument that was passed to the constructor these arguments will be passed here when we call this class using the new keyword in a minute you will see here in constructor we will have all global settings for our effect i set font size to 25 pixels the effect will be made out of individual columns the number of columns will depend on width of canvas and font size to find out how many columns we can fit in i do this.canvas width from line 17 divided by this dot font size from line 19. i will also need array that will hold all individual symbol objects i create a method to fill this symbols array with symbol objects i will call that custom method for example initialize and i will make it private by starting its name with a harsh symbol private methods cannot be called directly from the outside they have restricted access creating private methods like this is a good example of the second pillar of object-oriented programming called abstraction principle of abstraction means we are hiding unnecessary details from the user user doesn't need to know about this initialize method i will write the code in a way that initialize method automatically executes itself when we create instance of effect class abstraction is about hiding internal functionality and implementation details of our objects and only exposing essential information to the user abstraction helps to isolate the impact of changes made to the code so that if something goes wrong the change will only affect the implementation details of a class and not the outside code so the job of this initialize function is just to take symbols array from line 21 and fill it with symbol objects created using symbol class from line 6. the number of these symbols will depend on the number of columns from line 20. we have a for loop that will run once for each column and each time it will fill that index in symbols array with an instance of symbol class by using this special new keyword javascript will look for class with that name and it will trigger its constructor to create one new blank object using blueprint inside let's write that blueprint before we create each symbol we need to pass it some values from the outside as arguments we will need x and y coordinates font size and canvas height i will have this.character's property which will contain a long string of characters each time symbol jumps to a new position it will randomly choose one of these available characters i will use these characters since i'm trying to replicate matrix rain effect but feel free to use any custom set of characters you want it will also work with unicode emojis which could be interesting if you want to use the same characters i'm using i will make them available somewhere in the description down below so you can just copy and paste it now i just convert these arguments into class properties this dot text is going to be the currently active symbol so value of this dot text will be a random number from this dot character's string from line 8. we will write that logic inside draw method in a minute each symbol object created by this class will have access to public draw method this is a custom method again so you can call it whatever you want the job of this method will be to randomize current character and draw it on canvas at a specific position every time draw method is called it will choose a random symbol so this dot text from line 12 is one random character from these i pick a random one by taking this dot characters and calling character add on it character art is a built in javascript string method it can be called on string data type characters on line 8 is a very long string character add built in javascript method takes a single index argument and returns a new string containing only that one character located at that specific offset of the string so here in brackets i need to pass it a single number between 0 and length of this dot character's string we need numbers so first i call mastod floor to remove decimal points and it will be a random number between 0 and this dot character's length like this all this just stands for one number if the result is 1 we get this character the first character in the string is index 0. index 20 will give me this character index 35 will give me this one i think you get the idea so now we chose a random symbol from all available characters let's draw it on canvas i pass context argument to my draw method so that i can specify what canvas i want to draw on i take that context and i set its fill style to green or maybe this shade will be better now i call built in canvas fill text method which takes three arguments text we want to draw and x and y coordinates where i want to draw it i pass it this dot text which contains one symbol we just randomized and i will draw it at this dot x and this dot y coordinates the way i want to write this effect is that this dot x and this dot y will have to be multiplied by current font size to make all the characters and symbols sit nicely next to and below each other if i change font size the effect will automatically rearrange itself to accommodate for larger or smaller font the characters will be falling down so when they reach bottom of canvas canvas height i will reset them back to vertical position 0 up top else we just increase y by 1. since i'm multiplying y times font size they will jump in steps equal to font size with no overlap the next symbol will be drawn below depending on font size perfect our symbol class is complete we have a blueprint that will be called every time we call this class with the new keyword and all objects created by this class will have access to this custom draw method which will randomize move and draw symbols i go back inside initialize method on effect class here i'm running a for loop that will fill symbols array with symbol objects depending on number of columns we have available here for each column i create one symbol that will be falling down as we just wrote it at logic inside draw method on line seven i can see my symbol class expects four arguments coming from the outside horizontal x coordinate will be indexed from that column i want them to start falling from top so initial vertical coordinate will be 0 font size will be this dot font size from line 31 and canva's height will be this.canvas height from line 30. nice let's create an instance of effect class constant variable i call for example effect is equal to new effect and on line 28 i can see it needs canvas dimensions so i pass it canvas width from line 3 and canvas height from line 4. inside animation loop i will set build in canvas font property the font property specifies the current text style and i set it to effect dot font size referencing class property we declared on line 31 plus pixel monospace mono space phones have characters that occupy the same amount of horizontal space now i take symbols array from line 33 and i call for each on it i call each element for example symbol and for each symbol i call their associated draw method from line 15. i can see it expects context as an argument so i pass it ctx from line 2. now i call built in request animation frame method and i pass it animate the name of its parent method this will create endless animation loop i need to trigger the loop by calling animate like this nothing is happening just yet it's because symbols array on line 33 is still empty i wrote initialize method that fills it with symbol objects but i haven't called that method anywhere as i said we want to use abstraction here so this private method is not directly accessible from the outside we are hiding any workings of our object from the user i will call this method inside constructor like this i am calling private method from inside constructor as we know constructor is called when we instantiate class by using the new keyword this way initialize will be automatically executed when i instantiate effect class here on line 43. i can console.log symbols here like this just to check it's still empty so there must be an issue with this for loop somewhere why is it not filling my array with objects it's because this dot columns is a number so there is no need to use dot length here and we are drawing symbols well done click the like if you are getting any value i want the old symbols to slowly fade away so i will draw semi-transparent rectangle over canvas for every animation frame i set fill style to rgba 0 0 0 which is black and opacity 0.05 i call fill rectangle and i draw it across the entire canvas color needs to be in quotes it's a string nice this is a useful trick to remember if you want something to slowly fade away on canvas just draw semi-transparent rectangle over it each animation frame draws new semi-transparent see-through black rectangle which will cause old paint underneath to slowly fade step by step we don't want it to be moving like this we want each column to have randomized delay on line 19 i check if vertical y position is on the bottom of canvas and if it is i reset it back to top i will add one more condition here when you call math.random on its own like this it returns a random value between 0 and 1. so i say if that returned random number is more than 0.5 only then reset the column that breaks it down a bit how about 0.7 now we are starting to see bigger differences between columns vertical positions 0.9 0.95 let's go with 0.98 nice the effect is moving very fast i can slow it down in multiple ways what if i want to control frame rate i want to have a variable that defines frames per second and i want animation to adjust itself to that frame rate automatically we can do it by using timestamps and delta time technique we use frame rate to calculate how many milliseconds each frame should last on screen and then we calculate the delta time to control animation speed delta time is the difference between frames and milliseconds let me show you and explain it's simple i need a variable that will keep track of last time of timestamp from the previous animation frame i will compare it to the current timestamp and the difference between them is delta time at first i set it to 0 i need a variable that will set fps let's say i want the animation to run at 30 frames per second next frame variable will be the amount of milliseconds we wait until we trigger and draw the next frame i want 30 frames per second so 1000 milliseconds divided by fps which is currently set to 30. timer will be a variable which accumulates delta time when it reaches threshold defined in next frame it will animate the next frame reset itself to 0 and it will start counting again nice how do we get the current timestamp request animation frame method has a special feature it automatically passes a timestamp argument to the method it calls so animate will have access to this auto-generated timestamp argument i will assign it a variable name here i will just call it timestamp now we need to calculate the delta time which is the difference in milliseconds between previous animation frame and the current animation frame i calculated by taking the timestamp that was just passed here minus the timestamp from the previous frame which i will be saving in last time variable when we calculated delta time we will assign last time to the new timestamp so that it can be used for the next loop now we have delta time we know how many milliseconds it takes for our computer to serve the next frame of animation i can use it to time frame rate i say if timer from line 48 is more than next frame from line 47 trigger all this drawing code trigger next step in animation and also i need to reset timer back to 0 so it can start countdown to the next frame again else we just increase timer by delta time we don't animate anything and we just wait until timer is high enough so this is how you use timestamps and delta time to control frame rate one important thing to keep in mind is that this timestamp is auto-generated by request animation frame it means that we will only have timestamp for the second loop the very first loop is called from here and there is no auto-generated timestamp so i have to pass it some value let's pass it to zero now my animation is running at 30 frames per second 15 frames per second i think for this particular code drain effect it's better with lower fps which also makes the effect more lightweight because we don't have to draw it so often you can see that japanese alphabet characters have different horizontal alignment than latin characters we can fix that by setting text align canvas property to center now it's more even things like fill style and text align are global canvas properties once assigned they will apply to everything drawn on canvas element until they are reassigned to a different value for performance reasons we should try to write our code in a way so we don't override these values very often here i'm declaring them once per animation loop which is fine but here on line 17 i'm setting global fill style property on my canvas every time i call draw method which runs for every character in symbols array for each frame we can reduce the number of calls by removing it here and declaring it here instead so now instead of re-declaring it over and over for every symbol i'm just declaring it once for all the symbols in the array per frame i just have to be careful about the order here i declare fill style here i draw the semi-transparent rectangle to get fading trails effect then i set global fill style to a different color and that color will be used to draw all my symbols perfect i can increase frame rate since we are serving the next frame by using built-in request animation frame method it will have a cap in most modern browsers request animation frame automatically adjusts itself to screen refresh rate unless you have a high refresh gaming screen your refresh rate should probably be somewhere around 60 frames per second when i resize my browser window the effect doesn't adjust itself automatically how can we make it responsive it's easy i create event listener for window resize event whenever resize event is triggered i set canvas width and canvas height to new width and height of browse window nice that works canvas is resizing i want to spread the effect across the new available area so i will have to recalculate number of columns we have available because it depends on canvas width and font size we set canvas width at first here on line 28 when we create instance of effect class we can expose some of these properties and make them accessible from the outside so that their values can be updated that way they can be set to a new value i do that by creating a public resize method on my effect class this method will take new width and height and it will set canvas width and canvas height to these new values after we updated the values we recalculate how many columns can fit to the new canvas width we delete all symbol objects from the array by assigning symbols from line 32 to an empty array and we call private initialize method that will create new symbol object for each column inside resize event listener i update canvas width and canvas height and i call this new resize method we just wrote i passed it new canvas width and canvas height i made a typo somewhere let's see oh here on line 46 i missed brackets nice now it works and whenever we change screen size the effect will automatically reset and recalculate its values to take up all the available canvas space i set fps to 30 frames per second as we said before we can create linear or radial gradient on canvas built in create linear gradient method will create gradient object we pass it x and y of the starting point and x and y coordinates of the endpoint it will create linear gradient between these two points so these coordinates set direction and size of gradient i want my gradient to go from coordinates 0 0 to coordinates canvas with canvas height so size and direction of my gradient will be this we also have to define what colors we want our gradient to be made out of we use special built in add color stop method that can be called on this gradient object we pass it offset and color offset is value between 0 and 1 0 is start 0.5 is middle one is the end we can add as many color stops we want in between my gradient will have six color stops at 0 20 40 60 80 and 100 percent and colors will be for example red yellow green cyan blue and magenta to apply canvas gradient we need to assign it to fill style or stroke style property important thing to understand is that gradient is not applied to individual shapes but to the actual canvas element so basically to the background it means that individual shapes letters and drawings will take different gradient color depending on their current position they will change colors as they move over different areas on canvas based on size and direction of gradient we defined for the canvas element as you can see my gradient is going from top left to bottom right corner i can change its direction by swapping around these values create radial gradient has always been a little bit confusing for me because if you give it wrong values it will create strange shapes and blank canvas areas it was never very intuitive for me until i took time to properly read documentation it's actually simple as well let me show you it takes 6 arguments x and y of center point of starting inner circle and its radius and x and y of center point of the outer circle and its radius gradient will be drawn between these two circles i want my gradient to be exactly in the middle of screen so center point coordinates of inner circle will be canvas width divided by 2 for horizontal position and canvas height divided by 2 for vertical position i give my inner circle radius of 100 pixels for example outer circle will also have center point exactly in the middle of canvas and its radius will be 200 pixels nice we have a radial gradient here i make the outer radius a larger value even larger the gradient doesn't have to be symmetrical inner circle can have center point that is off to the side like this just be careful if you give the inner circle values that position it outside of the outer circle you will get very strange behavior i think because of this radial gradient can be confusing for some coders but now you understand it if you have any questions how to apply gradients to your canvas effects let me know if you understand how gradients work after watching this video i would also like to know you can leave a quick comment that just says plus one since you added one new skill to your creative coding toolkits today if you want to make your gradient effect responsive we also have to include it in window resize event i just take all this code and i put it inside my event listener notice that i'm not re-declaring this led variable i'm just reassigning it to a different value every time canvas changes size the gradient will adjust itself to make sure it's centered do you want to discover more creative coding secrets check out some of these free courses i'll see you there [Music]
Info
Channel: Franks laboratory
Views: 5,531
Rating: undefined out of 5
Keywords: martix rain, javascript rain, html canvas, html canvas for beginners, html canvas tutorial, HTML5 Canvas, unicode rain, javascript animation, HTML5 Canvas for Beginners, vanilla JavaScript, front end web development, html5 canvas tutorial, Learn HTML5 Canvas, HTML5 Canvas API, html5 canvas animation, html, html5, javascript, franks laboratory, html canvas basics, frankslaboratory, learn web development, web development tutorial, web development tutorial for beginners
Id: f5ZswIE_SgY
Channel Id: undefined
Length: 24min 51sec (1491 seconds)
Published: Fri Dec 10 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.