blog.psheon.me · English · 中文 · RSS
An interactive blog. Every article builds one thing from scratch — a CNN, a Transformer, a diffusion model, neuroevolution, a quadruped's walking policy, a SLAM system, a city of autonomous agents, a task scheduler, a path tracer, an AI composer — and ships with instruments you can train, open up and break right in the page. Apart from MuJoCo's physics in article 006, everything is written in TypeScript and runs in the reader's tab: no TensorFlow.js, no ONNX Runtime, no server. Bilingual (繁體中文 / English).
從零實作的互動部落格:每一篇都能在瀏覽器裡訓練、拆開、弄壞。CNN、Transformer、擴散模型、神經演化、 機器狗走路策略、SLAM、自己過日子的小鎮居民、任務排程器、路徑追蹤器、AI 作曲家,全部用 TypeScript 從零寫起,不靠任何機器學習函式庫, 也不靠伺服器。
Built with Next.js 16 (App Router, static generation) · MDX · shadcn/ui (Base UI) · Tailwind v4 · TypeScript ·
Three.js, MuJoCo WebAssembly and WebGPU where an article needs them. The site is a PWA: a hand-written
service worker (public/sw.js) keeps articles readable offline.
pnpm install
pnpm dev # http://localhost:3000
pnpm test # vitest (tests/): lib/ml gradients and golden values, content and search, every article's simulation
pnpm e2e # playwright: builds, serves and tests the site, incl. axe on every page in both themes
pnpm lint && pnpm typecheck && pnpm buildThe canonical origin (RSS, sitemap, metadata, OG images) comes from NEXT_PUBLIC_SITE_URL if set,
otherwise from the production domain Vercel assigns (lib/site.ts). Production sets it to
https://blog.psheon.me; preview deployments take their origin from Vercel.
Branches: work on dev; main changes only through a pull request. Vercel deploys main to
production and gives every pull request a preview. Where the project stands and what is in flight:
docs/HANDOFF.md.
content/posts/<slug>/
zh.mdx required — a post exists once this file does
en.mdx optional — without it, /en serves the zh text with a notice
components/ interactive components, imported by the article itself
Frontmatter is validated at build time (lib/content/schema.ts); a bad field fails the build
and names the file.
---
title: …
description: …
date: 2026-09-18
tags: [computer-vision, cnn] # lowercase kebab-case
no: 3 # notebook entry number
interactive: true # optional — shows the "interactive" badge
draft: true # optional — built in `pnpm dev` only, never in production
---Read docs/DESIGN.md first: the design system — tokens, components, interaction and
accessibility rules, content rules and the publishing checklist.
Figure, Instrument, Sidenote and Callout are available in every article without an
import. content/posts/cnn-from-scratch is a full example.
Conventions that keep pages fast and honest:
- An article's components live next to it and are imported by the MDX file, so they are code-split
per article. Anything heavy that isn't needed for first paint (models, dialogs) is loaded with
next/dynamicbehind a placeholder of the same shape. - A number in an article should be reproducible: measured in a test, by a script under
docs/research/, or live in the reader's browser. Say which. - Inside an
Instrument, titles are<p>, not headings; instruments can appear before the article's firsth2.
| Path | What lives there |
|---|---|
content/posts |
The articles; each one's interactive components live beside it |
lib/ml |
Dependency-free ML: tensor ops and an inference Sequential; neuroevolution; a reverse-mode autodiff engine (matrix and image ops, every one checked against finite differences); a decoder-only Transformer; Adam |
lib/rt |
The path tracer for the light series: scene, BVH, a CPU reference and the WebGPU kernel |
lib/content |
Post index, frontmatter schema, table of contents, reading time, the operator count on the home page |
lib/search.ts |
Full-text index builder and ranking (substring matching, so Chinese works) |
lib/seo.ts, lib/site.ts |
Canonical URLs, hreflang and Open Graph basics; the site's origin |
lib/og |
Open Graph card renderer (subsets a CJK font at build time) |
lib/i18n |
Locales and typed UI dictionaries |
lib/three.ts |
The named three.js exports the 3D figures use, so the bundle can be trimmed |
components/site |
Header, home page (hero, post bento, previews), search palette, PWA install and service worker |
components/article |
Article chrome: table of contents, reading progress, footer |
components/lab |
The Instrument frame and shared instrument parts |
components/rt |
The path tracer's stage, worker and React hook |
components/mdx |
Prose components |
components/ui |
shadcn/ui components, plus layout primitives ported from Launch UI |
styles/launch-ui.css |
Glass, fade and hairline utilities from Launch UI |
public/sw.js |
The service worker (network first for pages, cache first for immutable assets) |
scripts/train-mnist |
One-off PyTorch training for article 001; exports weights and golden values for the tests |
scripts/music |
Packs article 014's chorales and its trained composer into public/posts/music-ai/*.bin |
scripts/light |
Packs the light series' assets (the playground, the vehicles, the character and its clips) into public/posts/light-playground/*.bin: geometry, skeleton and names only, never a texture |
tests |
Vitest suites, grouped by library and by article |
e2e |
Playwright smoke tests and axe accessibility checks |
docs/research, docs/reviews |
Measurements and notes behind article decisions; editorial and external reviews |
Retrain the digit classifier with:
uv run --with torch --with torchvision --with numpy python scripts/train-mnist/train.pyMeasured with Lighthouse on a production build (mobile preset, throttled): accessibility, best practices and SEO at 100; performance in the high 80s to mid 90s; about 0.5 MB per page; no layout shift. Chinese is set in system fonts on purpose: CJK web fonts cost about 2 MB and 220 KB of render-blocking CSS and took first paint from 1.2 s to 14 s.
Layout primitives and CSS utilities adapted from Launch UI.
AAPL price data in the trading article is daily closing prices for 2024. The Lite3 robot model and
walking policy in article 006 come from DEEP Robotics; their licences are in public/lite3/. The light
series' playground is the geometry of Sketchbook's world by
Jan Blaha (MIT); its textures are not used and world.glb is never committed. Article 014 trains on
Craig Sapp's digital edition of Bach's 370 four-part chorales
(CC BY-NC-SA 4.0); the tokens and the trained model in public/posts/music-ai/ are derived from it and carry the
same licence.