Three.js Morphing Blob — WebGL Organic Vertex-Noise Sphere

Three.js Morphing Blob · Animations · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Icosahedron base geometry: even triangle distribution avoids polar distortion under displacement
Original-position displacement: every frame deforms from a saved snapshot, preventing drift or ballooning
Hand-rolled noise function: organic, non-repeating wobble with zero external noise library
Per-frame normal recomputation: computeVertexNormals keeps lighting physically correct as the shape changes
Two orbiting point lights: a moving key and rim light sell a glassy, liquid material feel
Independent rotation and tilt: slow Y-axis spin plus a sine-driven X tilt on top of the noise wobble
MeshStandardMaterial with emissive glow: metalness and roughness controls for easy re-theming
Loaded entirely from a CDN: no npm install, bundler, or build step required

About this UI Snippet

How to Build a Morphing Blob With Three.js Vertex Displacement

Screenshot of the Three.js Morphing Blob snippet rendered live

The Three.js Morphing Blob snippet takes a plain sphere and turns it into a continuously breathing, organic form — the kind of effect you see on modern SaaS landing pages — using nothing but a high-subdivision icosahedron, a hand-rolled noise function, and per-vertex displacement recomputed every frame in plain WebGL through Three.js loaded from a CDN.

Why an icosahedron instead of a UV sphere

The base shape is a THREE.IcosahedronGeometry with a subdivision level of 6, which produces thousands of near-evenly-distributed triangles across the surface. A standard SphereGeometry clusters vertices tightly near its poles and stretches them near the equator, which makes any per-vertex displacement look uneven — bulging oddly at the top and bottom. An icosahedron's uniform triangle distribution means the same noise formula produces consistent, evenly-sized bumps everywhere on the surface.

Displacing from a saved original, never from the last frame

The single most important detail in this snippet: the geometry's original vertex positions are copied into a plain array once, at startup, before any animation runs. Every frame, each vertex is recomputed as original position × (1 + noise) — always starting from that saved original, never from wherever the vertex ended up on the previous frame. Get this wrong (displacing cumulatively frame over frame) and the blob will drift, balloon, or collapse within seconds; displacing from a fixed original is what keeps the wobble stable and reversible indefinitely.

A hand-rolled noise function, no library required

Rather than pulling in a Simplex or Perlin noise library, the snippet uses a compact function that multiplies three sine and cosine terms together, each on a different axis, frequency, and phase offset tied to a slowly incrementing time value. It isn't mathematically "true" gradient noise, but it produces a smooth, non-repeating, organic-looking ripple across the surface for zero extra dependencies — proof that convincing procedural motion doesn't always need a proper noise library.

Recomputing normals is what makes the lighting work

After displacing vertices, the snippet calls geometry.computeVertexNormals() every single frame. Skip this step and the surface will still visually deform, but the lighting will look completely wrong — flat, faceted, or oddly shaded — because the MeshStandardMaterial shades each triangle based on its normal vector, and that normal has to be recalculated any time the underlying geometry actually changes shape.

Orbiting point lights sell the "liquid" feel

Two point lights — a violet key light and a cooler cyan rim light — orbit the blob independently of its rotation, one of them tracing a circle over time via simple sine/cosine positioning. Because the surface is constantly shifting, a moving light source catches different facets from moment to moment, which is what makes the material read as glassy or liquid rather than a static plastic sphere with a texture animation layered on top.

Slow rotation and tilt, not just displacement

On top of the noise wobble, the mesh itself slowly rotates on its Y axis and gently tilts back and forth on X using another sine term. Combined with the orbiting lights, this small addition means no two frames ever look quite identical, even though the underlying noise pattern technically does eventually repeat.

Where this technique goes next

The same original-position-plus-noise pattern that drives this blob is the foundation for cloth simulation previews, terrain generation, and audio-reactive visualizers — anywhere a mesh needs to deform smoothly without an actual physics engine. Pair it with a morphing SVG icon set for a coordinated "everything breathes" visual language, or contrast it against the rigid, faceted look of a 3D cube.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not have to reverse-engineer the displacement math by staring at the noise function alone. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why displacement is computed from a saved original array rather than the previous frame's positions, or why computeVertexNormals has to run every single frame instead of once at startup. The same assistant can help optimize it, for instance checking whether the per-vertex loop could be moved into a custom vertex shader for a large performance win on lower-end devices, or whether normal recomputation could be skipped on frames where the noise amplitude is near zero. It is also useful for extending the effect: ask it to swap the hand-rolled noise for a proper Simplex noise implementation, drive the amplitude from mouse proximity so the blob reacts to the cursor, or add a second, faster-oscillating noise layer for finer surface detail. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "morphing blob" effect in plain HTML, CSS, and JavaScript using Three.js loaded from a CDN (no bundler, no build step) — an organic, continuously deforming sphere rendered in WebGL.

