JavaScript Image Animation Tutorial [Pixel Rain]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
to create any of these effects all you need is text editor and the javascript it might be easier than you think the most important html canvas method that allows us to take an image and convert it into interactive particles is called get [Music] whenever i see creative animation or an effect on the internet i always inspect it most of them are done using libraries how about we build our own animations completely from scratch with no frameworks and no libraries using just plain vanilla javascript and practice fundamental programming principles and techniques in the process [Music] hi coders welcome to another creative coding tutorial today we will build a vanilla javascript algorithm that can take any image of your choice it will scan that image for pixelator and create color and brightness map that represents the image when we have the data we delete the image create a very simple particle system and we make these particles flow over the canvas at different speeds depending on the brightness of the area in the original image recreating it as particle rainfall this video is completely standalone and i will explain everything from scratch i also have another tutorial where we break image into interactive particles and another one where i explain get image data for complete beginners in that video i show you how to analyze image pixel by pixel average out color values for each individual pixel and turn image into grayscale i will link both of these related videos down in the description while building this effect we will practice fundamental vanilla javascript principles and techniques that can be used for many other different programming projects not just for this particular effect we are building today we will learn about es6 classes array manipulation math.random draw image and get image data built in html canvas methods and couple of other things i really like this animation you can use it for your coding portfolio to impress potential employers or just as an exercise to practice vanilla javascript and get yourself one step closer towards your personal front-end web development mastery it can be used as animated background interactive company logo or even maybe as a loading animation if you follow this channel and you are interested in javascript html canvas and creative coding i'm sure you can come up with even more use cases and interesting variations if this is the first time or meeting hi my name is frank and i'm a self-taught front-end web developer i'm originally from czech republic but i moved to london many years ago where are you from you can leave a comment if you want i want to know which countries my viewers are from if you are also on a journey to become a self-taught front-end web developer remember that you are your number one asset invest in yourself and stick with it for as long as it's needed and you will be successful well done for watching educational content like this online you are doing great keep learning keep building projects and don't give up that's how you get where you want to be in fact let me know in the comments how long have you been studying javascript it's good to stay active in online self-taught community to keep yourself motivated we are here to help each other and learn together i make creative coding tutorials and my goal is to help you master javascript step by step while having fun building visually memorable projects don't forget to click like if you want to see more content like this you can also subscribe and click all notifications on the bell icon to make sure you don't miss any of my future vanilla javascript tutorials this episode is not for complete javascript beginners i will explain all the codes today from scratch line by line but if this is your first javascript or html canvas project you can check out my playlist in the video description with tutorials i specifically picked for beginners so later you can join me for more complex tutorials like this one hope you have fun let's start coding [Music] let's start in index.html by creating html5 canvas element i give it id of canvas1 i also link css stylesheet and javascript file here install css i use asterisk selector to target all elements on the page and i do global reset to make sure our styles are the same across different browsers margin 0 padding 0 box size and set to border box and let's also do black background i give canvas border 2 pixels solid white and i center it by setting its position 50 from top this will actually only work if i set its position to absolute left will also be 50 and transform translate minus 50 minus 50 will center it both vertically and horizontally i make the canvas exactly the same size as the image i will be using so for you it might be different my image is 500 times 706 pixels everything else will be done with javascript in script js file i will start by bringing my image into the project so constant variable i call for example my image and i set it equal to new image now i can give it src property which could point to an image file but because some browsers don't like it when you analyze pixels of image with get image data when that image is not hosted on the same server to avoid all different kinds of cross origin resource sharing errors i will convert our image into url string that way the image itself is part of javascript file and everything will work without errors we can use javascript to convert the image but for speech today let's use a website that will do it for us i google something like png to base64 and i choose this link my image can be any image format it doesn't have to be png here i can just drag and drop image i will be using my advice is to make the image as small as possible otherwise you will get a very long data string and since we need to be cycling through these pixels later with javascript smaller image will improve your performance also if you saw the final effect you don't need very fine image resolution for this effect to look great so i made my image as small as possible you can go even smaller if you are having any performance issues i drag and drop it here and i convert it to base 64. for us to be able to use it we need string to start with data colon image so make sure you tick this checkbox here now i copy this extremely long data string which just basically converted the entire image into a line of code so we won't need the actual image file at all i paste that code on line 2 to bring the image into our project now the usual canvas setup cons canvas equals to document.getelementbyid and i pass it canvas1 the id i gave it earlier ctx shortcut for context is equal to this canvas variable dot getcontext2d now we have access to all 2d canvas drawing methods i set canvas width and canvas height to be the same values i declared in style css to make sure the scaling is right now i draw the image on canvas by using built-in html canvas method called draw image it has three versions we will use the middle version of this method that expects five arguments the first is the image i want to draw so my image variable from line one i want the image to start from top left corner of canvas so coordinates 0 0 and i want it to cover the entire canvas area so end coordinates of image rectangle will be canvas width canvas height sometimes drawing your image this way will not work for you because the draw image method only works when image has been fully loaded to make sure we avoid any potential errors we can wrap this whole thing in event listener since we gave our image src property we can now listen for load event on it like this and in callback function only after the image has been fully loaded we run all the code that depends on that image i will just put everything inside like this why not we are now all set let's create a simple particle system that will produce a set of falling particles to flow over the image i create a led variable called particles array and i set it equal to an empty array i use led here so that i can reassign it to a new empty array later if i want to i create a constant variable called number of particles and i set it to let's say 5000 i create a javascript class called particle with capital p we will use it to create 5 000 similar particle data objects and we will push them inside particles array from line 12. constructor is a mandatory method on javascript class and it will contain blueprint for each individual particle this dot x horizontal x coordinate will be a random number between 0 and canvas width i want particles to kind of splash over the image from top so i set start in distort y horizontal coordinate to zero you can also do other things here maybe you want the particles to flow from bottom to top or from left to right or maybe you want them to spiral around in a circle you would adjust starting x and y based on the final effect you are going for falling speed will be 0 at first i will also have velocity which will be a random number between 0 and 0.5 basically here i have falling speed which will be calculated based on brightness of background so particles will fall over black areas very fast and over light areas of the image much slower velocity is here just to give it some additional randomness i think it will look good particles will have random size between 1 and 2.5 pixels for example update method will calculate particle position for each frame before we draw it let's start simply by adding plus 1 to horizontal y y-coordinate once particles fall below the bottom edge of canvas i want them to reset to position 0 up top so they can fall down again at the same time i will also give them different random horizontal x position this is important because particles will fall slower over light areas of the image actually rather than to have all particles fall at the same speed we can randomize it a bit this dot y plus equals this dot velocity and velocity on line 20 is a random number between 0 and 3.5 custom draw method will simply just draw a circle to represent each particle begin path to start drawing fill style will be white ctx arc to draw a circle i pass it x and y size start angle and end angle then i call ctx fill to fill circular pathway color i create a custom function called init shortcut for initialize this function will just have a for loop that will run as many times depending on number of particles variable in this case 5000 each time it runs i call built-in push method on particles array from line 12. push method places whatever we pass to it at the end of the array so i pass it new particle the new keyword will trigger particle class constructor on line 16. it will create one new blank particle object and assign it properties and randomized values based on the blueprint for loop will run 5000 times filling particle array with 5000 randomized particle objects now i call init to fill the array function animate will be our main animation loop first i want a semi-transparent black rectangle to be drawn over the canvas for every frame this will give particles fading trails i set global alpha to 0.05 this just specifies transparency value that is applied to shapes and images on canvas 0 is fully transparent one is fully opaque now i set fill style to rgb 0 0 0 which is black color i draw a rectangle that covers the entire canvas ctx fill rect starting coordinates 0 0 and in coordinates canvas with canvas height i will cycle through the entire particles array and for each particle object in the array i call their associated update method from line 23 and a draw method we declared online 30. this for loop will cycle through all 5000 particles for each frame of animation it will recalculate their position with update method and it will draw them at their new coordinates with draw method now i just call animate to kick off animation loop this will not work because i also have to call a request animation frame here and i pass it animate request animation frame is a built-in javascript method when i pass it animate the name of its parent function from line 43 that way animate will run all its code and it will just call itself again here on line 51 create an animation loop through a program in principle called recursion when function calls itself over and over that worked now we have falling white particles that leave trials perfect i can temporarily copy draw image call from line 10 and i put it inside animation loop so that we can see the original image for now click like please if you're getting any value from this tutorial you can also subscribe and hit all notifications to make sure you don't miss any of my future creative coding vanilla javascript tutorials particles are falling and ignoring the image how do i make them fall at different speeds based on brightness of the area they are moving over one way to do that is to create a brightness map of the entire image it will correspond to x and y coordinates of each pixel then i can run this information against particle's current x and y position and adjust particle's speed based on its current coordinates let's do it step by step first i create a new led variable called mapped image this will be an empty array at first my goal is to have this array hold brightness value of each pixel in the image along with that pixels x and y coordinates so i can compare it to x and y coordinates of each particle and adjust their movement speed accordingly so on the first page load we just draw image on canvas here on line 10. i create a custom variable called for example pixels and i set it equal to ctx.getimagedata built in canvas method this method scans area of canvas for pixel information and it will return an array-like object that holds red green blue and alpha value for each individual pixel in the scanned area i want to scan the entire canvas so i pass it to 0 0 as starting coordinates and canvas with canvas height as the end coordinates so now my custom pixels variable holds whatever get image data returned after scanning the designated area in our case the entire canvas if i count to lock pixels i see this returned image data object if i open it it contains array called data it also contains height and width attributes that correspond to width and height of the scanned area we scan the entire canvas so width and height correspond to canvas width and canvas height from lines 7 and 8. let's inspect the data array you can see it is called uint clamped array that means unassigned integer so it can only contain elements that are whole numbers with no decimal points it also says clamped because these numbers are limited to a range between 0 and 255 if you worked with css before you know that in rgba color declaration every color can be declared by combination of red green and blue with values between 0 and 255 for each we established that each element in this data array could only be a number between 0 and 255. if you look at the data structure you can see that every 4 pixels in the array combined create rgba color declaration of 1 pixel in our image so this one for example is 0 for red 0 for green 0 for blue and 255 for alpha opacity in this case alpha is also declared as a value between 0 which is fully transparent to 255 fully opaque we can double check if you are right about this we have an array of 1 million 412 000 elements and we know that each four elements in this array represent rgba color value of one pixel so one million four hundred and twelve thousand divided by four is three hundred and fifty three thousand these numbers depend on the size of the image you uploaded so for you it might be different we know the image i'm using is 500 pixels wide and 706 pixels high so 500 times 706 is also 353 000 so that checks out let's look at the pixels with color that are not black for example here we have 111 for red 83 for green blue and 255 for alpha then 139 is right of the next pixel and so on so now we understand how the color data returned by getimagedata method is organized we can cycle through it and save it in our own array and since we know width and height of the scanned area we can calculate x and y-coordinates of each pixel since we know how many pixels fit on one row and we know how many rows and how many columns our image has this is the only a bit more difficult part in this tutorial so if you are a beginner keep in mind this is not easy don't feel bad if you struggle to imagine what exactly is going on i made a beginner friendly version of this technique where we cycle through all pixels and turn image into grayscale sometimes it's easier to first try this with a simple project i will link it in the video description we will cycle through every pixel in this image row by row from left to right starting from the top left corner so the first for loop will have a vertical y coordinate at zero our image is 500 pixels wide so y will be 0 and x will be 0 1 2 3 all the way to 500 then we increase y to 1 and again we cycle through pixels 0 to 500 horizontally then we increase y to 2 and we cycle through the entire x coordinate of pixels again we will do this 706 times because our image is 706 pixels high which means it contains 706 rows of horizontal pixels the code will look like this we will use nested for loops which means loop inside of another loop the outer loop will represent vertical y coordinate so it will run 706 times because our image is 706 pixels high which means we have 706 rows of pixels we will start with top row 0 and go all the way down to row 706 on the bottom for each row of pixels in the image i will create an array called row it will hold our pixel data for each of the rows for every one of these rows we enter the inner loop and index of this in loop will correspond to horizontal x-coordinate of pixel within the image starting from x coordinate 0 and going to the right until we reach pixel 500 because our image is 500 pixels wide then we just exit the inner loop increase y by 1 therefore jump in to the next row and going through the horizontal pixels from left to right from zero to 500 again i'm not sure if i'm over explaining this or if you need me to explain it more let me know in the comments please i'm just trying to make it accessible for beginners as well so now we have two nested for loops that work together to cycle through every single pixel in the image for each individual pixel i want to read its color values so here i will create a temporary variables for red green and blue red for each pixel will be pixels variable from line 11 dot data which is this data object here with one million four hundred and twelve thousand elements where we know each four elements represent red green blue and alpha of one pixel there are many ways we can skip array index by four i will use this formula i'm sure there is easier way to do this let me know in the comments the first part that says y times 4 times pixel's width just keeps track of overall number of array elements from previous rows and the second part that says x times 4 just adds the items from the current row to it so the final number we get is array position of red value for pixel with this y-coordinate and this x-coordinate this is not programming anymore this is more like advanced logic and visualization i wish i had more visual tools to show you better what's going on i will try to come up with something for future tutorials in the meantime let's just finish this once we know what index red color value is it's easy to get green blue and alpha because we know that this data array is organized in a way where red is followed by green which is followed by blue and alpha since i know this i know that green is whatever red is plus one and blue is position of right in pixels array plus 2. so now i have calculated red green and blue of pixels at this vertical y coordinate and this horizontal x coordinate i could just add them together and divide them by three to get their average value which is the same technique we used to turn image into grayscale in the previous episode for beginners link in the video description there is a strange thing about human eye that we don't perceive red green and blue the same the same amount of red is not the same brightness as the same amount of blue when perceived by human eye we can create a simple utility function that will take red green and blue value we just calculated for each pixel it will adjust them by different amount based on human brightness perception and it will return a single number representing relative brightness of that pixel custom function called for example calculate relative brightness it will expect three arguments red green and blue we calculated on lines 20 21 and 22. it will just straight up return a number calculated by following formula i found this formula online we don't have to fully understand it because all it does it adjusts red green and blue by different amounts to make up for the fact that the human eye doesn't perceive these three colors the same when it comes to their relative brightness this is just for fun to make it more visually accurate i guess as i said this formula could have been a simple other red plus green plus blue divided by three to get average and it would work as well of course then you have to adjust the rest of the code like particle falling speed based on the range of numbers this would return up on line 23 i create a variable called brightness thanks to javascript principle called hoisting i can call my custom calculate relative brightness function i declared on line 27 up here on line 23 before that function is declared hoisting allows us to do that it expects three arguments so i pass it right i calculated here on line 20. this simply is a reference to index in pixels array as we cycle through it so for example for this pixel red would be zero green would be zero and blue would be zero so brightness is zero as well i create a constant variable called cell and i set it equal to an array i give it property called cell brightness and i set it equal to brightness variable from line 23. here inside the cell array you could also create another property called cell color and create rgb color declaration where you concatenate red green and blue and you save this pixel's actual color so we can use it in fill style and draw method for that particle that way you can persist original colors of the image more on that later so we calculated relative brightness of pixel of this vertical y and this horizontal x coordinate and saved it in a custom array i call cell i take row variable from line 18 and i push cell from line 24 to that array we will create this cell array for every pixel in every row so row variable from line 18 will be created 706 times because outside for loop will run for every row of our image which is 706 pixels high and inside of each of these 706 rows we create cell array here on line 24. we will have 500 cells for each row because our image is 500 pixels wide each cell holds relative brightness value for each individual pixel in the image so every time the loop is done and we pushed 500 cells into that row we take the entire row from line 18 and push it into mapped image array from line 16. that way when all these loops have run we have mapped image array with 706 row arrays inside of each of these row arrays there are 500 cell arrays each cell array from line 24 represents 1 pixel in the image we did it we cycled through pixels variable from line 11 we took that image data and created our own array called mapped image that contains brightness values for each pixel on canvas if i consolidate mapped image you see 706 items these are the row arrays from line 18. each one holds 500 cell elements from line 24 and each cell is an array that contains only one element that is this cell brightness property that contains relative brightness of each pixel we calculated we will get a lot of zeros as cell brightness value because there are large black areas around my image but if i keep looking i will be able to find other values here as well see now i just need to take this information about brightness i stored in mapped image variable and somehow make particles fall at different speeds based on that first of all we need to navigate in indexes of that array based on particles current x and y coordinates since array index has to be integer whole number with no decimal points here on line 48 and 49 inside particles class constructor i create position 1 and position 2 custom variables that will simply round down this dot x and this dot y making sure that these numbers don't have decimal points i also need to put these values here inside update method to make sure every time we update x and y position these values stay rounded down as whole numbers as integers now the main trick of how this entire effect works i will adjust this.speed from line 45 i will literally take values from my custom mapped image array and since we organized pixel data in the array to the same width and height as our canvas using our nested for loops i pull value from a mapped image array based on particles current x and y position this dot position 1 corresponds to particles current vertical y coordinate as we declared on line 52 and adding it as index like this on line 54 will access custom row array in mapped image which has the same vertical y position as the particle currently has then we go one level deeper inside map image array to access horizontal x position i called these arrays cells if you remember and they contain only one property called cell brightness so that's array position 0. so what we have here is mapped image custom row array from line 18 custom cell array from line 24 and it has only one element i called cell brightness from line 25 so position in this array is zero and since outer loop that created mapped image on line 17 matches height of canvas and in a loop from line 19 matches canvas with the brightness information held in mapped image will correspond exactly with our image let me show you i appreciate this might be hard to follow and imagine what's going on at first if you can't follow what i'm explaining here with no problems congratulations you are not in majority of us it took me a while to realize how this works to create a full mental picture i bet some of you will be able to tell me there is a much simpler way to do this and i am looking forward to these comments i've learned a lot from your comments already so please keep them coming so here on line 54 i take speed from line 45 and i assign it to brightness value of that area in the original image then i create a custom variable let's call it movement for example relative brightness we calculated earlier and which is now reflected in distort speed because of line 54 with a small number between 0 and 2.5 approximately i think since i want dark particles that have brightness close to 0 move very fast and i want light particles with relative brightness close to 2.5 to move very slow i flip it by saying 2.5 which is the maximum minus this dot speed and i also want to randomize it a bit so if we have a large area of particles with the same color they still don't move exactly the same speed to do that i just do plus this.velocity from line 46. now here on line 57 i say this.y plus equals movement and we should be able to see that particles react to image now velocity on line 46 is too high let's change it to random number between 0 and 0.5 perfect important part of this effect is that the faster the particles move the more transparent they are on line 77 inside animate i removed the image so it's not been redrawn over and over you can see we are getting something nice on canvas already code between lines 77 and 79 just creates a semi-transparent rectangle that is being drawn on canvas over and over given particles fade in trails once we draw it i want global alpha to increase to let's say 0.2 and here inside for loop that cycles through all particles for every animation frame before we actually draw the particle i will adjust global alpha for that particle to be equal to particle's speed property that's a bit too much let's half it speed times 0.5 up on line 10 on the first page load i draw the original image on canvas using built-in html canvas draw image method on line 11 i call get image data on it to get information about all its pixels and i save it to my custom pixels variable at that point i don't need the image anymore so i just clear canvas deleting the original image when i do this we will never see that image at all it will be drawn analyzed and deleted when page loads are very fast there are a lot of moving parts and many ways to customize this effect you can try to tweak some values and see what it does idea for this effect came from this brilliant code pen link in the video description luis also has many other interesting animations on there you can follow him if you want there is a lot of code in that code pen today we wrote our own version line by line using just plain vanilla javascript and we explained exactly what's going on on each line of code i hope it gave you some value and brought you one step closer to becoming a master of web animation now you should be able to understand it and tweak it to make your own variations or maybe even build on it and create something completely new are you able to take what we learned today and use pixel array to keep track of colors of the original image and make particles change colors based on that it should look something like this i had so much fun today hope you learned something new leave a like if you did if you want more creative coding with vanilla javascript check out some of my playlists i will see you there
Info
Channel: Franks laboratory
Views: 20,533
Rating: undefined out of 5
Keywords: javascript image animation, javascript image animation tutorial, javascript tutorial, javascript animation, vanilla javascript animation, vanilla javascript tutorial, pixel rain, javascript rain, html canvas animation, html canvas tutorial, html canvas image animation, animations in javascript, image animations tutorial, html canvas, html5 canvas, learn javascript, web animation, Javascript and html canvas, drawimage, getimagedata, franks laboratory, frankslaboratory
Id: RCVxXgJ8xSk
Channel Id: undefined
Length: 33min 27sec (2007 seconds)
Published: Fri Jan 01 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.