Node, Deno, Bun and Lambda
@sealpixel/render runs on Node 24 or later, Deno and Bun. It depends on @sealpixel/core and @sealpixel/wasm only. The node, deno and bun conditions of @sealpixel/wasm all load the core from disk.
Node, Deno and Bun
Install the package and import it. The core loads from node_modules/@sealpixel/wasm on the first render, with no option.
import { createRenderer } from '@sealpixel/render';
import { defaultPlugins } from '@sealpixel/plugins';
const renderer = createRenderer({ plugins: defaultPlugins });Deno needs --allow-read, because the loader reads the core binary from disk.
The renderer loads no font or image. Read the ones your logs use and pass the bytes as assets, see Assets.
The package's own tests render the goldens on all three runtimes, against the built package.
A bundle, for example on AWS Lambda
A bundler moves the code of @sealpixel/wasm into your bundle, but it does not copy the binary sealpixel_core_bg.wasm. Without node_modules beside the bundle, the first render then fails with Cannot find package '@sealpixel/wasm'.
Do these two steps:
- Copy
node_modules/@sealpixel/wasm/dist/generated/sealpixel_core_bg.wasmnext to the bundle. - Give its path to
wasm.module.
import { fileURLToPath } from 'node:url';
import { createRenderer } from '@sealpixel/render';
import { defaultPlugins } from '@sealpixel/plugins';
const here = (name: string) => fileURLToPath(new URL(`./${name}`, import.meta.url));
// Outside the handler, so a warm function reuses it.
const renderer = createRenderer({
plugins: defaultPlugins,
wasm: { module: here('sealpixel_core_bg.wasm') },
});
export const handler = async (event) => {
const result = await renderer.render({ /* original, editLog, upTo, output */ });
// Return or store result.bytes the way your function answers.
};wasm.module also accepts the bytes or a compiled WebAssembly.Module.
Fonts in a bundle
The renderer loads no asset, so the bundle carries the fonts like the binary. Copy node_modules/@sealpixel/plugin-annotate/assets/Roboto-Regular.ttf next to the bundle. Read it once, outside the handler, and pass the bytes:
import { readFileSync } from 'node:fs';
import { DEFAULT_FONT, defaultPlugins } from '@sealpixel/plugins';
const renderer = createRenderer({
plugins: defaultPlugins,
wasm: { module: here('sealpixel_core_bg.wasm') },
assets: [{ id: DEFAULT_FONT.id, bytes: new Uint8Array(readFileSync(here('Roboto-Regular.ttf'))) }],
});Do the same for every other font or image that your logs use. assetDeclarations(plugins) lists them.
What was tested
esbuild 0.28 bundled a handler like the one above with --bundle --platform=node --format=esm. The bundle, sealpixel_core_bg.wasm and the font went into an empty directory with no node_modules above it. Node 24 ran the handler there, and the hashes of the goldens ops/full-pipeline, ops/redact-rect-pixelate and ops/annotate-text-roboto matched the recorded hashes.
Give the function memory for the largest original you accept, see Memory.