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

@beamterm/renderer

v0.12.0

Published

High-performance WebGL2 terminal renderer with sub-millisecond render times

Readme

@beamterm/renderer

npm version License: MIT

High-performance WebGL2 terminal renderer achieving sub-millisecond render times through GPU-accelerated instanced rendering.

✨ Features

  • 📦 Zero Dependencies: Pure WASM + WebGL2, no external runtime dependencies
  • 🎨 Rich Text Styling: Bold, italic, underline, strikethrough with full color support
  • ⚡ Efficient Updates: Batch cell updates with single GPU buffer upload
  • 📐 Responsive: Automatic terminal resizing with proper aspect ratio maintenance
  • 🎯 TypeScript Ready: Full TypeScript definitions included
  • 🖱️ Mouse Selection: Built-in text selection with clipboard integration

📋 Requirements

  • WebGL2 capable browser
  • WASM support

Should work with any modern browser.

📦 Installation

NPM/Yarn

npm install @beamterm/renderer
# or
yarn add @beamterm/renderer

CDN

<script src="https://unpkg.com/@beamterm/renderer@latest/dist/cdn/beamterm.min.js"></script>
<script>
    await Beamterm.init();
    const renderer = new Beamterm.BeamtermRenderer('#terminal');
    // SelectionMode available as Beamterm.SelectionMode
    renderer.enableSelection(Beamterm.SelectionMode.Linear, true);
</script>

🚀 Quick Start

ES Modules (Recommended)

import { main as init, style, cell, BeamtermRenderer, SelectionMode } from '@beamterm/renderer';

// Initialize WASM module
await init();

// Create renderer with embedded static atlas (default)
const renderer = new BeamtermRenderer('#terminal');

// Or use a dynamic font atlas with any system font
const dynamicRenderer = BeamtermRenderer.withDynamicAtlas(
    '#terminal',
    ['JetBrains Mono', 'Fira Code'],  // font fallback chain
    16.0                               // font size in pixels
);

// Get terminal dimensions
const size = renderer.terminalSize();
console.log(`Terminal: ${size.width}×${size.height} cells`);

// Create a batch for efficient updates
const batch = renderer.batch();

// Clear terminal with background color
batch.clear(0x1a1b26);

// Write styled text
const textStyle = style().bold().underline().fg(0x7aa2f7).bg(0x1a1b26);
batch.text(2, 1, "Hello, Beamterm!", textStyle);

// Draw individual cells
batch.cell(0, 0, cell("🚀", style().fg(0xffffff)));

// Fill a rectangular region
const boxStyle = style().fg(0x565f89).bg(0x1a1b26);
batch.fill(1, 0, 18, 3, cell("█", boxStyle));

// Render frame
renderer.render();

TypeScript

import { main as init, style, BeamtermRenderer, Batch, Size, SelectionMode } from '@beamterm/renderer';

async function createTerminal(): Promise<void> {
  await init();
  
  const renderer = new BeamtermRenderer('#terminal');
  const batch: Batch = renderer.batch();
  
  // TypeScript provides full type safety
  const labelStyle = style()
    .bold()
    .italic()
    .underline()
    .fg(0x9ece6a)
    .bg(0x1a1b26);
    
  batch.text(0, 0, "TypeScript Ready! ✨", labelStyle);
  batch.flush();
  renderer.render();
}

📖 API Reference

BeamtermRenderer

The main renderer class that manages the WebGL2 context and rendering pipeline.

// Using embedded static font atlas (default)
const renderer = new BeamtermRenderer(canvasSelector);

// Using dynamic font atlas with browser fonts
const renderer = BeamtermRenderer.withDynamicAtlas(canvasSelector, fontFamilies, fontSize);

Static Methods

  • withDynamicAtlas(canvasSelector, fontFamilies, fontSize): Create a renderer with a dynamic font atlas that rasterizes glyphs on-demand using browser fonts. Best when character set isn't known at build time.
    • canvasSelector: CSS selector for the canvas element
    • fontFamilies: Array of font family names (e.g., ['JetBrains Mono', 'Fira Code'])
    • fontSize: Font size in pixels

