A liquid bridge appears before two circles touch. Each drop contributes to the same invisible field. Add those contributions, choose a boundary, and the space between them becomes part of the object.
Then light that boundary, add a small expression and let the parts move together. This experiment uses a two-dimensional metaball field rendered with WebGL. The glossy depth is a height-based shading treatment, rather than a fluid simulation. No setup is needed to explore; basic JavaScript and shader knowledge help when editing the starter.
01 / GIVE EVERY DROP A PATH
Start with six simple circles.
Use one large centre and five small drops. Each drop needs only a position and a radius. A shared phase moves the small drops around the centre while their distance grows and shrinks. At the end of a full cycle, the positions and sizes meet the beginning again.
Try: choose Drops. Set Loop position near 0%, then 50%, then 100%. Raise Drop travel to make the separation easier to see. The endpoints are the same configuration.
02 / MAKE THE BRIDGE
Add influence. Choose a boundary.
At every pixel, measure the distance to each centre. A drop contributes strongly nearby and weakly far away. Adding the contributions gives a shared field. Fill pixels whose field reaches a threshold: this is the liquid silhouette.
field = Σ radius² / (distance² + ε) inside = field ≥ threshold
The tiny ε keeps the centre finite. A lower threshold makes the drops larger and connects them sooner. Our Merge slider lowers the threshold; it does not add a physical attraction. A narrow smooth transition around the boundary softens pixel edges.
Try: choose Merge, pause at 20–25%, and move Merge from zero to 100%. Watch the neck widen while the centres stay fixed.
03 / FIND THE SURFACE
Turn a field into a little volume.
A flat silhouette can become a glossy object without building a mesh. Make a shallow height from the field: zero at the boundary and higher inside. Sample neighbouring heights to estimate its slope. The surface normal points away from that slope.
Diffuse light describes the roundness. A concentrated specular term adds the bright highlight. Soft coloured bands suggest a reflected environment, and the edge receives a quiet violet tint. All of these use the same normal, so the highlight bends with a stretching bridge.
Try: choose Light. Compare Surface sheen at zero and 100%. Move the loop into a stretched moment and notice how the bands follow the changing shape.
04 / LET THE WORLD RESPOND
A face. A few rings. One clock.
The orbiting white lights and small smile are simple signed-distance shapes layered over the central orb. Expression can change with the same phase as the drops. It stays readable because its size is small and its position belongs to the centre.
Three rings expand from the orb. Each has a different phase offset and fades at the start and end of its life. A tiny offset between red, green and blue channels creates a spectral edge; fine angular variations give the rings a quiet shimmer.
ring age = fract(phase × 2 + offset) radius = start + age × travel brightness = sin(age × π)
Try: choose World. Turn the rings off, then bring them back. Compare No face, Small smile and Orbiting lights. Keep only the layers that help your version.
05 / PLAN IT IN FIGMA
Use frames to test the rhythm.
Make a black 600 × 600 frame. Add a roughly 180-pixel centre orb, five 40–55-pixel drops, a small white face and three thin ring layers. Give the circles blue fills; use soft cyan and violet gradients for the centre’s highlights. Name the layers clearly: Orb, Drop 1–5, Face and Ring 1–3.
Duplicate the frame into Gathered, Leaving, Spread and Returning. Move and scale the existing drops; preserve their names and hierarchy. Connect the frames with After delay and Smart Animate. Start with a brief 150 ms hold and 800 ms transitions, then adjust the timing in the prototype. The final transition returns to Gathered.
Smart Animate can interpolate supported properties such as position, scale and opacity. It does not calculate a metaball field or continuously reshape a vector path. For a designed prototype, keep bridge artwork on separate layers and fade it between the states. For the continuously joining contour and responsive shading in this lesson, use the working shader starter.
Try: pause three distinct moments here and save frames as a visual timing board. Let those snapshots guide the gathered, stretched and separated states of your prototype.
06 / MAKE IT YOURS
Pause at a moment worth keeping.
Scrubbing pauses the animation. Drag the central orb to place the entire world, or use the arrow keys. Home centres it; Space pauses or resumes. A reduced-motion preference starts paused. The renderer also stops while the scene is offscreen or the tab is hidden.
Choose a colour, expression and amount of sheen. Save this frame prepares a 1600 × 1200 PNG containing the current build stage, pose and background. It uses the same renderer as the live scene, so the exported shape and lighting agree.
Try: make a calm mint version with a small smile and no rings. Then make an energetic violet version with wider travel and spectral rings. Which change has the greatest effect on its character?
YOUR TURN / MAKE A STRETCH FEEL RIGHT
Find the moment before it separates.
Pause between 15% and 30%. Adjust Drop travel and Merge until one small drop is connected by a narrow neck. Change the sheen and see how the light describes that bridge.
Now advance the phase just enough for it to break away. Save both frames. The small difference between those moments is where the liquid feeling lives.
The working starter contains the complete field shader, orbit model, controls and styles in one HTML file. Open it in a browser, then edit its embedded JavaScript in a text editor. WebGL is required for the live scene; no server, package installation or remote assets are needed.
// Each drop contributes to one shared field.
float field(vec2 p) {
float value = 0.0;
for (int i = 0; i < 6; i++) {
vec2 d = p - bodies[i].xy;
value += bodies[i].z * bodies[i].z / (dot(d, d) + 0.00008);
}
return value;
}
// Threshold chooses the silhouette; height gives it light.