Personal research blog powered by Next.js 16 · Editorial aesthetic · Warm cream palette
🔗 Live Demo · 📝 Writing Articles · 🎨 Design System · 🛠 Tech Stack
A warm, editorial palette built around cream tones with deep blue accents — designed for long-form reading comfort.
| Token | Hex | Usage |
|---|---|---|
--bg |
#f7f7f5 |
Page background |
--surface |
#ffffff |
Card surfaces |
--surface-soft |
#f5f3ee |
Soft surfaces |
--surface-muted |
#f0eee9 |
Muted surfaces |
--accent |
#30568b |
Primary accent (deep blue) |
--accent-strong |
#1f4067 |
Strong accent |
--accent-soft |
#4a6fa5 |
Soft accent |
--text |
#1b1c19 |
Primary text |
--text-muted |
#43474f |
Muted text |
--text-soft |
#737780 |
Soft text |
| Role | Font Stack |
|---|---|
| Headlines / Body | Newsreader (serif) + SourceHanSerifCN |
| Motto / Italic | Newsreader italic |
| Code / Mono | IBM Plex Mono |
| Resume labels | LXGWWenKai |
Base size: 16px with 1.75 line-height (body), 1.88 (article body)
| Type | Color | Use Case |
|---|---|---|
note / info |
#30568b |
Annotations |
tip / success |
#2f6f55 |
Best practices |
warning |
#b56a1d |
Caveats |
danger / bug |
#a64646 |
Critical warnings |
quote / example |
#6a4fa3 |
Examples |
Place every article under content/posts/{Category}/{slug}/index.md.
content/posts/
├── Agents/
│ ├── ReAct/index.md
│ └── function_calling-mcp/index.md
└── Test/
└── Test/index.md
The URL becomes /articles/{Category}/{slug} → /articles/Agents/ReAct.
---
title: "Article Title"
summary: "Brief description shown in cards and meta"
date: "2026-03-30"
readTime: "10 min read"
draft: false # true = unpublished
---| Field | Required | Description |
|---|---|---|
title |
✅ | Article title |
summary |
✅ | Short description for cards and SEO |
date |
✅ | Publication date (YYYY-MM-DD) |
readTime |
✅ | Estimated read time, e.g. "10 min read" |
draft |
❌ | true hides the article from production |
> [!note] Title
> Content here
> [!tip] Best Practice
> Use callouts to highlight important information
> [!warning] Caution
> This will break if you do X
> [!danger] Warning
> Never do this in production```mermaid
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[Action]
B -->|No| D[End]
```Inline: $E = mc^2$
Block:
$$
\sum_{i=1}^{n} x_i^2
$$```typescript
const state = cache(() => loadPost(params))
```Place images and files alongside the index.md. They are automatically mirrored to /public/post-assets/ via build script.
<!-- In index.md -->

<!-- Becomes accessible at -->
/post-assets/{Category}/{slug}/diagram.png| Element | Description |
|---|---|
| Hero | Title, summary, date, read time |
| Body | Full-width markdown content |
| Timeline | Hierarchical heading nav in sidebar |
| Prev/Next | Article-level navigation |
| Download | Export article as Markdown |
| Layer | Technology |
|---|---|
| Framework | Next.js 16.2 + React 19 |
| Language | TypeScript |
| Styling | Pure CSS (CSS Custom Properties) |
| Markdown | Unified/Remark pipeline |
| Math | KaTeX (remark-math + rehype-katex) |
| Diagrams | Mermaid |
| Callouts | Custom remark-obsidian-callouts plugin |
| Code | react-syntax-highlighter (vscDarkPlus theme) |
| Content | gray-matter frontmatter parsing |
| Testing | Vitest + React Testing Library |
| Fonts | Newsreader, IBM Plex Mono, SourceHanSerifCN subsets, LXGWWenKai subset |
# Install dependencies
npm install
# Start dev server
npm run dev
# Run tests
npm test
# Regenerate font subsets after content or resume text changes
npm run fonts:subset
# Build for production
npm run buildMIT — feel free to fork and customize.