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

dkb-texture-optimize-pro

v1.1.0

Published

Texture optimization library for HTML5 games (PixiJS/ThreeJS) with per-texture configuration and in-place optimization using Sharp

Readme

Texture Optimize Pro

🎨 Texture optimization library for HTML5 games (PixiJS/ThreeJS) with per-texture configuration

Optimize your game textures with Sharp - the fastest Node.js image processing library. Configure each texture individually by name with custom max sizes, formats, and quality settings.

✨ Features

  • Lightning Fast - Powered by Sharp (libvips) for 4-26x faster processing.
  • 🎯 Per-Texture Configuration - Each texture can have custom settings based on filename.
  • 📏 Automatic Power-of-2 - Automatically resizes to nearest power-of-2 for WebGL compatibility (32, 64, 128, 256, 512, 1024, 2048, 4096).
  • 📐 Always Maintains Aspect Ratio - Never stretches or skews your images.
  • 🖼️ Preserves Input Format - Your .png files stay .png, and .jpg stay .jpg.
  • 🗜️ Optimized Compression - Applies quality settings for PNG, JPG, and WebP.
  • 📦 Batch Processing - Process entire directories with configurable concurrency.
  • 🔄 Smart Re-optimization - Automatically preserves originals for unlimited quality-preserving re-optimizations.
  • 🎮 Game-Optimized - Built for PixiJS, ThreeJS, and playable ads.
  • 🔧 TypeScript - Full type safety and IntelliSense support.

📦 Installation

npm install dkb-texture-optimize-pro
# or
yarn add dkb-texture-optimize-pro
# or
pnpm add dkb-texture-optimize-pro

🚀 Quick Start

This guide will walk you through setting up and using the texture optimizer for your project.

1. Prepare Your Project Structure

Create a directory structure for your textures:

your-project/
├── src/
│   └── assets/
│       └── textures/
│           ├── player-sprite.png
│           ├── enemy-goblin.png
│           ├── background-sky.jpg
│           └── ui/
│               ├── button.png
│               └── icon.png
└── package.json

2. Initialize Configuration

Run the init command to create a sample configuration file:

npx texture-optimizer init

This creates texture-optimize-pro.json in your project root.

3. Configure Your Textures

Edit texture-optimize-pro.json to match your texture files:

{
  "defaultSettings": {
    "maxSize": 512,
    "quality": 80
  },
  "textures": [
    {
      "name": "player-sprite",
      "useDefault": false,
      "maxSize": 512,
      "quality": 85
    },
    {
      "name": "enemy-goblin",
      "useDefault": false,
      "maxSize": 256,
      "quality": 80
    },
    {
      "name": "background-sky",
      "useDefault": true
    }
  ]
}

See the "Configuration" section below for a detailed breakdown.

4. Run the Optimizer

The optimizer supports two modes:

Option A: In-Place Optimization (Recommended for Development)

Optimizes textures in their current location and backs up originals automatically:

npx texture-optimizer build --base-path src/assets/textures

What happens:

  • Originals automatically backed up to _originalTexture/ folders
  • Optimized textures replace originals in place
  • Perfect for iterative development and re-optimization

Expected Output:

🎨 Texture Optimizer for HTML5 Games

Config: /path/to/texture-optimize-pro.json
Input:  /path/to/src/assets/textures
Mode:   In-place optimization (originals → _originalTexture)

📋 Loading texture configuration from: /path/to/texture-optimize-pro.json
   Found 3 configured textures in config
📁 Found 5 texture files to process

✓ [IN-PLACE] [CUSTOM] player-sprite.png → player-sprite.png (45.2% smaller, 0.15 MB, 512x512, maxSize: 512px)
✓ [IN-PLACE] [CUSTOM] enemy-goblin.png → enemy-goblin.png (52.1% smaller, 0.08 MB, 256x256, maxSize: 256px)
✓ [IN-PLACE] [DEFAULT] background-sky.jpg → background-sky.jpg (12.3% smaller, 1.24 MB, 1024x1024, maxSize: 1024px)

==================================================
Processing Summary
✓ Successful: 3/3
📦 Originals backed up to: _originalTexture/ folders

