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

@ziweiwu/folio

v0.4.2

Published

Read markdown in your terminal, properly. Real typography, Shiki syntax highlighting, vim keys, search, a table of contents, link following, and scrolling that keeps up with your keyboard.

Downloads

619

Readme

folio

ci npm

Read markdown in your terminal, properly. Real typography, real syntax highlighting, and scrolling that keeps up with your keyboard.

npm install -g @ziweiwu/folio
folio README.md

folio showing a document

What it feels like to use

It opens instantly, it scrolls like a native app, and the keys are the ones you already know. Nothing to configure — point it at a file and read.

  • Scrolling never lags. j k for a line, d u for half a screen, space for a full one, g G for the ends. Hold a key and it stays smooth instead of falling behind and then lurching. The mouse wheel works too.
  • You always know where you are. The status bar shows the file, how far through you are, and which section you're currently inside — not just a percentage.
  • Resize without losing your place. Widen the window and you stay on the paragraph you were reading.

What it does

Code you can actually read

Syntax highlighting through Shiki — the same TextMate grammars and themes VS Code uses, so keywords, types, functions and strings are all distinct rather than uniformly coloured.

syntax highlighting

Press y to copy the code block on screen to your clipboard. It goes over OSC 52, so it works through SSH and inside tmux where pbcopy can't reach.

Find your way around

/ searches, n and N step through matches. Search is smartcase — lowercase matches anything, a capital means you meant it — and a hit lands a third of the way down the screen so you keep the context above it. Every jump says which match you are on out of how many, so you can tell three hits from thirty and see the wrap when it comes back round to the first.

searching

t opens the table of contents. Pick a heading and jump straight to it.

table of contents

Nothing gets chopped

A long command or a wide table is laid out at its full width, and h l move the viewport over it. Only the wide rows move — the prose around them stays exactly where you were reading it, so you never lose the sentence explaining the command. ‹ and › mark whichever edge continues.

horizontal scrolling

Links go somewhere

