const fs = require('fs'); const path = require('path'); const { createCanvas } = require('@napi-rs/canvas'); const SIZE = 600; const outDir = __dirname; function roundedRect(ctx, x, y, w, h, r) { ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); } function drawSteam(ctx, x, y, color) { ctx.strokeStyle = color; ctx.lineWidth = 10; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(x, y + 32); ctx.bezierCurveTo(x - 14, y + 6, x + 22, y - 6, x + 8, y - 34); ctx.stroke(); } function drawChopsticks(ctx, color) { ctx.strokeStyle = color; ctx.lineWidth = 12; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(380, 170); ctx.lineTo(490, 280); ctx.stroke(); ctx.beginPath(); ctx.moveTo(415, 150); ctx.lineTo(525, 260); ctx.stroke(); } function drawLogo({ filename, bgGradientFrom, bgGradientTo, cardColor, cardShadow, bowlTop, bowlBottom, accent, textColor, steamColor, chopColor, }) { const canvas = createCanvas(SIZE, SIZE); const ctx = canvas.getContext('2d'); // background const bg = ctx.createLinearGradient(0, 0, SIZE, SIZE); bg.addColorStop(0, bgGradientFrom); bg.addColorStop(1, bgGradientTo); ctx.fillStyle = bg; ctx.fillRect(0, 0, SIZE, SIZE); // icon card ctx.save(); ctx.shadowColor = cardShadow; ctx.shadowBlur = 28; ctx.shadowOffsetY = 14; roundedRect(ctx, 72, 72, 456, 456, 120); ctx.fillStyle = cardColor; ctx.fill(); ctx.restore(); // bowl gradient const bowlGrad = ctx.createLinearGradient(200, 270, 400, 420); bowlGrad.addColorStop(0, bowlTop); bowlGrad.addColorStop(1, bowlBottom); // bowl body ctx.fillStyle = bowlGrad; roundedRect(ctx, 170, 300, 260, 130, 54); ctx.fill(); // bowl lip ctx.fillStyle = 'rgba(255,255,255,0.86)'; ctx.beginPath(); ctx.ellipse(300, 298, 144, 36, 0, 0, Math.PI * 2); ctx.fill(); // inner bowl ctx.fillStyle = 'rgba(13,31,60,0.32)'; ctx.beginPath(); ctx.ellipse(300, 300, 76, 18, 0, 0, Math.PI * 2); ctx.fill(); // noodles ctx.strokeStyle = accent; ctx.lineWidth = 9; ctx.lineCap = 'round'; for (let i = 0; i < 3; i++) { const y = 282 + i * 8; ctx.beginPath(); ctx.moveTo(220, y); ctx.bezierCurveTo(250, y - 14, 350, y - 14, 380, y); ctx.stroke(); } // steam drawSteam(ctx, 245, 215, steamColor); drawSteam(ctx, 300, 190, steamColor); drawSteam(ctx, 355, 215, steamColor); // chopsticks drawChopsticks(ctx, chopColor); // JM monogram chip roundedRect(ctx, 220, 448, 160, 56, 28); ctx.fillStyle = 'rgba(255,255,255,0.22)'; ctx.fill(); ctx.fillStyle = textColor; ctx.font = 'bold 34px sans-serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText('점메추', 300, 476); const output = path.join(outDir, filename); fs.writeFileSync(output, canvas.toBuffer('image/png')); return output; } const light = drawLogo({ filename: 'lunch-pick-logo-light-600-v2.png', bgGradientFrom: '#F7FBFF', bgGradientTo: '#E8F3FF', cardColor: 'rgba(255,255,255,0.94)', cardShadow: 'rgba(30,102,180,0.20)', bowlTop: '#29B2F4', bowlBottom: '#0A7FE8', accent: '#0876D7', textColor: '#0F3F7C', steamColor: '#5AAAF6', chopColor: '#1D4D87', }); const dark = drawLogo({ filename: 'lunch-pick-logo-dark-600-v2.png', bgGradientFrom: '#061226', bgGradientTo: '#0D203F', cardColor: 'rgba(17,39,72,0.95)', cardShadow: 'rgba(0,0,0,0.45)', bowlTop: '#56C8FF', bowlBottom: '#1997F0', accent: '#9ED9FF', textColor: '#EAF4FF', steamColor: '#BFE4FF', chopColor: '#E6F3FF', }); console.log(light); console.log(dark);