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

funky-pixi-text

v1.0.0

Published

A PIXI.js addon text field class using MSDF font rendering

Readme

funky-pixi-text

A high-quality, GPU-accelerated MSDF (Multi-channel Signed Distance Field) text rendering library for PIXI.js v7. It provides crisp text rendering at any scale, advanced visual effects (gradients, drop shadows, strokes, 3D extrusion, texture fills), full layout control (word wrap, kerning, alignment, letter spacing), and an adaptive performance system that scales from ultra-low-end mobile devices to high-end desktops.

Table of Contents


Features

  • MSDF rendering — crisp glyphs at any zoom level from a single texture atlas
  • Single draw call per text instance — all glyphs batched into one PIXI mesh
  • Layout engine — multi-line, word wrap, kerning, letter spacing, leading, line-height, alignment (left / center / right / justify)
  • Visual effects — solid color, linear gradient, radial (circular) gradient, stroke, drop shadow (with blur), 3D extrusion, texture fill with blend modes
  • Auto-scale to fit within a maxWidth / maxHeight box
  • Adaptive performance — six built-in presets (ultra_lowultra), automatic GPU detection, FPS / memory / thermal / battery aware runtime monitor
  • Custom font loading via a PIXI Assets extension (FontLoader)
  • Familiar APIText extends PIXI.Container; properties update via setStyle(), setColor(), etc.

Installation

npm install funky-pixi-text pixi.js

PIXI.js v7 (^7.2.4) is a peer dependency.


Quick Start

import { Application, Assets } from "pixi.js";
import { Text, FontLoader } from "funky-pixi-text";

const app = new Application({ backgroundColor: 0x222222, resizeTo: window });
document.body.appendChild(app.view as HTMLCanvasElement);

// Load an MSDF font (atlas .png + bmfont .json)
await Assets.load({
  src: "fonts/Roboto-Black.json",
  loadParser: FontLoader.name,
});

const label = new Text("Hello MSDF!", {
  fontName: "Roboto-Black",
  fontSize: 96,
  color: 0xffffff,
  align: "center",
  anchorX: 0.5,
  anchorY: 0.5,
});

label.position.set(app.screen.width / 2, app.screen.height / 2);
app.stage.addChild(label);

Generating MSDF Fonts

This library consumes BMFont JSON atlases generated by msdf-bmfont-xml or compatible tools.

npm i -g msdf-bmfont-xml
msdf-bmfont -f json -o Roboto-Black --font-size 64 ./Roboto-Black.ttf

This produces two files (the loader picks both up automatically):

  • Roboto-Black.json — glyph metrics, kerning, atlas layout
  • Roboto-Black.png — the MSDF atlas texture

Place them side-by-side and load the .json through PIXI Assets.


Loading Fonts

The package exports a PIXI Asset load parser, registered automatically as a PIXI extension when you import the library.

Loading by URL (texture resolved automatically)

import { Assets } from "pixi.js";
import { FontLoader } from "funky-pixi-text";

await Assets.load({
  src: "fonts/Roboto-Black.json",
  loadParser: FontLoader.name, // "MSDFFontLoaderExtension"
});

// Reference in Text() by the file base name
new Text("Hi", { fontName: "Roboto-Black" });

Loading multiple fonts

await Assets.load([
  { src: "fonts/Roboto-Black.json", loadParser: FontLoader.name },
  { src: "fonts/Tourney.json",      loadParser: FontLoader.name },
  { src: "fonts/Meddon-Regular.json", loadParser: FontLoader.name },
]);

Overriding the texture URL or font name

Pass data to override defaults:

await Assets.load({
  src: "fonts/MyFont.json",
  loadParser: FontLoader.name,
  data: {
    fontName: "MyCustomKey",         // key used by Text({ fontName })
    textureUrl: "fonts/[email protected]", // override atlas path
  },
});

The Text Class

Text extends PIXI.Container and emits a single batched PIXI.Mesh containing all glyphs.

Constructor

new Text(text: string, style: TextStyle)

Both arguments are required. The font referenced by style.fontName must already be loaded via Assets.

Instance methods

