Projects
Tool
Live

Membrane

This site — personal blog and portfolio.

A WebGL-backed personal site built on Next.js with a custom Tailwind v4 design system. The background is a live GLSL interference shader. Built as a long-term home for writing and projects.

// project.spec

typeTool
statusLive
year2026

// stack

Next.jsWebGLGLSLTailwind CSS v4TypeScript

Membrane is this site — a personal blog and portfolio built on Next.js with a custom design system and a WebGL background. It's named after the idea of a semi-permeable boundary: some things pass through (writing, projects), some things don't (tracking scripts, third-party fonts, anything that weighs down the page).

Design system

The visual language is built on a custom Tailwind CSS v4 configuration. Every color, every font size, every spacing value is a named token in the theme. The palette is deliberately narrow: ivory for headings, parchment for prose, gold for accent, sand for secondary text, umber for metadata. Nothing else.

Typography follows a strict hierarchy. Headings use Cormorant Garamond at light weight with negative tracking. Body prose uses Lora at 16px with generous leading. Technical labels use IBM Plex Mono at small sizes with wide tracking. The combination creates a visual rhythm that distinguishes signal from noise without decorative elements.

The WebGL background

The page background is a live GLSL interference shader — rendered on a full-screen canvas behind the content, at the z-canvas layer. The shader generates subtle wave interference patterns that shift slowly over time. It's designed to be barely noticeable: the viewer's peripheral vision registers movement, but the conscious mind doesn't track it unless deliberately attending to it.

Technical details: the shader uses simplex noise to generate base patterns, then composites multiple layers at different frequencies and speeds. Each layer is additive, creating emergent complexity from simple rules — the same principle that produces interesting textures in nature. The GPU cost is negligible because the fragment shader is lightweight and the canvas resolution is clamped.

Performance

The site is statically generated with Next.js. Build output is pure HTML with inline CSS — no runtime JavaScript except for the custom cursor, mobile nav sheet, and the WebGL canvas shader. Lighthouse scores: 100 Performance, 100 Accessibility, 100 Best Practices, 100 SEO.

Every page is pre-rendered at build time. The blog uses MDX for content authoring, compiled to static HTML. There's no CMS, no database, no API calls at runtime. The build is the deploy.

What I learned

Building a personal site from scratch forces you to make decisions that frameworks make for you. Font loading strategy. Scroll restoration. Mobile navigation UX. Progress indicators for long-form content. Each decision is a constraint, and the constraints accumulate into a design language.

The most useful constraint was the color palette. Limiting to five named colors forced me to use typography and spacing to create hierarchy rather than relying on color. The result is more readable and more distinctive than anything I would have produced with a full palette.

more projects