Rebuilding this site with Next.js 16, Sanity and a lot of empty space
Why I threw away a working blog, rebuilt it on Next.js 16 and Sanity, and designed it around ma, the Japanese idea that empty space does the work.
This site started as a Next.js 14 starter: shadcn/ui on top, Sanity as the CMS, a few placeholder posts. It worked, but it had aged in two directions at once. The framework had moved on, and the design looked like every other starter, including the ones I had built before.
So I rebuilt it from scratch. Same idea, a personal blog and portfolio that doubles as an open-source template, but on current tools and with a design I actually wanted to read in.
Starting over instead of upgrading#
Upgrading in place would have meant carrying old decisions forward one migration at a time. Instead I wrote down what the site had to do, split the work into small tickets, and rebuilt it on a branch: scaffold, design foundation, the Sanity project, the data layer, each page, SEO, CI and deployment. Every ticket shipped as its own pull request with a review, and the whole branch merged into master in one go.
The stack is Next.js 16 with Cache Components, React 19, Tailwind CSS v4, shadcn/ui and a brand new Sanity project with the Studio embedded at /studio.
Content that is fast and still live#
Next.js 16 turns caching inside out: nothing is cached unless you say so, and the parts you mark with "use cache" are prerendered into a static shell. Sanity's Live Content API fits that model well. Pages are static by default, cache tags come from the content itself, and when I publish in the Studio only the affected pages are revalidated.
Draft mode and the Presentation tool still work on top of that, so I can edit a post and watch it change in place before anything goes public.
Ma: letting space do the work#
For the redesign I borrowed from Japanese and Chinese minimalism, especially ma (間), the meaningful interval, and yohaku (余白), the deliberately empty margin. In practice that turned into a few rules:
- Three colour roles only: washi paper for the background, sumi ink for text, and a single vermilion accent used sparingly.
- One typeface per job: Shippori Mincho for headings, Newsreader for reading, Geist for the interface and small mono labels for dates.
- A list that works without cover images, because most posts don't need one.
- One signature mark, the small 間 seal in the header.
Motion with a reason#
Every animation had to answer one question first: what does this explain? Content settles in like ink on paper, a little soft and faint, then sharp. A post title travels from the list into the article heading, so you can see that what you clicked is what opened. Pages crossfade with React's View Transitions, and switching themes fades from paper to ink.
None of it slows navigation down. Exits are faster than entrances, the animations run in CSS rather than on the main thread, and with reduced motion turned on only the fades remain.
A template, not just a site#
The repository stays a template. My content lives only in Sanity; the repo ships with a small set of sample documents you can import with one command, plus a README that walks through creating your own Sanity project and deploying to Vercel. If you want a calm place to write, fork it and make it yours.