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

glyphforge

v0.1.0

Published

Drop-in WebGL ASCII hero sections for React. One component, any 3D model — or forge one in the browser from text, SVG, an image, or a parametric shape.

Readme

Glyphforge

Drop-in WebGL ASCII hero sections for React — and a model forge so you don't have to go find a .glb first.

npm install glyphforge three @react-three/fiber @react-three/postprocessing postprocessing
import { GlyphHero } from "glyphforge"

<GlyphHero model={{ type: "text", value: "SHIP IT" }} preset="matrix" />

That's the whole integration. No boilerplate repo to clone, no demo asset to delete, no scale={8} to hand-tune.


Why this exists

Every ASCII-hero demo hands you a repo to fork and then tells you to "replace user-model.glb with your own". That one line is the entire problem — most people don't have a .glb, and getting one means Blender, a marketplace, or a licence you didn't read.

Glyphforge builds the model in the browser instead. Type a word. Drop a PNG. Paste an SVG. Pick a parametric shape. You get real geometry you can also export as a standard .glb and use anywhere else.


Model sources

Everything below runs client-side. No backend, no API key, no upload.

| Source | What it does | | --- | --- | | text | Extrudes live browser text into 3D. Any font the page can render — webfonts and emoji included. No .typeface.json conversion. | | image | relief displaces a grid by luminance (photos, depth maps). extrude traces the silhouette and pushes it out (flat logos, icons). | | svg | Filled paths become extruded 3D, with counters resolved as real holes. | | shape | Nine parametric primitives with seeded distortion — deterministic, instant, zero assets. | | url | Your own .glb / .gltf. Auto-fitted and centred on load. |

<GlyphHero model={{ type: "text", value: "ACME", font: "900 200px Georgia", depth: 0.4 }} />
<GlyphHero model={{ type: "image", src: "/logo.png", mode: "extrude" }} />
<GlyphHero model={{ type: "svg", src: "/mark.svg", depth: 0.3 }} />
<GlyphHero model={{ type: "shape", shape: "crystal", distortion: 0.5, seed: 7 }} />
<GlyphHero model={{ type: "url", src: "/models/mine.glb" }} />

Browsers don't expose glyph outlines, so text rasterises the string and traces it with marching squares, nests the contours to find holes, and extrudes the result. That same tracer powers image extrude mode.

Forge without rendering

import { forgeGeometry, exportModel } from "glyphforge/forge"

const geometry = await forgeGeometry({ type: "text", value: "HELLO" })
const blob = await exportModel(geometry) // a real .glb

Presets

terminal · matrix · blueprint · brutalist · glitch · chromatic · paper

<GlyphHero preset="matrix" />                 // start from a preset
<GlyphHero preset="matrix" cellSize={12} />   // override anything

Build one interactively in the Studio and copy the generated component out.


Components

<GlyphHero />

A complete hero section: canvas plus your content.

<GlyphHero model={{ type: "shape", shape: "torusKnot" }} preset="terminal" layout="overlay">
  <h1>Your headline</h1>
</GlyphHero>
  • layout="overlay" — content centred over the canvas (default)
  • layout="split" — content one side, canvas the other (canvasSide="left" | "right")

<GlyphCanvas />

Just the WebGL surface, filling its container. Use it when you already have a layout.

<AsciiEffect />

The raw post-processing pass, for your own R3F scene:

<EffectComposer>
  <AsciiEffect characterSet="terminal" tint="#917AFF" cellSize={9} />
</EffectComposer>

Props

Look

| Prop | Default | | | --- | --- | --- | | preset | "terminal" | Starting point; every other prop overrides it | | cellSize | 9 | Character cell size in px. Smaller = finer and costlier | | characterSet | "terminal" | Ramp name, your own string[] (sparse→dense), or null for procedural glyphs | | glyphStyle | "standard" | Procedural style when characterSet is null: standard · dense · minimal · blocks | | tint | preset | One flat colour for every glyph. Omit to keep scene colour | | invert | true | Flip brightness→density | | volumeShading | true | Widen the range so shadows read dense, highlights sparse | | transparent | false | Composite over the host page instead of an opaque background | | backgroundColor | "#000000" | Opaque-mode background | | postfx | preset | Scanlines, curvature, vignette, glitch, grain, aberration, pointer glow, fps lock |

Built-in ramps: terminal classic blocks shades dots binary katakana runic.

Scene

| Prop | Default | | | --- | --- | --- | | cameraZ | "auto" | Frames the model for the current viewport. Set a number to pin it | | maxDpr | 1.5 | Pixel-ratio ceiling | | pauseOffscreen | true | Stop rendering when scrolled out of view | | motion | | autoRotate, hoverBoost, hoverZoom, draggable, tilt, animation, animationSpeed, respectReducedMotion | | controls | off | Viewport navigation: zoom, pan, zoomRange, resetToken | | material | | color, roughness, metalness, keepMaterials | | fallback / errorFallback | | Loading and failure UI |

cameraZ="auto" matters more than it sounds: a long word auto-fits to a wide, flat mesh, and a fixed camera distance would render it as an unreadable sliver.

Camera controls

<GlyphCanvas controls={{ zoom: true, pan: true }} />

Scroll or pinch to zoom, shift/middle/right-drag to pan, double-click to reset. Left-drag still rotates the model.

Both are off by default, and that default is deliberate: a hero section that captures the wheel stops the page scrolling the moment the pointer crosses it, which visitors read as the site being broken. Turn them on for editors and viewers — the Studio does.

Zoom is a multiplier on the auto-framed distance rather than an absolute position, so resizing the window still reframes correctly without discarding where the viewer had zoomed to.

Animation

Embedded glTF clips play automatically:

<GlyphCanvas
  model={{ type: "url", src: "/models/walk.glb" }}
  motion={{ animation: "Walk", animationSpeed: 0.8 }}
/>

animation takes true (first clip), a clip name, or false. Rigged models are cloned with SkeletonUtils, so skinned meshes keep their own bones. Playback stops for prefers-reduced-motion and while the hero is offscreen.


Behaviour worth knowing

  • Reduced motion — auto-rotation and time-driven effects stop when the visitor has prefers-reduced-motion: reduce. Dragging still works.
  • Offscreen — the render loop pauses when the hero scrolls away.
  • No WebGL — renders a quiet fallback instead of a blank rectangle.
  • No network at runtime — lighting comes from a procedurally generated environment, not a CDN-hosted HDR.
  • Multiple instances — every effect owns its state, so two heroes on one page don't fight over settings or share a clock.

CLI

npx glyphforge init --yes   # detect framework, install peers, scaffold a component
npx glyphforge add hero     # copy the real source into your repo — you own it
npx glyphforge list         # what `add` can copy

add copies the actual library source (not a duplicated template), so ejected code never drifts from the package.


Requirements

React 18+, and three ≥ 0.155 with @react-three/fiber, @react-three/postprocessing, postprocessing as peers.

.glb files with Draco or KTX2 compression need their loaders configured — decode them ahead of time, or forge the model here instead.


Licence

MIT — see LICENSE.

The GLSL ASCII shader and the glyph-atlas approach are derived from webgl-ascii-hero by egorshest, also MIT. See NOTICE for the full attribution.