threlte logo
@threlte/extras

<Text3DGeometry>

webgl <Text3DGeometry> works with WebGL and is available from the @threlte/extras export. webgpu <Text3DGeometry> works with WebGPU and is available from the @threlte/extras/webgpu export.

Render 3D text as a geometry using Three.js’ TextGeometry.

<script lang="ts">
  import { Canvas } from '@threlte/core'
  import { Checkbox, Pane, Slider, Textarea } from 'svelte-tweakpane-ui'
  import Scene from './Scene.svelte'
  import { MathUtils } from 'three'

  let options = $state({
    text: 'Hello\nWorld',
    bevelEnabled: true,
    bevelOffset: 0,
    bevelSegments: 20,
    bevelSize: 0.2,
    bevelThickness: 0.1,
    curveSegments: 12,
    depth: 1,
    size: 5,
    smooth: 0.1
  })
</script>

<Pane
  title="Text3DGeometry"
  position="fixed"
>
  <Textarea
    bind:value={options.text}
    label="text"
  />
  <Checkbox
    label="bevelEnabled"
    bind:value={options.bevelEnabled}
  />
  <Slider
    label="bevelOffset"
    bind:value={options.bevelOffset}
    min={0}
    max={2}
  />
  <Slider
    label="bevelSegments"
    bind:value={options.bevelSegments}
    step={1}
    min={0}
    max={50}
  />
  <Slider
    label="bevelSize"
    bind:value={options.bevelSize}
    min={0}
    max={2}
  />
  <Slider
    label="bevelThickness"
    bind:value={options.bevelThickness}
    min={0}
    max={2}
  />
  <Slider
    label="curveSegments"
    bind:value={options.curveSegments}
    step={1}
    min={0}
    max={50}
  />
  <Slider
    label="depth"
    bind:value={options.depth}
    min={0}
    max={5}
  />
  <Slider
    label="size"
    bind:value={options.size}
    min={0}
    max={10}
  />
  <Slider
    label="smooth"
    bind:value={options.smooth}
    min={0}
    max={MathUtils.degToRad(180)}
  />
</Pane>

<div>
  <Canvas>
    <Scene {...options} />
  </Canvas>
</div>

<style>
  div {
    height: 100%;
  }
</style>
<script lang="ts">
  import { T } from '@threlte/core'
  import { Align, Environment, Float, OrbitControls, Text3DGeometry } from '@threlte/extras'

  interface Props {
    text: string
    bevelEnabled: boolean
    bevelOffset: number
    bevelSegments: number
    bevelSize: number
    bevelThickness: number
    curveSegments: number
    depth: number
    size: number
    smooth: number
  }

  let { ...rest }: Props = $props()
</script>

<Align>
  {#snippet children({ align })}
    <T.Mesh>
      <Text3DGeometry
        font="/fonts/Inter-semibold.blob"
        {...rest}
        oncreate={() => {
          align()
        }}
      />
      <T.MeshStandardMaterial
        color="#FD3F00"
        toneMapped={false}
        metalness={1.0}
        roughness={0.1}
      />
    </T.Mesh>
  {/snippet}
</Align>

<Environment url="/textures/equirectangular/hdr/shanghai_riverside_1k.hdr" />

<Float
  rotationIntensity={[0, 3, 0]}
  rotationSpeed={1}
  floatingRange={[-5, 5]}
  speed={1}
>
  <T.PerspectiveCamera
    makeDefault
    position.y={0}
    position.z={20}
    fov={90}
  >
    <OrbitControls
      enableDamping
      enablePan={false}
      enableZoom={false}
    />
  </T.PerspectiveCamera>
</Float>

Examples

Basic Example

Scene.svelte
<script lang="ts">
  import { T } from '@threlte/core'
  import { Text3DGeometry } from '@threlte/extras'
</script>

<T.Mesh>
  <Text3DGeometry text={'Hello World'} />
  <T.MeshStandardMaterial />
</T.Mesh>

Using a Custom Font

If no font property is provided, the default font “Helvetiker” will be used and loaded from the CDN JSDeliver.

If you want to use a custom font, you can generate a font using typeface.js. Provide the path to the resulting JSON file using the prop font.

Suspense-Ready

The component <Text3DGeometry> is suspense-ready. Using it in a <Suspense> boundary will suspend rendering until the provided font is loaded:

Scene.svelte
<script lang="ts">
  import { T } from '@threlte/core'
  import { Text3DGeometry, Suspense } from '@threlte/extras'
  import Fallback from './Fallback.svelte'
</script>

<Suspense>
  <T.Mesh>
    <Text3DGeometry
      font={'path-to-your-font'}
      text={'Hello World'}
    />
    <T.MeshStandardMaterial />
  </T.Mesh>

  {#snippet fallback()}
    <Fallback />
  {/snippet}
</Suspense>

Loading a Font Yourself

You can also load the font yourself and pass it to the component, like so:

Scene.svelte
<script lang="ts">
  import { T, useLoader } from '@threlte/core'
  import { Text3DGeometry } from '@threlte/extras'
  import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js'

  let font = useLoader(FontLoader).load('path-to-your-font')
</script>

{#if $font}
  <T.Mesh>
    <Text3DGeometry
      font={$font}
      text={'Hello World'}
    />
    <T.MeshStandardMaterial />
  </T.Mesh>
{/await}

Centering Text

You can center a text by using the <Align> component and calling the align slot prop when the text geometry is created.

Scene.svelte
<Align>
  {#snippet children({ align })}
    <T.Mesh>
      <Text3DGeometry
        font={'path-to-your-font'}
        text={`Hello!`}
        oncreate={align}
      />
      <T.MeshStandardMaterial />
    </T.Mesh>
  {/snippet}
</Align>

Smoothing Text

You can smooth the text by setting the smooth prop to a value above 0 to smooth all edges where the angle between faces is less than the smooth value.

Component Signature

Props

name
type
required
default
description

text
string
yes
The text to turn into geometry.

bevelEnabled
boolean
no
false
Bevels the edges of the text.

bevelOffset
number
no
0
How far from the text's outline the bevel starts.

bevelSegments
number
no
3
The number of bevel layers.

bevelSize
number
no
8
How far the bevel extends from the text's outline.

bevelThickness
number
no
10
How deep the bevel goes into the text.

curveSegments
number
no
12
The number of points on each curve of the glyphs.

depth
number
no
50
How far the text is extruded.

extrudePath
Curve<Vector3>
no
A curve to extrude the text along instead of a straight line. Disables the bevel.

font
Font | string
no
'https://cdn.jsdelivr.net/npm/three/examples/fonts/helvetiker_regular.typeface.json'
A loaded font, or the URL of a typeface.json font to load.

size
number
no
100
The size of the text.

smooth
number
no
Math.PI / 3
Smooths the normals wherever faces meet at an angle below this, in radians. 0 keeps every face flat.

steps
number
no
1
The number of segments along the extrusion.

UVGenerator
UVGenerator
no
Generates the UVs of the extruded geometry.

Events

name
payload
description

onrendered
TextGeometry
Called with the new geometry whenever the text geometry is rebuilt.