Project

This Blog

Source, stack, and design decisions behind nikhedonia.dev — a coding and mathematics blog built with Next.js, MDX, and interactive React components.

Next.jsTypeScriptMDXTailwind CSSShikiKaTeX

Motivation

Over two decades of programming and consulting, I've accumulated hundreds of code snippets, notes, and case-studies — half-written proofs, one-file benchmarks, debugging war stories, algorithm implementations that took a weekend to get right. For most of that time they sat on a hard drive, occasionally useful to me but invisible to anyone else.

I don't want them to rot. I want an easy way to make them public so they might help someone else the same way a random blog post once helped me.

The catch: many of those notes are rough — cryptic shorthand, half-finished derivations, code without context. LLMs changed this. It's now fast to take a messy note and produce something readable without losing the original insight. This blog is the result of that process: my accumulated scraps, polished just enough to publish, presented with decent math rendering and interactive visualizations where the math deserves to be felt, not just read.

Most of what ends up here is not novel research. It's things I found non-obvious, things I had to derive myself, or things I wish had been explained differently when I first encountered them.

Technical Stack

The blog is a Next.js App Router application, styled with Tailwind v4, and authored entirely in MDX.

MDX Pipeline

Content lives in content/{articles,slides,projects,snippets}/*.mdx. Each file has YAML frontmatter with title, date, description, banner, and tags.

The MDX pipeline is powered by next-mdx-remote/rsc — React Server Components render the content, so there's no client-side overhead for static prose. Interactive components are loaded with next/dynamic (no SSR) and injected via a central component map.

lib/mdx-components.tsx
const Counter  = dynamic(() => import('@/components/interactive/Counter'),   { ssr: false })
const SineWave = dynamic(() => import('@/components/interactive/SineWave'),  { ssr: false })
const FourierViz = dynamic(() => import('@/components/interactive/FourierViz'), { ssr: false })
 
export const mdxComponents = { Counter, SineWave, FourierViz, Callout, ...htmlOverrides }

MDX files can then use <Counter /> or <SineWave /> directly without any imports — the components map handles everything.

Syntax Highlighting

Code blocks use rehype-pretty-code with the Shiki engine and the github-dark theme. This gives VS Code-quality highlighting with zero client-side JavaScript.

```python title="example.py"
def fib(n): return n if n < 2 else fib(n-1) + fib(n-2)
```

Mathematics

Math is rendered server-side with KaTeX via remark-math + rehype-katex. Both inline (E=mc2E = mc^2) and display mode are supported:

×B=μ0J+μ0ε0Et\nabla \times \mathbf{B} = \mu_0 \mathbf{J} + \mu_0\varepsilon_0 \frac{\partial \mathbf{E}}{\partial t}

Content Layout System

Different content types use different layouts:

TypeLayoutKey Feature
ArticlesFull banner + proseLong-form, math-heavy
SlidesCard-per-slidePresentation-style
ProjectsTech stack + links headerPortfolio display
SnippetsCompact, code-firstQuick reference

Adding New Interactive Components

  1. Create components/interactive/MyComponent.tsx (must be a Client Component)
  2. Add a dynamic import to lib/mdx-components.tsx
  3. Use <MyComponent /> in any MDX file — no per-file imports needed

That's the whole workflow.