npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sinefont

v0.1.3

Published

A cursive React font made entirely of sine waves -- animated glyphs that wiggle and morph between words, plus a built-in tool to draw your own alphabet.

Readme

sinefont

A cursive React font that's 100% sine waves. Every glyph is a parametric curve — x(t) and y(t) are each their own sum of harmonics, like a handful of pendulums swinging together — so letters can loop, animate with a gentle idle wiggle, and morph smoothly from one word to the next.

sinefont rendering the word "sinefont" in animated cursive

Live demo →

import { SineText } from 'sinefont';

export default function App() {
  return <SineText text="hello" animate fontSize={96} />;
}

Install

npm install sinefont

Requires React 18 or 19 (react and react-dom are peer dependencies, not bundled).

Usage

import { useState } from 'react';
import { SineText } from 'sinefont';

export default function App() {
  const [text, setText] = useState('hello');

  return (
    <>
      <SineText
        text={text}
        animate
        wiggleAmount={3}
        wiggleSpeed={1}
        morphDuration={600}
        color="#7dd3fc"
        strokeWidth={4}
        fontSize={120}
      />
      <input value={text} onChange={(e) => setText(e.target.value)} />
    </>
  );
}

Changing text doesn't just swap the drawing — each glyph's harmonics smoothly tween from the old shape to the new one, so words morph into each other instead of popping.

Props

| Prop | Type | Default | Description | | ---------------- | ------------------------- | --------------- | -------------------------------------------------------------------- | | text | string | — | The word/phrase to render. Change it anytime. | | glyphs | Record<string, GlyphDef>| built-in font | A custom font to render with. See Custom fonts. | | fontSize | number | 96 | Font size in px. | | color | string | currentColor | Stroke color. | | strokeWidth | number | 4 | Stroke width. | | letterSpacing | number | 10 | Extra space between glyphs (font units). | | animate | boolean | false | Turns on the continuous idle wiggle. | | wiggleAmount | number | 3 | Wiggle strength. | | wiggleSpeed | number | 1 | Wiggle speed. | | morphDuration | number | 600 | Milliseconds to morph from the previous word to a new one. | | sizeJitter | number | 0 | Randomly varies each letter's size by up to this fraction (0-1), re-rolled whenever text changes -- so repeated letters don't come out identical, like a real hand. | | baselineJitter| number | 0 | Amplitude (font units) of a gentle random wave the line sits on instead of a straight baseline, re-rolled whenever text changes. | | className | string | — | Passed to the underlying <svg>. | | style | React.CSSProperties | — | Passed to the underlying <svg>. |

Custom fonts

sinefont ships with a small built-in cursive alphabet, but you can bring your own — draw one with the glyph editor (see Drawing your own font below), download it as JSON, and load it at runtime:

import { useEffect, useState } from 'react';
import { SineText, loadGlyphFont, type GlyphDef } from 'sinefont';

export default function App() {
  const [font, setFont] = useState<Record<string, GlyphDef>>();

  useEffect(() => {
    loadGlyphFont('/fonts/my-handwriting.json').then(setFont);
  }, []);

  if (!font) return null;
  return <SineText text="hello" glyphs={font} animate />;
}

loadGlyphFont just fetches and validates the JSON file — you can also build a glyphs map by hand, or generate one programmatically, since it's plain data: { [letter]: { advance, coeffsX, coeffsY, marks? } }.

Drawing your own font

This repo is also the font-drawing tool. Clone it, run the app, and use the "Glyph Editor" tab to draw letters by hand (freehand strokes get fitted to sine harmonics automatically), preview them animated, and export:

The glyph editor: a hand-drawn "g" with its faint reference letter, the fitted sine-wave reconstruction, and a live word preview

git clone https://github.com/ryanlane/sinefont.git
cd sinefont
npm install
npm run dev

From the editor you can:

  • Copy code — paste straight into src/lib/sinefont/glyphs.ts as the built-in alphabet.
  • Download JSON — get a sinefont-glyphs.json file. Drop it in this project's public/ folder and the app picks it up automatically on next load (no code changes) — or use it with loadGlyphFont in any other project, per Custom fonts above.

Edits also autosave to localStorage as you draw, so refreshing the page during a drawing session won't lose your work.

Publishing / building the package

npm run dev and npm run build build the demo app (this README, the editor, etc.). The publishable library itself — just src/lib/sinefont — is built separately:

npm run build:lib

This emits dist/sinefont.mjs (ESM), dist/sinefont.cjs (CJS), and type declarations, which is what actually ships to npm (see the files field in package.json).

Inspiration

Inspired by Zanzlanz's "How I released a game that has no assets" — the idea of generating everything from pure math instead of hand-authored assets carried straight over into building a font out of nothing but sine waves.

License

MIT