| Method | Description | |---|---| | setText(text: string): void | Replace the displayed string and rebuild the layout. | | setStyle(partial: Partial<TextStyle>): void | Update one or more style properties. Performs a uniform-only fast-path when possible; otherwise rebuilds geometry. | | setColor(color: number \| TextStyleGradient): void | Shortcut to change fill color or gradient (uniform-only update when shape unchanged). | | setSmoothing(value: number): void | Adjust edge AA smoothing (0.055.0). | | setKerning(enabled: boolean, scale?: number): void | Toggle kerning and optionally scale the kerning amount. | | getTextBounds(): PIXI.Rectangle | Returns the laid-out bounding box including padding for shadow / extrude / smoothing. | | debugKerning(): void | Logs all kerning pairs present in the font. | | destroy(options?): void | Frees geometry, material, shader, and removes the instance from internal tracking. |

Static methods

| Method | Description | |---|---| | Text.enableAutoConfigUpdate(ticker?: PIXI.Ticker): () => void | Begin watching the global performance config and rebuild all live Text instances when it changes. Returns a cleanup function. | | Text.disableAutoConfigUpdate(): void | Stop the global watcher. |


TextStyle Reference

type TextStyle = {
  fontName: string;          // REQUIRED — key used when font was loaded
  fontSize?: number;         // default 16 (logical pixels)
  color?: number | TextStyleGradient; // 0xRRGGBB or gradient object; default 0xffffff

  // Layout
  align?: "left" | "center" | "right" | "justify"; // default "left"
  anchorX?: number;          // 0..1 (0 = left, 0.5 = center, 1 = right); default 0
  anchorY?: number;          // 0..1 (0 = top,  0.5 = middle, 1 = bottom); default 0
  wordWrap?: boolean;        // default false
  maxWidth?: number;         // pixels, used with wordWrap and/or autoScale
  maxHeight?: number;        // pixels, used with autoScale
  autoScale?: boolean;       // shrink fontSize to fit maxWidth/maxHeight; default false
  leading?: number;          // extra px added to line height
  lineHeight?: number;       // override line height in pixels (0 = use font default)
  letterSpacing?: number;    // px added between characters
  kerning?: boolean;         // default true
  kerningScale?: number;     // multiplier for kerning amount; default 1.0

  // Effects
  stroke?: TextStyleStroke | null;
  dropShadow?: TextStyleDropShadow | null;
  extrude?: TextStyleExtrude | null;
  fillTexture?: TextStyleTextureFill | null;

  // Rendering
  smoothing?: number;        // edge AA half-width (0.05..5.0); default 0.02
  scale?: number;            // visual multiplier; default 1.0
  msdfSign?: number;         // 1 or -1; flip signed distance (rare)

  // Performance
  performanceMode?: "auto" | "high-quality" | "balanced" | "mobile-optimized";
  performanceConfig?: PerformanceConfig; // see below
};

Gradient

type TextStyleGradient = {
  type: "linear" | "circular";
  colors: number[];                       // 0xRRGGBB array (up to maxGradientStops)
  alphas?: number[];                      // matching per-stop alphas (0..1)
  stops?: number[];                       // matching positions (0..1)
  angle?: number;                         // degrees, linear only
  center?: { x: number; y: number };      // circular only, 0..1 in glyph space
  radius?: number;                        // circular only, 0..1; <=0 = auto
};

Stroke

type TextStyleStroke = {
  color: number;       // 0xRRGGBB
  width: number;       // 0..10 (px in MSDF distance units)
  smoothing?: number;  // 0..10, default 1.0
};

Drop Shadow

type TextStyleDropShadow = {
  color: number;     // 0xRRGGBB
  angle: number;     // degrees
  distance: number;  // px
  blur: number;      // 0..30 (clamped by performance config)
  alpha?: number;    // 0..1, default 1
};

Extrude (3D)

type TextStyleExtrude = {
  depth?: number;     // px, default 16
  steps?: number;     // raymarch steps (clamped by performance config), default 24
  angle?: number;     // degrees, direction of extrusion, default 45
  sideColor?: number; // 0xRRGGBB; defaults to a darker face color
};

Texture Fill

type TextStyleTextureFill = {
  url?: string;                         // image URL (loaded via Assets if not cached)
  assetId?: string;                     // OR an existing Assets alias
  uvScale?: [number, number];           // default [1,1]
  uvOffset?: [number, number];          // default [0,0]
  rotation?: number;                    // radians, default 0
  mix?: number;                         // 0..1, default 1
  colorAlpha?: number;                  // 0..1, default 1
  textureAlpha?: number;                // 0..1, default 1
  blendMode?: TextureBlendMode;         // "normal" | "multiply" | "screen" |
                                        // "overlay" | "softLight" | "hardLight" |
                                        // "colorDodge" | "colorBurn" |
                                        // "vividLight" | "linearLight" |
                                        // "luminosity" | "hue"
};

