diff --git a/.storybook/stories/Svg.stories.tsx b/.storybook/stories/Svg.stories.tsx
new file mode 100644
index 000000000..540e83384
--- /dev/null
+++ b/.storybook/stories/Svg.stories.tsx
@@ -0,0 +1,99 @@
+import { useEffect } from '@storybook/addons'
+import { useArgs } from '@storybook/client-api'
+import { ComponentMeta } from '@storybook/react'
+import * as React from 'react'
+import { ComponentProps, FC, Suspense } from 'react'
+import { MathUtils, NoToneMapping, Vector3 } from 'three'
+import { Svg, SvgProps } from '../../src'
+import { Setup } from '../Setup'
+
+const svgRecord = {
+ Tiger: 'models/svg/tiger.svg',
+ 'Three.js': 'models/svg/threejs.svg',
+ 'Joins and caps': 'models/svg/lineJoinsAndCaps.svg',
+ Hexagon: 'models/svg/hexagon.svg',
+ Energy: 'models/svg/energy.svg',
+ 'Test 1': 'models/svg/tests/1.svg',
+ 'Test 2': 'models/svg/tests/2.svg',
+ 'Test 3': 'models/svg/tests/3.svg',
+ 'Test 4': 'models/svg/tests/4.svg',
+ 'Test 5': 'models/svg/tests/5.svg',
+ 'Test 6': 'models/svg/tests/6.svg',
+ 'Test 7': 'models/svg/tests/7.svg',
+ 'Test 8': 'models/svg/tests/8.svg',
+ 'Test 9': 'models/svg/tests/9.svg',
+ Units: 'models/svg/tests/units.svg',
+ Ordering: 'models/svg/tests/ordering.svg',
+ Defs: 'models/svg/tests/testDefs/Svg-defs.svg',
+ Defs2: 'models/svg/tests/testDefs/Svg-defs2.svg',
+ Defs3: 'models/svg/tests/testDefs/Wave-defs.svg',
+ Defs4: 'models/svg/tests/testDefs/defs4.svg',
+ Defs5: 'models/svg/tests/testDefs/defs5.svg',
+ 'Style CSS inside defs': 'models/svg/style-css-inside-defs.svg',
+ 'Multiple CSS classes': 'models/svg/multiple-css-classes.svg',
+ 'Zero Radius': 'models/svg/zero-radius.svg',
+ 'Styles in svg tag': 'models/svg/tests/styles.svg',
+ 'Round join': 'models/svg/tests/roundJoinPrecisionIssue.svg',
+}
+
+const url = 'https://threejs.org/examples'
+
+interface SvgStoryProps extends SvgProps {
+ svg: string
+ fillWireframe: boolean
+ strokesWireframe: boolean
+}
+
+const args: SvgStoryProps = {
+ src: `${url}/${svgRecord.Tiger}`,
+ svg: svgRecord.Tiger,
+ skipFill: false,
+ skipStrokes: false,
+ fillWireframe: false,
+ strokesWireframe: false,
+}
+
+export default {
+ title: 'Abstractions/Svg',
+ component: Svg,
+ decorators: [
+ (storyFn) => (
+ st.gl.setClearColor('#ccc')}
+ cameraPosition={new Vector3(0, 0, 200)}
+ lights={false}
+ >
+ {storyFn()}
+
+ ),
+ ],
+ args,
+ argTypes: {
+ svg: {
+ options: svgRecord,
+ control: {
+ type: 'select',
+ },
+ },
+ },
+}
+
+export const SvgSt: FC = ({ svg, fillWireframe, strokesWireframe, ...props }) => {
+ const [_, updateArgs] = useArgs()
+ useEffect(() => {
+ updateArgs({ src: `${url}/${svg || svgRecord.Tiger}` })
+ }, [svg])
+ return (
+
+
+
+
+ )
+}
diff --git a/README.md b/README.md
index eea7d4a30..81b79e089 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,7 @@ The `native` route of the library **does not** export `Html` or `Loader`. The de
useAnimations
MarchingCubes
Decal
+ Svg
Shaders
@@ -1166,6 +1167,18 @@ If declarative composition is not possible, use the `mesh` prop to define the su
```
+#### Svg
+
+[![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/abstractions-svg--svg-st)
+
+Wrapper around the `three` [svg loader](https://threejs.org/examples/?q=sv#webgl_loader_svg) demo.
+
+Accepts an SVG url or svg raw data.
+
+```js
+
+```
+
# Shaders
#### MeshReflectorMaterial
diff --git a/src/core/Svg.tsx b/src/core/Svg.tsx
new file mode 100644
index 000000000..3a8c06270
--- /dev/null
+++ b/src/core/Svg.tsx
@@ -0,0 +1,81 @@
+import { MeshBasicMaterialProps, MeshProps, Object3DProps, useLoader } from '@react-three/fiber'
+import * as React from 'react'
+import { forwardRef, Fragment, useEffect, useMemo } from 'react'
+import { DoubleSide, Object3D } from 'three'
+import { SVGLoader } from 'three-stdlib'
+
+export interface SvgProps extends Omit {
+ /** src can be a URL or SVG data */
+ src: string
+ skipFill?: boolean
+ skipStrokes?: boolean
+ fillMaterial?: MeshBasicMaterialProps
+ strokeMaterial?: MeshBasicMaterialProps
+ fillMeshProps?: MeshProps
+ strokeMeshProps?: MeshProps
+}
+
+export const Svg = forwardRef(function R3FSvg(
+ { src, skipFill, skipStrokes, fillMaterial, strokeMaterial, fillMeshProps, strokeMeshProps, ...props },
+ ref
+) {
+ const svg = useLoader(SVGLoader, !src.startsWith('