Tab picks the next link and scrolls it into view, Enter follows it, Backspace goes back. Or just click it — a click follows the link under the pointer, and the wheel scrolls.

  • Relative paths open that file — ./guide.md, guide, or a directory with an index.md inside
  • #anchors jump to the heading, using the same slugs GitHub links with
  • [[Wikilinks]], [[target|label]] and [[target#heading]] work, so an Obsidian or Foam vault reads properly
  • External URLs are shown rather than opened — a pager that launches a browser is a surprise, and they're already clickable via OSC 8

It remembers where you were

Close a long document and reopen it later and you're back at the same place. What's stored is the block, not the line number, so it survives being reopened in a different-sized window. --no-resume opens at the top.

Light and dark

Picked automatically from your terminal, or forced with --theme.

light theme

Formats it doesn't parse

.org, .txt, .rst and logs are shown verbatim rather than misread as markdown — Org's * headings aren't emphasis, and pretending otherwise misrepresents the file.

So are source and configuration files — .py, .ts, .json, .yaml, dotfiles, a Makefile. Markdown joins consecutive lines into a paragraph, so parsing one of those doesn't merely style it wrongly, it deletes the indentation that is the file. --markdown forces the parser anyway, and --text forces verbatim on anything.

A directory or a binary file is refused with a reason, not rendered as pages of caret notation.

See it for yourself

examples/ in the repository is a guided tour — nine documents covering every construct folio draws, from nested lists to mermaid blocks to right-to-left text. Clone it and read the tour in the viewer itself:

git clone https://github.com/ziweiwu/folio && cd folio
folio examples/README.md      # then Tab, Enter, Backspace to walk the tour

Keys

The full guide walks through all of this in order; ? lists the keys without leaving the viewer.

j k ↓ ↑      one line              d u          half a screen
f b space    a full screen         g G          top, bottom
h l ← →      sideways              0            back to the left edge
wheel        three lines           click        follow the link under it

tab ⇧tab     pick a link           enter        follow it
backspace    go back               y            copy the code block on screen
/            search                n N          next, previous match
t            contents              r            reload from disk
?            all keys              q esc ^C     quit

Options

-w, --width N       Text column width (default 88). 0 fills the terminal.
    --theme NAME    auto, dark or light (default auto, read from COLORFGBG)
-p, --plain         No colour at all. NO_COLOR does the same.
-n, --line-numbers  Number the lines inside code blocks
    --links MODE    osc8 (clickable, default), ref (numbered), plain (URL inline)
    --wrap          Chop wide code and tables to fit, rather than scrolling
    --no-resume     Always open at the top
    --no-pager      Print and exit even on a terminal
    --watch         Re-render when the file changes on disk
    --text          Show the file verbatim, with no markup parsing
    --markdown      Parse as markdown even if the extension says otherwise

It behaves like a Unix tool

folio README.md            # a pager
folio README.md | cat      # plain text, no escape codes
FORCE_COLOR=3 folio R.md | less -R
cat NOTES.md | folio       # still interactive, via /dev/tty
folio --watch spec.md      # re-renders as you edit
folio spec.md | head -20   # closing the pipe early is not an error

Exit status is 0 for success, 1 for a document that could not be read, 2 for bad usage. Piping a document in still opens a real pager: the content comes from stdin and the keyboard is borrowed from the controlling terminal.

A reader that stops reading is not a failure: head, grep -q and quitting out of less all close the pipe mid-write, and folio treats that as the job being done rather than printing a broken-pipe trace. Printed output is also clamped to the width of your terminal, so a table wider than the screen is cut with a mark instead of wrapping into noise.

A document is content, never instructions. Control bytes in a file — an escape sequence that would clear your screen, a forged OSC 8 link target, a \r that overwrites the line above — are shown in caret notation (^[, ^G) the way less shows them, rather than handed to your terminal. Pointing folio at a README you have not read is safe.

Why not glow

| | glow | folio | |---|---|---| | Scrolling a long file | re-renders the document each scroll | lays out once, then slices | | Cost per frame | grows with the document | 0.10 ms on a 6,246-row document | | A held key | queues renders and falls behind | coalesced to one update per frame | | Resize | loses your place | re-anchors to the block you were reading | | Position | a percentage | percentage and the section you are inside | | Wide code | folds it | scrolls sideways over it | | Links | not followable | Tab to pick, Enter to open, Backspace to go back | | Wikilinks | no | [[target|label]] and [[target#heading]] | | Reopening a file | at the top | where you left off | | Highlighting | Chroma | Shiki — the grammars and themes VS Code uses |

Design philosophy

Three things, in this order, whenever they conflict.

Simplicity. Seven runtime dependencies, no configuration file, no plugin system, no stash. It opens a file and shows it to you.

Clarity. An 88-column text measure, hanging indents, real hierarchy, and colour used as a redundant signal rather than the only one. NO_COLOR output stays fully legible — headings keep their rules, tasks their boxes, code its frame.

Speed. Layout runs once per document, not once per scroll. Opening a file never waits for syntax highlighting.

How it works

The whole design rests on one split:

source ──parse──▶ tokens ──layout──▶ Line[]   once, per (source, width, theme)
                                       │
                            offset ────┴──▶ compose ──▶ frame   per scroll

layoutDoc is a pure function returning an array of fully-styled rows. Scrolling only changes an integer, and the Ink tree is one Text node per visible row — so a 6,246-row document costs exactly what a 30-row one costs. Measured on an M1:

| | | |---|---| | Lay out a 6,246-row document | 135 ms, once, at open | | Compose one frame of it | 0.10 ms | | Ink drawing that frame | ~30 ms |

Highlighting is the expensive part of layout, so the first frame is drawn without it and replaced when the grammars are ready. Only the languages a document actually uses are loaded.

Development

See AGENTS.md for the working agreement, and INVARIANTS.md for the contract this is built against.

npm test                    # 500 unit and property tests
npm run lint && npm run typecheck && npm run build
npm run verify:smoke        # the no-terminal paths
npm run verify:screenshots  # do docs/*.png still match what the app draws?
npm run verify:pty          # a real pty: drive it, signal it, check what it restored
npm run preview -- test/fixtures/kitchen-sink.md 100   # layout only, no TUI
npm run screenshots         # regenerate docs/*.png from real frames

Everything but verify:pty also runs from a Stop hook in .claude/, so a change that leaves the tree failing is refused rather than summarised. CI runs the same list, and carries verify:pty on a macOS runner because it needs a real pty and takes minutes.

Licence

MIT