Morphing text particles

< html > < body > < style > body { background - color : black ;}</ style > < script > let phrases = [' :-(', ' :-)',' Welcome ', ' to another ', ' JavaScript ', ' tutorial :', '> morphing ', '| text ', '< particles ','----------','__________',]; let framesPerPhase = 127 ; let size = 10 ; let imgData ; let canvas = document . createElement (" canvas "); canvas . width = 1200 ; let counter = 0 ; let phraseCounter = - 1 ; let phase = 2 ; let canvas2 = document . createElement (" canvas "); canvas2. width = 800 ; canvas2. height = 400 ; let particles = []; let activeParticleCount = 0 ; let phraseParticleCount ; let spread = 100 ; document . body . appendChild (canvas2); let context = canvas . getContext ("2d"); let context2 = canvas2. getContext ("2d"); let img = new Image (); img . src = ' fnt . png '; function setTarget ( particle , x , y ) { particle . targetX = x ; particle . targetY = y ; particle . speedX = ( particle . targetX - particle . x ) / framesPerPhase ; particle . speedY = ( particle . targetY - particle . y ) / framesPerPhase ; } function calculatePhrase () { phraseParticleCount = 0 ; let phrase = phrases [ phraseCounter ]; for ( let letter = 0 ; letter < phrase . length ; letter ++) { let char = phrase . charCodeAt ( letter ); for ( let y = 0 ; y < 8 ; y ++) for ( let x = 0 ; x < 8 ; x ++) { let offset = x * 4 ; let pixel = imgData . data [ char * 8 * 4 + offset + y * ( canvas . width * 4 )]; if (! pixel ) { let particle ; if (! particles [ phraseParticleCount ]) { particle = { targetX : x * size + letter * 8 * size , targetY : 100 + y * size , color : 0 , brightnessIncrease : 2 }; particle . x = particle . targetX - spread / 2 + Math . floor ( Math . random () * spread ); particle . y = particle . targetY - spread / 2 + Math . floor ( Math . random () * spread ); particles . push ( particle ); } else { particle = particles [ phraseParticleCount ]; particle . brightnessIncrease = 2 ; } setTarget ( particle , x * size + letter * 8 * size , 100 + y * size ); phraseParticleCount ++; } } } if ( phraseParticleCount >= activeParticleCount ) { activeParticleCount = phraseParticleCount ; } else { for ( let i = phraseParticleCount ; i < activeParticleCount ; i ++) { let particle = particles [ i ]; particle . brightnessIncrease = - 2 ; setTarget ( particle , particle . x , particle . y ); } } } function animate () { if ( phase == 1 ) { context2. clearRect ( 0 , 0 , canvas2. width , canvas2. height ); for ( let i = 0 ; i < activeParticleCount ; i ++) { let particle = particles [ i ]; particle . x = particle . x + particle . speedX ; particle . y = particle . y + particle . speedY ; let color = particle . color ; if ( color > 2 ) { context2. fillStyle = ' rgb (' + color + ',' + color + ',' + color + ')'; context2. fillRect ( particle . x , particle . y , size , size ); } color = color + particle . brightnessIncrease ; if ( color > 254 ) color = 254 ; if ( color < 0 ) color = 0 ; particle . color = color ; } } if ( counter % framesPerPhase == 0 ) { phase ++; if ( phase == 3 ) { phase = 1 ; phraseCounter ++; if ( phraseCounter == phrases . length ) phraseCounter = 0 ; calculatePhrase (); } } counter ++; window . requestAnimationFrame ( animate ); } img . onload = function () { context . drawImage ( img , 0 , 0 ); imgData = context . getImageData ( 0 , 0 , canvas . width , canvas . height ); animate (); }; </ script > </ body > </ html >

Here's another short code snippet for you that produces the cool text transition effect above.It extracts bitmap data from a PNG font and creates particles for non-blank pixels. Then it moves the particles to form another word:Details:[1-4] HTML setupVariables:[5] phrases to display[6] number of frames per one phase of animation[7] particle size[8] an array with the bitmap of the source font set[9-10] canvas with the source font (will not be visible)[11] animation frame counter[12] current phrase[13] current animation phase (1=animate, 2=wait)[14-16] the target canvas that will show the animation[17] the array of particles that will do all the work[18] the number of particles that are currently active[19] the number of particles needed to display a given phrase[20] the distance between the randomized particle location and the target location (only for the first phrase)[21-25] HTML setup for the two canvases and the source image (taken from here) [27-32] Set target coordinates for a given particle, calculate its speed[34-73] Convert a phrase to particles:[35] reset the particle counter[36] get the phrase from the array[37-38] Get the ASCII code of each letter[39-40] For each pixel in the 8x8 grid:[41] get the offset of the red component (since it's a black and white image, all RGB components are equal, so I just picked the first one)[42] get that byte from the imgData array[43-61] if it's not empty:[45-54] if a new particle needs to be created:[47-54] randomize its coordinates around the target, set color to black and brightness increase to positive[56-57] otherwise reuse an existing particle, set the brightness increase to positive[59-60] set the target coords for the particle and increase the particles count[64-65] if the number of particles in the new phrase is equal or greater than in the previous one, update the count[66-72] otherwise set the brightness increase to negative for all redundant particles[75-109] the animation function:[77-93] if we're in phase 1, animate the particles:[80-81] update their coordinates[84-85] draw the particles.[87] update their brightness (dimming if negative). The Red, Green and Blue components or the color are equal, resulting in shades of gray[88-91] make sure that the color is in the 0-255 that can be handled by RGB[95-96] if the counter reached a multiple of framesPerPhase, go to the next phase[97-103] go back to phase 1 if phase 2 finished. Increase the phrase counter (and reset if last phrase)[109-112] when the image is first loaded:[110-111] draw the font bitmap on the invisible canvas and copy the pixel data to the imgData array[112] start the animation!Check out these programming tutorials: