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

termtex

v0.9.8

Published

LaTeX math in your terminal: wraps any TUI with live typeset overlays on kitty-graphics terminals, Unicode everywhere else

Readme


Why this exists

Ask a coding agent — Claude Code, Codex, anything else — a question with real mathematics in the answer, and you get this:

The gradient vanishes at $A^{T}A\hat{x} = A^{T}b$, so
$\hat{x} = (A^{T}A)^{-1}A^{T}b$ whenever $A^{T}A$ is invertible.

The model is writing LaTeX because LaTeX is how mathematics is written. Your terminal doesn't know that, so you read source code instead of equations. Editors and chat UIs solved this years ago; terminals never did.

termtex sits between the program and your terminal and fixes it in flight. It is a filter on a byte stream — it knows nothing about the program it wraps, so it works with any CLI, and no agent's update can break it.

termtex              # just this — your shell, best renderer available
termtex claude       # instead of `claude`
termtex codex        # instead of `codex`

Bare termtex asks nothing of you. It runs your shell (or whatever command you configure) and works out where to put it:

| Situation | What happens | |---|---| | already in WezTerm / Kitty / Ghostty | runs right here — typeset math in place | | one of those is installed | opens it for you | | neither | opens the browser — typeset math there |

Force a path with --here (this terminal, Unicode only), --gui (open a graphics terminal), or --web (browser), or pin one with "launch" in the config file.

What it looks like

Inline math is rewritten to Unicode as it streams, in any terminal:

Nothing about this is agent-specific — the same wrapper, a different program:

Display math becomes a two-dimensional block; shell text like $PATH is left strictly alone:

On a terminal that speaks the kitty graphics protocol — or in termtex web — display equations are typeset properly and drawn over the raw source, in place, without disturbing the program underneath:

The terminal frames above are rendered from output captured verbatim from real termtex runs; the typeset equations come from termtex's own MathJax pipeline. Regenerate them with node tools/make-docs-assets.mjs.

Quick start

Needs Node ≥ 18. No TeX installation, ever.

npm install -g termtex     # or: npm install && npm link, from a clone
termtex doctor             # what can this terminal do?
termtex claude             # go

Examples

# wrap a coding agent — any of them
termtex claude
termtex codex
termtex claude --continue          # arguments pass straight through
termtex aider --model gpt-4o       # nothing is special-cased

# keep the session alive after the terminal closes
termtex abduco -A math claude
termtex abduco -a math             # reattach later, rendering included

# run it in a browser instead — any terminal, ssh-friendly, full typeset math
termtex web -- claude
termtex web -- ssh -t devbox       # remote session, math rendered locally

# named profiles, so switching is one word
termtex @cc                        # e.g. ["abduco","-A","cc","claude"]
termtex @cx                        # e.g. ["codex"]

# no agent involved at all
termtex notes.md                   # render a file
somecmd | termtex                  # render a pipe
termtex --tex '\frac{a}{b}'        # render one equation
termtex python3                    # wrap a REPL

How it renders

Three tiers, picked automatically for what your terminal supports:

| Tier | Where | What you get | |---|---|---| | Unicode | every terminal | $E_n = \hbar\omega(n+1/2)$Eₙ = ħω(n + 1/2); display math as 2-D blocks | | Typeset images | kitty-graphics terminals (WezTerm, Kitty, Ghostty) | MathJax-quality equations drawn over the text, in place | | Browser | anywhere, via termtex web | the same typeset math as SVG, no special terminal needed |

Run termtex doctor to see which apply to you; it prints the exact install command if you want the typeset tier in a terminal.

The engines: MathJax for typesetting and a WASM build of libtexprintf for Unicode. Both are in-process — no TeX, no compiler, no network.

Wrap mode: how it stays out of the way

termtex <command> runs the program on a PTY, so it sees a real terminal and behaves exactly as it would unwrapped, while its output passes through two layers:

  • Typeset overlay (kitty-graphics terminals). A headless terminal emulator shadows the real screen, so termtex knows where each $$…$$ span currently sits. Each is drawn on top of the raw text as a positioned, z-ordered, individually deletable image that occupies no cells. The program's geometry is untouched; when a span moves or scrolls away, its image is re-placed or removed.
  • Unicode stream rewriting (everywhere). Only spans complete within a single line are rewritten, so the line count never changes and the program's repaint bookkeeping stays valid.

