npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@posty5/psd-editor

v1.1.3

Published

Edit PSD templates — replace image and text layers, save the edited PSD, and render PNG. Single class API.

Readme

@posty5/psd-editor

Edit reusable Photoshop PSD templates — replace named image and text layers, save the edited PSD, and render a PNG or JPEG. One class, one method, zero hassle.


🌟 What is @posty5/psd-editor?

@posty5/psd-editor is a Node.js package that lets you programmatically edit PSD templates. It exposes a single PsdEditor class with one main method — edit() — making integration as simple as possible.

  • 🖼️ Replace Image Layers — Swap placeholders with local files or remote URLs
  • ✏️ Replace Text Layers — Update text content with automatic RTL detection
  • 💾 Save Edited PSD — Write the modified PSD back to disk
  • 🎨 Render PNG or JPEG — Flatten and export the result in your preferred format
  • 🔍 High-Quality Output — Scale up to 2×, 3×, or any multiplier for Retina/print
  • 🎯 JPEG Quality Control — Fine-tune compression between 0 (smallest) and 1 (best)
  • 🧹 Auto Cleanup — Downloaded remote images are released from memory automatically
  • 📦 Single API — One class, one method, typed with TypeScript

Part of the Posty5 ecosystem: https://posty5.com


📦 Installation

npm install @posty5/psd-editor

Note: canvas is a native dependency. Some Linux environments require Cairo/Pango system packages. Follow the node-canvas installation guide if npm cannot install its prebuilt binary.


🚀 Quick Start

import { PsdEditor } from '@posty5/psd-editor';

const editor = new PsdEditor();

const result = await editor.edit({
  templatePath: './templates/social-post.psd',
  images: {
    IMAGE_1: './images/local-photo.jpg',
    'AR/front/Image_Logo': 'https://cdn.example.com/logo.png'
  },
  texts: {
    TITLE_1: 'A new English title',
    'AR/front/Trend Now/التريند الآن': 'التريند الآن'
  },
  outputFormat: 'jpeg',
  quality: 0.92,
  psdOutputPath: './output/edited.psd',
  outputPath: './output/social-post.jpg'
});

console.log(result.outputPath);   // absolute path to the rendered image
console.log(result.psdOutputPath); // absolute path to the edited PSD
console.log(result.width, result.height);

If output paths are omitted, use the returned buffer directly:

const { imageBuffer } = await editor.edit({
  templatePath: './template.psd',
  images: { PHOTO: './photo.jpg' }
});

await uploadSomewhere(imageBuffer);

📚 API Documentation

PsdEditor Class

The main entry point. Create an instance and call edit():

import { PsdEditor } from '@posty5/psd-editor';

const editor = new PsdEditor();

editor.edit(options) — Edit a PSD Template

Replace image and text layers, save the edited PSD, and render an image.

Parameters:

interface EditOptions {
  templatePath: string;                        // Path to the source PSD template
  images?: Record<string, ImageSource>;        // Layer name → image source
  texts?: Record<string, string>;              // Layer name → replacement text
  description?: string;                        // Optional label for the result
  psdOutputPath?: string;                      // Save edited PSD to this path
  outputPath?: string;                         // Save rendered image to this path
  outputFormat?: 'png' | 'jpeg';              // Output format (default: 'png')
  quality?: number;                            // JPEG quality 0–1 (default: 0.92)
  scale?: number;                              // Resolution multiplier (default: 1)
  remoteImages?: {
    timeoutMs?: number;                        // Download timeout (default: 15s)
    maxBytes?: number;                         // Max download size (default: 20 MiB)
    headers?: Record<string, string>;          // HTTP headers for remote downloads
  };
  logger?: (message: string) => void;          // Progress callback
}

Returns:

interface EditResult {
  imageBuffer: Buffer;       // Rendered image data (PNG or JPEG)
  outputFormat: 'png' | 'jpeg'; // Format of imageBuffer
  width: number;             // Logical PSD width in pixels (before scale)
  height: number;            // Logical PSD height in pixels (before scale)
  renderedWidth: number;     // Actual image width (width × scale)
  renderedHeight: number;    // Actual image height (height × scale)
  description?: string;      // Label when provided
  outputPath?: string;       // Absolute path when outputPath was set
  psdOutputPath?: string;    // Absolute path when psdOutputPath was set
}

PsdEditor.listLayers(templatePath) — Inspect Template Layers

Static method. Returns every layer path in template order as string[].

import { PsdEditor } from '@posty5/psd-editor';

const layers = PsdEditor.listLayers('./template.psd');
console.log(layers);
// ['Background', 'Group/IMAGE_1', 'Group/TITLE_1', ...]

Layer matching is case-insensitive. If the same name occurs more than once, pass its full path to remove ambiguity.


🎯 Output Format & Quality

