Skip to main content

The Craft of Small Details

A deep dive into the quiet design engineering details that make a personal website feel grounded, from history state pagination and server component boundaries to stroke weights, card geometry, and render-safe audio.

10 min read

When a personal website has been running for a while, you naturally grow blind to its rough edges. You know which areas are clickable, you understand how each section transitions, and you excuse minor layout shifts or awkward hitboxes because you built them. Recently, after spending more time studying user experience and design engineering, I decided to walk through my entire site with fresh eyes. Software communicates its care through subtle qualities that most people never consciously dissect. If an icon feels too faint on a mobile screen, if an archive card is cluttered with redundant labels, or if navigating backward resets your position, the interface feels slightly ungrounded. I wanted to systematically audit these quiet flaws and rebuild them properly.

The Skills and Standards Behind the Audit

To guide this audit systematically, I relied on structured skills rather than casual intuition. I deployed my own HIG compliance auditor skill, which I created to benchmark web interfaces against Apple Human Interface Guidelines. My skill focuses specifically on touch target ergonomics, accessibility, and translating platform-specific paradigms to the open web. Having a formalized set of checks made it possible to spot physical boundary violations that standard visual inspection misses. You can install and run this auditor directly into any project:

npx skills add omrajguru05/skills --skill hig-compliance-auditor

Alongside my HIG auditor, I incorporated Emil Kowalski's design engineering skills. His framework emphasizes that unseen details compound into an aggregate feeling of quality. From direct pointer-down feedback and active press scaling to optical stroke compensation across dark glass surfaces, these skills provided the motion and styling vocabulary needed to solve each issue cleanly:

npx skills@latest add emilkowalski/skills

Combining my HIG compliance auditor with these design engineering principles transformed subjective aesthetic impressions into concrete, testable engineering tasks.

The interactive labs and code examples below demonstrate each problem I uncovered, the code that resolved it, and the reasoning behind each decision.

Touch Targets and Optical Weight

A common trap in modern web design is prioritizing how an interface looks on a desktop monitor while ignoring how it behaves under a thumb on glass. My top navigation bar included search triggers that looked neat visually, but their hitboxes were tiny. On mobile devices, tap targets measured barely thirty-two pixels. Users tapping quickly on a phone frequently missed the hit box, resulting in unresponsive taps and subtle frustration.

According to Apple Human Interface Guidelines and the rules codified in my HIG compliance auditor skill, the minimum reliable touch target for handheld devices is forty-four by forty-four pixels. Even when an icon is optically small, its invisible interactive boundary must expand to meet this forty-four pixel threshold. Furthermore, the icon stroke weight in my dark glassmorphic navigation bar was only one point five pixels. Against a translucent dark backdrop with blur effects, that thin line lost optical contrast and appeared washed out.

I upgraded the icon to a rounded Apple Finder stroke icon, boosted its stroke weight to two point two pixels for crisp contrast on OLED displays, wrapped it in a forty-four pixel transparent touch boundary, and added physical press feedback using active scale ninety-five.

<button
  type="button"
  onClick={onOpenSearch}
  aria-label="Search articles and notes"
  className="flex items-center justify-center text-foreground/80 hover:text-foreground hover:bg-muted/50 active:bg-muted/70 active:scale-95 transition-all touch-target-44 rounded-full"
>
  <AppleFinder
    size={16}
    strokeWidth={2.2}
    className="transition-transform duration-100"
  />
</button>

In the interactive lab below, you can tap both buttons side by side to compare the raw thirty-two pixel hitbox against the engineered forty-four pixel target with optical stroke tuning.

Tap both buttons to compare optical stroke clarity and hit boundary responsiveness.

Before: 32px target, 1.5 stroke
Tap to test
After: 44px target, 2.2 stroke
Tap to test

Card Geometry and Cognitive Noise

Consistency in visual geometry is what separates an intentional design system from an ad-hoc collection of assembled cards. While reviewing the archive feeds across my writings and dev notes pages, I noticed an incongruity in how metadata badges were placed. The cards previously used a floating rounded pill badge for the publication date. Because rounded pills have curved semicircular caps on both sides, the text inside floats without a hard geometric anchor. When stacked vertically above the card headline, the pill caused visual wobble against the clean left edge of the title and summary paragraph.