Guardrails: only spans containing \, ^, or _ are touched by default, so $PATH:$HOME in tool output is never eaten (--aggressive loosens this); input composers and box-drawing chrome are skipped so typed text never desyncs; code fences and inline code pass through; anything that fails to render is left exactly as written; and terminal modes are restored on every exit path, including crashes.

Browser mode: termtex web

The browser is the one pixel-capable surface everyone already has, so this mode needs no particular terminal:

termtex web -- claude
termtex web -- abduco -A math codex     # detachable session in a tab
termtex web --port=9000 --no-open
termtex web --stop                      # end it from anywhere

The program runs on a server-side PTY; the page renders it with xterm.js and covers display math with server-typeset SVG — crisp at any zoom, and it works in scrollback.

  • WSL: run it in your Linux shell; WSL2 forwards localhost to Windows and termtex opens your Windows browser.
  • Over ssh: run it on the remote machine, then ssh -L 8437:localhost:8437 user@host and open the URL locally — math renders in your local browser regardless of what you ssh from.
  • Your browser's Install app turns the page into a standalone window with its own icon.

Detachable sessions

A session manager is just another command to wrap:

termtex abduco -A math claude          # create-or-attach; outlives the terminal
termtex abduco -a math                 # reattach; rendering comes with it
termtex web -- abduco -A math codex    # ... viewed in a browser tab

Detaching (Ctrl-\) exits termtex and leaves the session running. Put termtex outside (as above) and each viewer gets its own renderer, so the long-lived session holds no termtex state. Put it inside (abduco -A math termtex claude) and the renderer lives in the session instead. Both work; tmux composes the same way (images there need allow-passthrough on).

Desktop launcher

termtex install-launcher                 # detects macOS / WSL / Linux
termtex install-launcher --profile=cc --dir=~/work
termtex install-launcher --dry-run       # print what it would write

| Platform | What you get | |---|---| | macOS | ~/Applications/<name>.app — Spotlight, Launchpad, draggable to the Dock | | WSL | a .cmd on your Windows Desktop — double-click, or pin to the taskbar | | Linux | ~/.local/share/applications/<name>.desktop |

Absolute paths are baked in at install time, because GUI launchers don't inherit your shell PATH — the usual reason a double-clicked script does nothing. Clicking twice reuses the running session instead of starting a second server. Stop it from anywhere with termtex web --stop.

Getting the agent to emit LaTeX

termtex can only render mathematics it can identify. If an agent writes math as plain text (y_t = Σ_τ≤t g_out[t,p]) or tucks it inside code spans, there is nothing to detect — and termtex deliberately leaves both alone, because prose and code are full of underscores that are not subscripts (multipole_fft.py, periodic_state_period, k_scaled). Rendering those would corrupt every filename on screen.

So the single highest-leverage setting is your agent's instructions file (~/.claude/CLAUDE.md, AGENTS.md, …):

# Math
Write mathematics as LaTeX, using \( ... \) for inline math and \[ ... \] on
its own line for display math. Keep each equation on a single line. Do not
put equations in code spans or code fences, and do not pre-convert them to
Unicode — they are rendered downstream.

Why \( \) rather than $ … $: markdown treats _ as an italic marker, so a renderer can eat the underscores in $x_i$ before termtex sees them. termtex recovers from that where it can, but avoiding it is better. Both delimiter styles render.

If you previously told an agent to write math as plain Unicode — earlier versions of this README suggested exactly that — remove it. That instruction prevents the agent from emitting anything termtex can render.

Configuration

Everything program- or UI-specific is configuration, not code. Optional file at ~/.config/termtex/config.json (or $TERMTEX_CONFIG):

