Skip to content

Commit c00f951

Browse files
committed
feat: add syntax highlighting, use Epilogue/DM Mono fonts, fix SVG diagrams
- Use DM Mono for headings, Epilogue for blog/mission titles - Add highlight.js with dynamic imports for C++, Python, Go - Fix convergence chart clipped label (viewBox height) - Center delimiter/length-prefix and tokenization diagrams - Widen DAG boxes so text fits without overflow
1 parent 78f16c2 commit c00f951

12 files changed

Lines changed: 129 additions & 45 deletions

bun.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
1313
<link rel="preconnect" href="https://fonts.googleapis.com" />
1414
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
15-
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
15+
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,700;12..96,800&family=Epilogue:wght@300;400;500;600;700;800&family=Outfit:wght@300;400;500;600;700;800;900&family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=JetBrains+Mono:wght@400;500&family=DM+Mono:wght@300;400;500&display=swap" rel="stylesheet" />
1616
<script>
1717
(function() {
1818
var t = localStorage.getItem("theme");

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@
1212
"@sveltejs/vite-plugin-svelte": "^6.2.1",
1313
"svelte": "^5.45.2",
1414
"vite": "^7.3.1"
15+
},
16+
"dependencies": {
17+
"highlight.js": "^11.11.1"
1518
}
1619
}

src/components/BlogCard.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
}
5858
5959
.title {
60-
font-family: var(--font-heading);
60+
font-family: "Epilogue", var(--font-heading);
6161
font-size: 1.0625rem;
6262
font-weight: 600;
6363
color: var(--text-primary);

src/components/Hero.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
}
2222
2323
h1 {
24+
font-family: var(--font-heading);
2425
font-size: clamp(2.5rem, 6vw, 5rem);
25-
font-weight: 900;
26-
letter-spacing: -0.04em;
26+
font-weight: 800;
27+
letter-spacing: -0.03em;
2728
margin-bottom: 20px;
2829
line-height: 1.05;
2930
}

src/data/posts/automated-code-generation-clean-pipelines.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default `
1111
1212
<svg viewBox="0 0 600 260" fill="none" xmlns="http://www.w3.org/2000/svg" style="max-width:560px;margin:32px auto;display:block;">
1313
<style>
14-
.gt { font-family: var(--font-mono); font-size: 11px; fill: var(--text-primary); }
14+
.gt { font-family: var(--font-body); font-size: 12px; fill: var(--text-primary); }
1515
.gl { font-family: var(--font-body); font-size: 13px; fill: var(--text-secondary); }
1616
.gbox { fill: var(--bg-surface); stroke: var(--border-default); stroke-width: 1.5; }
1717
.garrow { stroke: var(--text-muted); stroke-width: 1.5; fill: none; marker-end: url(#ah3); }
@@ -22,22 +22,22 @@ export default `
2222
</marker>
2323
</defs>
2424
<text x="300" y="18" class="gl" text-anchor="middle" font-weight="600">Cleaning Pipeline DAG</text>
25-
<rect x="230" y="30" width="140" height="36" class="gbox"/>
25+
<rect x="215" y="30" width="170" height="36" class="gbox"/>
2626
<text x="300" y="53" class="gt" text-anchor="middle">Type Inference</text>
27-
<path d="M250 66 L170 90" class="garrow"/>
28-
<path d="M350 66 L430 90" class="garrow"/>
29-
<rect x="100" y="90" width="140" height="36" class="gbox"/>
30-
<text x="170" y="113" class="gt" text-anchor="middle">Missing Value Detection</text>
31-
<rect x="360" y="90" width="140" height="36" class="gbox"/>
32-
<text x="430" y="113" class="gt" text-anchor="middle">Outlier Detection</text>
33-
<path d="M170 126 L170 150" class="garrow"/>
34-
<path d="M430 126 L430 150" class="garrow"/>
35-
<rect x="100" y="150" width="140" height="36" class="gbox"/>
36-
<text x="170" y="173" class="gt" text-anchor="middle">Imputation Strategy</text>
37-
<rect x="360" y="150" width="140" height="36" class="gbox"/>
38-
<text x="430" y="173" class="gt" text-anchor="middle">Clip / Transform</text>
39-
<path d="M170 186 L265 210" class="garrow"/>
40-
<path d="M430 186 L335 210" class="garrow"/>
27+
<path d="M245 66 L155 90" class="garrow"/>
28+
<path d="M355 66 L445 90" class="garrow"/>
29+
<rect x="60" y="90" width="190" height="36" class="gbox"/>
30+
<text x="155" y="113" class="gt" text-anchor="middle">Missing Value Detection</text>
31+
<rect x="350" y="90" width="190" height="36" class="gbox"/>
32+
<text x="445" y="113" class="gt" text-anchor="middle">Outlier Detection</text>
33+
<path d="M155 126 L155 150" class="garrow"/>
34+
<path d="M445 126 L445 150" class="garrow"/>
35+
<rect x="60" y="150" width="190" height="36" class="gbox"/>
36+
<text x="155" y="173" class="gt" text-anchor="middle">Imputation Strategy</text>
37+
<rect x="350" y="150" width="190" height="36" class="gbox"/>
38+
<text x="445" y="173" class="gt" text-anchor="middle">Clip / Transform</text>
39+
<path d="M155 186 L255 210" class="garrow"/>
40+
<path d="M445 186 L345 210" class="garrow"/>
4141
<rect x="210" y="210" width="180" height="36" class="gbox" stroke="var(--accent)" stroke-width="2"/>
4242
<text x="300" y="233" class="gt" text-anchor="middle" fill="var(--accent)">Code Generation</text>
4343
</svg>

