Skip to content

React

Tegaki’s default export is a React component that supports SSR, streaming text, and imperative playback control.

npm install tegaki react react-dom
import { TegakiRenderer } from 'tegaki';
import bundle from 'tegaki/fonts/caveat';

function App() {
  return (
    <TegakiRenderer
      font={bundle}
      time={{ mode: 'uncontrolled', speed: 1, loop: true }}
      style={{ fontSize: 48 }}
    >
      Hello World
    </TegakiRenderer>
  );
}
Loading...

Drive the animation from external state:

import { useState } from 'react';
import { TegakiRenderer } from 'tegaki';
import bundle from 'tegaki/fonts/caveat';

function App() {
  const [time, setTime] = useState(0);

  return (
    <>
      <input
        type="range"
        min={0}
        max={10}
        step={0.01}
        value={time}
        onChange={(e) => setTime(Number(e.target.value))}
      />
      <TegakiRenderer font={bundle} time={time} style={{ fontSize: 48 }}>
        Scrub me!
      </TegakiRenderer>
    </>
  );
}
Loading...
Drag the slider to scrub through the animation

Access the engine instance via ref:

import { useRef } from 'react';
import { TegakiRenderer, type TegakiRendererHandle } from 'tegaki';
import bundle from 'tegaki/fonts/caveat';

function App() {
  const ref = useRef<TegakiRendererHandle>(null);

  return (
    <TegakiRenderer
      ref={ref}
      font={bundle}
      time={{ mode: 'uncontrolled', speed: 1 }}
      style={{ fontSize: 48 }}
    >
      Hello World
    </TegakiRenderer>
  );
}

The handle exposes:

  • ref.current.engine: the TegakiEngine instance (or null before mount)
  • ref.current.element: the container HTMLDivElement

Glows, gradients, tapered ends and the rest are plugins. Import the factories from tegaki and pass the plugins in a list:

import { glowPlugin, strokeGradientPlugin, TegakiRenderer } from 'tegaki';

// Outside the component, so the list stays the same from render to render.
const plugins = [strokeGradientPlugin(), glowPlugin({ radius: 0.1, color: '#00ccff' })];

<TegakiRenderer
  font={bundle}
  time={{ mode: 'uncontrolled', speed: 1, loop: true }}
  plugins={plugins}
  style={{ fontSize: 48 }}
>
  Glowing rainbow
</TegakiRenderer>
Loading...

A new list of new plugins on every render redraws the canvas, so define it outside the component or in useMemo. Registered plugins can also be named (plugins={['taper', ['glow', { radius: 0.1 }]]}), and a list of names is fine inline. See Style plugins and Naming plugins. The pressure prop (0 to 1, default 1) sets how much the ink’s width follows the pen’s pressure.

For AI chat interfaces, where text arrives a chunk at a time:

function StreamingMessage({ text }) {
  return (
    <TegakiRenderer
      font={bundle}
      time={{ mode: 'uncontrolled', speed: 4, catchUp: 0.5 }}
      style={{ fontSize: 32 }}
    >
      {text}
    </TegakiRenderer>
  );
}

See Streaming Text for more details.