Skip to content

Commit b35b31a

Browse files
committed
feat: initial site — Sovereign Terminal aesthetic, WebGL hero
Static showcase site for MALD. Branch `site` is an orphan, isolated from `main` (no Rust source). Deploys to GitHub Pages on every push via .github/workflows/site.yml. Stack: HTML + JSX-via-Babel-standalone + WebGL shader. No build step, no node_modules, no bundler. Works on Pages out of the box once Pages is set to "GitHub Actions" source. Sections (top-to-bottom, matching the design mockup): - Sticky header with blurred bg on scroll - Hero: WebGL shader bg, tagline pills, h1, sub-line, install + GitHub CTAs, scoop install copy pill, scroll hint - // what it is — three cards (Local files / Local AI / Sovereign defaults) - // three surfaces — pill tabs (GUI/TUI/CLI), faux-window panel layout - // features — 3×2 grid (HNSW · wikilinks · graph · RAG · multi-space · daemon) - // architecture — SVG line diagram (CLI ↔ Daemon ↔ HNSW ↔ Ollama, Markdown files → Daemon) - // install — Windows / macOS / Linux tabs with code blocks - Footer: wordmark, MIT licensed · v0.5.7, link column Design tokens (Sovereign Terminal OS): - bg: #0B0D0E base, #111416 panel, #171A1D panel-alt, #1F2326 surface - text: #E8E2D4, muted #B8B5AC, dim #8B918A - sage accent #8FAF8F, warm gold #BFA76A - mono everywhere (JetBrains Mono via Google Fonts) - 4px spacing grid, 4/8/12 radii max, 1px borders Performance: - Shader capped 30fps via requestAnimationFrame throttle - Pauses when tab hidden (Page Visibility API) - Disables animation entirely under prefers-reduced-motion - Section reveals via IntersectionObserver, 300ms ease-out Accessibility: - Semantic HTML, sage focus rings, keyboard-reachable interactive elements - ARIA labels on the copy buttons - Reduced-motion respect throughout Tweaks panel (tweaks-panel.jsx) is included for live design iteration — toggleable from a corner trigger, lets us tune accent / shader intensity / copy without redeploying.
0 parents  commit b35b31a

10 files changed

Lines changed: 1976 additions & 0 deletions

File tree

‎.github/workflows/site.yml‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Site
2+
3+
on:
4+
push:
5+
branches: [site]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: pages
15+
cancel-in-progress: true
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v5
22+
- name: Stage site
23+
run: |
24+
mkdir -p _site
25+
rsync -av \
26+
--exclude='.git' \
27+
--exclude='.github' \
28+
--exclude='_site' \
29+
--exclude='.tmp_site' \
30+
./ _site/
31+
- uses: actions/upload-pages-artifact@v3
32+
with:
33+
path: _site
34+
35+
deploy:
36+
needs: build
37+
runs-on: ubuntu-latest
38+
environment:
39+
name: github-pages
40+
url: ${{ steps.deployment.outputs.page_url }}
41+
steps:
42+
- id: deployment
43+
uses: actions/deploy-pages@v4

‎.nojekyll‎

Whitespace-only changes.

