threlte logo
@threlte/extras

<Text3DGeometry>

Render 3D text as a geometry using threejs’s TextGeometry.

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

  let text = 'Hello\nWorld'
  let bevelEnabled = true
  let bevelOffset = 0
  let bevelSegments = 20
  let bevelSize = 0.2
  let bevelThickness = 0.1
  let curveSegments = 12
  let depth = 1
  let size = 5
  let smooth = 0.1
</script>

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

<div>
  <Canvas>
    <Scene
      {text}
      {bevelEnabled}
      {bevelOffset}
      {bevelSegments}
      {bevelSize}
      {bevelThickness}
      {curveSegments}
      {depth}
      {size}
      {smooth}
    />
  </Canvas>
</div>

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

  export let text: string
  export let bevelEnabled: boolean
  export let bevelOffset: number
  export let bevelSegments: number
  export let bevelSize: number
  export let bevelThickness: number
  export let curveSegments: number
  export let depth: number
  export let size: number
  export let smooth: number
</script>

<Align>
  {#snippet children({ align })}
    <T.Mesh>
      <Text3DGeometry
        font={'/fonts/Inter-semibold.blob'}
        {text}
        {bevelEnabled}
        {bevelOffset}
        {bevelSegments}
        {bevelSize}
        {bevelThickness}
        {curveSegments}
        {depth}
        {size}
        {smooth}
        oncreate={() => {
          align()
        }}
      />
      <T.MeshStandardMaterial
        color="#FD3F00"
        toneMapped={false}
        metalness={1.0}
        roughness={0.1}
      />
    </T.Mesh>
  {/snippet}
</Align>

<Environment files="/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

font
Font | string
yes
Either a loaded font or a path to a font file.

text
string
yes
The text to display.

bevelEnabled
boolean
no
false

bevelOffset
number
no
0

bevelSegments
number
no
3

bevelSize
number
no
8

bevelThickness
number
no
10

curveSegments
number
no
12

depth
number
no
1

extrudePath
Curve<Vector3>
no

height
number
no
50

size
number
no
100

smooth
number
no
0
Smooth all edges where the angle between faces is less than value

steps
number
no
1

UVGenerator
UVGenerator
no