Skip to main content

Changelog

v6.28.0

Header-Aware Sticky, OG Revalidation & Token Refresh

Another new release! In this release, I focused on making navigation feel more intentional and trimming a few things that no longer needed to be there.

The navbar now watches the hero header in desktop too and only pins after you scroll past it. I also fixed the stacked cards offset underneath, so content no longer jumps. The scroll feels calmer and more predictable.

I removed the custom smooth scroll system (Lenis). It just stopped feeling like “me”. The extra smoothness started to feel more like a layer between me and the content than an improvement. Native scroll with a lighter lock does the job with less JavaScript, especially on mobile. The desktop header keeps its drag interaction, but heavy animation logic is now limited to desktop. Mobile loads faster and feels snappier, while content still renders for SEO.

Open Graph images are now generated per slug with revalidation, so sharing Writing and Work pages to social is more consistent. Titles now scale to length so long titles don’t overflow, and tweet embeds have a fallback so one failing embed doesn’t break the page.

I tidied the design tokens. Font loading is more consistent, warning text has proper contrast in light and dark modes, and sizes use rem for better scaling. Overall type now has a more consistent rhythm and first paint is a bit lighter.


  • Allowed the site to be embedded in iframes for previews
  • Tightened security headers for tracking and proxying
  • Added rate limiting to the Singline waitlist
  • Updated the build setup with the Netlify Next.js plugin and bumped Node, pnpm, and Next for better stability
  • Made the header stripe and responsive logo in the navigation bar more reliable
v6.27.5

Sticky Navbar, Bundle Optimizations & More

In this release, I focused on performance optimization and making interactions feel more refined across the site.

The navbar now features a sticky latch — snapping into a fixed position as you scroll past the hero, giving navigation a more intentional and polished feel. It stays out of the way when you don't need it and locks in exactly when you do.

Inspired by Gabriel Valdivia's experience migrating away from Framer, I moved to R2 to reduce costs and regain more control over my media pipeline. The migration was the hardest part — not just moving files, but also updating Sanity data and doing a significant refactor of content blocks that were tightly coupled to Cloudflare-specific image and video formats. I took that opportunity to make the code more product-agnostic so those blocks aren't tied to any specific provider. Cloudflare still handles image transformation and blur placeholder generation via srcset, just no longer for storage.

There are occasional image loading inconsistencies I'm still tracking down, could be Next.js, R2 configuration, or something in between — but overall things are in a good place.

This release includes major JavaScript bundle optimizations. The desktop header is now code-split using Next.js dynamic() imports, so mobile devices no longer download or execute the drag system, ResizeObserver loops, or widget animation logic. The interactive code still SSR's for SEO, but the heavy client-side execution is gated to desktop viewports, giving mobile users faster parse times and a better Time to Interactive.Smoother Animations

Mobile header widgets now cascade in with staggered entrance animations featuring subtle 3D perspective effects. All animations respect prefers-reduced-motion for accessibility.

Added 356 lines of centralized spacing rules in typography.css, establishing consistent vertical rhythm across all prose variants. Headings, lists, and blockquotes now follow a unified spacing scale site-wide.

Also in mobile in writing and work detail page, the image and video now edge to edge filling the entire width, not inside the main container. This will look so much neat when reading on mobile.

Screenshot of a blog post by Afnizar Nur Ghifari, featuring text about creating a supportive design community. An image shows a workspace with people collaborating.

  • Work project favicons now use SVG masks instead of CSS border-radius for reliable rounded corner rendering across environments
  • Testimonial accordion auto-pauses when scrolled out of view via IntersectionObserverPagination dots have expanded touch targets using pseudo-elements for better mobile accessibility
  • Avatar widget now loads thumbnail variants for a faster initial renderIncreased Sanity fetch timeout from 5s to 10s to reduce transient failures on slow connections
  • Removed 30+ lines of dead code, including unused image optimization utilities and motion components
  • Simplified image handling by removing redundant Cloudinary/ImageKit transformation logic in favor of consistent R2 URLs
v6.27.0

Avatar Picker, Changelogs, and More

Welcome to the first changelog for my personal site! a running log of what's new, improved, and fixed as I build in public.

A new picker component for browsing and selecting avatars. It's a bit cringy, I know — but I like it. It supports touch input and drag-to-scroll, so browsing through options feels smooth on both mobile and desktop. Give it a try from the avatar widget on the home page.

Rather than shipping changes quietly, this page gives every update a proper home. You're reading the first one.

A new widget in the horizontal header surfaces my latest writing, so it stays visible as new posts come in.


  • The avatar widget was refactored with absolute positioning and proper z-index layering for a more stable layout. A titleColor prop was added, ring styling was swapped for outline, and the picker is now horizontally scrollable on mobile.
  • Static imports now replace dynamic blur placeholder generation across avatar, footer, and gallery images — keeping Next.js builds fast as the site grows.