Opening The Door Into The Above With Code Orange

Using Three.js and PixiJS

Lee Martin
5 min readNov 20, 2023
Code Orange

Reposted from my dev blog: leemartin.com/into-the-above

Social media exists as a thin veil between perception and reality. We can curate the success of our identity, the beauty of our lives, and all of our worldly desires. Are you willing to look underneath? And if so, what will you find there? Code Orange invites you to open the door daily into the above. Explore the struggle and collapse of these two spheres in the form of hand made collages and prepare yourself for new music.

www.intotheabove.com

Read on to learn how Three.js and PixiJS were used to develop this experience.

Open The Door

Into The Above

When I first heard the phrase “Open The Door,” I immediately knew I was going to develop an actual door which users could click to open in order to enter The Above. I figured this would be pretty straight forward to put together with Three.js so that’s what I started with. The two main meshes of our door are the door itself and the door handle. In addition, we have meshes for the doorway and entry (what we see through the door.) I’ll focus on the door and door handle in this blog but check out this CodePen for the entire construction.

Door

We can create our door with a bit of BoxGeometry. Rather than add the door directly to our Three.js scene, we’ll add it to a swing Group which will handle the door opening rotation animation. When it comes to rotating objects from a single side (cantilever,) I’ve found it easier to work with objects nested in groups.

// Swing
const swing = new THREE.Group()

// Position
swing.position.set(18, 0, 0)

// Add to scene
scene.add(swing)

// Geometry
const geometry = new THREE.BoxGeometry(36, 80, 1.5)

// Material
const material = new THREE.MeshBasicMaterial({
color: 0xFFFFFF,
side: THREE.DoubleSide
})

// Door
const door = new THREE.Mesh(geometry, material)

// Position
door.position.set(-18, 0, -0.75)

// Add to swing
swing.add(door)

Door Handle

The handle is dealt with in a similar manner. The handle is a small BoxGeometry and it lives within a turn Group which manages its unique rotation (a 90° turn down on the z axis.) We’ll add the handle to the door mesh we setup earlier so it stays attached to the door when the door rotates.

// Turn
const turn = new THREE.Group()

// Position
turn.position.set(-16, 0, 1)

// Add to door
door.add(turn)

// Geometry
const geometry = new THREE.BoxGeometry(6, 1, 1)

// Material
const material = new THREE.MeshBasicMaterial({
color: 0xCCCCCC,
side: THREE.DoubleSide
})

// Handle
const handle = new THREE.Mesh(geometry, material)

// Position
handle.position.set(3, 0, 0)

// Add to turn
turn.add(handle)

Opening The Door

We can now animate our door open using Greensock. First, we’ll turn the handle down. Then, we’ll swing the door out. Again, these simple rotations are possible because we nestled the meshes within manually positioned groups.

// Timeline
const tl = gsap.timeline()

// Turn handle
tl.to(turn.rotation, {
duration: 1,
z: THREE.MathUtils.degToRad(-90)
})

// Swing door
tl.to(swing.rotation, {
duration: 5,
y: THREE.MathUtils.degToRad(90)
})

Again, I’d check out the CodePen I linked to earlier for more of the construction. I’ve shared an abstract base for the door so you can fork it and add your own textures. We went with a VideoTexture for our entry into the above. Speaking of which, let’s get into The Above.

The Above

intotheabove.com

On our experience, The Above is represented by a dynamic PixiJS powered collage consisting of images and videos which the client can manage on Contentful and change daily. I’ve shared a rather extensive CodePen of its construction so I’ll just talk through a few of the choices that were made.

Responsive

I wanted the collage to be fullscreen which means it needs to be able to handle a limitless amount of screen sizes and ratios. In addition to the collage base being responsive, materials added to the collage would be placed in random locations and receive random rotations. This randomness might lead to a clumping of materials so I established a six quadrant system for placement. On a portrait screen, the quadrants would be two columns of three rows. On a wide screen, the quadrants would be two rows of three columns. Each material added to the collage would receive a random location which existed somewhere within one of these quadrants. This allowed randomness within reason. In addition, users can click on materials to bring the clicked material forward by adjusting its z-index.

Video Materials

I love PIXI Sprites because they are fully adjustable objects which can receive many types of textures. In the case of our app, we wanted these sprites to originate from both images and videos. Images are pretty simple but what about dynamic videos? For videos, we just need to dynamically load the video into the dom, wait for it to load, and then associate the video as a texture on the new material sprite.

// Video
const video = document.createElement("video")

// Settings
video.autoplay = true
video.crossOrigin = "anonymous"
video.loop = true
video.muted = true
video.playsInline = true

// Update source
video.src = url

// Append to body
document.body.appendChild(video)

// Await video load
await new Promise(resolve => video.onloadedmetadata)

// Texture
texture = PIXI.Texture.from(video)

// Material
const material = PIXI.Sprite.from(texture)

While videos do autoplay when loaded, they are initially muted and only unmuted when the user clicks on them. This gives us the visual benefits of an autoplaying video without the headaches of many autoplaying audio streams. Also, it technically isn’t possible to autoplay an audible video without direct user interaction.

More

Those were the bigger learnings but I’d recommend checking out the CodePen if you’re looking for even more. I tried my best to comment the code throughout so you understand what is going on.

Acknowledgements

Thanks to Suzi Akyuz, Jason Mageau, Rachel Hacken, and their teams at Roc Nation and Blue Grape Music for tapping me for this build. Thanks to Code Orange for inviting me into the above with them. More to come.

--

--

Netmaker. Playing the Internet in your favorite band for two decades. Previously Silva Artist Management, SoundCloud, and Songkick.