diff --git a/.changeset/brand-logo-downloads.md b/.changeset/brand-logo-downloads.md new file mode 100644 index 000000000..a845151cc --- /dev/null +++ b/.changeset/brand-logo-downloads.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/docs/brand.md b/docs/brand.md index 963e75f74..dbcab7dc6 100644 --- a/docs/brand.md +++ b/docs/brand.md @@ -11,8 +11,9 @@ Where Hunk's logo files live, which version to use where, and the colors and typ ## Public downloads The public brand page at [hunk.dev/brand/](https://hunk.dev/brand/) offers all four logos in -ink and paper colors as SVG, transparent 2048px-wide PNG, and vector PDF, plus a ZIP bundle. -The website footer links to it. +ink and paper colors as SVG, 2048px-wide PNG (transparent, or solid on the paired background so +it stays visible in any image viewer), and vector PDF, plus a ZIP bundle. The website footer +links to it. The ink SVGs below remain the canonical sources. Regenerate the committed exports in `website/public/brand/downloads/` and `website/public/brand/hunk-brand.zip` after editing them: @@ -30,7 +31,7 @@ the website build does not require the export tools. ## Logo versions -All files are in `website/public/brand/` and served at `https://hunk.dev/brand/`. They are filled with the ink color `#16140f`; recolor by editing the `fill`, or inline the SVG and use `currentColor`. +All files are in `website/public/brand/` and served at `https://hunk.dev/brand/`. They are filled with the ink color `#16140f`; recolor by editing the `fill`, or inline the SVG and use `currentColor`. Each viewBox already includes about one stem-width of clear space, so exports never touch their edges. | File | What it is | Use it for | | ------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | diff --git a/website/public/brand/downloads/README.txt b/website/public/brand/downloads/README.txt index c1432465c..b4d300d53 100644 --- a/website/public/brand/downloads/README.txt +++ b/website/public/brand/downloads/README.txt @@ -1,6 +1,6 @@ Hunk brand assets — https://hunk.dev/brand/ -SVG: scalable originals. PNG: transparent, 2048px wide. PDF: vector export. +SVG: scalable originals. PNG: transparent, 2048px wide. Solid PNG: 2048px wide on the matching background. PDF: vector export. Ink: for light backgrounds. Paper: for dark backgrounds. Use the flat mark below 40px. Keep proportions and leave clear space around the logo. Do not stretch, rotate, add effects, or imply endorsement by Hunk. diff --git a/website/public/brand/downloads/logo-lockup-ink-solid.png b/website/public/brand/downloads/logo-lockup-ink-solid.png new file mode 100644 index 000000000..6157c977f Binary files /dev/null and b/website/public/brand/downloads/logo-lockup-ink-solid.png differ diff --git a/website/public/brand/downloads/logo-lockup-ink.pdf b/website/public/brand/downloads/logo-lockup-ink.pdf index 1a407422e..4cb09410c 100644 Binary files a/website/public/brand/downloads/logo-lockup-ink.pdf and b/website/public/brand/downloads/logo-lockup-ink.pdf differ diff --git a/website/public/brand/downloads/logo-lockup-ink.png b/website/public/brand/downloads/logo-lockup-ink.png index 0e2bbd514..f72d9a5ef 100644 Binary files a/website/public/brand/downloads/logo-lockup-ink.png and b/website/public/brand/downloads/logo-lockup-ink.png differ diff --git a/website/public/brand/downloads/logo-lockup-paper-solid.png b/website/public/brand/downloads/logo-lockup-paper-solid.png new file mode 100644 index 000000000..59549cca5 Binary files /dev/null and b/website/public/brand/downloads/logo-lockup-paper-solid.png differ diff --git a/website/public/brand/downloads/logo-lockup-paper.pdf b/website/public/brand/downloads/logo-lockup-paper.pdf index dff4b7148..c2c2a6094 100644 Binary files a/website/public/brand/downloads/logo-lockup-paper.pdf and b/website/public/brand/downloads/logo-lockup-paper.pdf differ diff --git a/website/public/brand/downloads/logo-lockup-paper.png b/website/public/brand/downloads/logo-lockup-paper.png index d2e2fea1c..8db53f4ab 100644 Binary files a/website/public/brand/downloads/logo-lockup-paper.png and b/website/public/brand/downloads/logo-lockup-paper.png differ diff --git a/website/public/brand/downloads/logo-lockup-paper.svg b/website/public/brand/downloads/logo-lockup-paper.svg index 8cfaaafba..23846a740 100644 --- a/website/public/brand/downloads/logo-lockup-paper.svg +++ b/website/public/brand/downloads/logo-lockup-paper.svg @@ -1 +1 @@ - + diff --git a/website/public/brand/downloads/logo-mark-3d-ink-solid.png b/website/public/brand/downloads/logo-mark-3d-ink-solid.png new file mode 100644 index 000000000..536b7a25e Binary files /dev/null and b/website/public/brand/downloads/logo-mark-3d-ink-solid.png differ diff --git a/website/public/brand/downloads/logo-mark-3d-ink.pdf b/website/public/brand/downloads/logo-mark-3d-ink.pdf index 91a227afd..4c85aad02 100644 Binary files a/website/public/brand/downloads/logo-mark-3d-ink.pdf and b/website/public/brand/downloads/logo-mark-3d-ink.pdf differ diff --git a/website/public/brand/downloads/logo-mark-3d-ink.png b/website/public/brand/downloads/logo-mark-3d-ink.png index d94ec3bc1..725a5f273 100644 Binary files a/website/public/brand/downloads/logo-mark-3d-ink.png and b/website/public/brand/downloads/logo-mark-3d-ink.png differ diff --git a/website/public/brand/downloads/logo-mark-3d-paper-solid.png b/website/public/brand/downloads/logo-mark-3d-paper-solid.png new file mode 100644 index 000000000..a1b5b4d7b Binary files /dev/null and b/website/public/brand/downloads/logo-mark-3d-paper-solid.png differ diff --git a/website/public/brand/downloads/logo-mark-3d-paper.pdf b/website/public/brand/downloads/logo-mark-3d-paper.pdf index 1970c0f0c..456388788 100644 Binary files a/website/public/brand/downloads/logo-mark-3d-paper.pdf and b/website/public/brand/downloads/logo-mark-3d-paper.pdf differ diff --git a/website/public/brand/downloads/logo-mark-3d-paper.png b/website/public/brand/downloads/logo-mark-3d-paper.png index a8a8147ff..129cdd72c 100644 Binary files a/website/public/brand/downloads/logo-mark-3d-paper.png and b/website/public/brand/downloads/logo-mark-3d-paper.png differ diff --git a/website/public/brand/downloads/logo-mark-3d-paper.svg b/website/public/brand/downloads/logo-mark-3d-paper.svg index 5f69ba03c..a2e4a059a 100644 --- a/website/public/brand/downloads/logo-mark-3d-paper.svg +++ b/website/public/brand/downloads/logo-mark-3d-paper.svg @@ -1 +1 @@ - + diff --git a/website/public/brand/downloads/logo-mark-ink-solid.png b/website/public/brand/downloads/logo-mark-ink-solid.png new file mode 100644 index 000000000..48657388f Binary files /dev/null and b/website/public/brand/downloads/logo-mark-ink-solid.png differ diff --git a/website/public/brand/downloads/logo-mark-ink.pdf b/website/public/brand/downloads/logo-mark-ink.pdf index f4ca950d5..bb348f833 100644 Binary files a/website/public/brand/downloads/logo-mark-ink.pdf and b/website/public/brand/downloads/logo-mark-ink.pdf differ diff --git a/website/public/brand/downloads/logo-mark-ink.png b/website/public/brand/downloads/logo-mark-ink.png index bed7b619d..4e20b087f 100644 Binary files a/website/public/brand/downloads/logo-mark-ink.png and b/website/public/brand/downloads/logo-mark-ink.png differ diff --git a/website/public/brand/downloads/logo-mark-paper-solid.png b/website/public/brand/downloads/logo-mark-paper-solid.png new file mode 100644 index 000000000..2db45da12 Binary files /dev/null and b/website/public/brand/downloads/logo-mark-paper-solid.png differ diff --git a/website/public/brand/downloads/logo-mark-paper.pdf b/website/public/brand/downloads/logo-mark-paper.pdf index 5dba0d16e..05f37aad0 100644 Binary files a/website/public/brand/downloads/logo-mark-paper.pdf and b/website/public/brand/downloads/logo-mark-paper.pdf differ diff --git a/website/public/brand/downloads/logo-mark-paper.png b/website/public/brand/downloads/logo-mark-paper.png index ae4ac28c3..21dc12f17 100644 Binary files a/website/public/brand/downloads/logo-mark-paper.png and b/website/public/brand/downloads/logo-mark-paper.png differ diff --git a/website/public/brand/downloads/logo-mark-paper.svg b/website/public/brand/downloads/logo-mark-paper.svg index a7312c4a4..3c30e19c5 100644 --- a/website/public/brand/downloads/logo-mark-paper.svg +++ b/website/public/brand/downloads/logo-mark-paper.svg @@ -1 +1 @@ - + diff --git a/website/public/brand/downloads/logo-wordmark-ink-solid.png b/website/public/brand/downloads/logo-wordmark-ink-solid.png new file mode 100644 index 000000000..209bdc199 Binary files /dev/null and b/website/public/brand/downloads/logo-wordmark-ink-solid.png differ diff --git a/website/public/brand/downloads/logo-wordmark-ink.pdf b/website/public/brand/downloads/logo-wordmark-ink.pdf index a368c5155..d155cda92 100644 Binary files a/website/public/brand/downloads/logo-wordmark-ink.pdf and b/website/public/brand/downloads/logo-wordmark-ink.pdf differ diff --git a/website/public/brand/downloads/logo-wordmark-ink.png b/website/public/brand/downloads/logo-wordmark-ink.png index 8f83b5bcc..dadf75708 100644 Binary files a/website/public/brand/downloads/logo-wordmark-ink.png and b/website/public/brand/downloads/logo-wordmark-ink.png differ diff --git a/website/public/brand/downloads/logo-wordmark-paper-solid.png b/website/public/brand/downloads/logo-wordmark-paper-solid.png new file mode 100644 index 000000000..4da3343ce Binary files /dev/null and b/website/public/brand/downloads/logo-wordmark-paper-solid.png differ diff --git a/website/public/brand/downloads/logo-wordmark-paper.pdf b/website/public/brand/downloads/logo-wordmark-paper.pdf index 36874b82a..b14c33f75 100644 Binary files a/website/public/brand/downloads/logo-wordmark-paper.pdf and b/website/public/brand/downloads/logo-wordmark-paper.pdf differ diff --git a/website/public/brand/downloads/logo-wordmark-paper.png b/website/public/brand/downloads/logo-wordmark-paper.png index 2b729428e..c163743e2 100644 Binary files a/website/public/brand/downloads/logo-wordmark-paper.png and b/website/public/brand/downloads/logo-wordmark-paper.png differ diff --git a/website/public/brand/downloads/logo-wordmark-paper.svg b/website/public/brand/downloads/logo-wordmark-paper.svg index b9d054883..17e9ca90d 100644 --- a/website/public/brand/downloads/logo-wordmark-paper.svg +++ b/website/public/brand/downloads/logo-wordmark-paper.svg @@ -1 +1 @@ - + diff --git a/website/public/brand/hunk-brand.zip b/website/public/brand/hunk-brand.zip index 313440fd6..830a9becc 100644 Binary files a/website/public/brand/hunk-brand.zip and b/website/public/brand/hunk-brand.zip differ diff --git a/website/public/brand/logo-lockup.svg b/website/public/brand/logo-lockup.svg index dd9d005df..68b876883 100644 --- a/website/public/brand/logo-lockup.svg +++ b/website/public/brand/logo-lockup.svg @@ -1 +1 @@ - + diff --git a/website/public/brand/logo-mark-3d.svg b/website/public/brand/logo-mark-3d.svg index 9bd05dd5b..e31226d1d 100644 --- a/website/public/brand/logo-mark-3d.svg +++ b/website/public/brand/logo-mark-3d.svg @@ -1 +1 @@ - + diff --git a/website/public/brand/logo-mark.svg b/website/public/brand/logo-mark.svg index 3bfb071e8..558df030b 100644 --- a/website/public/brand/logo-mark.svg +++ b/website/public/brand/logo-mark.svg @@ -1 +1 @@ - + diff --git a/website/public/brand/logo-wordmark.svg b/website/public/brand/logo-wordmark.svg index 6efe7286a..e201b7d53 100644 --- a/website/public/brand/logo-wordmark.svg +++ b/website/public/brand/logo-wordmark.svg @@ -1 +1 @@ - + diff --git a/website/scripts/generate-brand.ts b/website/scripts/generate-brand.ts index bdced10d8..447fe80e7 100644 --- a/website/scripts/generate-brand.ts +++ b/website/scripts/generate-brand.ts @@ -1,8 +1,8 @@ -/** Exports transparent logo downloads from the canonical SVGs; requires librsvg and zip. */ +/** Exports transparent and solid-background logo downloads from the canonical SVGs; requires librsvg and zip. */ import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; import { fileURLToPath } from "node:url"; import { join } from "node:path"; -import { brandColors, brandDownloadPath, brandLogos } from "../src/data/brand"; +import { brandColors, brandDownloadPath, brandFormats, brandLogos } from "../src/data/brand"; const publicDir = fileURLToPath(new URL("../public/", import.meta.url)); const brandDir = join(publicDir, "brand"); @@ -27,14 +27,17 @@ for (const logo of brandLogos) { await writeFile(svgPath, source.replaceAll("#16140f", color.value)); } files.push(svgPath); - for (const format of ["png", "pdf"]) { - const output = join(downloads, `${logo.id}-${color.id}.${format}`); + for (const format of brandFormats) { + if (format.id === "svg") continue; + const output = join(publicDir, brandDownloadPath(logo.id, color.id, format.id).slice(1)); + const background = format.id === "solid-png" ? ["--background-color", color.background] : []; await run([ "rsvg-convert", "--format", - format, + format.extension, "--width", "2048", + ...background, "--output", output, svgPath, @@ -47,7 +50,7 @@ for (const logo of brandLogos) { const guide = join(downloads, "README.txt"); await writeFile( guide, - "Hunk brand assets — https://hunk.dev/brand/\n\nSVG: scalable originals. PNG: transparent, 2048px wide. PDF: vector export.\nInk: for light backgrounds. Paper: for dark backgrounds.\nUse the flat mark below 40px. Keep proportions and leave clear space around the logo.\nDo not stretch, rotate, add effects, or imply endorsement by Hunk.\n", + "Hunk brand assets — https://hunk.dev/brand/\n\nSVG: scalable originals. PNG: transparent, 2048px wide. Solid PNG: 2048px wide on the matching background. PDF: vector export.\nInk: for light backgrounds. Paper: for dark backgrounds.\nUse the flat mark below 40px. Keep proportions and leave clear space around the logo.\nDo not stretch, rotate, add effects, or imply endorsement by Hunk.\n", ); await rm(join(brandDir, "hunk-brand.zip"), { force: true }); await run(["zip", "-j", "-X", "hunk-brand.zip", ...files, guide]); diff --git a/website/src/data/brand.ts b/website/src/data/brand.ts index 6e02f8ce7..556185cd0 100644 --- a/website/src/data/brand.ts +++ b/website/src/data/brand.ts @@ -4,29 +4,29 @@ export const brandLogos = [ id: "logo-mark", name: "Flat mark", description: "The everyday mark. Use for icons, avatars, and small placements.", - width: 100, - height: 99, + width: 116, + height: 115, }, { id: "logo-mark-3d", name: "3D mark", description: "The block with its offset outline. Use at 40px and up.", - width: 86, - height: 86, + width: 95, + height: 94, }, { id: "logo-wordmark", name: "Wordmark", description: "Just the lowercase letters, drawn as paths. No font needed.", - width: 113, - height: 38, + width: 125, + height: 51, }, { id: "logo-lockup", name: "Full lockup", description: "Mark and wordmark together. For slides, articles, and larger placements.", - width: 215, - height: 86, + width: 224, + height: 94, }, ] as const; @@ -35,11 +35,20 @@ export const brandColors = [ { id: "paper", name: "Paper", value: "#fffdf8", background: "#16140f" }, ] as const; -export const brandFormats = ["svg", "png", "pdf"] as const; +// Transparent PNGs vanish in viewers whose backdrop matches the logo color, so each color also +// ships a solid PNG filled with its paired background. +export const brandFormats = [ + { id: "svg", label: "SVG", name: "SVG", extension: "svg" }, + { id: "png", label: "PNG", name: "transparent PNG", extension: "png" }, + { id: "solid-png", label: "Solid PNG", name: "solid PNG", extension: "png" }, + { id: "pdf", label: "PDF", name: "PDF", extension: "pdf" }, +] as const; + +export type BrandFormatId = (typeof brandFormats)[number]["id"]; /** Resolves an original ink SVG or a generated color/format variant. */ -export function brandDownloadPath(id: string, color: string, format: string): string { - return color === "ink" && format === "svg" - ? `/brand/${id}.svg` - : `/brand/downloads/${id}-${color}.${format}`; +export function brandDownloadPath(id: string, color: string, format: BrandFormatId): string { + if (color === "ink" && format === "svg") return `/brand/${id}.svg`; + if (format === "solid-png") return `/brand/downloads/${id}-${color}-solid.png`; + return `/brand/downloads/${id}-${color}.${format}`; } diff --git a/website/src/pages/brand.astro b/website/src/pages/brand.astro index 4d1e72990..23696378d 100644 --- a/website/src/pages/brand.astro +++ b/website/src/pages/brand.astro @@ -29,7 +29,7 @@ const description = "Download the Hunk logo, mark, and wordmark as SVG, transpar

