| name | webgl-3d-object |
| description | Create a real 3D WebGL object with geometric mesh depth, physically based material, directional and ambient lighting, perspective camera, subtle rotation, and floating motion. Use when a page needs a faceted 3D hero object or product-like visual with real lighting instead of CSS transform tricks. |
WebGL 3D Object
Use When
- A hero, feature block, or product moment needs one strong 3D object.
- The visual should show real geometry, lighting, highlights, and edges.
- A faceted mesh should float or rotate subtly inside a web layout.
- CSS transforms, SVG illusions, or flat gradients are not enough.
Rules
- Use real 3D geometry:
IcosahedronGeometry, DodecahedronGeometry, BoxGeometry, custom BufferGeometry, or a glTF mesh.
- Use a perspective camera so the object has depth and scale.
- Use PBR material:
MeshStandardMaterial or MeshPhysicalMaterial.
- Tune
metalness, roughness, and emissive to match the brand mood.
- Light the object with at least one directional light plus ambient or hemisphere fill.
- Animate transforms only: subtle rotation, bobbing, or parallax.
- Handle resize and dispose geometry/material/renderer on teardown.
HTML And CSS
<div class="webgl-object-shell">
<canvas class="webgl-object-canvas" data-webgl-3d-object></canvas>
</div>
.webgl-object-shell {
position: relative;
width: min(100%, 720px);
aspect-ratio: 1 / 1;
}
.webgl-object-canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
display: block;
}
Three.js Object Recipe
import * as THREE from "three";
function initWebGL3DObject(canvas, options = {}) {
if (!canvas) return () => {};
const renderer = new THREE.WebGLRenderer({
canvas,
antialias: true,
alpha: true,
});
renderer.setClearColor(0x000000, 0);
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, options.maxDpr || 1.75));
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = options.exposure || 1.05;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
const scene = new THREE.Scene();
camera = .(, , , );
camera..(, , );
geometry = .(options. || , options. || );
material = .({
: options. || ,
: options. ?? ,
: options. ?? ,
: options. || ,
: options. ?? ,
: ,
});
object = .(geometry, material);
object. = ;
object. = ;
scene.(object);
ambient = .(, );
scene.(ambient);
key = .(, );
key..(, , );
key. = ;
key...(, );
scene.(key);
rim = .(options. || , );
rim..(-, , -);
scene.(rim);
shadowPlane = .(
.(, ),
.({ : })
);
shadowPlane..(, -, );
shadowPlane.. = -. / ;
shadowPlane. = ;
scene.(shadowPlane);
reduceMotion = .().;
rafId = ;
() {
width = .(, canvas.);
height = .(, canvas.);
renderer.(.(. || , options. || ));
renderer.(width, height, );
camera. = width / height;
camera.();
}
() {
t = time * ;
object.. = - + .(t * ) * ;
object.. = t * ;
object.. = .(t * ) * ;
object.. = reduceMotion ? : .(t * ) * ;
renderer.(scene, camera);
(!reduceMotion) rafId = (render);
}
() {
(rafId);
();
();
}
();
();
.(, handleResize);
{
(rafId);
.(, handleResize);
geometry.();
material.();
shadowPlane..();
shadowPlane..();
renderer.();
};
}
cleanupObject = (
.(),
{
: ,
: ,
: ,
: ,
: ,
}
);
Material Defaults
- Premium metal:
metalness: 0.45-0.7, roughness: 0.25-0.45.
- Soft ceramic:
metalness: 0.0-0.15, roughness: 0.38-0.62.
- Glow-tinted tech object: low
emissive with emissiveIntensity: 0.12-0.35.
- Faceted object: set
flatShading: true; smooth product object: set it to false.
Lighting Defaults
- Key light: directional, high front-side angle, strongest source.
- Ambient fill: low intensity so shadows stay visible.
- Rim light: brand-tinted or cool light from behind to reveal edges.
- Shadows: enable only when the object needs grounded depth; keep map size moderate.
Motion Defaults
- Rotation: slow, continuous, and secondary to the page content.
- Floating:
0.04 to 0.12 units on Y.
- Reduced motion: render a still frame or only allow direct interaction.
- Avoid camera movement unless the object is the main interaction.
Avoid
- CSS 3D transforms pretending to be WebGL.
- Unlit materials when the ask is real lighting and depth.
- Flat planes with gradients instead of actual geometry.
- Strong bloom or particles that hide the form.
- High DPR, huge shadow maps, or too many lights on mobile.
- Letting the object compete with foreground copy or CTAs.
Quick Checks
- The object has visible form, edges, highlights, and shadows.
- The material uses
metalness, roughness, and optional emissive.
- Directional and ambient lights are both present.
- The camera is perspective, not orthographic by accident.
- Resize does not stretch the object.
- Geometry, material, event listeners, RAF, and renderer are cleaned up.