I Recreated the ‘Flying Windows’ Screensaver with JavaScript

Created using the p5.js library

Miroslav Šlapka
Jan 7 · 5 min read

I am going to show you how to create a 3D effect on canvas using a library called p5.js. I watched some videos demonstrating the usage of this library and I found also this coding challenge (creating starfield) in Processing. I decided to rewrite it in JavaScript and then improve it slightly. Do you remember old Windows screensavers? One of them looked like this:

Image for post
Image for post
old Windows screensaver

The animation above is based on Starfield Simulation, or Warp drive. Instead of ‘stars’ we can see flying windows. Let’s recreate this but with the latest Windows logo so the result would look like this.

Image for post
Image for post
flying Windows logo created in p5.js (Check out the DEMO)

P5.js

p5.js is a JavaScript library for creative coding, with a focus on making coding accessible and inclusive for artists, designers, educators, beginners, and anyone else!

It is JavaScript implementation of Processing, which is a flexible software sketchbook and a language for learning how to code within the context of the visual arts. It is very easy to start with, because there is also an online p5.js editor. When you open it, you will see just 3 files:

  • index.html
  • sketch.js
  • style.css

Index.html links the library and sketch.js is the file we are going to work with. It contains 2 main functions by default:

setup() is used for initialization and runs only once, while draw() function runs repeatedly and is used for animation. That’s all you need to know for now about p5.js.

Warp drive with Windows simulation

Warp drive basically means travelling faster-than-light, and you might be familiar with it from the Star Trek series. Instead of stars we want to create Windows, so let’s create a few variables first.

Then in the setup() function we can iterate through the number of windows and fill the array with a newly created Window objects.

How does Window object look like? Let’s use class to define it

Window has several properties: x, y, z (coordinates) and pz , which is the previous z location. width and height are system variables defining the canvas size.

Random() function returns a random floating-point number, and we use it to randomly redistribute our windows on the screen (x , y , z).

update()

There is also update() function we can take a look at:

Just a few things going on here.

In canvas, ‘x’ and ‘y’ start at the top left corner.

Image for post
Image for post
Canvas coordinates system

We have also the ‘z’ coordinate even though we don’t have WEBGL (3D) mode enabled. We want to simulate movement on that axis though. In the update() function we update that coordinate by subtracting speed so the objects appear to come towards us.

this.z = this.z - speed;

If ‘z’ is less than 1, the objects are out of the canvas and therefore we reset the coordinates.

show()

In the show() function we have:

Daniel Shiffman in his source code explain the above in the comments:

with theese “map”, I get the new star positions
the division x / z get a number between 0 and a very high number,
we map this number (proportionally to a range of 0–1), inside a range of 0 — width/2.
In this way we are sure the new coordinates “sx” and “sy” move faster at each frame and which they finish their travel outside of the canvas

I’d like to point out 2 things here:

  • map() function re-maps a number from one range to another.
map(value, start1, stop1, start2, stop2)
  • the divisions x / z and y / z represent the equation of weak perspective projection. In other words, transforming world-space coordinates (x,y,z) to screen-space (u,v)
u = x / z; 
v = y / z;
Image for post
Image for post
Weak Perspective Projection

draw()

Now we can update the main draw() function:

We iterate through the windows array and call the functions we defined before on each object. You should see this:

Image for post
Image for post

Almost there! But we want windows!

Loading images

I downloaded the Windows logo and prepared several color variants:

Image for post
Image for post
Windows logos

We need to create a preload() function and create a new variable imgs

I prepared 5 images, and gave them the same name with the number suffix, so it’s easy to load them in a loop. Now we can add another property to constructor, where we can use again the random function. We are passing an array there, so a random image variant will be picked.

Note: Instead of creating several images, I tried changing the color of the image with a tint() function, but the performance suffered greatly.

Then we just replace ellipse() in a show() function with the image() like this:

image(this.img, sx, sy, r, r);

Yay! We recreated the Windows screensaver. I feel like something is missing though.

Loading (error) sound

I wanted to play the Windows error sound in a loop as if the windows flying out of the screen were making it. P5 has an additional library called p5.sound.js that we can use for that.

We just have to update the preload function like this:

And also update the main setup() function:

Well done, you should get this RESULT.

Thank you for reading!

JavaScript In Plain English

New JavaScript + Web Development articles every day.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store