Logo downloads

-

SVG scales to any size. PNG is transparent, 2048px wide. PDF is for print.

+

SVG scales to any size. PNGs are 2048px wide: transparent, or solid on the matching background. PDF is for print.

{brandLogos.map((logo) => ( @@ -47,7 +47,7 @@ const description = "Download the Hunk logo, mark, and wordmark as SVG, transpar {color.name}
{brandFormats.map((format) => ( - {format.toUpperCase()} + {format.label} ))}
diff --git a/website/src/styles/brand-page.css b/website/src/styles/brand-page.css index aeba044bb..f2bca1bf0 100644 --- a/website/src/styles/brand-page.css +++ b/website/src/styles/brand-page.css @@ -109,7 +109,9 @@ .brand-formats { display: flex; - gap: 18px; + flex-wrap: wrap; + justify-content: flex-end; + gap: 6px 18px; } .brand-formats a:hover { @@ -167,7 +169,7 @@ } .brand-formats { - gap: 14px; + gap: 6px 14px; } .brand-swatches { diff --git a/website/tests/brand-smoke.spec.ts b/website/tests/brand-smoke.spec.ts index 84dfbf3e3..cf098f0b0 100644 --- a/website/tests/brand-smoke.spec.ts +++ b/website/tests/brand-smoke.spec.ts @@ -1,7 +1,28 @@ import AxeBuilder from "@axe-core/playwright"; -import { expect, test } from "@playwright/test"; +import { expect, test, type Page } from "@playwright/test"; import { brandColors, brandDownloadPath, brandFormats, brandLogos } from "../src/data/brand"; +/** Decodes an image in the page and returns its top-left RGBA pixel. */ +async function readTestCornerPixel(page: Page, src: string): Promise { + return page.evaluate(async (url) => { + const image = new Image(); + image.src = url; + await image.decode(); + + const canvas = document.createElement("canvas"); + canvas.width = 1; + canvas.height = 1; + const context = canvas.getContext("2d")!; + context.drawImage(image, 0, 0); + return Array.from(context.getImageData(0, 0, 1, 1).data); + }, src); +} + +/** Converts a #rrggbb color to its RGB channels. */ +function hexToTestRgb(hex: string): number[] { + return [1, 3, 5].map((start) => Number.parseInt(hex.slice(start, start + 2), 16)); +} + test("brand page is discoverable and offers working logo downloads", async ({ page }) => { await page.goto("/"); await page.getByRole("contentinfo").getByRole("link", { name: "Brand", exact: true }).click(); @@ -17,19 +38,23 @@ test("brand page is discoverable and offers working logo downloads", async ({ pa for (const color of brandColors) { for (const format of brandFormats) { const link = page.getByRole("link", { - name: `Download ${logo.name.toLowerCase()} in ${color.name.toLowerCase()} as ${format.toUpperCase()}`, + name: `Download ${logo.name.toLowerCase()} in ${color.name.toLowerCase()} as ${format.name}`, exact: true, }); - const path = brandDownloadPath(logo.id, color.id, format); + const path = brandDownloadPath(logo.id, color.id, format.id); await expect(link).toHaveAttribute("href", path); await expect(link).toHaveAttribute("download", ""); const response = await page.request.get(path); expect(response.ok()).toBe(true); const body = await response.body(); - if (format === "png") { + if (format.extension === "png") { expect(body.subarray(0, 8).toString("hex")).toBe("89504e470d0a1a0a"); expect(body.readUInt32BE(16)).toBe(2048); - } else if (format === "pdf") { + // The padded corner shows the backdrop: clear for transparent PNGs, the paired color for solid ones. + expect(await readTestCornerPixel(page, path)).toEqual( + format.id === "solid-png" ? [...hexToTestRgb(color.background), 255] : [0, 0, 0, 0], + ); + } else if (format.id === "pdf") { expect(body.subarray(0, 5).toString()).toBe("%PDF-"); // SVG masks export as embedded bitmaps; logo PDFs must stay pure vector. expect(body.toString("latin1")).not.toContain("/Subtype /Image");