Usage Examples

Basic Text

const t = new Text("PIXI MSDF", {
  fontName: "Roboto-Black",
  fontSize: 64,
  color: 0xff8800,
  anchorX: 0.5,
  anchorY: 0.5,
});

Word Wrap and Auto-Scaling

// Fixed-width paragraph that wraps
const paragraph = new Text(
  "The quick brown fox jumps over the lazy dog.",
  {
    fontName: "Roboto-Black",
    fontSize: 32,
    wordWrap: true,
    maxWidth: 400,
    align: "justify",
    lineHeight: 40,
  },
);

// Shrink to fit a fixed box (no wrap)
const fit = new Text("LongHeadline", {
  fontName: "Roboto-Black",
  fontSize: 200,
  autoScale: true,
  maxWidth: 300,
  maxHeight: 80,
});

// Combine: wrap AND shrink so the wrapped block also fits a height
const fitAndWrap = new Text("A multi-line block that must fit.", {
  fontName: "Roboto-Black",
  fontSize: 80,
  wordWrap: true,
  autoScale: true,
  maxWidth: 300,
  maxHeight: 200,
});

Linear & Radial Gradients

// Linear gradient (top → bottom)
new Text("GRADIENT", {
  fontName: "Tourney",
  fontSize: 96,
  color: {
    type: "linear",
    angle: 90,
    colors: [0xff0066, 0xffff00, 0x00ccff],
    stops:  [0.0,     0.5,     1.0],
  },
});

// Radial / circular gradient
new Text("SUN", {
  fontName: "Tourney",
  fontSize: 96,
  color: {
    type: "circular",
    colors: [0xffffff, 0xffaa00, 0xff0000],
    center: { x: 0.5, y: 0.5 },
    radius: 0.7,
  },
});

Stroke / Outline

new Text("Outlined", {
  fontName: "Roboto-Black",
  fontSize: 72,
  color: 0xffffff,
  stroke: { color: 0x000000, width: 3, smoothing: 1 },
});

Drop Shadow

new Text("Shadowed", {
  fontName: "Roboto-Black",
  fontSize: 72,
  color: 0xffffff,
  dropShadow: {
    color: 0x000000,
    angle: 45,
    distance: 6,
    blur: 8,
    alpha: 0.6,
  },
});

3D Extrusion

new Text("3D!", {
  fontName: "Tourney",
  fontSize: 160,
  color: 0xffcc00,
  extrude: {
    depth: 24,
    steps: 16,
    angle: 60,
    sideColor: 0x885500,
  },
});

Texture Fill

import { Assets } from "pixi.js";

await Assets.load({ alias: "wood", src: "/images/wood.jpg" });

new Text("WOODEN", {
  fontName: "Roboto-Black",
  fontSize: 120,
  color: 0xffffff,
  fillTexture: {
    assetId: "wood",
    uvScale: [2, 2],
    rotation: 0.1,
    mix: 1,
    blendMode: "overlay",
  },
});

Updating Text and Style at Runtime

Text is constructed with (text, style). Change the displayed string with setText(), and edit visual properties with setStyle() (which uses a uniform-only fast-path without rebuilding the layout when possible):

label.setText("New string");

label.setColor(0x00ff88);
label.setSmoothing(0.05);
label.setKerning(true, 1.2);

label.setStyle({
  fontSize: 80,
  align: "center",
  dropShadow: { color: 0x000000, angle: 90, distance: 4, blur: 6 },
});

// Bounds (includes shadow/stroke/extrude padding)
const bounds = label.getTextBounds();
console.log(bounds.width, bounds.height);

// Clean up
label.destroy();

Performance System

The library ships with a tunable performance pipeline. Every Text instance compiles a shader variant based on a PerformanceConfig. Lower-tier configs disable features (shadow blur, gradients, extrusion, texture fill) and reduce supersampling / loop iterations to keep frame rates high on weak GPUs.

Presets

Built-in preset names:

type PerformancePresetName =
  | "ultra_low"     // no shadow blur / no gradients / no extrusion
  | "mobile_low"
  | "mobile_mid"
  | "mobile_high"
  | "desktop"
  | "ultra";        // 8x supersampling, max blur, max steps
