Files
Genarrative/scripts/generate-taonier-squish-logo-variants.mjs

184 lines
6.5 KiB
JavaScript

import { mkdirSync, writeFileSync } from 'node:fs';
import path from 'node:path';
const repoRoot = process.cwd();
const outputDir = path.join(
repoRoot,
'public',
'branding',
'taonier-logo-squish-variants',
);
const variants = [
{
id: 'taonier-squish-berry-mint',
title: '莓果薄荷',
topStart: '#ff4778',
topEnd: '#ff6b5f',
bottomStart: '#12c9b7',
bottomEnd: '#16b899',
starStart: '#ffd54c',
starEnd: '#ffb82e',
accent: '#ffc545',
background: '#fffaf2',
},
{
id: 'taonier-squish-candy-pop',
title: '糖果桃青',
topStart: '#ff5fa2',
topEnd: '#ff8670',
bottomStart: '#2ed7c5',
bottomEnd: '#65d8f4',
starStart: '#ffe06f',
starEnd: '#ffbf4d',
accent: '#ffce5e',
background: '#fff8fb',
},
{
id: 'taonier-squish-jelly-cream',
title: '奶油果冻',
topStart: '#ff758d',
topEnd: '#ff9a70',
bottomStart: '#42d6b5',
bottomEnd: '#7ce3c5',
starStart: '#fff07a',
starEnd: '#ffc955',
accent: '#ffd76a',
background: '#fffdf4',
},
{
id: 'taonier-squish-bubble-bright',
title: '亮彩泡泡',
topStart: '#ff3f8f',
topEnd: '#ff6d6d',
bottomStart: '#00c2b8',
bottomEnd: '#00d69a',
starStart: '#fff15c',
starEnd: '#ffbe35',
accent: '#ffbd3c',
background: '#fdfcff',
},
{
id: 'taonier-squish-sunny-coral',
title: '暖日珊瑚',
topStart: '#ff684f',
topEnd: '#ff8d67',
bottomStart: '#22c4a8',
bottomEnd: '#4dd9b5',
starStart: '#ffe36d',
starEnd: '#ffb948',
accent: '#ffc04a',
background: '#fff8ed',
},
{
id: 'taonier-squish-neon-cute',
title: '霓虹可爱',
topStart: '#ff3d7f',
topEnd: '#ff4fb8',
bottomStart: '#00bfae',
bottomEnd: '#00d2ff',
starStart: '#fff16a',
starEnd: '#ffd13d',
accent: '#ffcf45',
background: '#fbfbff',
},
];
function buildLogoSvg(variant, includeLabel = false) {
const labelHeight = includeLabel ? 72 : 0;
const height = 1024 + labelHeight;
const labelMarkup = includeLabel
? `
<rect x="0" y="1024" width="1024" height="72" fill="#fffdf8"/>
<text x="512" y="1069" text-anchor="middle" font-family="Microsoft YaHei, PingFang SC, Arial, sans-serif" font-size="36" fill="#302a25">${variant.title}</text>`
: '';
return `<?xml version="1.0" encoding="UTF-8"?>
<svg width="1024" height="${height}" viewBox="0 0 1024 ${height}" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="top" x1="250" y1="180" x2="770" y2="420" gradientUnits="userSpaceOnUse">
<stop stop-color="${variant.topStart}"/>
<stop offset="1" stop-color="${variant.topEnd}"/>
</linearGradient>
<linearGradient id="bottom" x1="250" y1="620" x2="760" y2="850" gradientUnits="userSpaceOnUse">
<stop stop-color="${variant.bottomStart}"/>
<stop offset="1" stop-color="${variant.bottomEnd}"/>
</linearGradient>
<linearGradient id="star" x1="438" y1="452" x2="586" y2="590" gradientUnits="userSpaceOnUse">
<stop stop-color="${variant.starStart}"/>
<stop offset="1" stop-color="${variant.starEnd}"/>
</linearGradient>
<filter id="softShadow" x="140" y="120" width="760" height="790" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feDropShadow dx="0" dy="18" stdDeviation="16" flood-color="#231f20" flood-opacity="0.08"/>
</filter>
</defs>
<rect width="1024" height="${height}" fill="${variant.background}"/>
<g filter="url(#softShadow)">
<path d="M257.5 295.6C286.4 210.6 398.9 164 513.4 176.9C618.3 188.7 731.3 244.8 776.2 326.4C810.8 389.2 779.6 447.5 709.4 458.8C646.8 468.8 596.8 438.6 543.5 429.4C475.6 417.7 428.6 456.8 370.4 471.7C301.2 489.4 229.3 378.4 257.5 295.6Z" fill="url(#top)"/>
<path d="M251.2 672.8C273.2 589.1 366.4 562.5 427.4 617.9C469.5 656.1 503.6 712.6 565.5 721.3C621.9 729.2 660.5 692.6 712.6 673.7C776.6 650.4 839.4 693.4 821.8 762.9C798.2 856 672.2 910 543.4 889.5C424.4 870.6 328.6 812.7 275.9 743.4C259.1 721.4 244.5 698.4 251.2 672.8Z" fill="url(#bottom)"/>
</g>
<path d="M512 428C528.1 481.8 550.2 503.9 604 520C550.2 536.1 528.1 558.2 512 612C495.9 558.2 473.8 536.1 420 520C473.8 503.9 495.9 481.8 512 428Z" fill="url(#star)"/>
<path d="M396 489C405.9 498.8 417.4 503.7 431 504C417.4 504.3 405.9 509.2 396 519C386.1 509.2 374.6 504.3 361 504C374.6 503.7 386.1 498.8 396 489Z" fill="${variant.accent}" opacity="0.95"/>
<path d="M630 486C639.9 495.8 651.4 500.7 665 501C651.4 501.3 639.9 506.2 630 516C620.1 506.2 608.6 501.3 595 501C608.6 500.7 620.1 495.8 630 486Z" fill="${variant.accent}" opacity="0.95"/>
<circle cx="373" cy="557" r="11" fill="${variant.accent}" opacity="0.88"/>
<circle cx="650" cy="555" r="11" fill="${variant.accent}" opacity="0.88"/>
${labelMarkup}
</svg>`;
}
function buildContactSheetSvg() {
const cell = 320;
const label = 64;
const gap = 28;
const width = cell * 3 + gap * 4;
const height = (cell + label) * 2 + gap * 3;
const items = variants
.map((variant, index) => {
const row = Math.floor(index / 3);
const col = index % 3;
const x = gap + col * (cell + gap);
const y = gap + row * (cell + label + gap);
const logo = buildLogoSvg(variant)
.replace(/<\?xml[^>]+>\n/u, '')
.replace('<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">', `<svg x="${x}" y="${y}" width="${cell}" height="${cell}" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">`);
return `${logo}
<rect x="${x}" y="${y + cell}" width="${cell}" height="${label}" fill="#fffdf8"/>
<text x="${x + cell / 2}" y="${y + cell + 40}" text-anchor="middle" font-family="Microsoft YaHei, PingFang SC, Arial, sans-serif" font-size="22" fill="#302a25">${String(index + 1).padStart(2, '0')} ${variant.title}</text>`;
})
.join('\n');
return `<?xml version="1.0" encoding="UTF-8"?>
<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">
<rect width="${width}" height="${height}" fill="#f6f2eb"/>
${items}
</svg>`;
}
mkdirSync(outputDir, { recursive: true });
for (const variant of variants) {
writeFileSync(
path.join(outputDir, `${variant.id}.svg`),
buildLogoSvg(variant),
'utf8',
);
}
writeFileSync(
path.join(outputDir, 'taonier-squish-variants-contact-sheet.svg'),
buildContactSheetSvg(),
'utf8',
);
console.log(
JSON.stringify(
{
ok: true,
outputDir,
files: [...variants.map((variant) => `${variant.id}.svg`), 'taonier-squish-variants-contact-sheet.svg'],
},
null,
2,
),
);