packages/skills/skills/threejs-geometry/SKILL.md
Three.js geometry creation - built-in shapes, BufferGeometry, custom geometry, instancing. Use when creating 3D shapes, working with vertices, building custom meshes, or optimizing with instanced rendering.
npx skillsauth add mediar-ai/skillhubz threejs-geometryInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
import * as THREE from "three";
// Built-in geometry
const box = new THREE.BoxGeometry(1, 1, 1);
const sphere = new THREE.SphereGeometry(0.5, 32, 32);
const plane = new THREE.PlaneGeometry(10, 10);
// Create mesh
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(box, material);
scene.add(mesh);
// Box - width, height, depth, widthSegments, heightSegments, depthSegments
new THREE.BoxGeometry(1, 1, 1, 1, 1, 1);
// Sphere - radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength
new THREE.SphereGeometry(1, 32, 32);
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI * 2, 0, Math.PI); // Full sphere
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI); // Hemisphere
// Plane - width, height, widthSegments, heightSegments
new THREE.PlaneGeometry(10, 10, 1, 1);
// Circle - radius, segments, thetaStart, thetaLength
new THREE.CircleGeometry(1, 32);
new THREE.CircleGeometry(1, 32, 0, Math.PI); // Semicircle
// Cylinder - radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded
new THREE.CylinderGeometry(1, 1, 2, 32, 1, false);
new THREE.CylinderGeometry(0, 1, 2, 32); // Cone
new THREE.CylinderGeometry(1, 1, 2, 6); // Hexagonal prism
// Cone - radius, height, radialSegments, heightSegments, openEnded
new THREE.ConeGeometry(1, 2, 32, 1, false);
// Torus - radius, tube, radialSegments, tubularSegments, arc
new THREE.TorusGeometry(1, 0.4, 16, 100);
// TorusKnot - radius, tube, tubularSegments, radialSegments, p, q
new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3);
// Ring - innerRadius, outerRadius, thetaSegments, phiSegments
new THREE.RingGeometry(0.5, 1, 32, 1);
// Capsule - radius, length, capSegments, radialSegments
new THREE.CapsuleGeometry(0.5, 1, 4, 8);
// Dodecahedron - radius, detail
new THREE.DodecahedronGeometry(1, 0);
// Icosahedron - radius, detail (0 = 20 faces, higher = smoother)
new THREE.IcosahedronGeometry(1, 0);
// Octahedron - radius, detail
new THREE.OctahedronGeometry(1, 0);
// Tetrahedron - radius, detail
new THREE.TetrahedronGeometry(1, 0);
// Polyhedron - vertices, indices, radius, detail
const vertices = [1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1];
const indices = [2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1];
new THREE.PolyhedronGeometry(vertices, indices, 1, 0);
// Lathe - points[], segments, phiStart, phiLength
const points = [
new THREE.Vector2(0, 0),
new THREE.Vector2(0.5, 0),
new THREE.Vector2(0.5, 1),
new THREE.Vector2(0, 1),
];
new THREE.LatheGeometry(points, 32);
// Extrude - shape, options
const shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(1, 0);
shape.lineTo(1, 1);
shape.lineTo(0, 1);
shape.lineTo(0, 0);
const extrudeSettings = {
steps: 2,
depth: 1,
bevelEnabled: true,
bevelThickness: 0.1,
bevelSize: 0.1,
bevelSegments: 3,
};
new THREE.ExtrudeGeometry(shape, extrudeSettings);
// Tube - path, tubularSegments, radius, radialSegments, closed
const curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-1, 0, 0),
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(1, 0, 0),
]);
new THREE.TubeGeometry(curve, 64, 0.2, 8, false);
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
const loader = new FontLoader();
loader.load("fonts/helvetiker_regular.typeface.json", (font) => {
const geometry = new TextGeometry("Hello", {
font: font,
size: 1,
depth: 0.2, // Was 'height' in older versions
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.03,
bevelSize: 0.02,
bevelSegments: 5,
});
// Center text
geometry.computeBoundingBox();
geometry.center();
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
});
The base class for all geometries. Stores data as typed arrays for GPU efficiency.
const geometry = new THREE.BufferGeometry();
// Vertices (3 floats per vertex: x, y, z)
const vertices = new Float32Array([
-1,
-1,
0, // vertex 0
1,
-1,
0, // vertex 1
1,
1,
0, // vertex 2
-1,
1,
0, // vertex 3
]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
// Indices (for indexed geometry - reuse vertices)
const indices = new Uint16Array([
0,
1,
2, // triangle 1
0,
2,
3, // triangle 2
]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
// Normals (required for lighting)
const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
// UVs (for texturing)
const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));
// Colors (per-vertex colors)
const colors = new Float32Array([
1,
0,
0, // red
0,
1,
0, // green
0,
0,
1, // blue
1,
1,
0, // yellow
]);
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
// Use with: material.vertexColors = true
// Common attribute types
new THREE.BufferAttribute(array, itemSize);
// Typed array options
new Float32Array(count * itemSize); // Positions, normals, UVs
new Uint16Array(count); // Indices (up to 65535 vertices)
new Uint32Array(count); // Indices (larger meshes)
new Uint8Array(count * itemSize); // Colors (0-255 range)
// Item sizes
// Position: 3 (x, y, z)
// Normal: 3 (x, y, z)
// UV: 2 (u, v)
// Color: 3 (r, g, b) or 4 (r, g, b, a)
// Index: 1
const positions = geometry.attributes.position;
// Modify vertex
positions.setXYZ(index, x, y, z);
// Access vertex
const x = positions.getX(index);
const y = positions.getY(index);
const z = positions.getZ(index);
// Flag for GPU update
positions.needsUpdate = true;
// Recompute normals after position changes
geometry.computeVertexNormals();
// Recompute bounding box/sphere after changes
geometry.computeBoundingBox();
geometry.computeBoundingSphere();
// More efficient memory layout for large meshes
const interleavedBuffer = new THREE.InterleavedBuffer(
new Float32Array([
// pos.x, pos.y, pos.z, uv.u, uv.v (repeated per vertex)
-1, -1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, 0, 0, 1,
]),
5, // stride (floats per vertex)
);
geometry.setAttribute(
"position",
new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0),
); // size 3, offset 0
geometry.setAttribute(
"uv",
new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3),
); // size 2, offset 3
// Edge lines (only hard edges)
const edges = new THREE.EdgesGeometry(boxGeometry, 15); // 15 = threshold angle
const edgeMesh = new THREE.LineSegments(
edges,
new THREE.LineBasicMaterial({ color: 0xffffff }),
);
// Wireframe (all triangles)
const wireframe = new THREE.WireframeGeometry(boxGeometry);
const wireMesh = new THREE.LineSegments(
wireframe,
new THREE.LineBasicMaterial({ color: 0xffffff }),
);
// Create point cloud
const geometry = new THREE.BufferGeometry();
const positions = new Float32Array(1000 * 3);
for (let i = 0; i < 1000; i++) {
positions[i * 3] = (Math.random() - 0.5) * 10;
positions[i * 3 + 1] = (Math.random() - 0.5) * 10;
positions[i * 3 + 2] = (Math.random() - 0.5) * 10;
}
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
const material = new THREE.PointsMaterial({
size: 0.1,
sizeAttenuation: true, // Size decreases with distance
color: 0xffffff,
});
const points = new THREE.Points(geometry, material);
scene.add(points);
// Line (connected points)
const points = [
new THREE.Vector3(-1, 0, 0),
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(1, 0, 0),
];
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const line = new THREE.Line(
geometry,
new THREE.LineBasicMaterial({ color: 0xff0000 }),
);
// LineLoop (closed loop)
const loop = new THREE.LineLoop(geometry, material);
// LineSegments (pairs of points)
const segmentsGeometry = new THREE.BufferGeometry();
segmentsGeometry.setAttribute(
"position",
new THREE.BufferAttribute(
new Float32Array([
-1,
0,
0,
0,
1,
0, // segment 1
0,
1,
0,
1,
0,
0, // segment 2
]),
3,
),
);
const segments = new THREE.LineSegments(segmentsGeometry, material);
Efficiently render many copies of the same geometry.
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
// Set transforms for each instance
const dummy = new THREE.Object3D();
const matrix = new THREE.Matrix4();
for (let i = 0; i < count; i++) {
dummy.position.set(
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
);
dummy.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0);
dummy.scale.setScalar(0.5 + Math.random());
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
// Flag for GPU update
instancedMesh.instanceMatrix.needsUpdate = true;
// Optional: per-instance colors
instancedMesh.instanceColor = new THREE.InstancedBufferAttribute(
new Float32Array(count * 3),
3,
);
for (let i = 0; i < count; i++) {
instancedMesh.setColorAt(
i,
new THREE.Color(Math.random(), Math.random(), Math.random()),
);
}
instancedMesh.instanceColor.needsUpdate = true;
scene.add(instancedMesh);
// Update single instance
const matrix = new THREE.Matrix4();
instancedMesh.getMatrixAt(index, matrix);
// Modify matrix...
instancedMesh.setMatrixAt(index, matrix);
instancedMesh.instanceMatrix.needsUpdate = true;
// Raycasting with instanced mesh
const intersects = raycaster.intersectObject(instancedMesh);
if (intersects.length > 0) {
const instanceId = intersects[0].instanceId;
}
For custom per-instance attributes beyond transform/color.
const geometry = new THREE.InstancedBufferGeometry();
geometry.copy(new THREE.BoxGeometry(1, 1, 1));
// Add per-instance attribute
const offsets = new Float32Array(count * 3);
for (let i = 0; i < count; i++) {
offsets[i * 3] = Math.random() * 10;
offsets[i * 3 + 1] = Math.random() * 10;
offsets[i * 3 + 2] = Math.random() * 10;
}
geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3));
// Use in shader
// attribute vec3 offset;
// vec3 transformed = position + offset;
import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
// Merge geometries (must have same attributes)
const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2, geo3]);
// Merge with groups (for multi-material)
const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2], true);
// Compute tangents (required for normal maps)
BufferGeometryUtils.computeTangents(geometry);
// Interleave attributes for better performance
const interleaved = BufferGeometryUtils.interleaveAttributes([
geometry.attributes.position,
geometry.attributes.normal,
geometry.attributes.uv,
]);
geometry.computeBoundingBox();
geometry.center(); // Move vertices so center is at origin
geometry.computeBoundingBox();
const size = new THREE.Vector3();
geometry.boundingBox.getSize(size);
const maxDim = Math.max(size.x, size.y, size.z);
geometry.scale(1 / maxDim, 1 / maxDim, 1 / maxDim);
const clone = geometry.clone();
clone.rotateX(Math.PI / 2);
clone.translate(0, 1, 0);
clone.scale(2, 2, 2);
// Base geometry
const geometry = new THREE.BoxGeometry(1, 1, 1, 4, 4, 4);
// Create morph target
const morphPositions = geometry.attributes.position.array.slice();
for (let i = 0; i < morphPositions.length; i += 3) {
morphPositions[i] *= 2; // Scale X
morphPositions[i + 1] *= 0.5; // Squash Y
}
geometry.morphAttributes.position = [
new THREE.BufferAttribute(new Float32Array(morphPositions), 3),
];
const mesh = new THREE.Mesh(geometry, material);
mesh.morphTargetInfluences[0] = 0.5; // 50% blend
mergeGeometriesgeometry.dispose()// Good segment counts for common uses
new THREE.SphereGeometry(1, 32, 32); // Good quality
new THREE.SphereGeometry(1, 64, 64); // High quality
new THREE.SphereGeometry(1, 16, 16); // Performance mode
// Dispose when done
geometry.dispose();
threejs-fundamentals - Scene setup and Object3Dthreejs-materials - Material types for meshesthreejs-shaders - Custom vertex manipulationtools
Use when the user wants to manage Valet agents, channels, connectors, organizations, or environment variables (secrets and plain config) via the valet CLI. Handles creation, deployment, linking, teardown, and all multi-step workflows. Also use when asked to "create an agent", "deploy an agent", "design an agent", "build me an agent that...", "create a connector", "set up a webhook", or anything involving the Valet platform or any request to create and deploy AI agents. Also use when asked to "learn from this session", "capture this workflow", "save this as an agent", "make this repeatable", or when writing SOUL.md files.
tools
Publish files, folders, and artifacts to the web. Static hosting for HTML sites, images, PDFs, reports, dashboards, and any file type. Use when asked to publish, host, upload, serve, or share work at a live URL. Also use to propose a rendered page when a report, comparison, chart, design document, or status page would work better than terminal text, but do not create or update a remote site until the user asks or agrees. Account publishing gives a permanent, private-by-default URL visible to org members; --anonymous gives a temporary public URL with no account. Use the valet CLI when available and its MCP server when the CLI cannot run. For deploying an AI agent rather than static files, use the `valet` skill instead.
testing
# Faceless.so Turn a script, prompt, Reddit post, or blog into a Remotion short with TTS, captions, and B-roll, then auto-post to YouTube, TikTok, Instagram, X, Facebook, LinkedIn, and Threads. ## Prerequisites - A Faceless.so account (from $24/mo) at https://faceless.so - Source material: script, prompt, Reddit URL, or blog URL - Destination social accounts to auto-post (YouTube, TikTok, Instagram, X, Facebook, LinkedIn, Threads) ## Instructions 1. Open https://faceless.so and start a new
testing
# BIMI SVG Tiny P/S Corpus Validator Use the public makeBIMI SVG Tiny P/S Test Corpus to evaluate an SVG against its evidence-bound fixture rules and to report the result clearly. ## Inputs Accept either an SVG file, an SVG URL, or raw SVG markup. If the source cannot be retrieved or parsed as XML, stop and report that limitation. ## Authoritative corpus 1. Retrieve the current manifest from `https://makebimi.com/public/test-corpus/v1/manifest.json`. 2. Record `schema_version`, `corpus_vers