Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions site/BRAND_ASSETS.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
# ALGAL header identity
# ALGAL website identity

The header preserves the three overlapping circles from `favicon.svg` at its
current 28px size. `algal-mark.svg` removes only the opaque rounded background
rectangle; its view box, circle coordinates, strokes, and group are unchanged.
The name and transparent mark share the released Design Kit metallic foil recipe.
The extracted original artwork remains visible when masks or forced colors
disable the decorative paint. The favicon itself is unchanged.
The favicon silhouette comes from the actual header mark, `algal-mark.svg`. Browser variants render it in pure white on transparency. Apple touch variants use the same white mark on black. The visible bounds are centered horizontally and vertically and fill the square on their longest axis, preserving the aspect ratio with no added padding.

- Original `favicon.svg` SHA-256: `340aad988f525145b7caf7545abf311fa5f52cf46c399f172bc948de437d4a88`.
- Transparent `algal-mark.svg` SHA-256: `c962e23d88fea8c8e4aa10ebadbad97af09d54d65b3ed3d63080eef94396a07b`.
Run `bun run generate:icons` to regenerate the SVG and PNG variants from `algal-mark.svg`.

The stylesheet and browser controller are build-only dependencies; the CLI keeps
its zero required runtime dependency contract. No product copy or page layout
is generated by Design Kit.
| File | Size | SHA-256 |
| --- | --- | --- |
| algal-mark.svg | SVG | `c962e23d88fea8c8e4aa10ebadbad97af09d54d65b3ed3d63080eef94396a07b` |
| favicon.svg | SVG | `75802f85fecb6d76c8507c8374b81875101b6dec4733154f4dadc34c3394b63e` |
| favicon-48.png | 48×48 | `19cf28dfd722aa94260e9d61e9f742336a62d68cfccd5013684368655a5721d0` |
| apple-touch-icon.png | 180×180 | `6b92c290b40a46c2dc8a570fd8d3f710f613ef59d1be85c79daa20148782e533` |
Binary file modified site/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified site/favicon-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion site/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 24 additions & 6 deletions site/generate-icons.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
// Renders the SVG favicon into the PNG sizes that browsers, link unfurlers,
// and iOS home screens request. Run `bun run generate:icons` after editing
// site/favicon.svg and commit the PNGs beside it.
// Browser icons follow the current transparent header mark. Run
// `bun run generate:icons` and commit the SVG and PNG derivatives together.
import { readFile, writeFile } from "node:fs/promises";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { Resvg } from "@resvg/resvg-js";

const siteDirectory = dirname(fileURLToPath(import.meta.url));
const svg = await readFile(join(siteDirectory, "favicon.svg"), "utf8");

const source = await readFile(join(siteDirectory, "algal-mark.svg"), "utf8");
const white = source.replace(/stroke="[^"]*"/gu, 'stroke="#ffffff"');
const sample = new Resvg(white, { fitTo: { mode: "width", value: 2048 } }).render();
const pixels = sample.pixels;
let left = sample.width, top = sample.height, right = -1, bottom = -1;
for (let y = 0; y < sample.height; y++) for (let x = 0; x < sample.width; x++) {
if (pixels[(y * sample.width + x) * 4 + 3]! > 0) {
left = Math.min(left, x); right = Math.max(right, x);
top = Math.min(top, y); bottom = Math.max(bottom, y);
}
}
if (right < left) throw new Error("The header mark is empty");
const scale = sample.width / 32;
const side = Math.max(right - left + 1, bottom - top + 1) / scale;
const cx = (left + right + 1) / 2 / scale, cy = (top + bottom + 1) / 2 / scale;
const box = [cx - side / 2, cy - side / 2, side, side].join(" ");
const svg = white.replace('viewBox="0 0 32 32"', `viewBox="${box}"`);
await writeFile(join(siteDirectory, "favicon.svg"), svg);
for (const [file, size] of [["favicon-48.png", 48], ["apple-touch-icon.png", 180]] as const) {
const png = new Resvg(svg, { fitTo: { mode: "width", value: size } }).render().asPng();
const png = new Resvg(svg, {
fitTo: { mode: "width", value: size },
...(file === "apple-touch-icon.png" ? { background: "#000000" } : {}),
}).render().asPng();
await writeFile(join(siteDirectory, file), png);
}
Loading