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

discord-multiimage

v1.0.9

Published

Display multiple images in Discord with grid or stacked layouts.

Downloads

8

Readme

🖼️ discord-multiimage

Transform messy Discord image spam into beautiful, unified galleries

The zero-friction way to send multiple images in Discord without the clutter

npm version License MIT Discord.js v14+ Downloads


🎯 The Problem

Discord bots that send multiple images create visual chaos:

🤖 Bot: Here are your results!
[Embed 1: Single image with title]
[Embed 2: Single image with title] 
[Embed 3: Single image with title]
[Embed 4: Single image with title]

Result: Cluttered chat, repetitive titles, inconsistent spacing, poor mobile experience.

✨ The Solution

discord-multiimage creates native-looking galleries that feel like Discord designed them:

🤖 Bot: Here are your results!
[Single unified embed with 4 images in perfect grid layout]

Result: Clean, professional, mobile-friendly image presentations.


🚀 Quick Start

npm install discord-multiimage

🧱 Grid Mode – Merge into One Embed

Ideal for displaying 2–4 images in a single unified layout.

const { mergeImagesInGrid } = require('discord-multiimage');
const { EmbedBuilder } = require('discord.js');

const imageUrls = [
  'https://example.com/screenshot1.png',
  'https://example.com/screenshot2.png',
  'https://example.com/screenshot3.png'
];

const { file, imageUrl } = await mergeImagesInGrid(imageUrls);

const embed = new EmbedBuilder()
  .setTitle('Game Screenshots')
  .setImage(imageUrl)
  .setColor('#5865F2');

await interaction.reply({ embeds: [embed], files: [file] });

🧩 Stacked Mode – Clean Multiple Embeds

Great for scrollable galleries like art portfolios or product shots.

const { buildStackedImageData } = require('discord-multiimage');
const { EmbedBuilder } = require('discord.js');

const { imageUrls, invisibleTitle, groupUrl } = buildStackedImageData([
  'https://example.com/art1.jpg',
  'https://example.com/art2.jpg',
  'https://example.com/art3.jpg'
], {
  groupUrl: 'https://portfolio.example.com' // Required for grouping
});

const embeds = imageUrls.map(url =>
  new EmbedBuilder()
    .setTitle(invisibleTitle)  // Invisible but needed for Discord to group (Optional: You can use any title yet it will appear as a link)
    .setURL(groupUrl)
    .setImage(url)
    .setColor('#FF6B6B')
);

await channel.send({ embeds });

🪄 One Unified API – Auto Mode Switch

Use createMultiImageData() to let your bot dynamically choose layout style.

const { createMultiImageData } = require('discord-multiimage');
const { EmbedBuilder } = require('discord.js');

const result = await createMultiImageData({
  mode: 'grid', // or 'stacked'
  imageUrls: ['https://example.com/img1.png', 'https://example.com/img2.png'],
  options: {
    spacing: 6,
    backgroundColor: '#2f3136'
  }
});

if (result.file) {
  const embed = new EmbedBuilder().setImage(result.imageUrl);
  await interaction.reply({ embeds: [embed], files: [result.file] });
} else {
  const embeds = result.imageUrls.map(url =>
    new EmbedBuilder().setImage(url).setURL(result.groupUrl).setTitle('\u200B')
  );
  await channel.send({ embeds });
}

🎨 Visual Examples

Grid Layouts (Auto-Generated)

| 2 Images | 3 Images | 4 Images | |:---:|:---:|:---:| | Side-by-side(16:9 ratio) | Large + Stack(4:3 ratio) | Perfect Grid(1:1 ratio) | | IMG1 IMG2 | IMG1IMG2 | IMG1 IMG2IMG3 IMG4 |

Before vs After Comparison

Bot: Here are the match results!

📊 Match Statistics
[Image: Player stats screenshot]

📊 Match Statistics  
[Image: Team composition]

📊 Match Statistics
[Image: Game timeline]

📊 Match Statistics
[Image: Final scoreboard]
Bot: Here are the match results!

📊 Match Statistics
[Beautiful 2x2 grid showing all 4 images
 in one clean, professional embed]