‎README.md‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# MALD product site
2+
3+
Static showcase site for [MALD](https://github.com/NAME0x0/MALD).
4+
5+
- **Branch:** `site` (orphan, isolated from `main` — no Rust source on this branch)
6+
- **Stack:** plain HTML + JSX-via-Babel-standalone + custom WebGL shader. No build step.
7+
- **Deploy:** GitHub Pages via `.github/workflows/site.yml` on every push to `site`.
8+
- **URL:** https://NAME0x0.github.io/MALD/
9+
10+
## Local preview
11+
12+
Open `index.html` in any modern browser, or serve the directory:
13+
14+
```bash
15+
python -m http.server 8000
16+
# then visit http://localhost:8000
17+
```
18+
19+
## Files
20+
21+
- `index.html` — entry, sets up CSS tokens, loads scripts via CDN
22+
- `app.jsx` — root React app, composes sections, owns tweak state
23+
- `sections.jsx` — Header / Hero / WhatItIs / ThreeSurfaces / Features / Architecture / Install / Footer
24+
- `shader.jsx` — WebGL hero background (sage scanlines + grain + vignette + drifting glow)
25+
- `icons.jsx` — geometric sage glyphs
26+
- `tweaks-panel.jsx` — live token tweaker (visible on the deployed site for design iteration)
27+
- `favicon.svg` — copied from the main repo
28+
- `.nojekyll` — disables Jekyll processing on GitHub Pages

‎app.jsx‎

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// MALD site — root app
2+
const { useState, useEffect } = React;
3+
4+
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
5+
"accent": "#8FAF8F",
6+
"shaderIntensity": 1.0,
7+
"headline": "Terminal-first personal knowledge OS.",
8+
"subline": "Plain markdown on disk. Local AI. No telemetry, no cloud, no compromise.",
9+
"version": "v0.5.7"
10+
}/*EDITMODE-END*/;
11+
12+
function App() {
13+
const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
14+
15+
// Inject styles for blink + nav hover
16+
useEffect(() => {
17+
const s = document.createElement('style');
18+
s.textContent = `
19+
.cli-blink::after { content: '▌'; animation: blink 1s steps(1) infinite; color: ${tweaks.accent}; }
20+
@keyframes blink { 50% { opacity: 0; } }
21+
.nav-link { transition: color 150ms ease-out; }
22+
.nav-link:hover { color: var(--text); }
23+
`;
24+
document.head.appendChild(s);
25+
return () => s.remove();
26+
}, [tweaks.accent]);
27+
28+
return (
29+
<div>
30+
<Header accent={tweaks.accent} />
31+
<Hero
32+
accent={tweaks.accent}
33+
shaderIntensity={tweaks.shaderIntensity}
34+
headline={tweaks.headline}
35+
subline={tweaks.subline}
36+
/>
37+
<WhatItIs accent={tweaks.accent} />
38+
<ThreeSurfaces accent={tweaks.accent} />
39+
<Features accent={tweaks.accent} />
40+
<Architecture accent={tweaks.accent} />
41+
<Install accent={tweaks.accent} />
42+
<Footer accent={tweaks.accent} version={tweaks.version} />
43+
44+
<TweaksPanel title="Tweaks">
45+
<TweakSection title="Brand">
46+
<TweakColor label="Accent (sage)" value={tweaks.accent} onChange={(v) => setTweak('accent', v)} />
47+
<TweakRadio
48+
label="Accent preset"
49+
value={tweaks.accent}
50+
onChange={(v) => setTweak('accent', v)}
51+
options={[
52+
{ label: 'Sage', value: '#8FAF8F' },
53+
{ label: 'Amber', value: '#BFA76A' },
54+
{ label: 'Cyan', value: '#7AB0B0' },
55+
{ label: 'Rust', value: '#C67878' },
56+
]}
57+
/>
58+
</TweakSection>
59+
<TweakSection title="Hero">
60+
<TweakSlider
61+
label="Shader intensity"
62+
min={0} max={2} step={0.05}
63+
value={tweaks.shaderIntensity}
64+
onChange={(v) => setTweak('shaderIntensity', v)}
65+
/>
66+
<TweakText
67+
label="Headline"
68+
value={tweaks.headline}
69+
onChange={(v) => setTweak('headline', v)}
70+
/>
71+
<TweakText
72+
label="Sub-line"
73+
value={tweaks.subline}
74+
onChange={(v) => setTweak('subline', v)}
75+
/>
76+
</TweakSection>
77+
<TweakSection title="Meta">
78+
<TweakText
79+
label="Version"
80+
value={tweaks.version}
81+
onChange={(v) => setTweak('version', v)}
82+
/>
83+
</TweakSection>
84+
</TweaksPanel>
85+
</div>
86+
);
87+
}
88+
89+
ReactDOM.createRoot(document.getElementById('root')).render(<App />);

‎favicon.svg‎

Lines changed: 8 additions & 0 deletions
Loading

‎icons.jsx‎

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Simple inline SVG icons matching Lucide style — geometric, 1.5px stroke
2+
const Icon = ({ children, size = 12, color = 'currentColor', strokeWidth = 1.5, ...rest }) => (
3+
<svg
4+
width={size}
5+
height={size}
6+
viewBox="0 0 24 24"
7+
fill="none"
8+
stroke={color}
9+
strokeWidth={strokeWidth}
10+
strokeLinecap="round"
11+
strokeLinejoin="round"
12+
style={{ display: 'block', flexShrink: 0 }}
13+
{...rest}
14+
>
15+
{children}
16+
</svg>
17+
);
18+
19+
const IconFileText = (p) => (
20+
<Icon {...p}>
21+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
22+
<polyline points="14 2 14 8 20 8" />
23+
<line x1="8" y1="13" x2="16" y2="13" />
24+
<line x1="8" y1="17" x2="16" y2="17" />
25+
</Icon>
26+
);
27+
const IconSparkles = (p) => (
28+
<Icon {...p}>
29+
<path d="M12 3l1.7 4.6L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.4z" />
30+
<path d="M19 15l.8 2.2L22 18l-2.2.8L19 21l-.8-2.2L16 18l2.2-.8z" />
31+
</Icon>
32+
);
33+
const IconShield = (p) => (
34+
<Icon {...p}>
35+
<path d="M12 2l8 3v6c0 5-3.5 9-8 11-4.5-2-8-6-8-11V5z" />
36+
</Icon>
37+
);
38+
const IconZap = (p) => (
39+
<Icon {...p}>
40+
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
41+
</Icon>
42+
);
43+
const IconLink = (p) => (
44+
<Icon {...p}>
45+
<path d="M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1" />
46+
<path d="M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1" />
47+
</Icon>
48+
);
49+
const IconGitBranch = (p) => (
50+
<Icon {...p}>
51+
<line x1="6" y1="3" x2="6" y2="15" />
52+
<circle cx="18" cy="6" r="3" />
53+
<circle cx="6" cy="18" r="3" />
54+
<path d="M18 9a9 9 0 0 1-9 9" />
55+
</Icon>
56+
);
57+
const IconQuote = (p) => (
58+
<Icon {...p}>
59+
<path d="M21 15a2 2 0 0 1-2 2h-7l-4 4v-4H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h15a2 2 0 0 1 2 2z" />
60+
<path d="M8 9v2" />
61+
<path d="M14 9v2" />
62+
</Icon>
63+
);
64+
const IconLayers = (p) => (
65+
<Icon {...p}>
66+
<polygon points="12 2 2 7 12 12 22 7 12 2" />
67+
<polyline points="2 17 12 22 22 17" />
68+
<polyline points="2 12 12 17 22 12" />
69+
</Icon>
70+
);
71+
const IconActivity = (p) => (
72+
<Icon {...p}>
73+
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />
74+
</Icon>
75+
);
76+
const IconCopy = (p) => (
77+
<Icon {...p}>
78+
<rect x="9" y="9" width="13" height="13" rx="2" />
79+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
80+
</Icon>
81+
);
82+
const IconCheck = (p) => (
83+
<Icon {...p}>
84+
<polyline points="20 6 9 17 4 12" />
85+
</Icon>
86+
);
87+
const IconArrowDown = (p) => (
88+
<Icon {...p}>
89+
<line x1="12" y1="5" x2="12" y2="19" />
90+
<polyline points="19 12 12 19 5 12" />
91+
</Icon>
92+
);
93+
const IconDiamond = (p) => (
94+
<Icon {...p}>
95+
<path d="M12 2 L22 12 L12 22 L2 12 Z" />
96+
</Icon>
97+
);
98+
99+
Object.assign(window, {
100+
Icon, IconFileText, IconSparkles, IconShield, IconZap, IconLink,
101+
IconGitBranch, IconQuote, IconLayers, IconActivity, IconCopy, IconCheck,
102+
IconArrowDown, IconDiamond,
103+
});

