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

phantom-canva

v1.0.0

Published

Advanced canvas image generation for welcome (wlc) and goodbye (gdb) images with 5 styles each

Readme

Phantom-Canva

https://img.shields.io/npm/v/phantom-canva https://img.shields.io/npm/dm/phantom-canva https://img.shields.io/npm/l/phantom-canva https://img.shields.io/node/v/phantom-canva

Advanced Canvas Image Generation Library for Welcome & Goodbye Images

Generate stunning welcome and goodbye images with 5 different styles each. Perfect for Discord bots, community platforms, and any application needing dynamic visual greetings or farewells.

Installation • Usage • API Reference • Examples • License


✨ Features

· 🎨 5 Welcome Styles - From simple to stylized welcome images · 👋 5 Goodbye Styles - Various farewell image designs · 🖼️ URL & File Upload Support - Use image URLs or direct file buffers · ⚡ High Performance - Optimized canvas rendering · 🎯 Easy to Use - Simple function calls with clear parameters · 📦 Lightweight - Minimal dependencies, maximum output · 🔧 Customizable - Quality settings, text sizing, and more


📦 Installation

npm install phantom-canva

Dependencies

This package requires the following peer dependencies:

npm install canvas @putuofc/assetsku canvafy axios file-type

🚀 Quick Start

const { wlc5, gdb5 } = require('phantom-canva');

// Generate a welcome image
const welcomeImage = await wlc5(
  'JohnDoe',                    // username
  'Gaming Community',           // guild name
  1234,                         // member count
  'https://example.com/avatar.jpg',  // avatar URL
  'https://example.com/bg.jpg',      // background URL
  90                            // quality (optional)
);

// Generate a goodbye image
const goodbyeImage = await gdb5(
  'JohnDoe',                    // username
  'Gaming Community',           // guild name
  1234,                         // member count
  'https://example.com/avatar.jpg',  // avatar URL
  'https://example.com/bg.jpg',      // background URL
  90                            // quality (optional)
);

// Use the buffers (e.g., send as response, save to disk, etc.)
require('fs').writeFileSync('welcome.jpg', welcomeImage);
require('fs').writeFileSync('goodbye.jpg', goodbyeImage);

📚 API Reference

Welcome Images (wlc1 - wlc5)

wlc1(username, guildName, guildIcon, memberCount, avatar, background, quality?)

Stylized welcome image with guild icon

Parameter Type Required Description username string ✅ Username to display (max 25 chars) guildName string ✅ Guild/server name (max 30 chars) guildIcon string/Buffer ✅ Guild icon URL or buffer memberCount number ✅ Member count (positive number) avatar string/Buffer ✅ User avatar URL or buffer background string/Buffer ✅ Background image URL or buffer quality number ❌ JPEG quality 1-100 (default: 100)

Returns: Promise


wlc2(username, guildName, memberCount, avatar, background)

Welcome image with rotated frame design

Parameter Type Required Description username string ✅ Username to display (max 25 chars) guildName string ✅ Guild/server name (max 50 chars) memberCount number ✅ Member count (positive number) avatar string/Buffer ✅ User avatar URL or buffer background string/Buffer ✅ Background image URL or buffer

Returns: Promise (PNG format)


wlc3(username, avatar)

Simple welcome image with avatar

Parameter Type Required Description username string ✅ Username to display (max 25 chars) avatar string/Buffer ✅ User avatar URL or buffer

Returns: Promise (PNG format)


wlc4(avatar, background, description)

Canvafy-powered welcome image

Parameter Type Required Description avatar string/Buffer ✅ User avatar URL or buffer background string/Buffer ✅ Background image URL or buffer description string ✅ Welcome message description

Returns: Promise (PNG format)


wlc5(username, guildName, memberCount, avatar, background, quality?)

Modern stylized welcome image

Parameter Type Required Description username string ✅ Username to display (max 25 chars) guildName string ✅ Guild/server name (max 30 chars) memberCount number ✅ Member count (positive number) avatar string/Buffer ✅ User avatar URL or buffer background string/Buffer ✅ Background image URL or buffer quality number ❌ JPEG quality 1-100 (default: 100)

Returns: Promise


Goodbye Images (gdb1 - gdb5)

gdb1(username, guildName, memberCount, avatar, background, quality?)

Stylized goodbye image

