164 lines
7.8 KiB
JavaScript
164 lines
7.8 KiB
JavaScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import opentype from 'opentype.js';
|
|
import sharp from 'sharp';
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
const outputDirectory = path.join(root, 'static', 'brand');
|
|
const fontDirectory = path.join(root, 'node_modules', '@fontsource', 'barlow', 'files');
|
|
const heavy = opentype.parse(fs.readFileSync(path.join(fontDirectory, 'barlow-latin-900-normal.woff')).buffer);
|
|
const medium = opentype.parse(fs.readFileSync(path.join(fontDirectory, 'barlow-latin-700-normal.woff')).buffer);
|
|
|
|
fs.mkdirSync(outputDirectory, { recursive: true });
|
|
|
|
const colors = {
|
|
background: '#0a0c0d',
|
|
surface: '#111415',
|
|
border: '#303536',
|
|
grid: '#2a3031',
|
|
orange: '#f6a821',
|
|
white: '#ecebe5'
|
|
};
|
|
|
|
function trackedPath(font, value, x, baseline, size, tracking = 0) {
|
|
let cursor = x;
|
|
let data = '';
|
|
for (const character of value) {
|
|
const glyph = font.charToGlyph(character);
|
|
data += glyph.getPath(cursor, baseline, size).toPathData(2);
|
|
cursor += glyph.advanceWidth * size / font.unitsPerEm + tracking;
|
|
}
|
|
return { data, width: cursor - x - tracking };
|
|
}
|
|
|
|
function emblem(x, y, size) {
|
|
const scale = size / 100;
|
|
return `
|
|
<g transform="translate(${x} ${y}) scale(${scale})">
|
|
<g fill="none" stroke="${colors.orange}" stroke-width="12" stroke-linecap="butt">
|
|
<path d="M73 20A38 38 0 0 0 15 63"/>
|
|
<path d="M85 37A38 38 0 0 1 55 88"/>
|
|
<path d="M42 87A38 38 0 0 1 18 70"/>
|
|
</g>
|
|
<rect x="72" y="23" width="10" height="10" fill="${colors.orange}"/>
|
|
<path d="M62 35H35V65H62M68 43V57" fill="none" stroke="${colors.white}" stroke-width="9" stroke-linecap="butt" stroke-linejoin="miter"/>
|
|
</g>`;
|
|
}
|
|
|
|
async function writePng(svg, filename, width, height) {
|
|
await sharp(Buffer.from(svg))
|
|
.resize(width, height, { fit: 'fill' })
|
|
.png({ compressionLevel: 9, adaptiveFiltering: true })
|
|
.toFile(path.join(outputDirectory, filename));
|
|
}
|
|
|
|
const transparentLogo = `
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">
|
|
${emblem(72, 72, 880)}
|
|
</svg>`;
|
|
|
|
const serverIcon = `
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">
|
|
<rect width="1024" height="1024" fill="${colors.background}"/>
|
|
<path d="M0 192H1024M0 512H1024M0 832H1024M192 0V1024M512 0V1024M832 0V1024" stroke="${colors.grid}" stroke-width="2" opacity=".32"/>
|
|
<rect x="96" y="96" width="832" height="832" fill="none" stroke="${colors.border}" stroke-width="3"/>
|
|
${emblem(132, 132, 760)}
|
|
</svg>`;
|
|
|
|
const shd = trackedPath(heavy, 'SHD', 0, 0, 190, -3);
|
|
const build = trackedPath(heavy, '.build', 0, 0, 190, -2);
|
|
const descriptor = trackedPath(medium, 'RESURGENCE DATA & TOOLS', 0, 0, 43, 7);
|
|
const wordmarkWidth = shd.width + build.width;
|
|
const lockupX = 600;
|
|
const wordmarkBaseline = 590;
|
|
|
|
const banner = `
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080" viewBox="0 0 1920 1080">
|
|
<defs>
|
|
<radialGradient id="signal" cx="34%" cy="58%" r="54%">
|
|
<stop offset="0" stop-color="#2b2416"/>
|
|
<stop offset=".44" stop-color="#141617"/>
|
|
<stop offset="1" stop-color="${colors.background}"/>
|
|
</radialGradient>
|
|
<linearGradient id="fade" x1="0" x2="1">
|
|
<stop stop-color="${colors.orange}" stop-opacity=".22"/>
|
|
<stop offset=".7" stop-color="${colors.orange}" stop-opacity="0"/>
|
|
</linearGradient>
|
|
</defs>
|
|
<rect width="1920" height="1080" fill="${colors.background}"/>
|
|
<rect y="96" width="1920" height="984" fill="url(#signal)"/>
|
|
<path d="M0 96H1920M0 864H1920M192 96V1080M1728 96V1080" stroke="${colors.border}" stroke-width="2"/>
|
|
<path d="M0 224H1920M0 352H1920M0 480H1920M0 608H1920M0 736H1920M320 96V1080M448 96V1080M576 96V1080M704 96V1080M832 96V1080M960 96V1080M1088 96V1080M1216 96V1080M1344 96V1080M1472 96V1080M1600 96V1080" stroke="${colors.grid}" stroke-width="1" opacity=".22"/>
|
|
<path d="M192 864H1260" stroke="url(#fade)" stroke-width="3"/>
|
|
<path d="M1534 210h194v194" fill="none" stroke="${colors.orange}" stroke-width="4" opacity=".42"/>
|
|
<path d="M386 756A272 272 0 0 1 386 212" fill="none" stroke="${colors.border}" stroke-width="2"/>
|
|
${emblem(188, 314, 330)}
|
|
<g transform="translate(${lockupX} ${wordmarkBaseline})">
|
|
<path d="${shd.data}" fill="${colors.white}"/>
|
|
<path d="${build.data}" fill="${colors.orange}" transform="translate(${shd.width} 0)"/>
|
|
<rect y="34" width="${Math.max(wordmarkWidth, descriptor.width)}" height="2" fill="${colors.border}"/>
|
|
<path d="${descriptor.data}" fill="${colors.white}" transform="translate(0 98)"/>
|
|
</g>
|
|
<g transform="translate(1540 820)">
|
|
<rect width="188" height="56" fill="${colors.surface}" stroke="${colors.border}" stroke-width="2"/>
|
|
<rect x="16" y="23" width="10" height="10" fill="${colors.orange}"/>
|
|
<path d="M42 28H158" stroke="${colors.orange}" stroke-width="2"/>
|
|
<path d="M166 22l8 6-8 6" fill="none" stroke="${colors.orange}" stroke-width="2"/>
|
|
</g>
|
|
</svg>`;
|
|
|
|
const inviteSplash = `
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080" viewBox="0 0 1920 1080">
|
|
<defs>
|
|
<radialGradient id="left-signal" cx="8%" cy="52%" r="58%">
|
|
<stop offset="0" stop-color="#3b2d15"/>
|
|
<stop offset=".38" stop-color="#171819"/>
|
|
<stop offset="1" stop-color="${colors.background}"/>
|
|
</radialGradient>
|
|
<radialGradient id="right-signal" cx="94%" cy="45%" r="50%">
|
|
<stop offset="0" stop-color="#241e13"/>
|
|
<stop offset=".48" stop-color="#111415"/>
|
|
<stop offset="1" stop-color="${colors.background}" stop-opacity="0"/>
|
|
</radialGradient>
|
|
<linearGradient id="relay-left" x1="0" x2="1">
|
|
<stop stop-color="${colors.orange}" stop-opacity=".8"/>
|
|
<stop offset="1" stop-color="${colors.orange}" stop-opacity="0"/>
|
|
</linearGradient>
|
|
<linearGradient id="relay-right" x1="1" x2="0">
|
|
<stop stop-color="${colors.orange}" stop-opacity=".55"/>
|
|
<stop offset="1" stop-color="${colors.orange}" stop-opacity="0"/>
|
|
</linearGradient>
|
|
</defs>
|
|
<rect width="1920" height="1080" fill="${colors.background}"/>
|
|
<rect width="1920" height="1080" fill="url(#left-signal)"/>
|
|
<rect width="1920" height="1080" fill="url(#right-signal)"/>
|
|
<path d="M0 120H1920M0 960H1920M160 0V1080M1760 0V1080" stroke="${colors.border}" stroke-width="2"/>
|
|
<path d="M0 288H1920M0 456H1920M0 624H1920M0 792H1920M328 0V1080M496 0V1080M664 0V1080M832 0V1080M1000 0V1080M1168 0V1080M1336 0V1080M1504 0V1080" stroke="${colors.grid}" stroke-width="1" opacity=".16"/>
|
|
<g opacity=".92">${emblem(-92, 224, 620)}</g>
|
|
<g opacity=".66">${emblem(1465, 326, 410)}</g>
|
|
<path d="M0 170H605" stroke="url(#relay-left)" stroke-width="4"/>
|
|
<path d="M0 910H500" stroke="url(#relay-left)" stroke-width="3"/>
|
|
<path d="M1335 188H1920" stroke="url(#relay-right)" stroke-width="3"/>
|
|
<path d="M1450 892H1920" stroke="url(#relay-right)" stroke-width="4"/>
|
|
<g fill="${colors.orange}">
|
|
<rect x="560" y="164" width="12" height="12"/>
|
|
<rect x="486" y="904" width="10" height="10"/>
|
|
<rect x="1348" y="182" width="12" height="12"/>
|
|
<rect x="1436" y="886" width="12" height="12"/>
|
|
</g>
|
|
<path d="M610 170h90M1310 188h-92M540 910h118M1400 892h-112" stroke="${colors.white}" stroke-width="2" opacity=".22"/>
|
|
<rect x="650" y="120" width="620" height="840" fill="${colors.background}" opacity=".42"/>
|
|
</svg>`;
|
|
|
|
await writePng(transparentLogo, 'shd-core-segments.png', 1024, 1024);
|
|
await writePng(serverIcon, 'shd-build-discord-icon.png', 1024, 1024);
|
|
await writePng(banner, 'shd-build-discord-banner-1920x1080.png', 1920, 1080);
|
|
await writePng(inviteSplash, 'shd-build-discord-invite-background-1920x1080.png', 1920, 1080);
|
|
await sharp(path.join(outputDirectory, 'shd-build-discord-banner-1920x1080.png'))
|
|
.resize(960, 540)
|
|
.png({ compressionLevel: 9, adaptiveFiltering: true })
|
|
.toFile(path.join(outputDirectory, 'shd-build-discord-banner-960x540.png'));
|
|
|
|
console.log(`Rendered brand assets to ${outputDirectory}`);
|