New to Claude Skills? Learn how to install them →

mengto on GitHub

WebGL 3D Object

Free

Create stunning 3D visuals with real geometry and lighting.

by mengto4.6k stars on mengto/skills
2 views
Updated Aug 9, 2026
Get this skill

Free · Opens the source repo

What WebGL 3D Object does

The WebGL 3D Object skill allows developers to integrate a realistic 3D object into their web applications using Three.js. This skill is particularly useful when a web page requires a striking visual element, such as a hero object or product showcase, that goes beyond simple CSS effects. By leveraging real 3D geometry, physically based materials, and dynamic lighting, this skill enhances the visual appeal of a page, making it more engaging for users.

To use this skill, developers can create various geometric shapes like icosahedrons or dodecahedrons, and customize their appearance with parameters such as color, metalness, and roughness. The skill emphasizes the importance of using a perspective camera to provide depth, and it supports subtle animations like rotation and floating motion to bring the 3D object to life. This is ideal for scenarios where a flat or CSS-based representation would fall short, providing a more immersive experience.

The skill also includes guidelines for lighting, ensuring that the 3D object is well-lit with directional and ambient lights, enhancing the realism of the scene. By following the provided rules and best practices, developers can create visually compelling 3D elements that are not only aesthetically pleasing but also optimized for performance, making them suitable for a variety of web contexts.

When to use it

Use this skill when you need a prominent 3D object on a webpage that showcases real depth and lighting effects.

When not to use it

This skill may not be suitable for applications that do not require 3D visuals or where performance is a critical concern, especially on mobile devices.

What you can build with it

Product Showcase

Integrate a 3D model of a product on an e-commerce site to enhance user engagement and provide a better visual representation.

Interactive Hero Section

Use a floating 3D object in the hero section of a landing page to capture attention and highlight key features.

Visual Data Representation

Create a 3D representation of complex data or concepts in educational or informational websites to improve understanding.

How to install WebGL 3D Object

View source

1. Install with the skills CLI

npx skills add mengto/skills/webgl-3d-object --agent claude-code

2. Or install it manually

Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.

Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs

Inside SKILL.md

Written by mengto

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

  1. Use real 3D geometry: IcosahedronGeometry, DodecahedronGeometry, BoxGeometry, custom BufferGeometry, or a glTF mesh.
  2. Use a perspective camera so the object has depth and scale.
  3. Use PBR material: MeshStandardMaterial or MeshPhysicalMaterial.
  4. Tune metalness, roughness, and emissive to match the brand mood.
  5. Light the object with at least one directional light plus ambient or hemisphere fill.
  6. Animate transforms only: subtle rotation, bobbing, or parallax.
  7. 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();
  const camera = new THREE.PerspectiveCamera(38, 1, 0.1, 100);
  camera.position.set(0, 0.15, 5.2);

  const geometry = new THREE.IcosahedronGeometry(options.radius || 1.35, options.detail || 1);
  const material = new THREE.MeshStandardMaterial({
    color: options.color || 0x8aa4ff,
    metalness: options.metalness ?? 0.48,
    roughness: options.roughness ?? 0.34,
    emissive: options.emissive || 0x101833,
    emissiveIntensity: options.emissiveIntensity ?? 0.22,
    flatShading: true,
  });

  const object = new THREE.Mesh(geometry, material);
  object.castShadow = true;
  object.receiveShadow = true;
  scene.add(object);

  const ambient = new THREE.AmbientLight(0xffffff, 0.38);
  scene.add(ambient);

  const key = new THREE.DirectionalLight(0xffffff, 2.15);
  key.position.set(3.4, 4.2, 4.8);
  key.castShadow = true;
  key.shadow.mapSize.set(1024, 1024);
  scene.add(key);

  const rim = new THREE.DirectionalLight(options.rimColor || 0x7dd3fc, 0.82);
  rim.position.set(-4.2, 1.2, -2.8);
  scene.add(rim);

  const shadowPlane = new THREE.Mesh(
    new THREE.PlaneGeometry(5.2, 5.2),
    new THREE.ShadowMaterial({ opacity: 0.18 })
  );
  shadowPlane.position.set(0, -1.65, 0);
  shadowPlane.rotation.x = -Math.PI / 2;
  shadowPlane.receiveShadow = true;
  scene.add(shadowPlane);

  const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  let rafId = 0;

  function resize() {
    const width = Math.max(1, canvas.clientWidth);
    const height = Math.max(1, canvas.clientHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, options.maxDpr || 1.75));
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }

  function render(time = 0) {
    const t = time * 0.001;
    object.rotation.x = -0.16 + Math.sin(t * 0.45) * 0.06;
    object.rotation.y = t * 0.28;
    object.rotation.z = Math.sin(t * 0.32) * 0.08;
    object.position.y = reduceMotion ? 0 : Math.sin(t * 0.8) * 0.08;

    renderer.render(scene, camera);
    if (!reduceMotion) rafId = requestAnimationFrame(render);
  }

  function handleResize() {
    cancelAnimationFrame(rafId);
    resize();
    render();
  }

  resize();
  render();
  window.addEventListener("resize", handleResize);

  return () => {
    cancelAnimationFrame(rafId);
    window.removeEventListener("resize", handleResize);
    geometry.dispose();
    material.dispose();
    shadowPlane.geometry.dispose();
    shadowPlane.material.dispose();
    renderer.dispose();
  };
}

const cleanupObject = initWebGL3DObject(
  document.querySelector("[data-webgl-3d-object]"),
  {
    color: 0x8aa4ff,
    rimColor: 0x7dd3fc,
    metalness: 0.48,
    roughness: 0.34,
    emissive: 0x101833,
  }
);

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.

Frequently asked questions about WebGL 3D Object

Similar skills