const { createCanvas, loadImage, registerFont } = require('canvas'); const path = require('path'); const CARD_WIDTH = 900; const CARD_HEIGHT = 300; async function generateWelcomeCard(member, config = {}) { const canvas = createCanvas(CARD_WIDTH, CARD_HEIGHT); const ctx = canvas.getContext('2d'); const bgColor = config.background_color || '#1a1a2e'; const accentColor = config.accent_color || '#7c3aed'; const textColor = config.text_color || '#ffffff'; const subtextColor = config.subtext_color || '#a0a0a0'; ctx.fillStyle = bgColor; ctx.fillRect(0, 0, CARD_WIDTH, CARD_HEIGHT); const gradient = ctx.createLinearGradient(0, 0, CARD_WIDTH, 0); gradient.addColorStop(0, hexToRgba(accentColor, 0.3)); gradient.addColorStop(0.5, hexToRgba(accentColor, 0.1)); gradient.addColorStop(1, 'transparent'); ctx.fillStyle = gradient; ctx.fillRect(0, 0, CARD_WIDTH, CARD_HEIGHT); ctx.strokeStyle = accentColor; ctx.lineWidth = 4; ctx.strokeRect(2, 2, CARD_WIDTH - 4, CARD_HEIGHT - 4); for (let i = 0; i < 50; i++) { const x = Math.random() * CARD_WIDTH; const y = Math.random() * CARD_HEIGHT; const size = Math.random() * 2; ctx.fillStyle = hexToRgba(accentColor, Math.random() * 0.3); ctx.beginPath(); ctx.arc(x, y, size, 0, Math.PI * 2); ctx.fill(); } const avatarSize = 160; const avatarX = 70; const avatarY = (CARD_HEIGHT - avatarSize) / 2; try { const avatarURL = member.displayAvatarURL({ extension: 'png', size: 256 }); const avatar = await loadImage(avatarURL); ctx.save(); ctx.beginPath(); ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2 + 4, 0, Math.PI * 2); ctx.fillStyle = accentColor; ctx.fill(); ctx.closePath(); ctx.beginPath(); ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2); ctx.clip(); ctx.drawImage(avatar, avatarX, avatarY, avatarSize, avatarSize); ctx.restore(); } catch (err) { ctx.save(); ctx.beginPath(); ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2); ctx.fillStyle = accentColor; ctx.fill(); ctx.restore(); ctx.fillStyle = textColor; ctx.font = 'bold 60px Arial'; ctx.textAlign = 'center'; ctx.fillText(member.user.username[0].toUpperCase(), avatarX + avatarSize / 2, avatarY + avatarSize / 2 + 20); } const textX = avatarX + avatarSize + 50; ctx.fillStyle = textColor; ctx.font = 'bold 36px Arial'; ctx.textAlign = 'left'; const welcomeText = config.title || 'WELCOME'; ctx.fillText(welcomeText, textX, 80); const username = member.user.username; const maxUsernameWidth = CARD_WIDTH - textX - 50; let fontSize = 48; ctx.font = `bold ${fontSize}px Arial`; while (ctx.measureText(username).width > maxUsernameWidth && fontSize > 24) { fontSize -= 2; ctx.font = `bold ${fontSize}px Arial`; } ctx.fillStyle = accentColor; ctx.fillText(username, textX, 140); ctx.fillStyle = subtextColor; ctx.font = '22px Arial'; const serverName = member.guild.name; ctx.fillText(`to ${serverName}`, textX, 175); const memberCount = member.guild.memberCount; ctx.fillStyle = textColor; ctx.font = 'bold 28px Arial'; ctx.fillText(`Member #${memberCount.toLocaleString()}`, textX, 230); const joinDate = new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); ctx.fillStyle = subtextColor; ctx.font = '20px Arial'; ctx.fillText(`Joined: ${joinDate}`, textX, 265); return canvas.toBuffer('image/png'); } function hexToRgba(hex, alpha) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); if (result) { const r = parseInt(result[1], 16); const g = parseInt(result[2], 16); const b = parseInt(result[3], 16); return `rgba(${r}, ${g}, ${b}, ${alpha})`; } return `rgba(124, 58, 237, ${alpha})`; } module.exports = { generateWelcomeCard };