Old browser

Sorry pal, you'll need a modern browser for this.

JS tribute to Eric Prydz's Opus

Like many others, I've been stuck at home due to the coronavirus pandemic; as of April 4 2020, I haven't been outside since the 20th of February; in order to distract myself from the situation and keep the morale up, I've been working on LibreSpeed, playing games, made some maps and mods for Warzone 2100, and worked on some minor projects that you'll be seeing over the next few months. This is one of them.

If you don't know Eric Prydz, he's one of the best house music artists ever; his most famous song, Pjanoo, you'll have almost certainly heard at some point in your life. In my opinion, his best song is Opus, released in July 2015, a true masterpiece of progressive house music that I can't get enough of.

This article is a tribute to Opus, and is an animated version of the cover of this release made entirely with JavaScript, some clever math, and by exploiting a bug that's present in all current browsers.

My recreation

The original cover

This the original cover for Opus, upscaled with Waifu2x because the original was pretty low res. Eric Prydz Opus - Single release cover If I had to guess, this cover was made with a fog machine and some lasers or a projector, much like the original Windows 10 wallpaper, and was then photoshopped.

How it works

Despite looking pretty cool, the effect is actually really simple and lightweight (the animated starfield present on the rest of this website is way more CPU intensive). It is also very small, at less than 4kb of size (not minified). This page is almost 5 times the size of the demo.
This is what we need to do each frame:

  • Apply a sort of persistence of vision effect to the previous frame
  • Optionally, draw some fog
  • Draw laser beams for this frame

The laser beams are the most complicated part of the drawing process. A laser beam is made up of 3 parts: the line in the middle and 2 dots. Everything is drawn using additive blending, so that it looks like lasers in real life.
To draw one of these beams, this is what we do:

  • Calculate the x,y coordinates of the center of the circle based on the spacing between circles
  • If the point is outside the screen or the central area (there's some padding), bring it back inside
  • Offset the x,y coordinates according to sine, cosine functions that depend on the time, the circle position, and which beam we're drawing inside that circle (default is 2 beams). When moving, this creates a circle. This is the position of the first dot
  • Calculate the x,y coordinates of the second dot by calculating the difference between the coordinates of the first dot and the center of the screen, multiplying the difference by the depth that we want for the circles, and adding it to the coordinates of the first dot
  • Draw the beam between the 2 points
  • Draw the 2 dots
This is what the lines look like without any additional effect: Lines with no effects

The persistence of vision effect can be achieved very easily by multiplying the previous frame by a color. In our case, the color is a very light shade of blue, #C0D0F0, with 20% alpha. This is the color used (without alpha and with alpha respectively):   
By doing this before each frame, the laser beams gradually change color and fade out.
Note that due to a well known bug in all major browsers, the beams never actually fade out completely, which is what is used to create the slightly visible cyliners. This is caused by a rounding error and it becomes more evident the longer you want your fade to be.
This is how it looks before and after the persistence of vision effect: Before and after persistence of vision effect

A fog effect (default disabled) can be done by drawing some random, thick, very light lines across the screen using multiply blending. In our case, the color was a slightly darker shade of blue, #9DADCB, with 20% alpha. This is the color used (without alpha and with alpha respectively):   
This is what the fog looks like before it is multiplied to the frame, and after: Fog before and after multiplying

When the canvas is resized, everything is deleted and a several draw/fade cycles need to be done to create the cylinder. This creates a lag spike on slow devices.
To improve performance, many things, such as scaling and how many circles to draw, are precalculated here based on the size of the canvas.

The only downside of this technique is that everything is FPS dependent: the animation is designed to run at 60fps, and it will run at that speed on 99% of machines, but if you have a high refresh rate monitor, it will play faster, and if you have a really slow machine, it will play slower.

The code

Download HTML file
You are free to do what you want with this code.

Share this article