Rewrite design system blog post in plain, direct voice
Previous version was full of designer-speak ("the heartbeat of this theme",
"digital garden", "a statement about how I view software"). Rewrote to match
the author's actual writing style: direct, structural, explains the why behind
decisions, honest about issues encountered. Same content, stripped of the
metaphors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,129 +1,121 @@
|
|||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: "Designing My System: Soft, Translucent, and Alive",
|
title: "Designing My Personal Site",
|
||||||
publishedAt: "2025-12-10",
|
publishedAt: "2025-12-10",
|
||||||
summary:
|
summary:
|
||||||
"A deep dive into the design philosophy behind my personal website's new theme, moving from rigid boxes to organic, living layers.",
|
"The design decisions behind this site's visual system — what I changed, why, and how it works.",
|
||||||
tags: ["Design", "UI/UX", "TailwindCSS", "Frontend"],
|
tags: ["Design", "UI/UX", "TailwindCSS", "Frontend"],
|
||||||
image: "/images/design-system.png",
|
image: "/images/design-system.png",
|
||||||
};
|
};
|
||||||
|
|
||||||
## The Philosophy: Soft, Translucent, and Alive
|
Most developer portfolios look the same: flat white, rigid grid, card borders at full opacity. That's fine — it's readable and it works — but I wanted this site to feel a bit more considered. Here's what I actually changed and why.
|
||||||
|
|
||||||
When I set out to redesign my personal website, I wanted to move away from the standard "developer portfolio" aesthetic—rigid grids, harsh borders, and flat colors. I wanted something that felt organic, something that breathed.
|
## Background
|
||||||
|
|
||||||
I call this simply **My Design System**. It's not a product; it's a reflection of my personal aesthetic. The core philosophy rests on three pillars:
|
The background is a fixed layer sitting behind everything at `z-index: -10`. It has two parts.
|
||||||
|
|
||||||
1. **Soft**: Replacing sharp corners with deep `1rem` (16px) to `1.5rem` (24px) border radii.
|
First, a 24px dot grid using a CSS background gradient:
|
||||||
2. **Translucent**: Using glassmorphism to create depth without heavy drop shadows.
|
|
||||||
3. **Alive**: Incorporating subtle, continuous motion that makes the site feel like a living organism rather than a static document.
|
|
||||||
|
|
||||||
## The "Living Blob"
|
```css
|
||||||
|
background-image: linear-gradient(to right, #80808010 1px, transparent 1px),
|
||||||
The heartbeat of this theme is the background. Instead of a flat color or a static gradient, I implemented what I call the "Living Blob".
|
linear-gradient(to bottom, #80808010 1px, transparent 1px);
|
||||||
|
background-size: 24px 24px;
|
||||||
```tsx
|
|
||||||
// src/app/layout.tsx
|
|
||||||
<div className="pointer-events-none fixed inset-0 -z-10 flex items-center justify-center overflow-hidden">
|
|
||||||
<div className="absolute inset-0 bg-[linear-gradient(to_right,#80808012_1px,transparent_1px)...] bg-[size:24px_24px]"></div>
|
|
||||||
<div className="animate-blob h-[800px] w-[800px] rounded-full bg-neutral-400/40 blur-3xl dark:bg-neutral-500/30"></div>
|
|
||||||
</div>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This single element—a massive, blurred circle—animates on a 7-second infinite loop, gently pulsing and shifting. It sits behind a technical grid pattern, creating a juxtaposition between the organic and the engineered.
|
Second, two large blurred circles that slowly drift on a 9-second loop:
|
||||||
|
|
||||||
## Floating UI
|
```tsx
|
||||||
|
<div className="animate-blob absolute left-[45%] top-[30%] h-[700px] w-[700px] rounded-full bg-primary/5 blur-3xl" />
|
||||||
|
```
|
||||||
|
|
||||||
One of the biggest structural changes was detaching the navigation and sidebar from the viewport edges.
|
The circles use `primary/5` — 5% opacity of the site's dark navy — so they're barely perceptible in isolation. The effect is more visible through the glass surfaces (nav, sidebar, cards) because of the `backdrop-blur` applied there.
|
||||||
|
|
||||||
In a traditional layout, the sidebar is stuck to the left, and the navbar is stuck to the top. In this system, they are **floating cards**.
|
The keyframe:
|
||||||
|
|
||||||
- **Navbar**: Fixed `top-4`, `left-4`, `right-4`.
|
```css
|
||||||
- **Sidebar**: Fixed `top-24`, `left-4`, `bottom-4`.
|
@keyframes blob {
|
||||||
|
0%, 100% { transform: scale(1) translate(0px, 0px); }
|
||||||
|
25% { transform: scale(1.08) translate(40px, -30px); }
|
||||||
|
50% { transform: scale(0.94) translate(-25px, 50px); }
|
||||||
|
75% { transform: scale(1.04) translate(35px, 30px); }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
This creates a sense of layering. The UI elements aren't _part_ of the window; they are tools floating _above_ the content.
|
Just shifts and scales slightly over time so the page doesn't feel completely static.
|
||||||
|
|
||||||
## Design Tokens
|
## Glass surfaces
|
||||||
|
|
||||||
### 1. Shape & Rounding
|
The nav, sidebar, and cards all use the same basic pattern: partially transparent background with a backdrop blur.
|
||||||
|
|
||||||
I chose a base radius of `1rem` (16px) because it strikes the perfect balance between friendly and professional.
|
Nav and sidebar:
|
||||||
|
|
||||||
- **Cards**: `rounded-3xl` (24px). Large containers need softer corners to feel less imposing.
|
```tsx
|
||||||
- **Buttons**: `rounded-xl` (12px). Tactile and clickable.
|
className="bg-background/80 backdrop-blur-md border-border/50"
|
||||||
- **Icons**: `rounded-full`.
|
```
|
||||||
|
|
||||||
This softness extends to interaction states. When you hover over a card, the `overflow-hidden` property ensures that any inner content (like images or background fills) respects these curves perfectly.
|
Cards:
|
||||||
|
|
||||||
### 2. Shadows & Glassmorphism
|
```tsx
|
||||||
|
className="bg-card/80 backdrop-blur-sm"
|
||||||
|
```
|
||||||
|
|
||||||
Instead of heavy drop shadows to show depth, I rely on **Glassmorphism**.
|
The blur is stronger on the nav and sidebar (`md` vs `sm`) because they sit in front of everything and need cleaner visual separation from the content layer behind them.
|
||||||
|
|
||||||
- **Surface**: `bg-background/80` with `backdrop-blur-md`. This allows the "Living Blob" to bleed through, tinting the UI with the background color.
|
For this to work, the color variables need to carry an alpha channel. In Tailwind v3, that means using `<alpha-value>` in the config:
|
||||||
- **Border**: `border-border/60`. A subtle, semi-transparent border defines the edges.
|
|
||||||
- **Shadow**: `shadow-sm`. A very light lift, just enough to separate the layer.
|
|
||||||
|
|
||||||
### 3. Color Palette
|
```ts
|
||||||
|
// tailwind.config.ts
|
||||||
|
background: "hsl(var(--background) / <alpha-value>)",
|
||||||
|
foreground: "hsl(var(--foreground) / <alpha-value>)",
|
||||||
|
// and so on for every color
|
||||||
|
```
|
||||||
|
|
||||||
The system uses a strict monochrome HSL palette that adapts to the user's system preference.
|
Without this, `bg-background/80` silently renders at full opacity — the modifier does nothing. Took longer to track down than I'd like to admit.
|
||||||
|
|
||||||
|
## Typography
|
||||||
|
|
||||||
|
Two fonts: [Playfair Display](https://fonts.google.com/specimen/Playfair+Display) for headings and card titles, Inter for everything else. Both loaded via `next/font`.
|
||||||
|
|
||||||
|
The reason isn't purely aesthetic — it's contrast. Inter at body size is readable and neutral, which is what you want for dense text. Playfair at heading sizes adds visual weight without needing to push font sizes up. It also reads differently from the surrounding text, which makes the hierarchy more obvious at a glance.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/lib/fonts.ts
|
||||||
|
export const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
|
||||||
|
export const playfair = Playfair_Display({ subsets: ["latin"], variable: "--font-heading" });
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// tailwind.config.ts
|
||||||
|
fontFamily: {
|
||||||
|
sans: ["var(--font-sans)", ...fontFamily.sans],
|
||||||
|
heading: ["var(--font-heading)", ...fontFamily.serif],
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Shape
|
||||||
|
|
||||||
|
Cards use `rounded-2xl` (16px) instead of the shadcn default `rounded-lg` (8px). The sharper corners looked out of place next to the blurred background — softer corners make the floating-card feel more coherent.
|
||||||
|
|
||||||
|
## What didn't work out of the box
|
||||||
|
|
||||||
|
The shadcn component suite I updated to targets dense dashboards. The defaults are too compact for a reading-oriented site:
|
||||||
|
|
||||||
|
| Component | Default | Updated |
|
||||||
|
|-------------|----------------|----------------|
|
||||||
|
| Card text | `text-xs/relaxed` (12px) | `text-sm` (14px) |
|
||||||
|
| Card title | `text-sm font-medium` (14px) | `text-base font-semibold` (16px) |
|
||||||
|
| Badge | 10px text, 20px height | 12px text, 24px height |
|
||||||
|
| Button | 12px text, 28px height | 14px text, 36px height |
|
||||||
|
|
||||||
|
The other issue was keyframes. Several accordion and slide animations were defined inside an `@theme inline { }` block — a Tailwind v4 directive. In a v3 project, the browser treats `@theme` as an unknown at-rule and skips its contents entirely, so the animations were silently broken. Moved them to top-level CSS and they worked immediately.
|
||||||
|
|
||||||
|
## Color palette
|
||||||
|
|
||||||
import { ColorPalette } from "~/components/ColorPalette";
|
import { ColorPalette } from "~/components/ColorPalette";
|
||||||
|
|
||||||
<ColorPalette />
|
<ColorPalette />
|
||||||
|
|
||||||
## Typography: Editorial Meets Digital
|
The palette is a standard HSL monochrome system that adapts to the user's system preference. Nothing exotic.
|
||||||
|
|
||||||
For typography, I wanted to blend the readability of a digital product with the elegance of an editorial magazine. This "Editorial meets Digital" philosophy relies on the interplay between two distinct typefaces.
|
---
|
||||||
|
|
||||||
### The Serif: Playfair Display
|
That's the system. Most of it is just being deliberate about which defaults to override and why.
|
||||||
|
|
||||||
<p className="mb-6 font-heading text-4xl">Playfair Display</p>
|
|
||||||
|
|
||||||
I chose **Playfair Display** for all headings (`h1`–`h6`). It's a transitional serif typeface with high contrast strokes and delicate hairlines.
|
|
||||||
|
|
||||||
- **Why Serif?** Serifs feel "human", "established", and "emotional". They break the sterile "tech" vibe common in developer portfolios.
|
|
||||||
- **Why Playfair?** Its high contrast makes it perfect for large display sizes. It commands attention and adds a layer of sophistication that a sans-serif simply cannot achieve.
|
|
||||||
|
|
||||||
### The Sans: Inter
|
|
||||||
|
|
||||||
<p className="mb-6 font-sans text-4xl">Inter</p>
|
|
||||||
|
|
||||||
I chose **Inter** for the body text. It is the gold standard for screen readability.
|
|
||||||
|
|
||||||
- **Why Sans?** Sans-serif fonts are "rational", "clean", and "invisible". They reduce cognitive load, making long-form reading (like this blog post) effortless.
|
|
||||||
- **Why Inter?** It was designed specifically for computer screens, with a tall x-height that remains legible even at small sizes.
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
|
|
||||||
The font stack is implemented using `next/font` for zero layout shift and CSS variables for Tailwind integration.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// tailwind.config.ts
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
fontFamily: {
|
|
||||||
sans: ["var(--font-sans)", ...fontFamily.sans],
|
|
||||||
heading: ["var(--font-heading)", ...fontFamily.serif],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
/* src/styles/globals.css */
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
@apply font-heading; /* Playfair Display */
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
@apply font-sans; /* Inter */
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
This design system is more than just a theme; it's a statement about how I view software. It shouldn't just be functional; it should be inviting. It should feel like a space you want to inhabit. By combining soft shapes, organic motion, and editorial typography, I hope I've created a digital garden that feels a little more human.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user