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

pixly

v1.0.1

Published

A modern, composable image processing library for JavaScript and TypeScript that provides a type-safe builder API for image transformations.

Readme

Pixly

A modern, composable image processing library for JavaScript and TypeScript that provides a type-safe builder API for image transformations.

Installation

npm install pixly
# or
yarn add pixly
# or
bun add pixly

Quick Start

import { px } from 'pixly';

// Process an image with auto-detection
const result = await px.decoder(px.auto())
  .encoder(px.webp.encode({ quality: 80 }))
  .apply(px.resize({ width: 800 }))
  .process('path/to/image.jpg');

// Get the result as different formats
const buffer = result.toBuffer();
const blob = result.toBlob();
const dataUrl = result.toDataURL();

Core Concepts

Builder Pattern

Pixly uses a fluent builder pattern that guides you through the image processing pipeline:

  1. Set a decoder (to read the input format)
  2. Set an encoder (to write the output format)
  3. Apply transformations
  4. Process the input
const result = await px.decoder(px.jpeg.decode())     // 1. Decode JPEG
  .encoder(px.png.encode())                           // 2. Encode to PNG
  .apply(px.resize({ width: 500 }))                   // 3. Add operations
  .apply(px.rotate(90))                                // 3. Chain more operations
  .process(imageInput);                                // 4. Process

Type Safety

The API uses TypeScript to ensure correct usage:

  • decoder() and encoder() must be called before process()
  • Each can only be called once
  • Operations are type-checked

Input Types

Pixly accepts various input types:

// From URL
const result = await px.decoder(px.auto())
  .encoder(px.webp.encode())
  .process('https://example.com/image.jpg');

// From File (browser)
const result = await px.decoder(px.auto())
  .encoder(px.webp.encode())
  .process(fileInput.files[0]);

// From Buffer/ArrayBuffer
const result = await px.decoder(px.auto())
  .encoder(px.webp.encode())
  .process(arrayBuffer);

// From Blob
const result = await px.decoder(px.auto())
  .encoder(px.webp.encode())
  .process(blob);

Codecs

Available Codecs

Each codec provides both decode() and encode() methods:

  • PNG: px.png
  • JPEG: px.jpeg
  • WebP: px.webp
  • AVIF: px.avif
  • JPEG XL: px.jxl
  • QOI: px.qoi
  • Auto: px.auto (decode only - auto-detects format)

Format Conversion

// Convert PNG to JPEG
const result = await px.decoder(px.png.decode())
  .encoder(px.jpeg.encode({ quality: 90 }))
  .process(pngImage);

// Convert any format to WebP
const result = await px.decoder(px.auto())
  .encoder(px.webp.encode({ quality: 85, lossless: false }))
  .process(inputImage);

Encoder Options

Different codecs support different encoding options:

// JPEG options
px.jpeg.encode({ quality: 90 });

// WebP options
px.webp.encode({ quality: 85, lossless: false });

// PNG options
px.png.encode({ compressionLevel: 6 });

Operations

All operations are applied using the apply() method:

Resize

const result = await px.decoder(px.auto())
  .encoder(px.webp.encode())
  .apply(px.resize({
    width: 800,
    height: 600,
    fit: 'cover',        // 'cover' | 'contain' | 'fill' | 'inside' | 'outside'
    position: 'center',  // Position when cropping
    background: [255, 255, 255, 0] // RGBA background color
  }))
  .process(input);

Rotate

const result = await px.decoder(px.auto())
  .encoder(px.jpeg.encode())
  .apply(px.rotate(90))  // Rotate 90 degrees clockwise
  .process(input);

Flip

const result = await px.decoder(px.auto())
  .encoder(px.png.encode())
  .apply(px.flip('horizontal'))  // 'horizontal' or 'vertical'
  .process(input);

Crop

const result = await px.decoder(px.auto())
  .encoder(px.webp.encode())
  .apply(px.crop({
    x: 100,
    y: 100,
    width: 400,
    height: 300
  }))
  .process(input);

Blur

const result = await px.decoder(px.auto())
  .encoder(px.jpeg.encode())
  .apply(px.blur(5))  // Blur radius
  .process(input);

Sharpen

const result = await px.decoder(px.auto())
  .encoder(px.jpeg.encode())
  .apply(px.sharpen(1.5))  // Sharpen amount
  .process(input);

Brightness

const result = await px.decoder(px.auto())
  .encoder(px.jpeg.encode())
  .apply(px.brightness(1.2))  // 1.0 = no change, >1 = brighter, <1 = darker
  .process(input);

