167 lines
4.1 KiB
JavaScript
167 lines
4.1 KiB
JavaScript
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 + 34);
|
|
ctx.bezierCurveTo(x - 14, y + 8, x + 18, y - 2, x + 6, y - 30);
|
|
ctx.stroke();
|
|
}
|
|
|
|
function drawRice(ctx, cx, cy, colorA, colorB) {
|
|
const grad = ctx.createLinearGradient(cx - 100, cy - 30, cx + 100, cy + 20);
|
|
grad.addColorStop(0, colorA);
|
|
grad.addColorStop(1, colorB);
|
|
ctx.fillStyle = grad;
|
|
ctx.beginPath();
|
|
ctx.ellipse(cx, cy, 128, 56, 0, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = 'rgba(255,255,255,0.65)';
|
|
for (let i = 0; i < 14; i++) {
|
|
const x = cx - 95 + i * 14;
|
|
const y = cy - 8 + ((i % 2) * 6 - 3);
|
|
ctx.beginPath();
|
|
ctx.ellipse(x, y, 4.3, 2.7, -0.3, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
}
|
|
}
|
|
|
|
function drawSideDish(ctx, x, y, colorOuter, colorInner) {
|
|
// small plate
|
|
ctx.fillStyle = colorOuter;
|
|
ctx.beginPath();
|
|
ctx.ellipse(x, y, 38, 16, 0, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
// food on plate
|
|
ctx.fillStyle = colorInner;
|
|
ctx.beginPath();
|
|
ctx.ellipse(x, y - 2, 24, 9, 0, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
}
|
|
|
|
function drawLogo(theme) {
|
|
const canvas = createCanvas(SIZE, SIZE);
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
const bg = ctx.createLinearGradient(0, 0, SIZE, SIZE);
|
|
bg.addColorStop(0, theme.bgFrom);
|
|
bg.addColorStop(1, theme.bgTo);
|
|
ctx.fillStyle = bg;
|
|
ctx.fillRect(0, 0, SIZE, SIZE);
|
|
|
|
ctx.save();
|
|
ctx.shadowColor = theme.shadow;
|
|
ctx.shadowBlur = 28;
|
|
ctx.shadowOffsetY = 10;
|
|
roundedRect(ctx, 74, 74, 452, 452, 122);
|
|
ctx.fillStyle = theme.card;
|
|
ctx.fill();
|
|
ctx.restore();
|
|
|
|
// main bowl
|
|
const bowlGrad = ctx.createLinearGradient(180, 280, 420, 430);
|
|
bowlGrad.addColorStop(0, theme.bowlTop);
|
|
bowlGrad.addColorStop(1, theme.bowlBottom);
|
|
|
|
ctx.fillStyle = bowlGrad;
|
|
roundedRect(ctx, 168, 306, 264, 140, 62);
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = theme.lipOuter;
|
|
ctx.beginPath();
|
|
ctx.ellipse(300, 305, 154, 44, 0, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = theme.lipInner;
|
|
ctx.beginPath();
|
|
ctx.ellipse(300, 310, 102, 25, 0, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
drawRice(ctx, 300, 283, theme.riceA, theme.riceB);
|
|
|
|
// side dishes (to emphasize food/meal)
|
|
drawSideDish(ctx, 192, 352, theme.sidePlate, theme.sideFoodA);
|
|
drawSideDish(ctx, 408, 352, theme.sidePlate, theme.sideFoodB);
|
|
|
|
// spoon silhouette (meal cue, no chopsticks)
|
|
ctx.strokeStyle = theme.spoon;
|
|
ctx.lineWidth = 10;
|
|
ctx.lineCap = 'round';
|
|
ctx.beginPath();
|
|
ctx.moveTo(445, 210);
|
|
ctx.lineTo(490, 300);
|
|
ctx.stroke();
|
|
ctx.fillStyle = theme.spoon;
|
|
ctx.beginPath();
|
|
ctx.ellipse(430, 196, 20, 14, -0.5, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
drawSteam(ctx, 245, 196, theme.steam);
|
|
drawSteam(ctx, 300, 172, theme.steam);
|
|
drawSteam(ctx, 355, 196, theme.steam);
|
|
|
|
const output = path.join(outDir, theme.filename);
|
|
fs.writeFileSync(output, canvas.toBuffer('image/png'));
|
|
return output;
|
|
}
|
|
|
|
const light = drawLogo({
|
|
filename: 'lunch-pick-logo-light-600-v4.png',
|
|
bgFrom: '#F6FAFF',
|
|
bgTo: '#EAF3FF',
|
|
card: 'rgba(255,255,255,0.97)',
|
|
shadow: 'rgba(16,78,147,0.18)',
|
|
bowlTop: '#31B4F4',
|
|
bowlBottom: '#0A85E8',
|
|
lipOuter: '#DDE9F8',
|
|
lipInner: '#8EA6C5',
|
|
riceA: '#FFFFFF',
|
|
riceB: '#EFF6FF',
|
|
sidePlate: '#D8E4F5',
|
|
sideFoodA: '#EF7C42',
|
|
sideFoodB: '#8BC34A',
|
|
spoon: '#1E4F8A',
|
|
steam: '#5EA8EE',
|
|
});
|
|
|
|
const dark = drawLogo({
|
|
filename: 'lunch-pick-logo-dark-600-v4.png',
|
|
bgFrom: '#07142A',
|
|
bgTo: '#0E2243',
|
|
card: 'rgba(17,39,72,0.96)',
|
|
shadow: 'rgba(0,0,0,0.46)',
|
|
bowlTop: '#66CBFF',
|
|
bowlBottom: '#1A9EF4',
|
|
lipOuter: '#DDE6F2',
|
|
lipInner: '#8CA2BC',
|
|
riceA: '#FFFFFF',
|
|
riceB: '#F2F7FF',
|
|
sidePlate: '#6E86A6',
|
|
sideFoodA: '#FF9F5A',
|
|
sideFoodB: '#A0D66A',
|
|
spoon: '#E6F1FF',
|
|
steam: '#B8DCFF',
|
|
});
|
|
|
|
console.log(light);
|
|
console.log(dark);
|