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

@wolf-tui/core

v1.3.3

Published

Framework-agnostic TUI core library

Readme

@wolf-tui/core

Framework-agnostic TUI core engine for wolf-tui. Provides DOM abstraction, layout engine, and rendering primitives.

Overview

This package is the foundation of wolf-tui. It provides:

  • DOM abstraction — Virtual DOM nodes for TUI elements
  • Taffy layout engine — Flexbox and CSS Grid via Rust bindings
  • Renderer — Converts DOM tree to ANSI terminal output
  • Utilities — Text measurement, keypress parsing, color handling

Note: This is an internal package. Most users should use @wolf-tui/react, @wolf-tui/vue, or @wolf-tui/angular instead.

Taffy Layout Engine

wolf-tui v2.0 uses Taffy, a high-performance Rust-based layout engine.

Why Taffy?

| Feature | Yoga (old) | Taffy (current) | | ----------- | -------------- | --------------- | | Flexbox | Yes | Yes | | CSS Grid | No | Yes | | calc() | No | Yes | | Framework | React-specific | Agnostic | | Performance | Good | Better |

Integration

Taffy is integrated via napi-rs native Node.js bindings:

internal/core/
├── rust/
│   ├── lib.rs       # napi-rs entry point
│   ├── layout.rs    # LayoutTree wrapper
│   ├── style.rs     # Style conversion
│   └── error.rs     # Error handling
├── Cargo.toml
└── layout.js        # Generated JS bindings

Platform Support

| Platform | Architecture | Binary | | -------- | ------------ | ------------------------------------ | | Linux | x86_64 | wolfie-layout.linux-x64-gnu.node | | Linux | aarch64 | wolfie-layout.linux-arm64-gnu.node | | macOS | x86_64 | wolfie-layout.darwin-x64.node | | macOS | aarch64 | wolfie-layout.darwin-arm64.node | | Windows | x86_64 | wolfie-layout.win32-x64-msvc.node |

Building Native Bindings

cd internal/core
pnpm build:rust    # Build native bindings only
pnpm build:full    # Build Rust + TypeScript

Requires Rust toolchain installed.


API Reference

DOM Functions

createNode(name, layoutTree)

Create a new DOM element.

import { createNode, LayoutTree } from '@wolf-tui/core'
import { LayoutTree as TaffyLayoutTree } from '@wolf-tui/core/layout'

const layoutTree = new TaffyLayoutTree()
const node = createNode('wolfie-box', layoutTree)

appendChildNode(parent, child)

Append a child node to a parent.

appendChildNode(parent, child)

insertBeforeNode(parent, child, before)

Insert a child before another node.

insertBeforeNode(parent, newChild, referenceChild)

removeChildNode(parent, child)

Remove a child from parent.

removeChildNode(parent, child)

setAttribute(node, key, value)

Set an attribute on a node.

setAttribute(node, 'className', 'my-class')

setStyle(node, style)

Set style properties on a node.

setStyle(node, {
	flexDirection: 'column',
	padding: 1,
	borderStyle: 'round',
})

createTextNode(value, layoutTree)

Create a text node.

const textNode = createTextNode('Hello', layoutTree)

setTextNodeValue(node, value)

Update text node content.

setTextNodeValue(textNode, 'Updated text')

Renderer

renderer(rootNode, isScreenReaderEnabled, layoutTree)

Render DOM tree to terminal output.

import { renderer } from '@wolf-tui/core'

const { output } = renderer(rootNode, false, layoutTree)
process.stdout.write(output)

Returns:

  • output — ANSI-styled string for terminal
  • outputHeight — Number of lines

Layout

getComputedLayout(node, layoutTree)

Get computed layout for a node.

import { getComputedLayout } from '@wolf-tui/core'

const layout = getComputedLayout(node, layoutTree)
// { left: 0, top: 0, width: 80, height: 24 }

Returns ComputedLayout:

  • left — X position
  • top — Y position
  • width — Computed width
  • height — Computed height

isDisplayNone(node, layoutTree)

Check if node is hidden.

if (isDisplayNone(node, layoutTree)) {
	// Node not rendered
}

Styles

applyLayoutStyle(layoutTree, nodeId, style)

Apply style to layout node.

import { applyLayoutStyle } from '@wolf-tui/core'

applyLayoutStyle(layoutTree, node.layoutNodeId, {
	flexDirection: 'column',
	padding: 2,
})

resolveViewportUnits(style, terminalWidth, terminalHeight)

Resolve vw/vh units to absolute values.

import { resolveViewportUnits } from '@wolf-tui/core'

const resolved = resolveViewportUnits(
	{ width: '50vw', height: '100vh' },
	80, // terminal columns
	24 // terminal rows
)
// { width: 40, height: 24 }

parseNumericValue(value)

Parse numeric style value.

parseNumericValue('1rem') // 4
parseNumericValue('8px') // 2
parseNumericValue(10) // 10

Utilities

measureText(text)

Measure text dimensions.

import { measureText } from '@wolf-tui/core'

const { width, height } = measureText('Hello\nWorld')
// { width: 5, height: 2 }

wrapText(text, maxWidth, wrapMode)

Wrap text to fit width.

import { wrapText } from '@wolf-tui/core'

const wrapped = wrapText('Long text here', 10, 'wrap')

Wrap modes:

  • 'wrap' — Wrap at word boundaries
  • 'truncate' / 'truncate-end' — Truncate with ellipsis at end
  • 'truncate-start' — Truncate with ellipsis at start
  • 'truncate-middle' — Truncate with ellipsis in middle

