nanoraster
0.4.1

Render for LLMs

Size, encode, and annotate renders for multimodal models — pixel-based billing, lossless input, and the annotations that carry spatial context.

Open Markdown

A render sent to a multimodal model faces different constraints than one sent to a person: the model is billed by the pixel, reads compression artifacts as if they were geometry, and cannot infer orientation or physical size from shading alone.

1. Bytes are free, pixels are billed

The major vision APIs convert an image to tokens from its pixel dimensions alone; the encoded file size never enters the bill. A 5 KB lossy WebP and a 30 KB lossless WebP of the same 768×432 render cost identical tokens on every provider below.

ProviderImage tokensReference
OpenAI⌈width/32⌉ × ⌈height/32⌉ patchesImages and vision
Anthropic⌈width/28⌉ × ⌈height/28⌉ visual tokensVision
Geminifixed per-image budget, set by media resolutionImage understanding

These are the documented base formulas for current-generation models on images small enough to skip provider-side resizing; some models add multipliers or detail and resolution settings that scale the result — the linked pages carry the per-model rules. Under those base formulas the default 768×432 render costs 336 patches on OpenAI and 448 visual tokens on Anthropic. Width and height are the only cost lever the renderer controls: halving both roughly quarters the bill, and shrinking the file changes nothing.

2. Send lossless input

Since bytes are free, lossy compression can only lose information the model might need. WebP's default quality of 1 encodes lossless, so an explicit format: 'webp' with no quality sends the model exactly the rendered pixels. Anthropic's vision guidance warns that lossy artifacts can degrade model performance while saving nothing on tokens. Reach for lossy WebPquality below 1 — only when upload latency matters more than fidelity.

3. Annotate for spatial reasoning

A model reading a render has no camera, no ruler, and no filename. The three annotations exist to put that context into the pixels themselves:

  • axes draws a camera-aware XYZ indicator, so the model knows which way the part is oriented.
  • scaleBar draws physical size in model units; without it a gearbox and a wristwatch gear read identically.
  • label names the subject or view, so a multi-image prompt stays attributable. Setting it is what draws it.
import { renderImage } from 'nanoraster';const image = await renderImage(glb, {  format: 'webp',  background: '#101418',  axes: true,  scaleBar: true,  label: 'gear',});

Rendering…

Annotated output needs at least 192 pixels on both axes; the mechanics of each overlay live in Format and annotate. For the strongest spatial evidence, send several labelled orthogonal views from one batch call — the shared label and axes let the model reconcile the views into one part.

On this page