Parameter Type Required Description username string ✅ Username to display (max 25 chars) guildName string ✅ Guild/server name (max 30 chars) memberCount number ✅ Member count (positive number) avatar string/Buffer ✅ User avatar URL or buffer background string/Buffer ✅ Background image URL or buffer quality number ❌ JPEG quality 1-100 (default: 100)

Returns: Promise


gdb2(username, guildName, memberCount, avatar, background)

Goodbye image with rotated frame design

Parameter Type Required Description username string ✅ Username to display (max 25 chars) guildName string ✅ Guild/server name (max 50 chars) memberCount number ✅ Member count (positive number) avatar string/Buffer ✅ User avatar URL or buffer background string/Buffer ✅ Background image URL or buffer

Returns: Promise (PNG format)


gdb3(username, avatar)

Simple goodbye image with avatar

Parameter Type Required Description username string ✅ Username to display (max 25 chars) avatar string/Buffer ✅ User avatar URL or buffer

Returns: Promise (PNG format)


gdb4(avatar, background, description)

Canvafy-powered goodbye image

Parameter Type Required Description avatar string/Buffer ✅ User avatar URL or buffer background string/Buffer ✅ Background image URL or buffer description string ✅ Goodbye message description

Returns: Promise (PNG format)


gdb5(username, guildName, memberCount, avatar, background, quality?)

Modern stylized goodbye image

Parameter Type Required Description username string ✅ Username to display (max 25 chars) guildName string ✅ Guild/server name (max 30 chars) memberCount number ✅ Member count (positive number) avatar string/Buffer ✅ User avatar URL or buffer background string/Buffer ✅ Background image URL or buffer quality number ❌ JPEG quality 1-100 (default: 100)

Returns: Promise


💡 Examples

Example 1: Discord Bot Welcome Message

const { wlc5 } = require('phantom-canva');
const { MessageAttachment } = require('discord.js');

client.on('guildMemberAdd', async (member) => {
  try {
    const welcomeBuffer = await wlc5(
      member.user.username,
      member.guild.name,
      member.guild.memberCount,
      member.user.displayAvatarURL({ format: 'png', size: 256 }),
      'https://example.com/welcome-bg.jpg',
      90
    );
    
    const attachment = new MessageAttachment(welcomeBuffer, 'welcome.png');
    const channel = member.guild.channels.cache.find(ch => ch.name === 'welcome');
    
    if (channel) {
      await channel.send({ content: `Welcome ${member.user}!`, files: [attachment] });
    }
  } catch (error) {
    console.error('Error generating welcome image:', error);
  }
});

Example 2: Express API Endpoint

const express = require('express');
const { wlc4, gdb4 } = require('phantom-canva');
const app = express();