Methods

  • batch(): Create a new batch for efficient cell updates
  • render(): Render the current frame to the canvas
  • resize(width, height): Resize the canvas and recalculate terminal dimensions
  • terminalSize(): Get terminal dimensions as { width, height } in cells
  • cellSize(): Get cell dimensions as { width, height } in pixels

Selection Methods

  • enableSelection(mode, trimWhitespace): Enable built-in text selection
  • setMouseHandler(callback): Set custom mouse event handler
  • getText(query): Get selected text based on cell query
  • copyToClipboard(text): Copy text to system clipboard
  • clearSelection(): Clear any active selection
  • hasSelection(): Check if there is an active selection

Batch

Batch operations for efficient GPU updates. All cell modifications should go through a batch.

const batch = renderer.batch();

Methods

  • clear(backgroundColor): Clear entire terminal with specified color
  • cell(x, y, cellData): Update a single cell
  • cells(cellArray): Update multiple cells (array of [x, y, cellData])
  • text(x, y, text, style): Write text starting at position
  • fill(x, y, width, height, cellData): Fill rectangular region
  • flush(): Upload all changes to GPU (required before render)

CellStyle

Fluent API for text styling.

const myStyle = style()
  .bold()
  .italic()
  .underline()
  .strikethrough()
  .fg(0x7aa2f7)
  .bg(0x204060);

Methods

  • fg(color): Set foreground color
  • bg(color): Set background color
  • bold(): Add bold style
  • italic(): Add italic style
  • underline(): Add underline effect
  • strikethrough(): Add strikethrough effect

Properties

  • bits: Get the combined style bits as a number

Helper Functions

  • style(): Create a new CellStyle instance
  • cell(symbol, style): Create a cell data object

Enums

SelectionMode

  • SelectionMode.Linear: Linear text flow selection (like normal terminals)
  • SelectionMode.Block: Rectangular block selection (like text editors)

Cell Data Structure

{
  symbol: string,    // Single character or emoji
  style: number,     // Style bits or CellStyle.bits
  fg: number,        // Foreground color (0xRRGGBB)
  bg: number         // Background color (0xRRGGBB)
}

Color Format

Colors are 24-bit RGB values in hex format:

const white = 0xffffff;
const black = 0x000000;
const red = 0xff0000;
const tokyoNightBg = 0x1a1b26;

🎯 Common Patterns

Animation Loop

function animate() {
  const batch = renderer.batch();
  
  // Update terminal content
  batch.clear(0x1a1b26);
  batch.text(0, 0, `Frame: ${Date.now()}`, style().fg(0xc0caf5));
  
  // Flush and render
  batch.flush();
  renderer.render();
  
  requestAnimationFrame(animate);
}

Responsive Terminal

window.addEventListener('resize', () => {
  const canvas = document.getElementById('terminal');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  
  renderer.resize(canvas.width, canvas.height);
  redrawTerminal();
});

Efficient Mass Updates

// Use batch.text() for uniform styling (fastest)
batch.text(0, 0, "Hello World", style().bold().fg(0x7aa2f7));

// Use batch.cells() for mixed styling
const mixedCells = [
  [0, 1, cell("R", style().bold().fg(0xf7768e))],    // Red bold
  [1, 1, cell("G", style().italic().fg(0x9ece6a))],  // Green italic  
  [2, 1, cell("B", style().underline().fg(0x7aa2f7))], // Blue underline
];
batch.cells(mixedCells);

Text Selection

// Enable built-in selection with linear mode
renderer.enableSelection(SelectionMode.Linear, true);

// Or use custom mouse handling
renderer.setMouseHandler((event) => {
  console.log(`Mouse ${event.event_type} at ${event.col},${event.row}`);
});

🎮 Examples

Check out the examples/ directory for complete examples:

📊 Performance Guidelines

Optimal Usage Patterns

  • batch.text() - Use for strings with uniform styling (fastest)
  • 🎨 batch.cells() - Use when cells need different styles/colors
  • 📦 batch.fill() - Use for large rectangular regions
  • 🚫 Avoid converting uniform text to individual cells

Performance Tips

  • Batch all updates in a single render cycle
  • Call batch.flush() only once per frame
  • Prefer batch.text() over multiple batch.cell() calls
  • Reuse style objects when possible

📄 License

MIT License - see LICENSE for details.

🔗 Links