To solve this, I replaced the rounded pill with an architectural four-pixel rectangular date badge. The subtle four-pixel corners lock the date flush into the vertical typography grid alongside the reading duration indicator.

Alongside locking the date geometry to the margin, I audited the interactive prompts on each card. Every archive entry previously ended with an explicit text link that said Read article with an arrow pointing right. While this seems harmless at first glance, it is completely redundant. An archive card that already features an index tag, a reading duration, a bold title, and a descriptive excerpt is unmistakably an article waiting to be read.

Adding a repetitive action label to every card increases cognitive noise and forces the reader to filter out visual clutter. Removing the label clarifies the hierarchy, giving the card room to breathe and letting the typography speak for itself. In the interactive preview below, toggle between Before and After to watch the date lock into the blue vertical grid line, and see the redundant action prompt dissolve through a particle vanish effect.

Toggle between card layouts to inspect edge alignment and visual hierarchy.

Sep 16, 20267 min read

The Craft of Small Details

A deep dive into the quiet design engineering details that make a personal website feel grounded, from history state pagination and server component boundaries to stroke weights and card geometry.

Homepage Architecture and the Docked Notch Tag

While archive feeds benefit from flush vertical margin alignment, the homepage grid required a different architectural solution. On the homepage, featured cards for Dev Notes, Poetry, and Quick Ships previously housed their date and category labels inside the card body as an internal skeleton bar above the title. This pushed the headline downward and created an awkward visual block inside the card canvas.

To establish a stronger physical hierarchy, I elevated the date completely out of the card interior into a docked notch tag. Centered directly across the top border line of the card, the notch tag acts as an external index marker. It uses gentle six-pixel rounded corners, a solid card-matching background to mask the underlying border line without subpixel bleed, and category-coded accent strokes.

The category color system uses distinct hues across the site: vibrant blue for Dev Notes and recent writing, regal purple for Poetry, and warm orange for Quick Ships. On hover, the docked notch tag illuminates with an accent glow while the card background lifts cleanly into focus.

// Docked notch tag centered directly on the top card border
<div className="group relative flex flex-col h-full pt-3">
  <div className="absolute top-0 left-5 sm:left-6 z-10 flex items-center">
    <div className="inline-flex items-center px-2.5 py-0.5 font-mono text-xs font-medium rounded-md border border-accent-blue/40 bg-bg-2 text-accent-blue group-hover:bg-bg-3 group-hover:border-accent-blue/70">
      {date}
    </div>
  </div>
  <div className="relative flex flex-col flex-1 rounded-xl border border-border-1 bg-bg-2 p-6 pt-7 group-hover:bg-bg-3">
    {children}
  </div>
</div>

In the interactive lab below, test the homepage card across all three category colorways. Compare the internal skeleton bar in Before against the docked notch tag and illumination in After.

Sep 16, 2026

The Craft of Small Details

A deep dive into the quiet design engineering details that make a personal website feel grounded, from history state pagination and server component boundaries to stroke weights.

Read Snippet

Hover over the card to test illumination. Notice how in After the docked tag rests directly across the top border line with zero border bleed.

Preserving Pagination State with Clean URLs

One of the most frustrating user experience bugs on content-heavy websites happens during archive browsing. Suppose you are looking through writings, and you paginate to page seven. You find an interesting article, click to read it, and then click the browser back button or the breadcrumb link to return to the list. On many websites, doing this unceremoniously dumps you back onto page one. You lose your browsing position entirely and must click next six times to resume where you left off.

The naive solution to this problem is appending a query parameter like question mark page equals seven to the URL. While functional, that clutters the address bar with temporary state that does not belong there. A visitor sharing a link to my writings index should share a clean address, not an arbitrary pagination offset from their session.

To solve this cleanly, I turned to the browser history state combined with a session storage fallback. When the user paginates, the application records the current page into window history state using replaceState. Because this state is attached directly to the history entry, the browser address bar remains completely clean without any query strings.

// Updating history state without polluting the address bar
const updatePaginationState = (page: number) => {
  if (typeof window === "undefined") return;
  
  sessionStorage.setItem("writings_page", String(page));
  
  const currentState = window.history.state || {};
  window.history.replaceState(
    { ...currentState, writingsPage: page },
    "",
    window.location.pathname
  );
};

