
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@slithy/prim-lib
Advanced tools
Core engine for primitive-based image reconstruction. Consumed by @slithy/prim-interface.
Reconstructs an image by iteratively placing geometric shapes. Each step evaluates candidate shapes, mutates them, picks the one that most reduces the difference from the target, and draws it onto the working canvas.
Canvas — wraps HTMLCanvasElement or OffscreenCanvas (environment-detected); handles image loading, pixel reads, drawing steps, and SVG outputOptimizer — runs the step loop; calls onStep after each shape is placed. Accepts an optional schedule function (defaults to requestAnimationFrame; pass fn => setTimeout(fn, 0) for worker contexts)State — holds the current canvas and its distance from the targetStep — a single candidate shape placement; computes best color and difference changeShape — abstract baseTriangle, Rectangle, Ellipse, Circle, Square, Hexagon, Glyph, DebugCfg — runtime config (all fields required):
interface Cfg {
width: number // image width for computation (set by Canvas.original)
height: number // image height for computation (set by Canvas.original)
steps: number // total shapes to place
shapes: number // candidate shapes evaluated per step
mutations: number // hill-climb attempts per candidate
alpha: number // starting shape opacity
mutateAlpha: boolean // whether opacity is mutated per candidate
computeSize: number // max image dimension for pixel distance calculations
viewSize: number // max image dimension for display canvas
allowUpscale?: boolean // allow output larger than source image (default: false)
scale?: number // viewSize / computeSize ratio (set by Canvas.original)
shapeTypes: Array<new (w: number, h: number) => ShapeInterface>
shapeWeights?: number[] // per-shape selection weights (same length as shapeTypes)
fill: 'auto' | string
}
PreCfg — Cfg with optional width/height; used before image dimensions are knownShapeInterface — structural interface for shapes; includes toData(alpha, color): StepDataCtx2D — CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D; used for canvas operations that work in both main-thread and worker contextsBbox, Point, ImageDataLike, ShapeImageDataRGB — [number, number, number] tuple
StepData — discriminated union of serialized shape data, keyed by t:
type StepData =
| { t: 't'; a: number; c: RGB; pts: [number, number][] } // Triangle
| { t: 'r'; a: number; c: RGB; pts: [number, number][] } // Rectangle
| { t: 'e'; a: number; c: RGB; cx: number; cy: number; rx: number; ry: number } // Ellipse
| { t: 'c'; a: number; c: RGB; cx: number; cy: number; r: number } // Circle
| { t: 's'; a: number; c: RGB; cx: number; cy: number; r: number } // Square
| { t: 'h'; a: number; c: RGB; cx: number; cy: number; r: number; angle: number } // Hexagon
| { t: 'sm'; a: number; c: RGB; cx: number; cy: number; fs: number; text: string } // Glyph
SerializedOutput — compact, storage-ready representation of a completed run:
interface SerializedOutput {
v: 1 // schema version
w: number // compute width
h: number // compute height
scale: number // viewSize / computeSize ratio
fill: RGB // background fill color
steps: StepData[]
}
ReplayResult — returned by replayOutput:
interface ReplayResult {
raster: HTMLCanvasElement | OffscreenCanvas
svg: SVGSVGElement
svgString: string
}
replayOutput(data: SerializedOutput): ReplayResult — reconstructs canvas and SVG natively from serialized output, without re-running the optimizer. Useful for restoring saved results from localStorage or a database.
renderStepToCtx(data: StepData, ctx: Ctx2D): void — renders a single StepData onto a 2D canvas context. Used internally by replayOutput and by runWorker to incrementally apply worker-posted steps to the display canvas.
stepDataToSVGElement(data: StepData): SVGElement — creates a DOM SVGElement from a StepData. Used internally by replayOutput and by runWorker to build the live SVG incrementally on the main thread.
getFill(data: ImageDataLike): string — computes a fill color (average of corner pixels) from image dataparseColor(str: string): RGB — parses "rgb(r, g, b)" to an [r, g, b] tuplestepPerf — accumulator for profiling rasterize vs pixel math time per stepprim-lib is derived from primitive.js, a JavaScript port of the Go primitive library by Michael Fogleman. The core algorithm — iterative shape placement via hill-climbing — is unchanged. What's different:
strict: true on both packagesimportScripts()<canvas> element for every shape rasterization call (~58,000 per run at default settings). prim-lib reuses a single module-level canvas, growing it only when a larger bbox is seen. This delivered a ~27× speedup (37 s → ~0.8 s rasterize time per run)willReadFrequently: true — canvas contexts used for getImageData are created with this flag, keeping pixel data in CPU memory and suppressing browser warningsCanvas detects its environment: in a browser context it creates HTMLCanvasElement; in a worker it creates OffscreenCanvas (same 2D API). Canvas.fromBitmap() loads an image from an ImageBitmap (worker-compatible) rather than new Image(). Optimizer accepts an injectable schedule function so callers can substitute setTimeout for requestAnimationFrame in worker contexts. The original included importScripts()-based worker stubs (not ESM-compatible) which were removed; worker support is now done properly via prim-interface's runWorker()prim-lib is the pure algorithm (no knowledge of how images arrive or where results go), and prim-interface is the adapter that wires it to the browserPreCfg / Cfg distinction — Canvas.original() accepts PreCfg (optional width/height) and resolves to a fully-populated Cfg, making the config lifecycle explicit in the typesStepData / SerializedOutput allow completed runs to be stored compactly and replayed via replayOutput() without re-running the optimizerCircle, Square, Hexagon, and Glyph are not in the original; Circle is a uniform-radius variant of EllipseshapeWeights allows biased shape selection with a guaranteed distribution: the optimizer pre-allocates exact per-shape step counts (largest-remainder rounding) and shuffles them, so the final mix always matches the requested weightsShape.rasterize() reuses a single module-level canvas (_rasterCanvas) grown to the max shape size seen; in a worker, this is an OffscreenCanvas (environment-detected by the Canvas constructor). Avoids per-call canvas creation which was the dominant cost (27x speedup)Cfg.shapeTypes holds shape constructors; shapes are chosen randomly each step unless shapeWeights is setshapeWeights is provided (same length as shapeTypes), Optimizer builds a step plan at construction time: each shape type is allocated an exact number of slots proportional to its weight (using largest-remainder rounding), then the plan is Fisher-Yates shuffled. This guarantees the final shape distribution matches the weights, rather than just biasing random selectionPreCfg exists to bridge the gap between call time (dimensions unknown) and runtime (dimensions set by Canvas.original() or Canvas.fromBitmap())Canvas.svgRoot() is a static helper shared by Canvas.empty() and replayOutput() to create the SVG root with clip path and background fill; it uses DOM APIs and is main-thread onlyFAQs
Core engine for primitive-based image reconstruction.
We found that @slithy/prim-lib 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
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.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.