@slithy/prim-interface
v1.0.0
Published
Browser-facing API for primitive-based image reconstruction.
Downloads
822
Maintainers
Readme
@slithy/prim-interface
Browser-facing API for @slithy/prim-lib. Consumed by apps/prim-demo.
What it does
Wraps prim-lib in a run() / runWorker() API and provides save/copy/share helpers for exporting results. run() runs the optimizer on the main thread; runWorker() moves computation into a Web Worker, keeping the main thread responsive during long jobs. Both share the same callback API.
Vite setup
This package ships a Web Worker and is incompatible with Vite's dependency optimizer. Add it to optimizeDeps.exclude in your Vite config:
// vite.config.ts
optimizeDeps: {
exclude: ['@slithy/prim-interface']
}The same applies to electron-vite projects — the exclusion goes under renderer.optimizeDeps.exclude.
Exports
run(source, config, callbacks) / runWorker(source, config, callbacks)
Start a reconstruction job. Both return a JobHandle for stopping, pausing, and resuming, and accept identical arguments.
const job = run(imageUrl, config, { // main-thread
onStart(raster, svg) {},
onStep({ raster, svg, svgString, stepData, progress }) {},
onComplete(serialized) {},
onStop() {},
onError(message) {},
});
const job = runWorker(imageUrl, config, { // off-thread
onStart(raster, svg) {},
onStep({ raster, svg, svgString, stepData, progress }) {},
onComplete(serialized) {},
onStop() {},
onError(message) {},
});
job.stop();
job.pause();
job.resume();run() — runs the optimizer on the main thread via requestAnimationFrame. Simpler; no worker overhead. UI may feel sluggish during compute-heavy steps at high shapes / mutations settings.
runWorker() — moves all computation into a Web Worker using OffscreenCanvas. The main thread only handles DOM updates (appending the canvas/SVG, calling callbacks). Requires a bundler that understands new Worker(new URL(..., import.meta.url)) — Vite handles this, but see the Vite setup section above for a required config change. Both fixed shapes (Triangle, Rectangle, etc.) and factory shapes (makeNGon, makeRect) are supported in config.shapeTypes.
Config
interface Config {
steps: number // shapes in the final image
shapes: number // candidate shapes evaluated per step
mutations: number // random mutations tried per candidate
alpha: number // shape opacity
mutateAlpha: boolean // whether opacity is mutated per candidate
computeSize: number // internal render resolution (px, longest edge)
viewSize: number // display/output resolution (px, longest edge)
allowUpscale?: boolean // allow output larger than source image (default: false)
pixelRatio?: number // device pixel ratio for the raster canvas (default: 1)
glyphChar?: string // Unicode character for the Glyph shape (default: '☺')
shapeTypes: ShapeConstructor[]
shapeWeights?: number[] // per-shape selection weights (same length as shapeTypes)
fill: 'auto' | string
}width, height, and scale are set automatically by run() after loading the source image.
allowUpscale — by default, output is capped at source image dimensions. Set to true to allow viewSize and computeSize to exceed the source, upscaling the output.
pixelRatio — pass window.devicePixelRatio to produce a HiDPI raster canvas. The canvas pixel dimensions are viewSize × pixelRatio; set its CSS size to viewSize for a 1:1 device pixel mapping. Does not affect the SVG output or the optimizer; only the raster display canvas.
glyphChar — Unicode character used by the Glyph shape when running via runWorker(). Defaults to '☺' when omitted. Has no effect with run(), since the main-thread path accepts shape constructors directly (subclass Glyph with a custom character if needed).
shapeWeights — optional array of weights, one per entry in shapeTypes, controlling how often each shape type is used. Weights are relative (e.g. [3, 1] means 75% / 25%). When provided, the optimizer pre-allocates an exact number of slots per shape type (proportional to the weights) and shuffles them, guaranteeing the final distribution matches — rather than just biasing random selection.
Callbacks
onStart(raster, svg) — called once after the source image loads. raster is the display canvas; svg is the live SVG element. Both update in place as shapes are added.
onStep(result) — called after each accepted shape:
interface StepResult {
raster: HTMLCanvasElement
svg: SVGSVGElement
svgString: string // serialized SVG markup
stepData: StepData // structured data for this shape
progress: {
current: number // shapes placed so far
total: number // cfg.steps
similarity: number // % similarity to source (0–100)
}
}onComplete(serialized) — called when all steps finish. Receives a SerializedOutput — a compact, storage-ready representation of the full run that can be replayed via replayOutput().
onStop() — called when the job is stopped via job.stop().
onError(message) — called if the job fails (e.g. image failed to load or decode). The job is considered stopped after this; no further callbacks will fire.
Exit helpers
Higher-level (rasterize SVG at save time for crisp output):
saveRasterFromVector(svgString, width, height, format?, quality?, options?, background?)— downloads PNG or JPEG rasterized from the SVG.backgroundfills the canvas before drawing: JPEG defaults to'white'(prevents black transparent areas); PNG defaults to transparent. Pass aBackgroundvalue to override.copyRasterFromVector(svgString, width, height)— copies a transparent PNG rasterized from the SVG to the clipboardshareFromVector(svgString, width, height, options?)— shares a transparent PNG rasterized from the SVG via the Web Share API
Lower-level (operate directly on a canvas or SVG string):
saveRaster(canvas, format?, quality?, options?)— downloads PNG or JPEG from a canvassaveVector(svgString, options?)— downloads SVGcopyRaster(canvas)— copies PNG to clipboardcopyVector(svgString)— copies SVG markup to clipboardshare(canvas, options?)— shares via Web Share API if available
SaveOptions controls download filenames, formatted as ${filename}--${suffix}.${ext}:
interface SaveOptions {
suffix?: string // default: 'prim'
filename?: string // stem without extension, default: 'output'
}Example: saveRaster(canvas, 'png', 0.92, { filename: 'mountains', suffix: 'v2' }) → mountains--v2.png
replayOutput(data: SerializedOutput): ReplayResult
Reconstructs a raster canvas and SVG from a SerializedOutput without re-running the optimizer. Use this to restore saved results from localStorage or a database.
const { raster, svg, svgString } = replayOutput(serializedData);Re-exports from prim-lib
Shapes: Triangle, Rectangle, Ellipse, Circle, Square, Hexagon, Glyph
Factories: makeNGon, makeRect
Factory option types: NGonOptions, RectOptions
Functions: stepPerf, replayOutput
Types: RGB, SerializedOutput, StepData, ReplayResult, ShapeInterface, Bbox, Background
Background controls the canvas fill for saveRasterFromVector:
type Background = string | [png: string, jpeg: string]Pass a CSS color string to use the same background for all formats, or a tuple to set PNG and JPEG fills independently.
