UNPKG

pixel-forge

Version:

A comprehensive generator for social media previews, favicons, and visual assets across all platforms

660 lines (659 loc) • 29.6 kB
#!/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();