All thoughts on
craft & code.
Essays on motion, frontend performance, and the 1% details that make interfaces feel premium.
text-wrap: balance and pretty — Typography the Browser Fixes Now
Lonely last words on headlines, orphans at paragraph ends — line-breaking sins designers fixed by hand for decades. Two CSS values now fix them permanently.
gsap.to(...)
gl.drawArrays(...)
Form Micro-Interactions: Where Motion Earns Its Keep
Forms are where users are most anxious and most honest. Validation timing, the shake that means no, and success states that reward completion.
The Third-Party Script Diet: Your Site Is Slow Because of Other People
Analytics, chat widgets, pixels — the median site ships more third-party code than its own. An audit ritual, a facade pattern, and a worker to exile the rest.
Designing Empty States: The First Screen Users Ever See
Every user meets your product empty before they meet it full. Turning blank screens from dead ends into starting lines — guidance, gradients of emptiness, and tone.
gsap.to(...)
gl.drawArrays(...)
The dialog Element: Modals You Stop Maintaining
Focus traps, backdrop, Escape handling, inert background — the modal checklist the platform now does for you. showModal(), ::backdrop, and closedby.
A Real prefers-reduced-motion Strategy (Not Just Turning Things Off)
Reduced motion is not no motion. Which animations to keep, which to swap for crossfades, and how to build it as a system instead of an apology.
Compositor-Only Animations: The 60fps Contract
transform and opacity animate on a separate thread and cannot jank — everything else can. The rendering pipeline, will-change etiquette, and cheap ways to fake the expensive.
gsap.to(...)
gl.drawArrays(...)
Border Radius Consistency: The Detail That Exposes Rushed UI
Mismatched corner radii are the typo of visual design. Nested radius math, a sane token scale, and why concentric corners feel right.
CSS Anchor Positioning: Tooltips That Position Themselves
Pin any element to any other element, with automatic flipping when space runs out — the layout problem that kept Popper.js alive, now solved in CSS.
Hover Choreography: Interfaces That Acknowledge You
A good hover state is a conversation: the cursor asks, the element answers, its siblings step back. Group hovers, focus parity, and timing that feels intentional.
gsap.to(...)
gl.drawArrays(...)
Image Formats in 2026: AVIF First, and Fewer Bytes Than You Think
AVIF is universally supported and half the size of JPEG at equal quality. The modern image stack: format, sizing, priority, and the three attributes that matter.
Whitespace Is Hierarchy: The Cheapest Design Tool You Have
Before color, weight, or size, spacing tells readers what belongs together. Proximity ratios, spacing scales, and why cramped interfaces feel cheap.
@property: Typed CSS Variables That Actually Animate
Custom properties are strings — which is why animating them snaps instead of tweening. @property gives them types, and suddenly gradients, angles, and numbers interpolate.
gsap.to(...)
gl.drawArrays(...)
Scroll Snap: Storytelling in Full-Screen Chapters
Scroll snapping turns a page into chapters — carousels, onboarding flows, full-bleed stories — with pure CSS. And the discipline to know when not to.
Font Loading Without the Flash: A 2026 Strategy
FOUT, FOIT, and layout shift are all self-inflicted. Preload, font-display, and size-adjust fallbacks make web fonts effectively invisible to loading.
Dark Mode Done Properly: It Is Not a Filter
Inverting colors is not designing a dark theme. Elevation flips from shadows to lightness, saturation must drop, and pure black is a mistake. The real checklist.
gsap.to(...)
gl.drawArrays(...)
CSS Subgrid: The Alignment Problem Grid Could Not Solve Alone
Cards in a row with misaligned titles, prices, and buttons — the oldest grid frustration. Subgrid lets children align to their grandparent tracks. Solved.
Staggered Reveals: Choreography, Not Decoration
Twelve cards fading in at once reads as one blob. Stagger them 40ms apart and the eye follows a story. The rules of good stagger timing, in CSS.
Speculation Rules: Instant Navigation by Betting on the Next Click
The browser can now prerender the next page before the user clicks — entire navigations in 0ms. The Speculation Rules API, and how to bet without wasting bandwidth.
gsap.to(...)
gl.drawArrays(...)
OKLCH: The Color Space Your Design System Should Have
HSL lies: 50% lightness in yellow and blue are wildly different brightnesses. OKLCH makes lightness honest — and makes generated palettes finally look designed.
The Popover API: Tooltips and Menus Without the Library
Light dismiss, top-layer stacking, focus handling — everything you imported Floating UI for is now two HTML attributes. The Popover API in practice.
FLIP: The Technique Behind Every Smooth Layout Animation
You cannot animate layout without jank — unless you invert it. FLIP turns expensive layout changes into cheap transforms, and it powers every smooth reorder you have seen.
gsap.to(...)
gl.drawArrays(...)
content-visibility: The Biggest Rendering Win Nobody Ships
One CSS property that tells the browser to skip rendering offscreen sections entirely — often halving initial render time on long pages. Here is how to use it…
Fluid Type Scales: Stop Breakpointing Your Typography
Font sizes that jump at breakpoints are a relic. clamp() plus viewport units give typography that glides between devices — one line per text style.
Container Queries: Components That Own Their Responsiveness
Media queries ask how big the window is. Container queries ask how big MY box is — the question components actually needed. Sidebars stop breaking cards forever.
gsap.to(...)
gl.drawArrays(...)
linear() Easing: Real Springs in Pure CSS
cubic-bezier can only draw one hump — no bounce, no overshoot-and-settle. The linear() function ends that limit and brings true spring physics to CSS.
INP: The Metric That Finally Measures How Your Site Feels
Interaction to Next Paint punishes what users actually hate: taps that do nothing. Here is where INP debt hides and the patterns that pay it down.
CSS :has() — The Parent Selector Changes How You Architect Styles
For twenty years CSS could only look down the tree. :has() looks up, sideways, and forward — killing a whole class of state-tracking JavaScript.
gsap.to(...)
gl.drawArrays(...)
Optical Alignment: When the Math Is Wrong
Perfectly centered is often visibly off. Why play icons, quotation marks, and rounded shapes need optical correction — and how to train your eye to see it.
The View Transitions API: App-Like Navigation Without a SPA
The View Transitions API brings native-app page morphs to plain multi-page sites. Two lines of CSS, no router, no framework — here is how to ship it today.
Got a project in mind? Let's build it.
Or just want to talk shop about motion and frontend craft — say hello.