Observed since 20 Oct, 19:41 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
3dsvg
Embeddable 3D component – render extruded SVGs with PBR materials, animations, and shadows

The easiest way to turn SVGs into interactive React 3D components.
npm install 3dsvg
Peer dependencies: react, react-dom, three, @react-three/fiber, @react-three/drei
import { SVG3D } from "3dsvg";
// 3D text
<SVG3D text="Hello" animate="spin" />
// SVG from your public folder
<SVG3D svg="/logo.svg" material="gold" animate="float" />
// Inline SVG markup
<SVG3D svg='<svg viewBox="0 0 24 24"><path d="M12 2L2 7l10 5 10-5z"/></svg>' />
// Remote URL
<SVG3D svg="https://cdn.example.com/icon.svg" material="metal" />
Next.js — wrap with next/dynamic for SSR safety:
const SVG3D = dynamic(
() => import("3dsvg").then((m) => ({ default: m.SVG3D })),
{ ssr: false }
);
Design 3D objects visually and export embed code at 3dsvg.design.
Provide either text or svg. If both are given, svg takes priority.
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | — | Text to render in 3D |
font | string | "DM Sans" | Google Font name (see available fonts) |
svg | string | — | SVG markup or URL (/logo.svg, https://..., ./path.svg) |
| Prop | Type | Default | Description |
|---|---|---|---|
depth | number | 1 | Extrusion depth (0.5 = flat, 10 = very deep) |
smoothness | number | 0.2 | Curve and bevel quality, 0–1 |
color | string | "#ffffff" | Base color (hex) |
| Prop | Type | Default | Description |
|---|---|---|---|
material | MaterialPreset | "default" | Material preset (see below) |
metalness | number | — | Override preset metalness (0–1) |
roughness | number | — | Override preset roughness (0–1) |
opacity | number | — | Override preset opacity (0–1) |
wireframe | boolean | false | Wireframe rendering mode |
Material presets:
| Preset | Metalness | Roughness | Notes |
|---|---|---|---|
default | 0.15 | 0.35 | Balanced starting point |
plastic | 0.0 | 0.3 | Smooth, non-reflective |
metal | 0.9 | 0.2 | Brushed metal |
glass | 0.1 | 0.05 | Transparent with refraction |
rubber | 0.0 | 0.9 | Matte, soft |
chrome | 1.0 | 0.05 | Mirror-like reflections |
gold | 1.0 | 0.25 | Gold tint applied automatically |
clay | 0.0 | 1.0 | Fully matte |
emissive | 0.0 | 0.5 | Self-illuminated glow |
holographic | 0.8 | 0.1 | Transparent with clearcoat |
| Prop | Type | Default | Description |
|---|---|---|---|
texture | string | — | Image URL to map onto the 3D surface |
textureRepeat | number | 1 | How many times the texture tiles |
textureRotation | number | 0 | Texture rotation in radians |
textureOffset | [number, number] | [0, 0] | UV offset [x, y] |
When a texture is set, the base color is overridden to white so the texture renders at full fidelity.
| Prop | Type | Default | Description |
|---|---|---|---|
lightPosition | [number, number, number] | [5, 8, 5] | Key light position [x, y, z] |
lightIntensity | number | 1.2 | Key light brightness |
ambientIntensity | number | 0.3 | Ambient fill light |
shadow | boolean | true | Show contact shadows |
| Prop | Type | Default | Description |
|---|---|---|---|
rotationX | number | 0 | Initial X rotation (radians) |
rotationY | number | 0 | Initial Y rotation (radians) |
zoom | number | 8 | Camera distance |
fov | number | 50 | Field of view (degrees) |
The camera automatically adjusts on narrow/portrait viewports — it zooms out proportionally so the 3D object always fits within the visible area.
| Prop | Type | Default | Description |
|---|---|---|---|
interactive | boolean | true | Master toggle — false disables drag, zoom, and orbit |
cursorOrbit | boolean | true | Object subtly follows the cursor |
orbitStrength | number | 0.15 | How strongly the object follows the cursor (radians) |
draggable | boolean | true | Allow drag to rotate |
scrollZoom | boolean | false | Allow scroll to zoom (off by default so embeds don't hijack page scroll) |
resetOnIdle | boolean | false | Return to default position after inactivity |
resetDelay | number | 2 | Seconds before reset triggers |
| Prop | Type | Default | Description |
|---|---|---|---|
animate | AnimationType | "none" | Loop animation type (see below) |
animateSpeed | number | 1 | Speed multiplier |
animateReverse | boolean | false | Reverse direction |
Animation types: none · spin · float · pulse · wobble · spinFloat · swing
| Prop | Type | Default | Description |
|---|---|---|---|
intro | string | "zoom" | Intro animation: zoom · fade · none |
introDuration | number | 2.5 | Duration in seconds |
introFrom | object | { zoom: 18, opacity: 0 } | Starting state |
introTo | object | { zoom: 8, opacity: 1 } | Ending state |
| Prop | Type | Default | Description |
|---|---|---|---|
width | string | number | "100%" | Container width |
height | string | number | "100%" | Container height |
background | string | "transparent" | Canvas background color |
className | string | — | CSS class on the wrapper div |
| Prop | Type | Description |
|---|---|---|
onReady | () => void | Fires when WebGL context is ready and first frame is rendered |
onAnimationComplete | () => void | Fires when the intro animation finishes |
onLoadingChange | (loading: boolean, progress: number) => void | Fires during geometry processing with loading state and progress (0-100). Use this to show custom loading UI. |
Geometry processing is asynchronous — complex SVGs are processed in batches to keep the browser responsive. The onLoadingChange callback lets you track progress and show a loading indicator:
<SVG3D
svgString={complexSvg}
onLoadingChange={(loading, progress) => {
if (loading) console.log(`Processing: ${progress}%`);
else console.log("Done");
}}
/>
DM Sans · Bebas Neue · Playfair Display · Righteous · Black Ops One · Permanent Marker · Rubik Mono One · Pacifico · Oswald · Archivo Black
MIT — Renato Costa
Made in Blueberry 🫐
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
opentype.jsEnvironment{
"local_name": "opentype.js",
"alias": false,
"peer_metadata": null
} | ^1.3.4 | runtime |
tsupEnvironment{
"local_name": "tsup",
"alias": false,
"peer_metadata": null
} | ^8 | development |
reactEnvironment{
"local_name": "react",
"alias": false,
"peer_metadata": null
} | ^19 | development |
threeEnvironment{
"local_name": "three",
"alias": false,
"peer_metadata": null
} | ^0.183.2 | development |
react-domEnvironment{
"local_name": "react-dom",
"alias": false,
"peer_metadata": null
} | ^19 | development |
typescriptEnvironment{
"local_name": "typescript",
"alias": false,
"peer_metadata": null
} | ^5 | development |
opentype.jsEnvironment{
"local_name": "opentype.js",
"alias": false,
"peer_metadata": null
} | ^1.3.4 | development |
@types/reactEnvironment{
"local_name": "@types/react",
"alias": false,
"peer_metadata": null
} | ^19 | development |
@types/threeEnvironment{
"local_name": "@types/three",
"alias": false,
"peer_metadata": null
} | ^0.183.1 | development |
@react-three/dreiEnvironment{
"local_name": "@react-three/drei",
"alias": false,
"peer_metadata": null
} | ^10.7.7 | development |
@react-three/fiberEnvironment{
"local_name": "@react-three/fiber",
"alias": false,
"peer_metadata": null
} | ^9.5.0 | development |
@types/opentype.jsEnvironment{
"local_name": "@types/opentype.js",
"alias": false,
"peer_metadata": null
} | ^1.3.9 | development |
reactEnvironment{
"local_name": "react",
"alias": false,
"peer_metadata": null
} | >=18 | peer |
threeEnvironment{
"local_name": "three",
"alias": false,
"peer_metadata": null
} | >=0.160.0 | peer |
react-domEnvironment{
"local_name": "react-dom",
"alias": false,
"peer_metadata": null
} | >=18 | peer |
@react-three/dreiEnvironment{
"local_name": "@react-three/drei",
"alias": false,
"peer_metadata": null
} | >=10 | peer |
@react-three/fiberEnvironment{
"local_name": "@react-three/fiber",
"alias": false,
"peer_metadata": null
} | >=9 | peer |
Source distribution
{
"shasum": "d724433283e63f237a4d185947d43e5fb5e46d34",
"tarball": "https://registry.npmjs.org/3dsvg/-/3dsvg-0.1.0.tgz",
"fileCount": 16,
"integrity": "sha512-LMv6+LAVEX90xzURo7E+en9iPFkfxYrzRLL6nPLDgkLnfcHqAKIlCy4jzJ5h2s2puQXJsjhD4RPsdLwBLv58rQ==",
"signatures": [
{
"sig": "MEYCIQC03EdQmPpJRmNkuKCJ7ZlKJeDJC4aCTi48vPfmX7HdTAIhAKOvYiDDG3CqXGMYBT6vVyyA2r4KWwLtLANJYonZi1t1",
"keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
}
],
"unpackedSize": 108457
}Observed since 20 Oct, 19:41 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:fef73d108359b0d753c898068675fecf951b4927ddd8a2e7c8a1a962dbfded63