After optimization:

textures/
├── player-sprite.png          (optimized)
├── enemy-goblin.png           (optimized)
└── _originalTexture/
    ├── player-sprite.png      (original backup)
    └── enemy-goblin.png       (original backup)

Option B: Output Directory Mode (Recommended for Production)

Outputs optimized textures to a separate directory, leaving source untouched:

npx texture-optimizer build \
  --base-path src/assets/textures \
  --output dist/textures

What happens:

  • Source files remain completely untouched
  • Optimized textures written to output directory
  • If _originalTexture/ exists in source, uses those as reference
  • Clean separation of source and build artifacts

Expected Output:

🎨 Texture Optimizer for HTML5 Games

Config: /path/to/texture-optimize-pro.json
Input:  /path/to/src/assets/textures
Output: /path/to/dist/textures

📋 Loading texture configuration from: /path/to/texture-optimize-pro.json
   Found 3 configured textures in config
📁 Found 5 texture files to process

✓ [CUSTOM] player-sprite.png → player-sprite.png (45.2% smaller, 0.15 MB, 512x512, maxSize: 512px)
✓ [CUSTOM] enemy-goblin.png → enemy-goblin.png (52.1% smaller, 0.08 MB, 256x256, maxSize: 256px)
✓ [DEFAULT] background-sky.jpg → background-sky.jpg (12.3% smaller, 1.24 MB, 1024x1024, maxSize: 1024px)

==================================================
Processing Summary
✓ Successful: 3/3

After optimization:

src/assets/textures/           (unchanged)
├── player-sprite.png
└── enemy-goblin.png

dist/textures/                 (optimized output)
├── player-sprite.png
└── enemy-goblin.png

5. Re-optimize Anytime (In-Place Mode)

When using in-place mode, you can re-optimize with different settings without quality loss:

# Change settings in texture-optimize-pro.json
# (e.g., maxSize: 512 → 1024, quality: 80 → 90)

# Run optimizer again
npx texture-optimizer build --base-path src/assets/textures

The optimizer automatically detects and uses originals from _originalTexture/:

📦 Using original from backup: player-sprite.png
✓ [IN-PLACE] [RE-OPT] [CUSTOM] player-sprite.png → player-sprite.png (72% smaller, 0.55 MB, 1024x1024, maxSize: 1024px)

🔧 Configuration

Configuration File (texture-optimize-pro.json)

defaultSettings :

  • Applied to all textures not listed in the textures array.
  • Applied to any textures in the array with useDefault: true.
{
  "defaultSettings": {
    "maxSize": 512,
    "quality": 80
  }
}

textures Array:

  • A list of entries to provide custom settings for specific textures.
{
  "name": "player-sprite",
  "useDefault": false,
  "maxSize": 512,
  "quality": 85
}
  • name: Filename without extension (e.g., "player-sprite" matches "player-sprite.png").
  • useDefault: true = use default settings, false = use custom settings specified here.
  • maxSize: Maximum dimension (width or height) in pixels.
  • quality: Compression quality (1-100).

Automatic Settings

  • Format: The output format now always matches the input format (e.g., .png stays .png).
  • Power of 2: Textures are always resized to the nearest power-of-2 dimension.
  • Aspect Ratio: The texture's aspect ratio is always maintained.

Name Matching

  • The name field matches the filename without the extension.
  • Example: "name": "player-sprite" matches player-sprite.png, player-sprite.jpg, etc.
  • The optimizer searches all subdirectories within your --base-path.

maxSize Options

  • Valid options: 32, 64, 128, 256, 512, 1024, 2048, 4096.
  • The optimizer will resize to the nearest lower power-of-2, capped at this maxSize.

Schema Reference

This is the internal schema for the settings objects:

interface TextureSettings {
  maxSize?: 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096;
  quality?: number; // 1-100
}

🔄 Re-optimization & Original Preservation

The optimizer automatically manages original textures for safe iterative optimization:

In-Place Mode

First Run:

  • Optimizes textures in-place (when no --output specified)
  • Creates _originalTexture/ backup folders automatically
  • Backs up original files before optimization

