@pk-nerdsaver-ai/snapcompact
Bitmap-frame context compression for vision-capable LLMs.
Instead of asking an LLM to summarize discarded conversation history, snapcompact serializes it and renders the text into dense PNG frames of pixel-font glyphs that vision models read back directly. The whole pass is local and deterministic — no LLM call, no API key, no latency beyond rendering. Rasterization and PNG encoding happen in native code (@pk-nerdsaver-ai/pi-natives).
Built for oh-my-pi's compaction pipeline, but the rendering API works on arbitrary text.
How it works
- Discarded history is serialized to compact text (
serializeConversation), with per-tool-result and per-argument character caps. - Text is normalized for the bundled bitmap fonts (
normalize): ANSI sequences stripped, whitespace collapsed, newline runs folded into a single full-block glyph so line structure survives. - Pages of text are rasterized into PNG frames (
render/renderMany). Frame width is fixed per shape; height hugs the rows actually printed, so a partially filled frame never bills blank pixel rows. - Frames persist in the compaction entry's
preserveDataand are re-attached to the summary message on every context rebuild.
Frame shapes are provider-aware, chosen by SQuAD recall evals (see research/) against real provider billing:
| Reader | Default shape | Notes |
|---|---|---|
| Anthropic | 6x12-dim |
X.org 6x12 glyphs, stopwords dimmed gray; high-res Claude lines get 1932px frames |
doc-8on16-sent-dim @2048 |
Two newspaper columns, sentence-hue ink; Gemini bills a fixed per-image budget, so larger frames are free chars | |
| OpenAI | 8on16-bw |
8x13 glyphs on a patch-aligned 16px pitch, sent at detail: "original" |
| Unknown | Anthropic shape | Per-provider image-count budgets guard against gateways that silently drop frames |
resolveShape({ api, id }) matches the model id, not just the wire API — a Claude routed through Vertex or OpenRouter keeps its Claude shape, priced for the gateway actually carrying the request.
Install
bun add @pk-nerdsaver-ai/snapcompactShips TypeScript source directly (no build step); requires Bun ≥ 1.3.14.
Usage
Render arbitrary text into LLM image blocks:
import { renderMany, frames, resolveShape } from "@pk-nerdsaver-ai/snapcompact";
const images = renderMany(longText, { model }); // ImageContent[], first page first
const count = frames(longText, { model }); // frame count without rendering
const shape = resolveShape(model); // eval-optimal Shape for the readerRun a full compaction pass over prepared messages:
import { compact } from "@pk-nerdsaver-ai/snapcompact";
const result = await compact(preparation, { model });
// result.summary — short "resume prior conversation" lead-in, reading guide, and FILES section
// result.preserveData — bounded archive source + rendered image middleAPI surface
- Compaction:
compact,CompactionPreparation,CompactionResult,getPreservedArchive,images,historyBlocks - Rendering:
render,renderMany,frames,geometry - Shapes:
SHAPES,SHAPE_VARIANTS,resolveShape,idealShapeVariant,isShape,isShapeVariantName - Text:
serializeConversation,normalize,dimStopwords,wrap - Budgets:
providerImageBudget,MAX_FRAMES_DEFAULT,FRAME_TOKEN_ESTIMATE,HQ_EDGE_FRAMES - File ops:
createFileOps,computeFileLists,upsertFileOperations