Exploring 3D
I've been spending time with 3D design lately, mostly out of curiosity. I wanted to get a feel for how light, geometry, and materials shape a scene. It feels like building, but in a looser, more visual way.
This is one of the first things I made: a heart-shaped gem with refraction, glow, and particles. You can rotate it, and you can change the color.
How it's made
The heart curve
The shape is not drawn by hand. It comes from a parametric equation. Feed in an angle t from 0 to 2π, and you get back x/y coordinates that trace a heart. sin(t)³ makes the top lobes, while the stacked cosine terms shape the point at the bottom.
const x = 16 * Math.pow(Math.sin(t), 3);
const y = 13 * Math.cos(t)
- 5 * Math.cos(2 * t)
- 2 * Math.cos(3 * t)
- Math.cos(4 * t);
Using 200 points around the curve gives a smooth outline. Three.js turns that into a Shape, and ExtrudeGeometry pushes it into 3D with beveled edges. That is what gives the gem its faceted look.
Faking gemstone light
Real gemstones bend light internally, which is expensive to simulate properly. Three.js has a MeshPhysicalMaterial that gets surprisingly close with a few settings. transmission makes the material transparent, ior set to 2.42 gives it a diamond-like refraction feel, and thickness controls how far light travels before it bends.
const gemMat = new THREE.MeshPhysicalMaterial({
transmission: 0.92, // almost fully transparent
ior: 2.42, // diamond-like refraction
thickness: 1.2, // depth of internal refraction
roughness: 0.0, // perfectly smooth surface
reflectivity: 1.0, // maximum reflections
});
The glow around the gem is a separate mesh scaled slightly larger with additive blending. Light adds up instead of replacing what is underneath, so the glow blooms naturally against the dark background.
Sine waves everywhere
Almost everything that moves here uses Math.sin() with elapsed time. Sine waves are smooth and repeating, which makes them great for motion that feels organic. The heartbeat pulse, the breathing glow, the halo, the spark twinkle, each one is basically a sine wave with a different speed and range.
// heartbeat: subtle 4% scale oscillation
const pulse = 1 + 0.04 * Math.sin(t * 2.5);
// glow breathing: slower, larger range
const breathe = 1.08 + 0.06 * Math.sin(t * 1.8);
// halo pulse: big and slow
const h1 = 4.0 + 0.8 * Math.sin(t * 1.2);
Layering a few sine waves at different speeds makes the scene feel more complex than it really is. The floating particles use sine and cosine together for circular motion, with random phase offsets so they do not all drift in sync.
Particles on a sphere
The sparkles are 120 points scattered around a sphere using spherical coordinates: a random angle for longitude, another for latitude, and a radius. Converting that to cartesian coordinates gives x, y, and z positions that wrap cleanly around the gem.
const theta = Math.random() * Math.PI * 2;
const phi = Math.random() * Math.PI;
const r = 0.5 + Math.random() * 1.2;
x = r * Math.sin(phi) * Math.cos(theta);
y = r * Math.sin(phi) * Math.sin(theta);
z = r * Math.cos(phi);
The whole particle system rotates slowly, and the opacity fades in and out with, yes, another sine wave.
There is something satisfying about making something that exists only to look interesting. No product angle, no pitch, just shape and light. I want to keep following that thread.