Initial release: diagram-design v1.0

Thirteen editorial diagram types (architecture, flowchart, sequence,
state, ER, timeline, swimlane, quadrant, nested, tree, layers, venn,
pyramid) as self-contained HTML files with inline SVG.

Progressive disclosure: lean SKILL.md points to per-type references.
Neutral stone+rust default skin, first-run gate that prompts users
to customize the style guide from their own website, URL-based
onboarding, annotation-callout primitive, sketchy filter variant,
live gallery at assets/index.html.
This commit is contained in:
Cathryn Lavery
2026-04-16 13:30:53 -05:00
commit 53bd8dde0f
75 changed files with 8186 additions and 0 deletions
+162
View File
@@ -0,0 +1,162 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight.com · Architecture</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Architecture · Diagram Design</p>
<h1>littlemight.com in production</h1>
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#a8a69d"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#ff6a30"/></marker>
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#5ba8eb"/></marker>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Arrows first (behind boxes) -->
<line x1="168" y1="272" x2="220" y2="272" stroke="#5ba8eb" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<line x1="364" y1="272" x2="416" y2="272" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<line x1="576" y1="256" x2="628" y2="212" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="576" y1="288" x2="628" y2="332" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrow labels -->
<rect x="172" y="252" width="48" height="12" rx="2" fill="#1c1a17"/>
<text x="196" y="262" fill="#5ba8eb" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">HTTPS</text>
<rect x="368" y="252" width="48" height="12" rx="2" fill="#1c1a17"/>
<text x="392" y="262" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">SSR</text>
<rect x="560" y="212" width="56" height="12" rx="2" fill="#1c1a17"/>
<text x="588" y="222" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">READ MDX</text>
<rect x="560" y="320" width="52" height="12" rx="2" fill="#1c1a17"/>
<text x="586" y="330" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">QUERY</text>
<!-- Node: Reader -->
<rect x="40" y="240" width="128" height="64" rx="6" fill="#1c1a17"/>
<rect x="40" y="240" width="128" height="64" rx="6" fill="rgba(168,166,157,0.10)" stroke="#8e8c83" stroke-width="1"/>
<rect x="48" y="248" width="28" height="12" rx="2" fill="transparent" stroke="rgba(142,140,131,0.40)" stroke-width="0.8"/>
<text x="62" y="257" fill="#8e8c83" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
<text x="104" y="276" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reader</text>
<text x="104" y="292" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser</text>
<!-- Node: Cloudflare -->
<rect x="220" y="240" width="144" height="64" rx="6" fill="#1c1a17"/>
<rect x="220" y="240" width="144" height="64" rx="6" fill="rgba(241,239,231,0.03)" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<rect x="228" y="248" width="32" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.22)" stroke-width="0.8"/>
<text x="244" y="257" fill="#8e8c83" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EDGE</text>
<text x="356" y="300" fill="rgba(241,239,231,0.06)" font-size="32" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">01</text>
<text x="292" y="276" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Cloudflare</text>
<text x="292" y="292" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Pages · cache</text>
<!-- Node: Astro (focal coral) -->
<rect x="416" y="240" width="160" height="64" rx="6" fill="#1c1a17"/>
<rect x="416" y="240" width="160" height="64" rx="6" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<rect x="424" y="248" width="32" height="12" rx="2" fill="transparent" stroke="rgba(255,106,48,0.50)" stroke-width="0.8"/>
<text x="440" y="257" fill="#ff6a30" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ORIG</text>
<text x="568" y="300" fill="rgba(255,106,48,0.10)" font-size="32" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">02</text>
<text x="496" y="276" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Astro Origin</text>
<text x="496" y="292" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">SSR + MDX</text>
<!-- Node: MDX Bundle -->
<rect x="628" y="160" width="144" height="64" rx="6" fill="#1c1a17"/>
<rect x="628" y="160" width="144" height="64" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<rect x="636" y="168" width="32" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.40)" stroke-width="0.8"/>
<text x="652" y="177" fill="#f1efe7" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">BUN</text>
<text x="700" y="196" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">MDX Bundle</text>
<text x="700" y="212" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">src/content/*.mdx</text>
<!-- Node: Content CMS -->
<rect x="628" y="320" width="144" height="64" rx="6" fill="#1c1a17"/>
<rect x="628" y="320" width="144" height="64" rx="6" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="1"/>
<rect x="636" y="328" width="28" height="12" rx="2" fill="transparent" stroke="rgba(168,166,157,0.50)" stroke-width="0.8"/>
<text x="650" y="337" fill="#a8a69d" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CMS</text>
<text x="700" y="356" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Content CMS</text>
<text x="700" y="372" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">assets · og images</text>
<!-- Legend strip -->
<line x1="40" y1="404" x2="960" y2="404" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="420" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="436" width="14" height="10" rx="2" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<text x="60" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Focal / origin</text>
<rect x="180" y="436" width="14" height="10" rx="2" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="200" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Backend / bundle</text>
<rect x="340" y="436" width="14" height="10" rx="2" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="1"/>
<text x="360" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Store</text>
<rect x="436" y="436" width="14" height="10" rx="2" fill="rgba(241,239,231,0.03)" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<text x="456" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Cloud</text>
<rect x="528" y="436" width="14" height="10" rx="2" fill="rgba(168,166,157,0.10)" stroke="#8e8c83" stroke-width="1"/>
<text x="548" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">External</text>
<line x1="636" y1="442" x2="664" y2="442" stroke="#5ba8eb" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="672" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">HTTP request</text>
<line x1="784" y1="442" x2="812" y2="442" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="820" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Primary flow</text>
</svg>
</div>
</body>
</html>
+174
View File
@@ -0,0 +1,174 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight.com · Architecture</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed; --color-paper-2: #efeee5;
--color-ink: #0b0d0b; --color-muted: #52534e; --color-soft: #65655c;
--color-rule: rgba(11,13,11,0.12);
--color-accent: #f7591f; --color-accent-tint: rgba(247,89,31,0.08);
--color-link: #1a70c7;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; letter-spacing: -0.005em; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Architecture · Diagram Design</p>
<h1>littlemight.com in production</h1>
<p class="subtitle">The static-first stack: Cloudflare's edge absorbs most reads, Astro renders MDX on misses, content is checked into the repo.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#1a70c7"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Arrows first (behind boxes) -->
<line x1="168" y1="272" x2="220" y2="272" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<line x1="364" y1="272" x2="416" y2="272" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<line x1="576" y1="256" x2="628" y2="212" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="576" y1="288" x2="628" y2="332" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrow labels -->
<rect x="172" y="252" width="48" height="12" rx="2" fill="#f5f4ed"/>
<text x="196" y="262" fill="#1a70c7" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">HTTPS</text>
<rect x="368" y="252" width="48" height="12" rx="2" fill="#f5f4ed"/>
<text x="392" y="262" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">SSR</text>
<rect x="560" y="212" width="56" height="12" rx="2" fill="#f5f4ed"/>
<text x="588" y="222" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">READ MDX</text>
<rect x="560" y="320" width="52" height="12" rx="2" fill="#f5f4ed"/>
<text x="586" y="330" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">QUERY</text>
<!-- Node: Reader -->
<rect x="40" y="240" width="128" height="64" rx="6" fill="#f5f4ed"/>
<rect x="40" y="240" width="128" height="64" rx="6" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<rect x="48" y="248" width="28" height="12" rx="2" fill="transparent" stroke="rgba(101,101,92,0.40)" stroke-width="0.8"/>
<text x="62" y="257" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
<text x="104" y="276" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reader</text>
<text x="104" y="292" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser</text>
<!-- Node: Cloudflare -->
<rect x="220" y="240" width="144" height="64" rx="6" fill="#f5f4ed"/>
<rect x="220" y="240" width="144" height="64" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<rect x="228" y="248" width="32" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="244" y="257" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EDGE</text>
<text x="356" y="300" fill="rgba(11,13,11,0.06)" font-size="32" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">01</text>
<text x="292" y="276" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Cloudflare</text>
<text x="292" y="292" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Pages · cache</text>
<!-- Node: Astro (focal coral) -->
<rect x="416" y="240" width="160" height="64" rx="6" fill="#f5f4ed"/>
<rect x="416" y="240" width="160" height="64" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="424" y="248" width="32" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="440" y="257" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ORIG</text>
<text x="568" y="300" fill="rgba(247,89,31,0.10)" font-size="32" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">02</text>
<text x="496" y="276" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Astro Origin</text>
<text x="496" y="292" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">SSR + MDX</text>
<!-- Node: MDX Bundle -->
<rect x="628" y="160" width="144" height="64" rx="6" fill="#f5f4ed"/>
<rect x="628" y="160" width="144" height="64" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="636" y="168" width="32" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="652" y="177" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">BUN</text>
<text x="700" y="196" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">MDX Bundle</text>
<text x="700" y="212" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">src/content/*.mdx</text>
<!-- Node: Content CMS -->
<rect x="628" y="320" width="144" height="64" rx="6" fill="#f5f4ed"/>
<rect x="628" y="320" width="144" height="64" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<rect x="636" y="328" width="28" height="12" rx="2" fill="transparent" stroke="rgba(82,83,78,0.50)" stroke-width="0.8"/>
<text x="650" y="337" fill="#52534e" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CMS</text>
<text x="700" y="356" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Content CMS</text>
<text x="700" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">assets · og images</text>
<!-- Legend strip -->
<line x1="40" y1="404" x2="960" y2="404" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="420" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="436" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="60" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Focal / origin</text>
<rect x="180" y="436" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="200" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Backend / bundle</text>
<rect x="340" y="436" width="14" height="10" rx="2" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<text x="360" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Store</text>
<rect x="436" y="436" width="14" height="10" rx="2" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="456" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Cloud</text>
<rect x="528" y="436" width="14" height="10" rx="2" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<text x="548" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">External</text>
<line x1="636" y1="442" x2="664" y2="442" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="672" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">HTTP request</text>
<line x1="784" y1="442" x2="812" y2="442" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="820" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Primary flow</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>Edge absorbs the reads</h3></div>
<p>Nearly every reader is served by Cloudflare's edge cache. The Astro origin only wakes on a cold slug or a revalidation.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Content lives in the repo</h3></div>
<ul><li>Posts are MDX files</li><li>Checked in, reviewed in PRs</li><li>No runtime database</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>CMS holds the big stuff</h3></div>
<p>Images, OG art, and downloadable assets live in a separate bucket keyed by slug. Astro links them at render time.</p>
</div>
</div>
<div class="footer">
<span>littlemight.com · architecture</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+162
View File
@@ -0,0 +1,162 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight.com · Architecture</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Architecture · Diagram Design</p>
<h1>littlemight.com in production</h1>
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#1a70c7"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Arrows first (behind boxes) -->
<line x1="168" y1="272" x2="220" y2="272" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<line x1="364" y1="272" x2="416" y2="272" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<line x1="576" y1="256" x2="628" y2="212" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<line x1="576" y1="288" x2="628" y2="332" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrow labels -->
<rect x="172" y="252" width="48" height="12" rx="2" fill="#f5f4ed"/>
<text x="196" y="262" fill="#1a70c7" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">HTTPS</text>
<rect x="368" y="252" width="48" height="12" rx="2" fill="#f5f4ed"/>
<text x="392" y="262" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">SSR</text>
<rect x="560" y="212" width="56" height="12" rx="2" fill="#f5f4ed"/>
<text x="588" y="222" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">READ MDX</text>
<rect x="560" y="320" width="52" height="12" rx="2" fill="#f5f4ed"/>
<text x="586" y="330" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">QUERY</text>
<!-- Node: Reader -->
<rect x="40" y="240" width="128" height="64" rx="6" fill="#f5f4ed"/>
<rect x="40" y="240" width="128" height="64" rx="6" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<rect x="48" y="248" width="28" height="12" rx="2" fill="transparent" stroke="rgba(101,101,92,0.40)" stroke-width="0.8"/>
<text x="62" y="257" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
<text x="104" y="276" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reader</text>
<text x="104" y="292" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser</text>
<!-- Node: Cloudflare -->
<rect x="220" y="240" width="144" height="64" rx="6" fill="#f5f4ed"/>
<rect x="220" y="240" width="144" height="64" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<rect x="228" y="248" width="32" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="244" y="257" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EDGE</text>
<text x="356" y="300" fill="rgba(11,13,11,0.06)" font-size="32" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">01</text>
<text x="292" y="276" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Cloudflare</text>
<text x="292" y="292" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Pages · cache</text>
<!-- Node: Astro (focal coral) -->
<rect x="416" y="240" width="160" height="64" rx="6" fill="#f5f4ed"/>
<rect x="416" y="240" width="160" height="64" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="424" y="248" width="32" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="440" y="257" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ORIG</text>
<text x="568" y="300" fill="rgba(247,89,31,0.10)" font-size="32" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">02</text>
<text x="496" y="276" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Astro Origin</text>
<text x="496" y="292" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">SSR + MDX</text>
<!-- Node: MDX Bundle -->
<rect x="628" y="160" width="144" height="64" rx="6" fill="#f5f4ed"/>
<rect x="628" y="160" width="144" height="64" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="636" y="168" width="32" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="652" y="177" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">BUN</text>
<text x="700" y="196" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">MDX Bundle</text>
<text x="700" y="212" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">src/content/*.mdx</text>
<!-- Node: Content CMS -->
<rect x="628" y="320" width="144" height="64" rx="6" fill="#f5f4ed"/>
<rect x="628" y="320" width="144" height="64" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<rect x="636" y="328" width="28" height="12" rx="2" fill="transparent" stroke="rgba(82,83,78,0.50)" stroke-width="0.8"/>
<text x="650" y="337" fill="#52534e" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CMS</text>
<text x="700" y="356" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Content CMS</text>
<text x="700" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">assets · og images</text>
<!-- Legend strip -->
<line x1="40" y1="404" x2="960" y2="404" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="420" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="436" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="60" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Focal / origin</text>
<rect x="180" y="436" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="200" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Backend / bundle</text>
<rect x="340" y="436" width="14" height="10" rx="2" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<text x="360" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Store</text>
<rect x="436" y="436" width="14" height="10" rx="2" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="456" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Cloud</text>
<rect x="528" y="436" width="14" height="10" rx="2" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<text x="548" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">External</text>
<line x1="636" y1="442" x2="664" y2="442" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="672" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">HTTP request</text>
<line x1="784" y1="442" x2="812" y2="442" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="820" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Primary flow</text>
</svg>
</div>
</body>
</html>
+200
View File
@@ -0,0 +1,200 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight content model · ER</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">ER · Diagram Design</p>
<h1>littlemight content model</h1>
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#a8a69d"/></marker>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Relationship lines (drawn first) -->
<!-- 1. Author — Article (1:N "writes") -->
<line x1="260" y1="240" x2="400" y2="240" stroke="#a8a69d" stroke-width="1" />
<!-- 2. Article — ArticleTag (1:N) -->
<line x1="640" y1="320" x2="780" y2="328" stroke="#a8a69d" stroke-width="1" />
<!-- 3. Tag — ArticleTag (1:N, vertical) -->
<line x1="880" y1="248" x2="880" y2="280" stroke="#a8a69d" stroke-width="1" />
<!-- Cardinality labels -->
<rect x="266" y="232" width="12" height="12" rx="2" fill="#1c1a17"/>
<text x="272" y="242" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="378" y="232" width="16" height="12" rx="2" fill="#1c1a17"/>
<text x="386" y="242" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<rect x="646" y="316" width="12" height="12" rx="2" fill="#1c1a17"/>
<text x="652" y="326" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="760" y="324" width="16" height="12" rx="2" fill="#1c1a17"/>
<text x="768" y="334" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<rect x="872" y="252" width="16" height="12" rx="2" fill="#1c1a17"/>
<text x="880" y="262" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="872" y="268" width="16" height="12" rx="2" fill="#1c1a17"/>
<text x="880" y="278" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<!-- Relationship labels -->
<rect x="304" y="220" width="56" height="14" rx="2" fill="#1c1a17"/>
<text x="332" y="230" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">WRITES</text>
<rect x="688" y="300" width="56" height="14" rx="2" fill="#1c1a17"/>
<text x="716" y="310" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">TAGGED</text>
<!-- Entity: Author -->
<rect x="60" y="160" width="200" height="160" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<rect x="60" y="160" width="200" height="40" rx="6" fill="rgba(241,239,231,0.04)" stroke="none"/>
<rect x="60" y="192" width="200" height="8" fill="rgba(241,239,231,0.04)"/>
<line x1="60" y1="200" x2="260" y2="200" stroke="rgba(241,239,231,0.22)" stroke-width="1"/>
<text x="76" y="176" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY</text>
<text x="76" y="192" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Author</text>
<text x="76" y="220" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="220" y="220" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="76" y="240" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">handle</text>
<text x="220" y="240" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="260" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">name</text>
<text x="220" y="260" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="280" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">bio</text>
<text x="220" y="280" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="300" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">site_url</text>
<text x="220" y="300" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<!-- Entity: Article (focal coral) -->
<rect x="400" y="120" width="240" height="240" rx="6" fill="rgba(255,106,48,0.04)" stroke="#ff6a30" stroke-width="1"/>
<rect x="400" y="120" width="240" height="40" rx="6" fill="rgba(255,106,48,0.10)" stroke="none"/>
<rect x="400" y="152" width="240" height="8" fill="rgba(255,106,48,0.10)"/>
<line x1="400" y1="160" x2="640" y2="160" stroke="rgba(255,106,48,0.40)" stroke-width="1"/>
<text x="416" y="136" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY · AGGREGATE ROOT</text>
<text x="416" y="152" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Article</text>
<text x="416" y="180" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="600" y="180" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="416" y="200" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">title</text>
<text x="600" y="200" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="416" y="220" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">slug</text>
<text x="600" y="220" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · unique</text>
<text x="416" y="240" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">body_mdx</text>
<text x="600" y="240" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="416" y="260" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">published_at</text>
<text x="600" y="260" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">timestamp</text>
<text x="416" y="280" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">→ author_id</text>
<text x="600" y="280" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="416" y="300" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">status</text>
<text x="600" y="300" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">enum</text>
<text x="416" y="320" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">og_image</text>
<text x="600" y="320" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · url</text>
<!-- Entity: Tag -->
<rect x="780" y="120" width="200" height="128" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<rect x="780" y="120" width="200" height="40" rx="6" fill="rgba(241,239,231,0.04)" stroke="none"/>
<rect x="780" y="152" width="200" height="8" fill="rgba(241,239,231,0.04)"/>
<line x1="780" y1="160" x2="980" y2="160" stroke="rgba(241,239,231,0.22)" stroke-width="1"/>
<text x="796" y="136" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY</text>
<text x="796" y="152" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Tag</text>
<text x="796" y="180" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="940" y="180" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="796" y="200" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">slug</text>
<text x="940" y="200" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · unique</text>
<text x="796" y="220" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">name</text>
<text x="940" y="220" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="796" y="240" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">description</text>
<text x="940" y="240" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<!-- Entity: ArticleTag (join) -->
<rect x="780" y="280" width="200" height="96" rx="6" fill="rgba(241,239,231,0.04)" stroke="#a8a69d" stroke-width="1" stroke-dasharray="4,3"/>
<rect x="780" y="280" width="200" height="40" rx="6" fill="rgba(241,239,231,0.06)" stroke="none"/>
<rect x="780" y="312" width="200" height="8" fill="rgba(241,239,231,0.06)"/>
<line x1="780" y1="320" x2="980" y2="320" stroke="rgba(241,239,231,0.22)" stroke-width="1"/>
<text x="796" y="296" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">JOIN</text>
<text x="796" y="312" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif">ArticleTag</text>
<text x="796" y="340" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">→ article_id</text>
<text x="940" y="340" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="796" y="360" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace">→ tag_id</text>
<text x="940" y="360" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<!-- Legend -->
<line x1="40" y1="404" x2="960" y2="404" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="420" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="436" width="14" height="10" rx="2" fill="rgba(255,106,48,0.04)" stroke="#ff6a30" stroke-width="1"/>
<text x="60" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Aggregate root</text>
<rect x="180" y="436" width="14" height="10" rx="2" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="200" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Entity</text>
<rect x="268" y="436" width="14" height="10" rx="2" fill="rgba(241,239,231,0.04)" stroke="#a8a69d" stroke-width="1" stroke-dasharray="3,2"/>
<text x="288" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Join table</text>
<text x="372" y="444" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">#</text>
<text x="388" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Primary key</text>
<text x="476" y="444" fill="#f1efe7" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">→</text>
<text x="492" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Foreign key</text>
<text x="584" y="444" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">1 / N</text>
<text x="616" y="444" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Cardinality</text>
</svg>
</div>
</body>
</html>
+203
View File
@@ -0,0 +1,203 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight content model · ER</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">ER · Diagram Design</p>
<h1>littlemight content model</h1>
<p class="subtitle">The four entities behind the site. Article is the aggregate root — everything else exists to describe or classify it. `#` marks primary keys, `→` marks foreign keys.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Relationship lines (drawn first) -->
<!-- 1. Author — Article (1:N "writes") -->
<line x1="260" y1="240" x2="400" y2="240" stroke="#52534e" stroke-width="1" />
<!-- 2. Article — ArticleTag (1:N) -->
<line x1="640" y1="320" x2="780" y2="328" stroke="#52534e" stroke-width="1" />
<!-- 3. Tag — ArticleTag (1:N, vertical) -->
<line x1="880" y1="248" x2="880" y2="280" stroke="#52534e" stroke-width="1" />
<!-- Cardinality labels -->
<rect x="266" y="232" width="12" height="12" rx="2" fill="#f5f4ed"/>
<text x="272" y="242" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="378" y="232" width="16" height="12" rx="2" fill="#f5f4ed"/>
<text x="386" y="242" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<rect x="646" y="316" width="12" height="12" rx="2" fill="#f5f4ed"/>
<text x="652" y="326" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="760" y="324" width="16" height="12" rx="2" fill="#f5f4ed"/>
<text x="768" y="334" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<rect x="872" y="252" width="16" height="12" rx="2" fill="#f5f4ed"/>
<text x="880" y="262" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="872" y="268" width="16" height="12" rx="2" fill="#f5f4ed"/>
<text x="880" y="278" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<!-- Relationship labels -->
<rect x="304" y="220" width="56" height="14" rx="2" fill="#f5f4ed"/>
<text x="332" y="230" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">WRITES</text>
<rect x="688" y="300" width="56" height="14" rx="2" fill="#f5f4ed"/>
<text x="716" y="310" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">TAGGED</text>
<!-- Entity: Author -->
<rect x="60" y="160" width="200" height="160" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="60" y="160" width="200" height="40" rx="6" fill="rgba(11,13,11,0.04)" stroke="none"/>
<rect x="60" y="192" width="200" height="8" fill="rgba(11,13,11,0.04)"/>
<line x1="60" y1="200" x2="260" y2="200" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<text x="76" y="176" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY</text>
<text x="76" y="192" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Author</text>
<text x="76" y="220" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="220" y="220" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="76" y="240" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">handle</text>
<text x="220" y="240" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="260" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">name</text>
<text x="220" y="260" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="280" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">bio</text>
<text x="220" y="280" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="300" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">site_url</text>
<text x="220" y="300" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<!-- Entity: Article (focal coral) -->
<rect x="400" y="120" width="240" height="240" rx="6" fill="rgba(247,89,31,0.04)" stroke="#f7591f" stroke-width="1"/>
<rect x="400" y="120" width="240" height="40" rx="6" fill="rgba(247,89,31,0.10)" stroke="none"/>
<rect x="400" y="152" width="240" height="8" fill="rgba(247,89,31,0.10)"/>
<line x1="400" y1="160" x2="640" y2="160" stroke="rgba(247,89,31,0.40)" stroke-width="1"/>
<text x="416" y="136" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY · AGGREGATE ROOT</text>
<text x="416" y="152" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Article</text>
<text x="416" y="180" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="600" y="180" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="416" y="200" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">title</text>
<text x="600" y="200" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="416" y="220" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">slug</text>
<text x="600" y="220" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · unique</text>
<text x="416" y="240" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">body_mdx</text>
<text x="600" y="240" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="416" y="260" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">published_at</text>
<text x="600" y="260" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">timestamp</text>
<text x="416" y="280" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">→ author_id</text>
<text x="600" y="280" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="416" y="300" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">status</text>
<text x="600" y="300" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">enum</text>
<text x="416" y="320" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">og_image</text>
<text x="600" y="320" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · url</text>
<!-- Entity: Tag -->
<rect x="780" y="120" width="200" height="128" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="780" y="120" width="200" height="40" rx="6" fill="rgba(11,13,11,0.04)" stroke="none"/>
<rect x="780" y="152" width="200" height="8" fill="rgba(11,13,11,0.04)"/>
<line x1="780" y1="160" x2="980" y2="160" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<text x="796" y="136" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY</text>
<text x="796" y="152" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Tag</text>
<text x="796" y="180" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="940" y="180" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="796" y="200" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">slug</text>
<text x="940" y="200" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · unique</text>
<text x="796" y="220" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">name</text>
<text x="940" y="220" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="796" y="240" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">description</text>
<text x="940" y="240" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<!-- Entity: ArticleTag (join) -->
<rect x="780" y="280" width="200" height="96" rx="6" fill="rgba(11,13,11,0.04)" stroke="#52534e" stroke-width="1" stroke-dasharray="4,3"/>
<rect x="780" y="280" width="200" height="40" rx="6" fill="rgba(11,13,11,0.06)" stroke="none"/>
<rect x="780" y="312" width="200" height="8" fill="rgba(11,13,11,0.06)"/>
<line x1="780" y1="320" x2="980" y2="320" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<text x="796" y="296" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">JOIN</text>
<text x="796" y="312" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif">ArticleTag</text>
<text x="796" y="340" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">→ article_id</text>
<text x="940" y="340" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="796" y="360" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">→ tag_id</text>
<text x="940" y="360" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<!-- Legend -->
<line x1="40" y1="404" x2="960" y2="404" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="420" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="436" width="14" height="10" rx="2" fill="rgba(247,89,31,0.04)" stroke="#f7591f" stroke-width="1"/>
<text x="60" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Aggregate root</text>
<rect x="180" y="436" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="200" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Entity</text>
<rect x="268" y="436" width="14" height="10" rx="2" fill="rgba(11,13,11,0.04)" stroke="#52534e" stroke-width="1" stroke-dasharray="3,2"/>
<text x="288" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Join table</text>
<text x="372" y="444" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">#</text>
<text x="388" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Primary key</text>
<text x="476" y="444" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">→</text>
<text x="492" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Foreign key</text>
<text x="584" y="444" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">1 / N</text>
<text x="616" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Cardinality</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>Article is the root</h3></div>
<p>Author, Tag, and the join table only exist to describe Article. If you're thinking about a feature, start here and trace outward.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Many-to-many via a join</h3></div>
<ul><li>Tags aren't embedded on Article</li><li>ArticleTag is a pure join — no metadata</li><li>Dashed border signals it's not a primary entity</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Cardinality over arrows</h3></div>
<p>Plain lines with 1/N at the ends read cleaner than crow's feet at this size. Every relationship carries both numbers.</p>
</div>
</div>
<div class="footer">
<span>littlemight content model · ER</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+200
View File
@@ -0,0 +1,200 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight content model · ER</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">ER · Diagram Design</p>
<h1>littlemight content model</h1>
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Relationship lines (drawn first) -->
<!-- 1. Author — Article (1:N "writes") -->
<line x1="260" y1="240" x2="400" y2="240" stroke="#52534e" stroke-width="1" />
<!-- 2. Article — ArticleTag (1:N) -->
<line x1="640" y1="320" x2="780" y2="328" stroke="#52534e" stroke-width="1" />
<!-- 3. Tag — ArticleTag (1:N, vertical) -->
<line x1="880" y1="248" x2="880" y2="280" stroke="#52534e" stroke-width="1" />
<!-- Cardinality labels -->
<rect x="266" y="232" width="12" height="12" rx="2" fill="#f5f4ed"/>
<text x="272" y="242" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="378" y="232" width="16" height="12" rx="2" fill="#f5f4ed"/>
<text x="386" y="242" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<rect x="646" y="316" width="12" height="12" rx="2" fill="#f5f4ed"/>
<text x="652" y="326" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="760" y="324" width="16" height="12" rx="2" fill="#f5f4ed"/>
<text x="768" y="334" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<rect x="872" y="252" width="16" height="12" rx="2" fill="#f5f4ed"/>
<text x="880" y="262" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">1</text>
<rect x="872" y="268" width="16" height="12" rx="2" fill="#f5f4ed"/>
<text x="880" y="278" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="middle" font-weight="600">N</text>
<!-- Relationship labels -->
<rect x="304" y="220" width="56" height="14" rx="2" fill="#f5f4ed"/>
<text x="332" y="230" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">WRITES</text>
<rect x="688" y="300" width="56" height="14" rx="2" fill="#f5f4ed"/>
<text x="716" y="310" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">TAGGED</text>
<!-- Entity: Author -->
<rect x="60" y="160" width="200" height="160" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="60" y="160" width="200" height="40" rx="6" fill="rgba(11,13,11,0.04)" stroke="none"/>
<rect x="60" y="192" width="200" height="8" fill="rgba(11,13,11,0.04)"/>
<line x1="60" y1="200" x2="260" y2="200" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<text x="76" y="176" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY</text>
<text x="76" y="192" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Author</text>
<text x="76" y="220" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="220" y="220" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="76" y="240" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">handle</text>
<text x="220" y="240" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="260" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">name</text>
<text x="220" y="260" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="280" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">bio</text>
<text x="220" y="280" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="76" y="300" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">site_url</text>
<text x="220" y="300" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<!-- Entity: Article (focal coral) -->
<rect x="400" y="120" width="240" height="240" rx="6" fill="rgba(247,89,31,0.04)" stroke="#f7591f" stroke-width="1"/>
<rect x="400" y="120" width="240" height="40" rx="6" fill="rgba(247,89,31,0.10)" stroke="none"/>
<rect x="400" y="152" width="240" height="8" fill="rgba(247,89,31,0.10)"/>
<line x1="400" y1="160" x2="640" y2="160" stroke="rgba(247,89,31,0.40)" stroke-width="1"/>
<text x="416" y="136" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY · AGGREGATE ROOT</text>
<text x="416" y="152" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Article</text>
<text x="416" y="180" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="600" y="180" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="416" y="200" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">title</text>
<text x="600" y="200" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="416" y="220" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">slug</text>
<text x="600" y="220" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · unique</text>
<text x="416" y="240" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">body_mdx</text>
<text x="600" y="240" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="416" y="260" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">published_at</text>
<text x="600" y="260" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">timestamp</text>
<text x="416" y="280" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">→ author_id</text>
<text x="600" y="280" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="416" y="300" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">status</text>
<text x="600" y="300" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">enum</text>
<text x="416" y="320" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">og_image</text>
<text x="600" y="320" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · url</text>
<!-- Entity: Tag -->
<rect x="780" y="120" width="200" height="128" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="780" y="120" width="200" height="40" rx="6" fill="rgba(11,13,11,0.04)" stroke="none"/>
<rect x="780" y="152" width="200" height="8" fill="rgba(11,13,11,0.04)"/>
<line x1="780" y1="160" x2="980" y2="160" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<text x="796" y="136" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">ENTITY</text>
<text x="796" y="152" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif">Tag</text>
<text x="796" y="180" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace"># id</text>
<text x="940" y="180" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="796" y="200" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">slug</text>
<text x="940" y="200" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text · unique</text>
<text x="796" y="220" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">name</text>
<text x="940" y="220" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<text x="796" y="240" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">description</text>
<text x="940" y="240" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">text</text>
<!-- Entity: ArticleTag (join) -->
<rect x="780" y="280" width="200" height="96" rx="6" fill="rgba(11,13,11,0.04)" stroke="#52534e" stroke-width="1" stroke-dasharray="4,3"/>
<rect x="780" y="280" width="200" height="40" rx="6" fill="rgba(11,13,11,0.06)" stroke="none"/>
<rect x="780" y="312" width="200" height="8" fill="rgba(11,13,11,0.06)"/>
<line x1="780" y1="320" x2="980" y2="320" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<text x="796" y="296" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">JOIN</text>
<text x="796" y="312" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif">ArticleTag</text>
<text x="796" y="340" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">→ article_id</text>
<text x="940" y="340" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<text x="796" y="360" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace">→ tag_id</text>
<text x="940" y="360" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end">uuid</text>
<!-- Legend -->
<line x1="40" y1="404" x2="960" y2="404" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="420" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="436" width="14" height="10" rx="2" fill="rgba(247,89,31,0.04)" stroke="#f7591f" stroke-width="1"/>
<text x="60" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Aggregate root</text>
<rect x="180" y="436" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="200" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Entity</text>
<rect x="268" y="436" width="14" height="10" rx="2" fill="rgba(11,13,11,0.04)" stroke="#52534e" stroke-width="1" stroke-dasharray="3,2"/>
<text x="288" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Join table</text>
<text x="372" y="444" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">#</text>
<text x="388" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Primary key</text>
<text x="476" y="444" fill="#0b0d0b" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">→</text>
<text x="492" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Foreign key</text>
<text x="584" y="444" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" font-weight="600">1 / N</text>
<text x="616" y="444" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Cardinality</text>
</svg>
</div>
</body>
</html>
+154
View File
@@ -0,0 +1,154 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Should you write this as a skill?</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Flowchart · Diagram Design</p>
<h1>Should you write this as a skill?</h1>
<svg viewBox="0 0 1000 600" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#a8a69d"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#ff6a30"/></marker>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Arrows (drawn first, behind nodes) -->
<!-- Start → Step -->
<line x1="500" y1="88" x2="500" y2="120" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Step → Diamond 1 -->
<line x1="500" y1="168" x2="500" y2="192" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 1 "NO" right -->
<line x1="600" y1="240" x2="720" y2="240" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 1 "YES" down -->
<line x1="500" y1="288" x2="500" y2="328" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 2 "NO" right -->
<line x1="600" y1="376" x2="720" y2="376" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 2 "YES" down (coral — happy path) -->
<line x1="500" y1="424" x2="500" y2="464" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- Arrow labels -->
<rect x="644" y="230" width="24" height="12" rx="2" fill="#1c1a17"/>
<text x="656" y="239" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">NO</text>
<rect x="484" y="298" width="32" height="12" rx="2" fill="#1c1a17"/>
<text x="500" y="307" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">YES</text>
<rect x="644" y="366" width="24" height="12" rx="2" fill="#1c1a17"/>
<text x="656" y="375" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">NO</text>
<rect x="484" y="434" width="32" height="12" rx="2" fill="#1c1a17"/>
<text x="500" y="443" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">YES</text>
<!-- Start oval -->
<rect x="420" y="40" width="160" height="48" rx="24" fill="rgba(241,239,231,0.03)" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<text x="500" y="68" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">New workflow</text>
<!-- Rectangle: Step -->
<rect x="420" y="120" width="160" height="48" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="500" y="148" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Do it manually once</text>
<!-- Diamond 1: Repeated >3 times? -->
<polygon points="500,192 600,240 500,288 400,240" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="500" y="238" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Will you repeat</text>
<text x="500" y="252" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">it >3 times?</text>
<!-- End oval: One-off -->
<rect x="720" y="216" width="160" height="48" rx="24" fill="rgba(241,239,231,0.03)" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<text x="800" y="240" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">One-off</text>
<text x="800" y="254" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">keep manual</text>
<!-- Diamond 2: Reusable across projects? -->
<polygon points="500,328 600,376 500,424 400,376" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="500" y="374" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reusable across</text>
<text x="500" y="388" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">projects?</text>
<!-- End oval: CLAUDE.md note -->
<rect x="720" y="352" width="160" height="48" rx="24" fill="rgba(241,239,231,0.03)" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<text x="800" y="376" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">CLAUDE.md note</text>
<text x="800" y="390" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">project-scoped</text>
<!-- End oval: Write a skill (coral focal) -->
<rect x="420" y="464" width="160" height="56" rx="28" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<text x="500" y="492" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Write a skill</text>
<text x="500" y="508" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">reusable + assets</text>
<!-- Legend -->
<line x1="40" y1="540" x2="960" y2="540" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="556" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND · SHAPE CARRIES TYPE</text>
<rect x="40" y="572" width="24" height="12" rx="6" fill="rgba(241,239,231,0.03)" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<text x="72" y="582" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Start / end (oval)</text>
<rect x="220" y="572" width="24" height="12" rx="2" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="252" y="582" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Step (rectangle)</text>
<polygon points="412,578 424,572 436,578 424,584" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="448" y="582" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Decision (diamond)</text>
<line x1="604" y1="580" x2="632" y2="580" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="640" y="582" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Happy path</text>
<line x1="768" y1="580" x2="796" y2="580" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<text x="804" y="582" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Branch</text>
</svg>
</div>
</body>
</html>
+157
View File
@@ -0,0 +1,157 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Should you write this as a skill?</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Flowchart · Diagram Design</p>
<h1>Should you write this as a skill?</h1>
<p class="subtitle">A three-decision triage for turning a one-off workflow into something reusable. Shape carries type — ovals bracket the flow, rectangles are steps, diamonds are decisions.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 600" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Arrows (drawn first, behind nodes) -->
<!-- Start → Step -->
<line x1="500" y1="88" x2="500" y2="120" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Step → Diamond 1 -->
<line x1="500" y1="168" x2="500" y2="192" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 1 "NO" right -->
<line x1="600" y1="240" x2="720" y2="240" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 1 "YES" down -->
<line x1="500" y1="288" x2="500" y2="328" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 2 "NO" right -->
<line x1="600" y1="376" x2="720" y2="376" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 2 "YES" down (coral — happy path) -->
<line x1="500" y1="424" x2="500" y2="464" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- Arrow labels -->
<rect x="644" y="230" width="24" height="12" rx="2" fill="#f5f4ed"/>
<text x="656" y="239" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">NO</text>
<rect x="484" y="298" width="32" height="12" rx="2" fill="#f5f4ed"/>
<text x="500" y="307" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">YES</text>
<rect x="644" y="366" width="24" height="12" rx="2" fill="#f5f4ed"/>
<text x="656" y="375" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">NO</text>
<rect x="484" y="434" width="32" height="12" rx="2" fill="#f5f4ed"/>
<text x="500" y="443" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">YES</text>
<!-- Start oval -->
<rect x="420" y="40" width="160" height="48" rx="24" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="500" y="68" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">New workflow</text>
<!-- Rectangle: Step -->
<rect x="420" y="120" width="160" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="500" y="148" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Do it manually once</text>
<!-- Diamond 1: Repeated >3 times? -->
<polygon points="500,192 600,240 500,288 400,240" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="500" y="238" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Will you repeat</text>
<text x="500" y="252" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">it >3 times?</text>
<!-- End oval: One-off -->
<rect x="720" y="216" width="160" height="48" rx="24" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="800" y="240" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">One-off</text>
<text x="800" y="254" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">keep manual</text>
<!-- Diamond 2: Reusable across projects? -->
<polygon points="500,328 600,376 500,424 400,376" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="500" y="374" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reusable across</text>
<text x="500" y="388" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">projects?</text>
<!-- End oval: CLAUDE.md note -->
<rect x="720" y="352" width="160" height="48" rx="24" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="800" y="376" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">CLAUDE.md note</text>
<text x="800" y="390" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">project-scoped</text>
<!-- End oval: Write a skill (coral focal) -->
<rect x="420" y="464" width="160" height="56" rx="28" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="500" y="492" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Write a skill</text>
<text x="500" y="508" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">reusable + assets</text>
<!-- Legend -->
<line x1="40" y1="540" x2="960" y2="540" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="556" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND · SHAPE CARRIES TYPE</text>
<rect x="40" y="572" width="24" height="12" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="72" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Start / end (oval)</text>
<rect x="220" y="572" width="24" height="12" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="252" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Step (rectangle)</text>
<polygon points="412,578 424,572 436,578 424,584" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="448" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Decision (diamond)</text>
<line x1="604" y1="580" x2="632" y2="580" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="640" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Happy path</text>
<line x1="768" y1="580" x2="796" y2="580" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<text x="804" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Branch</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">WHY THIS FLOWCHART</p>
<div class="card-header"><span class="card-dot coral"></span><h3>Most things aren't skills</h3></div>
<p>The happy path is narrow on purpose. Only workflows that clear all three gates earn the overhead of a reusable skill — everything else is better as a project note.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Shape, not color</h3></div>
<ul><li>Oval bookends the flow</li><li>Rectangle is a step</li><li>Diamond is a decision</li><li>Color reserved for the happy path</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Every branch gets a label</h3></div>
<p>Unlabeled branches turn a flowchart into a maze. Yes/No is fine; conditions in mono when the logic is richer.</p>
</div>
</div>
<div class="footer">
<span>flowchart · should I write this as a skill?</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+154
View File
@@ -0,0 +1,154 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Should you write this as a skill?</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Flowchart · Diagram Design</p>
<h1>Should you write this as a skill?</h1>
<svg viewBox="0 0 1000 600" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Arrows (drawn first, behind nodes) -->
<!-- Start → Step -->
<line x1="500" y1="88" x2="500" y2="120" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Step → Diamond 1 -->
<line x1="500" y1="168" x2="500" y2="192" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 1 "NO" right -->
<line x1="600" y1="240" x2="720" y2="240" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 1 "YES" down -->
<line x1="500" y1="288" x2="500" y2="328" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 2 "NO" right -->
<line x1="600" y1="376" x2="720" y2="376" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Diamond 2 "YES" down (coral — happy path) -->
<line x1="500" y1="424" x2="500" y2="464" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- Arrow labels -->
<rect x="644" y="230" width="24" height="12" rx="2" fill="#f5f4ed"/>
<text x="656" y="239" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">NO</text>
<rect x="484" y="298" width="32" height="12" rx="2" fill="#f5f4ed"/>
<text x="500" y="307" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">YES</text>
<rect x="644" y="366" width="24" height="12" rx="2" fill="#f5f4ed"/>
<text x="656" y="375" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">NO</text>
<rect x="484" y="434" width="32" height="12" rx="2" fill="#f5f4ed"/>
<text x="500" y="443" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">YES</text>
<!-- Start oval -->
<rect x="420" y="40" width="160" height="48" rx="24" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="500" y="68" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">New workflow</text>
<!-- Rectangle: Step -->
<rect x="420" y="120" width="160" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="500" y="148" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Do it manually once</text>
<!-- Diamond 1: Repeated >3 times? -->
<polygon points="500,192 600,240 500,288 400,240" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="500" y="238" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Will you repeat</text>
<text x="500" y="252" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">it >3 times?</text>
<!-- End oval: One-off -->
<rect x="720" y="216" width="160" height="48" rx="24" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="800" y="240" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">One-off</text>
<text x="800" y="254" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">keep manual</text>
<!-- Diamond 2: Reusable across projects? -->
<polygon points="500,328 600,376 500,424 400,376" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="500" y="374" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reusable across</text>
<text x="500" y="388" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">projects?</text>
<!-- End oval: CLAUDE.md note -->
<rect x="720" y="352" width="160" height="48" rx="24" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="800" y="376" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">CLAUDE.md note</text>
<text x="800" y="390" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">project-scoped</text>
<!-- End oval: Write a skill (coral focal) -->
<rect x="420" y="464" width="160" height="56" rx="28" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="500" y="492" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Write a skill</text>
<text x="500" y="508" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">reusable + assets</text>
<!-- Legend -->
<line x1="40" y1="540" x2="960" y2="540" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="556" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND · SHAPE CARRIES TYPE</text>
<rect x="40" y="572" width="24" height="12" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="72" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Start / end (oval)</text>
<rect x="220" y="572" width="24" height="12" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="252" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Step (rectangle)</text>
<polygon points="412,578 424,572 436,578 424,584" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="448" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Decision (diamond)</text>
<line x1="604" y1="580" x2="632" y2="580" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="640" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Happy path</text>
<line x1="768" y1="580" x2="796" y2="580" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<text x="804" y="582" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Branch</text>
</svg>
</div>
</body>
</html>
+121
View File
@@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI app stack · Layer hierarchy</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Layer stack · Diagram Design</p>
<h1>AI app stack · Where the work actually happens</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Direction column (left margin) -->
<text x="60" y="68" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">ABSTRACTION</text>
<line x1="80" y1="80" x2="80" y2="400" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<polygon points="76,80 84,80 80,72" fill="#a8a69d"/>
<text x="60" y="416" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">SILICON</text>
<!-- Stack container hairlines (top + bottom edges) -->
<line x1="120" y1="80" x2="960" y2="80" stroke="rgba(241,239,231,0.12)" stroke-width="1"/>
<line x1="120" y1="400" x2="960" y2="400" stroke="rgba(241,239,231,0.12)" stroke-width="1"/>
<!-- L5 — UI (top layer, lifted fill) -->
<rect x="120" y="80" width="840" height="64" fill="#2a2723"/>
<line x1="120" y1="144" x2="960" y2="144" stroke="rgba(241,239,231,0.12)" stroke-width="1"/>
<text x="140" y="116" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L5</text>
<text x="260" y="118" fill="#f1efe7" font-size="16" font-weight="600" font-family="'Geist', sans-serif">UI surface</text>
<text x="940" y="118" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">chat, editor, canvas</text>
<!-- L4 — Agent harness (FOCAL, coral tint + coral stroke) -->
<rect x="120" y="144" width="840" height="64" fill="rgba(255,106,48,0.12)"/>
<rect x="120" y="144" width="840" height="64" fill="none" stroke="#ff6a30" stroke-width="1"/>
<text x="140" y="180" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em" font-weight="600">L4</text>
<text x="260" y="182" fill="#f1efe7" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Agent harness</text>
<text x="940" y="182" fill="#ff6a30" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">tools, memory, loop</text>
<!-- L3 — Prompt layer -->
<rect x="120" y="208" width="840" height="64" fill="#1c1a17"/>
<line x1="120" y1="272" x2="960" y2="272" stroke="rgba(241,239,231,0.12)" stroke-width="1"/>
<text x="140" y="244" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L3</text>
<text x="260" y="246" fill="#f1efe7" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Prompt layer</text>
<text x="940" y="246" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">system, few-shot, caching</text>
<!-- L2 — SDK -->
<rect x="120" y="272" width="840" height="64" fill="#221f1c"/>
<line x1="120" y1="336" x2="960" y2="336" stroke="rgba(241,239,231,0.12)" stroke-width="1"/>
<text x="140" y="308" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L2</text>
<text x="260" y="310" fill="#f1efe7" font-size="16" font-weight="600" font-family="'Geist', sans-serif">SDK / client</text>
<text x="940" y="310" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">auth, retries, streaming</text>
<!-- L1 — Model -->
<rect x="120" y="336" width="840" height="64" fill="#221f1c"/>
<text x="140" y="372" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L1</text>
<text x="260" y="374" fill="#f1efe7" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Model weights</text>
<text x="940" y="374" fill="#a8a69d" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">opus, sonnet, haiku</text>
<!-- Caption -->
<text x="120" y="456" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">FOCAL LAYER</text>
<text x="240" y="456" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">The harness is where most product differentiation actually lives — tools, memory, and the loop that stitches model calls into useful work.</text>
</svg>
</div>
</body>
</html>
+124
View File
@@ -0,0 +1,124 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI app stack · Layer hierarchy</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Layer stack · Diagram Design</p>
<h1>AI app stack · Where the work actually happens</h1>
<p class="subtitle">Five layers between silicon and the user. Most teams over-invest in the model and under-invest in the harness — which is the layer that decides whether the app feels magical or flaky.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Direction column (left margin) -->
<text x="60" y="68" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">ABSTRACTION</text>
<line x1="80" y1="80" x2="80" y2="400" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<polygon points="76,80 84,80 80,72" fill="#52534e"/>
<text x="60" y="416" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">SILICON</text>
<!-- Stack container hairlines (top + bottom edges) -->
<line x1="120" y1="80" x2="960" y2="80" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<line x1="120" y1="400" x2="960" y2="400" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<!-- L5 — UI (top layer, near-white fill) -->
<rect x="120" y="80" width="840" height="64" fill="#ffffff"/>
<line x1="120" y1="144" x2="960" y2="144" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="140" y="116" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L5</text>
<text x="260" y="118" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">UI surface</text>
<text x="940" y="118" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">chat, editor, canvas</text>
<!-- L4 — Agent harness (FOCAL, coral tint + coral stroke) -->
<rect x="120" y="144" width="840" height="64" fill="rgba(247,89,31,0.08)"/>
<rect x="120" y="144" width="840" height="64" fill="none" stroke="#f7591f" stroke-width="1"/>
<text x="140" y="180" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em" font-weight="600">L4</text>
<text x="260" y="182" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Agent harness</text>
<text x="940" y="182" fill="#f7591f" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">tools, memory, loop</text>
<!-- L3 — Prompt layer -->
<rect x="120" y="208" width="840" height="64" fill="#f5f4ed"/>
<line x1="120" y1="272" x2="960" y2="272" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="140" y="244" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L3</text>
<text x="260" y="246" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Prompt layer</text>
<text x="940" y="246" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">system, few-shot, caching</text>
<!-- L2 — SDK -->
<rect x="120" y="272" width="840" height="64" fill="#efeee5"/>
<line x1="120" y1="336" x2="960" y2="336" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="140" y="308" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L2</text>
<text x="260" y="310" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">SDK / client</text>
<text x="940" y="310" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">auth, retries, streaming</text>
<!-- L1 — Model -->
<rect x="120" y="336" width="840" height="64" fill="#efeee5"/>
<text x="140" y="372" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L1</text>
<text x="260" y="374" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Model weights</text>
<text x="940" y="374" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">opus, sonnet, haiku</text>
<!-- Caption -->
<text x="120" y="456" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">FOCAL LAYER</text>
<text x="240" y="456" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">The harness is where most product differentiation actually lives — tools, memory, and the loop that stitches model calls into useful work.</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>Coral marks the layer that pays rent</h3></div>
<p>Swapping models is a knob. Rewriting the harness is a product decision. The coral band says: this is the layer where you out-execute the competition, not the one where you chase leaderboards.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Reading the stack</h3></div>
<ul><li>Abstraction rises up the left column</li><li>L-index on the left, note on the right</li><li>Hairlines between layers, no shadows</li><li>Fill shade shifts from paper-2 to white</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Why only five</h3></div>
<p>Six-plus layers become a legend, not a diagram. Five holds the whole thing on one screen — every band readable without squinting, every note a scan away.</p>
</div>
</div>
<div class="footer">
<span>ai app stack · layer hierarchy</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+121
View File
@@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI app stack · Layer hierarchy</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Layer stack · Diagram Design</p>
<h1>AI app stack · Where the work actually happens</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Direction column (left margin) -->
<text x="60" y="68" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">ABSTRACTION</text>
<line x1="80" y1="80" x2="80" y2="400" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<polygon points="76,80 84,80 80,72" fill="#52534e"/>
<text x="60" y="416" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">SILICON</text>
<!-- Stack container hairlines (top + bottom edges) -->
<line x1="120" y1="80" x2="960" y2="80" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<line x1="120" y1="400" x2="960" y2="400" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<!-- L5 — UI (top layer, near-white fill) -->
<rect x="120" y="80" width="840" height="64" fill="#ffffff"/>
<line x1="120" y1="144" x2="960" y2="144" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="140" y="116" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L5</text>
<text x="260" y="118" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">UI surface</text>
<text x="940" y="118" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">chat, editor, canvas</text>
<!-- L4 — Agent harness (FOCAL, coral tint + coral stroke) -->
<rect x="120" y="144" width="840" height="64" fill="rgba(247,89,31,0.08)"/>
<rect x="120" y="144" width="840" height="64" fill="none" stroke="#f7591f" stroke-width="1"/>
<text x="140" y="180" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em" font-weight="600">L4</text>
<text x="260" y="182" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Agent harness</text>
<text x="940" y="182" fill="#f7591f" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">tools, memory, loop</text>
<!-- L3 — Prompt layer -->
<rect x="120" y="208" width="840" height="64" fill="#f5f4ed"/>
<line x1="120" y1="272" x2="960" y2="272" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="140" y="244" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L3</text>
<text x="260" y="246" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Prompt layer</text>
<text x="940" y="246" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">system, few-shot, caching</text>
<!-- L2 — SDK -->
<rect x="120" y="272" width="840" height="64" fill="#efeee5"/>
<line x1="120" y1="336" x2="960" y2="336" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="140" y="308" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L2</text>
<text x="260" y="310" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">SDK / client</text>
<text x="940" y="310" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">auth, retries, streaming</text>
<!-- L1 — Model -->
<rect x="120" y="336" width="840" height="64" fill="#efeee5"/>
<text x="140" y="372" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">L1</text>
<text x="260" y="374" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif">Model weights</text>
<text x="940" y="374" fill="#52534e" font-size="10" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.08em">opus, sonnet, haiku</text>
<!-- Caption -->
<text x="120" y="456" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">FOCAL LAYER</text>
<text x="240" y="456" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">The harness is where most product differentiation actually lives — tools, memory, and the loop that stitches model calls into useful work.</text>
</svg>
</div>
</body>
</html>
+130
View File
@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The CLAUDE.md Hierarchy</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Nested · Diagram Design</p>
<h1>The CLAUDE.md Hierarchy</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Level 1: ~/.claude/ (global) — outermost -->
<rect x="40" y="60" width="920" height="380" rx="8" fill="rgba(241,239,231,0.015)" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<!-- Level 2: ~/vault/ -->
<rect x="72" y="96" width="856" height="308" rx="8" fill="rgba(241,239,231,0.02)" stroke="rgba(241,239,231,0.35)" stroke-width="1"/>
<!-- Level 3: /business -->
<rect x="104" y="132" width="792" height="236" rx="8" fill="rgba(241,239,231,0.025)" stroke="rgba(241,239,231,0.45)" stroke-width="1"/>
<!-- Level 4: /marketing -->
<rect x="136" y="168" width="728" height="164" rx="8" fill="rgba(241,239,231,0.03)" stroke="#a8a69d" stroke-width="1"/>
<!-- Level 5: /project — innermost, coral focal -->
<rect x="168" y="204" width="664" height="92" rx="8" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<!-- Level labels on paper-colored masks -->
<rect x="56" y="52" width="188" height="16" fill="#1c1a17"/>
<text x="64" y="64" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">~/.claude/ (global)</text>
<rect x="88" y="88" width="148" height="16" fill="#1c1a17"/>
<text x="96" y="100" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">~/vault/ (notes)</text>
<rect x="120" y="124" width="96" height="16" fill="#1c1a17"/>
<text x="128" y="136" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">/business</text>
<rect x="152" y="160" width="108" height="16" fill="#1c1a17"/>
<text x="160" y="172" fill="#f1efe7" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">/marketing</text>
<rect x="184" y="196" width="88" height="16" fill="#1c1a17"/>
<text x="192" y="208" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em" font-weight="600">/project</text>
<!-- File-icon glyphs (simple rect with folded corner) inside each level -->
<g transform="translate(908, 408)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#1c1a17" stroke="rgba(241,239,231,0.35)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(241,239,231,0.35)" stroke-width="1"/>
</g>
<g transform="translate(876, 372)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#1c1a17" stroke="rgba(241,239,231,0.40)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(241,239,231,0.40)" stroke-width="1"/>
</g>
<g transform="translate(844, 336)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#1c1a17" stroke="rgba(241,239,231,0.50)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(241,239,231,0.50)" stroke-width="1"/>
</g>
<g transform="translate(812, 300)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#1c1a17" stroke="#a8a69d" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="#a8a69d" stroke-width="1"/>
</g>
<!-- Innermost label — human readable -->
<text x="500" y="248" fill="#f1efe7" font-size="16" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">CLAUDE.md</text>
<text x="500" y="272" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">inherits every level above</text>
<!-- Annotation top-right: italic callout with curved arrow -->
<text x="904" y="36" fill="#f1efe7" font-size="14" font-style="italic" font-family="'Instrument Serif', serif" text-anchor="end">no imports, no configuration</text>
<path d="M 820 44 Q 700 84 520 216" fill="none" stroke="rgba(241,239,231,0.40)" stroke-width="1" stroke-dasharray="4,3"/>
<circle cx="520" cy="216" r="2" fill="#f1efe7"/>
<!-- Annotation bottom-left: italic callout -->
<text x="40" y="484" fill="#a8a69d" font-size="14" font-style="italic" font-family="'Instrument Serif', serif">structure IS the index</text>
</svg>
</div>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The CLAUDE.md Hierarchy</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Nested · Diagram Design</p>
<h1>The CLAUDE.md Hierarchy</h1>
<p class="subtitle">How Claude Code composes context from every folder level above. Each outer ring is a broader scope; the innermost box is where the work happens — inheriting every instruction above it without a single import statement.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Level 1: ~/.claude/ (global) — outermost -->
<rect x="40" y="60" width="920" height="380" rx="8" fill="rgba(11,13,11,0.015)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<!-- Level 2: ~/vault/ -->
<rect x="72" y="96" width="856" height="308" rx="8" fill="rgba(11,13,11,0.02)" stroke="rgba(11,13,11,0.35)" stroke-width="1"/>
<!-- Level 3: /business -->
<rect x="104" y="132" width="792" height="236" rx="8" fill="rgba(11,13,11,0.025)" stroke="rgba(11,13,11,0.45)" stroke-width="1"/>
<!-- Level 4: /marketing -->
<rect x="136" y="168" width="728" height="164" rx="8" fill="rgba(11,13,11,0.03)" stroke="#52534e" stroke-width="1"/>
<!-- Level 5: /project — innermost, coral focal -->
<rect x="168" y="204" width="664" height="92" rx="8" fill="rgba(247,89,31,0.06)" stroke="#f7591f" stroke-width="1"/>
<!-- Level labels on paper-2-colored masks (match diagram-container bg) -->
<rect x="56" y="52" width="188" height="16" fill="#efeee5"/>
<text x="64" y="64" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">~/.claude/ (global)</text>
<rect x="88" y="88" width="148" height="16" fill="#efeee5"/>
<text x="96" y="100" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">~/vault/ (notes)</text>
<rect x="120" y="124" width="96" height="16" fill="#efeee5"/>
<text x="128" y="136" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">/business</text>
<rect x="152" y="160" width="108" height="16" fill="#efeee5"/>
<text x="160" y="172" fill="#0b0d0b" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">/marketing</text>
<rect x="184" y="196" width="88" height="16" fill="#efeee5"/>
<text x="192" y="208" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em" font-weight="600">/project</text>
<!-- File-icon glyphs inside each level -->
<g transform="translate(908, 408)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#efeee5" stroke="rgba(11,13,11,0.35)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(11,13,11,0.35)" stroke-width="1"/>
</g>
<g transform="translate(876, 372)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#efeee5" stroke="rgba(11,13,11,0.40)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(11,13,11,0.40)" stroke-width="1"/>
</g>
<g transform="translate(844, 336)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#efeee5" stroke="rgba(11,13,11,0.50)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(11,13,11,0.50)" stroke-width="1"/>
</g>
<g transform="translate(812, 300)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#efeee5" stroke="#52534e" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="#52534e" stroke-width="1"/>
</g>
<!-- Innermost label — human readable -->
<text x="500" y="248" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">CLAUDE.md</text>
<text x="500" y="272" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">inherits every level above</text>
<!-- Annotation top-right: italic callout with curved arrow -->
<text x="904" y="36" fill="#0b0d0b" font-size="14" font-style="italic" font-family="'Instrument Serif', serif" text-anchor="end">no imports, no configuration</text>
<path d="M 820 44 Q 700 84 520 216" fill="none" stroke="rgba(11,13,11,0.40)" stroke-width="1" stroke-dasharray="4,3"/>
<circle cx="520" cy="216" r="2" fill="#0b0d0b"/>
<!-- Annotation bottom-left: italic callout -->
<text x="40" y="484" fill="#52534e" font-size="14" font-style="italic" font-family="'Instrument Serif', serif">structure IS the index</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>Containment is the config</h3></div>
<p>Every CLAUDE.md inside a parent folder implicitly wraps the one below. No manifest, no import graph — the file tree itself declares scope, so renaming a folder is the only migration you'll ever run.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Reads outside-in</h3></div>
<ul><li>Global rules load first</li><li>Each parent narrows context</li><li>Innermost file gets the last word</li><li>Conflicts resolve by specificity</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Five levels is the ceiling</h3></div>
<p>Past five rings the diagram stops teaching — and so does the filesystem. If you need six levels of instruction, you probably need two projects instead.</p>
</div>
</div>
<div class="footer">
<span>the claude.md hierarchy · nested containment</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+134
View File
@@ -0,0 +1,134 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The CLAUDE.md Hierarchy</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Nested · Diagram Design</p>
<h1>The CLAUDE.md Hierarchy</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Level 1: ~/.claude/ (global) — outermost -->
<rect x="40" y="60" width="920" height="380" rx="8" fill="rgba(11,13,11,0.015)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<!-- Level 2: ~/vault/ -->
<rect x="72" y="96" width="856" height="308" rx="8" fill="rgba(11,13,11,0.02)" stroke="rgba(11,13,11,0.35)" stroke-width="1"/>
<!-- Level 3: /business -->
<rect x="104" y="132" width="792" height="236" rx="8" fill="rgba(11,13,11,0.025)" stroke="rgba(11,13,11,0.45)" stroke-width="1"/>
<!-- Level 4: /marketing -->
<rect x="136" y="168" width="728" height="164" rx="8" fill="rgba(11,13,11,0.03)" stroke="#52534e" stroke-width="1"/>
<!-- Level 5: /project — innermost, coral focal -->
<rect x="168" y="204" width="664" height="92" rx="8" fill="rgba(247,89,31,0.06)" stroke="#f7591f" stroke-width="1"/>
<!-- Level labels on paper-colored masks -->
<rect x="56" y="52" width="188" height="16" fill="#f5f4ed"/>
<text x="64" y="64" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">~/.claude/ (global)</text>
<rect x="88" y="88" width="148" height="16" fill="#f5f4ed"/>
<text x="96" y="100" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">~/vault/ (notes)</text>
<rect x="120" y="124" width="96" height="16" fill="#f5f4ed"/>
<text x="128" y="136" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">/business</text>
<rect x="152" y="160" width="108" height="16" fill="#f5f4ed"/>
<text x="160" y="172" fill="#0b0d0b" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">/marketing</text>
<rect x="184" y="196" width="88" height="16" fill="#f5f4ed"/>
<text x="192" y="208" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em" font-weight="600">/project</text>
<!-- File-icon glyphs (simple rect with folded corner) inside each level -->
<!-- Glyph in level 1 (bottom-right area of outer ring) -->
<g transform="translate(908, 408)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#f5f4ed" stroke="rgba(11,13,11,0.35)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(11,13,11,0.35)" stroke-width="1"/>
</g>
<!-- Glyph in level 2 ring -->
<g transform="translate(876, 372)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#f5f4ed" stroke="rgba(11,13,11,0.40)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(11,13,11,0.40)" stroke-width="1"/>
</g>
<!-- Glyph in level 3 ring -->
<g transform="translate(844, 336)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#f5f4ed" stroke="rgba(11,13,11,0.50)" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="rgba(11,13,11,0.50)" stroke-width="1"/>
</g>
<!-- Glyph in level 4 ring -->
<g transform="translate(812, 300)">
<path d="M0 0 L16 0 L20 4 L20 20 L0 20 Z" fill="#f5f4ed" stroke="#52534e" stroke-width="1"/>
<path d="M16 0 L16 4 L20 4" fill="none" stroke="#52534e" stroke-width="1"/>
</g>
<!-- Innermost label — human readable -->
<text x="500" y="248" fill="#0b0d0b" font-size="16" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">CLAUDE.md</text>
<text x="500" y="272" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">inherits every level above</text>
<!-- Annotation top-right: italic callout with curved arrow -->
<text x="904" y="36" fill="#0b0d0b" font-size="14" font-style="italic" font-family="'Instrument Serif', serif" text-anchor="end">no imports, no configuration</text>
<path d="M 820 44 Q 700 84 520 216" fill="none" stroke="rgba(11,13,11,0.40)" stroke-width="1" stroke-dasharray="4,3"/>
<circle cx="520" cy="216" r="2" fill="#0b0d0b"/>
<!-- Annotation bottom-left: italic callout -->
<text x="40" y="484" fill="#52534e" font-size="14" font-style="italic" font-family="'Instrument Serif', serif">structure IS the index</text>
</svg>
</div>
</body>
</html>
+117
View File
@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content pyramid · what compounds</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Pyramid · Diagram Design</p>
<h1>Content pyramid · what compounds</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Left axis: direction of rarity -->
<line x1="100" y1="112" x2="100" y2="320" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<polygon points="96,112 104,112 100,100" fill="rgba(241,239,231,0.45)"/>
<text x="80" y="216" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="middle" transform="rotate(-90 80 216)">RARER · FEWER · COMPOUNDS ↑</text>
<!-- Base layer: Short posts -->
<polygon points="240,280 760,280 820,344 180,344" fill="rgba(241,239,231,0.04)" stroke="rgba(241,239,231,0.12)" stroke-width="1"/>
<text x="500" y="308" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Short posts</text>
<text x="500" y="324" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">daily · ~200 words</text>
<text x="836" y="316" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~240/yr</text>
<!-- L3: Essays -->
<polygon points="300,216 700,216 760,280 240,280" fill="rgba(241,239,231,0.04)" stroke="rgba(241,239,231,0.12)" stroke-width="1"/>
<text x="500" y="244" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Essays</text>
<text x="500" y="260" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">weekly · 800–1,500 words</text>
<text x="776" y="252" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~48/yr</text>
<!-- L2: Long-form guides -->
<polygon points="360,152 640,152 700,216 300,216" fill="rgba(241,239,231,0.04)" stroke="rgba(241,239,231,0.12)" stroke-width="1"/>
<text x="500" y="180" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Long-form guides</text>
<text x="500" y="196" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">quarterly · 4,000+ words</text>
<text x="716" y="188" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~4/yr</text>
<!-- Apex: Flagship book — CORAL FOCAL (triangle, pointed) -->
<polygon points="500,76 640,152 360,152" fill="rgba(255,106,48,0.10)" stroke="#ff6a30" stroke-width="1"/>
<text x="500" y="120" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Flagship book</text>
<text x="500" y="136" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">every 3–5 years</text>
<text x="656" y="112" fill="#ff6a30" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">the apex</text>
<!-- Footnote under pyramid -->
<text x="500" y="384" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif" text-anchor="middle" font-style="italic">The base funds the apex. The apex defines the base.</text>
<!-- Legend -->
<line x1="40" y1="436" x2="960" y2="436" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="452" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="464" width="16" height="12" fill="rgba(255,106,48,0.10)" stroke="#ff6a30" stroke-width="1"/>
<text x="64" y="474" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Apex — rarest, highest leverage</text>
<rect x="280" y="464" width="16" height="12" fill="rgba(241,239,231,0.04)" stroke="rgba(241,239,231,0.25)" stroke-width="1"/>
<text x="304" y="474" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Supporting layer — the volume work</text>
<text x="560" y="474" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Layer width is honest: narrower = rarer shipping cadence.</text>
</svg>
</div>
</body>
</html>
+120
View File
@@ -0,0 +1,120 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content pyramid · what compounds</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Pyramid · Diagram Design</p>
<h1>Content pyramid · what compounds</h1>
<p class="subtitle">Four layers of output, ordered by how rarely they ship and how far they travel. The base keeps you present. The apex defines the body of work — and it's the only layer anyone quotes back a decade later.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Left axis: direction of rarity -->
<line x1="100" y1="112" x2="100" y2="320" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<polygon points="96,112 104,112 100,100" fill="rgba(11,13,11,0.45)"/>
<text x="80" y="216" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="middle" transform="rotate(-90 80 216)">RARER · FEWER · COMPOUNDS ↑</text>
<!-- Base layer: Short posts -->
<polygon points="240,280 760,280 820,344 180,344" fill="#efeee5" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="500" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Short posts</text>
<text x="500" y="324" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">daily · ~200 words</text>
<text x="836" y="316" fill="#65655c" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~240/yr</text>
<!-- L3: Essays -->
<polygon points="300,216 700,216 760,280 240,280" fill="#efeee5" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="500" y="244" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Essays</text>
<text x="500" y="260" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">weekly · 800–1,500 words</text>
<text x="776" y="252" fill="#65655c" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~48/yr</text>
<!-- L2: Long-form guides -->
<polygon points="360,152 640,152 700,216 300,216" fill="#efeee5" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="500" y="180" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Long-form guides</text>
<text x="500" y="196" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">quarterly · 4,000+ words</text>
<text x="716" y="188" fill="#65655c" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~4/yr</text>
<!-- Apex: Flagship book — CORAL FOCAL (triangle, pointed) -->
<polygon points="500,76 640,152 360,152" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="500" y="120" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Flagship book</text>
<text x="500" y="136" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">every 3–5 years</text>
<text x="656" y="112" fill="#f7591f" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">the apex</text>
<!-- Footnote under pyramid -->
<text x="500" y="384" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" text-anchor="middle" font-style="italic">The base funds the apex. The apex defines the base.</text>
<!-- Legend -->
<line x1="40" y1="436" x2="960" y2="436" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="452" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="464" width="16" height="12" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="64" y="474" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Apex — rarest, highest leverage</text>
<rect x="280" y="464" width="16" height="12" fill="#efeee5" stroke="rgba(11,13,11,0.25)" stroke-width="1"/>
<text x="304" y="474" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Supporting layer — the volume work</text>
<text x="560" y="474" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Layer width is honest: narrower = rarer shipping cadence.</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>One coral layer, on purpose</h3></div>
<p>A five-colour pyramid is a children's diagram. Reserving coral for the apex makes the whole structure actually say something: this is the rarest thing you'll make, and it's the one the rest of the pyramid is feeding.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Width tells the truth</h3></div>
<ul><li>~240 short posts a year</li><li>~48 essays</li><li>~4 long-form guides</li><li>1 flagship every 3–5 years</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Pyramids only work for hierarchy</h3></div>
<p>If your four categories don't have a rarity order — if a bullet list would communicate it — use bullets. Pyramids promise you're trading volume for value as you climb.</p>
</div>
</div>
<div class="footer">
<span>content pyramid · what compounds</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+117
View File
@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content pyramid · what compounds</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Pyramid · Diagram Design</p>
<h1>Content pyramid · what compounds</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Left axis: direction of rarity -->
<line x1="100" y1="112" x2="100" y2="320" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<polygon points="96,112 104,112 100,100" fill="rgba(11,13,11,0.45)"/>
<text x="80" y="216" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="middle" transform="rotate(-90 80 216)">RARER · FEWER · COMPOUNDS ↑</text>
<!-- Base layer: Short posts -->
<polygon points="240,280 760,280 820,344 180,344" fill="#efeee5" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="500" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Short posts</text>
<text x="500" y="324" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">daily · ~200 words</text>
<text x="836" y="316" fill="#65655c" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~240/yr</text>
<!-- L3: Essays -->
<polygon points="300,216 700,216 760,280 240,280" fill="#efeee5" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="500" y="244" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Essays</text>
<text x="500" y="260" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">weekly · 800–1,500 words</text>
<text x="776" y="252" fill="#65655c" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~48/yr</text>
<!-- L2: Long-form guides -->
<polygon points="360,152 640,152 700,216 300,216" fill="#efeee5" stroke="rgba(11,13,11,0.12)" stroke-width="1"/>
<text x="500" y="180" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Long-form guides</text>
<text x="500" y="196" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">quarterly · 4,000+ words</text>
<text x="716" y="188" fill="#65655c" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">~4/yr</text>
<!-- Apex: Flagship book — CORAL FOCAL (triangle, pointed) -->
<polygon points="500,76 640,152 360,152" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="500" y="120" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Flagship book</text>
<text x="500" y="136" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">every 3–5 years</text>
<text x="656" y="112" fill="#f7591f" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.08em">the apex</text>
<!-- Footnote under pyramid -->
<text x="500" y="384" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" text-anchor="middle" font-style="italic">The base funds the apex. The apex defines the base.</text>
<!-- Legend -->
<line x1="40" y1="436" x2="960" y2="436" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="452" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="464" width="16" height="12" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="64" y="474" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Apex — rarest, highest leverage</text>
<rect x="280" y="464" width="16" height="12" fill="#efeee5" stroke="rgba(11,13,11,0.25)" stroke-width="1"/>
<text x="304" y="474" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Supporting layer — the volume work</text>
<text x="560" y="474" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Layer width is honest: narrower = rarer shipping cadence.</text>
</svg>
</div>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content ideas · Impact × Effort</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Quadrant · Diagram Design</p>
<h1>Content ideas · Impact × Effort</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Quadrant backgrounds (very subtle, only coral on DO FIRST) -->
<rect x="120" y="80" width="380" height="170" fill="rgba(255,106,48,0.03)"/>
<!-- Axis cross -->
<line x1="120" y1="250" x2="880" y2="250" stroke="rgba(241,239,231,0.45)" stroke-width="1"/>
<line x1="500" y1="80" x2="500" y2="420" stroke="rgba(241,239,231,0.45)" stroke-width="1"/>
<!-- Axis end labels -->
<text x="880" y="266" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.14em">HIGH EFFORT →</text>
<text x="120" y="266" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">← LOW EFFORT</text>
<text x="512" y="80" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">↑ HIGH IMPACT</text>
<text x="512" y="432" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">↓ LOW IMPACT</text>
<!-- Quadrant corner labels -->
<text x="140" y="104" fill="#ff6a30" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em" font-weight="600">DO FIRST</text>
<text x="860" y="104" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.18em">MAJOR PROJECTS</text>
<text x="140" y="412" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">QUICK WINS</text>
<text x="860" y="412" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.18em">AVOID</text>
<!-- Items: TL (Do First) -->
<!-- coral focal -->
<circle cx="220" cy="140" r="6" fill="#ff6a30"/>
<text x="232" y="144" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif">diagram-design</text>
<circle cx="320" cy="200" r="4" fill="#f1efe7"/>
<text x="332" y="204" fill="#a8a69d" font-size="11" font-family="'Geist', sans-serif">Update changelog</text>
<!-- Items: TR (Major Projects) -->
<circle cx="620" cy="140" r="4" fill="#f1efe7"/>
<text x="632" y="144" fill="#a8a69d" font-size="11" font-family="'Geist', sans-serif">Design v4 refresh</text>
<circle cx="760" cy="180" r="4" fill="#f1efe7"/>
<text x="772" y="184" fill="#a8a69d" font-size="11" font-family="'Geist', sans-serif">New publication</text>
<!-- Items: BL (Quick Wins) -->
<circle cx="260" cy="320" r="4" fill="#f1efe7"/>
<text x="272" y="324" fill="#a8a69d" font-size="11" font-family="'Geist', sans-serif">Fix footer link</text>
<circle cx="360" cy="380" r="4" fill="#f1efe7"/>
<text x="372" y="384" fill="#a8a69d" font-size="11" font-family="'Geist', sans-serif">Update OG tags</text>
<!-- Items: BR (Avoid) -->
<circle cx="640" cy="380" r="4" fill="#f1efe7"/>
<text x="652" y="384" fill="#a8a69d" font-size="11" font-family="'Geist', sans-serif">Rewrite build pipeline</text>
<circle cx="780" cy="320" r="4" fill="#f1efe7"/>
<text x="792" y="324" fill="#a8a69d" font-size="11" font-family="'Geist', sans-serif">Port to Nuxt</text>
<!-- Legend -->
<line x1="40" y1="456" x2="960" y2="456" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="472" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="488" r="6" fill="#ff6a30"/>
<text x="68" y="492" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Start tomorrow</text>
<circle cx="192" cy="488" r="4" fill="#f1efe7"/>
<text x="208" y="492" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Candidate project</text>
<text x="336" y="492" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Position is the signal. Colour is reserved for the single action item.</text>
</svg>
</div>
</body>
</html>
+136
View File
@@ -0,0 +1,136 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content ideas · Impact × Effort</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Quadrant · Diagram Design</p>
<h1>Content ideas · Impact × Effort</h1>
<p class="subtitle">Eight candidate projects mapped by the pay-off they'd generate against the cost to ship. Position is the signal — color is reserved for the one item worth starting tomorrow.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Quadrant backgrounds (very subtle, only coral on DO FIRST) -->
<rect x="120" y="80" width="380" height="170" fill="rgba(247,89,31,0.03)"/>
<!-- Axis cross -->
<line x1="120" y1="250" x2="880" y2="250" stroke="rgba(11,13,11,0.45)" stroke-width="1"/>
<line x1="500" y1="80" x2="500" y2="420" stroke="rgba(11,13,11,0.45)" stroke-width="1"/>
<!-- Axis end labels -->
<text x="880" y="266" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.14em">HIGH EFFORT →</text>
<text x="120" y="266" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">← LOW EFFORT</text>
<text x="512" y="80" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">↑ HIGH IMPACT</text>
<text x="512" y="432" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">↓ LOW IMPACT</text>
<!-- Quadrant corner labels -->
<text x="140" y="104" fill="#f7591f" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em" font-weight="600">DO FIRST</text>
<text x="860" y="104" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.18em">MAJOR PROJECTS</text>
<text x="140" y="412" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">QUICK WINS</text>
<text x="860" y="412" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.18em">AVOID</text>
<!-- Items: TL (Do First) -->
<!-- coral focal -->
<circle cx="220" cy="140" r="6" fill="#f7591f"/>
<text x="232" y="144" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif">diagram-design</text>
<circle cx="320" cy="200" r="4" fill="#0b0d0b"/>
<text x="332" y="204" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Update changelog</text>
<!-- Items: TR (Major Projects) -->
<circle cx="620" cy="140" r="4" fill="#0b0d0b"/>
<text x="632" y="144" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Design v4 refresh</text>
<circle cx="760" cy="180" r="4" fill="#0b0d0b"/>
<text x="772" y="184" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">New publication</text>
<!-- Items: BL (Quick Wins) -->
<circle cx="260" cy="320" r="4" fill="#0b0d0b"/>
<text x="272" y="324" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Fix footer link</text>
<circle cx="360" cy="380" r="4" fill="#0b0d0b"/>
<text x="372" y="384" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Update OG tags</text>
<!-- Items: BR (Avoid) -->
<circle cx="640" cy="380" r="4" fill="#0b0d0b"/>
<text x="652" y="384" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Rewrite build pipeline</text>
<circle cx="780" cy="320" r="4" fill="#0b0d0b"/>
<text x="792" y="324" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Port to Nuxt</text>
<!-- Legend -->
<line x1="40" y1="456" x2="960" y2="456" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="472" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="488" r="6" fill="#f7591f"/>
<text x="68" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Start tomorrow</text>
<circle cx="192" cy="488" r="4" fill="#0b0d0b"/>
<text x="208" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Candidate project</text>
<text x="336" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Position is the signal. Colour is reserved for the single action item.</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>One coral dot, on purpose</h3></div>
<p>A 2×2 with four coloured quadrants is a poster, not a decision tool. Reserving coral for the single item you commit to tomorrow makes the matrix actually prioritise.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Axes labelled at ends</h3></div>
<ul><li>HIGH / LOW at the extremes</li><li>Arrows show direction</li><li>No labels at midpoints</li><li>The cross is 1px ink, not a box</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Empty BR isn't wasted</h3></div>
<p>Two items in "Avoid" is informative — it says the team considered them and rejected them. A blank quadrant would leave you wondering.</p>
</div>
</div>
<div class="footer">
<span>content ideas · impact × effort</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content ideas · Impact × Effort</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Quadrant · Diagram Design</p>
<h1>Content ideas · Impact × Effort</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Quadrant backgrounds (very subtle, only coral on DO FIRST) -->
<rect x="120" y="80" width="380" height="170" fill="rgba(247,89,31,0.03)"/>
<!-- Axis cross -->
<line x1="120" y1="250" x2="880" y2="250" stroke="rgba(11,13,11,0.45)" stroke-width="1"/>
<line x1="500" y1="80" x2="500" y2="420" stroke="rgba(11,13,11,0.45)" stroke-width="1"/>
<!-- Axis end labels -->
<text x="880" y="266" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.14em">HIGH EFFORT →</text>
<text x="120" y="266" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">← LOW EFFORT</text>
<text x="512" y="80" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">↑ HIGH IMPACT</text>
<text x="512" y="432" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.14em">↓ LOW IMPACT</text>
<!-- Quadrant corner labels -->
<text x="140" y="104" fill="#f7591f" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em" font-weight="600">DO FIRST</text>
<text x="860" y="104" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.18em">MAJOR PROJECTS</text>
<text x="140" y="412" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">QUICK WINS</text>
<text x="860" y="412" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.18em">AVOID</text>
<!-- Items: TL (Do First) -->
<!-- coral focal -->
<circle cx="220" cy="140" r="6" fill="#f7591f"/>
<text x="232" y="144" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif">diagram-design</text>
<circle cx="320" cy="200" r="4" fill="#0b0d0b"/>
<text x="332" y="204" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Update changelog</text>
<!-- Items: TR (Major Projects) -->
<circle cx="620" cy="140" r="4" fill="#0b0d0b"/>
<text x="632" y="144" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Design v4 refresh</text>
<circle cx="760" cy="180" r="4" fill="#0b0d0b"/>
<text x="772" y="184" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">New publication</text>
<!-- Items: BL (Quick Wins) -->
<circle cx="260" cy="320" r="4" fill="#0b0d0b"/>
<text x="272" y="324" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Fix footer link</text>
<circle cx="360" cy="380" r="4" fill="#0b0d0b"/>
<text x="372" y="384" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Update OG tags</text>
<!-- Items: BR (Avoid) -->
<circle cx="640" cy="380" r="4" fill="#0b0d0b"/>
<text x="652" y="384" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Rewrite build pipeline</text>
<circle cx="780" cy="320" r="4" fill="#0b0d0b"/>
<text x="792" y="324" fill="#52534e" font-size="11" font-family="'Geist', sans-serif">Port to Nuxt</text>
<!-- Legend -->
<line x1="40" y1="456" x2="960" y2="456" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="472" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="488" r="6" fill="#f7591f"/>
<text x="68" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Start tomorrow</text>
<circle cx="192" cy="488" r="4" fill="#0b0d0b"/>
<text x="208" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Candidate project</text>
<text x="336" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Position is the signal. Colour is reserved for the single action item.</text>
</svg>
</div>
</body>
</html>
+220
View File
@@ -0,0 +1,220 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Article request · Sequence</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Sequence · Diagram Design</p>
<h1>Article request, cold cache</h1>
<svg viewBox="0 0 1000 584" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- Dot grid background -->
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
<!-- Arrow markers -->
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#a8a69d"/>
</marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#ff6a30"/>
</marker>
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#5ba8eb"/>
</marker>
</defs>
<!-- Background: paper + dot grid -->
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- =================================================================
LIFELINES — dashed vertical lines from each actor, behind everything.
Actor lifeline x-coords: 128, 352, 584, 800
================================================================= -->
<line x1="128" y1="128" x2="128" y2="488" stroke="rgba(241,239,231,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="352" y1="128" x2="352" y2="488" stroke="rgba(241,239,231,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="584" y1="128" x2="584" y2="488" stroke="rgba(241,239,231,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="800" y1="128" x2="800" y2="488" stroke="rgba(241,239,231,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<!-- =================================================================
ACTIVATION BARS — w=8 rects on lifelines showing control duration.
Drawn before message arrows so arrows land on their edges.
================================================================= -->
<!-- Cloudflare activation: receives at y=176, responds at y=408 -->
<rect x="348" y="180" width="8" height="232" fill="rgba(241,239,231,0.06)" stroke="#a8a69d" stroke-width="0.8"/>
<!-- Astro activation: called at y=232, returns at y=352 -->
<rect x="580" y="236" width="8" height="120" fill="rgba(241,239,231,0.06)" stroke="#a8a69d" stroke-width="0.8"/>
<!-- =================================================================
MESSAGE ARROWS — time flows top→down.
Draw before labels so label masks cover the line.
================================================================= -->
<!-- M1: Reader → Cloudflare (HTTPS request · link-blue) -->
<line x1="128" y1="176" x2="352" y2="176" stroke="#5ba8eb" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<!-- M2: Cloudflare → Astro (cache miss · muted) -->
<line x1="352" y1="232" x2="580" y2="232" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- M3: Astro self-message (render MDX · muted U-loop) -->
<path d="M 588 284 L 624 284 L 624 316 L 588 316" fill="none" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- M4: Astro → Cloudflare (return HTML · muted dashed) -->
<line x1="580" y1="352" x2="356" y2="352" stroke="#a8a69d" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- M5: Cloudflare → Reader (primary success · coral) -->
<line x1="348" y1="408" x2="128" y2="408" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- M6: Reader → Analytics (async beacon · muted dashed) -->
<line x1="128" y1="464" x2="800" y2="464" stroke="#a8a69d" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- =================================================================
MESSAGE LABELS — each with an opaque paper-colored mask.
================================================================= -->
<!-- M1 label -->
<rect x="188" y="160" width="104" height="12" rx="2" fill="#1c1a17"/>
<text x="240" y="170" fill="#5ba8eb" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">GET /ARTICLES/SLUG</text>
<!-- M2 label -->
<rect x="416" y="216" width="100" height="12" rx="2" fill="#1c1a17"/>
<text x="466" y="226" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CACHE MISS · ORIGIN</text>
<!-- M3 label (to the right of the self-loop) -->
<rect x="632" y="292" width="72" height="12" rx="2" fill="#1c1a17"/>
<text x="668" y="302" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">RENDER MDX</text>
<!-- M4 label -->
<rect x="420" y="336" width="96" height="12" rx="2" fill="#1c1a17"/>
<text x="468" y="346" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">200 · HTML + MAX-AGE</text>
<!-- M5 label (coral · primary response) -->
<rect x="192" y="392" width="96" height="12" rx="2" fill="#1c1a17"/>
<text x="240" y="402" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">200 · EDGE-CACHED</text>
<!-- M6 label (placed between Astro and Analytics lifelines, a clear gap) -->
<rect x="648" y="448" width="96" height="12" rx="2" fill="#1c1a17"/>
<text x="696" y="458" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PAGEVIEW BEACON</text>
<!-- =================================================================
ACTOR BOXES — drawn after arrows/labels.
Each actor: 144–160 wide × 56 tall. Centers: 128, 352, 584, 800.
================================================================= -->
<!-- Actor 1: Reader (external / soft) -->
<rect x="56" y="72" width="144" height="56" rx="6" fill="#1c1a17"/>
<rect x="56" y="72" width="144" height="56" rx="6" fill="rgba(168,166,157,0.10)" stroke="#8e8c83" stroke-width="1"/>
<rect x="64" y="80" width="28" height="12" rx="2" fill="transparent" stroke="rgba(142,140,131,0.40)" stroke-width="0.8"/>
<text x="78" y="89" fill="#8e8c83" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
<text x="128" y="104" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reader</text>
<text x="128" y="119" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser</text>
<!-- Actor 2: Cloudflare (cloud / muted) -->
<rect x="280" y="72" width="144" height="56" rx="6" fill="#1c1a17"/>
<rect x="280" y="72" width="144" height="56" rx="6" fill="rgba(241,239,231,0.03)" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<rect x="288" y="80" width="32" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.22)" stroke-width="0.8"/>
<text x="304" y="89" fill="#8e8c83" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EDGE</text>
<text x="352" y="104" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Cloudflare</text>
<text x="352" y="119" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Pages · cache</text>
<!-- Actor 3: Astro Origin (focal / coral) -->
<rect x="504" y="72" width="160" height="56" rx="6" fill="#1c1a17"/>
<rect x="504" y="72" width="160" height="56" rx="6" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<rect x="512" y="80" width="32" height="12" rx="2" fill="transparent" stroke="rgba(255,106,48,0.50)" stroke-width="0.8"/>
<text x="528" y="89" fill="#ff6a30" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ORIG</text>
<text x="584" y="104" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Astro Origin</text>
<text x="584" y="119" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">SSR + MDX</text>
<!-- Actor 4: Analytics (optional / dashed) -->
<rect x="728" y="72" width="144" height="56" rx="6" fill="#1c1a17"/>
<rect x="728" y="72" width="144" height="56" rx="6" fill="rgba(241,239,231,0.02)" stroke="rgba(241,239,231,0.22)" stroke-width="1" stroke-dasharray="4,3"/>
<rect x="736" y="80" width="28" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.22)" stroke-width="0.8"/>
<text x="750" y="89" fill="#8e8c83" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ASY</text>
<text x="800" y="104" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Analytics</text>
<text x="800" y="119" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Beacon · async</text>
<!-- =================================================================
LEGEND — horizontal strip at the bottom.
Separator at y=504, eyebrow at y=520, items at y=540–548.
================================================================= -->
<line x1="56" y1="504" x2="944" y2="504" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="56" y="520" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<!-- Item 1: Actor swatch (coral focal) -->
<rect x="56" y="540" width="14" height="10" rx="2" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<text x="76" y="548" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Focal actor</text>
<!-- Item 2: Activation bar swatch -->
<rect x="188" y="536" width="4" height="18" fill="rgba(241,239,231,0.06)" stroke="#a8a69d" stroke-width="0.8"/>
<text x="200" y="548" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Activation</text>
<!-- Item 3: Request arrow (link-blue) -->
<line x1="308" y1="546" x2="336" y2="546" stroke="#5ba8eb" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="344" y="548" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">HTTP request</text>
<!-- Item 4: Return / async (muted dashed) -->
<line x1="476" y1="546" x2="504" y2="546" stroke="#a8a69d" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<text x="512" y="548" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Return / async</text>
<!-- Item 5: Primary response (coral) -->
<line x1="652" y1="546" x2="680" y2="546" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="688" y="548" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Primary response</text>
</svg>
</div>
</body>
</html>
+386
View File
@@ -0,0 +1,386 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Article Request · Sequence</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-paper-2: #efeee5;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-soft: #65655c;
--color-rule: rgba(11,13,11,0.12);
--color-rule-solid: rgba(135,139,134,0.25);
--color-accent: #f7591f;
--color-accent-tint: rgba(247,89,31,0.08);
--color-link: #1a70c7;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', 'Times New Roman', serif;
--font-mono: 'Geist Mono', ui-monospace, Menlo, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
min-height: 100vh;
padding: 3rem 2rem;
color: var(--color-ink);
}
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.75rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.1;
color: var(--color-ink);
margin-bottom: 0.5rem;
}
.subtitle {
font-family: var(--font-sans);
font-size: 1rem;
line-height: 1.55;
color: var(--color-muted);
max-width: 58ch;
}
.diagram-container {
background: var(--color-paper-2);
border-radius: 8px;
border: 1px solid var(--color-rule);
padding: 1.5rem;
overflow-x: auto;
}
svg { width: 100%; min-width: 900px; display: block; }
.cards {
display: grid;
grid-template-columns: 1.1fr 1fr 0.9fr;
gap: 1rem;
margin-top: 1.5rem;
}
@media (max-width: 820px) {
.cards { grid-template-columns: 1fr; }
}
.card {
background: #ffffff;
border-radius: 6px;
border: 1px solid var(--color-rule);
padding: 1.25rem;
}
.card .eyebrow {
font-family: var(--font-mono);
font-size: 0.5rem;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
.card-header {
display: flex;
align-items: center;
gap: 0.6rem;
margin-bottom: 0.875rem;
padding-bottom: 0.875rem;
border-bottom: 1px solid rgba(11,13,11,0.08);
}
.card-dot {
width: 7px; height: 7px;
border-radius: 50%;
flex-shrink: 0;
}
.card-dot.ink { background: var(--color-ink); }
.card-dot.muted { background: var(--color-muted); }
.card-dot.coral { background: var(--color-accent); }
.card-dot.link { background: var(--color-link); }
.card h3 {
font-family: var(--font-sans);
font-size: 0.875rem;
font-weight: 600;
color: var(--color-ink);
letter-spacing: -0.005em;
}
.card p {
color: var(--color-muted);
font-size: 0.8125rem;
line-height: 1.55;
}
.card ul {
list-style: none;
color: var(--color-muted);
font-size: 0.8125rem;
line-height: 1.55;
}
.card li {
margin-bottom: 0.3rem;
padding-left: 0.875rem;
position: relative;
}
.card li::before {
content: '—';
position: absolute;
left: 0;
color: rgba(11,13,11,0.25);
font-size: 0.75rem;
}
.footer {
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid rgba(11,13,11,0.10);
font-family: var(--font-mono);
font-size: 0.72rem;
letter-spacing: 0.06em;
color: var(--color-soft);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<div class="header">
<p class="header-eyebrow">Sequence · Diagram Design</p>
<h1>Article request, cold cache</h1>
<p class="subtitle">How littlemight.com serves a reader when the requested slug isn't already sitting in Cloudflare's edge cache — origin render, beacon, and back in one round trip.</p>
</div>
<!-- Sequence Diagram -->
<div class="diagram-container">
<svg viewBox="0 0 1000 584" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- Dot grid background -->
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<!-- Arrow markers -->
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#52534e"/>
</marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#f7591f"/>
</marker>
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#1a70c7"/>
</marker>
</defs>
<!-- Background: paper + dot grid -->
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- =================================================================
LIFELINES — dashed vertical lines from each actor, behind everything.
Actor lifeline x-coords: 128, 352, 584, 800
================================================================= -->
<line x1="128" y1="128" x2="128" y2="488" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="352" y1="128" x2="352" y2="488" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="584" y1="128" x2="584" y2="488" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="800" y1="128" x2="800" y2="488" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<!-- =================================================================
ACTIVATION BARS — w=8 rects on lifelines showing control duration.
Drawn before message arrows so arrows land on their edges.
================================================================= -->
<!-- Cloudflare activation: receives at y=176, responds at y=408 -->
<rect x="348" y="180" width="8" height="232" fill="rgba(11,13,11,0.06)" stroke="#52534e" stroke-width="0.8"/>
<!-- Astro activation: called at y=232, returns at y=352 -->
<rect x="580" y="236" width="8" height="120" fill="rgba(11,13,11,0.06)" stroke="#52534e" stroke-width="0.8"/>
<!-- =================================================================
MESSAGE ARROWS — time flows top→down.
Draw before labels so label masks cover the line.
================================================================= -->
<!-- M1: Reader → Cloudflare (HTTPS request · link-blue) -->
<line x1="128" y1="176" x2="352" y2="176" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<!-- M2: Cloudflare → Astro (cache miss · muted) -->
<line x1="352" y1="232" x2="580" y2="232" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- M3: Astro self-message (render MDX · muted U-loop) -->
<path d="M 588 284 L 624 284 L 624 316 L 588 316" fill="none" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- M4: Astro → Cloudflare (return HTML · muted dashed) -->
<line x1="580" y1="352" x2="356" y2="352" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- M5: Cloudflare → Reader (primary success · coral) -->
<line x1="348" y1="408" x2="128" y2="408" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- M6: Reader → Analytics (async beacon · muted dashed) -->
<line x1="128" y1="464" x2="800" y2="464" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- =================================================================
MESSAGE LABELS — each with an opaque paper-colored mask.
================================================================= -->
<!-- M1 label -->
<rect x="188" y="160" width="104" height="12" rx="2" fill="#f5f4ed"/>
<text x="240" y="170" fill="#1a70c7" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">GET /ARTICLES/SLUG</text>
<!-- M2 label -->
<rect x="416" y="216" width="100" height="12" rx="2" fill="#f5f4ed"/>
<text x="466" y="226" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CACHE MISS · ORIGIN</text>
<!-- M3 label (to the right of the self-loop) -->
<rect x="632" y="292" width="72" height="12" rx="2" fill="#f5f4ed"/>
<text x="668" y="302" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">RENDER MDX</text>
<!-- M4 label -->
<rect x="420" y="336" width="96" height="12" rx="2" fill="#f5f4ed"/>
<text x="468" y="346" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">200 · HTML + MAX-AGE</text>
<!-- M5 label (coral · primary response) -->
<rect x="192" y="392" width="96" height="12" rx="2" fill="#f5f4ed"/>
<text x="240" y="402" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">200 · EDGE-CACHED</text>
<!-- M6 label (placed between Astro and Analytics lifelines, a clear gap) -->
<rect x="648" y="448" width="96" height="12" rx="2" fill="#f5f4ed"/>
<text x="696" y="458" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PAGEVIEW BEACON</text>
<!-- =================================================================
ACTOR BOXES — drawn after arrows/labels.
Each actor: 144–160 wide × 56 tall. Centers: 128, 352, 584, 800.
================================================================= -->
<!-- Actor 1: Reader (external / soft) -->
<rect x="56" y="72" width="144" height="56" rx="6" fill="#f5f4ed"/>
<rect x="56" y="72" width="144" height="56" rx="6" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<rect x="64" y="80" width="28" height="12" rx="2" fill="transparent" stroke="rgba(101,101,92,0.40)" stroke-width="0.8"/>
<text x="78" y="89" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
<text x="128" y="104" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reader</text>
<text x="128" y="119" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser</text>
<!-- Actor 2: Cloudflare (cloud / muted) -->
<rect x="280" y="72" width="144" height="56" rx="6" fill="#f5f4ed"/>
<rect x="280" y="72" width="144" height="56" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<rect x="288" y="80" width="32" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="304" y="89" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EDGE</text>
<text x="352" y="104" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Cloudflare</text>
<text x="352" y="119" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Pages · cache</text>
<!-- Actor 3: Astro Origin (focal / coral) -->
<rect x="504" y="72" width="160" height="56" rx="6" fill="#f5f4ed"/>
<rect x="504" y="72" width="160" height="56" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="512" y="80" width="32" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="528" y="89" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ORIG</text>
<text x="584" y="104" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Astro Origin</text>
<text x="584" y="119" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">SSR + MDX</text>
<!-- Actor 4: Analytics (optional / dashed) -->
<rect x="728" y="72" width="144" height="56" rx="6" fill="#f5f4ed"/>
<rect x="728" y="72" width="144" height="56" rx="6" fill="rgba(11,13,11,0.02)" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="4,3"/>
<rect x="736" y="80" width="28" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="750" y="89" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ASY</text>
<text x="800" y="104" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Analytics</text>
<text x="800" y="119" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Beacon · async</text>
<!-- =================================================================
LEGEND — horizontal strip at the bottom.
Separator at y=504, eyebrow at y=520, items at y=540–548.
================================================================= -->
<line x1="56" y1="504" x2="944" y2="504" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="56" y="520" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<!-- Item 1: Actor swatch (coral focal) -->
<rect x="56" y="540" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="76" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Focal actor</text>
<!-- Item 2: Activation bar swatch -->
<rect x="188" y="536" width="4" height="18" fill="rgba(11,13,11,0.06)" stroke="#52534e" stroke-width="0.8"/>
<text x="200" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Activation</text>
<!-- Item 3: Request arrow (link-blue) -->
<line x1="308" y1="546" x2="336" y2="546" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="344" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">HTTP request</text>
<!-- Item 4: Return / async (muted dashed) -->
<line x1="476" y1="546" x2="504" y2="546" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<text x="512" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Return / async</text>
<!-- Item 5: Primary response (coral) -->
<line x1="652" y1="546" x2="680" y2="546" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="688" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Primary response</text>
</svg>
</div>
<!-- Summary cards -->
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header">
<span class="card-dot coral"></span>
<h3>Edge handles the hot path</h3>
</div>
<p>On subsequent reads the whole exchange collapses to M1 → M5. Cloudflare serves the cached HTML without waking the origin. The coral arrow is the only one the reader ever perceives.</p>
</div>
<div class="card">
<div class="card-header">
<span class="card-dot ink"></span>
<h3>Origin render on miss</h3>
</div>
<ul>
<li>Astro SSRs MDX on cold cache</li>
<li>Returns HTML + cache headers</li>
<li>Edge stores the result</li>
<li>Next reader skips the origin trip</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<span class="card-dot muted"></span>
<h3>Analytics is fire-and-forget</h3>
</div>
<p>The pageview beacon is dashed for a reason: the reader never waits on it, and a failed beacon never breaks the page.</p>
</div>
</div>
<!-- Footer -->
<div class="footer">
<span>littlemight.com · article request sequence</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+220
View File
@@ -0,0 +1,220 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Article request · Sequence</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Sequence · Diagram Design</p>
<h1>Article request, cold cache</h1>
<svg viewBox="0 0 1000 584" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- Dot grid background -->
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<!-- Arrow markers -->
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#52534e"/>
</marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#f7591f"/>
</marker>
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#1a70c7"/>
</marker>
</defs>
<!-- Background: paper + dot grid -->
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- =================================================================
LIFELINES — dashed vertical lines from each actor, behind everything.
Actor lifeline x-coords: 128, 352, 584, 800
================================================================= -->
<line x1="128" y1="128" x2="128" y2="488" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="352" y1="128" x2="352" y2="488" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="584" y1="128" x2="584" y2="488" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="800" y1="128" x2="800" y2="488" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
<!-- =================================================================
ACTIVATION BARS — w=8 rects on lifelines showing control duration.
Drawn before message arrows so arrows land on their edges.
================================================================= -->
<!-- Cloudflare activation: receives at y=176, responds at y=408 -->
<rect x="348" y="180" width="8" height="232" fill="rgba(11,13,11,0.06)" stroke="#52534e" stroke-width="0.8"/>
<!-- Astro activation: called at y=232, returns at y=352 -->
<rect x="580" y="236" width="8" height="120" fill="rgba(11,13,11,0.06)" stroke="#52534e" stroke-width="0.8"/>
<!-- =================================================================
MESSAGE ARROWS — time flows top→down.
Draw before labels so label masks cover the line.
================================================================= -->
<!-- M1: Reader → Cloudflare (HTTPS request · link-blue) -->
<line x1="128" y1="176" x2="352" y2="176" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<!-- M2: Cloudflare → Astro (cache miss · muted) -->
<line x1="352" y1="232" x2="580" y2="232" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- M3: Astro self-message (render MDX · muted U-loop) -->
<path d="M 588 284 L 624 284 L 624 316 L 588 316" fill="none" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- M4: Astro → Cloudflare (return HTML · muted dashed) -->
<line x1="580" y1="352" x2="356" y2="352" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- M5: Cloudflare → Reader (primary success · coral) -->
<line x1="348" y1="408" x2="128" y2="408" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- M6: Reader → Analytics (async beacon · muted dashed) -->
<line x1="128" y1="464" x2="800" y2="464" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- =================================================================
MESSAGE LABELS — each with an opaque paper-colored mask.
================================================================= -->
<!-- M1 label -->
<rect x="188" y="160" width="104" height="12" rx="2" fill="#f5f4ed"/>
<text x="240" y="170" fill="#1a70c7" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">GET /ARTICLES/SLUG</text>
<!-- M2 label -->
<rect x="416" y="216" width="100" height="12" rx="2" fill="#f5f4ed"/>
<text x="466" y="226" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CACHE MISS · ORIGIN</text>
<!-- M3 label (to the right of the self-loop) -->
<rect x="632" y="292" width="72" height="12" rx="2" fill="#f5f4ed"/>
<text x="668" y="302" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">RENDER MDX</text>
<!-- M4 label -->
<rect x="420" y="336" width="96" height="12" rx="2" fill="#f5f4ed"/>
<text x="468" y="346" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">200 · HTML + MAX-AGE</text>
<!-- M5 label (coral · primary response) -->
<rect x="192" y="392" width="96" height="12" rx="2" fill="#f5f4ed"/>
<text x="240" y="402" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">200 · EDGE-CACHED</text>
<!-- M6 label (placed between Astro and Analytics lifelines, a clear gap) -->
<rect x="648" y="448" width="96" height="12" rx="2" fill="#f5f4ed"/>
<text x="696" y="458" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PAGEVIEW BEACON</text>
<!-- =================================================================
ACTOR BOXES — drawn after arrows/labels.
Each actor: 144–160 wide × 56 tall. Centers: 128, 352, 584, 800.
================================================================= -->
<!-- Actor 1: Reader (external / soft) -->
<rect x="56" y="72" width="144" height="56" rx="6" fill="#f5f4ed"/>
<rect x="56" y="72" width="144" height="56" rx="6" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<rect x="64" y="80" width="28" height="12" rx="2" fill="transparent" stroke="rgba(101,101,92,0.40)" stroke-width="0.8"/>
<text x="78" y="89" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
<text x="128" y="104" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reader</text>
<text x="128" y="119" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser</text>
<!-- Actor 2: Cloudflare (cloud / muted) -->
<rect x="280" y="72" width="144" height="56" rx="6" fill="#f5f4ed"/>
<rect x="280" y="72" width="144" height="56" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<rect x="288" y="80" width="32" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="304" y="89" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EDGE</text>
<text x="352" y="104" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Cloudflare</text>
<text x="352" y="119" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Pages · cache</text>
<!-- Actor 3: Astro Origin (focal / coral) -->
<rect x="504" y="72" width="160" height="56" rx="6" fill="#f5f4ed"/>
<rect x="504" y="72" width="160" height="56" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="512" y="80" width="32" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="528" y="89" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ORIG</text>
<text x="584" y="104" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Astro Origin</text>
<text x="584" y="119" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">SSR + MDX</text>
<!-- Actor 4: Analytics (optional / dashed) -->
<rect x="728" y="72" width="144" height="56" rx="6" fill="#f5f4ed"/>
<rect x="728" y="72" width="144" height="56" rx="6" fill="rgba(11,13,11,0.02)" stroke="rgba(11,13,11,0.22)" stroke-width="1" stroke-dasharray="4,3"/>
<rect x="736" y="80" width="28" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="750" y="89" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ASY</text>
<text x="800" y="104" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Analytics</text>
<text x="800" y="119" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Beacon · async</text>
<!-- =================================================================
LEGEND — horizontal strip at the bottom.
Separator at y=504, eyebrow at y=520, items at y=540–548.
================================================================= -->
<line x1="56" y1="504" x2="944" y2="504" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="56" y="520" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<!-- Item 1: Actor swatch (coral focal) -->
<rect x="56" y="540" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="76" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Focal actor</text>
<!-- Item 2: Activation bar swatch -->
<rect x="188" y="536" width="4" height="18" fill="rgba(11,13,11,0.06)" stroke="#52534e" stroke-width="0.8"/>
<text x="200" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Activation</text>
<!-- Item 3: Request arrow (link-blue) -->
<line x1="308" y1="546" x2="336" y2="546" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="344" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">HTTP request</text>
<!-- Item 4: Return / async (muted dashed) -->
<line x1="476" y1="546" x2="504" y2="546" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<text x="512" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Return / async</text>
<!-- Item 5: Primary response (coral) -->
<line x1="652" y1="546" x2="680" y2="546" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="688" y="548" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Primary response</text>
</svg>
</div>
</body>
</html>
+145
View File
@@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Article lifecycle · State machine</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">State machine · Diagram Design</p>
<h1>Article lifecycle</h1>
<svg viewBox="0 0 1000 460" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#a8a69d"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#ff6a30"/></marker>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Transitions (drawn first) -->
<!-- Start → Draft -->
<line x1="68" y1="200" x2="120" y2="200" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Draft → In Review -->
<line x1="280" y1="200" x2="340" y2="200" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- In Review → Published (coral — happy path) -->
<line x1="500" y1="200" x2="560" y2="200" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- Published → Archived (down) -->
<line x1="640" y1="240" x2="640" y2="300" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Archived → End (down) -->
<line x1="640" y1="400" x2="640" y2="432" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- In Review → Draft (curved back up-and-left) -->
<path d="M 420 160 C 420 96, 200 96, 200 160" fill="none" stroke="#a8a69d" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- Transition labels -->
<rect x="172" y="184" width="48" height="12" rx="2" fill="#1c1a17"/>
<text x="196" y="194" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CREATE</text>
<rect x="288" y="184" width="48" height="12" rx="2" fill="#1c1a17"/>
<text x="312" y="194" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">SUBMIT</text>
<rect x="500" y="184" width="60" height="12" rx="2" fill="#1c1a17"/>
<text x="530" y="194" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">APPROVE</text>
<rect x="612" y="264" width="56" height="12" rx="2" fill="#1c1a17"/>
<text x="640" y="274" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXPIRE</text>
<rect x="620" y="416" width="40" height="12" rx="2" fill="#1c1a17"/>
<text x="640" y="426" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PURGE</text>
<!-- Reject label on curved path -->
<rect x="276" y="92" width="80" height="12" rx="2" fill="#1c1a17"/>
<text x="316" y="102" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">REJECT · REVISE</text>
<!-- Start dot (filled ink) -->
<circle cx="60" cy="200" r="6" fill="#f1efe7"/>
<!-- State: Draft -->
<rect x="120" y="160" width="160" height="80" rx="8" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<rect x="128" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.40)" stroke-width="0.8"/>
<text x="148" y="177" fill="#f1efe7" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="200" y="208" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Draft</text>
<text x="200" y="224" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">unpublished</text>
<!-- State: In Review -->
<rect x="340" y="160" width="160" height="80" rx="8" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<rect x="348" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.40)" stroke-width="0.8"/>
<text x="368" y="177" fill="#f1efe7" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="420" y="208" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">In Review</text>
<text x="420" y="224" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">awaiting approval</text>
<!-- State: Published (focal coral) -->
<rect x="560" y="160" width="160" height="80" rx="8" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<rect x="568" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(255,106,48,0.50)" stroke-width="0.8"/>
<text x="588" y="177" fill="#ff6a30" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="640" y="208" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Published</text>
<text x="640" y="224" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">live on site</text>
<!-- State: Archived -->
<rect x="560" y="300" width="160" height="100" rx="8" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="1"/>
<rect x="568" y="308" width="40" height="12" rx="2" fill="transparent" stroke="rgba(168,166,157,0.50)" stroke-width="0.8"/>
<text x="588" y="317" fill="#a8a69d" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="640" y="348" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Archived</text>
<text x="640" y="364" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">noindex · hidden</text>
<text x="640" y="382" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">redirect retained</text>
<!-- End ring dot -->
<circle cx="640" cy="440" r="8" fill="none" stroke="#f1efe7" stroke-width="1"/>
<circle cx="640" cy="440" r="5" fill="#f1efe7"/>
</svg>
</div>
</body>
</html>
+148
View File
@@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Article lifecycle · state machine</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">State machine · Diagram Design</p>
<h1>Article lifecycle</h1>
<p class="subtitle">The four states a post passes through from draft to archive, with the rejection loop made explicit. Published is the state the team optimizes for — hence coral.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 460" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Transitions (drawn first) -->
<!-- Start → Draft -->
<line x1="68" y1="200" x2="120" y2="200" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Draft → In Review -->
<line x1="280" y1="200" x2="340" y2="200" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- In Review → Published (coral — happy path) -->
<line x1="500" y1="200" x2="560" y2="200" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- Published → Archived (down) -->
<line x1="640" y1="240" x2="640" y2="300" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Archived → End (down) -->
<line x1="640" y1="400" x2="640" y2="432" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- In Review → Draft (curved back up-and-left) -->
<path d="M 420 160 C 420 96, 200 96, 200 160" fill="none" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- Transition labels -->
<rect x="172" y="184" width="48" height="12" rx="2" fill="#f5f4ed"/>
<text x="196" y="194" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CREATE</text>
<rect x="288" y="184" width="48" height="12" rx="2" fill="#f5f4ed"/>
<text x="312" y="194" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">SUBMIT</text>
<rect x="500" y="184" width="60" height="12" rx="2" fill="#f5f4ed"/>
<text x="530" y="194" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">APPROVE</text>
<rect x="612" y="264" width="56" height="12" rx="2" fill="#f5f4ed"/>
<text x="640" y="274" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXPIRE</text>
<rect x="620" y="416" width="40" height="12" rx="2" fill="#f5f4ed"/>
<text x="640" y="426" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PURGE</text>
<!-- Reject label on curved path -->
<rect x="276" y="92" width="80" height="12" rx="2" fill="#f5f4ed"/>
<text x="316" y="102" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">REJECT · REVISE</text>
<!-- Start dot (filled ink) -->
<circle cx="60" cy="200" r="6" fill="#0b0d0b"/>
<!-- State: Draft -->
<rect x="120" y="160" width="160" height="80" rx="8" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="128" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="148" y="177" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="200" y="208" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Draft</text>
<text x="200" y="224" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">unpublished</text>
<!-- State: In Review -->
<rect x="340" y="160" width="160" height="80" rx="8" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="348" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="368" y="177" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="420" y="208" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">In Review</text>
<text x="420" y="224" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">awaiting approval</text>
<!-- State: Published (focal coral) -->
<rect x="560" y="160" width="160" height="80" rx="8" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="568" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="588" y="177" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="640" y="208" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Published</text>
<text x="640" y="224" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">live on site</text>
<!-- State: Archived -->
<rect x="560" y="300" width="160" height="100" rx="8" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<rect x="568" y="308" width="40" height="12" rx="2" fill="transparent" stroke="rgba(82,83,78,0.50)" stroke-width="0.8"/>
<text x="588" y="317" fill="#52534e" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="640" y="348" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Archived</text>
<text x="640" y="364" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">noindex · hidden</text>
<text x="640" y="382" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">redirect retained</text>
<!-- End ring dot -->
<circle cx="640" cy="440" r="8" fill="none" stroke="#0b0d0b" stroke-width="1"/>
<circle cx="640" cy="440" r="5" fill="#0b0d0b"/>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>Published is the win state</h3></div>
<p>Everything flows toward Published. The rejection loop is dashed because it's a detour, not a failure — the article is still in-progress.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Reject is a loop, not a dead-end</h3></div>
<ul><li>Dashed to signal detour</li><li>Returns to Draft, not a new state</li><li>Review feedback is the action</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Archive keeps the URL</h3></div>
<p>Archived preserves the redirect map so inbound links survive. Only Purge removes the record entirely.</p>
</div>
</div>
<div class="footer">
<span>article lifecycle · state machine</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+145
View File
@@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Article lifecycle · State machine</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">State machine · Diagram Design</p>
<h1>Article lifecycle</h1>
<svg viewBox="0 0 1000 460" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Transitions (drawn first) -->
<!-- Start → Draft -->
<line x1="68" y1="200" x2="120" y2="200" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Draft → In Review -->
<line x1="280" y1="200" x2="340" y2="200" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- In Review → Published (coral — happy path) -->
<line x1="500" y1="200" x2="560" y2="200" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- Published → Archived (down) -->
<line x1="640" y1="240" x2="640" y2="300" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Archived → End (down) -->
<line x1="640" y1="400" x2="640" y2="432" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- In Review → Draft (curved back up-and-left) -->
<path d="M 420 160 C 420 96, 200 96, 200 160" fill="none" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- Transition labels -->
<rect x="172" y="184" width="48" height="12" rx="2" fill="#f5f4ed"/>
<text x="196" y="194" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CREATE</text>
<rect x="288" y="184" width="48" height="12" rx="2" fill="#f5f4ed"/>
<text x="312" y="194" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">SUBMIT</text>
<rect x="500" y="184" width="60" height="12" rx="2" fill="#f5f4ed"/>
<text x="530" y="194" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">APPROVE</text>
<rect x="612" y="264" width="56" height="12" rx="2" fill="#f5f4ed"/>
<text x="640" y="274" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXPIRE</text>
<rect x="620" y="416" width="40" height="12" rx="2" fill="#f5f4ed"/>
<text x="640" y="426" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PURGE</text>
<!-- Reject label on curved path -->
<rect x="276" y="92" width="80" height="12" rx="2" fill="#f5f4ed"/>
<text x="316" y="102" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">REJECT · REVISE</text>
<!-- Start dot (filled ink) -->
<circle cx="60" cy="200" r="6" fill="#0b0d0b"/>
<!-- State: Draft -->
<rect x="120" y="160" width="160" height="80" rx="8" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="128" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="148" y="177" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="200" y="208" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Draft</text>
<text x="200" y="224" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">unpublished</text>
<!-- State: In Review -->
<rect x="340" y="160" width="160" height="80" rx="8" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="348" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="368" y="177" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="420" y="208" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">In Review</text>
<text x="420" y="224" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">awaiting approval</text>
<!-- State: Published (focal coral) -->
<rect x="560" y="160" width="160" height="80" rx="8" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="568" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="588" y="177" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="640" y="208" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Published</text>
<text x="640" y="224" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">live on site</text>
<!-- State: Archived -->
<rect x="560" y="300" width="160" height="100" rx="8" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<rect x="568" y="308" width="40" height="12" rx="2" fill="transparent" stroke="rgba(82,83,78,0.50)" stroke-width="0.8"/>
<text x="588" y="317" fill="#52534e" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
<text x="640" y="348" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Archived</text>
<text x="640" y="364" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">noindex · hidden</text>
<text x="640" y="382" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">redirect retained</text>
<!-- End ring dot -->
<circle cx="640" cy="440" r="8" fill="none" stroke="#0b0d0b" stroke-width="1"/>
<circle cx="640" cy="440" r="5" fill="#0b0d0b"/>
</svg>
</div>
</body>
</html>
+170
View File
@@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Publishing an article · Swimlane</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Swimlane · Diagram Design</p>
<h1>Publishing an article</h1>
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#a8a69d"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#ff6a30"/></marker>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Lane dividers -->
<line x1="40" y1="80" x2="960" y2="80" stroke="rgba(241,239,231,0.22)" stroke-width="1"/>
<line x1="40" y1="160" x2="960" y2="160" stroke="rgba(241,239,231,0.10)" stroke-width="1"/>
<line x1="40" y1="240" x2="960" y2="240" stroke="rgba(241,239,231,0.10)" stroke-width="1"/>
<line x1="40" y1="320" x2="960" y2="320" stroke="rgba(241,239,231,0.10)" stroke-width="1"/>
<line x1="40" y1="400" x2="960" y2="400" stroke="rgba(241,239,231,0.22)" stroke-width="1"/>
<!-- Actor column divider -->
<line x1="160" y1="80" x2="160" y2="400" stroke="rgba(241,239,231,0.22)" stroke-width="1"/>
<!-- Lane labels -->
<text x="60" y="124" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">AUTHOR</text>
<text x="60" y="204" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">REVIEWER</text>
<text x="60" y="284" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">EDITOR</text>
<text x="60" y="364" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">CI / CD</text>
<!-- Arrows (drawn first) -->
<!-- 1. Draft → Open PR (within Author) -->
<line x1="300" y1="120" x2="340" y2="120" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 2. Open PR → Review (Author → Reviewer handoff, diagonal down-right) -->
<line x1="460" y1="144" x2="500" y2="176" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 3. Review → Polish (Reviewer → Editor, vertical down) -->
<line x1="570" y1="224" x2="570" y2="256" stroke="#a8a69d" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- 4. Polish → Approve (within Editor) -->
<line x1="640" y1="280" x2="680" y2="280" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 5. Approve → Build (Editor → CI/CD, coral handoff) -->
<line x1="750" y1="304" x2="720" y2="336" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- 6. Build → Deploy (within CI/CD) -->
<line x1="760" y1="360" x2="800" y2="360" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrow labels -->
<rect x="452" y="140" width="60" height="12" rx="2" fill="#1c1a17"/>
<text x="482" y="150" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">HANDOFF</text>
<rect x="548" y="228" width="52" height="12" rx="2" fill="#2a2723"/>
<text x="574" y="238" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">REVISE</text>
<rect x="712" y="308" width="80" height="12" rx="2" fill="#1c1a17"/>
<text x="752" y="318" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">DEPLOY TRIGGER</text>
<!-- Steps -->
<!-- Author: Draft MDX -->
<rect x="180" y="96" width="120" height="48" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="240" y="118" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Draft MDX</text>
<text x="240" y="132" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">src/content/…</text>
<!-- Author: Open PR -->
<rect x="340" y="96" width="120" height="48" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="400" y="118" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Open PR</text>
<text x="400" y="132" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">gh pr create</text>
<!-- Reviewer: Review content -->
<rect x="500" y="176" width="140" height="48" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="570" y="198" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Review content</text>
<text x="570" y="212" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">fact-check · voice</text>
<!-- Editor: Polish copy -->
<rect x="500" y="256" width="140" height="48" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="570" y="278" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Polish copy</text>
<text x="570" y="292" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">style · line edits</text>
<!-- Editor: Approve merge -->
<rect x="680" y="256" width="140" height="48" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="750" y="278" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Approve merge</text>
<text x="750" y="292" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">squash · main</text>
<!-- CI/CD: Build -->
<rect x="680" y="336" width="80" height="48" rx="6" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="720" y="358" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Build</text>
<text x="720" y="372" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">astro build</text>
<!-- CI/CD: Deploy (coral focal) -->
<rect x="800" y="336" width="120" height="48" rx="6" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<text x="860" y="358" fill="#f1efe7" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Deploy</text>
<text x="860" y="372" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">cloudflare pages</text>
<!-- Legend -->
<line x1="40" y1="428" x2="960" y2="428" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="444" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="460" width="14" height="10" rx="2" fill="#2a2723" stroke="#f1efe7" stroke-width="1"/>
<text x="60" y="468" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Step</text>
<rect x="132" y="460" width="14" height="10" rx="2" fill="rgba(255,106,48,0.08)" stroke="#ff6a30" stroke-width="1"/>
<text x="152" y="468" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Focal outcome</text>
<line x1="268" y1="466" x2="296" y2="466" stroke="#a8a69d" stroke-width="1.2" marker-end="url(#arrow)"/>
<text x="304" y="468" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Within-lane step</text>
<line x1="444" y1="466" x2="472" y2="466" stroke="#a8a69d" stroke-width="1.2" stroke-dasharray="4,3" marker-end="url(#arrow)"/>
<text x="480" y="468" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Revision loop</text>
<line x1="608" y1="466" x2="636" y2="466" stroke="#ff6a30" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="644" y="468" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Critical handoff</text>
</svg>
</div>
</body>
</html>
+173
View File
@@ -0,0 +1,173 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Publishing an article · Swimlane</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Swimlane · Diagram Design</p>
<h1>Publishing an article</h1>
<p class="subtitle">Four actors, seven steps, three handoffs. The step each person owns lives in their lane — arrows crossing lanes are where coordination happens.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Lane dividers -->
<line x1="40" y1="80" x2="960" y2="80" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<line x1="40" y1="160" x2="960" y2="160" stroke="rgba(11,13,11,0.10)" stroke-width="1"/>
<line x1="40" y1="240" x2="960" y2="240" stroke="rgba(11,13,11,0.10)" stroke-width="1"/>
<line x1="40" y1="320" x2="960" y2="320" stroke="rgba(11,13,11,0.10)" stroke-width="1"/>
<line x1="40" y1="400" x2="960" y2="400" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<!-- Actor column divider -->
<line x1="160" y1="80" x2="160" y2="400" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<!-- Lane labels -->
<text x="60" y="124" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">AUTHOR</text>
<text x="60" y="204" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">REVIEWER</text>
<text x="60" y="284" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">EDITOR</text>
<text x="60" y="364" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">CI / CD</text>
<!-- Arrows (drawn first) -->
<!-- 1. Draft → Open PR (within Author) -->
<line x1="300" y1="120" x2="340" y2="120" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 2. Open PR → Review (Author → Reviewer handoff, diagonal down-right) -->
<line x1="460" y1="144" x2="500" y2="176" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 3. Review → Polish (Reviewer → Editor, vertical down) -->
<line x1="570" y1="224" x2="570" y2="256" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- 4. Polish → Approve (within Editor) -->
<line x1="640" y1="280" x2="680" y2="280" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 5. Approve → Build (Editor → CI/CD, coral handoff) -->
<line x1="750" y1="304" x2="720" y2="336" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- 6. Build → Deploy (within CI/CD) -->
<line x1="760" y1="360" x2="800" y2="360" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrow labels -->
<rect x="452" y="140" width="60" height="12" rx="2" fill="#f5f4ed"/>
<text x="482" y="150" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">HANDOFF</text>
<rect x="548" y="228" width="52" height="12" rx="2" fill="#efeee5"/>
<text x="574" y="238" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">REVISE</text>
<rect x="712" y="308" width="80" height="12" rx="2" fill="#f5f4ed"/>
<text x="752" y="318" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">DEPLOY TRIGGER</text>
<!-- Steps -->
<!-- Author: Draft MDX -->
<rect x="180" y="96" width="120" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="240" y="118" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Draft MDX</text>
<text x="240" y="132" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">src/content/…</text>
<!-- Author: Open PR -->
<rect x="340" y="96" width="120" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="400" y="118" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Open PR</text>
<text x="400" y="132" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">gh pr create</text>
<!-- Reviewer: Review content -->
<rect x="500" y="176" width="140" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="570" y="198" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Review content</text>
<text x="570" y="212" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">fact-check · voice</text>
<!-- Editor: Polish copy -->
<rect x="500" y="256" width="140" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="570" y="278" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Polish copy</text>
<text x="570" y="292" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">style · line edits</text>
<!-- Editor: Approve merge -->
<rect x="680" y="256" width="140" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="750" y="278" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Approve merge</text>
<text x="750" y="292" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">squash · main</text>
<!-- CI/CD: Build -->
<rect x="680" y="336" width="80" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="720" y="358" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Build</text>
<text x="720" y="372" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">astro build</text>
<!-- CI/CD: Deploy (coral focal) -->
<rect x="800" y="336" width="120" height="48" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="860" y="358" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Deploy</text>
<text x="860" y="372" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">cloudflare pages</text>
<!-- Legend -->
<line x1="40" y1="428" x2="960" y2="428" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="444" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="460" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="60" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Step</text>
<rect x="132" y="460" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="152" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Focal outcome</text>
<line x1="268" y1="466" x2="296" y2="466" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<text x="304" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Within-lane step</text>
<line x1="444" y1="466" x2="472" y2="466" stroke="#52534e" stroke-width="1.2" stroke-dasharray="4,3" marker-end="url(#arrow)"/>
<text x="480" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Revision loop</text>
<line x1="608" y1="466" x2="636" y2="466" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="644" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Critical handoff</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>The deploy trigger is the risky edge</h3></div>
<p>Every other step lives inside one person's head. The Editor→CI/CD handoff is where automation takes over and humans lose the ability to undo — hence coral.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>One owner per step</h3></div>
<ul><li>No step crosses two lanes</li><li>Handoffs are arrows, not shared steps</li><li>Dashed arrow = revision detour</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Uneven step counts are fine</h3></div>
<p>The Reviewer lane has one step; CI/CD has two. Lanes don't need to match — they exist to make ownership unambiguous.</p>
</div>
</div>
<div class="footer">
<span>publishing an article · swimlane</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+170
View File
@@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Publishing an article · Swimlane</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Swimlane · Diagram Design</p>
<h1>Publishing an article</h1>
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Lane dividers -->
<line x1="40" y1="80" x2="960" y2="80" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<line x1="40" y1="160" x2="960" y2="160" stroke="rgba(11,13,11,0.10)" stroke-width="1"/>
<line x1="40" y1="240" x2="960" y2="240" stroke="rgba(11,13,11,0.10)" stroke-width="1"/>
<line x1="40" y1="320" x2="960" y2="320" stroke="rgba(11,13,11,0.10)" stroke-width="1"/>
<line x1="40" y1="400" x2="960" y2="400" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<!-- Actor column divider -->
<line x1="160" y1="80" x2="160" y2="400" stroke="rgba(11,13,11,0.22)" stroke-width="1"/>
<!-- Lane labels -->
<text x="60" y="124" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">AUTHOR</text>
<text x="60" y="204" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">REVIEWER</text>
<text x="60" y="284" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">EDITOR</text>
<text x="60" y="364" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" letter-spacing="0.18em">CI / CD</text>
<!-- Arrows (drawn first) -->
<!-- 1. Draft → Open PR (within Author) -->
<line x1="300" y1="120" x2="340" y2="120" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 2. Open PR → Review (Author → Reviewer handoff, diagonal down-right) -->
<line x1="460" y1="144" x2="500" y2="176" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 3. Review → Polish (Reviewer → Editor, vertical down) -->
<line x1="570" y1="224" x2="570" y2="256" stroke="#52534e" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
<!-- 4. Polish → Approve (within Editor) -->
<line x1="640" y1="280" x2="680" y2="280" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- 5. Approve → Build (Editor → CI/CD, coral handoff) -->
<line x1="750" y1="304" x2="720" y2="336" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<!-- 6. Build → Deploy (within CI/CD) -->
<line x1="760" y1="360" x2="800" y2="360" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Arrow labels -->
<rect x="452" y="140" width="60" height="12" rx="2" fill="#f5f4ed"/>
<text x="482" y="150" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">HANDOFF</text>
<rect x="548" y="228" width="52" height="12" rx="2" fill="#efeee5"/>
<text x="574" y="238" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">REVISE</text>
<rect x="712" y="308" width="80" height="12" rx="2" fill="#f5f4ed"/>
<text x="752" y="318" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.12em">DEPLOY TRIGGER</text>
<!-- Steps -->
<!-- Author: Draft MDX -->
<rect x="180" y="96" width="120" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="240" y="118" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Draft MDX</text>
<text x="240" y="132" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">src/content/…</text>
<!-- Author: Open PR -->
<rect x="340" y="96" width="120" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="400" y="118" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Open PR</text>
<text x="400" y="132" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">gh pr create</text>
<!-- Reviewer: Review content -->
<rect x="500" y="176" width="140" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="570" y="198" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Review content</text>
<text x="570" y="212" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">fact-check · voice</text>
<!-- Editor: Polish copy -->
<rect x="500" y="256" width="140" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="570" y="278" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Polish copy</text>
<text x="570" y="292" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">style · line edits</text>
<!-- Editor: Approve merge -->
<rect x="680" y="256" width="140" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="750" y="278" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Approve merge</text>
<text x="750" y="292" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">squash · main</text>
<!-- CI/CD: Build -->
<rect x="680" y="336" width="80" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="720" y="358" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Build</text>
<text x="720" y="372" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">astro build</text>
<!-- CI/CD: Deploy (coral focal) -->
<rect x="800" y="336" width="120" height="48" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="860" y="358" fill="#0b0d0b" font-size="11" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Deploy</text>
<text x="860" y="372" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">cloudflare pages</text>
<!-- Legend -->
<line x1="40" y1="428" x2="960" y2="428" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="444" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="460" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="60" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Step</text>
<rect x="132" y="460" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="152" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Focal outcome</text>
<line x1="268" y1="466" x2="296" y2="466" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<text x="304" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Within-lane step</text>
<line x1="444" y1="466" x2="472" y2="466" stroke="#52534e" stroke-width="1.2" stroke-dasharray="4,3" marker-end="url(#arrow)"/>
<text x="480" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Revision loop</text>
<line x1="608" y1="466" x2="636" y2="466" stroke="#f7591f" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
<text x="644" y="468" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Critical handoff</text>
</svg>
</div>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight milestones · Timeline</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Timeline · Diagram Design</p>
<h1>littlemight, fourteen months</h1>
<svg viewBox="0 0 1000 420" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Year markers (background) -->
<text x="60" y="340" fill="rgba(241,239,231,0.06)" font-size="72" font-weight="600" font-family="'Geist Mono', monospace">2025</text>
<text x="700" y="340" fill="rgba(241,239,231,0.06)" font-size="72" font-weight="600" font-family="'Geist Mono', monospace">2026</text>
<!-- Baseline -->
<line x1="80" y1="240" x2="920" y2="240" stroke="rgba(150,146,138,0.45)" stroke-width="1"/>
<!-- Year boundary tick (between 2025 and 2026) -->
<line x1="680" y1="232" x2="680" y2="248" stroke="rgba(241,239,231,0.20)" stroke-width="1"/>
<text x="680" y="260" fill="#8e8c83" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">JAN '26</text>
<!-- Start / end caps -->
<line x1="80" y1="232" x2="80" y2="248" stroke="rgba(241,239,231,0.20)" stroke-width="1"/>
<line x1="920" y1="232" x2="920" y2="248" stroke="rgba(241,239,231,0.20)" stroke-width="1"/>
<!-- Event 1: FEB 2025 · First post (below) -->
<line x1="100" y1="240" x2="100" y2="296" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<circle cx="100" cy="240" r="4" fill="#f1efe7"/>
<text x="100" y="312" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">FEB 2025</text>
<text x="100" y="328" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">First post</text>
<!-- Event 2: APR 2025 · Design v1 (above) -->
<line x1="240" y1="184" x2="240" y2="240" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<circle cx="240" cy="240" r="4" fill="#f1efe7"/>
<text x="240" y="156" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">APR 2025</text>
<text x="240" y="172" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v1</text>
<!-- Event 3: SEP 2025 · Design v2 (below) -->
<line x1="500" y1="240" x2="500" y2="296" stroke="rgba(241,239,231,0.30)" stroke-width="1"/>
<circle cx="500" cy="240" r="4" fill="#f1efe7"/>
<text x="500" y="312" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">SEP 2025</text>
<text x="500" y="328" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v2</text>
<text x="500" y="344" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">typography pass</text>
<!-- Event 4: JAN 2026 · Design v3 (above, coral major) -->
<line x1="740" y1="160" x2="740" y2="240" stroke="#ff6a30" stroke-width="1"/>
<circle cx="740" cy="240" r="6" fill="#ff6a30"/>
<text x="740" y="128" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">JAN 2026</text>
<text x="740" y="148" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v3</text>
<text x="740" y="164" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">complexity budget</text>
<!-- Event 5: APR 2026 · now · Diagram Design skill (below, coral) -->
<line x1="900" y1="240" x2="900" y2="296" stroke="#ff6a30" stroke-width="1"/>
<circle cx="900" cy="240" r="6" fill="#ff6a30"/>
<text x="900" y="312" fill="#ff6a30" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">APR 2026 · NOW</text>
<text x="900" y="328" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">diagram-design</text>
<text x="900" y="344" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">eight diagram types</text>
<!-- Legend -->
<line x1="40" y1="376" x2="960" y2="376" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="392" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="408" r="4" fill="#f1efe7"/>
<text x="68" y="412" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Event</text>
<circle cx="148" cy="408" r="6" fill="#ff6a30"/>
<text x="164" y="412" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Major milestone</text>
<text x="296" y="412" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Spacing is proportional to real elapsed time.</text>
</svg>
</div>
</body>
</html>
+136
View File
@@ -0,0 +1,136 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight milestones · Timeline</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Timeline · Diagram Design</p>
<h1>littlemight, fourteen months</h1>
<p class="subtitle">Five design moments from the first post to the current diagram-design overhaul. Spacing is proportional to calendar time — the five-month gap between v1 and v2 is genuinely wider on the page.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 420" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Year markers (background) -->
<text x="60" y="340" fill="rgba(11,13,11,0.06)" font-size="72" font-weight="600" font-family="'Geist Mono', monospace">2025</text>
<text x="700" y="340" fill="rgba(11,13,11,0.06)" font-size="72" font-weight="600" font-family="'Geist Mono', monospace">2026</text>
<!-- Baseline -->
<line x1="80" y1="240" x2="920" y2="240" stroke="rgba(135,139,134,0.45)" stroke-width="1"/>
<!-- Year boundary tick (between 2025 and 2026) -->
<line x1="680" y1="232" x2="680" y2="248" stroke="rgba(11,13,11,0.20)" stroke-width="1"/>
<text x="680" y="260" fill="#65655c" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">JAN '26</text>
<!-- Start / end caps -->
<line x1="80" y1="232" x2="80" y2="248" stroke="rgba(11,13,11,0.20)" stroke-width="1"/>
<line x1="920" y1="232" x2="920" y2="248" stroke="rgba(11,13,11,0.20)" stroke-width="1"/>
<!-- Event 1: FEB 2025 · First post (below) -->
<line x1="100" y1="240" x2="100" y2="296" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<circle cx="100" cy="240" r="4" fill="#0b0d0b"/>
<text x="100" y="312" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">FEB 2025</text>
<text x="100" y="328" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">First post</text>
<!-- Event 2: APR 2025 · Design v1 (above) -->
<line x1="240" y1="184" x2="240" y2="240" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<circle cx="240" cy="240" r="4" fill="#0b0d0b"/>
<text x="240" y="156" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">APR 2025</text>
<text x="240" y="172" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v1</text>
<!-- Event 3: SEP 2025 · Design v2 (below) -->
<line x1="500" y1="240" x2="500" y2="296" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<circle cx="500" cy="240" r="4" fill="#0b0d0b"/>
<text x="500" y="312" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">SEP 2025</text>
<text x="500" y="328" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v2</text>
<text x="500" y="344" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">typography pass</text>
<!-- Event 4: JAN 2026 · Design v3 (above, coral major) -->
<line x1="740" y1="160" x2="740" y2="240" stroke="#f7591f" stroke-width="1"/>
<circle cx="740" cy="240" r="6" fill="#f7591f"/>
<text x="740" y="128" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">JAN 2026</text>
<text x="740" y="148" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v3</text>
<text x="740" y="164" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">complexity budget</text>
<!-- Event 5: APR 2026 · now · Diagram Design skill (below, coral) -->
<line x1="900" y1="240" x2="900" y2="296" stroke="#f7591f" stroke-width="1"/>
<circle cx="900" cy="240" r="6" fill="#f7591f"/>
<text x="900" y="312" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">APR 2026 · NOW</text>
<text x="900" y="328" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">diagram-design</text>
<text x="900" y="344" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">eight diagram types</text>
<!-- Legend -->
<line x1="40" y1="376" x2="960" y2="376" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="392" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="408" r="4" fill="#0b0d0b"/>
<text x="68" y="412" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Event</text>
<circle cx="148" cy="408" r="6" fill="#f7591f"/>
<text x="164" y="412" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Major milestone</text>
<text x="296" y="412" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Spacing is proportional to real elapsed time.</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>v3 set the complexity budget</h3></div>
<p>January's design overhaul is the pivot — the rule that no diagram exceeds nine components comes from there, and it's why this skill exists in the form it does.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Honest spacing</h3></div>
<ul><li>5 months between v1 and v2</li><li>4 months between v2 and v3</li><li>3 months between v3 and now</li><li>Cadence is tightening, not gaming the axis</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Alternate label placement</h3></div>
<p>Above / below flipping prevents label collision without forcing a second row. Five events on one baseline stays legible.</p>
</div>
</div>
<div class="footer">
<span>littlemight · design lineage</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>littlemight milestones · Timeline</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Timeline · Diagram Design</p>
<h1>littlemight, fourteen months</h1>
<svg viewBox="0 0 1000 420" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Year markers (background) -->
<text x="60" y="340" fill="rgba(11,13,11,0.06)" font-size="72" font-weight="600" font-family="'Geist Mono', monospace">2025</text>
<text x="700" y="340" fill="rgba(11,13,11,0.06)" font-size="72" font-weight="600" font-family="'Geist Mono', monospace">2026</text>
<!-- Baseline -->
<line x1="80" y1="240" x2="920" y2="240" stroke="rgba(135,139,134,0.45)" stroke-width="1"/>
<!-- Year boundary tick (between 2025 and 2026) -->
<line x1="680" y1="232" x2="680" y2="248" stroke="rgba(11,13,11,0.20)" stroke-width="1"/>
<text x="680" y="260" fill="#65655c" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">JAN '26</text>
<!-- Start / end caps -->
<line x1="80" y1="232" x2="80" y2="248" stroke="rgba(11,13,11,0.20)" stroke-width="1"/>
<line x1="920" y1="232" x2="920" y2="248" stroke="rgba(11,13,11,0.20)" stroke-width="1"/>
<!-- Event 1: FEB 2025 · First post (below) -->
<line x1="100" y1="240" x2="100" y2="296" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<circle cx="100" cy="240" r="4" fill="#0b0d0b"/>
<text x="100" y="312" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">FEB 2025</text>
<text x="100" y="328" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">First post</text>
<!-- Event 2: APR 2025 · Design v1 (above) -->
<line x1="240" y1="184" x2="240" y2="240" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<circle cx="240" cy="240" r="4" fill="#0b0d0b"/>
<text x="240" y="156" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">APR 2025</text>
<text x="240" y="172" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v1</text>
<!-- Event 3: SEP 2025 · Design v2 (below) -->
<line x1="500" y1="240" x2="500" y2="296" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<circle cx="500" cy="240" r="4" fill="#0b0d0b"/>
<text x="500" y="312" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">SEP 2025</text>
<text x="500" y="328" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v2</text>
<text x="500" y="344" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">typography pass</text>
<!-- Event 4: JAN 2026 · Design v3 (above, coral major) -->
<line x1="740" y1="160" x2="740" y2="240" stroke="#f7591f" stroke-width="1"/>
<circle cx="740" cy="240" r="6" fill="#f7591f"/>
<text x="740" y="128" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">JAN 2026</text>
<text x="740" y="148" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design v3</text>
<text x="740" y="164" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">complexity budget</text>
<!-- Event 5: APR 2026 · now · Diagram Design skill (below, coral) -->
<line x1="900" y1="240" x2="900" y2="296" stroke="#f7591f" stroke-width="1"/>
<circle cx="900" cy="240" r="6" fill="#f7591f"/>
<text x="900" y="312" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">APR 2026 · NOW</text>
<text x="900" y="328" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">diagram-design</text>
<text x="900" y="344" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">eight diagram types</text>
<!-- Legend -->
<line x1="40" y1="376" x2="960" y2="376" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="392" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="408" r="4" fill="#0b0d0b"/>
<text x="68" y="412" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Event</text>
<circle cx="148" cy="408" r="6" fill="#f7591f"/>
<text x="164" y="412" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Major milestone</text>
<text x="296" y="412" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Spacing is proportional to real elapsed time.</text>
</svg>
</div>
</body>
</html>
+171
View File
@@ -0,0 +1,171 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Claude Code skill taxonomy · Tree</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Tree · Diagram Design</p>
<h1>Claude Code skill taxonomy</h1>
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Tier tags (left margin) -->
<text x="40" y="108" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">TIER 0 · ROOT</text>
<text x="40" y="224" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="start">TIER 1</text>
<text x="40" y="324" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="start">TIER 2</text>
<!-- Connectors drawn first (behind nodes) -->
<!-- Root → Tier 1 bus -->
<path d="M 500 128 L 500 168 L 220 168 L 220 208" fill="none" stroke="#a8a69d" stroke-width="1"/>
<path d="M 500 168 L 500 208" fill="none" stroke="#a8a69d" stroke-width="1"/>
<path d="M 500 168 L 780 168 L 780 208" fill="none" stroke="#a8a69d" stroke-width="1"/>
<!-- Design → leaves -->
<path d="M 220 256 L 220 296 L 140 296 L 140 336" fill="none" stroke="#a8a69d" stroke-width="1"/>
<path d="M 220 296 L 300 296 L 300 336" fill="none" stroke="#a8a69d" stroke-width="1"/>
<!-- Engineering → leaves -->
<path d="M 500 256 L 500 296 L 480 296 L 480 336" fill="none" stroke="#a8a69d" stroke-width="1"/>
<path d="M 500 296 L 660 296 L 660 336" fill="none" stroke="#a8a69d" stroke-width="1"/>
<!-- Research → single leaf -->
<path d="M 780 256 L 780 296 L 840 296 L 840 336" fill="none" stroke="#a8a69d" stroke-width="1"/>
<!-- Root node: Skills (coral focal) -->
<rect x="420" y="80" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="420" y="80" width="160" height="48" rx="6" fill="rgba(255,106,48,0.10)" stroke="#ff6a30" stroke-width="1"/>
<rect x="428" y="88" width="32" height="12" rx="2" fill="transparent" stroke="rgba(255,106,48,0.50)" stroke-width="0.8"/>
<text x="444" y="97" fill="#ff6a30" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ROOT</text>
<text x="500" y="118" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Skills</text>
<!-- Tier 1: Design -->
<rect x="140" y="208" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="140" y="208" width="160" height="48" rx="6" fill="rgba(241,239,231,0.04)" stroke="#f1efe7" stroke-width="1"/>
<rect x="148" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.40)" stroke-width="0.8"/>
<text x="162" y="225" fill="#f1efe7" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="220" y="240" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design</text>
<text x="220" y="252" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">ui · visual · ux</text>
<!-- Tier 1: Engineering -->
<rect x="420" y="208" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="420" y="208" width="160" height="48" rx="6" fill="rgba(241,239,231,0.04)" stroke="#f1efe7" stroke-width="1"/>
<rect x="428" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.40)" stroke-width="0.8"/>
<text x="442" y="225" fill="#f1efe7" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="500" y="240" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Engineering</text>
<text x="500" y="252" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">ship · review · test</text>
<!-- Tier 1: Research -->
<rect x="700" y="208" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="700" y="208" width="160" height="48" rx="6" fill="rgba(241,239,231,0.04)" stroke="#f1efe7" stroke-width="1"/>
<rect x="708" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(241,239,231,0.40)" stroke-width="0.8"/>
<text x="722" y="225" fill="#f1efe7" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="780" y="240" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Research</text>
<text x="780" y="252" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">investigate · analyze</text>
<!-- Tier 2: polish -->
<rect x="60" y="336" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="60" y="336" width="160" height="48" rx="6" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="0.8"/>
<text x="140" y="360" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">polish</text>
<text x="140" y="372" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">align · space · rhythm</text>
<!-- Tier 2: critique -->
<rect x="220" y="336" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="220" y="336" width="160" height="48" rx="6" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="0.8"/>
<text x="300" y="360" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">critique</text>
<text x="300" y="372" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">hierarchy · density</text>
<!-- Tier 2: review -->
<rect x="400" y="336" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="400" y="336" width="160" height="48" rx="6" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="0.8"/>
<text x="480" y="360" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">review</text>
<text x="480" y="372" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">pre-land diff · sql</text>
<!-- Tier 2: ship -->
<rect x="580" y="336" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="580" y="336" width="160" height="48" rx="6" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="0.8"/>
<text x="660" y="360" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">ship</text>
<text x="660" y="372" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">merge · deploy · verify</text>
<!-- Tier 2: investigate -->
<rect x="760" y="336" width="160" height="48" rx="6" fill="#1c1a17"/>
<rect x="760" y="336" width="160" height="48" rx="6" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="0.8"/>
<text x="840" y="360" fill="#f1efe7" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">investigate</text>
<text x="840" y="372" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">root cause · evidence</text>
<!-- Legend strip -->
<line x1="40" y1="412" x2="960" y2="412" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="428" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="444" width="14" height="10" rx="2" fill="rgba(255,106,48,0.10)" stroke="#ff6a30" stroke-width="1"/>
<text x="60" y="452" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Root · focal</text>
<rect x="180" y="444" width="14" height="10" rx="2" fill="rgba(241,239,231,0.04)" stroke="#f1efe7" stroke-width="1"/>
<text x="200" y="452" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Category branch</text>
<rect x="340" y="444" width="14" height="10" rx="2" fill="rgba(241,239,231,0.05)" stroke="#a8a69d" stroke-width="0.8"/>
<text x="360" y="452" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Leaf skill</text>
<text x="500" y="452" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Orthogonal connectors only. Coral marks the root — every branch descends from one idea.</text>
</svg>
</div>
</body>
</html>
+174
View File
@@ -0,0 +1,174 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Claude Code skill taxonomy · Tree</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Tree · Diagram Design</p>
<h1>Claude Code skill taxonomy</h1>
<p class="subtitle">Three tiers, one root. The full skill library fans out from a single idea — and every leaf descends through exactly one category. Orthogonal connectors, one coral accent, nothing else.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Tier tags (left margin) -->
<text x="40" y="108" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">TIER 0 · ROOT</text>
<text x="40" y="224" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="start">TIER 1</text>
<text x="40" y="324" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="start">TIER 2</text>
<!-- Connectors drawn first (behind nodes) -->
<!-- Root → Tier 1 bus -->
<path d="M 500 128 L 500 168 L 220 168 L 220 208" fill="none" stroke="#52534e" stroke-width="1"/>
<path d="M 500 168 L 500 208" fill="none" stroke="#52534e" stroke-width="1"/>
<path d="M 500 168 L 780 168 L 780 208" fill="none" stroke="#52534e" stroke-width="1"/>
<!-- Design → leaves -->
<path d="M 220 256 L 220 296 L 140 296 L 140 336" fill="none" stroke="#52534e" stroke-width="1"/>
<path d="M 220 296 L 300 296 L 300 336" fill="none" stroke="#52534e" stroke-width="1"/>
<!-- Engineering → leaves -->
<path d="M 500 256 L 500 296 L 480 296 L 480 336" fill="none" stroke="#52534e" stroke-width="1"/>
<path d="M 500 296 L 660 296 L 660 336" fill="none" stroke="#52534e" stroke-width="1"/>
<!-- Research → single leaf -->
<path d="M 780 256 L 780 296 L 840 296 L 840 336" fill="none" stroke="#52534e" stroke-width="1"/>
<!-- Root node: Skills (coral focal) -->
<rect x="420" y="80" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="420" y="80" width="160" height="48" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="428" y="88" width="32" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="444" y="97" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ROOT</text>
<text x="500" y="118" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Skills</text>
<!-- Tier 1: Design -->
<rect x="140" y="208" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="140" y="208" width="160" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="148" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="162" y="225" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="220" y="240" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design</text>
<text x="220" y="252" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">ui · visual · ux</text>
<!-- Tier 1: Engineering -->
<rect x="420" y="208" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="420" y="208" width="160" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="428" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="442" y="225" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="500" y="240" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Engineering</text>
<text x="500" y="252" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">ship · review · test</text>
<!-- Tier 1: Research -->
<rect x="700" y="208" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="700" y="208" width="160" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="708" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="722" y="225" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="780" y="240" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Research</text>
<text x="780" y="252" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">investigate · analyze</text>
<!-- Tier 2: polish -->
<rect x="60" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="60" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="140" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">polish</text>
<text x="140" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">align · space · rhythm</text>
<!-- Tier 2: critique -->
<rect x="220" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="220" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="300" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">critique</text>
<text x="300" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">hierarchy · density</text>
<!-- Tier 2: review -->
<rect x="400" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="400" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="480" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">review</text>
<text x="480" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">pre-land diff · sql</text>
<!-- Tier 2: ship -->
<rect x="580" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="580" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="660" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">ship</text>
<text x="660" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">merge · deploy · verify</text>
<!-- Tier 2: investigate -->
<rect x="760" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="760" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="840" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">investigate</text>
<text x="840" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">root cause · evidence</text>
<!-- Legend strip -->
<line x1="40" y1="412" x2="960" y2="412" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="428" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="444" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="60" y="452" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Root · focal</text>
<rect x="180" y="444" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="200" y="452" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Category branch</text>
<rect x="340" y="444" width="14" height="10" rx="2" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="360" y="452" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Leaf skill</text>
<text x="500" y="452" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Orthogonal connectors only. Coral marks the root — every branch descends from one idea.</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>One root, one coral dot</h3></div>
<p>A taxonomy is a promise: every child has exactly one parent. Coral lives on the root because that's the only node the tree is actually about — everything else is a descent.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>Connectors are orthogonal</h3></div>
<ul><li>Parent drops vertical</li><li>Horizontal bus connects siblings</li><li>Each child drops into its top edge</li><li>No diagonals, no curves</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>Uneven breadth is honest</h3></div>
<p>Design and Engineering fan to two leaves; Research drops to one. The layout reflects the real shape of the library, not a forced symmetry.</p>
</div>
</div>
<div class="footer">
<span>claude code skill taxonomy</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+171
View File
@@ -0,0 +1,171 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Claude Code skill taxonomy · Tree</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Tree · Diagram Design</p>
<h1>Claude Code skill taxonomy</h1>
<svg viewBox="0 0 1000 480" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Tier tags (left margin) -->
<text x="40" y="108" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">TIER 0 · ROOT</text>
<text x="40" y="224" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="start">TIER 1</text>
<text x="40" y="324" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em" text-anchor="start">TIER 2</text>
<!-- Connectors drawn first (behind nodes) -->
<!-- Root → Tier 1 bus -->
<path d="M 500 128 L 500 168 L 220 168 L 220 208" fill="none" stroke="#52534e" stroke-width="1"/>
<path d="M 500 168 L 500 208" fill="none" stroke="#52534e" stroke-width="1"/>
<path d="M 500 168 L 780 168 L 780 208" fill="none" stroke="#52534e" stroke-width="1"/>
<!-- Design → leaves -->
<path d="M 220 256 L 220 296 L 140 296 L 140 336" fill="none" stroke="#52534e" stroke-width="1"/>
<path d="M 220 296 L 300 296 L 300 336" fill="none" stroke="#52534e" stroke-width="1"/>
<!-- Engineering → leaves -->
<path d="M 500 256 L 500 296 L 480 296 L 480 336" fill="none" stroke="#52534e" stroke-width="1"/>
<path d="M 500 296 L 660 296 L 660 336" fill="none" stroke="#52534e" stroke-width="1"/>
<!-- Research → single leaf -->
<path d="M 780 256 L 780 296 L 840 296 L 840 336" fill="none" stroke="#52534e" stroke-width="1"/>
<!-- Root node: Skills (coral focal) -->
<rect x="420" y="80" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="420" y="80" width="160" height="48" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="428" y="88" width="32" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="444" y="97" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ROOT</text>
<text x="500" y="118" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Skills</text>
<!-- Tier 1: Design -->
<rect x="140" y="208" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="140" y="208" width="160" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="148" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="162" y="225" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="220" y="240" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Design</text>
<text x="220" y="252" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">ui · visual · ux</text>
<!-- Tier 1: Engineering -->
<rect x="420" y="208" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="420" y="208" width="160" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="428" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="442" y="225" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="500" y="240" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Engineering</text>
<text x="500" y="252" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">ship · review · test</text>
<!-- Tier 1: Research -->
<rect x="700" y="208" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="700" y="208" width="160" height="48" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="708" y="216" width="28" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="722" y="225" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CAT</text>
<text x="780" y="240" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Research</text>
<text x="780" y="252" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">investigate · analyze</text>
<!-- Tier 2: polish -->
<rect x="60" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="60" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="140" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">polish</text>
<text x="140" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">align · space · rhythm</text>
<!-- Tier 2: critique -->
<rect x="220" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="220" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="300" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">critique</text>
<text x="300" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">hierarchy · density</text>
<!-- Tier 2: review -->
<rect x="400" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="400" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="480" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">review</text>
<text x="480" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">pre-land diff · sql</text>
<!-- Tier 2: ship -->
<rect x="580" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="580" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="660" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">ship</text>
<text x="660" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">merge · deploy · verify</text>
<!-- Tier 2: investigate -->
<rect x="760" y="336" width="160" height="48" rx="6" fill="#f5f4ed"/>
<rect x="760" y="336" width="160" height="48" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="840" y="360" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">investigate</text>
<text x="840" y="372" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">root cause · evidence</text>
<!-- Legend strip -->
<line x1="40" y1="412" x2="960" y2="412" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="428" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<rect x="40" y="444" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="60" y="452" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Root · focal</text>
<rect x="180" y="444" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="200" y="452" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Category branch</text>
<rect x="340" y="444" width="14" height="10" rx="2" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="0.8"/>
<text x="360" y="452" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Leaf skill</text>
<text x="500" y="452" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Orthogonal connectors only. Coral marks the root — every branch descends from one idea.</text>
</svg>
</div>
</body>
</html>
+130
View File
@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Good design · Desirable × Feasible × Viable</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17;
--color-ink: #f1efe7;
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Venn · Diagram Design</p>
<h1>Good design · Desirable × Feasible × Viable</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.10)"/>
</pattern>
<clipPath id="clip-center">
<circle cx="500" cy="180" r="140"/>
</clipPath>
<clipPath id="clip-center-2">
<circle cx="428" cy="320" r="140"/>
</clipPath>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Three set circles (stroke + very-low-opacity tint; tints compound in overlaps) -->
<!-- Desirable — top, ink -->
<circle cx="500" cy="180" r="140" fill="rgba(241,239,231,0.04)" stroke="#f1efe7" stroke-width="1"/>
<!-- Feasible — bottom-left, muted -->
<circle cx="428" cy="320" r="140" fill="rgba(168,166,157,0.05)" stroke="#a8a69d" stroke-width="1"/>
<!-- Viable — bottom-right, soft -->
<circle cx="572" cy="320" r="140" fill="rgba(142,140,131,0.05)" stroke="#8e8c83" stroke-width="1"/>
<!-- Coral focal tint on the all-three intersection -->
<g clip-path="url(#clip-center)">
<g clip-path="url(#clip-center-2)">
<circle cx="572" cy="320" r="140" fill="rgba(255,106,48,0.14)"/>
</g>
</g>
<!-- Set labels -->
<text x="500" y="20" fill="#f1efe7" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Desirable</text>
<text x="500" y="36" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">PEOPLE WANT IT</text>
<text x="152" y="400" fill="#a8a69d" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="start">Feasible</text>
<text x="152" y="416" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="start" letter-spacing="0.14em">WE CAN BUILD IT</text>
<text x="848" y="400" fill="#8e8c83" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="end">Viable</text>
<text x="848" y="416" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.14em">BUSINESS SUSTAINS</text>
<!-- Pairwise intersection labels -->
<text x="360" y="232" fill="#a8a69d" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Prototype</text>
<text x="360" y="248" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">no business model</text>
<text x="640" y="232" fill="#a8a69d" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Vaporware</text>
<text x="640" y="248" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">can't build it</text>
<text x="500" y="368" fill="#a8a69d" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Internal tool</text>
<text x="500" y="384" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">nobody wants it</text>
<!-- Focal: all-three center -->
<text x="500" y="260" fill="#ff6a30" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Shippable</text>
<text x="500" y="276" fill="#a8a69d" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">THE SWEET SPOT</text>
<!-- Legend strip -->
<line x1="40" y1="456" x2="960" y2="456" stroke="rgba(241,239,231,0.10)" stroke-width="0.8"/>
<text x="40" y="472" fill="#a8a69d" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="488" r="6" fill="none" stroke="#ff6a30" stroke-width="1.2"/>
<text x="68" y="492" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">All three — ship it</text>
<circle cx="192" cy="488" r="6" fill="none" stroke="#a8a69d" stroke-width="1"/>
<text x="208" y="492" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif">Two of three — incomplete</text>
<text x="380" y="492" fill="#a8a69d" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Coral marks the intersection that earns the work. The others name the traps.</text>
</svg>
</div>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Good design · Desirable × Feasible × Viable</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { --color-paper:#f5f4ed; --color-paper-2:#efeee5; --color-ink:#0b0d0b; --color-muted:#52534e; --color-soft:#65655c; --color-rule:rgba(11,13,11,0.12); --color-accent:#f7591f; --color-link:#1a70c7; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2.5rem; }
.header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
.subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 900px; display: block; }
.cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
@media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
.card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
.card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
.card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(11,13,11,0.08); }
.card-dot { width: 7px; height: 7px; border-radius: 50%; }
.card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
.card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
.card li::before { content: '—'; position: absolute; left: 0; color: rgba(11,13,11,0.25); font-size: 0.75rem; }
.footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(11,13,11,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<p class="header-eyebrow">Venn · Diagram Design</p>
<h1>Good design · Desirable × Feasible × Viable</h1>
<p class="subtitle">Three tests every product has to pass before it earns the word "shippable." Miss one and you get a prototype, a vaporware demo, or an internal tool nobody asked for. Coral marks the intersection worth the work.</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<clipPath id="clip-center">
<circle cx="500" cy="180" r="140"/>
</clipPath>
<clipPath id="clip-center-2">
<circle cx="428" cy="320" r="140"/>
</clipPath>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Three set circles (stroke + very-low-opacity tint; tints compound in overlaps) -->
<!-- Desirable — top, ink -->
<circle cx="500" cy="180" r="140" fill="rgba(11,13,11,0.04)" stroke="#0b0d0b" stroke-width="1"/>
<!-- Feasible — bottom-left, muted -->
<circle cx="428" cy="320" r="140" fill="rgba(82,83,78,0.05)" stroke="#52534e" stroke-width="1"/>
<!-- Viable — bottom-right, soft -->
<circle cx="572" cy="320" r="140" fill="rgba(101,101,92,0.05)" stroke="#65655c" stroke-width="1"/>
<!-- Coral focal tint on the all-three intersection -->
<g clip-path="url(#clip-center)">
<g clip-path="url(#clip-center-2)">
<circle cx="572" cy="320" r="140" fill="rgba(247,89,31,0.10)"/>
</g>
</g>
<!-- Set labels -->
<text x="500" y="20" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Desirable</text>
<text x="500" y="36" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">PEOPLE WANT IT</text>
<text x="152" y="400" fill="#52534e" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="start">Feasible</text>
<text x="152" y="416" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="start" letter-spacing="0.14em">WE CAN BUILD IT</text>
<text x="848" y="400" fill="#65655c" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="end">Viable</text>
<text x="848" y="416" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.14em">BUSINESS SUSTAINS</text>
<!-- Pairwise intersection labels -->
<text x="360" y="232" fill="#52534e" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Prototype</text>
<text x="360" y="248" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">no business model</text>
<text x="640" y="232" fill="#52534e" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Vaporware</text>
<text x="640" y="248" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">can't build it</text>
<text x="500" y="368" fill="#52534e" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Internal tool</text>
<text x="500" y="384" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">nobody wants it</text>
<!-- Focal: all-three center -->
<text x="500" y="260" fill="#f7591f" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Shippable</text>
<text x="500" y="276" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">THE SWEET SPOT</text>
<!-- Legend strip -->
<line x1="40" y1="456" x2="960" y2="456" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="472" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="488" r="6" fill="none" stroke="#f7591f" stroke-width="1.2"/>
<text x="68" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">All three — ship it</text>
<circle cx="192" cy="488" r="6" fill="none" stroke="#52534e" stroke-width="1"/>
<text x="208" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Two of three — incomplete</text>
<text x="380" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Coral marks the intersection that earns the work. The others name the traps.</text>
</svg>
</div>
<div class="cards">
<div class="card">
<p class="eyebrow">THE HEADLINE</p>
<div class="card-header"><span class="card-dot coral"></span><h3>One sweet spot, in coral</h3></div>
<p>Three overlapping circles create seven regions. Six of them are diagnostic — they name the failure mode. Only the center earns the coral. If every region is colored, the diagram stops prioritizing anything.</p>
</div>
<div class="card">
<div class="card-header"><span class="card-dot ink"></span><h3>The three tests</h3></div>
<ul><li>Desirable — someone pulls for it</li><li>Feasible — the team can actually build it</li><li>Viable — the economics hold up over time</li><li>All three, or you don't ship</li></ul>
</div>
<div class="card">
<div class="card-header"><span class="card-dot muted"></span><h3>The named traps</h3></div>
<p>Prototype (loved, buildable, no model). Vaporware (loved, profitable, un-buildable). Internal tool (buildable, profitable, unloved). Labeling each one makes the map more useful than the center alone.</p>
</div>
</div>
<div class="footer">
<span>good design · desirable × feasible × viable</span>
<span>example · diagram-design</span>
</div>
</div>
</body>
</html>
+137
View File
@@ -0,0 +1,137 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Good design · Desirable × Feasible × Viable</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">Venn · Diagram Design</p>
<h1>Good design · Desirable × Feasible × Viable</h1>
<svg viewBox="0 0 1000 500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<!-- Clip to the all-three intersection (centroid region) for the coral tint -->
<clipPath id="clip-center">
<circle cx="500" cy="180" r="140"/>
</clipPath>
<clipPath id="clip-center-2">
<circle cx="428" cy="320" r="140"/>
</clipPath>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Three set circles (stroke + very-low-opacity tint; tints compound in overlaps) -->
<!-- Desirable — top, ink -->
<circle cx="500" cy="180" r="140" fill="rgba(11,13,11,0.04)" stroke="#0b0d0b" stroke-width="1"/>
<!-- Feasible — bottom-left, muted -->
<circle cx="428" cy="320" r="140" fill="rgba(82,83,78,0.05)" stroke="#52534e" stroke-width="1"/>
<!-- Viable — bottom-right, soft -->
<circle cx="572" cy="320" r="140" fill="rgba(101,101,92,0.05)" stroke="#65655c" stroke-width="1"/>
<!-- Coral focal tint on the all-three intersection -->
<g clip-path="url(#clip-center)">
<g clip-path="url(#clip-center-2)">
<circle cx="572" cy="320" r="140" fill="rgba(247,89,31,0.10)"/>
</g>
</g>
<!-- Set labels (outside circles, pinned to far side) -->
<!-- Desirable -->
<text x="500" y="20" fill="#0b0d0b" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Desirable</text>
<text x="500" y="36" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">PEOPLE WANT IT</text>
<!-- Feasible -->
<text x="152" y="400" fill="#52534e" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="start">Feasible</text>
<text x="152" y="416" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="start" letter-spacing="0.14em">WE CAN BUILD IT</text>
<!-- Viable -->
<text x="848" y="400" fill="#65655c" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="end">Viable</text>
<text x="848" y="416" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="end" letter-spacing="0.14em">BUSINESS SUSTAINS</text>
<!-- Pairwise intersection labels (inside overlap regions) -->
<!-- Desirable ∩ Feasible (upper-left overlap): "Prototype" — between top and BL -->
<text x="360" y="232" fill="#52534e" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Prototype</text>
<text x="360" y="248" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">no business model</text>
<!-- Desirable ∩ Viable (upper-right overlap): "Vaporware" -->
<text x="640" y="232" fill="#52534e" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Vaporware</text>
<text x="640" y="248" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">can't build it</text>
<!-- Feasible ∩ Viable (lower overlap): "Internal tool" -->
<text x="500" y="368" fill="#52534e" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Internal tool</text>
<text x="500" y="384" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">nobody wants it</text>
<!-- Focal: all-three center -->
<text x="500" y="260" fill="#f7591f" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Shippable</text>
<text x="500" y="276" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.14em">THE SWEET SPOT</text>
<!-- Legend strip -->
<line x1="40" y1="456" x2="960" y2="456" stroke="rgba(11,13,11,0.10)" stroke-width="0.8"/>
<text x="40" y="472" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
<circle cx="52" cy="488" r="6" fill="none" stroke="#f7591f" stroke-width="1.2"/>
<text x="68" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">All three — ship it</text>
<circle cx="192" cy="488" r="6" fill="none" stroke="#52534e" stroke-width="1"/>
<text x="208" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif">Two of three — incomplete</text>
<text x="380" y="492" fill="#52534e" font-size="8.5" font-family="'Geist', sans-serif" font-style="italic">Coral marks the intersection that earns the work. The others name the traps.</text>
</svg>
</div>
</body>
</html>
+206
View File
@@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Diagram Design · Gallery</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--paper: #f5f4ed;
--paper-2: #efeee5;
--ink: #0b0d0b;
--muted: #52534e;
--soft: #65655c;
--rule: rgba(11,13,11,0.12);
--rule-strong: rgba(11,13,11,0.25);
--accent: #f7591f;
--sans: 'Geist', system-ui, sans-serif;
--serif: 'Instrument Serif', serif;
--mono: 'Geist Mono', ui-monospace, monospace;
}
html, body { height: 100%; }
body {
font-family: var(--sans);
background: var(--paper);
color: var(--ink);
display: flex;
flex-direction: column;
overflow: hidden;
}
.topbar {
padding: 1rem 1.25rem 0.625rem;
border-bottom: 1px solid var(--rule);
flex: 0 0 auto;
}
.title-row {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 0.75rem;
gap: 1rem;
}
.title-row h1 {
font-family: var(--serif);
font-size: 1.5rem;
font-weight: 400;
letter-spacing: -0.01em;
line-height: 1;
}
.title-row .meta {
font-family: var(--mono);
font-size: 0.66rem;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--muted);
}
.title-row .open-raw {
font-family: var(--mono);
font-size: 0.66rem;
letter-spacing: 0.06em;
color: var(--muted);
text-decoration: none;
padding: 0.3rem 0.625rem;
border: 1px solid var(--rule);
border-radius: 4px;
transition: color 0.15s, border-color 0.15s;
}
.open-raw:hover { color: var(--accent); border-color: var(--accent); }
.tabs {
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
margin-bottom: 0.5rem;
}
.tabs.variants {
margin-bottom: 0;
padding-top: 0.5rem;
border-top: 1px solid var(--rule);
}
.tab {
font-family: var(--sans);
font-size: 0.8125rem;
font-weight: 500;
padding: 0.375rem 0.75rem;
background: transparent;
color: var(--muted);
border: 1px solid var(--rule);
border-radius: 4px;
cursor: pointer;
transition: all 0.12s;
letter-spacing: -0.005em;
}
.tab:hover {
color: var(--ink);
border-color: var(--rule-strong);
}
.tab.active {
background: var(--ink);
color: var(--paper);
border-color: var(--ink);
}
.tab .eyebrow {
display: inline-block;
margin-right: 0.25rem;
font-family: var(--mono);
font-size: 0.56rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: inherit;
opacity: 0.5;
}
.tab.new::after {
content: 'NEW';
display: inline-block;
margin-left: 0.35rem;
font-family: var(--mono);
font-size: 0.54rem;
letter-spacing: 0.12em;
color: var(--accent);
vertical-align: 1px;
}
.tab.active.new::after { color: var(--paper); }
main {
flex: 1 1 auto;
position: relative;
background: var(--paper-2);
overflow: hidden;
}
iframe {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
border: 0;
background: var(--paper);
display: block;
}
</style>
</head>
<body>
<header class="topbar">
<div class="title-row">
<h1>Diagram Design <span class="meta" style="font-family: var(--mono); font-size: 0.66rem; margin-left: 0.5rem;">· gallery</span></h1>
<a class="open-raw" id="open-raw" href="#" target="_blank" rel="noopener">open in new tab ↗</a>
</div>
<div class="tabs" id="type-tabs" role="tablist" aria-label="Diagram type">
<button class="tab active" data-type="architecture"><span class="eyebrow">01</span>Architecture</button>
<button class="tab" data-type="flowchart"><span class="eyebrow">02</span>Flowchart</button>
<button class="tab" data-type="sequence"><span class="eyebrow">03</span>Sequence</button>
<button class="tab" data-type="state"><span class="eyebrow">04</span>State</button>
<button class="tab" data-type="er"><span class="eyebrow">05</span>ER</button>
<button class="tab" data-type="timeline"><span class="eyebrow">06</span>Timeline</button>
<button class="tab" data-type="swimlane"><span class="eyebrow">07</span>Swimlane</button>
<button class="tab" data-type="quadrant"><span class="eyebrow">08</span>Quadrant</button>
<button class="tab new" data-type="nested"><span class="eyebrow">09</span>Nested</button>
<button class="tab new" data-type="tree"><span class="eyebrow">10</span>Tree</button>
<button class="tab new" data-type="layers"><span class="eyebrow">11</span>Layers</button>
<button class="tab new" data-type="venn"><span class="eyebrow">12</span>Venn</button>
<button class="tab new" data-type="pyramid"><span class="eyebrow">13</span>Pyramid</button>
</div>
<div class="tabs variants" id="variant-tabs" role="tablist" aria-label="Variant">
<button class="tab active" data-variant="">Minimal light</button>
<button class="tab" data-variant="-dark">Minimal dark</button>
<button class="tab" data-variant="-full">Full editorial</button>
</div>
</header>
<main>
<iframe id="preview" src="example-architecture.html" title="Preview"></iframe>
</main>
<script>
const state = { type: 'architecture', variant: '' };
const iframe = document.getElementById('preview');
const openRaw = document.getElementById('open-raw');
function update() {
const src = `example-${state.type}${state.variant}.html`;
iframe.src = src;
openRaw.href = src;
}
function bindTabs(containerId, key) {
const container = document.getElementById(containerId);
container.addEventListener('click', (e) => {
const btn = e.target.closest('.tab');
if (!btn) return;
container.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
btn.classList.add('active');
state[key] = btn.dataset[key];
update();
});
}
bindTabs('type-tabs', 'type');
bindTabs('variant-tabs', 'variant');
update();
</script>
</body>
</html>
+79
View File
@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Diagram</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #1c1a17; /* deep warm charcoal */
--color-ink: #f1efe7; /* warm off-white */
--color-muted: #a8a69d;
--color-accent: #ff6a30;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">[Type] · Diagram Design</p>
<h1>[Diagram title]</h1>
<svg viewBox="0 0 1000 600" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(241,239,231,0.08)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#a8a69d"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#ff6a30"/></marker>
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#5ba8eb"/></marker>
</defs>
<rect width="100%" height="100%" fill="#1c1a17"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.6"/>
<!-- Draw arrows first, then nodes. Replace with your content. -->
</svg>
</div>
</body>
</html>
+403
View File
@@ -0,0 +1,403 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[PROJECT NAME] Architecture</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* ── Tokens ─────────────────────────────────────────────────── */
:root {
--color-paper: #f5f4ed;
--color-paper-2: #efeee5;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-soft: #65655c;
--color-rule: rgba(11,13,11,0.12);
--color-rule-solid: rgba(135,139,134,0.25);
--color-accent: #f7591f;
--color-accent-tint: rgba(247,89,31,0.08);
--color-link: #1a70c7;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', 'Times New Roman', serif;
--font-mono: 'Geist Mono', ui-monospace, Menlo, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
min-height: 100vh;
padding: 3rem 2rem;
color: var(--color-ink);
}
.container { max-width: 1200px; margin: 0 auto; }
/* ── Header ─────────────────────────────────────────────────── */
.header { margin-bottom: 2.5rem; }
.header-eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.75rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.1;
color: var(--color-ink);
margin-bottom: 0.5rem;
}
.subtitle {
font-family: var(--font-sans);
font-size: 1rem;
line-height: 1.55;
color: var(--color-muted);
max-width: 52ch;
}
/* ── Diagram container ────────────────────────────────────────── */
.diagram-container {
background: var(--color-paper-2);
border-radius: 8px;
border: 1px solid var(--color-rule);
padding: 1.5rem;
overflow-x: auto;
}
svg { width: 100%; min-width: 900px; display: block; }
/* ── Info cards ───────────────────────────────────────────────── */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
margin-top: 1.5rem;
}
.card {
background: #ffffff;
border-radius: 6px;
border: 1px solid var(--color-rule);
padding: 1.25rem;
}
.card-header {
display: flex;
align-items: center;
gap: 0.6rem;
margin-bottom: 0.875rem;
padding-bottom: 0.875rem;
border-bottom: 1px solid rgba(11,13,11,0.08);
}
.card-dot {
width: 7px; height: 7px;
border-radius: 50%;
flex-shrink: 0;
}
.card-dot.ink { background: var(--color-ink); }
.card-dot.muted { background: var(--color-muted); }
.card-dot.coral { background: var(--color-accent); }
.card-dot.link { background: var(--color-link); }
.card-dot.soft { background: var(--color-soft); }
.card h3 {
font-family: var(--font-sans);
font-size: 0.875rem;
font-weight: 600;
color: var(--color-ink);
letter-spacing: -0.005em;
}
.card ul {
list-style: none;
color: var(--color-muted);
font-size: 0.8125rem;
line-height: 1.55;
}
.card li {
margin-bottom: 0.3rem;
padding-left: 0.875rem;
position: relative;
}
.card li::before {
content: '—';
position: absolute;
left: 0;
color: rgba(11,13,11,0.25);
font-size: 0.75rem;
}
/* ── Footer ─────────────────────────────────────────────────── */
.footer {
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid rgba(11,13,11,0.10);
font-family: var(--font-mono);
font-size: 0.72rem;
letter-spacing: 0.06em;
color: var(--color-soft);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
}
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<div class="header">
<p class="header-eyebrow">Architecture · [Date]</p>
<h1>[Project Name]</h1>
<p class="subtitle">[One-sentence description of what this diagram shows.]</p>
</div>
<!-- Main Diagram -->
<div class="diagram-container">
<svg viewBox="0 0 1000 700" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- Dot grid background (matches site .hero-terminal pattern) -->
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<!-- Arrow: muted (default — generic / internal connections) -->
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#52534e"/>
</marker>
<!-- Arrow: coral (accent — primary / highlighted flows) -->
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#f7591f"/>
</marker>
<!-- Arrow: link-blue (#1a70c7 — HTTP/API / external calls) -->
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#1a70c7"/>
</marker>
</defs>
<!-- Background: paper + dot grid -->
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.6"/>
<!-- =================================================================
DRAW ARROWS FIRST — they paint behind boxes (SVG document order).
================================================================= -->
<!-- HTTP/API arrow (link-blue) with label -->
<line x1="130" y1="305" x2="195" y2="305" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="162" y="297" fill="#1a70c7" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">HTTPS</text>
<!-- Generic internal arrow -->
<line x1="310" y1="305" x2="356" y2="305" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Vertical arrow -->
<line x1="253" y1="332" x2="253" y2="376" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- Auth / security flow (dashed coral) -->
<path d="M 80 140 L 80 200 Q 80 218 98 218 L 200 218 Q 218 218 218 236 L 218 276"
fill="none" stroke="#f7591f" stroke-width="1.2" stroke-dasharray="5,4"
marker-end="url(#arrow-accent)"/>
<text x="148" y="212" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">JWT</text>
<!-- Primary data flow (coral) -->
<line x1="620" y1="305" x2="696" y2="305" stroke="#f7591f" stroke-width="1.2" marker-end="url(#arrow-accent)"/>
<text x="655" y="297" fill="#f7591f" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">TLS</text>
<!-- =================================================================
COMPONENT BOXES
Pattern: opaque paper rect first (masks arrows), then styled rect.
Mono type labels use Geist Mono — mono is dominant in tool/data.
================================================================= -->
<!-- ── External / User ──────────────────────────────────────── -->
<rect x="30" y="278" width="100" height="54" rx="6" fill="#f5f4ed"/>
<rect x="30" y="278" width="100" height="54" rx="6" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<!-- Rectangular type tag (not rounded — brand rule) -->
<rect x="38" y="284" width="26" height="12" rx="2" fill="transparent" stroke="rgba(101,101,92,0.4)" stroke-width="0.8"/>
<text x="51" y="293" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
<!-- Main label -->
<text x="80" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Users</text>
<text x="80" y="323" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser / Mobile</text>
<!-- ── Security / Auth ──────────────────────────────────────── -->
<rect x="30" y="78" width="100" height="56" rx="6" fill="#f5f4ed"/>
<rect x="30" y="78" width="100" height="56" rx="6" fill="rgba(247,89,31,0.06)" stroke="rgba(247,89,31,0.50)" stroke-width="1"/>
<rect x="38" y="84" width="28" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.40)" stroke-width="0.8"/>
<text x="52" y="93" fill="rgba(247,89,31,0.8)" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">AUTH</text>
<text x="80" y="110" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Auth Provider</text>
<text x="80" y="125" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">OAuth 2.0</text>
<!-- ── Region boundary (dashed) ─────────────────────────────── -->
<rect x="158" y="38" width="822" height="624" rx="8" fill="transparent" stroke="rgba(11,13,11,0.18)" stroke-width="1" stroke-dasharray="6,4"/>
<text x="170" y="55" fill="#52534e" font-size="8" font-weight="500" font-family="'Geist Mono', monospace" letter-spacing="0.12em">AWS REGION · US-WEST-2</text>
<!-- ── Cloud / CDN (with faded watermark numeral — slide card pattern) -->
<rect x="198" y="278" width="112" height="54" rx="6" fill="#f5f4ed"/>
<rect x="198" y="278" width="112" height="54" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<!-- Faded mono watermark numeral (background) -->
<text x="294" y="323" fill="rgba(11,13,11,0.06)" font-size="40" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">01</text>
<rect x="206" y="284" width="24" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="218" y="293" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CDN</text>
<text x="254" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">CloudFront</text>
<text x="254" y="323" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">AWS CDN</text>
<!-- ── Cloud / Storage ───────────────────────────────────────── -->
<rect x="198" y="378" width="112" height="102" rx="6" fill="#f5f4ed"/>
<rect x="198" y="378" width="112" height="102" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="294" y="468" fill="rgba(11,13,11,0.06)" font-size="40" font-weight="600" font-family="'Geist Mono', monospace" text-anchor="end">02</text>
<rect x="206" y="384" width="22" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="217" y="393" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">S3</text>
<text x="254" y="408" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">S3 Buckets</text>
<text x="254" y="426" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">bucket-assets</text>
<text x="254" y="440" fill="#52534e" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle">bucket-uploads</text>
<text x="254" y="466" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">OAI PROTECTED</text>
<!-- ── Security group boundary ───────────────────────────────── -->
<rect x="348" y="264" width="120" height="80" rx="6" fill="transparent" stroke="rgba(247,89,31,0.45)" stroke-width="1" stroke-dasharray="4,4"/>
<text x="356" y="278" fill="rgba(247,89,31,0.7)" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.08em">SG · :443</text>
<!-- ── Load Balancer (inside security group) ──────────────────── -->
<rect x="358" y="282" width="100" height="54" rx="6" fill="#f5f4ed"/>
<rect x="358" y="282" width="100" height="54" rx="6" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<rect x="366" y="288" width="22" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.22)" stroke-width="0.8"/>
<text x="377" y="297" fill="#65655c" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.06em">LB</text>
<text x="408" y="311" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Load Balancer</text>
<text x="408" y="326" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">HTTPS :443</text>
<!-- ── Backend / API ─────────────────────────────────────────── -->
<rect x="508" y="278" width="112" height="54" rx="6" fill="#f5f4ed"/>
<rect x="508" y="278" width="112" height="54" rx="6" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<rect x="516" y="284" width="26" height="12" rx="2" fill="transparent" stroke="rgba(11,13,11,0.40)" stroke-width="0.8"/>
<text x="529" y="293" fill="#0b0d0b" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">API</text>
<text x="564" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">API Server</text>
<text x="564" y="323" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">FastAPI :8000</text>
<!-- ── Database ───────────────────────────────────────────────── -->
<rect x="698" y="278" width="120" height="54" rx="6" fill="#f5f4ed"/>
<rect x="698" y="278" width="120" height="54" rx="6" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<rect x="706" y="284" width="22" height="12" rx="2" fill="transparent" stroke="rgba(82,83,78,0.50)" stroke-width="0.8"/>
<text x="717" y="293" fill="#52534e" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">DB</text>
<text x="758" y="308" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Database</text>
<text x="758" y="323" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">PostgreSQL</text>
<!-- ── Frontend / UI ─────────────────────────────────────────── -->
<rect x="198" y="518" width="200" height="112" rx="6" fill="#f5f4ed"/>
<rect x="198" y="518" width="200" height="112" rx="6" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<rect x="206" y="524" width="22" height="12" rx="2" fill="transparent" stroke="rgba(247,89,31,0.50)" stroke-width="0.8"/>
<text x="217" y="533" fill="#f7591f" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">UI</text>
<text x="298" y="550" fill="#0b0d0b" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Web App</text>
<text x="298" y="567" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">React + TypeScript</text>
<text x="298" y="581" fill="#52534e" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Astro SSG</text>
<!-- Link-blue URL label -->
<text x="298" y="614" fill="#1a70c7" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.04em">app.example.com</text>
<!-- =================================================================
LEGEND — OUTSIDE all boundary boxes.
Region boundary ends at y=662 → legend starts at y=682.
================================================================= -->
<text x="510" y="544" fill="#0b0d0b" font-size="9" font-weight="500" font-family="'Geist Mono', monospace" letter-spacing="0.12em">LEGEND</text>
<rect x="510" y="558" width="14" height="10" rx="2" fill="rgba(247,89,31,0.08)" stroke="#f7591f" stroke-width="1"/>
<text x="530" y="567" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Frontend / UI</text>
<rect x="510" y="576" width="14" height="10" rx="2" fill="#ffffff" stroke="#0b0d0b" stroke-width="1"/>
<text x="530" y="585" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Backend / API</text>
<rect x="510" y="594" width="14" height="10" rx="2" fill="rgba(11,13,11,0.03)" stroke="rgba(11,13,11,0.30)" stroke-width="1"/>
<text x="530" y="603" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Cloud / Service</text>
<rect x="510" y="612" width="14" height="10" rx="2" fill="rgba(11,13,11,0.05)" stroke="#52534e" stroke-width="1"/>
<text x="530" y="621" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Database</text>
<rect x="510" y="630" width="14" height="10" rx="2" fill="rgba(82,83,78,0.10)" stroke="#65655c" stroke-width="1"/>
<text x="530" y="639" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">External / User</text>
<!-- Arrow types -->
<line x1="510" y1="655" x2="524" y2="655" stroke="#1a70c7" stroke-width="1.2" marker-end="url(#arrow-link)"/>
<text x="530" y="659" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">HTTP / API call</text>
<line x1="510" y1="671" x2="524" y2="671" stroke="#f7591f" stroke-width="1.2" stroke-dasharray="4,3" marker-end="url(#arrow-accent)"/>
<text x="530" y="675" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Auth flow</text>
<line x1="510" y1="687" x2="524" y2="687" stroke="#52534e" stroke-width="1.2" marker-end="url(#arrow)"/>
<text x="530" y="691" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Internal connection</text>
<rect x="510" y="698" width="14" height="10" rx="2" fill="transparent" stroke="rgba(247,89,31,0.45)" stroke-width="1" stroke-dasharray="3,3"/>
<text x="530" y="707" fill="#52534e" font-size="9" font-family="'Geist', sans-serif">Security group</text>
</svg>
</div>
<!-- Info Cards -->
<div class="cards">
<div class="card">
<div class="card-header">
<span class="card-dot coral"></span>
<h3>Card Title 1</h3>
</div>
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
<li>Item four</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<span class="card-dot ink"></span>
<h3>Card Title 2</h3>
</div>
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
<li>Item four</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<span class="card-dot muted"></span>
<h3>Card Title 3</h3>
</div>
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
<li>Item four</li>
</ul>
</div>
</div>
<!-- Footer -->
<div class="footer">
<span>[Project Name] · Architecture Overview</span>
<span>[Date]</span>
</div>
</div>
</body>
</html>
+79
View File
@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Diagram</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-paper: #f5f4ed;
--color-ink: #0b0d0b;
--color-muted: #52534e;
--color-accent: #f7591f;
--font-sans: 'Geist', system-ui, sans-serif;
--font-serif: 'Instrument Serif', serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
}
body {
font-family: var(--font-sans);
background: var(--color-paper);
color: var(--color-ink);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem 2rem;
}
.frame { max-width: 1200px; width: 100%; }
.eyebrow {
font-family: var(--font-mono);
font-size: 0.66rem;
font-weight: 500;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--color-muted);
margin-bottom: 0.5rem;
}
h1 {
font-family: var(--font-serif);
font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--color-ink);
margin-bottom: 1.5rem;
}
svg { width: 100%; min-width: 900px; display: block; }
</style>
</head>
<body>
<div class="frame">
<p class="eyebrow">[Type] · Diagram Design</p>
<h1>[Diagram title]</h1>
<svg viewBox="0 0 1000 600" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="0.9" fill="rgba(11,13,11,0.10)"/>
</pattern>
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#52534e"/></marker>
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f7591f"/></marker>
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#1a70c7"/></marker>
</defs>
<rect width="100%" height="100%" fill="#f5f4ed"/>
<rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
<!-- Draw arrows first, then nodes. Replace with your content. -->
</svg>
</div>
</body>
</html>