FightCamp
Duration: November 2021 - January 2023
Role: Full-Stack Engineer
The Context
FightCamp was the "Peloton for boxing", a connected fitness startup riding the pandemic home-workout boom. I joined a small web team of three engineers, and I got the role through a former mentee from Internet Brands who'd recommended me.
The company had grown fast, but the website's foundations hadn't kept up; I found out exactly how far behind they were on my first R&D Friday.
The Challenge
Performance Discovery
No one had ever run a Lighthouse audit on the marketing site, so on my first R&D Friday (monthly time set aside for cleanup, refactoring, and poking around), I did. The scores were dismal.
Mobile First Contentful Paint was 8-12 seconds, which meant users on 3G/4G were bouncing before they ever saw a thing. So I dug into why:
- Images: HD images (hundreds of megabytes total) served regardless of viewport size
- Videos: Hero videos were 500-800 MB, downloaded entirely on page load
- Bundle bloat: Duplicate libraries, no tree shaking, ~725 KB total
- No lazy loading: Everything loaded upfront, blocking render
- Missing optimizations: Incorrect image dimensions, missing HTML attributes
I pitched my manager a systematic fix, he approved it, and it became my primary project.
Marketing Was Bottlenecked, Again
I'd seen this exact pattern before, at Winc: marketing leaned on engineering for every content update. A copy change, an image swap, a new section, all of it needed a developer. I'd already solved this once, so I knew where it was heading.
The Solution
Performance Optimization
I went after each root cause one at a time:
Images:
- Built a centralized image component with viewport-dependent srcset
- Integrated with Storyblok CMS + fallback providers
- Added lazy loading via Intersection Observer
- Served device-appropriate quality and dimensions
Video:
- Manually optimized video assets, creating multiple quality tiers
- Reduced file sizes from 500-800 MB to <300 MB (MP4) / <150 MB (WebM)
- Built a lazy-load video component that deferred download until near-viewport
Bundle:
- Removed duplicate libraries
- Tailored Nuxt.js build configuration
- Streamlined task chaining
- Reduced bundle from ~725 KB to ~275 KB
Discovery: While debugging, I found the Vue store alone was costing 20 Lighthouse points; with it unloaded, scores jumped to 98-99. The store stayed because we needed the functionality, but at least it explained the ceiling I kept hitting.
Storyblok CMS Migration
I went through 7 marketing pages looking for the patterns they shared, then extended the UI component library with 10+ CMS-connected components:
- PageSection, Copy, Video, Image, Hero, Thumbnail, and more
- Each one documented in Storybook with usage examples
- Full Jest test coverage
- Storyblok API integration with input validation rules
That let the content team build and update pages without pulling in an engineer.
A/B Testing Infrastructure
Marketing wanted to experiment with different copy angles, video variations, and offers, but every variant meant an engineer hand-building it, so the experiments just never happened.
So I built configurable test components wired into Google Optimize:
- Quarterly collaboration with marketing on test design
- 2-week test cycles
- Test types: copy (health vs. training messaging), video (male vs. female athletes), images (action shots vs. stills), offers (control vs. discount variants)
Mentorship
I paired with Sam, a junior developer, on the gnarlier TypeScript tickets. I focused on teaching him how to break a component down and decompose a task, the same way my own mentors had taught me.
The Impact
| Metric | Before | After | Change |
|---|---|---|---|
| First Contentful Paint (Mobile) | 8-12s | 1.8-2.5s | ~80% faster |
| Largest Contentful Paint | 15-20s | 5-8s | ~63% faster |
| Total Blocking Time | 3-4s | 0.8-1.3s | ~70% reduction |
| Cumulative Layout Shift | 3-6s | 0.6-1.25s | ~79% improvement |
| Lighthouse Score | 32-43 | ~80 | +40 points |
| Bundle Size | 650-800 KB | 250-300 KB | ~62% reduction |
| Mobile Bounce Rate | 60-75% | 37-45% | ~39% reduction |
Other impacts:
- Engineering requests from content team dropped from ~10/week to ~2/week (80% reduction)
- Sam promoted from Junior to Front-End Developer within one year
- 10+ CMS components documented and tested
Why I Left
I was furloughed in January 2023 during the post-pandemic correction. Connected fitness contracted hard, and Peloton's troubles around the same time tell the broader story. FightCamp had over-projected its growth, so when the market turned they cut headcount.
What I Learned
This role reinforced something I'd first seen at Winc: the highest-leverage engineering work usually isn't the most technically difficult; it's the work that takes friction off another team. The CMS migration wasn't glamorous, but it changed how fast marketing could move, and that's what mattered.
The performance work taught me something else: sometimes the biggest wins are sitting in plain sight, waiting for someone to bother looking. No one had run a Lighthouse audit, so I did, and it turned into the most impactful thing I shipped there.
Tech Stack
Vue.js, Nuxt.js, TypeScript, Storyblok CMS, Storybook, Jest, Google Optimize, Google Analytics, AWS S3, Lighthouse, Intersection Observer API, WebM/MP4 optimization