src/data/posts/beyond-edit-distance.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ export default `
1111
1212
<svg viewBox="0 0 600 200" fill="none" xmlns="http://www.w3.org/2000/svg" style="max-width:560px;margin:32px auto;display:block;">
1313
<style>
14-
.d-text { font-family: var(--font-mono); font-size: 12px; fill: var(--text-primary); }
14+
.d-text { font-family: var(--font-mono); font-size: 11px; fill: var(--text-primary); }
1515
.d-label { font-family: var(--font-body); font-size: 13px; fill: var(--text-secondary); }
1616
</style>
17-
<text x="20" y="20" class="d-label" font-weight="600">Tokenization: Two Approaches</text>
18-
<rect x="20" y="35" width="260" height="65" fill="var(--bg-surface)" stroke="var(--border-default)" stroke-width="1.5"/>
19-
<text x="150" y="53" class="d-label" text-anchor="middle" font-weight="500">Whitespace Splitting</text>
20-
<text x="150" y="73" class="d-text" text-anchor="middle">"wireless bluetooth headphones"</text>
21-
<text x="150" y="90" class="d-text" text-anchor="middle" fill="var(--accent)">[wireless, bluetooth, headphones]</text>
22-
<rect x="320" y="35" width="260" height="65" fill="var(--bg-surface)" stroke="var(--border-default)" stroke-width="1.5"/>
23-
<text x="450" y="53" class="d-label" text-anchor="middle" font-weight="500">Character N-grams (n=3)</text>
24-
<text x="450" y="73" class="d-text" text-anchor="middle">"wireless"</text>
25-
<text x="450" y="90" class="d-text" text-anchor="middle" fill="var(--accent)">[wir, ire, rel, ele, les, ess]</text>
17+
<text x="300" y="18" class="d-label" text-anchor="middle" font-weight="600">Tokenization: Two Approaches</text>
18+
<rect x="20" y="32" width="268" height="68" fill="var(--bg-surface)" stroke="var(--border-default)" stroke-width="1.5"/>
19+
<text x="154" y="52" class="d-label" text-anchor="middle" font-weight="500">Whitespace Splitting</text>
20+
<text x="154" y="72" class="d-text" text-anchor="middle">"wireless bluetooth headphones"</text>
21+
<text x="154" y="89" class="d-text" text-anchor="middle" fill="var(--accent)">[wireless, bluetooth, headphones]</text>
22+
<rect x="312" y="32" width="268" height="68" fill="var(--bg-surface)" stroke="var(--border-default)" stroke-width="1.5"/>
23+
<text x="446" y="52" class="d-label" text-anchor="middle" font-weight="500">Character N-grams (n=3)</text>
24+
<text x="446" y="72" class="d-text" text-anchor="middle">"wireless"</text>
25+
<text x="446" y="89" class="d-text" text-anchor="middle" fill="var(--accent)">[wir, ire, rel, ele, les, ess]</text>
2626
<rect x="20" y="120" width="560" height="60" fill="var(--accent)" fill-opacity="0.15" stroke="var(--accent)" stroke-width="1.5"/>
2727
<text x="300" y="142" class="d-label" text-anchor="middle">Whitespace: preserves semantic units, fast, order-dependent</text>
2828
<text x="300" y="162" class="d-label" text-anchor="middle">N-grams: captures subword similarity, handles typos, slower</text>

src/data/posts/binary-protocols-length-prefixing.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export default `
1616
.bbox { fill: var(--bg-surface); stroke: var(--border-default); stroke-width: 1.5; }
1717
</style>
1818
<text x="300" y="16" class="bl" text-anchor="middle" font-weight="600">Delimiter vs Length-Prefix: Field Access</text>
19-
<g transform="translate(20, 35)">
20-
<text x="260" y="10" class="bl" text-anchor="middle">Delimited (must scan all bytes to find field N)</text>
19+
<g transform="translate(135, 35)">
20+
<text x="165" y="10" class="bl" text-anchor="middle">Delimited (must scan all bytes to find field N)</text>
2121
<rect x="0" y="20" width="60" height="30" class="bbox"/>
2222
<text x="30" y="40" class="bt" text-anchor="middle">field1</text>
2323
<rect x="60" y="20" width="10" height="30" fill="var(--accent)" fill-opacity="0.4" stroke="var(--accent)" stroke-width="1.5"/>
@@ -35,8 +35,8 @@ export default `
3535
<path d="M0 62 L330 62" stroke="var(--accent)" stroke-width="2" stroke-dasharray="3,3"/>
3636
<text x="165" y="78" class="bt" text-anchor="middle" fill="var(--accent)">must scan 330 bytes to reach field4</text>
3737
</g>
38-
<g transform="translate(20, 130)">
39-
<text x="260" y="10" class="bl" text-anchor="middle">Length-Prefixed (jump directly to field N)</text>
38+
<g transform="translate(110, 130)">
39+
<text x="190" y="10" class="bl" text-anchor="middle">Length-Prefixed (jump directly to field N)</text>
4040
<rect x="0" y="20" width="20" height="30" fill="var(--accent)" fill-opacity="0.25" stroke="var(--accent)" stroke-width="1.5"/>
4141
<text x="10" y="40" class="bt" text-anchor="middle" fill="var(--accent)">6</text>
4242
<rect x="20" y="20" width="60" height="30" class="bbox"/>
@@ -53,8 +53,8 @@ export default `
5353
<text x="310" y="40" class="bt" text-anchor="middle" fill="var(--accent)">6</text>
5454
<rect x="320" y="20" width="60" height="30" class="bbox" stroke="var(--accent)" stroke-width="2"/>
5555
<text x="350" y="40" class="bt" text-anchor="middle" fill="var(--accent)">field4</text>
56-
<path d="M0 62 L300 62" stroke="var(--accent)" stroke-width="2"/>
57-
<text x="150" y="78" class="bt" text-anchor="middle" fill="var(--accent)">sum lengths: jump to byte 300 in O(1)</text>
56+
<path d="M0 62 L380 62" stroke="var(--accent)" stroke-width="2"/>
57+
<text x="190" y="78" class="bt" text-anchor="middle" fill="var(--accent)">sum lengths: jump to byte 300 in O(1)</text>
5858
</g>
5959
</svg>
6060

