webdevpuneet.com

Three.js Crystal Cluster — Glassy WebGL Gem Formation

Three.js Crystal Cluster · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

Copy & paste

Source Code

<canvas id="crystalCanvas"></canvas>
<div class="cc-badge">18 gems · glass-like material</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Clearcoat glass approximation: a cheap, convincing glassy look without real refraction or environment capture
Mixed geometry types: octahedrons, cones, and icosahedrons cycle to avoid a repetitive, copy-pasted look
Randomized bounded placement: gems scatter organically within a flattened volume, not along a formula
Independent per-gem drift: unique phase-offset vertical bobbing so no two gems move in lockstep
Randomized spin direction: some gems rotate clockwise, others counter-clockwise, based on random signed speed
Orbiting colored light: a moving light source continuously shifts which facets catch a bright highlight
OrbitControls with auto-rotate: damped drag-to-inspect with idle rotation when not in use
Loaded entirely from a CDN: no npm install, bundler, or build step required

About this UI Snippet

How to Build a Glassy Three.js Crystal Cluster

Screenshot of the Three.js Crystal Cluster snippet rendered live

The Three.js Crystal Cluster snippet scatters 18 faceted, semi-transparent gems into an organic mineral-formation shape, lit by an orbiting colored light for a shifting, glassy shine, using MeshPhysicalMaterial's clearcoat property to approximate a glass-like finish without true refraction, all with core Three.js and OrbitControls loaded from a CDN.

Clearcoat as a cheap glass approximation

True glass rendering — physically accurate refraction bending light as it passes through an object — is expensive and typically requires environment capture techniques like the one in the liquid metal sphere snippet. This snippet instead reaches for MeshPhysicalMaterial's clearcoat property: a thin, extra reflective layer on top of the base material, similar to a car's clear lacquer coat over paint. Combined with low roughness, moderate transparency, and a touch of emissive glow, clearcoat produces a shiny, glass-like read that's convincing at a glance and far cheaper to render than real refraction.

Mixed geometry types avoid a repetitive look

Rather than cloning one gem shape 18 times, the snippet cycles through three different geometry generators — an octahedron, a cone, and an icosahedron — so consecutive gems in the cluster are never identical shapes. Combined with per-gem random scale and rotation, this mixed-geometry approach is what keeps a cluster of 18 objects from reading as one shape copy-pasted repeatedly.

Random placement inside a bounded volume, not a formula

Unlike the precisely parametric DNA helix or solar system snippets, crystal formations in nature don't follow a clean mathematical curve — they cluster unevenly. Each gem gets a uniformly random position within a fixed-size bounding volume (flattened slightly on the Y axis so the cluster reads as a mound rather than a sphere), a fully random static rotation, and a random scale between roughly a third and four-fifths of the base geometry size. This intentional randomness, rather than any formula, is what makes the group look like a genuine mineral formation instead of an arranged, artificial pattern.

Independent drift keeps a static-looking cluster alive

Beyond the random initial placement, every gem also has its own tiny, independent vertical drift — a sine wave with a random phase offset and a barely-perceptible amplitude — plus its own slow, independent spin speed (some clockwise, some counter-clockwise, since the speed is randomized around zero). No two gems move identically, which reads as a subtly living formation rather than the initial arrangement simply sitting frozen in place.

An orbiting colored light, not a fixed one

The main point light slowly circles the cluster on a fixed radius using sine and cosine of the shared animation clock. Because every gem's clearcoat highlight depends on the angle between the light and the viewer, a moving light source constantly shifts which facets catch a bright highlight from moment to moment — exactly the detail that makes a static gem cluster look genuinely alive rather than like a single frozen render.

Where this technique applies

The clearcoat-plus-mixed-geometry-plus-random-placement pattern generalizes to any "cluster of similar but distinct objects" scene — gem piles, ice formations, abstract geometric sculptures, or loot/reward visuals in games. Pair this snippet with a morphing blob for a contrast between faceted, hard-edged crystal and smooth, organic form.

Step by step

How to Use

  1. 1
    Load both CDN scriptsAdd three.min.js and OrbitControls.js from the CDN panel, in that order.
  2. 2
    Paste HTML, CSS, and JS18 glassy gems appear scattered together, slowly drifting and spinning.
  3. 3
    Drag to inspectRotate the camera to see the clearcoat highlights shift across different facets.
  4. 4
    Watch the orbiting lightThe main point light circles the cluster, continuously changing which gems catch a bright highlight.
  5. 5
    Adjust gem count and spreadChange CRYSTAL_COUNT and the spread constant for a denser, sparser, tighter, or wider cluster.
  6. 6
    Retint the gemsEdit the COLORS array for a different palette across the cluster.

Real-world uses

Common Use Cases

💎
Fantasy and gaming sites
Show a glowing crystal formation as a hero object, with 18 gems of mixed octahedron, cone and icosahedron geometry avoiding repetition.
💍
Jewellery and gem previews
Start a gemstone product preview, with MeshPhysicalMaterial clearcoat producing a convincing glassy look without costly refraction.
📚
Clearcoat material teaching
Give learners a focused, minimal demonstration of physically based glass approximation with an orbiting coloured point light.
🎨
Portfolio showpieces
Show a visually striking 3D scene, where unique phase-offset bobbing means no two gems move in sync.
🏆
Reward and loot screens
Use a glowing gem cluster for achievement or loot reveals, and a slowly drifting wellness scene when calm visuals are needed.

Got questions?

Frequently Asked Questions

The material uses MeshPhysicalMaterial's clearcoat property, which adds a thin, extra-reflective surface layer on top of the base material — similar to a clear lacquer coat over paint. Combined with low roughness, partial transparency, and a touch of emissive glow, this produces a shiny, glassy read that is much cheaper to render than true physically-based refraction.

Cycling through an octahedron, a cone, and an icosahedron across the 18 gems, combined with random per-gem scale and rotation, prevents the cluster from reading as one shape simply copy-pasted repeatedly. Mixed geometry is what makes the group look like a genuine, varied mineral formation.

Unlike structures with an inherent mathematical shape (a helix, a spiral galaxy, orbiting planets), a crystal formation in nature clusters unevenly with no clean underlying curve. Each gem gets a uniformly random position within a bounded, flattened volume, which is what makes the result look like an organic mineral cluster rather than an arranged, formulaic pattern.

Every gem is given its own random phase offset for its vertical bobbing sine wave and its own random spin speed (which can be positive or negative). Because no two gems share the exact same motion, the cluster reads as a collection of independently-alive objects rather than a single rigid group animating as one block.

A clearcoat highlight's brightness and position on a surface depend heavily on the angle between the light source and the camera. A light that continuously circles the cluster keeps shifting which facets catch a bright highlight moment to moment, which is what prevents the gems from looking like a single static, frozen render.

Yes. Click JSX for a React component, Vue for a Vue 3 SFC, Angular for a standalone component, or Tailwind for a React + Tailwind CSS utility-class version. Build the cluster group inside a mount effect so the random placement only runs once per mount, and call controls.dispose() plus renderer.dispose() on cleanup.