Live Ocean
A 1,367 km ocean swim, tracked live from shore to shore.
- Role
- Frontend Lead
- Discipline
- Live Tracking
- Year
- 2026
- Focus
- Next.js, TypeScript

(Overview)
I led frontend on the live tracking experience for Swim4TheOcean - the product audiences used to follow a 1,367 km New Zealand ocean swim in real time.
The tracker had to stay live for 90 days: GPS, history scrubbing, CMS updates, mobile map UX, and shareable links - without becoming a second campaign site.
I built a Next.js shell around PredictWind’s marine map, used Sanity for mid-mission edits, and kept stats, scrubbing, and URL state in sync with the map through a typed postMessage bridge.
Ran the full swim with dual-track GPS, compressed-timeline replay, and weather tied to scrub time. Ops updated legs and media without redeploys. 4.48M page views and ~300k unique visitors.
- Next.js
- TypeScript
- TailwindCSS
- tRPC
- Sanity
- nuqs
(By the numbers)
(Brief)
Mission context
Swim4TheOcean followed ultra-marathon swimmer Jono Ridler from North Cape to Wellington (Jan–Apr 2026). PredictWind powered the public live tracker so people could follow location, pace, distance, and sea conditions across 1,367 km.
(Film)
Mission film
Campaign footage that set the story. The tracker had to make the swim watchable in real time.
(Architecture)
System layers
A Next.js shell and PredictWind map stay in sync through a typed message bridge.
- Next.js shell
- Stats, scrubber, media viewer, and shareable URL state
- Map iframe
- PredictWind map with track, layers, markers, and follow mode
- Sanity
- Legs, stroke rates, stopovers, and media - editable mid-mission
- APIs
- GPS tracks and weather/marine conditions via tRPC
(Product surface)
What followers could do
- 01
Live progress
Distance, swim time, speed, and stroke rate with course remaining.
- 02
Conditions
Wind, waves, currents, and sea temperature keyed to scrub time and position.
- 03
Timeline
Live mode, playback, skip-breaks replay, and shareable timestamps.
- 04
Media
CMS images, video, livestreams, and updates opened from map markers.
(Product)
Tracker UI
Full-viewport map with live stats, scrubbable timeline, and mission media.


Mobile
Stats and scrubber sit in a bottom sheet so the map stays full-bleed on phone.

(Hard problems)
Constraints that shaped the build
90 days of swim and rest cycles
Compressed timeline that skips rest by default so replay stays usable
Map and React app on different lifecycles
Typed postMessage bridge keeps date, live mode, layers, and follow in sync
Ops need mid-mission updates
Sanity live queries for legs, media, and map settings - no redeploys
(Impact)
What I shipped
- 01
Shipped the production tracker used throughout the 90-day mission.
- 02
Made map state, media, and scrub time shareable via URL state and a postMessage bridge.
- 03
Gave ops a Sanity workflow so the live product never blocked on deploys.