src/data/posts/estimating-pi-monte-carlo.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ PCG-64 3.14160 0.00001</code></pre>
8383
8484
<p>Each additional digit of accuracy costs <strong>100x more samples</strong>. For pi estimation, this convergence rate is impractical (we know pi to trillions of digits analytically). But for problems without analytical solutions, high-dimensional integrals, complex system simulations, Monte Carlo's guaranteed 1/sqrt(N) convergence regardless of dimensionality makes it the only practical method.</p>
8585
86-
<svg viewBox="0 0 600 220" fill="none" xmlns="http://www.w3.org/2000/svg" style="max-width:560px;margin:32px auto;display:block;">
86+
<svg viewBox="0 0 600 240" fill="none" xmlns="http://www.w3.org/2000/svg" style="max-width:560px;margin:32px auto;display:block;">
8787
<style>
8888
.et { font-family: var(--font-mono); font-size: 11px; fill: var(--text-primary); }
8989
.el { font-family: var(--font-body); font-size: 13px; fill: var(--text-secondary); }
@@ -102,7 +102,7 @@ PCG-64 3.14160 0.00001</code></pre>
102102
<text x="320" y="180" class="et" text-anchor="middle">10^6</text>
103103
<text x="460" y="180" class="et" text-anchor="middle">10^8</text>
104104
<path d="M20,30 L40,130 L60,50 L80,95 L120,65 L160,88 L200,75 L240,82 L280,78 L320,80 L360,79.5 L400,80.2 L440,79.9 L470,80" stroke="var(--accent)" stroke-width="2" fill="none"/>
105-
<text x="240" y="195" class="el" text-anchor="middle">Samples (N), log scale</text>
105+
<text x="240" y="200" class="el" text-anchor="middle">Samples (N), log scale</text>
106106
</g>
107107
</svg>
108108