Subsequent Runs:

  • Detects existing _originalTexture/ folders
  • Uses backed-up originals as source (not already-optimized files)
  • Applies new settings without quality degradation
  • Console shows [RE-OPT] tag to indicate re-optimization

Benefits:

  • ✨ Unlimited re-optimizations without quality loss
  • 🔒 Original textures always preserved
  • 🎯 Safe experimentation with different settings
  • 🔄 Change maxSize or quality freely - always from original source

Example workflow:

# Initial optimization
npx texture-optimizer build -b src/textures
# Creates: src/textures/_originalTexture/

# Change settings in texture-optimize-pro.json
# (e.g., maxSize: 512 → 1024, quality: 80 → 90)

# Re-optimize with new settings
npx texture-optimizer build -b src/textures
# Uses: src/textures/_originalTexture/ as source
# Result: Fresh optimization from original, no quality loss!

Output Directory Mode

With Existing Backups: If _originalTexture/ folders exist in your source directory, the optimizer will use them as reference:

# Source has backups from previous in-place optimization
src/textures/_originalTexture/player.png (exists)

# Run with output directory
npx texture-optimizer build -b src/textures -o dist/textures

# Uses backup as source, outputs to dist/

Without Backups: Uses current source files and outputs to specified directory.

Special Case - Backup-Only Folders

If you have only _originalTexture/ folders (no textures outside), the optimizer will:

  • Detect textures inside _originalTexture/
  • Optimize them and output to parent directory
  • Useful for restoring optimized textures from backups
# Only _originalTexture/ exists
textures/
└── _originalTexture/
    └── player.png

# Run optimizer
npx texture-optimizer build -b textures

# Result:
textures/
├── player.png              (optimized, created)
└── _originalTexture/
    └── player.png          (original, unchanged)

✨ Tips & Best Practices

1. Choosing Between Modes

Use In-Place Mode when:

  • Developing and iterating on optimization settings
  • Want to experiment with different quality/size combinations
  • Need to re-optimize frequently
  • Working in development environment

Use Output Directory Mode when:

  • Building for production
  • Want to keep source and build separate
  • Using in CI/CD pipelines
  • Don't need to re-optimize frequently

2. Naming Convention

Use clear, descriptive names that match your files:

Good:
- player-idle.png → "name": "player-idle"
- enemy-boss-1.png → "name": "enemy-boss-1"
- bg-forest-day.jpg → "name": "bg-forest-day"

Bad:
- texture1.png → hard to configure
- IMG_0001.png → meaningless name

3. Choose the Right Input Format

  • PNG: Best for transparency, UI elements, text, or pixel art.
  • JPG: Best for photos, complex backgrounds, or realistic art (no transparency).
  • WebP: Best compression for modern browsers.

4. Power-of-2 for WebGL

This feature is automatic and enabled by default. It is critical for:

  • ThreeJS textures (required for mipmapping).
  • PixiJS textures (improves performance and compatibility).
  • Any WebGL-based rendering.

5. Quality Settings

Use this as a guide for setting the quality property (1-100):

  • 90-100: High-quality assets, hero characters, prominent UI.
  • 80-90: Standard game assets.
  • 70-80: Backgrounds, secondary elements.
  • 60-70: Playable ads, or where extreme optimization is needed.

6. Test Your Settings

After optimizing, always load your game and verify:

  • Textures look visually acceptable.
  • No performance issues are introduced.
  • File sizes are reduced.
  • The total bundle size meets your requirements.

7. Managing Backups

Development:

  • Keep _originalTexture/ folders for re-optimization flexibility
  • Commit to version control if team needs re-optimization capability

Production/Deployment:

  • Exclude _originalTexture/ from builds (already larger originals)
  • Add to .gitignore if needed: echo "_originalTexture" >> .gitignore
  • Use output directory mode to avoid shipping backups

Disk Space:

  • Backups typically use 2-3x space of optimized textures
  • Trade-off for unlimited quality-preserving re-optimizations

🛠️ Integration with Your Build Process

You can run the optimizer manually or integrate it into your build scripts.