‎index.html‎

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>MALD — Terminal-first personal knowledge OS</title>
7+
<meta name="description" content="Terminal-first personal knowledge OS. Plain markdown on disk. Local AI. No telemetry, no cloud, no compromise." />
8+
<meta property="og:title" content="MALD — Terminal-first personal knowledge OS" />
9+
<meta property="og:description" content="Plain markdown on disk. Local AI. No telemetry, no cloud, no compromise." />
10+
<meta property="og:type" content="website" />
11+
<meta property="og:url" content="https://NAME0x0.github.io/MALD/" />
12+
<meta name="twitter:card" content="summary" />
13+
<meta name="theme-color" content="#0B0D0E" />
14+
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
15+
<link rel="preconnect" href="https://fonts.googleapis.com" />
16+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
17+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
18+
<style>
19+
:root {
20+
--bg-base: #0B0D0E;
21+
--bg-panel: #111416;
22+
--bg-panel-alt: #171A1D;
23+
--bg-surface: #1F2326;
24+
--text: #E8E2D4;
25+
--text-muted: #B8B5AC;
26+
--text-dim: #8B918A;
27+
--accent: #8FAF8F;
28+
--accent-warm: #BFA76A;
29+
--warn: #D19A66;
30+
--error: #C67878;
31+
--border: #1F2326;
32+
--border-strong: #2A2F33;
33+
--mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
34+
}
35+
* { box-sizing: border-box; }
36+
html, body {
37+
margin: 0;
38+
padding: 0;
39+
background: var(--bg-base);
40+
color: var(--text);
41+
font-family: var(--mono);
42+
font-feature-settings: "calt" 0;
43+
-webkit-font-smoothing: antialiased;
44+
-moz-osx-font-smoothing: grayscale;
45+
}
46+
body { overflow-x: hidden; }
47+
::selection { background: rgba(143, 175, 143, 0.3); color: var(--text); }
48+
a { color: inherit; text-decoration: none; }
49+
button { font-family: inherit; cursor: pointer; }
50+
:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
51+
52+
/* Reveal */
53+
.reveal { opacity: 0; transform: translateY(8px); transition: opacity 300ms ease-out, transform 300ms ease-out; }
54+
.reveal.in { opacity: 1; transform: translateY(0); }
55+
56+
/* Scroll bg blur */
57+
.header-blur {
58+
backdrop-filter: blur(8px) saturate(120%);
59+
-webkit-backdrop-filter: blur(8px) saturate(120%);
60+
background: rgba(11, 13, 14, 0.72);
61+
border-bottom: 1px solid var(--border);
62+
}
63+
64+
@media (prefers-reduced-motion: reduce) {
65+
.reveal { transition: none; opacity: 1; transform: none; }
66+
}
67+
</style>
68+
</head>
69+
<body>
70+
<div id="root"></div>
71+
72+
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
73+
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
74+
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
75+
76+
<script type="text/babel" src="tweaks-panel.jsx"></script>
77+
<script type="text/babel" src="icons.jsx"></script>
78+
<script type="text/babel" src="shader.jsx"></script>
79+
<script type="text/babel" src="sections.jsx"></script>
80+
<script type="text/babel" src="app.jsx"></script>
81+
</body>
82+
</html>

0 commit comments

Comments
 (0)