
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@slithy/prim-interface
Advanced tools
Browser-facing API for @slithy/prim-lib. Consumed by apps/prim-demo.
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.
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() {},
});
const job = runWorker(imageUrl, config, { // off-thread
onStart(raster, svg) {},
onStep({ raster, svg, svgString, stepData, progress }) {},
onComplete(serialized) {},
onStop() {},
});
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 automatically. Shape constructors in config.shapeTypes are mapped to names internally; only the built-in shapes (Triangle, Rectangle, Ellipse, Circle, Square, Hexagon, Glyph) are supported.
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)
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.
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.
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().
Higher-level (rasterize SVG at save time for crisp output):
saveRasterFromVector(svgString, width, height, format?, quality?, options?) — downloads PNG or JPEG rasterized from the SVGcopyRasterFromVector(svgString, width, height) — copies a PNG rasterized from the SVG to the clipboardshareFromVector(svgString, width, height, options?) — shares a PNG rasterized from the SVG via the Web Share APILower-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 availableSaveOptions 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): ReplayResultReconstructs 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);
Triangle, Rectangle, Ellipse, Circle, Square, Hexagon, Glyph, stepPerf, replayOutput, RGB, SerializedOutput, StepData, ReplayResult
FAQs
Browser-facing API for primitive-based image reconstruction.
We found that @slithy/prim-interface demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.