When the reader clicks into an article and subsequently navigates backward, the archive component reads the saved page index from the history state and immediately renders page seven. Furthermore, when a user clicks the writings link in the top navigation bar, the application treats that as an intentional fresh visit, clears the session storage, and resets the view to page one.

Try the simulated archive below. Paginate to page seven, open an article, and use either the back link or simulated browser back button to see your position preserved.

Navigate to an article and click back to see pagination position preserved without URL query strings.

omrajguru.com/devnotes
Page 7 of 8
The Craft of Small Details
7 min
Fluid Springs and Spatial Continuity
5 min
Architectural Seams in React 19
9 min

Server Component Boundaries and Event Handlers

Modern React and Next.js applications draw a sharp architectural boundary between Server Components and Client Components. Server Components execute exclusively on the server, generating static HTML and streaming UI without shipping unnecessary JavaScript to the client. Client Components handle interactivity, event listeners, and browser APIs.

When building the breadcrumb navigation for article headers, I wanted the back link to be smart. If the visitor arrived from an archive page, clicking back should trigger browser history navigation to preserve their scroll and pagination position. If they arrived directly from an external link or search engine, it should fall back to standard anchor navigation to the main archive.

In my initial implementation, I passed an onClick event handler into a link inside the article page shell. Because the shell was a Server Component, React immediately threw a runtime serialization error. Props passed across the server and client boundary must be serializable JSON values. Functions and event listeners cannot cross that boundary.

"use client";
 
import { useRouter } from "next/navigation";
import Link from "next/link";
import { ArrowLeft } from "@/icons";
 
export function ArticleBackLink({ href, label }: { href: string; label: string }) {
  const router = useRouter();
 
  const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
    if (typeof window !== "undefined" && window.history.length > 1) {
      e.preventDefault();
      router.back();
    }
  };
 
  return (
    <Link
      href={href}
      onClick={handleClick}
      className="inline-flex items-center gap-2 hover:text-text-1 transition-colors"
    >
      <ArrowLeft className="h-4 w-4" />
      <span>{label}</span>
    </Link>
  );
}

The proper solution was isolating the interactive behavior into a dedicated client component called ArticleBackLink. The Server Component remains entirely pure, rendering structural HTML, while the isolated client component encapsulates the interactive history check. This keeps client bundle sizes minimal while maintaining crisp architectural separation.

Render-Safe Audio Synchronization

The media player on my site allows listeners to stream spoken audio recordings of long articles. While auditing component performance, I discovered an anti-pattern in how the audio player tracked time elapsed and track duration.

The component was reading mutable DOM properties from the audio element reference directly during the React render phase. Reading current time and duration from a mutable ref during render violates React purity. Because ref mutations do not schedule re-renders, the player used an awkward mounting flag to force updates, leading to rendering inconsistencies and potential layout thrashing.

// Event-driven, pure React state synchronization
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
 
const handleTimeUpdate = (e: React.SyntheticEvent<HTMLAudioElement>) => {
  setCurrentTime(e.currentTarget.currentTime);
};
 
const handleLoadedMetadata = (e: React.SyntheticEvent<HTMLAudioElement>) => {
  setDuration(e.currentTarget.duration);
};
 
const handleEnded = () => {
  setIsPlaying(false);
  setCurrentTime(0);
};

I refactored the player to rely entirely on native HTML audio event handlers. By binding onLoadedMetadata, onTimeUpdate, and onEnded directly to React state setters, time and duration updates flow through predictable React render cycles. The component becomes deterministic, eliminates side effects during render, and synchronizes the playback bar cleanly at sixty frames per second.

Why Small Details Matter

When you step back from these changes individually, none of them sound radical in isolation. A two-pixel wider touch target, an eight-line history state handler, a four-pixel badge radius, and an event-driven audio hook will not make headlines. Yet in software engineering, the sum of these quiet decisions is precisely what defines user trust.

Great design engineering is not about flashy decoration. It is about removing friction that people feel even when they cannot name it. When an interface respects thumb ergonomics, maintains visual geometry, preserves your location across navigation, and responds instantly to your touch, it feels grounded and dependable. Building software with that level of care takes patience, but it is the only kind of craftsmanship worth pursuing.