Control the output format and compression quality via outputFormat and quality.

PNG (default — lossless)

const result = await editor.edit({
  templatePath: './template.psd',
  images: { PHOTO: './photo.jpg' },
  outputFormat: 'png',          // lossless, larger file
  outputPath: './output/result.png'
});

JPEG (lossy — smaller file size)

const result = await editor.edit({
  templatePath: './template.psd',
  images: { PHOTO: './photo.jpg' },
  outputFormat: 'jpeg',
  quality: 0.9,                 // 0 = smallest file, 1 = best quality
  outputPath: './output/result.jpg'
});

| quality | Description | | --- | --- | | 1.0 | Maximum quality, largest file | | 0.92 | Default — excellent quality, good compression | | 0.8 | Good quality, noticeably smaller file | | 0.6 | Moderate quality, very small file | | 0 | Minimum quality, smallest file |

quality only applies when outputFormat is 'jpeg'. It is ignored for PNG.

Using the buffer directly

const result = await editor.edit({
  templatePath: './template.psd',
  images: { PHOTO: './photo.jpg' },
  outputFormat: 'jpeg',
  quality: 0.85
});

// result.imageBuffer — ready to upload, stream, or store
console.log(result.outputFormat); // 'jpeg'
await s3.putObject({ Body: result.imageBuffer, ContentType: 'image/jpeg' });

🔍 High-Quality Output (scale)

Use the scale option to render the image at a higher resolution than the native PSD size. Ideal for print, Retina displays, or any output that requires more pixels.

| scale | Output size for a 1254×960 PSD | | --- | --- | | 1 (default) | 1254 × 960 px | | 2 | 2508 × 1920 px | | 3 | 3762 × 2880 px |

const result = await editor.edit({
  templatePath: './template.psd',
  images: { PHOTO: './photo.jpg' },
  outputFormat: 'jpeg',
  quality: 0.92,
  scale: 2,                     // 2× resolution
  outputPath: './output/[email protected]'
});

console.log(result.width);          // 1254 — logical PSD width
console.log(result.renderedWidth);  // 2508 — actual pixel width in the file

scale must be a positive number. Fractional values (e.g. 0.5) are also accepted to downscale.


🖼️ Image Sources

Each value in images accepts one of the following:

type ImageSource = string | URL | Buffer | Uint8Array;

| Source Type | Example | Notes | | --- | --- | --- | | Local file | './assets/cover.jpg' | Resolved from process.cwd() | | Remote URL | 'https://cdn.example.com/photo.png' | Downloaded automatically | | URL object | new URL('https://...') | Same as string URL | | Buffer | fs.readFileSync('./img.png') | In-memory image data | | Uint8Array | Raw byte array | Converted to Buffer internally |

Remote Image Configuration

await editor.edit({
  templatePath: './template.psd',
  images: {
    PHOTO: 'https://private-cdn.example.com/photo.jpg'
  },
  remoteImages: {
    timeoutMs: 10_000,
    maxBytes: 8 * 1024 * 1024,
    headers: {
      Authorization: `Bearer ${process.env.CDN_TOKEN}`
    }
  }
});

🧹 Automatic cleanup — All downloaded remote images are released from memory after edit() completes, even if an error occurs.

⚠️ Security — The caller is responsible for URL trust. Do not pass arbitrary user-controlled URLs without SSRF protection.


✏️ Text and Fonts

texts: {
  TITLE: 'English title',
  ARABIC_TITLE: 'عنوان عربي'
}

Key behaviors:

  • 🔄 Auto-direction — RTL/LTR is detected from content, not locked to the template
  • 📦 Paragraph boxes — Text on a paragraph (box) layer wraps to the PSD text box and the font auto-shrinks so long strings fit instead of being clipped
  • ↔️ Point text grows — Text on a point layer keeps its anchor while the raster grows to fit longer strings
  • 📐 Original size — Replacement text starts from the font size defined by the PSD layer
  • 🔤 System fonts — Fonts referenced by the PSD must be installed on the OS

Tip: On Ubuntu, install fonts in ~/.local/share/fonts or /usr/local/share/fonts, then run fc-cache -f.


🔧 Runtime Dependencies

| Package | Purpose | | --- | --- | | ag-psd | Read and write PSD structure, layer data, masks, vectors, and text metadata | | canvas | Decode images and render the final PNG or JPEG |

No separate HTTP client is used — remote images use the built-in Node.js fetch.


💻 Node.js Compatibility

  • Node.js: >= 18.0.0
  • Module Systems: ESM and CommonJS
  • TypeScript: Full type definitions included

🛠️ Development

npm install
npm run typecheck
npm test
npm run build

To inspect what npm will publish:

npm pack --dry-run

📄 License

MIT — see LICENSE for details.


🔗 Useful Links


Made with ❤️ by the Posty5 team