Tegaki Documentation

repository·main·Indexed 25 days ago

https://github.com/gkurt/tegaki

A library that converts any font into animated handwriting without manual path authoring or native dependencies. It provides a CLI for generating self-drawing SVGs and font bundles, a processing pipeline for skeletonization and stroke extraction, and dedicated renderers for React, Svelte, Vue, SolidJS, Astro, and Web Components. Includes bundled support for multiple scripts including Latin, Japanese, Korean, Arabic, Hebrew, Devanagari, and Bengali.

Tokens
33.1K
Snippets
96
Records
203
Agent score
79%

What's inside Tegaki

  1. Overview of Tegaki capabilities

    main

    Tegaki is a tool for creating animated handwriting from any font. It follows a three-step workflow:

    1. Generate: Use the generator CLI to download Google Fonts, extract glyph outlines, compute skeletons, and trace stroke paths (including width and timing data).
    2. Bundle: The stroke data is packaged into a compact bundle containing glyph metrics and timing information.
    3. Render: Use a compatible component in your application to handle text layout, line wrapping, and smooth animation playback.

    Additionally, Tegaki supports streaming, allowing you to animate handwriting as text streams in from an API, which is useful for AI chat interfaces.

  2. Understand the Tegaki font generation pipeline

    main

    The Tegaki generator processes fonts through a multi-stage pipeline to produce stroke data for handwriting animation. Each glyph undergoes the following stages:

    1. Extract: opentype.js extracts path commands and metrics.
    2. Flatten: Adaptive de Casteljau subdivision converts bezier curves to polyline segments.
    3. Rasterize: Scanline fill with nonzero winding rule produces a binary bitmap.
    4. Skeletonize: Zhang-Suen thinning reduces the bitmap to 1px-wide skeleton.
    5. Trace: Walks skeleton pixels into polylines, prunes short spurs, and simplifies with Ramer-Douglas-Peucker.
    6. Width: Distance transform computes stroke width at each skeleton point.
    7. Stroke order: Groups polylines into connected components, sorted top-to-bottom/left-to-right.
  3. Understand bundled font licenses in tegaki

    main

    The tegaki package includes pre-generated bundles for several fonts. All bundled fonts are licensed under the SIL Open Font License, Version 1.1.

    When using these fonts in your projects, ensure you comply with the SIL Open Font License, which allows for use, study, copying, merging, embedding, modification, redistribution, and sale of modified/unmodified copies, provided that:

    1. The Font Software itself is not sold by itself.
    2. Each copy contains the copyright notice and this license.
    3. Modified versions do not use Reserved Font Names without permission.
    4. The software is distributed entirely under this license.
    5. The software is not used for illegal or harmful activities.
  4. Control animation time manually

    main

    You can drive the animation by passing a numeric value to the time prop instead of a configuration object. This allows you to scrub through the animation using external state (e.g., a range input).

    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>
        </>
      );
    }
  5. Register font bundles in Astro

    main

    To avoid duplicating font data in the HTML output when using the same font across multiple components on a page, register the bundle once using the bundle prop. This serializes the font data into a <script type="application/json"> tag. Once registered, you can reference the font by its fullFamily name (e.g., "Caveat") instead of passing the entire bundle object again.

    ---
    import TegakiRenderer from 'tegaki/astro';
    import bundle from 'tegaki/fonts/caveat';
    ---
    
    <!-- Register the bundle once (renders nothing visible) -->
    <TegakiRenderer font={bundle} bundle />
    
    <!-- Use the font by name -->
    <TegakiRenderer font="Caveat" text="First line" />
    <TegakiRenderer font="Caveat" text="Second line" />
  6. Use TegakiEngine with Vanilla JS

    main

    You can use TegakiEngine directly with plain JavaScript or TypeScript without a framework. The engine automatically creates all necessary DOM elements inside the provided container.

    <div id="tegaki" style="font-size: 48px"></div
    
    <script type="module">
      import { TegakiEngine } from 'tegaki/core';
      import bundle from 'tegaki/fonts/caveat';
    
      const container = document.getElementById('tegaki');
    
      const engine = new TegakiEngine(container, {
        text: 'Hello World',
        font: bundle,
        time: { mode: 'uncontrolled', speed: 1, loop: true },
      });
    </script>
  7. Configure Vite to support Tegaki font assets

    main

    Tegaki uses ESM import-attributes (with { type: 'url' }) to load font assets. In Vite's dev mode, the pre-bundler (esbuild) may fail to propagate these references, causing 404 errors when attempting to fetch .ttf files from .vite/deps/.

    To fix this, exclude tegaki from optimizeDeps in your vite.config.ts. This ensures imports are routed through Vite's standard asset pipeline.

    Note: After applying this change, you must fully restart the dev server. It is also recommended to delete node_modules/.vite/deps/ to ensure a clean pre-bundling pass.

    import { defineConfig } from 'vite';
    
    export default defineConfig({
      // ...
      optimizeDeps: {
        exclude: ['tegaki'],
      },
    });
  8. Use Tegaki with Astro

    main

    Tegaki provides a native Astro component that renders full HTML at build time and hydrates on the client. This ensures text is visible even before hydration and requires no JavaScript framework for the initial render. To use it, import TegakiRenderer from tegaki/astro and provide a font bundle.

    ---
    import TegakiRenderer from 'tegaki/astro';
    import bundle from 'tegaki/fonts/caveat';
    ---
    
    <TegakiRenderer
      font={bundle}
      text="Hello World"
      time={{ mode: 'uncontrolled', speed: 1, loop: true }}
      style="font-size: 48px"
    />