Skip to content

Commit 4587e9e

Browse files
leex279claude
andcommitted
docs(brand): add brand foundation page on archon.diy
- Mount the canonical Archon brand sheet at `/brand/` in the docs site (Penpot-exported standalone HTML, top-right "Console →" cross-link surgically removed via a re-runnable patch script). - Add a Starlight overview page with a Quick reference (gradient, surface) and an embedded full brand sheet. - Sidebar gains a "🎨 Brand" entry between Roadmap and The Book of Archon. - Fix the dark-mode active sidebar link being unreadable (`color: var(--sl-color-white)`). - Require future UI changes to align with the brand foundation (new "UI and Visual Design" section in root CLAUDE.md). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent aa71520 commit 4587e9e

9 files changed

Lines changed: 355 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,15 @@ curl http://localhost:3637/api/conversations/<conversationId>/messages
587587

588588
## Development Guidelines
589589

590+
### UI and Visual Design
591+
592+
All UI changes — production web (`packages/web/`), experiments (`packages/web/src/experiments/`), the docs site, marketing surfaces, and any future visual surface — must align with the Archon brand foundation.
593+
594+
- **Canonical brand guide:** https://archon.diy/brand/ (source: `packages/docs-web/src/content/docs/brand/index.md` + `packages/docs-web/public/brand/foundation.html`).
595+
- **Use brand tokens, not ad-hoc values.** Colors, gradients, surfaces, and typography must come from the established design tokens (`packages/web/src/index.css`) or the brand guide. Don't hard-code hex values that aren't in the system.
596+
- **Introducing a new visual token** (color, font, radius, spacing) means updating both the token source and the brand guide. Don't fork the palette per package.
597+
- **When in doubt, consult the brand guide first** before inventing new visual treatments. Open a discussion if the guide doesn't cover your case.
598+
590599
### When Creating New Features
591600

592601
**Quick reference:**

