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

@pilates/render

v1.0.2

Published

Out-of-box renderer for @pilates/core. Declarative tree to ANSI-styled string.

Readme

@pilates/render

Out-of-box renderer for @pilates/core. Declarative POJO tree → painted ANSI string with borders, titles, colors, and text wrap.

Install

npm install @pilates/render

@pilates/core is a peer of this package's runtime dep — installing @pilates/render pulls it in automatically.

Quick start

import { render } from '@pilates/render';

const out = render({
  width: 80,
  height: 5,
  flexDirection: 'row',
  children: [
    { flex: 1, border: 'rounded', title: 'Logs', children: [{ text: 'user logged in' }] },
    { width: 20, border: 'single', title: 'Status', children: [{ text: 'ok', color: 'green', bold: true }] },
  ],
});

process.stdout.write(out);
// ╭─ Logs ───────────────────────────────────────────────────╮┌─ Status ─────────┐
// │user logged in                                            ││ok                │
// │                                                          ││                  │
// ╰──────────────────────────────────────────────────────────╯└──────────────────┘

Tree shape

A RenderNode is either a container (with optional children) or a text leaf (with a text property). Both share the layout properties from @pilates/core, expressed as plain object fields.

import type { RenderNode } from '@pilates/render';

const tree: RenderNode = {
  width: 40, height: 10,
  flexDirection: 'column',
  padding: 1,
  children: [
    { height: 1, children: [{ text: 'header', bold: true }] },
    { flex: 1, border: 'single', children: [{ text: 'body content' }] },
  ],
};

Style options

| Category | Properties | |---|---| | Layout | All of @pilates/core's setters as POJO fields: flexDirection, flex, width, height, padding, margin, gap, justifyContent, alignItems, alignSelf, alignContent, flexWrap, positionType, position, display, etc. | | Border | border (5 styles), borderColor, title, titleColor | | Text | color, bgColor, bold, italic, underline, dim, inverse, wrap ('wrap' / 'truncate' / 'none') |

Border styles

Set border: '<style>' on any container:

single   ┌─────┐    rounded  ╭─────╮    double  ╔═════╗    bold  ┏━━━━━┓
         │     │             │     │            ║     ║          ┃     ┃
         └─────┘             ╰─────╯            ╚═════╝          ┗━━━━━┛

'none' (the default) draws nothing. title is rendered inline at the top edge with surrounding padding (┌─ Title ───┐); titles longer than the available run are truncated with .

Colors

Three formats, accepted everywhere a color is expected (color, bgColor, borderColor, titleColor):

{ text: 'red',     color: 'red'      }   // 16 named colors
{ text: 'orange',  color: '#ff5500'  }   // 24-bit hex
{ text: 'palette', color: 208       }   // 256-color index

Named: black, red, green, yellow, blue, magenta, cyan, white, gray, plus the eight bright* variants.

API

import { render, renderToFrame, Frame } from '@pilates/render';

render(tree: RenderNode, options?: { ansi?: boolean }): string
renderToFrame(tree: RenderNode): Frame
  • render(tree, { ansi }) — paints the tree and returns a printable string. ANSI is auto-stripped when stdout is not a TTY (e.g. piped output); set ansi: true or false to override.
  • renderToFrame(tree) — returns the underlying Frame (2D cell grid). Use this to drive diff-based redraws via @pilates/diff, to inspect cells in tests, or to write your own ANSI emitter.

Low-level SGR helpers (added in 1.0.0-rc.2)

For consumers building alternative renderers that need to match this package's output byte-for-byte:

import {
  Cell, CellStyle, Rect, Attr,
  SGR_RESET, attrsSgr, bgSgr, fgSgr, packAttrs, sgr,
} from '@pilates/render';
  • Cell / CellStyle / Rect — the cell-grid value types
  • Attr — bitmask enum (Bold, Dim, Italic, Underline, Inverse)
  • fgSgr(color) / bgSgr(color) — SGR parameter for fg/bg color
  • attrsSgr(bitmask) — SGR parameters for an attribute bitmask
  • sgr(params) — wrap a parameter list in \x1b[...m
  • SGR_RESET\x1b[0m
  • packAttrs(style) — pack a TextStyle bag into a numeric bitmask

@pilates/diff uses exactly these helpers, so its output matches what render() would emit for the same cells.

TTY handling

By default, render() checks process.stdout.isTTY:

| Context | ANSI emitted? | |---|---| | Interactive terminal (TTY) | Yes | | Piped/redirected output | No (escapes stripped) | | Non-Node runtimes | Yes |

Override explicitly when you need to force one or the other (snapshot tests, capturing output for a log file, etc.):

render(tree, { ansi: true })   // force ANSI on
render(tree, { ansi: false })  // strip ANSI even in a TTY

Status

Release candidate (1.0.0-rc.2). API is stable for render, renderToFrame, and the low-level SGR helpers.

License

MIT