psd-to-svg-mockup
v0.1.0
Published
Convert a Photoshop product-mockup .psd into ONE structured "design-quad" SVG (and edit existing ones) — a faithful layer-by-layer transcription with effects, masks and clipping, not image-to-vector tracing.
Downloads
45
Maintainers
Readme
psd-to-svg-mockup
Convert a Photoshop product‑mockup .psd into ONE structured "design‑quad" SVG — and
edit existing ones. It's a faithful layer‑by‑layer transcription (the PSD already is a
mockup: raster layers + a placeholder for the artwork), not image‑to‑vector tracing.
The output SVG carries a placeholder polygon:
<polygon id="Design" points="x1,y1 x2,y2 x3,y3 x4,y4"
data-radius="…" data-blend="…" data-opacity="…" />Any consumer of that contract warps a design image into the quad at runtime — deterministically, no AI.
Self‑contained: zero workspace dependencies — only three npm deps.
Install
npm i psd-to-svg-mockup # pulls ag-psd, @napi-rs/canvas, sharpimport { psdToStructuredSvg } from "psd-to-svg-mockup";Node 18+, ESM. @napi-rs/canvas + sharp ship prebuilt native binaries (incl. Windows/Intel).
Ships compiled JavaScript + type declarations (dist/); the TypeScript source lives in the repo.
Quick start
import { readFileSync, writeFileSync } from "node:fs";
import { psdToStructuredSvg } from "psd-to-svg-mockup";
const { svg, width, height, design, warnings } = await psdToStructuredSvg(readFileSync("mockup.psd"));
writeFileSync("mockup.svg", svg); // structured, ready to compose into
console.log(design.points, `${width}×${height}`, warnings);API
One‑shot
psdToStructuredSvg(buf): Promise<PsdConvertResult>— auto‑detect the design placeholder, split layers below/above it, flatten and emit the SVG.{ svg, width, height, design, layers, warnings }.
Two‑step (for a review/edit UI)
analyzePsd(buf): Promise<PsdAnalysis>— every layer (name, bounds, blend, opacity, smart, hidden flag, own masked pixels as a WebP data URL for client compositing), the detecteddesignIndex+quad, and a compositepreview.buildSvgFromPlan(buf, plan): Promise<{ svg, … }>— turn an explicitPsdPlan { designIndex|null, quad?, belowIndices[], aboveIndices[], radius?, blend?, opacity? }into the SVG. Every plan field is validated/whitelisted (they end up inside SVG attributes).
Edit an existing structured SVG
analyzeStructuredSvg(svg): SvgMockupDoc— decompose a stored mockup back into layers + quad +data-*styling. Handles legacy nested‑<svg>files (normalizes all coordinates into the root viewBox) and reads each image'spreserveAspectRatio+mix-blend-mode.rebuildStructuredSvg(doc, plan): { svg, … }— re‑assemble a clean contract SVG, reusing the embedded rasters byte‑for‑byte (no recompression).
What it preserves
Photoshop renders these but ag-psd only parses them as metadata — this package renders the
feasible subset onto @napi-rs/canvas during flattening:
- Layer effects: drop / inner shadow, outer / inner glow, color overlay, color stroke, bevel/emboss (approximated as a directional edge band). Global light angle is honored; choke is treated as a 0–100 % spread; HSB/CMYK/LAB effect colors are converted to sRGB.
- Masks: raster layer masks and ancestor group masks (multiplicative).
- Group opacity is baked into each child.
- Clipping groups — bases resolved over the full z‑order; a layer clipped to a hidden base is skipped, like Photoshop.
- Hidden "place your design" placeholders are still detected for the quad (pixels excluded).
- Blend modes: PSD modes map to CSS
mix-blend-mode;linear dodge→screen; a multiply/screen layer above the design is emitted as its ownmix-blend-modeimage so it blends with the composed design at runtime instead of becoming an opaque wash. - Design‑layer cut‑outs (e.g. a camera hole in the case shape) are re‑painted into the overlay so they stay visible over the placed design.
Rasters are embedded as bounded WebP (≤ 2000 px) while the viewBox keeps the original PSD
size, so SVGs stay small and the quad still lines up.
Note:
librsvg(whatsharpuses to rasterize SVG) cannot decode WebP data‑URLs — browsers can. If you rasterize these SVGs server‑side with sharp, transcode the embedded layers to PNG first. Browser/<img>rendering and@mycelium/svg-mockupcompositing are unaffected.
Test
npm test # synthetic PSD → convert → assert contract → edit round-trip (tsx test/smoke.ts)