Option A: package.json Pre-build Script (In-Place)

Add to your package.json to run automatically before every build:

{
  "scripts": {
    "optimize-textures": "texture-optimizer build --base-path src/assets/textures",
    "prebuild": "npm run optimize-textures",
    "build": "vite build"
  }
}

Now, just run npm run build.

Option B: package.json Pre-build Script (Output Directory)

{
  "scripts": {
    "optimize-textures": "texture-optimizer build --base-path src/assets/textures --output dist/textures",
    "prebuild": "npm run optimize-textures",
    "build": "vite build"
  }
}

Option C: package.json Separate Commands

Keep both as separate commands to run manually:

{
  "scripts": {
    "optimize-inplace": "texture-optimizer build --base-path src/assets/textures",
    "optimize": "texture-optimizer build --base-path src/assets/textures --output dist/textures",
    "build": "vite build"
  }
}

Run when needed: npm run optimize-inplace or npm run optimize.

Option D: Vite Integration

You can also run the optimizer programmatically within your vite.config.ts:

import { defineConfig } from 'vite';

export default defineConfig({
  // ... your config
  build: {
    // Run texture optimizer before build
    async buildStart() {
      const { BatchProcessor } = await import('dkb-texture-optimize-pro');
      const processor = new BatchProcessor({
        basePath: 'src/assets/textures',
        outputDir: 'dist/textures', // Omit for in-place mode
        textureConfigPath: 'texture-optimize-pro.json'
      });
      await processor.processAll();
    }
  }
});

📖 CLI Usage

Build Command

texture-optimizer build [options]

Options:

  • -c, --config <path> - Path to texture-optimize-pro.json (default: "texture-optimize-pro.json")
  • -b, --base-path <path> - Base path for input textures (default: "src/assets/textures")
  • -o, --output <path> - Output directory (if not specified, optimizes in-place and backs up originals to _originalTexture folder)
  • --concurrency <number> - Number of concurrent operations (default: 10)
  • --verbose - Enable verbose logging

Examples:

# In-place optimization with backup
texture-optimizer build --base-path src/assets/textures

# Output to separate directory
texture-optimizer build \
  --base-path src/assets/textures \
  --output dist/textures

# Process with custom config and verbose logging
texture-optimizer build \
  --config my-texture-config.json \
  --base-path assets/images \
  --output build/optimized \
  --concurrency 5 \
  --verbose

Init Command

texture-optimizer init [directory]

Creates a sample texture-optimize-pro.json configuration file in the specified directory.

💻 Programmatic API

Single Texture Optimization

import { TextureOptimizer } from 'dkb-texture-optimize-pro';

// Settings for a single run, including the detected format
const optimizer = new TextureOptimizer({
  maxSize: 512,
  quality: 85,
  format: 'png' // Format must be specified here
});

const result = await optimizer.optimize(
  'src/player-sprite.png',
  'dist/player-sprite.png' // Output matches input format
);

console.log(`Reduced by ${result.reductionPercent.toFixed(1)}%`);
console.log(`${result.originalSize.width}x${result.originalSize.height} → ${result.optimizedSize.width}x${result.optimizedSize.height}`);

Batch Processing

import { BatchProcessor } from 'dkb-texture-optimize-pro';

// In-place mode (omit outputDir)
const processor = new BatchProcessor({
  basePath: 'src/assets/textures',
  textureConfigPath: 'texture-optimize-pro.json',
  concurrency: 10,
  verbose: true
});

// Output directory mode (specify outputDir)
const processorWithOutput = new BatchProcessor({
  basePath: 'src/assets/textures',
  outputDir: 'dist/textures',
  textureConfigPath: 'texture-optimize-pro.json',
  concurrency: 10,
  verbose: true
});

// BatchProcessor handles format detection automatically
const results = await processor.processAll();

console.log(`Processed ${results.length} textures`);
const successful = results.filter(r => r.success);
console.log(`Success rate: ${(successful.length / results.length * 100).toFixed(1)}%`);

Using Texture Config Manager

import { TextureConfigManager } from 'dkb-texture-optimize-pro';