Chaining Operations

Operations can be chained to create complex transformations:

const result = await px.decoder(px.auto())
  .encoder(px.webp.encode({ quality: 80 }))
  .apply(px.resize({ width: 1200, height: 800, fit: 'cover' }))
  .apply(px.rotate(45))
  .apply(px.brightness(1.1))
  .apply(px.sharpen(1.2))
  .apply(px.blur(0.5))
  .process(input);

Presets

Create reusable operation chains:

// Create a preset (without encoder/decoder)
const thumbnailPreset = px
  .apply(px.resize({ width: 150, height: 150, fit: 'cover' }))
  .apply(px.sharpen(1.2))
  .preset();

const instagramPreset = px
  .apply(px.resize({ width: 1080, height: 1080, fit: 'cover' }))
  .apply(px.brightness(1.05))
  .apply(px.sharpen(1.1))
  .preset();

// Use presets in different contexts
const thumbnail = await px.decoder(px.auto())
  .encoder(px.webp.encode({ quality: 80 }))
  .apply(thumbnailPreset)
  .process(input);

const instagramPost = await px.decoder(px.auto())
  .encoder(px.jpeg.encode({ quality: 90 }))
  .apply(instagramPreset)
  .process(input);

Output Formats

The processing result provides multiple output methods:

const result = await px.decoder(px.auto())
  .encoder(px.webp.encode())
  .apply(px.resize({ width: 800 }))
  .process(input);

// Get as Uint8Array buffer
const buffer = result.toBuffer();

// Get as Blob (useful in browsers)
const blob = result.toBlob();

// Get as data URL (base64 encoded)
const dataUrl = result.toDataURL();

Error Handling

Pixly provides clear error messages for common issues:

try {
  // This will throw - decoder and encoder required
  const result = await px
    .apply(px.resize({ width: 100 }))
    .process(input);
} catch (error) {
  console.error('Processing failed:', error.message);
}

TypeScript Support

Pixly is written in TypeScript and provides full type safety:

import type {
  ImageEditor,
  ProcessingResult,
  ResizeOptions,
  ImageInput
} from 'pixly';

Examples

Creating Multiple Sizes

const sizes = [
  { width: 150, name: 'thumbnail' },
  { width: 800, name: 'medium' },
  { width: 1920, name: 'large' }
];

const results = await Promise.all(
  sizes.map(async ({ width, name }) => {
    const result = await px.decoder(px.auto())
      .encoder(px.webp.encode({ quality: 85 }))
      .apply(px.resize({ width }))
      .process(originalImage);

    return {
      name,
      blob: result.toBlob()
    };
  })
);

Batch Processing with Preset

// Create a web optimization preset
const webOptimized = px
  .apply(px.resize({ width: 1920, height: 1080, fit: 'inside' }))
  .apply(px.sharpen(1.1))
  .preset();

// Apply to multiple images
const processedImages = await Promise.all(
  imageFiles.map(file =>
    px.decoder(px.auto())
      .encoder(px.webp.encode({ quality: 85 }))
      .apply(webOptimized)
      .process(file)
  )
);

Format Conversion Pipeline

// Convert all images to modern formats
async function modernizeImage(input: ImageInput) {
  // Try AVIF first (best compression)
  try {
    return await px.decoder(px.auto())
      .encoder(px.avif.encode({ quality: 80 }))
      .process(input);
  } catch {
    // Fall back to WebP
    return await px.decoder(px.auto())
      .encoder(px.webp.encode({ quality: 85 }))
      .process(input);
  }
}

Profile Picture Generator

const profilePicturePreset = px
  .apply(px.resize({ width: 400, height: 400, fit: 'cover' }))
  .apply(px.sharpen(1.2))
  .preset();

async function generateProfilePicture(file: File) {
  const result = await px.decoder(px.auto())
    .encoder(px.jpeg.encode({ quality: 90 }))
    .apply(profilePicturePreset)
    .process(file);

  return result.toBlob();
}

Browser and Node.js Support

Pixly works in both browser and Node.js environments, automatically handling environment-specific features.

Performance Tips

  1. Reuse Presets: Create presets once and reuse them for consistent transformations
  2. Choose Appropriate Formats: Use WebP or AVIF for smaller file sizes, JPEG for photos, PNG for images with transparency
  3. Optimize Quality Settings: Balance quality and file size based on your use case
  4. Process in Parallel: Use Promise.all() for batch processing

License

MIT