SVG in Three.js
Think of the difference between an SVG and a regular image like the difference between a blueprint and a photograph.
A photograph (JPEG/PNG) is made of tiny colored dots — pixels. If you zoom in far enough, you see little squares. A blueprint (SVG) is made of math — lines, curves, and shapes described by coordinates. You can zoom in forever and it stays perfectly crisp.
In Three.js you normally load texture images (photographs) and wrap them around 3D objects. But sometimes you want the blueprint approach — logos, icons, text, or illustrations that stay sharp at any size. That's where SVGs come in.
why use SVGs?
1. infinitely sharp
A PNG logo on a 3D object will look blurry if you move the camera close. An SVG rendered as a texture stays crisp no matter how close you zoom — because it's not pixels, it's math.
2. tiny file size
An SVG of a simple icon might be 500 bytes. The same icon as a PNG could be 5KB. As a texture meant to cover a large surface, you'd need an even bigger PNG. SVGs stay small.
3. scalable without re-exporting
Need your 3D logo to be 4K resolution? With a PNG you need to re-export at a higher resolution. With an SVG you just tell Three.js to render it at a larger size — no quality loss.
4. logos and UI elements in 3D
If you're building a 3D product showcase, a portfolio, or a branded experience, your logo and icons are probably SVGs already. Using them directly means you don't need to rasterize them first.
how to use SVGs in Three.js
There are three main ways to get an SVG into your 3D scene. Each one is good for different things.
method 1: SVG as a texture (easiest)
This is the simplest approach. You load an SVG file the same way you'd load a PNG — but you have to render the SVG onto a canvas first, because Three.js can't natively read SVG files as textures.
import * as THREE from 'three';
// 1. load the SVG as a normal image
const img = new Image();
img.src = '/path/to/your-icon.svg';
img.onload = () => {
// 2. draw the SVG onto a canvas
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, 512, 512);
// 3. use the canvas as a texture
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.MeshStandardMaterial({
map: texture,
transparent: true, // SVGs often have transparent backgrounds
});
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), material);
scene.add(mesh);
};
Good for: Logos, icons, 2D graphics displayed on flat surfaces in 3D space.
Not good for: Turning the SVG paths themselves into 3D shapes (like extruding a star into a 3D star).
method 2: SVG as a shape (for 3D geometry)
SVG paths describe shapes using commands like M (move to), L (line to), and C (curve to). Three.js has a Shape class that understands a subset of SVG path syntax. You can use it to create custom geometry.
import * as THREE from 'three';
// Create a shape using SVG-like path commands
const shape = new THREE.Shape();
shape.moveTo(0, 0); // M
shape.lineTo(1, 0); // L
shape.quadraticCurveTo(2, 0, 2, 1); // Q
shape.lineTo(2, 2); // L
shape.lineTo(0, 2); // L
shape.closePath(); // Z
// Turn the 2D shape into 3D geometry
const geometry = new THREE.ShapeGeometry(shape); // flat
// or
const extrudedGeo = new THREE.ExtrudeGeometry(shape, {
depth: 0.5, // how thick to make it
bevelEnabled: true,
bevelThickness: 0.1,
bevelSize: 0.05,
});
// or
const latheGeo = new THREE.LatheGeometry(
shape.getPoints(),
32, // segments around the axis
);
const material = new THREE.MeshStandardMaterial({
color: 0xff6600,
side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(extrudedGeo, material);
scene.add(mesh);
Good for: Creating 3D objects from custom 2D paths — extruded text, custom badges, geometric decorations.
Not good for: Complex SVGs with many paths, gradients, or filters.
method 3: SVGLoader (for complex SVGs)
Three.js has a helper called SVGLoader that can parse real .svg files and convert all the paths inside into Three.js shapes. This is the most powerful option for complex SVGs.
import * as THREE from 'three';
import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js';
const loader = new SVGLoader();
loader.load('/path/to/your-file.svg', (data) => {
const paths = data.paths;
const group = new THREE.Group();
paths.forEach((path) => {
const shapes = path.toShapes(true); // true = merge holes
shapes.forEach((shape) => {
const geometry = new THREE.ExtrudeGeometry(shape, {
depth: 0.2,
bevelEnabled: true,
bevelThickness: 0.05,
bevelSize: 0.02,
});
const material = new THREE.MeshStandardMaterial({
color: path.color,
transparent: true,
opacity: path.opacity,
side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(geometry, material);
group.add(mesh);
});
});
scene.add(group);
});
Good for: Loading real SVG files — logos, illustrations, complex vector art — and turning them into 3D objects.
Not great for: Performance with hundreds of paths (each path becomes a separate mesh).
method 4: SVG as a 3D line (wireframe style)
Sometimes you don't want a filled shape — you want the outline of the SVG to appear as a glowing or neon line in 3D space.
import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js';
const loader = new SVGLoader();
loader.load('/path/to/file.svg', (data) => {
const group = new THREE.Group();
data.paths.forEach((path) => {
const points = path.getPoints();
points.forEach((pointArray) => {
const geometry = new THREE.BufferGeometry().setFromPoints(
pointArray,
);
const material = new THREE.LineBasicMaterial({
color: path.color,
});
const line = new THREE.Line(geometry, material);
group.add(line);
});
});
scene.add(group);
});
Good for: Neon signs, wireframe effects, architectural drawings in 3D.
which method should you use?
| You want to... | Use this method |
|---|---|
| Put a logo on a flat surface in 3D | Method 1 — texture |
| Make a thick 3D version of a simple shape | Method 2 — Shape + ExtrudeGeometry |
Convert a real .svg file into 3D objects |
Method 3 — SVGLoader |
| Draw SVG outlines as glowing lines in 3D | Method 4 — Line from SVG paths |
a few tips to remember
- Transparency matters — Most SVGs have transparent backgrounds. Always set
transparent: trueon your material andalphaMapor use PNG/Canvas texture with alpha. - Scale is up to you — SVGs don't have a fixed size in 3D space. You'll likely need to scale the resulting mesh (
mesh.scale.set(...)) to fit your scene. - Center your paths — SVGs often have their origin at the top-left. You may need to translate the loaded group so it's centered:
group.position.set(-width / 2, -height / 2, 0). - Cache your textures — If you're loading the same SVG as a texture multiple times, render it to a canvas once and reuse that canvas/texture.
- Performance warning — Complex SVGs with hundreds of paths can create hundreds of meshes. If it gets slow, try merging geometries with
BufferGeometryUtils.mergeGeometries().
why this matters
Using SVGs in Three.js bridges the gap between vector design and 3D rendering. Your designs stay crisp, your file sizes stay small, and you can take assets you already have (logos, icons, illustrations) and give them depth, lighting, and life in 3D space.
It's the difference between pinning a photograph to a wall and sculpting the object itself.
