From 833ae6bcdaa5fdc2570b56491a9958656b6a1ae8 Mon Sep 17 00:00:00 2001 From: vraspar Date: Sat, 28 Mar 2026 17:01:11 -0700 Subject: [PATCH 1/7] =?UTF-8?q?feat(website):=20Zine=20redesign=20?= =?UTF-8?q?=E2=80=94=20printed=20zine=20aesthetic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A fundamentally different design language: - Newsreader serif headings (editorial, not tech) - Asymmetric left-biased layout (620px content, 780px code blocks) - Parchment background (#f3efe9) with clay accent (#a0785a) - CSS film grain overlay (inline SVG noise at 3.5% opacity) - Text-only hero: 'Share what your team knows.' - Naked 2x2 feature grid (no card borders or backgrounds) - Architecture as prose (three sentences, not a diagram) - Step numbers 01/02/03 in large serif (like chapter numbers) - Italic 'brain' wordmark in nav (Newsreader italic) - IBM Plex Mono for code (not JetBrains Mono) - 600ms scroll reveals with cubic-bezier easing - Sticky nav: brain | Docs | Blog | GitHub - 207 lines HTML, 489 lines CSS, 65 lines JS Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- website/README.md | 56 ++-- website/index.html | 283 +++++++++---------- website/main.js | 65 +++++ website/style.css | 673 ++++++++++++++++++++------------------------ website/terminal.js | 214 -------------- 5 files changed, 517 insertions(+), 774 deletions(-) create mode 100644 website/main.js delete mode 100644 website/terminal.js diff --git a/website/README.md b/website/README.md index d4926c0..9103c4b 100644 --- a/website/README.md +++ b/website/README.md @@ -1,54 +1,36 @@ # Brain CLI Website -Static landing page for the [Brain CLI](https://github.com/vraspar/brain) project. +Static landing page for [Brain CLI](https://github.com/vraspar/brain). + +## Design: "Zine" + +A homepage that looks like a printed zine. Serif headings (Newsreader), asymmetric layout, parchment background, clay accent, CSS film grain, architecture as prose. Not a tech template. ## Stack -- Plain HTML + CSS + vanilla JavaScript -- No frameworks, no build step, no dependencies -- Google Fonts: JetBrains Mono + Inter +- Plain HTML + CSS + vanilla JS (~65 lines) +- No frameworks, no build step +- Google Fonts: Newsreader + Inter + IBM Plex Mono ## Files ``` website/ -├── index.html # The entire page -├── style.css # All styles -├── terminal.js # Terminal typing animation (~170 lines) -└── README.md # This file +├── index.html +├── style.css +├── main.js +└── README.md ``` -## Local preview - -Open `index.html` in a browser, or use any static server: +## Preview ```bash -cd website -npx serve . -# or -python3 -m http.server 8000 +cd website && npx serve . ``` -## Deploy to GitHub Pages - -### Option 1: From `website/` directory - -1. Go to **Settings → Pages** in the GitHub repo -2. Set source to **Deploy from a branch** -3. Select branch `main` and folder `/website` -4. Save — site deploys to `https://vraspar.github.io/brain/` - -### Option 2: Copy to `docs/` (if Pages requires it) - -```bash -cp -r website/ docs/website/ -git add docs/website/ -git commit -m "deploy: website to GitHub Pages" -git push -``` - -Then configure Pages to serve from `/docs/website`. - -## Design +## Palette -Based on the Phosphor design spec. Dark monochrome theme with green (#4ade80) accent. All color combinations pass WCAG AA, most pass AAA. +- Background: `#f3efe9` (parchment) +- Ink: `#2b2b28` (warm near-black) +- Accent: `#a0785a` (clay) +- Code: `#1d1d1d` (darkroom) diff --git a/website/index.html b/website/index.html index 1fa8d5c..128ca88 100644 --- a/website/index.html +++ b/website/index.html @@ -10,138 +10,140 @@ - + - + - - -
-
-
brain
-

- A CLI for sharing knowledge across a dev team.
- Markdown in git. Searchable via FTS5.
- Accessible to AI agents through MCP. -

- -
- $ npm install -g @vraspar/brain@alpha - -
- -
-
- -
+ + +
+ +
+
+

Share what
your team knows.

+

A command-line tool for publishing and discovering technical knowledge. Markdown in git, searchable via SQLite FTS5, exposed to AI agents through MCP.

+
+ $ npm install -g @vraspar/brain@alpha + +
+
+
+ -
-
-

How it works

+
+
+ +
-
-
-
1. Start
-
-
# First person creates a brain
-
$ brain init --name "Acme Engineering"
-
-✅ Brain "Acme Engineering" is ready!
-
 
-
# Teammates join it
-
$ brain connect https://github.com/acme/brain-hub.git
-
-
+
01
+
+
+
# First person creates a brain
+
$ brain init --name "Acme Engineering"
+
✓ Brain "Acme Engineering" is ready!
+
 
+
# Teammates join it
+
$ brain connect https://github.com/acme/brain-hub.git
+
+
-
-
2. Add knowledge
-
-
# Push a single guide
-
$ brain push ./guide.md
-
-✅ Pushed: Docker Multi-Stage Builds - Tags: docker (auto-detected)
-
 
-
# Or import docs from a repo
-
$ brain ingest https://github.com/acme/docs.git
-
-✅ Ingested 24 entries from acme/docs
-
-
+
02
+
+
+
# Push a guide
+
$ brain push ./guide.md
+
✓ Pushed: Docker Multi-Stage Builds
+
Tags: docker (auto-detected)
+
 
+
# Or import from a repo
+
$ brain ingest https://github.com/acme/docs.git
+
✓ Ingested 24 entries from acme/docs
+
+
-
-
3. Discover
-
-
$ brain search "kubernetes"
-
+
03
+
+
+
$ brain search "kubernetes"
+
Found 3 results: -┌────────────────────────┬────────┬───────┬───────────┐ -│ Title │ Author │ Type │ Tags │ -├────────────────────────┼────────┼───────┼───────────┤ -│ K8s Deployment Guide │ bob │ guide │ k8s │ -│ CI Pipeline │ carol │ guide │ ci, k8s │ -│ Helm Chart Patterns │ alice │ skill │ helm, k8s │ -└────────────────────────┴────────┴───────┴───────────┘
-
-
+┌────────────────────────┬────────┬───────┬───────────┐ +│ Title │ Author │ Type │ Tags │ +├────────────────────────┼────────┼───────┼───────────┤ +│ K8s Deployment Guide │ bob │ guide │ k8s │ +│ CI Pipeline │ carol │ guide │ ci, k8s │ +│ Helm Chart Patterns │ alice │ skill │ helm, k8s │ +└────────────────────────┴────────┴───────┴───────────┘
-
-
-

Why brain?

+
+
+ -
-
+
+

Git as storage

-

Entries are markdown in a git repo. No server to run. No infrastructure to manage. Version history and access control come from git.

+

Entries are markdown in a git repo. No server. No infrastructure. Version history and access control are free.

-
+

FTS5 search

-

SQLite FTS5 with BM25 ranking, prefix matching, and contextual snippets. Sub-millisecond queries. Works offline. Index rebuilt from source on every sync.

+

SQLite full-text search with BM25 ranking. Sub-millisecond. Works offline. The index is a disposable cache, rebuilt from source on every sync.

+
+
+

MCP for agents

+

10 tools, 2 resources via Model Context Protocol. Your AI agent reads your team’s knowledge base natively. brain serve starts the server.

-
-

MCP-native

-

10 tools and 2 resources via Model Context Protocol. Your AI agent can search, read, edit, and publish entries. brain serve starts the server.

+
+

Knowledge trails

+

Auto-linked entries via tag overlap and content similarity. brain trail <topic> walks the knowledge graph.

-

Also: repo ingest · freshness scoring · knowledge trails · Obsidian vault · 20 commands

- -

- Zero infrastructure. One command to start.
- brain connect https://github.com/acme/brain-hub.git -

+

Also: repo ingest · freshness scoring · Obsidian vault · interactive search · 20 commands · --format json

- -
-
-

Works with your AI agent

- -

Add to your MCP client config:

- -
-
mcp.json
-
{ + +
+
+ +

Add brain to your MCP client:

+
+
+
+
mcp.json
+
{ "mcpServers": { "brain": { "command": "brain", @@ -150,87 +152,56 @@

Works with your AI agent

} }
- -

10 tools: push_knowledge · search_knowledge · whats_new · get_entry · brain_stats · get_recommendations · update_entry · list_entries · explore_topic · retract_entry
2 resources: brain://digest · brain://stats

- -

Your agent can search team knowledge, publish findings, and check what's new.

- -

Claude · Copilot · Cursor · Windsurf

+
+
+

Works with Claude · Copilot · Cursor · Windsurf

- -
-
-

Quick start

- -
+ +
+
+ +
+
+
# Install
-
$ npm install -g @vraspar/brain@alpha
+
$ npm install -g @vraspar/brain@alpha
 
# Create a brain
-
$ brain init --name "My Team"
+
$ brain init --name "My Team"
 
# Or join an existing one
-
$ brain connect <url>
+
$ brain connect <url>
- +
+

Requires Node.js 20+ and git.

-
-
-

Under the hood

- -
-       brain push / brain search / brain digest
-                        │
-                 ┌──────▼──────┐
-                 │     CLI     │
-                 └──────┬──────┘
-                        │
-       ┌────────────────┼────────────────┐
-       ▼                ▼                ▼
-  ┌──────────┐   ┌────────────┐   ┌──────────┐
-  │ Git repo │   │ SQLite    │   │ Receipts │
-  │ (storage)│   │ FTS5      │   │ (analytics│
-  │          │   │ (search)   │   │          │
-  └──────────┘   └────────────┘   └──────────┘
-
- -
-
- Storage - Markdown + YAML frontmatter in a git repo -
-
- Search - FTS5 virtual table, rebuilt on sync -
-
- Analytics - JSON receipts, eventually consistent -
-
+
+
+ +

Brain stores entries as markdown files with YAML frontmatter in a git repository. The search index is an SQLite FTS5 virtual table, rebuilt from the markdown files on every sync. Read receipts are JSON files committed alongside entries — analytics with zero infrastructure.

- - + diff --git a/website/main.js b/website/main.js new file mode 100644 index 0000000..7132d3f --- /dev/null +++ b/website/main.js @@ -0,0 +1,65 @@ +(function () { + 'use strict'; + + var prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + + // Scroll reveal with stagger + var reveals = document.querySelectorAll('.reveal'); + if (reveals.length > 0 && !prefersReduced) { + var observer = new IntersectionObserver( + function (entries) { + entries.forEach(function (entry, i) { + if (entry.isIntersecting) { + setTimeout(function () { + entry.target.classList.add('visible'); + }, i * 80); + observer.unobserve(entry.target); + } + }); + }, + { threshold: 0.08 } + ); + reveals.forEach(function (el) { observer.observe(el); }); + } else { + reveals.forEach(function (el) { el.classList.add('visible'); }); + } + + // Nav border on scroll + var nav = document.querySelector('.site-nav'); + var sentinel = document.querySelector('.nav-sentinel'); + if (nav && sentinel) { + new IntersectionObserver(function (entries) { + entries.forEach(function (entry) { + nav.classList.toggle('scrolled', !entry.isIntersecting); + }); + }).observe(sentinel); + } + + // Mobile nav + var toggle = document.querySelector('.nav-toggle'); + var menu = document.querySelector('.mobile-menu'); + if (toggle && menu) { + toggle.addEventListener('click', function () { + var open = toggle.classList.toggle('open'); + menu.classList.toggle('open', open); + menu.setAttribute('aria-hidden', String(!open)); + toggle.setAttribute('aria-expanded', String(open)); + }); + } + + // Copy button + document.querySelectorAll('.copy-btn').forEach(function (btn) { + btn.addEventListener('click', function () { + var text = btn.getAttribute('data-copy'); + if (!text) return; + navigator.clipboard.writeText(text).then(function () { + btn.classList.add('copied'); + btn.innerHTML = ''; + setTimeout(function () { + btn.classList.remove('copied'); + btn.innerHTML = ''; + }, 2000); + }); + }); + }); +})(); diff --git a/website/style.css b/website/style.css index 571f811..46cf943 100644 --- a/website/style.css +++ b/website/style.css @@ -1,30 +1,18 @@ :root { - /* Background */ - --bg-primary: #0a0a0a; - --bg-surface: #141414; - --bg-elevated: #1a1a1a; - --border: #262626; - --border-focus: #333333; - - /* Text */ - --text-primary: #fafafa; - --text-body: #d4d4d8; - --text-secondary: #a1a1aa; - --text-muted: #71717a; - - /* Accent (Phosphor Green) */ - --accent: #4ade80; - --accent-bright: #86efac; - --accent-dim: #166534; - --accent-glow: rgba(74, 222, 128, 0.1); - - /* Terminal */ - --term-bg: #0d0d0d; - --term-border: #2a2a2a; - --term-prompt: #4ade80; - --term-cursor: #4ade80; - --term-output: #d4d4d8; - --term-comment: #6b7280; + --bg: #f3efe9; + --bg-alt: #ede8e1; + --bg-code: #1d1d1d; + --ink: #2b2b28; + --ink-light: #5c5955; + --ink-faint: #8a8580; + --ink-ghost: #b5b0aa; + --clay: #a0785a; + --clay-light: #c49a78; + --code-fg: #d4d0c8; + --code-prompt: #b8a88a; + --code-comment: #6b6660; + --code-border: #2a2a27; + --grain-opacity: 0.035; } *, @@ -43,24 +31,37 @@ html { body { font-family: 'Inter', system-ui, -apple-system, sans-serif; font-weight: 400; - line-height: 1.7; - color: var(--text-body); - background-color: var(--bg-primary); + font-size: 0.95rem; + line-height: 1.75; + color: var(--ink); + background-color: var(--bg); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } +/* Film grain overlay */ +body::before { + content: ''; + position: fixed; + inset: 0; + z-index: 9999; + pointer-events: none; + opacity: var(--grain-opacity); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.65' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E"); + background-size: 256px 256px; +} + /* Skip link */ .skip-link { position: absolute; top: -100%; left: 1rem; padding: 0.5rem 1rem; - background: var(--accent); - color: var(--bg-primary); - font-weight: 600; + background: var(--clay); + color: var(--bg); + font-weight: 500; border-radius: 4px; - z-index: 100; + z-index: 10000; text-decoration: none; } @@ -68,420 +69,377 @@ body { top: 1rem; } -/* Layout */ -.container { - max-width: 1100px; - margin: 0 auto; +/* Layout columns */ +.content-col { + max-width: 620px; + margin-left: 15%; padding: 0 1.5rem; } -@media (min-width: 768px) { - .container { - padding: 0 2rem; - } +.code-col { + max-width: 780px; + margin-left: 15%; + padding: 0 1.5rem; } -@media (min-width: 1100px) { - .container { - padding: 0; - } +/* Navigation */ +.nav-sentinel { + height: 0; + position: absolute; + top: 0; } -section { - padding: 5rem 0; +.site-nav { + position: sticky; + top: 0; + z-index: 100; + background: rgba(243, 239, 233, 0.9); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-bottom: 1px solid transparent; + transition: border-color 300ms ease; + height: 48px; } -/* Typography */ -h1, h2, h3, h4 { - font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; - color: var(--text-primary); - letter-spacing: -0.02em; - line-height: 1.3; +.site-nav.scrolled { + border-bottom-color: var(--ink-ghost); } -h1 { - font-size: 3.5rem; - font-weight: 700; +.nav-inner { + max-width: 1200px; + margin: 0 auto; + padding: 0 1.5rem; + display: flex; + align-items: center; + justify-content: space-between; + height: 48px; } -h2 { - font-size: 1.75rem; - font-weight: 700; - margin-bottom: 2.5rem; - text-align: center; +.nav-wordmark { + font-family: 'Newsreader', Georgia, serif; + font-style: italic; + font-size: 1rem; + color: var(--ink); + text-decoration: none; + letter-spacing: -0.01em; } -h3 { - font-size: 1.1rem; - font-weight: 600; +.nav-wordmark:hover { + color: var(--clay); } -p { - max-width: 65ch; - margin-left: auto; - margin-right: auto; +.nav-links { + display: flex; + gap: 2rem; } -a { - color: var(--text-body); +.nav-links a { + font-family: 'Inter', sans-serif; + font-size: 0.65rem; + font-weight: 500; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--ink-faint); text-decoration: none; transition: color 200ms ease; } -a:hover { - color: var(--accent); - text-decoration: underline; -} - -a:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - border-radius: 2px; -} - -/* Hero */ -.hero { - padding: 6rem 0 4rem; - text-align: center; -} - -.hero-wordmark { - font-family: 'JetBrains Mono', monospace; - font-size: 4rem; - font-weight: 700; - color: var(--accent); - margin-bottom: 1.5rem; - letter-spacing: -0.03em; -} - -.hero-subtitle { - font-size: 1.15rem; - color: var(--text-secondary); - line-height: 1.8; - margin-bottom: 2.5rem; - margin-left: auto; - margin-right: auto; -} - -.hero-subtitle span { - color: var(--text-body); -} - -.install-block { - display: inline-flex; - align-items: center; - gap: 0.75rem; - background: var(--term-bg); - border: 1px solid var(--term-border); - border-radius: 6px; - padding: 0.75rem 1.25rem; - margin-bottom: 3rem; - position: relative; -} - -.install-block code { - font-family: 'JetBrains Mono', monospace; - font-size: 0.95rem; - color: var(--text-primary); -} - -.install-block .prompt { - color: var(--term-prompt); +.nav-links a:hover { + color: var(--ink); } -.copy-btn { +.nav-toggle { + display: none; background: none; border: none; cursor: pointer; padding: 4px; - color: var(--text-muted); - transition: color 200ms ease; - display: flex; - align-items: center; + width: 24px; + height: 24px; + flex-direction: column; + justify-content: center; + gap: 4px; } -.copy-btn:hover { - color: var(--accent); +.nav-toggle span { + display: block; + width: 18px; + height: 1.5px; + background: var(--ink-faint); + transition: transform 200ms ease, opacity 200ms ease; } -.copy-btn:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - border-radius: 2px; -} +.nav-toggle.open span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); } +.nav-toggle.open span:nth-child(2) { opacity: 0; } +.nav-toggle.open span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); } -.copy-btn.copied { - color: var(--accent); +.mobile-menu { + display: none; + position: fixed; + top: 48px; + left: 0; + right: 0; + background: var(--bg); + border-bottom: 1px solid var(--ink-ghost); + padding: 1.5rem; + z-index: 99; + flex-direction: column; + gap: 1rem; } -.hero-links { - display: flex; - justify-content: center; - gap: 1.5rem; - margin-top: 2rem; -} +.mobile-menu.open { display: flex; } -.hero-links a { - color: var(--text-secondary); - font-size: 0.9rem; +.mobile-menu a { + font-size: 0.95rem; + color: var(--ink-light); + text-decoration: none; } -/* Terminal window */ -.terminal { - background: var(--term-bg); - border: 1px solid var(--term-border); - border-radius: 6px; - padding: 1.5rem; - font-family: 'JetBrains Mono', monospace; - font-size: 0.85rem; - line-height: 1.5; - overflow-x: auto; - text-align: left; - box-shadow: 0 0 60px var(--accent-glow); - transition: border-color 200ms ease; - position: relative; +/* Typography */ +h1, h2, h3 { + font-family: 'Newsreader', Georgia, 'Times New Roman', serif; + font-weight: 400; + color: var(--ink); } -.terminal:hover { - border-color: var(--border-focus); +h1 { + font-size: 3rem; + line-height: 1.15; + letter-spacing: -0.02em; } -.terminal-title { - position: absolute; - top: 0; - left: 0; - padding: 0.4rem 1rem; - font-size: 0.75rem; - color: var(--text-muted); - border-bottom: 1px solid var(--term-border); - border-right: 1px solid var(--term-border); - border-radius: 6px 0 6px 0; +h2 { + font-size: 1.5rem; + line-height: 1.3; + letter-spacing: -0.01em; } -.terminal .prompt { - color: var(--term-prompt); - user-select: none; +h3 { + font-size: 1.1rem; + line-height: 1.4; } -.terminal .command { - color: var(--text-primary); -} +p { max-width: 52ch; } -.terminal .output { - color: var(--term-output); - white-space: pre; +a { + color: var(--ink); + text-decoration: none; + transition: color 200ms ease; } -.terminal .comment { - color: var(--term-comment); +a:hover { color: var(--clay); } + +a:focus-visible { + outline: 2px solid var(--clay); + outline-offset: 2px; + border-radius: 2px; } -.terminal .cursor { - display: inline-block; - width: 0.55em; - height: 1.1em; - background: var(--term-cursor); - vertical-align: text-bottom; - animation: blink 1s step-end infinite; +code { + font-family: 'IBM Plex Mono', Menlo, monospace; + font-size: 0.85em; + color: var(--clay); } -@keyframes blink { - 50% { opacity: 0; } +/* Sections */ +.section { + padding: 8rem 0 6rem; } -.hero .terminal { - max-width: 700px; - margin: 0 auto; - min-height: 260px; +.section-label { + font-family: 'Inter', sans-serif; + font-size: 0.65rem; + font-weight: 500; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--ink-ghost); + margin-bottom: 3rem; } -/* How it works */ -.steps-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1.5rem; +.section-text { + color: var(--ink-light); margin-bottom: 1.5rem; } -.step-full { - grid-column: 1 / -1; +/* Hero */ +.hero { + padding: 10rem 0 6rem; } -.step-label { - font-family: 'JetBrains Mono', monospace; - font-size: 0.8rem; - color: var(--accent); - margin-bottom: 0.75rem; - font-weight: 600; +.hero h1 { + margin-bottom: 1.5rem; } -/* Why Brain cards */ -.cards-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 1.5rem; +.hero-sub { + color: var(--ink-light); + font-size: 0.95rem; margin-bottom: 2.5rem; + max-width: 48ch; } -.card { - border: 1px solid var(--border); +.install-line { + display: inline-flex; + align-items: center; + gap: 0.75rem; + border: 1px solid var(--ink-ghost); border-radius: 4px; - padding: 1.5rem; - transition: border-color 200ms ease; -} - -.card:hover { - border-color: var(--accent); + padding: 0.4rem 1rem; } -.card h3 { - color: var(--accent); - font-family: 'JetBrains Mono', monospace; - font-size: 1rem; - font-weight: 600; - margin-bottom: 0.75rem; +.install-line code { + font-family: 'IBM Plex Mono', monospace; + font-size: 0.8rem; + color: var(--ink); + background: none; } -.card p { - font-size: 0.93rem; - color: var(--text-body); - line-height: 1.6; - margin-left: 0; - margin-right: 0; +.install-line .prompt { + color: var(--clay); } -.section-also { - text-align: center; - font-family: 'JetBrains Mono', monospace; - font-size: 0.85rem; - color: var(--text-muted); - margin: 0 auto 2rem; +.copy-btn { + background: none; + border: none; + cursor: pointer; + padding: 2px; + color: var(--ink-ghost); + transition: color 200ms ease; + display: flex; + align-items: center; } -.section-punch { - text-align: center; - color: var(--text-secondary); - font-size: 1rem; - margin-left: auto; - margin-right: auto; -} +.copy-btn:hover { color: var(--clay); } +.copy-btn:focus-visible { outline: 2px solid var(--clay); outline-offset: 2px; } +.copy-btn.copied { color: var(--clay); } -.section-punch strong { - color: var(--text-primary); +/* Code blocks */ +.code-block { + background: var(--bg-code); + color: var(--code-fg); + border: 1px solid var(--code-border); + border-radius: 6px; + padding: 1.25rem 1.5rem; + font-family: 'IBM Plex Mono', Menlo, monospace; + font-size: 0.8rem; + line-height: 1.65; + overflow-x: auto; + white-space: pre; + position: relative; + margin-bottom: 1rem; } -.section-punch code { - font-family: 'JetBrains Mono', monospace; - color: var(--accent); - font-size: 0.9rem; +.code-block .prompt { + color: var(--code-prompt); + user-select: none; } -/* Agent integration */ -.agent-section .terminal { - max-width: 560px; - margin: 0 auto 2rem; -} +.code-block .cmd { color: var(--code-fg); } +.code-block .out { color: #a8a49c; white-space: pre; } +.code-block .comment { color: var(--code-comment); } -.agent-tools { - text-align: center; - font-family: 'JetBrains Mono', monospace; - font-size: 0.85rem; - color: var(--text-secondary); - margin-bottom: 1.5rem; - margin-left: auto; - margin-right: auto; +.file-label { + position: absolute; + top: 0; + left: 0; + padding: 0.3rem 0.75rem; + font-size: 0.65rem; + color: var(--code-comment); + border-bottom: 1px solid var(--code-border); + border-right: 1px solid var(--code-border); + border-radius: 6px 0 6px 0; } -.agent-desc { - text-align: center; - color: var(--text-body); - margin-bottom: 1.5rem; - max-width: 50ch; - margin-left: auto; - margin-right: auto; +/* Step numbers */ +.step-num { + font-family: 'Newsreader', Georgia, serif; + font-size: 2rem; + color: var(--clay); + line-height: 1; + margin-bottom: 1rem; + margin-top: 2rem; } -.agent-clients { - text-align: center; - font-family: 'JetBrains Mono', monospace; - font-size: 0.9rem; - color: var(--text-muted); - margin-left: auto; - margin-right: auto; +/* Features grid — no cards, naked text */ +.features-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2.5rem 3rem; + margin-bottom: 2.5rem; } -/* Quick start */ -.quick-start .terminal { - max-width: 700px; - margin: 0 auto; +.features-grid h3 { + margin-bottom: 0.5rem; + color: var(--ink); } -.quick-start .prereqs { - margin-top: 1rem; - font-size: 0.85rem; - color: var(--text-muted); - text-align: center; +.features-grid p { + font-size: 0.9rem; + color: var(--ink-light); + line-height: 1.65; } -/* Architecture */ -.arch-pre { - font-family: 'JetBrains Mono', monospace; - font-size: 0.8rem; - line-height: 1.4; - color: var(--text-primary); - max-width: 600px; - margin: 0 auto 2rem; - overflow-x: auto; +.also { + font-family: 'Inter', sans-serif; + font-size: 0.75rem; + color: var(--ink-ghost); } -.arch-pre .arch-accent { - color: var(--accent); +.also code { + font-size: 0.75rem; } -.arch-notes { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 1.5rem; - max-width: 700px; - margin: 0 auto; +/* Agent integration */ +.meta-line { + font-family: 'Inter', sans-serif; + font-size: 0.75rem; + color: var(--ink-ghost); + letter-spacing: 0.02em; } -.arch-note { - font-size: 0.85rem; - text-align: center; +/* Quick start */ +.prereqs { + margin-top: 0.5rem; + font-size: 0.8rem; + color: var(--ink-faint); } -.arch-note strong { - color: var(--text-primary); - font-family: 'JetBrains Mono', monospace; - font-weight: 600; - display: block; - margin-bottom: 0.25rem; - font-size: 0.8rem; +/* Architecture prose */ +.arch-prose { + color: var(--ink-light); + font-size: 0.95rem; + line-height: 1.8; + max-width: 52ch; } /* Footer */ .site-footer { - padding: 3rem 0; - text-align: center; - color: var(--text-muted); - font-size: 0.85rem; + padding: 4rem 0 3rem; +} + +.footer-meta { + font-size: 0.7rem; + color: var(--ink-ghost); + margin-bottom: 0.5rem; } .footer-links { - margin-top: 0.5rem; + display: flex; + gap: 1.5rem; } .footer-links a { - color: var(--text-muted); - margin: 0 0.5rem; + font-size: 0.7rem; + color: var(--ink-ghost); } +.footer-links a:hover { color: var(--clay); } + /* Scroll reveal */ .reveal { opacity: 0; - transform: translateY(20px); - transition: opacity 400ms ease-out, transform 400ms ease-out; + transform: translateY(16px); + transition: opacity 600ms cubic-bezier(0.23, 1, 0.32, 1), + transform 600ms cubic-bezier(0.23, 1, 0.32, 1); } .reveal.visible { @@ -497,54 +455,35 @@ a:focus-visible { transition: none; } - .terminal .cursor { - animation: none; - opacity: 1; - } + html { scroll-behavior: auto; } } /* Responsive */ @media (max-width: 768px) { - h1, .hero-wordmark { - font-size: 2.5rem; - } - - h2 { - font-size: 1.4rem; + .content-col, + .code-col { + margin-left: 0; + max-width: 100%; + padding: 0 1.5rem; } - section { - padding: 3.5rem 0; - } + .hero { padding: 6rem 0 4rem; } - .steps-grid { - grid-template-columns: 1fr; - } + h1 { font-size: 2.25rem; } - .cards-grid { - grid-template-columns: 1fr; - } + .section { padding: 5rem 0 3rem; } - .arch-notes { - grid-template-columns: 1fr; - } + .features-grid { grid-template-columns: 1fr; gap: 2rem; } - .arch-pre { - font-size: 0.7rem; - overflow-x: auto; - } + .code-block { font-size: 0.75rem; padding: 1rem 1.25rem; } - .terminal { - font-size: 0.78rem; - } + .nav-links { display: none; } + .nav-toggle { display: flex; } - .container { - padding: 0 1.25rem; - } + .step-num { font-size: 1.5rem; margin-top: 1.5rem; } } -@media (min-width: 769px) and (max-width: 1024px) { - .cards-grid { - grid-template-columns: 1fr 1fr; - } +@media (min-width: 769px) and (max-width: 1100px) { + .content-col { margin-left: 8%; } + .code-col { margin-left: 8%; } } diff --git a/website/terminal.js b/website/terminal.js deleted file mode 100644 index c008bca..0000000 --- a/website/terminal.js +++ /dev/null @@ -1,214 +0,0 @@ -(function () { - 'use strict'; - - var TYPING_SPEED = 35; - var PAUSE_BETWEEN = 800; - - var DEMO_SEQUENCE = [ - { - command: 'brain ingest https://github.com/acme/docs.git', - output: - '🔍 Scanning https://github.com/acme/docs.git...\n' + - ' Found 32 documentation files\n' + - '\n' + - '✅ Ingested 24 entries from acme/docs\n' + - ' ⚠ 8 skipped (duplicate slug)', - pauseAfter: 2500, - }, - { - command: 'brain search "kubernetes"', - output: - 'Found 3 results:\n' + - '┌────────────────────────┬────────┬───────┬───────────┐\n' + - '│ Title │ Author │ Type │ Tags │\n' + - '├────────────────────────┼────────┼───────┼───────────┤\n' + - '│ K8s Deployment Guide │ bob │ guide │ k8s │\n' + - '│ CI Pipeline │ carol │ guide │ ci, k8s │\n' + - '│ Helm Chart Patterns │ alice │ skill │ helm, k8s │\n' + - '└────────────────────────┴────────┴───────┴───────────┘', - pauseAfter: 2500, - }, - { - command: 'brain push ./guide.md', - output: - '✅ Pushed: Docker Multi-Stage Builds\n' + - ' Tags: docker (auto-detected)', - pauseAfter: 2000, - }, - { - command: 'brain trail kubernetes', - output: - 'K8s Deployment Guide\n' + - ' → Helm Chart Patterns (tags: k8s)\n' + - ' → CI Pipeline (tags: k8s, ci)', - pauseAfter: 2500, - }, - ]; - - var terminal = document.getElementById('hero-terminal'); - if (!terminal) return; - - var prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; - var isPaused = false; - var animationTimer = null; - - if (prefersReduced) { - showStaticDemos(); - return; - } - - terminal.addEventListener('mouseenter', function () { isPaused = true; }); - terminal.addEventListener('mouseleave', function () { isPaused = false; }); - - runSequence(); - - function showStaticDemos() { - var html = ''; - for (var i = 0; i < DEMO_SEQUENCE.length; i++) { - var step = DEMO_SEQUENCE[i]; - html += - '
$ ' + - escapeHtml(step.command) + - '
' + - escapeHtml(step.output) + - '
'; - if (i < DEMO_SEQUENCE.length - 1) html += '
 
'; - } - terminal.innerHTML = html; - } - - function runSequence() { - var stepIndex = 0; - - function nextStep() { - if (stepIndex >= DEMO_SEQUENCE.length) { - animationTimer = setTimeout(function () { - terminal.innerHTML = ''; - stepIndex = 0; - nextStep(); - }, 3000); - return; - } - - var step = DEMO_SEQUENCE[stepIndex]; - typeCommand(step.command, function () { - appendOutput(step.output); - stepIndex++; - animationTimer = setTimeout(function () { - waitForUnpause(nextStep); - }, step.pauseAfter); - }); - } - - nextStep(); - } - - function waitForUnpause(callback) { - if (!isPaused) { - callback(); - return; - } - var check = setInterval(function () { - if (!isPaused) { - clearInterval(check); - callback(); - } - }, 100); - } - - function typeCommand(text, callback) { - var lineEl = document.createElement('div'); - var promptSpan = document.createElement('span'); - promptSpan.className = 'prompt'; - promptSpan.textContent = '$ '; - lineEl.appendChild(promptSpan); - - var cmdSpan = document.createElement('span'); - cmdSpan.className = 'command'; - lineEl.appendChild(cmdSpan); - - var cursorSpan = document.createElement('span'); - cursorSpan.className = 'cursor'; - cursorSpan.innerHTML = ' '; - lineEl.appendChild(cursorSpan); - - terminal.appendChild(lineEl); - - var charIndex = 0; - - function typeNext() { - if (isPaused) { - animationTimer = setTimeout(typeNext, 100); - return; - } - if (charIndex < text.length) { - cmdSpan.textContent += text[charIndex]; - charIndex++; - animationTimer = setTimeout(typeNext, TYPING_SPEED); - } else { - cursorSpan.remove(); - animationTimer = setTimeout(callback, PAUSE_BETWEEN); - } - } - - typeNext(); - } - - function appendOutput(text) { - var outputEl = document.createElement('div'); - outputEl.className = 'output'; - outputEl.textContent = text; - outputEl.style.whiteSpace = 'pre'; - terminal.appendChild(outputEl); - - var spacer = document.createElement('div'); - spacer.innerHTML = ' '; - terminal.appendChild(spacer); - } - - function escapeHtml(str) { - return str - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/\n/g, '\n'); - } - - // Scroll reveal - var reveals = document.querySelectorAll('.reveal'); - if (reveals.length > 0 && !prefersReduced) { - var observer = new IntersectionObserver( - function (entries) { - entries.forEach(function (entry) { - if (entry.isIntersecting) { - entry.target.classList.add('visible'); - observer.unobserve(entry.target); - } - }); - }, - { threshold: 0.15 } - ); - reveals.forEach(function (el) { observer.observe(el); }); - } else { - reveals.forEach(function (el) { el.classList.add('visible'); }); - } - - // Copy button - var copyBtns = document.querySelectorAll('.copy-btn'); - copyBtns.forEach(function (btn) { - btn.addEventListener('click', function () { - var text = btn.getAttribute('data-copy'); - if (!text) return; - navigator.clipboard.writeText(text).then(function () { - btn.classList.add('copied'); - btn.innerHTML = - ''; - setTimeout(function () { - btn.classList.remove('copied'); - btn.innerHTML = - ''; - }, 2000); - }); - }); - }); -})(); From badc89dc400b0fa650308d34ea2ba6e7a9f027ef Mon Sep 17 00:00:00 2001 From: vraspar Date: Sat, 28 Mar 2026 17:12:40 -0700 Subject: [PATCH 2/7] fix(website): soften Zine design, remove dashes, warm code blocks - Remove all em dashes from prose (use commas, periods instead) - Warm up code blocks: #1d1d1d -> #2d2a26 (warm dark brown) - Mute clay accent: #a0785a -> #8f7561 (less orange, more earth) - Soften ink: #2b2b28 -> #3a3835 (reduced contrast with parchment) - Replace ASCII table with clean spaced text output - Rewrite hero subtitle and feature copy to sound more human - Reduce grain opacity slightly (0.035 -> 0.03) - Warmer code output text and prompts throughout Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- website/index.html | 29 +++++++++++++---------------- website/style.css | 24 ++++++++++++------------ 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/website/index.html b/website/index.html index 128ca88..db41de6 100644 --- a/website/index.html +++ b/website/index.html @@ -3,14 +3,14 @@ - brain — CLI-first knowledge sharing for dev teams + brain. knowledge sharing for dev teams - + - + @@ -47,7 +47,7 @@

Share what
your team knows.

-

A command-line tool for publishing and discovering technical knowledge. Markdown in git, searchable via SQLite FTS5, exposed to AI agents through MCP.

+

Your team writes things down. Brain makes those notes findable. It stores markdown in git, indexes it with SQLite FTS5, and lets AI agents access it through MCP.

$ npm install -g @vraspar/brain@alpha
@@ -114,19 +111,19 @@

Share what
your team knows.

Git as storage

-

Entries are markdown in a git repo. No server. No infrastructure. Version history and access control are free.

+

Entries are markdown files in a git repo. No server, no database. You get version history and access control for free.

FTS5 search

-

SQLite full-text search with BM25 ranking. Sub-millisecond. Works offline. The index is a disposable cache, rebuilt from source on every sync.

+

SQLite full-text search with BM25 ranking. Fast enough that you won't notice it. Works offline. Rebuilt from source on every sync.

MCP for agents

-

10 tools, 2 resources via Model Context Protocol. Your AI agent reads your team’s knowledge base natively. brain serve starts the server.

+

10 tools and 2 resources over Model Context Protocol. Your AI agent can read what your team has written. brain serve starts it.

Knowledge trails

-

Auto-linked entries via tag overlap and content similarity. brain trail <topic> walks the knowledge graph.

+

Entries link to each other through tags and content overlap. brain trail <topic> walks the connections.

@@ -184,7 +181,7 @@

Knowledge trails

-

Brain stores entries as markdown files with YAML frontmatter in a git repository. The search index is an SQLite FTS5 virtual table, rebuilt from the markdown files on every sync. Read receipts are JSON files committed alongside entries — analytics with zero infrastructure.

+

Brain stores entries as markdown files with YAML frontmatter in a git repository. The search index is a local SQLite FTS5 table, rebuilt from the markdown on every sync. Read receipts are JSON files committed alongside entries. Analytics with zero infrastructure.

diff --git a/website/style.css b/website/style.css index 46cf943..82021f6 100644 --- a/website/style.css +++ b/website/style.css @@ -1,18 +1,18 @@ :root { --bg: #f3efe9; --bg-alt: #ede8e1; - --bg-code: #1d1d1d; - --ink: #2b2b28; - --ink-light: #5c5955; + --bg-code: #2d2a26; + --ink: #3a3835; + --ink-light: #635f5a; --ink-faint: #8a8580; --ink-ghost: #b5b0aa; - --clay: #a0785a; - --clay-light: #c49a78; - --code-fg: #d4d0c8; - --code-prompt: #b8a88a; - --code-comment: #6b6660; - --code-border: #2a2a27; - --grain-opacity: 0.035; + --clay: #8f7561; + --clay-light: #a8917b; + --code-fg: #ccc8c0; + --code-prompt: #a89880; + --code-comment: #736d66; + --code-border: #3a3733; + --grain-opacity: 0.03; } *, @@ -317,7 +317,7 @@ code { background: var(--bg-code); color: var(--code-fg); border: 1px solid var(--code-border); - border-radius: 6px; + border-radius: 8px; padding: 1.25rem 1.5rem; font-family: 'IBM Plex Mono', Menlo, monospace; font-size: 0.8rem; @@ -334,7 +334,7 @@ code { } .code-block .cmd { color: var(--code-fg); } -.code-block .out { color: #a8a49c; white-space: pre; } +.code-block .out { color: #9e9a92; white-space: pre; } .code-block .comment { color: var(--code-comment); } .file-label { From b29d77fec2efe1c32e734dd2e42dd9136c28a2ab Mon Sep 17 00:00:00 2001 From: vraspar Date: Sat, 28 Mar 2026 17:15:09 -0700 Subject: [PATCH 3/7] fix(website): point blog links to GitHub docs/blog All three blog links (nav, mobile menu, footer) now point to https://github.com/vraspar/brain/tree/main/docs/blog instead of the broken /blog/ path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- website/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/index.html b/website/index.html index db41de6..5110d07 100644 --- a/website/index.html +++ b/website/index.html @@ -26,7 +26,7 @@ brain