const configManager = await TextureConfigManager.loadFromFile('texture-optimize-pro.json');

// Get settings for a specific texture
const settings = configManager.getSettingsForTexture('player-sprite.png');
console.log(`Max size: ${settings.maxSize}px`);
console.log(`Quality: ${settings.quality}`);

// Check if texture has custom settings
const hasCustom = configManager.hasCustomSettings('player-sprite.png');
console.log(`Uses custom settings: ${hasCustom}`);

// Get all configured textures
const configured = configManager.getConfiguredTextures();
console.log(`Configured textures: ${configured.join(', ')}`);

🎮 Use Cases & Recommendations

For Playable Ads (5MB limit)

Aggressive optimization is key for playable ads:

{
  "defaultSettings": {
    "maxSize": 512,
    "quality": 75
  }
}

Tips:

  • Use maxSize 256-512 for most textures
  • Quality 70-80 for good balance
  • Combine with texture atlases for maximum savings
  • Choose your input formats wisely (e.g., use .jpg for backgrounds, .png for UI)
  • Use in-place optimization to iterate on settings until you hit size target

For PixiJS Games

Balance quality and performance:

{
  "defaultSettings": {
    "maxSize": 512,
    "quality": 85,
  },
  "textures": [
    {
      "name": "hero-spritesheet",
      "useDefault": false,
      "maxSize": 2048,
      "quality": 90
    }
  ]
}

For ThreeJS 3D Games

Optimize for GPU memory:

{
  "defaultSettings": {
    "maxSize": 1024,
    "quality": 85,
  },"textures": [
    {
        "name": "hero-diffuse-map",
        "useDefault": false,
        "maxSize": 1024,
        "quality": 80
    }
  ]
}

Tips:

  • Power-of-2 is automatic, which is critical for ThreeJS mipmapping.
  • Use PNG for textures requiring alpha channel
  • JPG for diffuse maps without transparency

📊 Performance

Sharp Performance Benchmarks:

  • JPEG resize: 64x faster than ImageMagick
  • PNG resize: 4.7x faster than ImageMagick
  • WebP encoding: High quality with efficient compression
  • Batch processing: 10+ images/second on typical hardware

Memory Usage:

  • Configurable concurrency to manage memory
  • Default: 10 concurrent operations
  • Adjust based on image sizes and available RAM

🐛 Troubleshooting

Texture looks blurry Issues

Solution: The quality or maxSize is too low. Increase them in your config:

{
  "name": "my-texture",
  "useDefault": false,
  "maxSize": 1024,  // Was 512, now 1024
  "quality": 90      // Was 80, now 90
}

Output files too large Issues

Solution: Decrease maxSize or quality. Also, check your source asset; a large .png background might be better saved as a .jpg before optimizing.

{
  "name": "my-texture",
  "useDefault": false,
  "maxSize": 512,    // Was 1024
  "quality": 75      // Was 85
}

Texture not being optimized with custom settings

Solution: Check that the name in your config matches the filename exactly (without the extension).

File: player-sprite-idle.png
Config: "name": "player-sprite-idle"  ✓ Correct
Config: "name": "player-sprite"       ✗ Won't match

Re-optimization not working (In-Place Mode)

Solution: Ensure _originalTexture/ folders exist and contain the actual originals. Run with --verbose to see if backups are being used:

texture-optimizer build -b src/textures --verbose

Expected output:

📦 Using original from backup: player-sprite.png
✓ [IN-PLACE] [RE-OPT] [CUSTOM] player-sprite.png → ...

If not shown, _originalTexture/ may be missing or empty.

Sharp Installation Issues

If Sharp fails to install:

# Clear npm cache
npm cache clean --force

# Reinstall with rebuild
npm install sharp --build-from-source

Memory Issues

For large batches, reduce concurrency:

texture-optimizer build --concurrency 5

Or set environment variables:

export UV_THREADPOOL_SIZE=8
export MALLOC_ARENA_MAX=2

📜 License

MIT License © Dogukan Kaan Bozkurt

🤝 Contributing

Contributions welcome! Please open an issue or PR on GitHub.

🔗 Links