packages/docs-web/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export default defineConfig({
2525
sidebar: [
2626
{ label: '✦ Marketplace', link: '/workflows/' },
2727
{ label: '🗺️ Roadmap', link: '/roadmap/' },
28+
{ label: '🎨 Brand', link: '/brand/' },
2829
{
2930
label: 'The Book of Archon',
3031
autogenerate: { directory: 'book' },

packages/docs-web/public/brand/foundation.html

Lines changed: 194 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Brand foundation helpers
2+
3+
One-shot scripts for inspecting and patching `public/brand/foundation.html` (the Penpot-exported standalone brand sheet).
4+
5+
| Script | Purpose |
6+
| --- | --- |
7+
| `_find-console.ts` | Decode every JS/JSX asset in the bundle and grep for any case-insensitive `console` references. Used to locate cross-links to the sibling "Archon Console" doc. |
8+
| `_dump.ts <html> <uuid> <out>` | Decode one manifest entry by UUID to a file so you can edit/inspect the source. |
9+
| `_patch.ts <html>` | Re-applies our customisations (currently: removes the top-right `Console →` pill from the bundled JSX). Idempotent — fails loudly if the source no longer matches. |
10+
11+
## When to re-run
12+
13+
If `foundation.html` is re-exported from Penpot, the bundled JSX UUID changes and our patches will need to be reapplied:
14+
15+
```bash
16+
bun packages/docs-web/scripts/brand/_find-console.ts packages/docs-web/public/brand/foundation.html
17+
# Identify the new UUID for the main JSX (look for `<ArchonLockup subtitle="Brand"`)
18+
# Update TARGET_UUID in _patch.ts if needed, then:
19+
bun packages/docs-web/scripts/brand/_patch.ts packages/docs-web/public/brand/foundation.html
20+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { readFileSync, writeFileSync } from 'fs';
2+
import { gunzipSync } from 'zlib';
3+
4+
const file = readFileSync(process.argv[2], 'utf8');
5+
const uuid = process.argv[3];
6+
const outFile = process.argv[4];
7+
8+
const lines = file.split('\n');
9+
const manifestLine = lines.find((l, i) => i >= 180 && l.startsWith('{"'));
10+
if (!manifestLine) throw new Error('manifest not found');
11+
const manifest = JSON.parse(manifestLine);
12+
const entry = manifest[uuid];
13+
if (!entry) throw new Error('uuid not in manifest');
14+
const raw = Buffer.from(entry.data, 'base64');
15+
const text = entry.compressed ? gunzipSync(raw).toString('utf8') : raw.toString('utf8');
16+
writeFileSync(outFile, text);
17+
console.log(`wrote ${text.length} chars to ${outFile} (mime=${entry.mime}, compressed=${entry.compressed})`);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { readFileSync } from 'fs';
2+
import { gunzipSync } from 'zlib';
3+
4+
const file = readFileSync(process.argv[2] ?? './foundation.html', 'utf8');
5+
const lines = file.split('\n');
6+
const manifestLine = lines.find((l, i) => i >= 180 && l.startsWith('{"'));
7+
if (!manifestLine) {
8+
console.error('manifest line not found');
9+
process.exit(1);
10+
}
11+
const manifest = JSON.parse(manifestLine) as Record<
12+
string,
13+
{ mime: string; compressed: boolean; data: string }
14+
>;
15+
16+
for (const [uuid, entry] of Object.entries(manifest)) {
17+
if (!entry.mime.includes('javascript') && !entry.mime.includes('jsx')) continue;
18+
const raw = Buffer.from(entry.data, 'base64');
19+
const text = entry.compressed
20+
? gunzipSync(raw).toString('utf8')
21+
: raw.toString('utf8');
22+
const matches = [...text.matchAll(/.{0,40}[Cc]onsole.{0,40}/g)];
23+
if (matches.length > 0) {
24+
console.log(`\n=== ${uuid} (${entry.mime}, ${text.length} chars, compressed=${entry.compressed}) ===`);
25+
for (const m of matches.slice(0, 8)) {
26+
console.log(` ${m[0].replace(/\s+/g, ' ')}`);
27+
}
28+
if (matches.length > 8) console.log(` ... +${matches.length - 8} more`);
29+
}
30+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* One-shot patch for foundation.html: removes the top-right "Console →" pill
3+
* from the bundled JSX module so the standalone brand sheet stops cross-linking
4+
* to the Console doc.
5+
*
6+
* Re-run if you ever re-export the foundation HTML from Penpot.
7+
*/
8+
import { readFileSync, writeFileSync } from 'fs';
9+
import { gunzipSync, gzipSync } from 'zlib';
10+
11+
const TARGET_UUID = '0779aa1d-eb15-4e5c-8f25-e0ee165f5cbb';
12+
const HEADER_BLOCK_START = ' <div style={{ display: "flex", alignItems: "center", gap: 8 }}>';
13+
const HEADER_BLOCK_END = ' </a>\n </div>';
14+
15+
const path = process.argv[2];
16+
if (!path) {
17+
console.error('usage: bun _patch.ts <foundation.html>');
18+
process.exit(1);
19+
}
20+
21+
const file = readFileSync(path, 'utf8');
22+
const lines = file.split('\n');
23+
const manifestLineIdx = lines.findIndex((l, i) => i >= 180 && l.startsWith('{"'));
24+
if (manifestLineIdx < 0) throw new Error('manifest line not found');
25+
const manifest = JSON.parse(lines[manifestLineIdx]) as Record<
26+
string,
27+
{ mime: string; compressed: boolean; data: string }
28+
>;
29+
30+
const entry = manifest[TARGET_UUID];
31+
if (!entry) throw new Error(`uuid ${TARGET_UUID} not in manifest`);
32+
33+
const raw = Buffer.from(entry.data, 'base64');
34+
const original = entry.compressed ? gunzipSync(raw).toString('utf8') : raw.toString('utf8');
35+
36+
const startIdx = original.indexOf(HEADER_BLOCK_START);
37+
if (startIdx < 0) throw new Error('header block start not found — already patched?');
38+
const endIdx = original.indexOf(HEADER_BLOCK_END, startIdx);
39+
if (endIdx < 0) throw new Error('header block end not found');
40+
41+
const patched =
42+
original.slice(0, startIdx) +
43+
original.slice(endIdx + HEADER_BLOCK_END.length).replace(/^\n/, '');
44+
45+
const verify = patched.match(/Console /g) ?? [];
46+
console.log(`Console → occurrences: ${verify.length} (was 2, should be 1 after patch)`);
47+
48+
const reEncoded = entry.compressed
49+
? gzipSync(Buffer.from(patched, 'utf8')).toString('base64')
50+
: Buffer.from(patched, 'utf8').toString('base64');
51+
52+
manifest[TARGET_UUID] = { ...entry, data: reEncoded };
53+
lines[manifestLineIdx] = JSON.stringify(manifest);
54+
55+
writeFileSync(path, lines.join('\n'));
56+
console.log(`patched ${path} (entry shrank from ${original.length} to ${patched.length} chars)`);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: Brand
3+
description: Archon brand foundation — colors, logo, and usage guidelines.
4+
---
5+
6+
## Quick reference
7+
8+
The essentials at a glance:
9+
10+
- **Primary gradient** — <code style="color:#ED10EC">#ED10EC</code> → <code style="color:#8E40C8">#8E40C8</code> → <code style="color:#06CE94">#06CE94</code>
11+
- **Surface** — <code style="color:#0F1115;background:#fff;padding:0 6px;border-radius:3px">#0F1115</code>
12+
- **Logo** — the shield mark with the abstract Archon glyph, stroked with the primary gradient
13+
14+
Use the embedded foundation below for the canonical version. If you need a vector asset or have a question about an unusual usage, open a discussion on [GitHub](https://github.com/coleam00/Archon/discussions).
15+
16+
## Full brand sheet
17+
18+
The Archon brand foundation lives below. It's a single self-contained page covering the logo, color system, typography, and approved usage.
19+
20+
<iframe
21+
src="/brand/foundation.html"
22+
title="Archon Brand Foundation"
23+
style="width:100%;height:80vh;border:1px solid var(--sl-color-gray-5);border-radius:8px;background:#0F1115;"
24+
loading="lazy"
25+
></iframe>
26+
27+
Prefer a full-window view? [Open the brand sheet in a new tab](/brand/foundation.html).

packages/docs-web/src/styles/custom.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@
2323
[data-theme='dark'] .sidebar-content a[aria-current='page'] {
2424
background: linear-gradient(135deg, rgba(168, 85, 247, 0.15), rgba(59, 130, 246, 0.15));
2525
border-left-color: #a855f7;
26+
color: var(--sl-color-white);
2627
}

0 commit comments

Comments
 (0)