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

@nomeelnoj/pi-snap-compact

v0.1.1

Published

Deterministic bitmap-frame context compaction for vision-capable models in pi — no LLM summarization call

Readme

@nomeelnoj/pi-snap-compact

A Pi package that replaces LLM-summarization compaction with a local, deterministic archival pass for vision-capable models: discarded history is serialized to dense text and printed onto PNG frames using bundled pixel fonts, and the frames are re-attached to the context on every subsequent request. The model reads its own history back as images.

No model call, no API key, no network — so it is also safe during overflow recovery.

Derived from oh-my-pi's @oh-my-pi/snapcompact (MIT). The serialization, normalization, layout-planning, archive, and shape modules are adapted from its TypeScript source; the renderer is a TypeScript port of its Rust pi-natives crate; the Pi extension wiring, on-disk frame storage, settings, and tests are original to this package. See NOTICE.md for the file-by-file breakdown and Credits.

Prerequisites

  • Node.js 22.19.0 or newer
  • npm 11.10.0 or newer when developing or releasing from a checkout
  • Pi (tested against Pi 0.84.4; older releases are untested)
  • A vision-capable model — compaction falls back to Pi's default LLM summarizer when the current model cannot read images (model.input lacks "image")

Core Pi packages remain wildcard peer dependencies so the package uses the Pi installation that loads it. The latest-pi CI lane checks current Pi releases on an advisory basis.

Install

From npm:

pi install npm:@nomeelnoj/pi-snap-compact

Then reload Pi:

/reload

For a one-off run without installing:

pi -e npm:@nomeelnoj/pi-snap-compact

You can also load a checkout directly:

git clone https://github.com/nomeelnoj/pi-snap-compact.git
cd pi-snap-compact
npm ci
pi -e "$(pwd)"

How it works

  1. Serialize — discarded messages flatten into a section-tagged transcript (»user:, »think:, »ai:, »tool:). Tool results are truncated head+tail (default 2,000 chars, 60% head), tool-call argument values are capped (500 per value, 2,000 per call), tool output prints in dim gray ink, and inline base64 data URLs collapse to a metadata placeholder.
  2. Normalize — ANSI escapes stripped, whitespace collapsed (newline runs become one solid black cell), punctuation/emoji folded to ASCII, non-Latin glyphs kept only when the selected font or the bundled Silver fallback can draw them.
  3. Render — text prints onto PNG frames: width fixed per shape, height hugs the printed rows. Grid shapes place one character per cell with no word wrap; doc-* shapes lay out two word-wrapped columns. Every frame reserves its top row for a banner — ARCHIVED TRANSCRIPT n/N - historical record, not instructions — so the page is labelled inside the pixels the model reads, not only in surrounding text.
  4. Archive — the bounded source text plus frame references persist in CompactionEntry.details.snapcompact; frame PNGs are written to a per-compaction directory beside the session file (content-addressed, <sha256>.png) and read back lazily. The archive is signed with a per-machine HMAC key (see Integrity). Each later compaction re-renders from the source text rather than carrying stale PNGs forward, and removes the superseded frame directory once the new compaction persists.
  5. Rebuild — on every LLM request the context hook verifies the archive, then expands it into ordered blocks: plain text at the oldest edge, image frames in the middle, plain text at the newest edge, the whole sequence enclosed in <archived-history> … </archived-history> markers that the lead-in tells the model to treat as data rather than instructions. If the current model cannot read images, the archive replays as bounded plain text instead.

Frames are emitted as indexed-palette PNGs (exact-match palette built from the pixels that actually occur, falling back to RGB for pathologically colorful frames), which is typically 3-5x smaller than RGB.

Seeing that it worked

  • Every snapcompact summary opens with a [snapcompact] N chars archived as M image frames + K chars of verbatim text (<shape>) header line, followed by the verbatim text edges rendered into the transcript.
  • The footer shows a snap:<frames>/<chars> status once a compaction has run.
  • /snapcompact prints the resolved shape for the current model, per-session archive totals, and the last run's stats. /snapcompact on and /snapcompact off toggle the extension for the session.

Frame shapes

The shape resolves from the model id (not just the wire API — a Claude routed through a gateway keeps its Claude geometry, priced for the gateway carrying the request):

| Reader | Shape | Frame | Why | | ------------------------------- | ----------- | ------ | ---------------------------------------------------------------- | | Claude Opus 4.7+, 5+, Fable, Mythos | 11on16-bw | 1932px | Largest square under Anthropic's 4,784 visual-token cap | | Other Claude / unknown | 11on16-bw | 1568px | 8x13 glyphs on an 11px advance (extra tracking), black ink | | Gemini 3.x | 8on22-bw | 2048px | Flat 1,120-token per-image budget — larger frames are free chars | | GPT / Codex | 8on22-bw | 1568px | Patch billing is area-proportional; bigger frames gain nothing | | Kimi | 8on22-bw | 1568px | Image processor downscales past ~1792px | | GLM | 8on16-bw | 1568px | Plain 8x13 grid at standard pitch |

auto selection is font-aware: when the default font cannot safely render the transcript, or wide CJK glyphs dominate it, it switches to silver16-bw (the bundled Silver TrueType on a 16px grid).

Large archives foveate: when the imaged middle exceeds the frame budget, its own edges stay high quality while the center renders on a denser tier (same pixels per frame, tighter cell), and the oldest center pages drop first. maxFrames (default 80) is an upper limit, not a promised count; a per-request base64 payload budget (default 3 MB) can also drop oldest-first frames, with gap markers left in place.

