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

truffle-text

v2.0.0

Published

Deterministic Saffron-class text rendering with HarfBuzz shaping and certified Flash replay.

Readme

Truffle Text

Truffle is a deterministic AIR/Saffron HTML canvas text renderer. air-generative is the production path: HarfBuzz shaping, bidi, grapheme-safe fallback, recovered AIR outline fitting and escapement, and runtime rasterization at arbitrary positive sizes. legacy-air-exact is an explicit frozen replay oracle; generic is a developer comparison control.

Install

yarn add truffle-text
npx truffle-setup --out public/assets/truffle

Run truffle-setup again after upgrading the package. The command expands the compact package payload into files that your own website serves; no external CDN is required. Serve .tfc as application/octet-stream.

Browser or canvas usage

import { loadPackedTruffle } from 'truffle-text/packed';

const truffle = await loadPackedTruffle({
  base: './assets/truffle',
  styles: ['u_chat_speak', 'u_chat_name'],
});

truffle.drawText(context, 'Hello world!', {
  x: 0,
  y: 0,
  style: 'u_chat_speak',
});

truffle.drawRichText(context, 'Hello <b>bold</b> and ' +
  '<font size="18" color="#C62828">large red</font>', {
  x: 0,
  y: 24,
  style: 'u_regular',
});

For only the scalable engine, initially load the bundled fonts but none of the legacy tables:

const truffle = await loadPackedTruffle({
  base: './assets/truffle',
  loadCalibration: false,
});
const pixels = truffle.renderToBuffer('Hello — Truffle', {
  fontFamily: 'Ubuntu',
  size: 21.5,
  engineMode: 'air-generative',
});

Calling ensureStyles or ensureAllStyles later enables legacy tables lazily.

Applications that provide their own font bytes can use the standalone clean entry point. It has no dependency on the legacy renderer or payload:

import { SaffronText } from 'truffle-text/generative';

const truffle = SaffronText.fromFonts([{
  family: 'My UI Font',
  data: await fetch('/fonts/ui.ttf').then(response => response.arrayBuffer()),
}]);
const pixels = truffle.renderToBuffer('Any text', {
  fontFamily: 'My UI Font', size: 19.25, engineMode: 'air-generative',
});

Unicode fallback fonts

The npm payload bundles Ubuntu and Volter for the included Habbo-style presets. It does not bundle broad Unicode fonts. Applications that need Arabic, CJK, or other scripts should serve licensed TrueType faces, register them after loading Truffle, and name them in fontFallbacks.

This example registers upright Regular and Bold faces for families that do not provide designed italics. If your family includes real italic faces, register those instead of the upright aliases:

import { FlashFont } from 'truffle-text';

const unicodeFallbacks = ['Noto Sans Arabic', 'Zen Kaku Gothic New'];

async function loadFace(family, weight, url) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`Unable to load ${url}: HTTP ${response.status}`);
  return new FlashFont(
    new Uint8Array(await response.arrayBuffer()),
    `${family} ${weight}`,
  );
}

async function registerUprightFamily(family, regularUrl, boldUrl) {
  const [regular, bold] = await Promise.all([
    loadFace(family, 'Regular', regularUrl),
    loadFace(family, 'Bold', boldUrl),
  ]);

  for (const italic of [false, true]) {
    truffle.registerFont(family, regular, { bold: false, italic });
    truffle.registerFont(family, bold, { bold: true, italic });
  }
}

await Promise.all([
  registerUprightFamily(
    'Noto Sans Arabic',
    '/fonts/NotoSansArabic-Regular.ttf',
    '/fonts/NotoSansArabic-Bold.ttf',
  ),
  registerUprightFamily(
    'Zen Kaku Gothic New',
    '/fonts/ZenKakuGothicNew-Regular.ttf',
    '/fonts/ZenKakuGothicNew-Bold.ttf',
  ),
]);

const pixels = truffle.renderToBuffer('مرحبا · こんにちは世界', {
  styleName: 'u_chat_speak',
  fontFallbacks: unicodeFallbacks,
});

Fallback selection is grapheme-safe and works with shaping, bidi, rich text, measurement, editing, and rendering. Keep each external font's required copyright and license files with your application.

React or Nitro usage

Preload once while the client starts:

import { preloadTruffle, TruffleCanvasText, TruffleRichText } from 'truffle-text/react';

await preloadTruffle({
  base: './assets/truffle',
  styles: [
    'u_chat_speak',
    'u_chat_name',
    'u_chat_whisper',
    'u_chat_name_whisper',
    'u_chat_shout',
  ],
});

Then render named styles anywhere:

<TruffleCanvasText text="C5: " styleName="u_chat_name" />
<TruffleCanvasText text="Hello!" styleName="u_chat_speak" />
<TruffleRichText
  markup={'Hello <b>rich text</b>'}
  baseStyle="u_regular"
  width={320}
/>

Chat mappings used by the Habbo-style test:

Speak:   u_chat_name + u_chat_speak
Whisper: u_chat_name_whisper + u_chat_whisper
Shout:   u_chat_name + u_chat_shout

For bubble wrapping, measure and place text with Truffle before showing the bubble. Keep canvas coordinates integer-aligned. Do not show HTML text first and replace it after loading.

Styles

Use names from HABBO_CSS_STYLE_NAMES or inspect HABBO_STYLES. Named styles are read-only presets, not size or face restrictions:

const style = truffle.resolveStyle('u_regular', {
  engineMode: 'air-generative',
  size: 17.5,
  bold: true,
  color: 0x17365D,
});

Normal calls and fidelity: 'auto' use air-generative, even for certified signatures. The deprecated 'geometric' spelling is an alias for the same route. 'exact' or explicit legacy-air-exact requires certified replay and rejects a miss. Select generic only as a comparison control. The resolved engine is exposed in render metadata and by engine(style).metadata.mode.

Editable search and input fields

import { createTruffleEditable } from 'truffle-text/editable';

const search = createTruffleEditable(document.querySelector('#search'), truffle, {
  style: { styleName: 'u_italic', size: 11 },
  placeholder: 'Search profiles...',
});

This keeps a real transparent textarea for keyboard input, IME, clipboard, and accessibility while Truffle draws the text, selection, and caret from one layout. Ctrl+A never exposes browser-rendered fallback text. Dynamically added underlines have a one-pixel gap by default.

Playground

Try every included style in the browser at isetht.github.io/truffle-text/test.

Licensing

Truffle's original code is available under the MIT License. Bundled fonts are third-party components governed separately; see THIRD_PARTY_NOTICES.md and the licenses/ directory. Volter (Goldfish) does not currently have a located standalone licence or EULA, so review its notice before redistribution.