DENSE TEXT INFRASTRUCTURE FOR PIXIJS 8

Render text at
scene scale.

One retained layer for a million labels, compact glyph batches, incremental updates, CJKV and complex-script shaping, and camera-aware culling across WebGL and WebGPU.

Resident labels
1,000,000
Language path
CJKV + 7 scripts
Fixed CPU store
72 MiB
Renderer path
WebGL 2 + WebGPU
Preparing the renderer…

01 / START

Keep the public surface small.

Create labels synchronously, then publish accepted work through one explicit commit boundary. Stable identities keep hot updates compact.

Install

Terminal
bun add pixi-glyphflow pixi.js pixi-viewport

Create one retained layer

TypeScript
import { Application } from "pixi.js";
import { TextLayer } from "pixi-glyphflow";

const app = new Application();
await app.init({
  resizeTo: window,
  preference: ["webgpu", "webgl"],
  webgl: { preferWebGLVersion: 2 },
});
document.body.appendChild(app.canvas);

const labels = new TextLayer({
  renderer: app.renderer,
  initialCapacity: 1_000_000,
  culling: {
    bounds: { x: 0, y: 0, width: 1280, height: 720 },
    padding: 32,
  },
});
app.stage.addChild(labels);

labels.create({
  text: "Shanghai 24 C",
  x: 24,
  y: 32,
  style: { fontFamily: "Inter", fontSize: 18, fill: 0xffffff },
});

await labels.commit();

Vite builds use an ES module worker and an ES2022 target for the lazy HarfBuzz pipeline. This site runs that production configuration.

02 / VIEWPORT

Camera work stays camera work.

The binding converts visible viewport corners into layer-local bounds and coalesces drag, inertia, wheel, pinch, zoom, and rotation into one culling commit per frame.

Bind the camera

TypeScript
import { Viewport } from "pixi-viewport";
import { bindViewport } from "pixi-glyphflow/viewport";

const viewport = new Viewport({
  screenWidth: app.screen.width,
  screenHeight: app.screen.height,
  worldWidth: 18_000,
  worldHeight: 12_000,
  events: app.renderer.events,
});

viewport.drag().decelerate().wheel().pinch();
app.stage.addChild(viewport);

const binding = bindViewport(labels, viewport, { addChild: true });
await binding.whenIdle();

Move 100,000 labels

TypeScript
const movingIds = new Float64Array(100_000);
const positions = new Float32Array(200_000);

// Fill identities from createMany() and write packed x/y pairs.
labels.updatePositions(movingIds, positions);
await labels.commit();

console.table({
  revision: labels.stats.revision,
  visible: labels.stats.visibleLabelCount,
  glyphs: labels.stats.submittedGlyphs,
});

01 Camera frames preserve label revisions and shaped glyph runs.

02 Packed Float32 coordinates keep the movement path allocation-light.

03 Every binding listener leaves through one idempotent destroy path.

03 / FONTS

Shape the language. Keep the font choice explicit.

Binary fonts travel through HarfBuzz and glyph-ID MSDF generation. This live chain covers CJKV, Arabic, Devanagari, Hebrew, Thai, Greek, Cyrillic, Vietnamese, and emoji.

Register a custom CJKV font

TypeScript
const productFonts = [
  ["Product CJKV", "/fonts/product-cjkv.ttf"],
  ["Product Arabic", "/fonts/product-arabic.ttf"],
  ["Product Devanagari", "/fonts/product-devanagari.ttf"],
  ["Product Hebrew", "/fonts/product-hebrew.ttf"],
  ["Product Thai", "/fonts/product-thai.ttf"],
] as const;

await Promise.all(
  productFonts.map(async ([family, url]) => {
    const source = new Uint8Array(
      await fetch(url).then((response) => response.arrayBuffer()),
    );
    await labels.fonts.register({ family, source });
  }),
);

labels.fonts.registerFallback("global-ui", [
  ...productFonts.map(([family]) => family),
  "system-ui",
  "PingFang SC",
  "Hiragino Sans",
  "Apple SD Gothic Neo",
  "sans-serif",
]);

labels.create({
  text: "日本語 · 東京テキスト",
  style: { fontFamily: "global-ui", fontSize: 24 },
  shaping: {
    language: "ja",
    script: "Jpan",
    features: ["kern", "liga"],
    variations: { wght: 560 },
  },
});

await labels.commit();

01 Language and script tags select localized OpenType glyphs.

02 Glyph ID coverage advances through custom binary families in order.

03 CSS family stacks reach PixiJS layout and Canvas rasterization intact.

04 / PERFORMANCE

Measured under pressure.

Committed Chrome and WebGL 2 artifacts use isolated processes, GPU completion, warmup frames, and p95 reporting on an Apple M1 Pro.

Reference performance results
WorkloadScaleFrame p95
Million-label viewport1,000,000 resident5.20 ms
Viewport drag + inertia1,000,000 resident5.40 ms
Wheel + pinch zoom1,000,000 resident7.10 ms
Position storm100,000 packed moves9.00 ms
Dynamic counters100,000 text + position14.80 ms
Read the benchmark method and raw-artifact index

05 / ARCHITECTURE

One revision, four bounded stages.

Each stage owns a deep implementation boundary. The application learns one label model and one commit lifecycle.

  1. 01
    StoreDense identities + dirty journal
  2. 02
    ShapeLayout + HarfBuzz worker
  3. 03
    ResidentAtlas + glyph instances
  4. 04
    SubmitWebGL / WebGPU adapter

06 / API

Focused entry points.

Core usage stays on the root import. Optional integrations remain isolated so applications carry the surfaces they use.

Package paths

pixi-glyphflow
TextLayer, FontRegistry, and primary types
pixi-glyphflow/viewport
Frame-coalesced pixi-viewport binding
pixi-glyphflow/shaping
HarfBuzz main-thread and worker shapers
pixi-glyphflow/accessibility
Sparse semantic DOM mirror
pixi-glyphflow/advanced
Atlas, mesh, layout, upload, and spatial primitives

TextLayer essentials

createMany(specs)
Create a validated batch and return stable TextIds.
updatePositions(ids, xy)
Apply packed position changes in one columnar pass.
updateTextPositions(ids, text, xy)
Broadcast dynamic text with packed positions.
showAll() / hideAll()
Toggle every resident label through one columnar mutation.
commit()
Publish one monotonic revision through render and culling work.
setViewportBounds(bounds)
Select the resident subset submitted to the renderer.
stats
Read immutable capacity, culling, upload, draw, and timing diagnostics.

07 / GUIDES

Follow the operating path.

The maintained Markdown set carries complete contracts, compatibility boundaries, benchmark evidence, and migration detail.