Case Study

A healthcare website rebuilt
for editorial independence.

Migrating GoInvo’s website off aging Gatsby infrastructure and rebuilding it around three things: a Sanity CMS that lets non-technical editors publish independently, an animation layer with card-morph transitions and scroll-driven reveals, and accessibility as a first-class constraint. Live and serving real traffic.

Feb 2026 – present · GoInvo (employer work)

View Project (opens in new tab)
Next.js 16React 19TypeScriptSanity CMSTailwind CSS v4Framer MotionGROQView Transitions API
01

The Problem

GoInvo is a healthcare UX studio whose Gatsby site had become a liability on multiple fronts. Build times stretched to minutes as the plugin ecosystem stagnated. Every content update required a developer to write JSX, commit to Git, and wait for a deploy. Accessibility was inconsistent. Animations were absent. The studio’s writers and designers were locked out of their own site.

The brief: a CMS the studio’s writers could actually use, animation that matches their design quality, and accessibility from the start. I wrote migration scripts to port existing content, set up the collaborative editing environment, and built custom components so the team could publish without touching code. Jen, Eric, and Claire gave feedback throughout the build.

GoInvo homepage showing hero section, featured case study, and client testimonial

The rebuilt homepage: full-bleed photography, featured case study cards, and a client testimonial ribbon.

02

Architecture

Content flows from Sanity Studio through GROQ queries into React Server Components, which are statically generated at build time with incremental revalidation for updates. Only interactive elements (animations, forms, the card morph system) hydrate on the client.

Why Next.js 16 App Router: streaming and partial prerendering let the shell load instantly while dynamic content hydrates progressively, and nested layouts made the persistent header/footer with animated page transitions straightforward.

03

Giving Editors Control

Before: a writer finishes a vision article and sends it to a developer. The developer converts it to JSX, adds images, commits to Git, waits for a build, and deploys. The writer sees the result hours later and asks for three changes. Each round-trip costs a day.

After: the writer opens Sanity Studio, types directly into a rich text editor, drags in images, and sees a live preview of the published page updating as they type. They hit publish. The site updates in seconds. No developer needed.

Getting there meant modeling everything the studio publishes (case studies, articles, team bios, job postings, testimonials, client logos, services, and site-wide settings) as structured Sanity documents. The portable text fields support custom blocks for pull quotes, image grids, and full-bleed sections so editors can create rich layouts without writing markup.

Beyond the schema, I designed the Studio experience itself around how the team actually works. Previews are separated into their own sections so editors see exactly where new content will appear on the live site. Each section includes a blank card with an “Add” button, so a studio member browsing the Vision page can create a new article right there, in the context where it belongs, instead of navigating the Studio’s document list and hoping it lands in the right place.

Sanity Studio showing side-by-side live preview and content editing for a case study

The editor’s view: content on the left, live preview on the right. Changes appear instantly.

04

Making Navigation Feel Physical

A healthcare design studio needs its site to feel crafted. Hard page cuts between case studies undermine that. So when a user clicks a project card, the card’s image morphs into a full-width hero for the new page. Everything transforms in place.

This works because of how the brain tracks objects. The dorsal visual stream maintains continuity when something transforms in place, but registers a “new scene” when content jump-cuts. It’s the difference between opening a door and teleporting to a different room. The morph transition keeps the user oriented.

The hard part was making this work with Next.js. React’s App Router destroys the current page immediately on navigation, which kills any exit animation. The fix was a FrozenRouter that holds the old page in place during the exit, then hands off to the new page once the morph completes. Took days to debug.

The card-morph in action. The image expands from the grid into the hero position. No jump cut.

05

Results

0

Dev hours to publish content

All

content editor-managed — case studies to job postings

Feb 2026

First commit to content parity in 10 weeks

AA

WCAG compliance

The site is live. Content editors publish case studies, vision articles, and team updates without developer involvement.

Since launch I’ve been building an AI-assisted marketing layer on the same foundation: analytics pulled from GA4, Search Console, and Core Web Vitals into Sanity dashboards, plus LLM-driven content planning and citation checking. Ongoing.

GoInvo Vision page on mobile showing responsive layout with spotlight cards and featured articles

The Vision page on mobile: stacked spotlight cards and scroll-driven animations on small screens.

06

What I'd Do Differently

I stopped treating frameworks as black boxes.

The page transition bug had no Stack Overflow answer. The fix was in React’s internal LayoutRouterContext, which I only found by reading the App Router source. Before this project I would have worked around the limitation. Now I go to the source when docs run out.

I design for production editing patterns now, not developer testing.

Sanity’s live events fired on every keystroke, which was invisible in my single-editor local setup. With three editors in staging, the render storms were immediate. I now stress-test collaborative features with realistic editing behavior from day one.

Small defensive patterns compound across the whole pipeline.

Making the Sanity client return empty arrays when unconfigured (instead of throwing) was a one-line change. It unlocked CI in every environment without CMS credentials and removed an entire class of deployment issues. I think more carefully now about which small decisions have outsized downstream impact.