Requirements:
- A full-viewport canvas with a WebGLRenderer sized to match it, updated on window resize including camera aspect ratio.
- Use an IcosahedronGeometry with a high subdivision level (not a standard SphereGeometry) as the base shape, so vertices are distributed evenly across the surface rather than clustering at poles.
- Apply a MeshStandardMaterial with a visible emissive glow, and light the scene with at least two point lights of different colors so the surface reads as glassy or liquid rather than flat plastic.
- Immediately after creating the geometry, copy its original vertex position array into a separate saved array before any animation begins.
- Write a small hand-rolled noise function (no external noise library) that combines sine and cosine terms on different axes, frequencies, and a shared, continuously incrementing time value, returning a smooth pseudo-random value for any 3D input.
- Every animation frame, for every vertex, compute the new position as the saved original position scaled by (1 plus noise times an amplitude constant) — never compute displacement from the vertex's position on the previous frame, to avoid drift or runaway growth.
- After updating all vertex positions and flagging the position attribute as needing an update, call the geometry's method to recompute vertex normals every frame, so lighting continues to look physically correct as the shape deforms.
- Slowly rotate the mesh independently of the noise animation, and move at least one of the point lights in a circular or orbiting path over time using sine and cosine of the same time value.
- Expose the noise amplitude and frequency as named constants near the top of the script so they're easy to retune.

Step by step

How to Use

  1. 1
    Load the Three.js CDNAdd three.min.js from the CDN panel — no other libraries are needed.
  2. 2
    Paste HTML, CSS, and JSThe blob fills the viewport and starts animating immediately on load.
  3. 3
    Watch it breatheThe surface ripples continuously from the noise-driven vertex displacement.
  4. 4
    Tune the wobbleAdjust AMPLITUDE for a subtler or more extreme surface, and FREQ for tighter or broader bumps.
  5. 5
    Change the materialSwap color, metalness, and roughness on the MeshStandardMaterial for glass, matte, or metallic looks.
  6. 6
    Resize the windowRenderer size and camera aspect ratio update automatically.

Real-world uses

Common Use Cases

SaaS and startup hero sections
A morphing blob behind a headline is a common, modern signal of an AI or creative-tech product; pair with a gradient text title.
Brand and portfolio backgrounds
The organic, ever-shifting surface reads as more premium and alive than a static gradient blob image.
Teaching vertex displacement
A focused, minimal example of BufferGeometry mutation, normal recomputation, and material lighting in Three.js.
Loading and splash screens
A gently breathing blob gives a loading screen visual interest without any text or progress indicator required.
Boss or entity idle animation
The same original-plus-noise technique works as a base for game-adjacent creature or orb idle states.
AI and voice-assistant orbs
Combine with a voice assistant orb pattern for a 3D, WebGL-rendered variant.

Got questions?

Frequently Asked Questions

A SphereGeometry clusters vertices densely near its poles and spaces them widely near the equator, so any per-vertex displacement looks uneven across the surface. An icosahedron with a high subdivision level distributes triangles almost evenly everywhere, so the same noise formula produces consistent-looking bumps across the whole shape.

Displacing directly from the previous frame's already-displaced positions accumulates error — the blob would drift, balloon outward, or collapse inward within seconds. Storing the original geometry once and always computing displaced position = original × (1 + noise) guarantees the shape stays stable and bounded indefinitely, no matter how long the animation runs.

No — it is a compact hand-rolled function that multiplies sine and cosine terms on different axes and frequencies. It is not mathematically equivalent to gradient noise, but it produces a smooth, organic, non-repeating wobble that looks convincing, without pulling in an external noise library.

MeshStandardMaterial shades each triangle based on its normal vector, which describes which way that triangle faces. Once vertex positions change, the old normals no longer match the new shape, so the lighting looks flat or wrong unless the normals are recalculated every frame the geometry actually deforms.

Yes. Lower the AMPLITUDE constant for a barely-perceptible ripple, or raise it for an aggressive, spiky wobble. Adjusting FREQ alongside it controls whether the bumps are broad and smooth or tight and numerous.

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. Set up the renderer, geometry, and original-position snapshot inside a mount effect (useEffect, onMounted, ngAfterViewInit), and call renderer.dispose() plus cancelAnimationFrame on cleanup so the WebGL context and animation loop don't leak when the component unmounts.