Back

ARTIST · 3D Music Cards

A full-screen interactive music space: a Tripo character stands at the centre while six genuinely playable glass record panels surround them in an irregular 3D constellation. Select a track and its panel is pulled out of the space, flies to the foreground and lands at the bottom as a 2D player.

Author: Theodore
Try it live
ARTIST · 3D Music CardsTry it live

About this project

The six panels are genuine WebGL geometry inside the scene — they have thickness and curvature, they occlude the character and are occluded by them, and their depth order stays correct from every angle. They are not DOM cards floating over a canvas.

The whole interaction rests on one division of labour: 3D is for discovery, 2D is for control. The panels handle browsing and selection, drifting around the character and turning with your gestures; actual playback control belongs to the stable screen-space interface at the bottom. Selecting a song is not a state switch but a continuous hand-over — the panel itself flies down to become the player, and when another track is chosen, the old one flies back to its original 3D slot.

Highlights

  1. Drag empty space and the music cards revolve around the character, releasing into inertia; drag the character and only they turn, camera and panels untouched. Both drift slowly in opposite directions — the opposed motion is what makes the cluster read as an orbiting body rather than a backdrop
  2. Click a panel and it breaks out of the 3D space, sweeps past the character and unfolds into a horizontal player at the bottom; pick another and two panels are airborne at once — the old one folds back into its exact original slot as the new one comes forward
  3. The wheel dollies the camera between 4.6 and 16 world units: push in and the foreground panels overflow the frame, pull back and the whole space gathers into one music constellation seen from above
  4. The custom cursor's four-corner frame locks onto each panel's real projected quad — the brackets land on true perspective corners and turn with the panel's tilt

Technical breakdown

  • 3D assets · The untouched Tripo export

    Artist.glb ships exactly as exported from Tripo: 59 MB, 1.02M vertices, an 8192² base colour map — nothing decimated, nothing resized, full authored detail. The cost is priced in (~350 MB VRAM once mipmapped, a million vertices redrawn per frame) and two decisions keep it manageable: the heavy mesh opts out of raycasting — a million triangles per pointer move would stall the main thread — with an invisible capsule sized from the model's own bounds standing in for it; and since the export has no animation clips, the character gets a group-level idle (a slow sway plus a millimetre of breathing) rather than an invented skeleton.

    A meshopt pipeline in scripts/ takes the same file to 2.9 MB; the model is measured and normalised at load time, so swapping builds needs no code change.

  • Materials · Downgrading the volume material in Tripo exports

    Tripo exports tag the mesh with KHR_materials_volume, which lands in three.js as a MeshPhysicalMaterial with a transmission/thickness path this scene neither wants nor can afford. At load every material is downgraded to MeshStandardMaterial with the full PBR map set kept — same look, cost gone.

    Custom ShaderMaterials include colorspace_fragment explicitly: without it they write linear values straight into an sRGB framebuffer and render almost black.

  • Music panels · Real geometry on a curve

    Each panel is four kinds of geometry — a face, a rim strip swept for real thickness, a translucent back plate, and invisible hit quads — all sharing one cached buffer set, only the group transform differing per card. Everything is authored flat and wrapped onto a large vertical cylinder: the progress groove and clock are baked onto the same curve rather than parented to it, and the progress fill is a UV cutoff injected into a MeshBasicMaterial — scaling a mesh would lift its far end off the curve.

    Panel artwork splits across three canvases by update frequency: the 1320×680 face paints once, the time strip repaints when the displayed second changes, the icon only when playback flips — nothing expensive in the render loop. All six transparent panels skip depth writes and take banded renderOrder by camera distance every frame, so occlusion stays correct from any angle.

  • 3D-to-2D relay · A card lands as the player

    A WebGL mesh cannot become a DOM node, so continuity is assembled from three facts: a projector keeps every card's screen-space box current each frame — including hidden ones, because the return flight needs somewhere to land; the DOM panel's first frame is the very canvas bitmap already painted for the card's WebGL texture, not an HTML re-creation that would never quite line up; and the card hides on the same frame — two things in one place, one invisible.

    Widening holds until the flight is ~35% done — stretching a 2:1 card into an 11:1 bar mid-flight turns the artwork to mush — and the path is a quadratic bezier bowed to the side, so a card docking from the upper left sweeps around the artist. The destination is re-read every frame: the constellation is still drifting, and a rect sampled at launch would land the panel beside its card.