parseKeypress(input)

Parse terminal keypress data.

import { parseKeypress } from '@wolf-tui/core'

const key = parseKeypress('\x1b[A') // Up arrow
// { name: 'up', ctrl: false, shift: false, meta: false, ... }

colorize(text, color, backgroundColor)

Apply ANSI colors to text.

import { colorize } from '@wolf-tui/core'

const colored = colorize('Hello', 'green', 'black')

measureElement(node)

Measure a rendered element.

import { measureElement } from '@wolf-tui/core'

const { width, height } = measureElement(node)

Log Update

logUpdate.create(stream)

Create a log updater for a stream.

import { logUpdate } from '@wolf-tui/core'

const log = logUpdate.create(process.stdout)

log('First output')
log('Updated output') // Replaces previous
log.done() // Finalize

Methods:

  • log(text) — Update output (replaces previous)
  • log.clear() — Clear output
  • log.done() — Finalize and move cursor down

Types

DOMElement

Virtual DOM element.

interface DOMElement {
	nodeName: ElementNames
	style?: Styles
	attributes: Record<string, DOMNodeAttribute>
	childNodes: DOMNode[]
	parentNode?: DOMElement
	layoutNodeId?: number
	onRender?: () => void
}

Styles

Style properties.

interface Styles {
	// Layout
	display?: 'flex' | 'none'
	position?: 'relative' | 'absolute'
	flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse'
	flexWrap?: 'wrap' | 'nowrap' | 'wrap-reverse'
	flexGrow?: number
	flexShrink?: number
	flexBasis?: number | string
	alignItems?: 'flex-start' | 'center' | 'flex-end' | 'stretch'
	alignSelf?: 'flex-start' | 'center' | 'flex-end' | 'auto'
	justifyContent?:
		| 'flex-start'
		| 'center'
		| 'flex-end'
		| 'space-between'
		| 'space-around'
		| 'space-evenly'
	gap?: number
	rowGap?: number
	columnGap?: number

	// Sizing
	width?: number | string
	height?: number | string
	minWidth?: number
	minHeight?: number
	maxWidth?: number
	maxHeight?: number

	// Spacing
	padding?: number
	paddingX?: number
	paddingY?: number
	paddingTop?: number
	paddingRight?: number
	paddingBottom?: number
	paddingLeft?: number
	margin?: number
	marginX?: number
	marginY?: number
	marginTop?: number
	marginRight?: number
	marginBottom?: number
	marginLeft?: number

	// Border
	borderStyle?: 'single' | 'double' | 'round' | 'classic' | 'bold'
	borderColor?: string
	borderTopColor?: string
	borderRightColor?: string
	borderBottomColor?: string
	borderLeftColor?: string
	borderTop?: boolean
	borderRight?: boolean
	borderBottom?: boolean
	borderLeft?: boolean
	borderDimColor?: boolean

	// Text
	color?: string
	backgroundColor?: string
	fontWeight?: 'bold' | 'normal' | number
	fontStyle?: 'italic' | 'normal'
	textDecoration?: 'underline' | 'line-through' | 'none'
	textWrap?:
		| 'wrap'
		| 'truncate'
		| 'truncate-end'
		| 'truncate-middle'
		| 'truncate-start'
	dimColor?: boolean
	inverse?: boolean

	// Overflow
	overflow?: 'visible' | 'hidden'
	overflowX?: 'visible' | 'hidden'
	overflowY?: 'visible' | 'hidden'
}

LayoutTree

Layout tree interface (implemented by Taffy bindings).

interface LayoutTree {
	createNode(): number
	removeNode(nodeId: number): void
	setStyle(nodeId: number, style: Record<string, unknown>): void
	setTextDimensions(nodeId: number, width: number, height: number): void
	appendChild(parentId: number, childId: number): void
	insertChild(parentId: number, childId: number, index: number): void
	removeChild(parentId: number, childId: number): void
	computeLayout(rootId: number, availableWidth: number): void
	getLayout(nodeId: number): {
		x: number
		y: number
		width: number
		height: number
	}
}

Architecture

┌─────────────────────────────────────────────────────────────┐
│                Framework Adapters                            │
│              (React, Vue, Angular)                           │
└────────────────────────┬────────────────────────────────────┘
                         │
              ┌──────────▼──────────┐
              │   @wolf-tui/core      │
              │                     │
              │ ┌─────────────────┐ │
              │ │ DOM Abstraction │ │
              │ │  (dom.ts)       │ │
              │ └────────┬────────┘ │
              │          │          │
              │ ┌────────▼────────┐ │
              │ │ Style Handler   │ │
              │ │  (styles.ts)    │ │
              │ └────────┬────────┘ │
              │          │          │
              │ ┌────────▼────────┐ │
              │ │ Taffy Layout    │◀┼──── Rust Bindings
              │ │  (layout.rs)    │ │     (napi-rs)
              │ └────────┬────────┘ │
              │          │          │
              │ ┌────────▼────────┐ │
              │ │ Renderer        │ │
              │ │  (renderer.ts)  │ │
              │ └────────┬────────┘ │
              │          │          │
              │ ┌────────▼────────┐ │
              │ │ ANSI Output     │ │
              │ │  (output.ts)    │ │
              │ └─────────────────┘ │
              └─────────────────────┘
                         │
                         ▼
                    Terminal

License

MIT