pngine
v1.0.27
Published
WebGPU bytecode engine - shader art that fits in a PNG
Maintainers
Readme
PNGine NPM Package
WebGPU bytecode engine for PNG payloads.
Runtime Profiles
PNGine ships six browser-facing profiles:
| Profile | Import | Purpose |
| --- | --- | --- |
| Viewer (default) | pngine or pngine/viewer | Lean production player for PNG payloads with embedded executor |
| Dev | pngine/dev | Full feature surface for iteration and debugging |
| Core | pngine/core | Low-level runtime API (dispatcher-centric) |
| Executor | pngine/executor | Advanced payload/executor helper API |
| Mini | pngine/mini | Tiny main-thread player for flat (pNGf) payloads |
| Mini (no audio) | pngine/mini | Same as Mini with audio support stripped |
Self-Contained Playback
Every profile is designed to minimize external dependencies at runtime:
| Profile | Worker | WASM source | External files needed |
| --- | --- | --- | --- |
| Viewer | Blob-inlined | Extracted from PNG (embedded executor) | None — PNG carries its own executor |
| Dev | Blob-inlined | PNG or external fallback (wasmUrl) | Optional pngine.wasm if PNG lacks executor |
| Mini | None (main thread) | None (pNGf is interpreted directly) | None |
| Core | None (you manage it) | You provide it | You manage everything |
What this means: The viewer and mini profiles are each a single .mjs file
with zero external runtime dependencies. The PNG file is the only input — it
carries both the bytecode and (for viewer) the WASM executor.
Single-file HTML
Both viewer and mini accept ArrayBuffer | Uint8Array | Blob as source (not
just URLs), so a PNG can be base64-encoded inline for a fully self-contained
.html file:
<canvas id="c" width="512" height="512"></canvas>
<script type="module">
import { pngine, play } from 'pngine'; // or inline viewer.mjs directly
const data = Uint8Array.from(atob('iVBOR...'), c => c.charCodeAt(0));
const p = await pngine(data.buffer, { canvas: document.getElementById('c') });
play(p);
</script>For the smallest possible output, use pngine/mini with a --flat compiled
PNG, or use pngine --html which bypasses all JS runtimes entirely and emits
raw WebGPU API calls (~1–3 KB).
Viewer API (Default)
Usage scenario
Use viewer for normal playback of PNG payloads generated with the default embedded executor.
Input contract
pngine(
source: string | Uint8Array | ArrayBuffer | Blob,
options: {
canvas: HTMLCanvasElement;
debug?: boolean;
dpr?: number;
onError?: (err: Error) => void;
}
)Notes:
canvasis required.sourcecan be URL or byte data.wasmUrl, selector strings, andHTMLImageElementsources are dev-only features.- Viewer keeps wasm-in-wasm runtime support enabled by default.
- Viewer supports runtime interactivity via
draw(...uniforms),setUniform,setUniforms, andgetUniforms.
Example
import { pngine, play } from 'pngine';
const canvas = document.getElementById('canvas');
const p = await pngine('/assets/triangle.png', { canvas });
play(p);Dev API
Dev profile keeps the full feature set:
- Selector and image-element initialization paths.
- Shared executor fallback (
wasmUrl) for payloads without embedded executor. - Executor helper exports on the same entrypoint.
import { pngine, parsePayload } from 'pngine/dev';Core API
Core profile is for integrators who already manage device/context/lifecycle.
import { createCoreDispatcher, configureCanvas, getDevice } from 'pngine/core';Executor API
Advanced helpers for payload parsing and manual executor loading.
import { parsePayload, createExecutor, getExecutorImports } from 'pngine/executor';Mini API
Tiny player for --flat compiled payloads (pNGf format). Runs entirely on the
main thread — no Worker, no OffscreenCanvas, no WASM executor.
import { miniPngine } from 'pngine/mini';
const canvas = document.getElementById('canvas');
const inst = await miniPngine(canvas, '/shader-flat.png', { autoplay: true });
inst.play();
inst.pause();
inst.stop();
inst.destroy();
inst.time; // current time in seconds
inst.isPlaying; // animation statesource accepts string (URL), ArrayBuffer, or Uint8Array.
Bundle Sizes
| File | Raw | Gzip |
| --- | --- | --- |
| viewer.mjs | 70.0 KB | 16.1 KB |
| dev.mjs | 76.1 KB | 17.2 KB |
| core.mjs | 43.4 KB | 9.8 KB |
| executor.mjs | 5.0 KB | 1.7 KB |
| mini.mjs | 9.1 KB | 3.1 KB |
| mini-no-audio.mjs | 9.2 KB | 3.1 KB |
| index.js (Node stub) | 1.2 KB | - |
Build Commands
# Production bundles
npm run build
# Debug bundles (source maps, DEBUG=true)
npm run build:debugDist Files
dist/
├── viewer.mjs
├── dev.mjs
├── core.mjs
├── executor.mjs
├── mini.mjs
├── mini-no-audio.mjs
├── index.js # Node CJS stubs
├── index.mjs # Node ESM stubs
├── index.d.ts # default (viewer) types
├── viewer.d.ts
├── dev.d.ts
├── core.d.ts
├── executor.d.ts
├── mini.d.ts
└── mini-no-audio.d.tsCLI and Native Binaries
The package also ships the pngine CLI via optional native binaries:
| Package | Platform |
| --- | --- |
| @pngine/darwin-arm64 | macOS Apple Silicon |
| @pngine/darwin-x64 | macOS Intel |
| @pngine/linux-x64 | Linux x64 |
| @pngine/linux-arm64 | Linux ARM64 |
| @pngine/win32-x64 | Windows x64 |
| @pngine/win32-arm64 | Windows ARM64 |
License
CC0-1.0