🛠️ Advanced Configuration

Grid Mode Options

const { file, imageUrl } = await mergeImagesInGrid(urls, {
  spacing: 4,           // Pixels between images (default: 2)
  maxWidth: 800,        // Maximum canvas width (default: 600)
  backgroundColor: '#36393f', // Canvas background color
  cornerRadius: 8       // Rounded corners for images
});

Stacked Mode Options

const { imageUrls, invisibleTitle, groupUrl } = buildStackedImageData(urls, {
  groupUrl: 'https://your-site.com/gallery', // Required for grouping
  titleText: '\u200B'   // Custom invisible character (default: zero-width space)
});

🎯 Use Cases & Examples

🎮 Gaming Bots

// Show match highlights in one clean embed
const highlights = await mergeImagesInGrid([
  killcam1, killcam2, scoreboard, playerStats
]);

🎨 Art & Portfolio Bots

// Create scrollable art galleries
const gallery = buildStackedImageData(artworkUrls, {
  groupUrl: 'https://artist.portfolio.com'
});

📊 Analytics & Monitoring

// Combine multiple chart screenshots
const dashboard = await mergeImagesInGrid([
  salesChart, trafficChart, conversionChart
]);

🏪 E-commerce & Marketplace

// Product image galleries
const productGallery = buildStackedImageData([
  mainPhoto, sideView, detailShot, packagingPhoto
]);

🤔 Grid vs Stacked - Decision Guide

| Scenario | Recommended Mode | Why | |--------------|---------------------|---------| | Screenshots to compare side-by-side | Grid | Visual comparison is easier | | Art portfolio or photo gallery | Stacked | Users want to focus on each image | | Dashboard with multiple charts | Grid | Overview of all metrics at once | | Step-by-step tutorial images | Stacked | Sequential viewing preferred | | Before/after comparisons | Grid | Direct visual comparison | | Large collection (5+ images) | Stacked | Grid limited to 4 images max |


🧩 Compatibility

  • ✅ Works with Discord.js v14+
  • ⚠️ Requires Node.js ≥ 16.9
  • 🖼️ Uses skia-canvas — make sure your environment supports native modules

⚡ Performance & Technical Details

Dependencies

  • Core: discord.js v14+
  • Image Processing: skia-canvas (faster than node-canvas)
  • Zero bloat: No unnecessary dependencies

Image Processing

  • Automatic resizing to fit Discord's embed limits
  • Smart aspect ratio preservation
  • WebP optimization for smaller file sizes
  • Cross-platform canvas rendering

Discord Compatibility

  • Mobile optimized - perfect scrolling and zoom
  • Desktop native - looks like built-in Discord features
  • Embed limits - respects Discord's 25MB file size limits
  • Rate limiting - works with standard Discord.js rate limiting

🚨 Common Pitfalls & Solutions

❌ Stacked embeds not grouping?

Problem: Embeds appear separately instead of grouped.

// Missing required URL
.setURL(groupUrl) // ← This is required for grouping!

❌ Images loading slowly?

Problem: Large images taking too long to process.

// Optimize with smaller max width
await mergeImagesInGrid(urls, { maxWidth: 400 });

❌ Grid looking weird on mobile?

Problem: Images don't scale properly on small screens.

// Discord handles this automatically with our layouts!
// No additional code needed - it just works ✨

🤝 Contributing

We love contributions! Here's how to get started:

  1. Fork the repository
  2. Clone your fork: git clone https://github.com/sajidurdev/discord-multiimage.git
  3. Install dependencies: npm install
  4. Create a feature branch: git checkout -b amazing-feature
  5. Make your changes and add tests
  6. Submit a pull request

Development Setup

git clone https://github.com/sajidurdev/discord-multiimage.git
cd discord-multiimage
npm install
npm test

📄 License

MIT © sajidurdev

Free to use in any project - commercial or open source. Attribution appreciated but not required.


Made with ❤️ for the Discord community

📚 Usage Guide🐛 Report Bug💡 Request Feature💬 Discord Server

Star this repo if it helped you build better Discord bots!