API reference
Every public export of nanoraster — the two render calls, the renderer handle, the request and result types, the failure codes, and the validation constants.
Everything below is imported from nanoraster. GLB bytes you pass in are owned by
the call; the bytes you get back are newly allocated and yours.
Every option and its default
import { renderImage } from 'nanoraster';
const image = await renderImage(glb, {
format: 'webp', // required: 'png' | 'webp' | 'jpeg' | 'jpg' | 'raw'
width: 768, // default
height: 432, // default
quality: 1, // webp default (lossless); jpeg defaults to 0.92; png and raw ignore it
margin: 0.1, // default
up: 'y', // default
projection: 'perspective', // default
background: undefined, // default (transparent)
axes: false, // default
scaleBar: false, // default
lighting: 'studio', // default
label: undefined, // default (no label drawn)
phi: 60, // default
theta: -45, // default
});renderImages takes the same shared keys, minus phi, theta and label,
plus views: [{ id, label?, phi, theta, width?, height?, format?, quality? }],
one entry per image in result order, and timings: true to attach stage
timings. format: 'raw' skips the encoder and returns the frame itself, at
call level or per view; see Work with raw pixels.
Render
renderImage
Render one GLB camera view to one owned output.
export declare const renderImage: (
glb: Uint8Array<ArrayBuffer>,
options: RenderImageOptions,
) => Promise<RenderedImageFile>;- Parameters: owned GLB bytes and one validated render request.
- Returns: a newly allocated
render.<format>file with the resolved width and height. - Throws:
RenderErrorfor invalid requests, malformed GLB data, GPU faults, or encoding failures.
import { renderImage } from 'nanoraster';
const image = await renderImage(glb, { format: 'webp', width: 512 });renderImages
Parse and upload a GLB once, then render an ordered set of identified views:
the plan call. Each view may override the shared width, height, format
and quality, so one call renders a whole resolution or format ladder.
export declare const renderImages: <const Options extends RenderImagesOptions>(
glb: Uint8Array<ArrayBuffer>,
options: StrictRenderImagesOptions<Options>,
) => Promise<RenderedImagesResult<Options>>;- Parameters: owned GLB bytes and shared settings with a non-empty view tuple.
- Returns: a tuple with the input view IDs and order preserved; each
entry's MIME type follows its own
formatoverride. - Throws: as above, plus a mismatch between the views requested and the images returned.
import { renderImages } from 'nanoraster';
const [iso, front] = await renderImages(glb, {
format: 'webp',
views: [
{ id: 'iso', phi: 60, theta: -45 },
{ id: 'front', phi: 90, theta: 0 },
],
});Renderer reuse
The one-shot functions share one lazily created renderer per process, run in sequence and never disposed; create your own to control its lifetime or power preference. Reuse the renderer covers when and how.
createRenderer
Create a renderer that keeps the GPU device, shader and pipelines alive across calls.
export declare const createRenderer: (options?: CreateRendererOptions) => Promise<Renderer>;- Parameters: optional GPU selection hints.
- Returns: a
Rendererbound to one warm device. - Throws:
RenderErrorwith codeadapter-unavailablewhen no compatible adapter exists, orparsefor invalid options.
import { createRenderer } from 'nanoraster';
using renderer = await createRenderer({ powerPreference: 'low-power' });
const image = await renderer.renderImage(glb, { format: 'webp' });Renderer
The persistent handle returned by createRenderer. Its two
render methods mirror the module-level functions exactly (same options, same
results, byte-identical pixels on the same adapter) but reuse one device.
export type Renderer = {
readonly renderImage: (
glb: Uint8Array<ArrayBuffer>,
options: RenderImageOptions,
) => Promise<RenderedImageFile>;
readonly renderImages: <const Options extends RenderImagesOptions>(
glb: Uint8Array<ArrayBuffer>,
options: StrictRenderImagesOptions<Options>,
) => Promise<RenderedImagesResult<Options>>;
readonly dispose: () => void;
readonly [Symbol.dispose]: () => void;
};- A renderer is single-realm: create it inside the worker that uses it;
bytes cross
postMessage, handles do not. - Calls on one renderer run in sequence; a declared set of images goes
through one
renderImagescall, never a loop. - Device loss is recovered on the next call, which rebuilds the device and re-uploads.
dispose()marks the renderer disposed at once, is idempotent, and backsusingthroughSymbol.dispose; every later call rejects withRenderErrorcode'gpu', so recreate rather than retry. GPU teardown follows the queued calls, with no completion signal.
CreateRendererOptions
describeAdapter
Describe the adapter a renderer created with these options would bind; pass
the same powerPreference you would pass createRenderer.
export declare const describeAdapter: (options?: CreateRendererOptions) => Promise<AdapterInfo | undefined>;deviceType === 'cpu' means software rasterisation, an order of magnitude
slower; use this as the preflight when performance matters. Native hosts
report the full device class; browsers report 'unknown' unless the adapter
declares itself a fallback. No adapter resolves undefined; only invalid
options reject.
AdapterInfo
Options held in a variable
A variable widens 'webp' to string and the view IDs with it, so the result
tuple loses its names; as const satisfies keeps the literals and still checks
the keys, at compile time only.
import { renderImages, type RenderImagesOptions } from 'nanoraster';
const options = {
format: 'webp',
views: [{ id: 'iso', phi: 60, theta: -45 }],
} as const satisfies RenderImagesOptions;
const [iso] = await renderImages(glb, options);satisfies RenderImageOptions does the same for the singular call.
Options
Frame the model shows these fields in use.
RenderImageOptions
export type RenderImageOptions = RenderImageSharedOptions &
RenderLabelOptions & {
readonly phi?: number;
readonly theta?: number;
};RenderImageSharedOptions and RenderLabelOptions are internal composition
types; the table is the complete consumer-visible shape.
RenderImageView
export type RenderImageView<Id extends string = string> = {
readonly id: Id;
readonly label?: string;
readonly phi: number;
readonly theta: number;
readonly width?: number;
readonly height?: number;
readonly format?: 'png' | 'webp' | 'jpeg' | 'jpg' | 'raw';
readonly quality?: number;
};IDs must be unique within a request. The four output fields are per-view
overrides: each defaults to the shared value, follows the same validation, and
flows into that entry's filename and MIME type; format: 'raw' is accepted
here too.
RenderImagesOptions
export type RenderImagesOptions<Views extends readonly RenderImageView[] = readonly RenderImageView[]> =
RenderImageSharedOptions & {
readonly timings?: boolean;
readonly views: Views;
};views must be a non-empty ordered tuple with unique IDs; a view is labelled
when its own entry sets label. timings: true attaches a
RenderTimings to the result without changing what is
rendered.
StrictRenderImagesOptions
The exact parameter type of renderImages and
Renderer.renderImages: RenderImagesOptions narrowed so extra keys, empty
view tuples, and per-view settings placed at call level are compile errors.
Callers pass plain RenderImagesOptions literals; name this type only when
you forward the plan call through a generic wrapper:
import { renderImages, type RenderImagesOptions, type StrictRenderImagesOptions } from 'nanoraster';
const renderCatalogue = async <const Options extends RenderImagesOptions>(
glb: Uint8Array<ArrayBuffer>,
options: StrictRenderImagesOptions<Options>,
) => renderImages(glb, options);RenderLighting
export type RenderLighting = 'studio' | RenderLightingRig;The studio preset by name, or a rig. Omitting lighting, passing 'studio'
and spelling out the studio values render the same bytes; one rig applies to
every view of a batch. Light the subject shows each
field in use.
RenderLightingRig
A rig replaces the studio lights outright and inherits every other studio
value it leaves out. Directions are view-space by default (+x right, +y up,
+z toward the viewer); space: 'world' authors them in glTF coordinates.
RenderLight
One directional light. direction points from the surface toward the light and
is normalised by the renderer; color is linear RGB radiance, unitless, each
channel within renderImageLightColorRange.
Results
RenderedImageFile
Returned by renderImage, and as the file of every batch
entry. width and height are the dimensions the request resolved to. With
format: 'raw', bytes is the frame itself (straight-alpha sRGB RGBA8,
width * height * 4 bytes, top row first) and mimeType is
application/octet-stream; Work with raw pixels
has the layout in full.
import { renderImage } from 'nanoraster';
import { writeFile } from 'node:fs/promises';
const image = await renderImage(glb, { format: 'webp' });
await writeFile(image.name, image.bytes);RenderedImage
One identified entry in a batch result; the id is the literal you supplied on
the matching view.
RenderedImages
The ordered tuple inside every plan-call result.
export type RenderedImages<
Views extends readonly RenderImageView[],
SharedFormat extends ImageFormat = ImageFormat,
> = {
readonly [Index in keyof Views]: Views[Index] extends RenderImageView<infer Id>
? RenderedImage<Id, ViewOutputFormat<Views[Index], SharedFormat>>
: never;
};This mapped tuple preserves each input view's literal ID, position and length,
and narrows each entry's MIME type through its view's format override,
falling back to the shared format. Entry files are named
render-<id>.<format>.
RenderedImagesResult
What renderImages resolves to: the
RenderedImages tuple, plus a
RenderTimings on timings when the options literal set
timings: true. Reading timings without having requested it is a compile
error.
import { renderImages, type RenderedImagesResult, type RenderImagesOptions } from 'nanoraster';
const options = {
format: 'webp',
timings: true,
views: [{ id: 'iso', phi: 60, theta: -45 }],
} as const satisfies RenderImagesOptions;
const result: RenderedImagesResult<typeof options> = await renderImages(glb, options);
console.log(result[0].file.name, result.timings.parse); // 'render-iso.webp' 0.42RenderTimings
Attached to a plan call's result when the options set timings: true. The
fields map onto the pipeline stages: parse, setup (device
acquisition plus geometry upload), then per-view rasterise, annotate and
encode, all in milliseconds.
RenderViewTimings
One view's stage timings within a RenderTimings, in plan
order.
imageMimeTypes
The readonly runtime map of every accepted output format to its emitted MIME type.
export declare const imageMimeTypes: {
readonly png: 'image/png';
readonly webp: 'image/webp';
readonly jpeg: 'image/jpeg';
readonly jpg: 'image/jpeg';
readonly raw: 'application/octet-stream';
};Errors
Rendering rejects with RenderError. Parse and encode failures are
deterministic for the same request; GPU faults may succeed after the host
recovers, so Handle render failures retries
them.
RenderFailureCode
export type RenderFailureCode =
| 'adapter-unavailable'
| 'device-lost'
| 'driver-unsupported'
| 'gpu'
| 'parse'
| 'encode'
| 'unknown';| Value | Meaning | Retry guidance |
|---|---|---|
adapter-unavailable | No compatible GPU adapter was available. | Keep the last image and retry after host recovery. |
device-lost | The GPU device was lost during rendering. | Keep the last image and retry with a new device. |
driver-unsupported | The host's GPU driver faults mid-render on 32-bit ARM Linux. | Render on another driver, or set the documented opt-out. |
gpu | Another adapter, driver, or render-pass failure occurred. | Treat as transient unless host diagnostics prove otherwise. |
parse | GLB bytes or request options violated the input contract. | Fix the input before retrying. |
encode | The selected encoder could not produce the requested image. | Fix the format or background before retrying. |
unknown | The thrown value had no recognised failure tag. | Inspect message and preserve the original context. |
RenderError
RenderError extends the native Error class and adds this public surface:
export declare class RenderError extends Error {
readonly code: RenderFailureCode;
constructor(code: RenderFailureCode, message: string);
static from(error: unknown): RenderError;
get isGpuFault(): boolean;
}RenderError.from(error) returns an existing RenderError unchanged or
classifies any other thrown value, and never throws. isGpuFault is true
for adapter-unavailable, device-lost and gpu.
import { RenderError, renderImage } from 'nanoraster';
try {
await renderImage(glb, { format: 'webp' });
} catch (error) {
const failure = RenderError.from(error);
if (!failure.isGpuFault) throw failure;
}Constants
Every bound and pattern the validator applies, as the exact runtime values; import them rather than restating them, so caller-side checks cannot drift.
| Export | Runtime value | Unit or syntax | Affected field |
|---|---|---|---|
renderImageDimensionRange | readonly [16, 4096] | pixels | width, height |
renderImageQualityRange | readonly [0, 1] | normalised encoder quality | quality |
renderImageMarginRange | readonly [0, 0.5] | fraction of fitted extent | margin |
renderImageAnnotatedMinDimension | 192 | pixels | annotated width, height |
renderImageLabelMaxLength | 64 | Unicode code points | label |
renderImageLabelPattern | /^[\u0020-\u007E\u00B5\u2014\u2212]+$/u | supported characters | label |
renderImageViewIdPattern | /^[\dA-Za-z][\w-]{0,63}$/u | identifier syntax | id |
renderImageBackgroundPattern | /^#[\dA-Fa-f]{6}(?:[\dA-Fa-f]{2})?$/u | hexadecimal colour | background |
renderImageMaxLights | 8 | lights per rig | lighting.lights |
renderImageLightColorRange | readonly [0, 32] | linear radiance per channel | lighting.lights[].color |
renderImageAmbientRange | readonly [0, 4] | diffuse multiplier | lighting.ambient |
renderImageExposureRange | readonly [0.01, 16] | linear multiplier | lighting.exposure |
import { renderImageDimensionRange } from 'nanoraster';
const [min, max] = renderImageDimensionRange;
const clamp = (value: number): number => Math.min(Math.max(value, min), max);renderImageDimensionRange
Inclusive pixel bounds for both image dimensions.
renderImageMarginRange
Inclusive corner-fit margin bounds.
renderImageAnnotatedMinDimension
Minimum width and height when any annotation is enabled.
renderImageQualityRange
Inclusive encoder-quality bounds. JPEG treats the value as compression level
(default 0.92); WebP treats 1, its default, as lossless and anything lower
as lossy; PNG and raw ignore it.
renderImageBackgroundPattern
Hex clear-colour syntax; normalised straight-alpha RGBA backgrounds are not covered by it.
renderImageLabelMaxLength
Maximum label length in Unicode code points.
renderImageLabelPattern
Supported label characters: printable ASCII plus the micro sign, em dash, and minus sign.
renderImageViewIdPattern
Stable view identifier syntax; IDs become result filenames, so the first character is restricted.
renderImageMaxLights
Most directional lights one rig may carry.
renderImageLightColorRange
Inclusive per-channel bounds for a light's linear radiance.
renderImageAmbientRange
Inclusive bounds for the rig's flat ambient multiplier.
renderImageExposureRange
Inclusive bounds for the pre-tone-map exposure multiplier.