From cc55f55bb372fb9798b8a5d63902817cea7eaa6f Mon Sep 17 00:00:00 2001 From: connerkup Date: Mon, 15 Jun 2026 22:41:58 -0700 Subject: [PATCH] Redesign site logo with stronger logomark and path-based wordmark. Replace generic system-font SVG text with Plus Jakarta Sans and JetBrains Mono outlines, add a terminal-themed shield mark, and use the square mark on the home hero. Co-authored-by: Cursor --- website/public/favicon.svg | 11 +- website/scripts/generate-logos.mjs | 157 +++++++++++++++++++++++++ website/src/assets/logo-dark.svg | 18 ++- website/src/assets/logo-light.svg | 18 ++- website/src/assets/logo-mark-dark.svg | 13 ++ website/src/assets/logo-mark-light.svg | 13 ++ website/src/content/docs/index.mdx | 3 +- website/src/styles/custom.css | 11 ++ 8 files changed, 233 insertions(+), 11 deletions(-) create mode 100644 website/scripts/generate-logos.mjs create mode 100644 website/src/assets/logo-mark-dark.svg create mode 100644 website/src/assets/logo-mark-light.svg diff --git a/website/public/favicon.svg b/website/public/favicon.svg index ded5165..21ac0b2 100644 --- a/website/public/favicon.svg +++ b/website/public/favicon.svg @@ -1,4 +1,11 @@ - - + + + + + + + + + diff --git a/website/scripts/generate-logos.mjs b/website/scripts/generate-logos.mjs new file mode 100644 index 0000000..3da5933 --- /dev/null +++ b/website/scripts/generate-logos.mjs @@ -0,0 +1,157 @@ +/** + * Regenerate ShieldedShell logo SVGs (header, hero mark, favicon). + * Requires: npm install fontkit opentype.js (dev-only, run from repo root). + */ +import fs from 'node:fs'; +import https from 'node:https'; +import path from 'node:path'; +import { createRequire } from 'node:module'; + +const require = createRequire(import.meta.url); +const fontkit = require('fontkit'); + +const root = path.resolve(import.meta.dirname, '..'); +const assetsDir = path.join(root, 'src', 'assets'); +const publicDir = path.join(root, 'public'); + +const FONTS = { + jakarta: + 'https://fonts.gstatic.com/s/plusjakartasans/v12/LDIbaomQNQcsA88c7O9yZ4KMCoOg4IA6-91aHEjcWuA_d0nNSg.ttf', + mono: 'https://fonts.gstatic.com/s/jetbrainsmono/v24/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8L6tjPQ.ttf', +}; + +function fetch(url) { + return new Promise((resolve, reject) => { + https + .get(url, (res) => { + if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { + fetch(res.headers.location).then(resolve).catch(reject); + return; + } + const chunks = []; + res.on('data', (chunk) => chunks.push(chunk)); + res.on('end', () => resolve(Buffer.concat(chunks))); + }) + .on('error', reject); + }); +} + +function pathFor(font, text, x, y, size) { + const run = font.layout(text); + const scale = size / font.unitsPerEm; + let cx = x; + const parts = []; + for (let i = 0; i < run.glyphs.length; i++) { + const glyph = run.glyphs[i]; + const pos = run.positions[i]; + if (glyph.path) { + const p = glyph.path + .scale(scale) + .translate(cx + (pos?.xOffset || 0) * scale, y + (pos?.yOffset || 0) * scale); + parts.push(p.toSVG()); + } + cx += (pos?.xAdvance || glyph.advanceWidth) * scale; + } + return { d: parts.join(' '), width: cx - x }; +} + +function logomark(theme) { + const isLight = theme === 'light'; + const outer = isLight ? '#0f766e' : '#14b8a6'; + const outerMid = isLight ? '#115e59' : '#0d9488'; + const inner = isLight ? '#ecfdf5' : '#042f2e'; + const prompt = isLight ? '#ecfdf5' : '#ccfbf1'; + const ring = isLight ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.22)'; + + return ` + + + + + + + + + + + + `.trim(); +} + +function wordmark(theme, jakarta, mono) { + const isLight = theme === 'light'; + const shieldedColor = isLight ? '#0f172a' : '#f8fafc'; + const shellColor = isLight ? '#0f766e' : '#2dd4bf'; + const shieldedSize = 15.5; + const shellSize = 14.5; + const x = 44; + const y = 23.5; + const shielded = pathFor(jakarta, 'Shielded', x, y, shieldedSize); + const shell = pathFor(mono, 'Shell', x + shielded.width + 2, y, shellSize); + const width = Math.ceil(x + shielded.width + 2 + shell.width + 4); + + return { + width, + svg: ` + + + `.trim(), + }; +} + +function horizontalLogo(theme, jakarta, mono) { + const mark = logomark(theme); + const text = wordmark(theme, jakarta, mono); + return ` +`; +} + +function squareMark(theme) { + const mark = logomark(theme); + return ` +`; +} + +function favicon() { + return ` + + + + + + + + + + +`; +} + +const [jakartaBuf, monoBuf] = await Promise.all([ + fetch(FONTS.jakarta), + fetch(FONTS.mono), +]); +const jakarta = fontkit.create(jakartaBuf); +const mono = fontkit.create(monoBuf); + +fs.mkdirSync(assetsDir, { recursive: true }); +fs.mkdirSync(publicDir, { recursive: true }); + +const files = [ + [path.join(assetsDir, 'logo-light.svg'), horizontalLogo('light', jakarta, mono)], + [path.join(assetsDir, 'logo-dark.svg'), horizontalLogo('dark', jakarta, mono)], + [path.join(assetsDir, 'logo-mark-light.svg'), squareMark('light')], + [path.join(assetsDir, 'logo-mark-dark.svg'), squareMark('dark')], + [path.join(publicDir, 'favicon.svg'), favicon()], +]; + +for (const [file, content] of files) { + fs.writeFileSync(file, content.trim() + '\n'); +} + +console.log('Wrote', files.length, 'logo files'); diff --git a/website/src/assets/logo-dark.svg b/website/src/assets/logo-dark.svg index 9f912aa..fdf95c8 100644 --- a/website/src/assets/logo-dark.svg +++ b/website/src/assets/logo-dark.svg @@ -1,5 +1,15 @@ -