3D Dot Objects
A three-dimensional shape built entirely from glowing dots that slowly rotates and gently follows your cursor. Choose from forms like a sphere, cube, torus or helix, with colors shifting from front to back as it turns. The effect automatically respects the “reduce motion” accessibility setting, showing a static image instead of animating for visitors who prefer it.
Maintenance Mode Left On for Six Months
Designer Spends Three Days on Hover State
Loading Spinner Promoted to Art
Instructions
Setup options
selector — Either a CSS selector string (e.g. '#my-canvas') or a direct DOM element reference pointing to an existing <canvas>. The renderer draws into that canvas instead of creating its own. If the element doesn't exist or isn't a canvas, the function warns and returns null. (The '.bde-rich-text-2800-141' in your snippet is a placeholder that some templating tool is meant to replace with a real selector.)
Geometry options
shape3d — The overall 3D form of the dot cloud. Built-in shapes are 'cube' (default, dots on all 6 faces), 'sphere' (evenly distributed via a Fibonacci spiral), 'octahedron', 'tetrahedron', 'torus', 'cylinder' (with dots on both caps), and 'helix' (a double helix — two intertwined strands). Any unrecognized value falls back to the cube. Changing this triggers a full geometry rebuild.
dotsPerFace — Dot density. For the cube it's literally the grid resolution per face (n×n dots × 6 faces). For other shapes it scales the point count proportionally (e.g. the sphere uses roughly 4n² points). Minimum is 1. More dots = richer look but more GPU work.
size — The physical size of the shape in world units. For a cube it's the edge length; for the sphere it acts as the diameter; for the torus and cylinder it scales their radii and height. Changing it rebuilds the geometry.
dotSize — The base size of each individual dot in pixels. It gets multiplied by the device pixel ratio, scaled by the camera projection, and attenuated with depth, so dots farther away render smaller automatically.
shape — The 2D silhouette of each dot, rendered with signed-distance-field math in the fragment shader. Options: 'circle' (default), 'square', 'triangle', 'star' (five-pointed), 'diamond', 'hexagon', and 'ring' (a circle with a hollow center). This is just a uniform swap, so it's cheap to change at runtime.
Position and motion options
posX / posY — Horizontal and vertical offsets of the whole object from the screen center, in world units. In your example, posY: -3 nudges the sphere downward to make room visually.
speedX / speedY / speedZ — Continuous rotation speed around each axis, in radians per second. They accumulate every frame, so speedY: 0.45 spins the object about half a radian per second around the vertical axis. Set any of them to 0 to freeze rotation on that axis.
pulse — Amplitude of the "breathing" effect. Each dot oscillates along its surface normal with a random phase and frequency, displaced by up to this many world units. 0 (the default) disables it entirely.
pulseSpeed — How fast the pulse wave oscillates. Higher values make the rippling quicker. Because each dot also has its own random frequency multiplier, dots don't move in perfect unison.
Camera and depth options
distance — How far the camera sits from the object along the Z axis. Larger values make the object appear smaller and also subtly shrink the dots via the depth-based size attenuation in the shader.
fov — Camera field of view in degrees (default 45). Wider values add more perspective distortion. Notably, the shader compensates for FOV changes so dot sizes stay visually consistent.
fogNear / fogFar — The depth range over which dots fade to transparent. Dots closer than fogNear are fully visible; by fogFar they've faded out completely. In your example (camera at 5, fog from 5.5 to 8.5), the back half of the sphere dissolves into darkness, which sells the depth. fogFar is automatically clamped to be at least slightly beyond fogNear.
Color options
colorA — The color of dots whose normals face the camera — effectively the "front" or "near-side" color. Your example uses pure white here.
colorB — The color of dots facing away from the camera — the "back" or "far-side" color. The shader blends between the two based on how each dot's normal points relative to the viewer, producing the white-to-deep-blue gradient effect across the sphere's surface.
Background options
backgroundColor — A flat solid color composited behind the dots in the final render pass (explicitly not a gradient, per the shader comment).
backgroundOpacity — The alpha of that background fill, from 0 to 1. At 0 the canvas stays fully transparent, so the shape floats over whatever is behind it on the page — useful for embedding over existing content.
Post-processing options
bloom — Glow intensity. When greater than 0, the pipeline renders the scene offscreen, extracts bright pixels above a luminance threshold, blurs them with several Gaussian passes at half resolution, and adds them back scaled by this value. Higher numbers mean stronger halos — with bloom: 5 and white dots, you get the intense neon glow in your example. Setting it to 0 skips the entire bloom chain, saving GPU time.
chromatic — Chromatic aberration strength. The final composite samples the image three times with a slight radial offset and recombines only the red, green, and blue channels, creating subtle red/blue color fringing toward the edges of the frame. Something like 0.013 is a gentle lens-like effect.
grain — Film grain amount. Adds per-pixel random noise (time-varying, so it shimmers like real grain), scaled by the pixel's alpha so it only appears where there's actual content or background. 0 disables it.
Interaction option
interactive — Enables pointer parallax. The mouse position relative to the canvas tilts the object on top of its auto-rotation (up to roughly ±0.42 radians on X and ±0.55 radians on Y), with smooth easing so it feels weighty. When the cursor leaves the canvas, the tilt eases back to neutral. This is automatically disabled when the visitor has "prefers-reduced-motion" enabled — in that case the whole animation loop is skipped and only a single static frame is rendered.
Two extra notes
The returned object also has an update(next) method that accepts any subset of these same options at runtime — changing shape3d, size, or dotsPerFace rebuilds the geometry, everything else is applied cheaply. And destroy() tears everything down (event listeners, render targets, GPU resources) if you need to remove the effect.