pi-better-render
Streaming-first rich Markdown, code and math rendering for the pi TUI, with formula images in Kitty graphics terminals (display only; never touches the LLM context).
Package details
Install pi-better-render from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-better-render- Package
pi-better-render- Version
0.5.0- Published
- Nov 1, 2026
- Downloads
- 459/mo · 168/wk
- Author
- jefferychou
- License
- MIT
- Types
- extension
- Size
- 11.9 MB
- Dependencies
- 1 dependency · 2 peers
Pi manifest JSON
{
"image": "https://cdn.jsdelivr.net/gh/JeffeyChou/pi-better-render@main/assets/demo.gif",
"video": "https://cdn.jsdelivr.net/gh/JeffeyChou/pi-better-render@main/assets/demo.mp4",
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-better-render
Streaming-first rich rendering for pi's TUI. Markdown, code blocks, tables and LaTeX formulas are rendered as the answer streams in. Formulas are real images in terminals with the Kitty graphics protocol. Ghostty, kitty and WezTerm are tested; Warp is detected but not tested yet.

- Display only. It replaces the component that displays a message and never edits the message.
The session file and the next LLM request keep the original Markdown/LaTeX. As a safety net, a
contexthook also strips any terminal image artifacts before every request. - Formulas while streaming. Each formula becomes an image as soon as it is complete. There is no waiting for the message to end.
- In process, no big runtime. No browser, Pandoc or daemon is involved. A formula takes about 1 ms from TeX to PNG.
- Text-like images. Inline formulas sit inside the line, and every formula wraps, scrolls and diffs like text. Each image is sent to the terminal once and drawn in the theme's text color, on light and dark backgrounds. Formulas stay in the scrollback after pi exits.
- Copy as Markdown. Selecting an answer copies each formula as its LaTeX source, so pasted text is working Markdown again.
Compared with other pi extensions
| pi-better-render | pi-math | pi-markdown-preview | pi-rich-renderer | |
|---|---|---|---|---|
| Where it shows | In the chat, automatically | In the chat, automatically | Separate viewer (/preview), browser or PDF |
In the chat, automatically |
| Updates while streaming | ✅ Markdown and formulas, on every delta | ✅ Formulas | ❌ On demand; the browser's live mode updates per recorded message, not per token | ❌ Only when the message ends |
| Restyles Markdown (headings, callouts, tables, code) | ✅ | ❌ pi's built-in | ✅ As a Pandoc HTML page | ❌ pi's built-in |
| Formulas inside the text line | ✅ | ✅ | ✅ Inside a page screenshot | ❌ Each formula becomes a block image |
| Copying formulas from the chat | ✅ As their LaTeX source (fullscreen mode) | ❌ Not handled | – Separate viewer | ❌ Not handled |
| Math engine | MathJax 4, with optional TeX fallback | MathJax 3 | Pandoc MathML + MathJax in Chromium | latex + dvipng per formula |
Needs beyond npm install |
Nothing (TeX is optional) | Nothing | Pandoc and Chromium; LaTeX for PDF | A TeX installation |
| Stored message and LLM context | Untouched (display only) | Untouched (display only) | Untouched (read only) | Message content replaced at message_end; original restored for the LLM |
| Terminals with images | Kitty graphics terminals: Ghostty, kitty, WezTerm, Warp, others by override | Ghostty, kitty; WezTerm, Warp; iTerm2 (display formulas only) | Ghostty, kitty, iTerm2, WezTerm | Those supported by pi's image component |
| Without images | Unicode approximation | Original LaTeX | – | Original LaTeX |
| Beyond chat rendering | Mermaid diagrams as Unicode art | Custom macros and environments | Browser and PDF export, live view of tool calls, Mermaid, file preview, export tool | Disk cache of PNGs |
Each existing extension covers one part of the problem:
- pi-math typesets formulas in the chat but leaves the rest of the Markdown to pi.
- pi-markdown-preview renders a complete, polished page, but in a separate viewer after the reply has finished.
- pi-rich-renderer needs a TeX installation and swaps in images only once the message ends.
pi-better-render fills the gap between them. It renders the whole answer, Markdown structure and math alike, in the chat while it streams, in process, with nothing extra to install.
The others are still the better choice in some cases. For PDF or browser output, or for Mermaid diagram types beyond flowchart, sequence, state, class and ER, use pi-markdown-preview. For formula images in iTerm2, use pi-math. (Comparison as of October 2026.)
Install
pi install npm:pi-better-render # from npm
pi install git:github.com/JeffeyChou/pi-better-render
pi -e npm:pi-better-render # try it for one run without installing
From a local checkout: npm install, then pi install ./path/to/pi-better-render (or pi -e ./src/index.ts).
What it renders
- Markdown: headings without
#markers, emphasis, clickable links (OSC 8), lists and task lists, quotes and GitHub callouts (> [!NOTE],[!TIP],[!WARNING]…), rules. - Code: a background block with the language label and pi's syntax highlighting, no fences.
- Tables: rounded borders, column alignment and correct CJK widths. Narrow terminals shrink the columns, then show cards.
- Math:
$…$,\(…\),$$…$$,\[…\]and the AMS environments, typeset by MathJax 4 with AMS, mathtools, physics, mhchem, braket, cancel, bbm and more. Formulas take the theme's text color, in light and dark terminals.\text{中文}uses a system CJK font, or downloads Noto Sans SC/KR once (checked against a pinned SHA-256). Formulas MathJax rejects go to a locallatex+dvipngortectonicwhen one is installed. Without terminal images, formulas use pi's Unicode approximation. - Mermaid: flowchart, sequence, state, class and ER diagrams as box drawings. The renderer
(about 11 MB) is downloaded into
~/.pi/agent/better-render/depson the first diagram; until then, and for other diagram types, the block stays as code.
Copying
In pi's fullscreen mode (the default), selecting text copies formulas as their Markdown source,
for example $C_\ell^*$ or a $$ … $$ block, so pasted answers keep working math. Code blocks have a
Copy button that copies the source without fences or line numbers.
In regular mode (--tui-mode regular) the terminal does the copying, and formulas come out as the
image placeholder characters.
Terminals
Formula images work in terminals with the Kitty graphics protocol. Everything else renders in any terminal, and formulas fall back to a Unicode approximation where images are not available.
| Terminal | How formulas are drawn | Tested with pi 1.4.0 on macOS |
|---|---|---|
| Ghostty | Unicode placeholders | 1.3.1 |
| kitty | Unicode placeholders | 0.49.2 |
| WezTerm | One direct placement per formula row | 20240203 and nightly 20261026 |
| Warp | One direct placement per formula row | Not tested |
| Another terminal with Kitty graphics | Direct placements, after the override below | – |
| tmux, screen, terminals without Kitty graphics | Unicode approximation | – |
Ghostty, kitty and WezTerm were tested with light and dark colors, in fullscreen and regular mode.
pi detects the four terminals above. For another terminal with the Kitty graphics protocol, start pi
with PI_IMAGE_PROTOCOL=kitty (pi's own override), and add PI_BETTER_RENDER_IMAGES=placeholder
if the terminal also supports Unicode placeholders.
Commands
/better-render <argument>:
| Argument | Effect |
|---|---|
status |
Renderer state, math engine, cache hit rates and formula timings |
on / off |
Rich rendering, or pi's built-in Markdown |
math:streaming / math:final / math:off |
Formulas become images while streaming, after the message ends, or never |
lines |
Toggle line numbers in code blocks |
mermaid |
Toggle Mermaid diagrams (off shows their source) |
clear-cache |
Drop cached renders and free terminal images (formulas in the scrollback go blank) |
Environment variables:
| Variable | Effect |
|---|---|
PI_BETTER_RENDER_IMAGES=placeholder|direct|off |
Override terminal detection |
PI_BETTER_RENDER_TEX=off|latex|tectonic |
Pick the TeX fallback |
PI_BETTER_RENDER_MERMAID_INSTALL=0 |
Never download the Mermaid renderer |
PI_BETTER_RENDER_FONT_DOWNLOAD=0 |
Never download a CJK font |
PI_BETTER_RENDER_DEPS_DIR, PI_BETTER_RENDER_FONTS_DIR |
Where downloads go |
PI_BETTER_RENDER_DEBUG=1 |
Log context-sanitizer checks to ~/.pi/agent/better-render-debug.log |
How it works
The extension swaps pi's Markdown component for its own and never edits the message, so the session
file and the next LLM request keep the original Markdown and LaTeX. Each delta is lexed incrementally
with marked, and finished blocks come from a cache. Formulas are typeset in process by MathJax 4
(TeX → SVG), rasterized by resvg onto whole terminal cells, and sent once over the Kitty graphics
protocol, so they wrap and scroll like text.
Performance
On an Apple M-series laptop, a formula takes about 1 ms from TeX to PNG (about 10 ms with CJK text),
and MathJax starts in about 105 ms in the background. A streaming frame takes about 0.6 ms on average
over a 61k-character answer. npm run bench reproduces the streaming numbers.
Development
npm test # unit tests (rebuilds vendor/ first)
npm run typecheck
npm run bench # streaming cost per delta
npm run preview -- test/fixtures/perceptron.md [--live] # render a file in this terminal
npm run build bundles the MathJax parts in use into vendor/ (about 12 MB, mostly on-demand font
data), so an install is about 15 MB instead of 118 MB. vendor/ is committed because pi installs git
packages without a build step; MathJax is pinned exactly, so vendor/ only changes with the pins.
npm publish runs the typecheck and tests first.
Changelog
0.5.0 (2026-10-31)
All in #6.
- Formulas were nearly invisible in light terminals with pi's default
systemtheme (#5). They now take the theme's text color, and messages already on screen follow theme switches. - Selecting text in fullscreen mode copies formulas as their Markdown source instead of placeholder characters.
- Tested in Ghostty, kitty and WezTerm, with a terminal support table in this README.
- WezTerm showed only the last row of a display formula, and only the last copy of a formula used twice. Every row and every copy now shows.
- A terminal started from a Ghostty or kitty shell (
open -a WezTerm) was taken for Ghostty or kitty and got garbled formulas.
0.4.0 (2026-10-18)
- Copy buttons on code blocks in fullscreen mode (#2, by @xiaotianxt).
- Font download tests wait for the download instead of a fixed delay (#3, #4).
0.3.0 (2026-10-12)
- Formulas stay in the scrollback after pi exits, and after
/new,/resumeor/reload(#1). - Formulas survive pi's fullscreen redraws, which delete image placements.
- Formula images in WezTerm and Warp, through direct placements.
PI_BETTER_RENDER_IMAGESoverrides the detection.
0.2.0 (2026-09-24)
- Mermaid diagrams as box drawings, with the renderer downloaded on first use, and
/better-render mermaid. - CJK text in formulas, with Noto Sans SC/KR downloaded when no system font covers it.
- MathJax is bundled into
vendor/, so an install shrinks from 118 MB to about 15 MB.
0.1.0 (2026-09-24)
- First release: streaming Markdown, code, tables and MathJax 4 formula images in pi's TUI, display only, with incremental lexing.
Credits
MathJax (Apache-2.0) is bundled in vendor/; see vendor/LICENSE.
The Kitty diacritic table and the formula-scaling approach are adapted from Fadouse/pi-math (MIT).
License
MIT