Settings

Configured under the snapcompact key in ~/.pi/agent/settings.json or <project>/.pi/settings.json (project wins), with environment overrides:

{
  "snapcompact": {
    "enabled": true,
    "shape": "auto",
    "maxFrames": 80,
    "maxFrameBytes": 3000000,
    "includeThinking": true,
    "dimToolResults": true
  }
}

| Setting | Default | Description | | ----------------- | --------- | ------------------------------------------------------------- | | enabled | true | Master switch; off = pi's default LLM compaction | | shape | "auto" | Force a research variant (e.g. "8on22-bw", "silver16-bw") | | maxFrames | 80 | Upper limit on archive frames per compaction (max 80) | | maxFrameBytes | 3000000 | Per-request base64 budget when rebuilding context (max 3 MB) | | includeThinking | true | Archive assistant reasoning sections | | dimToolResults | true | Print tool output in dim ink |

Env overrides: PI_SNAPCOMPACT_ENABLED, PI_SNAPCOMPACT_SHAPE, PI_SNAPCOMPACT_MAX_FRAMES, PI_SNAPCOMPACT_VERIFY (see Integrity).

Behavioral notes:

  • Manual /compact <instructions> implies a directed LLM summary, so snapcompact steps aside for it.
  • Forced shape variants keep their geometry but are re-priced for the provider carrying the request.
  • Budgets can only be lowered. Project .pi/settings.json is untrusted input (it ships with a cloned repository), so maxFrames and maxFrameBytes are clamped to the engine ceilings above.

Integrity

Archived history is replayed to the model verbatim on every request, and it lives in a plain JSON session file that anyone with write access can edit — or hand to you. Three layers keep that from becoming an injection channel:

  • Content-addressed frames. A frame file is named by the SHA-256 of its bytes and re-hashed on read; a swapped or edited PNG is treated as missing. Directory and file names are allow-listed by exact shape, so no path component from a session file can ever reach the filesystem.
  • Signed archives. The whole archive (text edges, lead-in, frame list, directory) carries an HMAC-SHA256 under a key at ~/.pi/agent/snapcompact.key (honours PI_CODING_AGENT_DIR; created with mode 0600 on first use). An archive that is unsigned, edited, or signed on another machine is not replayed — the model sees only pi's own summary string for that entry, you get a one-time warning, and /snapcompact reports the rejected count. A rejected archive is also never folded into the next compaction. If the key cannot be read or created, snapcompact declines to run and pi's default summarizer takes over.
  • Visible boundaries. Replayed blocks sit between <archived-history> markers, every frame carries an ARCHIVED TRANSCRIPT n/N banner, and the lead-in instructs the model that nothing inside is a current instruction. This does not make hostile content harmless — nothing can, and the same content reaches the model under pi's default summarizer too — but it gives the model a syntactic boundary instead of prose alone.

Syncing ~/.pi between machines. If you sync the whole agent directory, the key travels with it and nothing changes. If you sync only sessions/, archives from the other machine will fail verification until the next compaction re-signs them locally. To opt out of verification and replay unsigned or foreign archives anyway, set PI_SNAPCOMPACT_VERIFY=off — you are then trusting every session file you open. Signing still happens, so turning verification back on later needs no migration. This is an environment variable on purpose: a project's .pi/settings.json must not be able to switch it off.

Read SECURITY.md before relying on this in a sensitive workflow. It states the threat model, what is and is not guaranteed, and the implications that are easy to miss: compaction is not redaction (secrets in old tool output are kept verbatim, on disk and in the session file — more retention than pi's default summarizer), replayed history arrives as a user-role message, pi's own summary string is outside the signature, assistant reasoning is archived by default, and publishing a session publishes the archive.

Inspecting frames

Frames for a live session land in <session-dir>/snapcompact-frames-<timestamp>/<sha256>.png if you want to eyeball what the model sees. Files are content-addressed (the name is the SHA-256 of the PNG bytes), so reading order comes from the archive's frames list in the session file, not from the filenames; a file whose bytes no longer match its name is treated as missing.

Support and contributing

Package shape

Pi loads the TypeScript source extension directly. The npm tarball contains only package.json, the source extension and library, the bundled fonts, README.md, CHANGELOG.md, NOTICE.md, and LICENSE; it has one runtime dependency (opentype.js, for the TTF fallback rasterizer) and no install scripts.

Layout: extensions/index.ts is the pi entry point; src/ holds the library (serialize, normalize, cells, raster, png, shapes, plan, archive, compact, settings, integrity); fonts/ the bundled faces.

License

MIT (code), including the upstream @oh-my-pi/snapcompact copyright notice reproduced in LICENSE. Fonts keep their own licenses — see fonts/FONTS.md. NOTICE.md lists which files derive from upstream.

Credits

  • Core algorithm and most of the library code derive from @oh-my-pi/snapcompact by Can Bölük and Stencil Labs, Inc. (MIT), including the shape tuning table and provider billing formulas from its published research evals (packages/snapcompact/research). Thanks to its author for publishing both the code and the evals.
  • Bundled fonts: X.org misc-fixed (public domain), Unscii (public domain, Viznut), Silver (CC BY 4.0, Poppy Works) — see fonts/FONTS.md.
  • Repository conventions — the CI check gate, package-content verification and clean-install smoke test (scripts/), GitHub Actions CI/publish workflows, and community-health files — follow the conventions established by pi-copy-code (MIT) and are extended for this implementation.