app.get('/api/welcome', async (req, res) => {
  const { username, avatar, background, description } = req.query;
  
  try {
    const imageBuffer = await wlc4(avatar, background, description);
    
    res.setHeader('Content-Type', 'image/png');
    res.setHeader('Content-Disposition', 'inline; filename="welcome.png"');
    res.send(imageBuffer);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.get('/api/goodbye', async (req, res) => {
  const { username, guildName, memberCount, avatar, background } = req.query;
  
  try {
    const imageBuffer = await gdb5(
      username,
      guildName,
      parseInt(memberCount),
      avatar,
      background,
      85
    );
    
    res.setHeader('Content-Type', 'image/jpeg');
    res.send(imageBuffer);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

Example 3: File Upload Support

const express = require('express');
const multer = require('multer');
const { wlc2, gdb2 } = require('phantom-canva');
const upload = multer({ storage: multer.memoryStorage() });
const app = express();

app.post('/api/welcome/upload', upload.fields([
  { name: 'avatar', maxCount: 1 },
  { name: 'background', maxCount: 1 }
]), async (req, res) => {
  const { username, guildName, memberCount } = req.body;
  const avatarBuffer = req.files['avatar'][0].buffer;
  const backgroundBuffer = req.files['background'][0].buffer;
  
  try {
    const imageBuffer = await wlc2(
      username,
      guildName,
      parseInt(memberCount),
      avatarBuffer,
      backgroundBuffer
    );
    
    res.setHeader('Content-Type', 'image/png');
    res.send(imageBuffer);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.post('/api/goodbye/upload', upload.fields([
  { name: 'avatar', maxCount: 1 },
  { name: 'background', maxCount: 1 }
]), async (req, res) => {
  const { username, guildName, memberCount } = req.body;
  const avatarBuffer = req.files['avatar'][0].buffer;
  const backgroundBuffer = req.files['background'][0].buffer;
  
  try {
    const imageBuffer = await gdb2(
      username,
      guildName,
      parseInt(memberCount),
      avatarBuffer,
      backgroundBuffer
    );
    
    res.setHeader('Content-Type', 'image/png');
    res.send(imageBuffer);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

Example 4: Save to File

const fs = require('fs').promises;
const { wlc3, gdb3 } = require('phantom-canva');

async function saveImages() {
  // Generate welcome image
  const welcomeBuffer = await wlc3('NewMember', 'https://example.com/avatar.jpg');
  await fs.writeFile('./output/welcome.png', welcomeBuffer);
  
  // Generate goodbye image
  const goodbyeBuffer = await gdb3('LeavingMember', 'https://example.com/avatar.jpg');
  await fs.writeFile('./output/goodbye.png', goodbyeBuffer);
  
  console.log('Images saved successfully!');
}

saveImages().catch(console.error);

Example 5: Batch Generation

const { wlc1 } = require('phantom-canva');

async function generateBatchWelcome(users, guildInfo) {
  const promises = users.map(user => 
    wlc1(
      user.username,
      guildInfo.name,
      guildInfo.icon,
      guildInfo.memberCount,
      user.avatar,
      guildInfo.background,
      80
    )
  );
  
  const images = await Promise.all(promises);
  
  return images.map((buffer, index) => ({
    user: users[index].username,
    image: buffer
  }));
}

// Usage
const users = [
  { username: 'Alice', avatar: 'https://example.com/alice.jpg' },
  { username: 'Bob', avatar: 'https://example.com/bob.jpg' }
];

const guildInfo = {
  name: 'Gaming Hub',
  icon: 'https://example.com/guild-icon.jpg',
  memberCount: 500,
  background: 'https://example.com/bg.jpg'
};

const results = await generateBatchWelcome(users, guildInfo);
results.forEach(result => {
  console.log(`Generated welcome for ${result.user}`);
  // Save or send result.image
});

🎨 Image Style Comparison

Version Style Format Features wlc1/gdb1 Stylized JPEG Circular avatar, guild icon, member count wlc2/gdb2 Rotated Frame PNG 17° rotated avatar, frame overlay wlc3/gdb3 Simple PNG Basic layout, centered avatar wlc4/gdb4 Canvafy PNG Modern design, customizable description wlc5/gdb5 Modern Stylized JPEG Large circular avatar, dynamic text sizing


🔧 Error Handling

const { wlc5, isValidImageUrl } = require('phantom-canva');

async function safeGenerateWelcome(params) {
  // Validate inputs
  if (!isValidImageUrl(params.avatar)) {
    throw new Error('Invalid avatar URL');
  }
  
  if (params.username.length > 25) {
    throw new Error('Username too long (max 25 characters)');
  }
  
  if (params.memberCount < 0) {
    throw new Error('Member count must be positive');
  }
  
  try {
    const imageBuffer = await wlc5(
      params.username,
      params.guildName,
      params.memberCount,
      params.avatar,
      params.background,
      params.quality || 90
    );
    return { success: true, image: imageBuffer };
  } catch (error) {
    console.error('Image generation failed:', error);
    return { success: false, error: error.message };
  }
}

📝 Requirements

· Node.js: >= 16.0.0 · Dependencies: · canvas - Graphics rendering · @putuofc/assetsku - Font and frame assets · canvafy - Alternative rendering engine · axios - HTTP requests for images · file-type - Image type validation


🤝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing)
  5. Open a Pull Request

📄 License

MIT © Phantom


🙏 Support

· 📧 Email: [email protected] · 🐛 Issues: GitHub Issues · 📖 Documentation: https://docs.phantom-canva.com


⚡ Quick Function Reference

// Welcome Images
import { 
  wlc1, wlc1FromFile,
  wlc2, wlc2FromFile,
  wlc3, wlc3FromFile,
  wlc4, wlc4FromFile,
  wlc5, wlc5FromFile
} from 'phantom-canva';

// Goodbye Images
import {
  gdb1, gdb1FromFile,
  gdb2, gdb2FromFile,
  gdb3, gdb3FromFile,
  gdb4, gdb4FromFile,
  gdb5, gdb5FromFile
} from 'phantom-canva';

Made with ❤️ for the developer community

Report Bug · Request Feature