diff --git a/AGENTS.md b/AGENTS.md
index 829481bd..53baa755 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -38,4 +38,5 @@ PRs target `main`. Before starting, `git fetch origin` and set the upstream to t
`git stash` is one stack shared by every worktree; set work aside with a commit instead.
Use the Nix dev shell (direnv, or `nix develop --command just ...`) so tooling matches CI.
Run `just fix` before committing. `just check` alone is not verification: look at the change in the dev server (`just dev`, `just dev-pub`, or `just dev-watch`).
+Hand-drawn art ships as SVG: `just trace` the drawn PNG, compare the two, then commit only the SVG.
Quests: before starting work, run `quest guide` and follow it. The `quest` binary comes from the kixelated/quest flake input and serves the quest skills; change them upstream and bump the input.
diff --git a/bun.lock b/bun.lock
index 668eebc7..27899455 100644
--- a/bun.lock
+++ b/bun.lock
@@ -25,6 +25,7 @@
"@types/bun": "^1.4.3",
"@types/node": "^26.6.5",
"rolldown": "^1.2.14",
+ "sharp": "^0.35.5",
"shiki": "^4.5.0",
"tailwindcss": "^4.3.3",
"typescript": "^7.0.2",
@@ -439,7 +440,7 @@
"@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="],
- "@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
+ "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
@@ -1329,8 +1330,6 @@
"@astrojs/compiler-binding-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" } }, "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg=="],
- "@astrojs/compiler-binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
-
"@astrojs/rss/zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="],
"@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
@@ -1363,9 +1362,9 @@
"@babel/traverse/@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
- "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
+ "@bruits/satteri-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
- "@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
+ "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
"@jridgewell/gen-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
diff --git a/flake.nix b/flake.nix
index cf289090..05f21be9 100644
--- a/flake.nix
+++ b/flake.nix
@@ -60,6 +60,11 @@
# `quest check` and the quest-* skills; see the input.
quest-cli
+
+ # `just trace`, which turns hand-drawn art into SVG.
+ imagemagick
+ librsvg
+ potrace
];
# `just cards` imports Playwright from here rather than node_modules,
diff --git a/justfile b/justfile
index 5b231acf..a9f338d8 100644
--- a/justfile
+++ b/justfile
@@ -40,6 +40,11 @@ cards *args:
bun i
bun tools/cards/render.ts {{args}}
+# Trace hand-drawn PNGs into SVGs beside them (tools/drawn/trace.ts). Then delete
+# each PNG and point its references at the SVG; a cover still gets a PNG og:image.
+trace *args:
+ bun tools/drawn/trace.ts {{args}}
+
# Upgrade any tooling
upgrade:
# Update the NPM dependencies
diff --git a/package.json b/package.json
index 8d4de885..f06bfb4f 100644
--- a/package.json
+++ b/package.json
@@ -54,6 +54,7 @@
"@types/bun": "^1.4.3",
"@types/node": "^26.6.5",
"rolldown": "^1.2.14",
+ "sharp": "^0.35.5",
"shiki": "^4.5.0",
"tailwindcss": "^4.3.3",
"typescript": "^7.0.2",
diff --git a/public/blog/application-first/ai.png b/public/blog/application-first/ai.png
deleted file mode 100644
index a92fc23a..00000000
Binary files a/public/blog/application-first/ai.png and /dev/null differ
diff --git a/public/blog/application-first/ai.svg b/public/blog/application-first/ai.svg
new file mode 100644
index 00000000..211e5381
--- /dev/null
+++ b/public/blog/application-first/ai.svg
@@ -0,0 +1,98 @@
+
diff --git a/public/blog/application-first/step.png b/public/blog/application-first/step.png
deleted file mode 100644
index 018bbd65..00000000
Binary files a/public/blog/application-first/step.png and /dev/null differ
diff --git a/public/blog/application-first/step.svg b/public/blog/application-first/step.svg
new file mode 100644
index 00000000..f1c584af
--- /dev/null
+++ b/public/blog/application-first/step.svg
@@ -0,0 +1,229 @@
+
diff --git a/public/blog/application-first/sun.png b/public/blog/application-first/sun.png
deleted file mode 100644
index b23ce3b3..00000000
Binary files a/public/blog/application-first/sun.png and /dev/null differ
diff --git a/public/blog/application-first/sun.svg b/public/blog/application-first/sun.svg
new file mode 100644
index 00000000..bec82937
--- /dev/null
+++ b/public/blog/application-first/sun.svg
@@ -0,0 +1,127 @@
+
diff --git a/public/blog/avatar.png b/public/blog/avatar.png
deleted file mode 100644
index a3be38a2..00000000
Binary files a/public/blog/avatar.png and /dev/null differ
diff --git a/public/blog/avatar.svg b/public/blog/avatar.svg
new file mode 100644
index 00000000..5aac20e1
--- /dev/null
+++ b/public/blog/avatar.svg
@@ -0,0 +1,99 @@
+
diff --git a/public/blog/be-the-outlier/narwhal.png b/public/blog/be-the-outlier/narwhal.png
deleted file mode 100644
index b7d5aefd..00000000
Binary files a/public/blog/be-the-outlier/narwhal.png and /dev/null differ
diff --git a/public/blog/be-the-outlier/narwhal.svg b/public/blog/be-the-outlier/narwhal.svg
new file mode 100644
index 00000000..efbd6a77
--- /dev/null
+++ b/public/blog/be-the-outlier/narwhal.svg
@@ -0,0 +1,323 @@
+
diff --git a/public/blog/cars2/backfill.png b/public/blog/cars2/backfill.png
deleted file mode 100644
index 007d4571..00000000
Binary files a/public/blog/cars2/backfill.png and /dev/null differ
diff --git a/public/blog/cars2/backfill.svg b/public/blog/cars2/backfill.svg
new file mode 100644
index 00000000..60047476
--- /dev/null
+++ b/public/blog/cars2/backfill.svg
@@ -0,0 +1,615 @@
+
diff --git a/public/blog/cars2/fanout.png b/public/blog/cars2/fanout.png
deleted file mode 100644
index 02ee19a1..00000000
Binary files a/public/blog/cars2/fanout.png and /dev/null differ
diff --git a/public/blog/cars2/fanout.svg b/public/blog/cars2/fanout.svg
new file mode 100644
index 00000000..104edf6a
--- /dev/null
+++ b/public/blog/cars2/fanout.svg
@@ -0,0 +1,424 @@
+
diff --git a/public/blog/cars2/mom.png b/public/blog/cars2/mom.png
deleted file mode 100644
index 0bd1399b..00000000
Binary files a/public/blog/cars2/mom.png and /dev/null differ
diff --git a/public/blog/cars2/mom.svg b/public/blog/cars2/mom.svg
new file mode 100644
index 00000000..4094de9a
--- /dev/null
+++ b/public/blog/cars2/mom.svg
@@ -0,0 +1,276 @@
+
diff --git a/public/blog/cars2/queen.png b/public/blog/cars2/queen.png
deleted file mode 100644
index e5174ce5..00000000
Binary files a/public/blog/cars2/queen.png and /dev/null differ
diff --git a/public/blog/cars2/queen.svg b/public/blog/cars2/queen.svg
new file mode 100644
index 00000000..ab7365f2
--- /dev/null
+++ b/public/blog/cars2/queen.svg
@@ -0,0 +1,557 @@
+
diff --git a/public/blog/cars2/speed2.png b/public/blog/cars2/speed2.png
deleted file mode 100644
index 0a66b2a1..00000000
Binary files a/public/blog/cars2/speed2.png and /dev/null differ
diff --git a/public/blog/cars2/speed2.svg b/public/blog/cars2/speed2.svg
new file mode 100644
index 00000000..fd88e909
--- /dev/null
+++ b/public/blog/cars2/speed2.svg
@@ -0,0 +1,202 @@
+
diff --git a/public/blog/cars2/toilet.png b/public/blog/cars2/toilet.png
deleted file mode 100644
index 403052f5..00000000
Binary files a/public/blog/cars2/toilet.png and /dev/null differ
diff --git a/public/blog/demoqed/demoqed.png b/public/blog/demoqed/demoqed.png
deleted file mode 100644
index 0f2555f8..00000000
Binary files a/public/blog/demoqed/demoqed.png and /dev/null differ
diff --git a/public/blog/demoqed/demoqed.svg b/public/blog/demoqed/demoqed.svg
new file mode 100644
index 00000000..7efe5b1f
--- /dev/null
+++ b/public/blog/demoqed/demoqed.svg
@@ -0,0 +1,96 @@
+
diff --git a/public/blog/first-cdn/cloudflare.png b/public/blog/first-cdn/cloudflare.png
deleted file mode 100644
index 6c7b896c..00000000
Binary files a/public/blog/first-cdn/cloudflare.png and /dev/null differ
diff --git a/public/blog/first-cdn/cloudflare.svg b/public/blog/first-cdn/cloudflare.svg
new file mode 100644
index 00000000..d7735cdd
--- /dev/null
+++ b/public/blog/first-cdn/cloudflare.svg
@@ -0,0 +1,170 @@
+
diff --git a/public/blog/first-cdn/global.png b/public/blog/first-cdn/global.png
deleted file mode 100644
index b75f5550..00000000
Binary files a/public/blog/first-cdn/global.png and /dev/null differ
diff --git a/public/blog/first-cdn/global.svg b/public/blog/first-cdn/global.svg
new file mode 100644
index 00000000..1f67fbeb
--- /dev/null
+++ b/public/blog/first-cdn/global.svg
@@ -0,0 +1,318 @@
+
diff --git a/public/blog/kixelCat.png b/public/blog/kixelCat.png
deleted file mode 100644
index aa75c511..00000000
Binary files a/public/blog/kixelCat.png and /dev/null differ
diff --git a/public/blog/kixelCat.svg b/public/blog/kixelCat.svg
new file mode 100644
index 00000000..f4e3ae3a
--- /dev/null
+++ b/public/blog/kixelCat.svg
@@ -0,0 +1,212 @@
+
diff --git a/public/blog/moq-boy/bren.png b/public/blog/moq-boy/bren.png
deleted file mode 100644
index 7f254d70..00000000
Binary files a/public/blog/moq-boy/bren.png and /dev/null differ
diff --git a/public/blog/moq-boy/bren.svg b/public/blog/moq-boy/bren.svg
new file mode 100644
index 00000000..acfa3ede
--- /dev/null
+++ b/public/blog/moq-boy/bren.svg
@@ -0,0 +1,302 @@
+
diff --git a/public/blog/moq-boy/bren2.png b/public/blog/moq-boy/bren2.png
deleted file mode 100644
index bd5f93eb..00000000
Binary files a/public/blog/moq-boy/bren2.png and /dev/null differ
diff --git a/public/blog/moq-boy/bren2.svg b/public/blog/moq-boy/bren2.svg
new file mode 100644
index 00000000..a30ccd36
--- /dev/null
+++ b/public/blog/moq-boy/bren2.svg
@@ -0,0 +1,508 @@
+
diff --git a/public/blog/moq-boy/moqboy.png b/public/blog/moq-boy/moqboy.png
deleted file mode 100644
index 16919ed0..00000000
Binary files a/public/blog/moq-boy/moqboy.png and /dev/null differ
diff --git a/public/blog/moq-boy/moqboy.svg b/public/blog/moq-boy/moqboy.svg
new file mode 100644
index 00000000..0d8d0a8d
--- /dev/null
+++ b/public/blog/moq-boy/moqboy.svg
@@ -0,0 +1,173 @@
+
diff --git a/public/blog/moq-boy/pub1.png b/public/blog/moq-boy/pub1.png
deleted file mode 100644
index 2706c252..00000000
Binary files a/public/blog/moq-boy/pub1.png and /dev/null differ
diff --git a/public/blog/moq-boy/pub1.svg b/public/blog/moq-boy/pub1.svg
new file mode 100644
index 00000000..225a3764
--- /dev/null
+++ b/public/blog/moq-boy/pub1.svg
@@ -0,0 +1,292 @@
+
diff --git a/public/blog/moq-boy/pub2.png b/public/blog/moq-boy/pub2.png
deleted file mode 100644
index 9028d87a..00000000
Binary files a/public/blog/moq-boy/pub2.png and /dev/null differ
diff --git a/public/blog/moq-boy/pub2.svg b/public/blog/moq-boy/pub2.svg
new file mode 100644
index 00000000..030227a8
--- /dev/null
+++ b/public/blog/moq-boy/pub2.svg
@@ -0,0 +1,238 @@
+
diff --git a/public/blog/moq-onion/cancel.png b/public/blog/moq-onion/cancel.png
deleted file mode 100644
index 17987903..00000000
Binary files a/public/blog/moq-onion/cancel.png and /dev/null differ
diff --git a/public/blog/moq-onion/cancel.svg b/public/blog/moq-onion/cancel.svg
new file mode 100644
index 00000000..0dac2601
--- /dev/null
+++ b/public/blog/moq-onion/cancel.svg
@@ -0,0 +1,381 @@
+
diff --git a/public/blog/moq-onion/karp.png b/public/blog/moq-onion/karp.png
deleted file mode 100644
index d4962c42..00000000
Binary files a/public/blog/moq-onion/karp.png and /dev/null differ
diff --git a/public/blog/moq-onion/karp.svg b/public/blog/moq-onion/karp.svg
new file mode 100644
index 00000000..3f6bbe3a
--- /dev/null
+++ b/public/blog/moq-onion/karp.svg
@@ -0,0 +1,33 @@
+
diff --git a/public/blog/moq-onion/onion.png b/public/blog/moq-onion/onion.png
deleted file mode 100644
index 49e33e9a..00000000
Binary files a/public/blog/moq-onion/onion.png and /dev/null differ
diff --git a/public/blog/moq-onion/onion.svg b/public/blog/moq-onion/onion.svg
new file mode 100644
index 00000000..ecc2ed01
--- /dev/null
+++ b/public/blog/moq-onion/onion.svg
@@ -0,0 +1,197 @@
+
diff --git a/public/blog/moq-onion/sfu.png b/public/blog/moq-onion/sfu.png
deleted file mode 100644
index 6aa9526a..00000000
Binary files a/public/blog/moq-onion/sfu.png and /dev/null differ
diff --git a/public/blog/moq-onion/sfu.svg b/public/blog/moq-onion/sfu.svg
new file mode 100644
index 00000000..0fcacf9c
--- /dev/null
+++ b/public/blog/moq-onion/sfu.svg
@@ -0,0 +1,235 @@
+
diff --git a/public/blog/moq-onion/track.png b/public/blog/moq-onion/track.png
deleted file mode 100644
index 770e2537..00000000
Binary files a/public/blog/moq-onion/track.png and /dev/null differ
diff --git a/public/blog/moq-onion/track.svg b/public/blog/moq-onion/track.svg
new file mode 100644
index 00000000..854e7460
--- /dev/null
+++ b/public/blog/moq-onion/track.svg
@@ -0,0 +1,429 @@
+
diff --git a/public/blog/moqbs/moqbs.png b/public/blog/moqbs/moqbs.png
deleted file mode 100644
index f6ef8986..00000000
Binary files a/public/blog/moqbs/moqbs.png and /dev/null differ
diff --git a/public/blog/moqbs/moqbs.svg b/public/blog/moqbs/moqbs.svg
new file mode 100644
index 00000000..7320d414
--- /dev/null
+++ b/public/blog/moqbs/moqbs.svg
@@ -0,0 +1,325 @@
+
diff --git a/public/blog/on-a-boat/boat.png b/public/blog/on-a-boat/boat.png
deleted file mode 100644
index 3fa8f2cb..00000000
Binary files a/public/blog/on-a-boat/boat.png and /dev/null differ
diff --git a/public/blog/on-a-boat/boat.svg b/public/blog/on-a-boat/boat.svg
new file mode 100644
index 00000000..191ddc5f
--- /dev/null
+++ b/public/blog/on-a-boat/boat.svg
@@ -0,0 +1,1564 @@
+
diff --git a/public/blog/on-a-boat/fanout.png b/public/blog/on-a-boat/fanout.png
deleted file mode 100644
index 97d00500..00000000
Binary files a/public/blog/on-a-boat/fanout.png and /dev/null differ
diff --git a/public/blog/on-a-boat/fanout.svg b/public/blog/on-a-boat/fanout.svg
new file mode 100644
index 00000000..1d3b1474
--- /dev/null
+++ b/public/blog/on-a-boat/fanout.svg
@@ -0,0 +1,320 @@
+
diff --git a/public/blog/on-a-boat/multipath.png b/public/blog/on-a-boat/multipath.png
deleted file mode 100644
index 7bb4dd95..00000000
Binary files a/public/blog/on-a-boat/multipath.png and /dev/null differ
diff --git a/public/blog/on-a-boat/multipath.svg b/public/blog/on-a-boat/multipath.svg
new file mode 100644
index 00000000..a2f0579a
--- /dev/null
+++ b/public/blog/on-a-boat/multipath.svg
@@ -0,0 +1,288 @@
+
diff --git a/public/blog/open-for-business/bean.png b/public/blog/open-for-business/bean.png
deleted file mode 100644
index 829c17f5..00000000
Binary files a/public/blog/open-for-business/bean.png and /dev/null differ
diff --git a/public/blog/open-for-business/ena.png b/public/blog/open-for-business/ena.png
deleted file mode 100644
index ed75f350..00000000
Binary files a/public/blog/open-for-business/ena.png and /dev/null differ
diff --git a/public/blog/open-for-business/ena.svg b/public/blog/open-for-business/ena.svg
new file mode 100644
index 00000000..adfe9193
--- /dev/null
+++ b/public/blog/open-for-business/ena.svg
@@ -0,0 +1,1013 @@
+
diff --git a/public/blog/open-for-business/imadethis.png b/public/blog/open-for-business/imadethis.png
deleted file mode 100644
index 6308129d..00000000
Binary files a/public/blog/open-for-business/imadethis.png and /dev/null differ
diff --git a/public/blog/open-for-business/imadethis.svg b/public/blog/open-for-business/imadethis.svg
new file mode 100644
index 00000000..e49ad77f
--- /dev/null
+++ b/public/blog/open-for-business/imadethis.svg
@@ -0,0 +1,539 @@
+
diff --git a/public/blog/open-for-business/reality.png b/public/blog/open-for-business/reality.png
deleted file mode 100644
index 4286da79..00000000
Binary files a/public/blog/open-for-business/reality.png and /dev/null differ
diff --git a/public/blog/open-for-business/reality.svg b/public/blog/open-for-business/reality.svg
new file mode 100644
index 00000000..a925273d
--- /dev/null
+++ b/public/blog/open-for-business/reality.svg
@@ -0,0 +1,605 @@
+
diff --git a/public/blog/quic-powers/anycast.png b/public/blog/quic-powers/anycast.png
deleted file mode 100644
index 6d648157..00000000
Binary files a/public/blog/quic-powers/anycast.png and /dev/null differ
diff --git a/public/blog/quic-powers/anycast.svg b/public/blog/quic-powers/anycast.svg
new file mode 100644
index 00000000..08ff51c0
--- /dev/null
+++ b/public/blog/quic-powers/anycast.svg
@@ -0,0 +1,206 @@
+
diff --git a/public/blog/quic-powers/anycast2.png b/public/blog/quic-powers/anycast2.png
deleted file mode 100644
index 7d19b017..00000000
Binary files a/public/blog/quic-powers/anycast2.png and /dev/null differ
diff --git a/public/blog/quic-powers/anycast2.svg b/public/blog/quic-powers/anycast2.svg
new file mode 100644
index 00000000..f153e641
--- /dev/null
+++ b/public/blog/quic-powers/anycast2.svg
@@ -0,0 +1,274 @@
+
diff --git a/public/blog/quic-powers/http.png b/public/blog/quic-powers/http.png
deleted file mode 100644
index 28cf6e01..00000000
Binary files a/public/blog/quic-powers/http.png and /dev/null differ
diff --git a/public/blog/quic-powers/http.svg b/public/blog/quic-powers/http.svg
new file mode 100644
index 00000000..cb7cee7a
--- /dev/null
+++ b/public/blog/quic-powers/http.svg
@@ -0,0 +1,481 @@
+
diff --git a/public/blog/quic-powers/quic.png b/public/blog/quic-powers/quic.png
deleted file mode 100644
index 6218fb39..00000000
Binary files a/public/blog/quic-powers/quic.png and /dev/null differ
diff --git a/public/blog/quic-powers/quic.svg b/public/blog/quic-powers/quic.svg
new file mode 100644
index 00000000..3cdea64a
--- /dev/null
+++ b/public/blog/quic-powers/quic.svg
@@ -0,0 +1,287 @@
+
diff --git a/public/blog/quic-powers/standards.png b/public/blog/quic-powers/standards.png
deleted file mode 100644
index 85712dd1..00000000
Binary files a/public/blog/quic-powers/standards.png and /dev/null differ
diff --git a/public/blog/quic-powers/standards.svg b/public/blog/quic-powers/standards.svg
new file mode 100644
index 00000000..02e445d4
--- /dev/null
+++ b/public/blog/quic-powers/standards.svg
@@ -0,0 +1,744 @@
+
diff --git a/public/blog/quic-powers/tcp.png b/public/blog/quic-powers/tcp.png
deleted file mode 100644
index 2167da5a..00000000
Binary files a/public/blog/quic-powers/tcp.png and /dev/null differ
diff --git a/public/blog/quic-powers/tcp.svg b/public/blog/quic-powers/tcp.svg
new file mode 100644
index 00000000..f51840d1
--- /dev/null
+++ b/public/blog/quic-powers/tcp.svg
@@ -0,0 +1,152 @@
+
diff --git a/public/blog/quic-powers/tuple-quic.png b/public/blog/quic-powers/tuple-quic.png
deleted file mode 100644
index 71f4a96b..00000000
Binary files a/public/blog/quic-powers/tuple-quic.png and /dev/null differ
diff --git a/public/blog/quic-powers/tuple-quic.svg b/public/blog/quic-powers/tuple-quic.svg
new file mode 100644
index 00000000..11744356
--- /dev/null
+++ b/public/blog/quic-powers/tuple-quic.svg
@@ -0,0 +1,306 @@
+
diff --git a/public/blog/quic-powers/tuple-quic2.png b/public/blog/quic-powers/tuple-quic2.png
deleted file mode 100644
index 2e6794ec..00000000
Binary files a/public/blog/quic-powers/tuple-quic2.png and /dev/null differ
diff --git a/public/blog/quic-powers/tuple-quic2.svg b/public/blog/quic-powers/tuple-quic2.svg
new file mode 100644
index 00000000..d9e7b9bf
--- /dev/null
+++ b/public/blog/quic-powers/tuple-quic2.svg
@@ -0,0 +1,426 @@
+
diff --git a/public/blog/quic-powers/tuple-quic3.png b/public/blog/quic-powers/tuple-quic3.png
deleted file mode 100644
index a4eb4ef9..00000000
Binary files a/public/blog/quic-powers/tuple-quic3.png and /dev/null differ
diff --git a/public/blog/quic-powers/tuple-quic3.svg b/public/blog/quic-powers/tuple-quic3.svg
new file mode 100644
index 00000000..b9830a40
--- /dev/null
+++ b/public/blog/quic-powers/tuple-quic3.svg
@@ -0,0 +1,185 @@
+
diff --git a/public/blog/quic-powers/tuple-tcp.png b/public/blog/quic-powers/tuple-tcp.png
deleted file mode 100644
index 7895c97f..00000000
Binary files a/public/blog/quic-powers/tuple-tcp.png and /dev/null differ
diff --git a/public/blog/quic-powers/tuple-tcp.svg b/public/blog/quic-powers/tuple-tcp.svg
new file mode 100644
index 00000000..8d3b3bad
--- /dev/null
+++ b/public/blog/quic-powers/tuple-tcp.svg
@@ -0,0 +1,239 @@
+
diff --git a/public/blog/quic-powers/tuple-tcp2.png b/public/blog/quic-powers/tuple-tcp2.png
deleted file mode 100644
index 75e864dd..00000000
Binary files a/public/blog/quic-powers/tuple-tcp2.png and /dev/null differ
diff --git a/public/blog/quic-powers/tuple-tcp2.svg b/public/blog/quic-powers/tuple-tcp2.svg
new file mode 100644
index 00000000..66b99784
--- /dev/null
+++ b/public/blog/quic-powers/tuple-tcp2.svg
@@ -0,0 +1,379 @@
+
diff --git a/public/blog/quic-powers/tuple-webrtc.png b/public/blog/quic-powers/tuple-webrtc.png
deleted file mode 100644
index 7800e35a..00000000
Binary files a/public/blog/quic-powers/tuple-webrtc.png and /dev/null differ
diff --git a/public/blog/quic-powers/tuple-webrtc.svg b/public/blog/quic-powers/tuple-webrtc.svg
new file mode 100644
index 00000000..4c971c25
--- /dev/null
+++ b/public/blog/quic-powers/tuple-webrtc.svg
@@ -0,0 +1,271 @@
+
diff --git a/public/blog/quic-powers/tuple-webrtc2.png b/public/blog/quic-powers/tuple-webrtc2.png
deleted file mode 100644
index 045e7be8..00000000
Binary files a/public/blog/quic-powers/tuple-webrtc2.png and /dev/null differ
diff --git a/public/blog/quic-powers/tuple-webrtc2.svg b/public/blog/quic-powers/tuple-webrtc2.svg
new file mode 100644
index 00000000..3b4de170
--- /dev/null
+++ b/public/blog/quic-powers/tuple-webrtc2.svg
@@ -0,0 +1,364 @@
+
diff --git a/public/blog/quic-powers/vegeta.png b/public/blog/quic-powers/vegeta.png
deleted file mode 100644
index 2aacbeb0..00000000
Binary files a/public/blog/quic-powers/vegeta.png and /dev/null differ
diff --git a/public/blog/quic-powers/vegeta.svg b/public/blog/quic-powers/vegeta.svg
new file mode 100644
index 00000000..b8222946
--- /dev/null
+++ b/public/blog/quic-powers/vegeta.svg
@@ -0,0 +1,1203 @@
+
diff --git a/public/blog/tls-and-quic/warning.png b/public/blog/tls-and-quic/warning.png
deleted file mode 100644
index e98740d9..00000000
Binary files a/public/blog/tls-and-quic/warning.png and /dev/null differ
diff --git a/public/blog/tls-and-quic/warning.svg b/public/blog/tls-and-quic/warning.svg
new file mode 100644
index 00000000..2eb94cf5
--- /dev/null
+++ b/public/blog/tls-and-quic/warning.svg
@@ -0,0 +1,302 @@
+
diff --git a/public/blog/webrtc-is-still-the-problem/context.png b/public/blog/webrtc-is-still-the-problem/context.png
deleted file mode 100644
index 7db5f8ba..00000000
Binary files a/public/blog/webrtc-is-still-the-problem/context.png and /dev/null differ
diff --git a/public/blog/webrtc-is-still-the-problem/context.svg b/public/blog/webrtc-is-still-the-problem/context.svg
new file mode 100644
index 00000000..de611530
--- /dev/null
+++ b/public/blog/webrtc-is-still-the-problem/context.svg
@@ -0,0 +1,604 @@
+
diff --git a/public/blog/webrtc-is-still-the-problem/mics.png b/public/blog/webrtc-is-still-the-problem/mics.png
deleted file mode 100644
index 687d32b7..00000000
Binary files a/public/blog/webrtc-is-still-the-problem/mics.png and /dev/null differ
diff --git a/public/blog/webrtc-is-still-the-problem/mics.svg b/public/blog/webrtc-is-still-the-problem/mics.svg
new file mode 100644
index 00000000..c2896ca7
--- /dev/null
+++ b/public/blog/webrtc-is-still-the-problem/mics.svg
@@ -0,0 +1,513 @@
+
diff --git a/public/blog/webrtc-is-still-the-problem/navi.png b/public/blog/webrtc-is-still-the-problem/navi.png
deleted file mode 100644
index c2227153..00000000
Binary files a/public/blog/webrtc-is-still-the-problem/navi.png and /dev/null differ
diff --git a/public/blog/webrtc-is-still-the-problem/navi.svg b/public/blog/webrtc-is-still-the-problem/navi.svg
new file mode 100644
index 00000000..bb35aab2
--- /dev/null
+++ b/public/blog/webrtc-is-still-the-problem/navi.svg
@@ -0,0 +1,210 @@
+
diff --git a/public/blog/webrtc-is-the-problem/bleach.png b/public/blog/webrtc-is-the-problem/bleach.png
deleted file mode 100644
index fe79196f..00000000
Binary files a/public/blog/webrtc-is-the-problem/bleach.png and /dev/null differ
diff --git a/public/blog/webrtc-is-the-problem/bleach.svg b/public/blog/webrtc-is-the-problem/bleach.svg
new file mode 100644
index 00000000..33cac235
--- /dev/null
+++ b/public/blog/webrtc-is-the-problem/bleach.svg
@@ -0,0 +1,164 @@
+
diff --git a/public/blog/webrtc-is-the-problem/car.png b/public/blog/webrtc-is-the-problem/car.png
deleted file mode 100644
index c6c33276..00000000
Binary files a/public/blog/webrtc-is-the-problem/car.png and /dev/null differ
diff --git a/public/blog/webrtc-is-the-problem/car.svg b/public/blog/webrtc-is-the-problem/car.svg
new file mode 100644
index 00000000..bebdf0d1
--- /dev/null
+++ b/public/blog/webrtc-is-the-problem/car.svg
@@ -0,0 +1,128 @@
+
diff --git a/public/blog/webrtc-is-the-problem/chad.png b/public/blog/webrtc-is-the-problem/chad.png
deleted file mode 100644
index d2883691..00000000
Binary files a/public/blog/webrtc-is-the-problem/chad.png and /dev/null differ
diff --git a/public/blog/webrtc-is-the-problem/chad.svg b/public/blog/webrtc-is-the-problem/chad.svg
new file mode 100644
index 00000000..a446d68c
--- /dev/null
+++ b/public/blog/webrtc-is-the-problem/chad.svg
@@ -0,0 +1,302 @@
+
diff --git a/public/blog/webrtc-is-the-problem/claude.png b/public/blog/webrtc-is-the-problem/claude.png
deleted file mode 100644
index 12944667..00000000
Binary files a/public/blog/webrtc-is-the-problem/claude.png and /dev/null differ
diff --git a/public/blog/webrtc-is-the-problem/claude.svg b/public/blog/webrtc-is-the-problem/claude.svg
new file mode 100644
index 00000000..21f44a0d
--- /dev/null
+++ b/public/blog/webrtc-is-the-problem/claude.svg
@@ -0,0 +1,49 @@
+
diff --git a/public/blog/webrtc-is-the-problem/rtt.png b/public/blog/webrtc-is-the-problem/rtt.png
deleted file mode 100644
index 1fee4fdd..00000000
Binary files a/public/blog/webrtc-is-the-problem/rtt.png and /dev/null differ
diff --git a/public/blog/webrtc-is-the-problem/rtt.svg b/public/blog/webrtc-is-the-problem/rtt.svg
new file mode 100644
index 00000000..061dad40
--- /dev/null
+++ b/public/blog/webrtc-is-the-problem/rtt.svg
@@ -0,0 +1,493 @@
+
diff --git a/public/blog/webrtc-is-the-problem/trenchcoat.png b/public/blog/webrtc-is-the-problem/trenchcoat.png
deleted file mode 100644
index f0682273..00000000
Binary files a/public/blog/webrtc-is-the-problem/trenchcoat.png and /dev/null differ
diff --git a/public/blog/webrtc-is-the-problem/trenchcoat.svg b/public/blog/webrtc-is-the-problem/trenchcoat.svg
new file mode 100644
index 00000000..457897bd
--- /dev/null
+++ b/public/blog/webrtc-is-the-problem/trenchcoat.svg
@@ -0,0 +1,444 @@
+
diff --git a/public/icons/README.md b/public/icons/README.md
index 90567871..014d8df6 100644
--- a/public/icons/README.md
+++ b/public/icons/README.md
@@ -9,7 +9,7 @@ This directory holds the traced SVGs used by moq.dev:
| `social/` | Author links on the site |
| `use-case/` | Homepage use case cards |
-Use `#4dc515` for the main silhouettes and strokes, with `#fcfcfc` for small recognizable accents: lettering, eyes, leaves, controls, and signal details. Keep large openings such as screens transparent. Simple silhouettes can stay entirely green. The homepage feature icons in `public/drawn/icon-*.svg` follow the same palette. Run new traces through `tools/icons/smooth.sh` to take out the tracer's nicks and bumps and crop them to the drawing; the homepage feature and use-case icons already have been. Ferris keeps his green body and white eye highlights; the IETF and QUIC marks keep their original artwork colors with white lettering.
+Use `#4dc515` for the main silhouettes and strokes, with `#fcfcfc` for small recognizable accents: lettering, eyes, leaves, controls, and signal details. Keep large openings such as screens transparent. Simple silhouettes can stay entirely green. The homepage feature icons in `public/drawn/icon-*.svg` follow the same palette. Run new traces through `SIGMA=12 just trace --crop` to take out the tracer's nicks and bumps and crop them to the drawing; the homepage feature and use-case icons already have been. Ferris keeps his green body and white eye highlights; the IETF and QUIC marks keep their original artwork colors with white lettering.
The arrows in `public/drawn/arrow-*.svg` are copies of moq.pro's drawn arrows (`app/static/drawn/`), recoloured from `#00bf2d` to `#4dc515` to match the icons they point at.
diff --git a/quest/m2/README.md b/quest/m2/README.md
index 0afa493e..958b9b26 100644
--- a/quest/m2/README.md
+++ b/quest/m2/README.md
@@ -5,6 +5,3 @@
Site work after the Voice AI demo: blog polish that improves every post but
waits behind the demos.
-## Required
-
-- [Hand-drawn blog art as SVG](/quest/m2/site-svg.md) - the blog's hand-drawn PNGs become transparent palette SVGs, covers rasterized for social cards at build
diff --git a/quest/m2/site-svg.md b/quest/m2/site-svg.md
deleted file mode 100644
index 10310409..00000000
--- a/quest/m2/site-svg.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# [M] Hand-drawn blog art as SVG
-
-## Goal
-
-The hand-drawn diagrams and sketches in the moq.dev blog are served as SVG instead of PNG, on a transparent background in the site
-palette, so each sits on the page itself at any resolution. Social cards
-still get a PNG. Screenshots, memes, photos, charts, and logos stay raster.
-A just recipe turns a newly drawn PNG into the same kind of SVG.
-
-## Plan
-
-Decided 2026-10-20 in planning:
-
-- **Hand-drawn only.** As of 2026-10-20 moq.dev holds 55 hand-drawn PNGs
- across the blog posts plus the author avatar. They are white (`#FAFAFA`),
- green (`#00BE2D`), and grey (`#A3A5A8`) strokes, some with yellow, red, or
- orange accents. Vectorizing the screenshots, memes, photos, and charts gains
- nothing.
-- **Transparent background, palette colours, no light mode.** The site is
- dark-only (`color-scheme: dark` on slate-900, no `prefers-color-scheme`) and
- embeds images as markdown ``, which CSS variables cannot reach. Drop
- the baked background, most often `#0F172A`, but `#292929` and `#212121` in
- quic-powers, which show as grey boxes today. Snap the antialiased stroke
- colours to the palette. `currentColor` was rejected because it only works
- for inlined SVG and the site has no light theme to serve.
-- **Per-colour potrace, keeping the hand-drawn look.** Quantize to the
- palette, then blur, threshold, and potrace each colour layer, the pipeline
- the site's existing drawn SVGs already come from. vtracer was rejected for
- noisier stroke output that does not match them. Redrawing by hand was
- rejected as 55 images of manual work that changes the look. No editable
- sources exist anywhere in moq.dev's history, only the flattened PNGs.
-- **Mixed images stay raster:** `to-wasm/slide.png` (pasted Ferris and
- TypeScript bitmaps), `on-a-boat/kraken.png` (a photo grid), and
- `update-00/globe.png` (a screenshot). Filled drawings such as
- `quic-powers/vegeta.png`, `kixelCat.png`, `be-the-outlier/narwhal.png`,
- `on-a-boat/boat.png`, `first-cdn/cloudflare.png`, and `moqbs/moqbs.png` are
- traced too. Any that comes out visibly worse or larger than its PNG stays
- PNG, and the PR lists each one. Embedding bitmaps inside an SVG was
- rejected because it defeats the point.
-- **Covers are rasterized at build time.** About a third of the drawings are
- a post's frontmatter `cover:`, which becomes `og:image`. Social crawlers
- cannot render SVG, so `scripts/check-og.ts` rejects it. The Astro build
- renders each SVG cover to PNG on the slate background for `og:image`, so the
- SVG is the only committed source and nothing can drift. Committing a PNG
- copy per cover, and leaving covers raster, were both rejected.
-- **One tool.** Generalize `tools/icons/smooth.sh`, which renders,
- blurs, thresholds, and potraces the homepage icons
- ([moq-dev/moq.dev#163](https://github.com/moq-dev/moq.dev/pull/163)), so it
- traces drawn PNGs as well. Do not keep two near-duplicate pipelines. Expose
- it as a just recipe, with potrace in the Nix dev shell. Hand-drawn posts
- keep coming.
-- **Docs: one line in `AGENTS.md`** on the drawn-PNG recipe. A doc page
- was rejected because readers of the docs site never see this.
-- **Lands here.** Planned in moq-dev/moq to follow moq.dev's move into that
- repository; moved here 2026-10-23 when the move was dropped, since moq.dev
- builds from a `moq` submodule instead.
-
-Guidance:
-
-- Delete each replaced PNG and update every reference, including posts that
- reuse another post's image (`robotics.mdx` reuses five), the cover, and
- `components/author.astro` for the avatar.
-- The drawings were made at fixed sizes (960x540, 1920x1080, 1920x640). Keep
- the `viewBox` at the original size so layout does not shift.
-- Compare each SVG against its PNG in the dev server at 1x and 2x before
- calling it done. Check a cover's built `og:image` too.
diff --git a/src/components/author.astro b/src/components/author.astro
index ea81fcb6..49e6a730 100644
--- a/src/components/author.astro
+++ b/src/components/author.astro
@@ -4,7 +4,7 @@ import { socials } from "@/socials";
---