diff --git a/web/public/brand/tux-classic.svg b/web/public/brand/tux-classic.svg new file mode 100644 index 0000000..6b558e7 --- /dev/null +++ b/web/public/brand/tux-classic.svg @@ -0,0 +1,438 @@ + + diff --git a/web/public/brand/tux.md b/web/public/brand/tux.md new file mode 100644 index 0000000..e615439 --- /dev/null +++ b/web/public/brand/tux.md @@ -0,0 +1,16 @@ +# Tux + +Linux mascot used on the Open Graph card. + +`tux.svg` is a flat derivative of Larry Ewing's Tux: the original +silhouette, filled with Vocalinux tokens (ink, paper-bright, sun). +No gradients, blurs, or glares. `tux-classic.svg` is the unaltered +Wikimedia vector. + +Original drawing by Larry Ewing with The GIMP. +Vector by Larry Ewing, Simon Budig, and Garrett LeSage. + +Permission: copy and modify, with attribution to Larry Ewing +(`lewing@isc.tamu.edu`) and The GIMP if someone asks. + +Source: https://commons.wikimedia.org/wiki/File:Tux.svg diff --git a/web/public/brand/tux.svg b/web/public/brand/tux.svg new file mode 100644 index 0000000..f716e0c --- /dev/null +++ b/web/public/brand/tux.svg @@ -0,0 +1,20 @@ + + diff --git a/web/public/og-image.png b/web/public/og-image.png index 668fd47..f4bfb1b 100644 Binary files a/web/public/og-image.png and b/web/public/og-image.png differ diff --git a/web/public/og-image.webp b/web/public/og-image.webp index b89c471..82fc128 100644 Binary files a/web/public/og-image.webp and b/web/public/og-image.webp differ diff --git a/web/scripts/render-social-assets.mjs b/web/scripts/render-social-assets.mjs index ebd9e94..ad8cb46 100644 --- a/web/scripts/render-social-assets.mjs +++ b/web/scripts/render-social-assets.mjs @@ -28,6 +28,8 @@ function toWebp(src, dest) { execFileSync("convert", [src, dest]); } +const skipIcons = process.env.OG_ONLY === "1"; + const sizes = [ [16, join(pub, "favicon-16x16.png")], [32, join(pub, "favicon-32x32.png")], @@ -42,28 +44,33 @@ const sizes = [ [512, join(pub, "vocalinux.png")], ]; -for (const [size, dest] of sizes) { - convertPng(size, dest); - if (dest.endsWith(".png") && !dest.includes("favicon-")) { - const webp = dest.replace(/\.png$/i, ".webp"); - if ( - dest.includes("vocalinux-") || - dest.endsWith("/vocalinux.png") - ) { - toWebp(dest, webp); +if (!skipIcons) { + for (const [size, dest] of sizes) { + convertPng(size, dest); + if (dest.endsWith(".png") && !dest.includes("favicon-")) { + const webp = dest.replace(/\.png$/i, ".webp"); + if ( + dest.includes("vocalinux-") || + dest.endsWith("/vocalinux.png") + ) { + toWebp(dest, webp); + } } } -} -convertPng(180, join(pub, "apple-touch-icon.png"), { paper: true }); -execFileSync("convert", [ - join(pub, "favicon-16x16.png"), - join(pub, "favicon-32x32.png"), - join(pub, "favicon.ico"), -]); + convertPng(180, join(pub, "apple-touch-icon.png"), { paper: true }); + execFileSync("convert", [ + join(pub, "favicon-16x16.png"), + join(pub, "favicon-32x32.png"), + join(pub, "favicon.ico"), + ]); +} const markSvg = readFileSync(mark, "utf8"); const markData = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(markSvg)}`; +const tuxData = `data:image/svg+xml;charset=utf-8,${encodeURIComponent( + readFileSync(join(pub, "brand/tux.svg"), "utf8"), +)}`; const dotsData = `data:image/svg+xml;charset=utf-8,${encodeURIComponent( readFileSync(join(pub, "brand/paper-dots.svg"), "utf8"), )}`; @@ -80,7 +87,7 @@ const ogHtml = ` background-image: url("${dotsData}"); font-family: "Avenir Next", "Helvetica Neue", ui-sans-serif, system-ui, "Segoe UI", Arial, sans-serif; } - .frame { display: flex; height: 630px; padding: 56px 64px; box-sizing: border-box; gap: 48px; } + .frame { display: flex; height: 630px; padding: 48px 40px 40px 64px; box-sizing: border-box; gap: 28px; } .copy { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; } .brand { display: flex; align-items: center; gap: 14px; font-size: 28px; font-weight: 600; letter-spacing: -0.03em; } .brand img { width: 56px; height: 56px; border-radius: 50%; } @@ -90,7 +97,9 @@ const ogHtml = ` .proof { display: flex; flex-wrap: wrap; gap: 10px 18px; margin-top: 28px; padding-top: 22px; border-top: 1px solid #c9c8bd; color: #5f6861; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 15px; } .proof span + span { padding-left: 18px; border-left: 1px solid #c9c8bd; } .url { margin-top: 26px; color: #5f6861; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 14px; } - .workbench { width: 420px; flex: none; align-self: center; } + .right { position: relative; width: 520px; flex: none; align-self: stretch; } + .workbench { width: 340px; margin-top: 36px; } + .tux { position: absolute; right: 0; bottom: 0; height: 430px; width: auto; } .panel { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; color: #fffdf7; background: #0b1a15; border-radius: 10px; font-size: 14px; } .rec { width: 8px; height: 8px; margin-right: 6px; border-radius: 50%; background: #de6a57; display: inline-block; } .window { margin-top: 10px; background: #fffdf7; border: 1px solid #9ea59f; border-radius: 12px; overflow: hidden; } @@ -121,16 +130,19 @@ const ogHtml = `
vocalinux.com
-