glyphed.js documentation

Write text that draws itself.

A dependency-free ESM package for animated, hand-drawn SVG text.

Install

Choose the package manager already in your project. No separate publishing step is needed for pnpm, Yarn, or Bun.

npm install glyphed.js
pnpm add glyphed.js
yarn add glyphed.js
bun add glyphed.js

Quick start

write() renders text into an element and animates it when it enters the viewport.

import { write } from "glyphed.js";

write("#hello", "Hello, world!");

API

write(target, text, options?)
One-call DOM rendering and scroll-triggered animation.
renderText(text, options?)
Returns the SVG HTML string without accessing the DOM.
attach(element, options?)
Triggers each rendered word through an IntersectionObserver.
animateWriting(element)
Immediately starts the stroke animation for a word.

Set animate: false for fully drawn, static text. Set once: false when your own render cycle should re-trigger an observer.

Handwriting is copyable by default: invisible real text sits over each word, so selecting and copying works like normal text. Pass copyable: false for decorative output. Undrawn strokes stay hidden until the pen reaches them; pass dots: true to show each stroke's starting dot ahead of time.

Icons

Every bundled icon is on the same 24-unit grid as the lettering. Search by name, then select an icon to copy a ready-to-use import and render call. Import individual icons to keep your bundle small.

Select an icon to copy its code.

For icons inside a sentence, pass imported icons by name. Matching :name: shortcodes draw inline; unknown shortcodes stay as text.

import { renderText } from "glyphed.js";
import { rocket, heart } from "glyphed.js/icons";

const markup = renderText("Ship it :rocket: with :heart:", {
  icons: { rocket, heart },
});
renderIcon(icon, options?)
SVG string. Options: size, color, strokeWidth, roughness, seed, delay, label, animate, hover (a small motion of its own while hovered).
drawIcon(target, icon, options?)
Renders into an element and draws in on scroll.
icon(name, strokes)
Define your own from path strings or the shapes helpers.

Charts

Pick a chart type to see it draw and copy a complete example. Charts use direct labels, accessible SVG output, and hatching as a second cue alongside color.

annotate(target, options)
underline, circle, box, highlight, strike, cross, bracket. Returns { redraw, remove }.
renderChart(options) / drawChart(target, options)
bar, line, pie, donut with hatched fills and handwritten labels.
ChartOptions
Set width, height, color, colors, fill, format, title, roughness, seed, dots, and animate as needed.
renderSparkline(values, options?)
A trend line one text-line tall, for inline use.

Annotations

Add a hand-drawn mark to an element after it is in the document. The returned controller lets you redraw after content changes or remove the mark during cleanup.

import { annotate } from "glyphed.js";

const mark = annotate("#price", {
  type: "circle",
  color: "#c63d24",
  passes: 2,
});

mark.redraw();
mark.remove();
annotate(target, options)
Types: underline, circle, box, highlight, strike, cross, bracket. Returns { redraw, remove }.

React

Render into a ref after mount. Re-render when the text changes.

import { useEffect, useRef } from "react";
import { write } from "glyphed.js";

export function Handwriting({ text }) {
  const ref = useRef(null);

  useEffect(() => {
    write(ref.current, text);
  }, [text]);

  return <span ref={ref} />;
}

SSR

renderText() is pure string output, so it can run during server rendering. Call attach() after hydration when animation is needed.

import { renderText } from "glyphed.js";

const markup = renderText("Server-rendered ink", { animate: false });

Glyphs

Coverage includes lowercase and uppercase English letters, digits, and . , ! ? ' - & ( ) — " ` { } [ ] * = + @ :. Unsupported characters are skipped. To add one, create a glyph module and register it in the glyph lookup.

Request a glyph or report an issue