{
  "command": ["claude"],
  "profiles": {
    "cc": ["abduco", "-A", "cc", "claude"],
    "cx": ["codex"],
    "remote": ["ssh", "-t", "devbox", "abduco -A m claude"]
  },
  "skipPattern": "^\\s*[>❯│╭╰]",
  "mathColor": "#e8e8e8",
  "mathBg": "#1e1e1e",
  "mathScale": 1,
  "port": 8437,
  "sources": ["~/.config/termtex/claude-code.js"]
}

Every key has a TERMTEX_* environment equivalent; precedence is CLI flags > env > file > default.

  • command — what bare termtex runs. Defaults to $SHELL.
  • profiles — named launch targets: termtex @cc. Extra arguments append; an unknown name lists what you have.
  • skipPattern — rows treated as UI chrome and passed through untouched. Retune here if a program's chrome changes; no library update needed.
  • sources — transcript readers for termtex last. termtex ships none; register one to enable that command (see below).

termtex last

Re-renders the newest agent response for the current directory — useful as a second pane (termtex last --watch) or over ssh. It's the only feature that would need to read an agent's private files, so termtex ships no readers at all. A ready-made Claude Code adapter is included as example code, never loaded unless you ask for it:

cp examples/sources/claude-code.js ~/.config/termtex/
# then add: { "sources": ["~/.config/termtex/claude-code.js"] }

Supporting another agent means writing a file like that one — id, detect, watchTarget, lastResponse — not patching termtex.

Options

| Flag | Modes | Meaning | |---|---|---| | --overlay=auto\|force\|off | wrap | typeset images over display math | | --aggressive | wrap, web | loosen math-span heuristics | | --images=auto\|kitty\|iterm\|sixel\|off | file, pipe, last | image tier for display math | | --math-color, --math-bg, --math-scale | all | appearance | | --port, --no-open, --new, --new-token, --stop | web | server behaviour | | --source=ID, --watch | last | transcript source, live pane | | --profile, --dir, --name, --platform, --dry-run | install-launcher | launcher generation |

Security notes

termtex web binds 127.0.0.1 only, and every route — page, WebSocket, /typeset, manifest, icon — requires an unguessable token, stored at ~/.local/state/termtex/token (mode 0600) and reused across restarts so bookmarks and installed web apps keep working. Same model as Jupyter and code-server; the tradeoff versus a per-run token is that anything already running as your user could read the file while a session is up. Rotate with termtex web --new-token.

Install

npm install -g termtex

Or from a clone, so edits are live:

cd termtex && npm install && npm link

Notes:

  • node-pty is an optional native dependency powering wrap and web modes. macOS needs Xcode Command Line Tools (xcode-select --install); Debian/Ubuntu needs build-essential. If it can't build, the install still succeeds and file/pipe/--tex modes work.
  • If your npm blocks install scripts: npm install-scripts approve node-pty && npm rebuild node-pty.

Development

npm test                          # unit + PTY end-to-end suite
node tools/make-docs-assets.mjs   # regenerate the images in this README

Tests skip rather than fail where an optional native dependency isn't available, so the suite never depends on a native build succeeding.

Alternatives considered

| Tool | Approach | Limitation for this use case | |---|---|---| | utftex | LaTeX → Unicode (C CLI) | Single equations only; it's the engine behind termtex's Unicode tier | | buun-ch/termtex | MathJax → PNG → kitty protocol | Filter only (no TUI wrapping), kitty-only, no Unicode fallback. Name collision is coincidental | | LaTerM | xterm.js overlay addon | Web-embedded xterm.js only — but the architectural blueprint for termtex's overlay | | latex2sixel | LaTeX → DVI → Sixel | Needs a TeX install and a sixel terminal | | pylatexenc / unicodeit | LaTeX → flat Unicode (Python) | No 2-D layout, no document awareness |

Limitations

  • The typeset overlay settles ~200 ms after output pauses, and needs a kitty-graphics terminal; everywhere else display math is Unicode.
  • Inline math is always Unicode — terminals can't baseline-align inline images. Inline spans broken across a hard line wrap aren't detected.
  • Sixel images are opaque; set --math-bg to your terminal background.
  • Indented (4-space) code blocks are treated as prose; use fences.

License

GPL-3.0-or-later — required because the bundled Unicode engine (libtexprintf) is GPL. MathJax is Apache-2.0.