import {
  setDefaultPreset,
  getPreset,
  getDefaultPerformanceConfig,
} from "funky-pixi-text";

setDefaultPreset("desktop");
const cfg = getDefaultPerformanceConfig();

Manual Configuration

Override the global config or pass a per-instance config:

import {
  setGlobalPerformanceConfig,
  mergePerformanceConfig,
  getPreset,
  Text,
} from "funky-pixi-text";

// Globally
setGlobalPerformanceConfig(
  mergePerformanceConfig(getPreset("mobile_mid"), {
    maxShadowBlurRadius: 6,
    enableExtrusion: false,
  }),
);

// Or per instance
new Text("Fast", {
  fontName: "Roboto-Black",
  fontSize: 48,
  performanceConfig: getPreset("mobile_low"),
});

You can also load presets from JSON at startup:

import { loadPresetsFromUrl } from "funky-pixi-text";
await loadPresetsFromUrl("/performance-presets.json");

Auto-Detection

import {
  detectPerformancePreset,
  detectPerformancePresetAsync,
  detectWebGLCapabilities,
} from "funky-pixi-text";

const preset = detectPerformancePreset();           // sync, heuristic
const detected = await detectPerformancePresetAsync(); // async, includes GPU benchmark
const caps = detectWebGLCapabilities();

Runtime Adaptive Monitoring

PerformanceMonitor watches FPS, memory pressure, thermal state, battery state, and GPU memory pressure, then steps presets up or down at runtime. Combine with Text.enableAutoConfigUpdate so every live text instance reacts to the changes.

import { PerformanceMonitor, Text } from "funky-pixi-text";
import { Ticker } from "pixi.js";

Text.enableAutoConfigUpdate();

const monitor = new PerformanceMonitor({
  targetFPS: 60,
  autoAdjust: true,
  autoUpdateGlobalConfig: true,
  checkMemoryPressure: true,
  checkThermalState: true,
  checkBatteryState: true,
  respectReducedMotion: true,
  onPerformanceChange: (preset, fps) => {
    console.log(`Switched to '${preset}' at ${fps.toFixed(1)} fps`);
  },
});

Ticker.shared.add(() => monitor.update());

Coming Soon

We're actively working on the next generation of tooling and platform support:

  • Text Style Editor — a standalone application for designing text styles visually. It will:
    • Export ready-to-use JSON style files you can drop straight into Text.
    • Generate MSDF (Multi-channel Signed Distance Field) font atlases directly from .ttf and .otf font files — no separate CLI tooling required.
    • Let you configure and live-test performance configuration presets so you can dial in the right quality/performance balance before shipping.
  • PIXI.js v8 support — a version of the library targeting PIXI.js v8 is in development.

Stay tuned!


Architecture

                ┌──────────────────────────┐
                │           Text           │   PIXI.Container facade
                └────────────┬─────────────┘
                             │
              ┌──────────────┼─────────────────────────┐
              ▼              ▼                         ▼
        getLayout()    ShaderAssembler            PerformanceConfig
        (layout/)      (renderer/multipass        (renderer/)
                        + passes + shaders)
              │              │
              ▼              ▼
           LayoutData    PIXI.Shader + uniforms
              └───────────┬──┘
                          ▼
                   PIXI.Mesh (one draw call)
  • src/Text.ts – facade Text class extending PIXI.Container. Owns text + style state, computes auto-scale, builds geometry, drives uniform updates.
  • src/layout/ – pure layout engine (getLayout) that converts characters into per-glyph positions, lines, kerning, wrap, alignment. Plus FontCache and Kerning helpers.
  • src/renderer/ – multi-pass shader assembler. Composable passes (BaseTextPass, StrokePass, GradientPass, TextureFillPass, ExtrudePass, DropShadowPass) are assembled by ShaderAssembler into a single shader program tuned by the active PerformanceConfig.
  • src/fontLoader/FontLoader.ts – PIXI Assets load parser that pulls in the BMFont JSON plus its companion PNG atlas and caches a LoadedFont (texture + metrics).
  • src/utils/ – default style construction, path helpers, and small utilities.

Development

# Install dependencies
npm install

# Build the library (type declarations + CJS/ESM bundles into dist/)
npm run build

# Run the test suite
npm test

License

This software is distributed under a custom proprietary license — see license.txt. Use and redistribution of the unmodified package are permitted for personal and commercial purposes; modification, derivative works, and reverse engineering are prohibited.