pixel-forge
Version:
A comprehensive generator for social media previews, favicons, and visual assets across all platforms
660 lines (659 loc) ⢠29.6 kB
JavaScript
#!/usr/bin/env node
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.program = void 0;
const commander_1 = require("commander");
Object.defineProperty(exports, "program", { enumerable: true, get: function () { return commander_1.program; } });
const path_1 = __importDefault(require("path"));
const fs_1 = require("fs");
const chalk_1 = __importDefault(require("chalk"));
const comprehensive_1 = require("../generators/social/comprehensive");
const facebook_1 = require("../generators/social/facebook");
const twitter_1 = require("../generators/social/twitter");
const linkedin_1 = require("../generators/social/linkedin");
const tiktok_1 = require("../generators/social/tiktok");
const whatsapp_1 = require("../generators/social/whatsapp");
const instagram_1 = require("../generators/social/instagram");
const favicon_1 = require("../generators/favicon/favicon");
const pwa_1 = require("../generators/pwa/pwa");
const seo_1 = require("../generators/web/seo");
const image_processor_1 = require("../core/image-processor");
// Import package.json as a module instead of using require
const package_json_1 = __importDefault(require("../../package.json"));
/**
* Check if ImageMagick is available and show helpful error if not
*/
async function checkImageMagickAvailability() {
const isAvailable = await image_processor_1.ImageProcessor.checkImageMagick();
if (!isAvailable) {
console.error(chalk_1.default.red('\nā ImageMagick is required but not found!\n'));
console.error(chalk_1.default.yellow('Please install ImageMagick first:\n'));
console.error(chalk_1.default.cyan(' macOS:'), ' brew install imagemagick');
console.error(chalk_1.default.cyan(' Ubuntu/Debian:'), ' sudo apt-get install imagemagick');
console.error(chalk_1.default.cyan(' Windows:'), ' choco install imagemagick');
console.error(chalk_1.default.cyan(' Or download:'), ' https://imagemagick.org/script/download.php\n');
console.error(chalk_1.default.gray('After installation, restart your terminal and try again.\n'));
process.exit(1);
}
}
/**
* Check if the file is a supported image format
*/
function isValidImageFormat(filePath) {
const ext = path_1.default.extname(filePath).toLowerCase();
return image_processor_1.SUPPORTED_INPUT_FORMATS.includes(ext);
}
/**
* Load configuration from file or use defaults
*/
async function loadConfig(configPath, options = {}) {
let config = {};
// Load config file if specified
if (configPath) {
try {
const configContent = await fs_1.promises.readFile(configPath, 'utf-8');
// Fix unsafe assignment by using a type assertion
config = JSON.parse(configContent);
}
catch (_error) {
console.warn(`Warning: Could not load config file ${configPath}. Using defaults.`);
}
}
// Override with CLI options
const finalConfig = {
appName: config.appName || options.title || 'My App',
description: config.description || options.description || 'Generated with Social Forge',
themeColor: config.themeColor || options.themeColor || '#000000',
backgroundColor: config.backgroundColor || options.backgroundColor || '#ffffff',
socialPreview: {
title: options.title || config.socialPreview?.title || config.appName || 'My App',
description: options.description || config.socialPreview?.description || config.description || '',
template: options.template || config.socialPreview?.template || 'basic'
},
platforms: {
social: options.social || config.platforms?.social !== false,
favicon: options.favicon || config.platforms?.favicon !== false,
pwa: options.pwa || config.platforms?.pwa !== false
},
output: {
path: options.output || config.output?.path || './public/images',
prefix: options.prefix || config.output?.prefix || '/images/',
quality: parseInt(options.quality || '90') || config.output?.quality || 90
}
};
// Return the final configuration
return finalConfig;
}
/**
* Generate all assets
*/
async function generateAll(sourceImage, config, options) {
console.log('š Generating all assets...\n');
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: true,
includeInstagram: true,
includeMessaging: true,
includePlatforms: true
});
// Generate favicon
const faviconGenerator = new favicon_1.FaviconGenerator(sourceImage, config);
await faviconGenerator.generate();
// Generate PWA assets
const pwaGenerator = new pwa_1.PWAGenerator(sourceImage, config);
await pwaGenerator.generate();
// Generate SEO assets
const seoGenerator = new seo_1.WebSEOGenerator(sourceImage, config);
await seoGenerator.generate({
outputFormat: options.format || 'png'
});
const files = [
...await generator.getGeneratedFiles(),
...faviconGenerator.getGeneratedFiles(),
...pwaGenerator.getGeneratedFiles(),
...seoGenerator.getGeneratedFiles()
];
console.log(`ā
Generated ${files.length} files in ${config.output.path}`);
if (options.verbose) {
console.log('\nGenerated files:');
files.forEach(file => console.log(` š ${file}`));
}
}
/**
* Generate specific platform assets
*/
async function generateSpecific(sourceImage, config, options) {
const generators = [];
// Social media platforms
if (options.facebook) {
const generator = new facebook_1.FacebookGenerator(sourceImage, config);
await generator.generate();
generators.push({ name: 'Facebook', generator, files: generator.getGeneratedFiles() });
}
if (options.twitter) {
const generator = new twitter_1.TwitterGenerator(sourceImage, config);
await generator.generate();
generators.push({ name: 'Twitter', generator, files: generator.getGeneratedFiles() });
}
if (options.linkedin) {
const generator = new linkedin_1.LinkedInGenerator(sourceImage, config);
await generator.generate();
generators.push({ name: 'LinkedIn', generator, files: generator.getGeneratedFiles() });
}
if (options.instagram) {
const generator = new instagram_1.InstagramGenerator(sourceImage, config);
await generator.generate({ includeStories: false, includeReels: false }); // Avoid text overlay issues
generators.push({ name: 'Instagram', generator, files: generator.getGeneratedFiles() });
}
if (options.tiktok) {
const generator = new tiktok_1.TikTokGenerator(sourceImage, config);
await generator.generate();
generators.push({ name: 'TikTok', generator, files: generator.getGeneratedFiles() });
}
if (options.whatsapp) {
const generator = new whatsapp_1.WhatsAppGenerator(sourceImage, config);
await generator.generate();
generators.push({ name: 'WhatsApp', generator, files: generator.getGeneratedFiles() });
}
if (options.youtube) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: false,
includePlatforms: true,
platforms: {
youtube: true,
tiktok: false,
pinterest: false
}
});
generators.push({ name: 'YouTube', generator, files: ['youtube-thumbnail.png', 'youtube-shorts.png'] });
}
if (options.pinterest) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: false,
includePlatforms: true,
platforms: {
youtube: false,
tiktok: false,
pinterest: true
}
});
generators.push({ name: 'Pinterest', generator, files: ['pinterest-pin.png', 'pinterest-board.png'] });
}
// Messaging platforms
if (options.imessage) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: true,
includePlatforms: false,
platforms: {
imessage: true,
whatsapp: false,
discord: false,
telegram: false,
signal: false,
slack: false
}
});
generators.push({ name: 'iMessage', generator, files: ['imessage.png'] });
}
if (options.discord) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: true,
includePlatforms: false,
platforms: {
imessage: false,
whatsapp: false,
discord: true,
telegram: false,
signal: false,
slack: false
}
});
generators.push({ name: 'Discord', generator, files: ['discord.png'] });
}
if (options.telegram) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: true,
includePlatforms: false,
platforms: {
imessage: false,
whatsapp: false,
discord: false,
telegram: true,
signal: false,
slack: false
}
});
generators.push({ name: 'Telegram', generator, files: ['telegram.png'] });
}
if (options.signal) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: true,
includePlatforms: false,
platforms: {
imessage: false,
whatsapp: false,
discord: false,
telegram: false,
signal: true,
slack: false
}
});
generators.push({ name: 'Signal', generator, files: ['signal.png'] });
}
if (options.slack) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: true,
includePlatforms: false,
platforms: {
imessage: false,
whatsapp: false,
discord: false,
telegram: false,
signal: false,
slack: true
}
});
generators.push({ name: 'Slack', generator, files: ['slack.png'] });
}
if (options.androidrcs) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: true,
includePlatforms: false,
platforms: {
androidRCS: true,
whatsapp: false,
discord: false,
telegram: false,
signal: false,
slack: false,
imessage: false
}
});
generators.push({ name: 'Android RCS', generator, files: ['android-rcs.png'] });
}
if (options.threads) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: false,
includePlatforms: true,
platforms: {
threads: true,
youtube: false,
tiktok: false,
pinterest: false,
bluesky: false,
mastodon: false
}
});
generators.push({ name: 'Threads', generator, files: ['threads.png'] });
}
if (options.bluesky) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: false,
includePlatforms: true,
platforms: {
threads: false,
youtube: false,
tiktok: false,
pinterest: false,
bluesky: true,
mastodon: false
}
});
generators.push({ name: 'Bluesky', generator, files: ['bluesky.png'] });
}
if (options.mastodon) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({
includeStandard: false,
includeInstagram: false,
includeMessaging: false,
includePlatforms: true,
platforms: {
threads: false,
youtube: false,
tiktok: false,
pinterest: false,
bluesky: false,
mastodon: true
}
});
generators.push({ name: 'Mastodon', generator, files: ['mastodon.png'] });
}
// Category generators
if (options.social) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({ includeStandard: true, includeInstagram: false, includeMessaging: false, includePlatforms: false });
generators.push({ name: 'Social Media', generator, files: ['facebook.png', 'twitter.png', 'linkedin.png'] });
}
if (options.messaging) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({ includeStandard: false, includeInstagram: false, includeMessaging: true, includePlatforms: false });
generators.push({ name: 'Messaging Apps', generator, files: ['whatsapp-profile.png', 'discord.png', 'telegram.png', 'signal.png', 'slack.png', 'imessage.png'] });
}
if (options.platforms) {
const generator = new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config);
await generator.generate({ includeStandard: false, includeInstagram: false, includeMessaging: false, includePlatforms: true });
generators.push({ name: 'Video Platforms', generator, files: ['tiktok.png', 'youtube-thumbnail.png', 'youtube-shorts.png', 'pinterest-pin.png', 'pinterest-board.png'] });
}
if (options.favicon) {
const generator = new favicon_1.FaviconGenerator(sourceImage, config);
await generator.generate();
generators.push({ name: 'Favicons', generator, files: generator.getGeneratedFiles() });
}
if (options.pwa) {
const generator = new pwa_1.PWAGenerator(sourceImage, config);
await generator.generate();
generators.push({ name: 'PWA Assets', generator, files: generator.getGeneratedFiles() });
}
if (options.seo) {
const generator = new seo_1.WebSEOGenerator(sourceImage, config);
await generator.generate({
outputFormat: options.format || 'png'
});
generators.push({ name: 'SEO Assets', generator, files: generator.getGeneratedFiles() });
}
if (options.web) {
// Generate complete web development package
const faviconGenerator = new favicon_1.FaviconGenerator(sourceImage, config);
await faviconGenerator.generate();
const pwaGenerator = new pwa_1.PWAGenerator(sourceImage, config);
await pwaGenerator.generate();
const seoGenerator = new seo_1.WebSEOGenerator(sourceImage, config);
await seoGenerator.generate({
outputFormat: options.format || 'png'
});
generators.push({
name: 'Web Development Package',
generator: seoGenerator,
files: [
...faviconGenerator.getGeneratedFiles(),
...pwaGenerator.getGeneratedFiles(),
...seoGenerator.getGeneratedFiles()
]
});
}
// Summary
console.log('ā
Generation complete!\n');
generators.forEach(({ name, files }) => {
console.log(`š ${name}: ${files.length} files`);
if (options.verbose) {
files.slice(0, 5).forEach(file => console.log(` š ${file}`));
if (files.length > 5) {
console.log(` ... and ${files.length - 5} more`);
}
}
});
const totalFiles = generators.reduce((sum, { files }) => sum + files.length, 0);
console.log(`\nš Total: ${totalFiles} files generated in ${config.output.path}`);
}
/**
* Show meta tags for generated assets
*/
async function showMetaTags(sourceImage, config, _options) {
console.log('š·ļø HTML Meta Tags:\n');
const generators = [
new comprehensive_1.ComprehensiveSocialGenerator(sourceImage, config),
new favicon_1.FaviconGenerator(sourceImage, config),
new pwa_1.PWAGenerator(sourceImage, config)
];
const allTags = [];
// Add an await to fix the require-await warning
await Promise.all(generators.map(generator => {
const tags = generator.getMetaTags();
allTags.push(...tags);
return Promise.resolve(); // Return a resolved promise for Promise.all
}));
// Remove duplicates and sort
const uniqueTags = [...new Set(allTags)].sort();
uniqueTags.forEach(tag => {
console.log(tag);
});
console.log(`\nš Total: ${uniqueTags.length} meta tags`);
}
/**
* Initialize a new project
*/
async function initProject(directory = '.') {
console.log('š¬ Initializing Social Forge project...\n');
// Create directory if it doesn't exist
await fs_1.promises.mkdir(directory, { recursive: true });
const configPath = path_1.default.join(directory, 'pixel-forge.config.json');
const defaultConfig = {
appName: 'My App',
description: 'My awesome application',
themeColor: '#000000',
backgroundColor: '#ffffff',
socialPreview: {
title: 'My App',
description: 'My awesome application',
template: 'basic'
},
platforms: {
social: true,
favicon: true,
pwa: true
},
output: {
path: './public/images',
prefix: '/images/',
quality: 90
}
};
await fs_1.promises.writeFile(configPath, JSON.stringify(defaultConfig, null, 2));
console.log(`ā
Created configuration file: ${configPath}`);
console.log('\nš Next steps:');
console.log(' 1. Edit pixel-forge.config.json with your app details');
console.log(' 2. Run: npx pixel-forge generate ./logo.png --all');
console.log(' 3. Add the generated meta tags to your HTML');
}
// CLI Program setup
commander_1.program
.name('pixel-forge')
.description('Generate comprehensive social media assets, favicons, and PWA icons')
.version(package_json_1.default.version);
// Generate command
commander_1.program
.command('generate <source>')
.description('Generate images from source file (supports PNG, JPEG, WebP, AVIF, TIFF, GIF, SVG, BMP)')
.option('-o, --output <path>', 'Output directory', './public/images')
.option('-c, --config <path>', 'Config file path')
.option('-q, --quality <number>', 'Image quality (1-100)', '90')
.option('-p, --prefix <path>', 'URL prefix for generated files', '/images/')
.option('-f, --format <format>', 'Output format (png|jpeg|webp|avif|tiff|gif)', 'png')
.option('--all', 'Generate all asset types')
.option('--social', 'Generate standard social media assets (Facebook, Twitter, LinkedIn)')
.option('--facebook', 'Generate Facebook assets only')
.option('--twitter', 'Generate Twitter assets only')
.option('--linkedin', 'Generate LinkedIn assets only')
.option('--instagram', 'Generate Instagram assets only')
.option('--tiktok', 'Generate TikTok assets only')
.option('--whatsapp', 'Generate WhatsApp assets only')
.option('--youtube', 'Generate YouTube assets only')
.option('--pinterest', 'Generate Pinterest assets only')
.option('--imessage', 'Generate iMessage assets only')
.option('--discord', 'Generate Discord assets only')
.option('--telegram', 'Generate Telegram assets only')
.option('--signal', 'Generate Signal assets only')
.option('--slack', 'Generate Slack assets only')
.option('--androidrcs', 'Generate Android RCS assets only')
.option('--threads', 'Generate Threads assets only')
.option('--bluesky', 'Generate Bluesky assets only')
.option('--mastodon', 'Generate Mastodon assets only')
.option('--messaging', 'Generate messaging app assets')
.option('--platforms', 'Generate video/visual platform assets')
.option('--favicon', 'Generate favicon assets only')
.option('--pwa', 'Generate PWA assets only')
.option('--seo', 'Generate SEO/OpenGraph assets only')
.option('--web', 'Generate complete web development package (favicon + PWA + SEO)')
.option('-t, --title <text>', 'App title')
.option('-d, --description <text>', 'App description')
.option('--theme-color <color>', 'Theme color (hex)', '#000000')
.option('--background-color <color>', 'Background color (hex)', '#ffffff')
.option('--template <type>', 'Template type (basic|gradient|custom)', 'basic')
.option('-v, --verbose', 'Verbose output')
.action(async (source, options) => {
try {
// Check ImageMagick availability first
await checkImageMagickAvailability();
// Validate source file
const sourcePath = path_1.default.resolve(source);
await fs_1.promises.access(sourcePath);
// Check if the file format is supported
if (!isValidImageFormat(sourcePath)) {
const supportedFormats = image_processor_1.SUPPORTED_INPUT_FORMATS.join(', ');
throw new Error(`Unsupported image format: ${path_1.default.extname(sourcePath)}. Please use one of the following: ${supportedFormats}`);
}
console.log(`š· Source image: ${sourcePath}`);
// Load configuration
const config = await loadConfig(options.config, options);
// Ensure output directory exists
await fs_1.promises.mkdir(config.output.path, { recursive: true });
console.log(`š Output directory: ${config.output.path}`);
console.log(`šØ Theme: ${config.themeColor} | Background: ${config.backgroundColor}\n`);
// Generate assets based on options
if (options.all) {
await generateAll(sourcePath, config, options);
}
else if (options.facebook || options.twitter || options.linkedin || options.instagram ||
options.tiktok || options.whatsapp || options.youtube || options.pinterest ||
options.imessage || options.discord || options.telegram || options.signal ||
options.slack || options.androidrcs || options.threads || options.bluesky ||
options.mastodon || options.social || options.messaging ||
options.platforms || options.favicon || options.pwa || options.seo || options.web) {
await generateSpecific(sourcePath, config, options);
}
else {
// Default: generate standard social media assets
await generateSpecific(sourcePath, config, { ...options, social: true });
}
}
catch (error) {
console.error('ā Error:', error instanceof Error ? error.message : error);
process.exit(1);
}
});
// Meta tags command
commander_1.program
.command('meta <source>')
.description('Generate HTML meta tags for the assets')
.option('-c, --config <path>', 'Config file path')
.option('-p, --prefix <path>', 'URL prefix for generated files', '/images/')
.action(async (source, options) => {
try {
const sourcePath = path_1.default.resolve(source);
await fs_1.promises.access(sourcePath);
const config = await loadConfig(options.config, options);
await showMetaTags(sourcePath, config, options);
}
catch (error) {
console.error('ā Error:', error instanceof Error ? error.message : error);
process.exit(1);
}
});
// Init command
commander_1.program
.command('init [directory]')
.description('Initialize a new Social Forge project')
.action(async (directory) => {
try {
await initProject(directory);
}
catch (error) {
console.error('ā Error:', error instanceof Error ? error.message : error);
process.exit(1);
}
});
// Info command
commander_1.program
.command('info')
.description('Show platform coverage and capabilities')
.action(() => {
console.log('š Pixel Forge - Complete Web Development Toolkit\n');
console.log('š Quick Start for Web Developers:');
console.log(' npx pixel-forge generate logo.png --web # Complete web package');
console.log(' npx pixel-forge generate logo.png --seo # SEO & social sharing');
console.log(' npx pixel-forge generate logo.png --favicon # All favicon formats');
console.log(' npx pixel-forge generate logo.png --pwa # PWA assets');
console.log('\nš§ Web Development Assets:');
console.log(' ā
SEO Images - OpenGraph (og-image.png), Twitter Cards');
console.log(' ā
Favicons - ICO, PNG, SVG, Apple Touch Icons');
console.log(' ā
PWA Assets - App icons, manifest.json, splash screens');
console.log(' ā
Safari Support - Pinned tab SVG, Apple optimizations');
console.log(' ā
Microsoft Support - Windows tiles, browserconfig.xml');
console.log('\nš± Major Social Networks:');
console.log(' ā
Facebook (1200x630) - OpenGraph optimized');
console.log(' ā
Twitter/X (1200x600) - Twitter Cards support');
console.log(' ā
LinkedIn (1200x627) - Professional networking');
console.log(' ā
Instagram (Multiple) - Square, Portrait, Stories, Reels');
console.log(' ā
TikTok (1080x1920) - Vertical video format');
console.log(' ā
YouTube (1280x720) - Thumbnails and Shorts');
console.log(' ā
Pinterest (1000x1500) - Pin and board optimized');
console.log('\nš¬ Messaging Applications:');
console.log(' ā
WhatsApp (400x400 + Preview) - Profile and sharing');
console.log(' ā
iMessage (1200x630) - iOS sharing');
console.log(' ā
Discord (1200x630) - Server sharing');
console.log(' ā
Telegram (1200x630) - Message sharing');
console.log(' ā
Signal (1200x630) - Privacy-focused');
console.log(' ā
Slack (1200x630) - Workplace communication');
console.log(' ā
Android RCS (1200x630) - Rich messaging');
console.log('\nš Emerging Platforms:');
console.log(' ā
Threads (1080x1080) - Meta\'s Twitter alternative');
console.log(' ā
Bluesky (1200x630) - Decentralized social network');
console.log(' ā
Mastodon (1200x630) - Federated social media');
console.log('\nš Statistics:');
console.log(' ⢠25+ platform formats supported');
console.log(' ⢠Complete web development coverage');
console.log(' ⢠Zero external dependencies (uses Sharp)');
console.log(' ⢠Framework-agnostic with Next.js helpers');
console.log(' ⢠TypeScript-first with full type safety');
console.log('\nš¼ļø Supported Image Formats:');
console.log(' ⢠Input: PNG, JPEG, WebP, AVIF, TIFF, GIF, SVG, BMP');
console.log(' ⢠Output: PNG, JPEG, WebP, AVIF, TIFF, GIF, HEIF');
console.log(' ⢠Auto-conversion between formats');
console.log('\nšÆ Platform-Specific Generation:');
console.log(' npx pixel-forge generate logo.png --facebook --twitter # Multiple platforms');
console.log(' npx pixel-forge generate logo.png --messaging # All messaging apps');
console.log(' npx pixel-forge generate logo.png --platforms # Video platforms');
console.log(' npx pixel-forge generate logo.png --all # Everything');
console.log('\nš” Perfect for:');
console.log(' ⢠Next.js, React, Vue, Angular applications');
console.log(' ⢠Static sites (Gatsby, Nuxt, SvelteKit)');
console.log(' ⢠Progressive Web Apps (PWAs)');
console.log(' ⢠E-commerce and marketing sites');
console.log(' ⢠Any web application needing social sharing');
});
// Parse CLI arguments
commander_1.program.parse();