src/pages/BlogPost.svelte

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
<script>
2+
import { onMount } from "svelte";
23
import { blogs } from "../data/blogs.js";
34
45
let { slug } = $props();
56
67
let post = $derived(blogs.find(b => b.slug === slug));
8+
let contentEl = $state(null);
79
810
function formatDate(dateStr) {
911
return new Date(dateStr).toLocaleDateString("en-US", {
@@ -12,6 +14,29 @@
1214
day: "numeric",
1315
});
1416
}
17+
18+
async function highlightCode() {
19+
if (!contentEl) return;
20+
const hljs = (await import("highlight.js/lib/core")).default;
21+
const cpp = (await import("highlight.js/lib/languages/cpp")).default;
22+
const python = (await import("highlight.js/lib/languages/python")).default;
23+
const go = (await import("highlight.js/lib/languages/go")).default;
24+
hljs.registerLanguage("cpp", cpp);
25+
hljs.registerLanguage("python", python);
26+
hljs.registerLanguage("go", go);
27+
contentEl.querySelectorAll("pre code").forEach(block => {
28+
hljs.highlightElement(block);
29+
});
30+
}
31+
32+
onMount(() => {
33+
highlightCode();
34+
});
35+
36+
$effect(() => {
37+
slug;
38+
if (contentEl) highlightCode();
39+
});
1540
</script>
1641

1742
<svelte:head>
@@ -31,7 +56,7 @@
3156
</div>
3257
<h1>{post.title}</h1>
3358
</header>
34-
<div class="article-content">
59+
<div class="article-content" bind:this={contentEl}>
3560
{@html post.content}
3661
</div>
3762
<footer class="article-footer">
@@ -94,13 +119,14 @@
94119
}
95120
96121
.article-meta h1 {
122+
font-family: "Epilogue", var(--font-heading);
97123
font-size: clamp(1.75rem, 4vw, 2.5rem);
98124
line-height: 1.2;
99125
letter-spacing: -0.03em;
100126
}
101127
102128
.article-content :global(h2) {
103-
font-family: var(--font-heading);
129+
font-family: "Epilogue", var(--font-heading);
104130
font-size: 1.5rem;
105131
font-weight: 600;
106132
margin-top: 48px;
@@ -109,7 +135,7 @@
109135
}
110136
111137
.article-content :global(h3) {
112-
font-family: var(--font-heading);
138+
font-family: "Epilogue", var(--font-heading);
113139
font-size: 1.25rem;
114140
font-weight: 500;
115141
margin-top: 32px;
@@ -133,6 +159,12 @@
133159
line-height: 1.6;
134160
}
135161
162+
.article-content :global(pre code) {
163+
background: none;
164+
border: none;
165+
padding: 0;
166+
}
167+
136168
.article-content :global(code) {
137169
font-family: var(--font-mono);
138170
font-size: 0.875em;
@@ -183,6 +215,49 @@
183215
font-style: italic;
184216
}
185217
218+
.article-content :global(.hljs) {
219+
background: transparent;
220+
color: var(--text-primary);
221+
}
222+
223+
.article-content :global(.hljs-keyword),
224+
.article-content :global(.hljs-built_in),
225+
.article-content :global(.hljs-type) {
226+
color: var(--accent);
227+
font-weight: 500;
228+
}
229+
230+
.article-content :global(.hljs-string),
231+
.article-content :global(.hljs-attr) {
232+
color: #b56b45;
233+
}
234+
235+
.article-content :global(.hljs-number),
236+
.article-content :global(.hljs-literal) {
237+
color: #8f6cc4;
238+
}
239+
240+
.article-content :global(.hljs-comment) {
241+
color: var(--text-muted);
242+
font-style: italic;
243+
}
244+
245+
.article-content :global(.hljs-function) {
246+
color: var(--text-primary);
247+
}
248+
249+
.article-content :global(.hljs-title) {
250+
color: #3a7cc2;
251+
}
252+
253+
.article-content :global(.hljs-params) {
254+
color: var(--text-secondary);
255+
}
256+
257+
.article-content :global(.hljs-meta) {
258+
color: var(--text-muted);
259+
}
260+
186261
.article-footer {
187262
margin-top: 64px;
188263
padding-top: 32px;

0 commit comments

Comments
 (0)