A mobile-first PWA for Marvel Strike Force players to build, manage, and share counter strategies for Alliance War and Cosmic Crucible.
Built solo in ~6 weeks. React, Supabase, 93 tests. A UX designer with a compiler.
I play Marvel Strike Force competitively and there was no decent tool for tracking counter strategies. The existing spreadsheets were slow, ugly, and completely unusable on mobile. I wanted something that felt like a real product.
TL;DR
Marvel Strike Force is a mobile RPG where the endgame is Alliance War — coordinated PvP where you pick attacking teams to counter defending teams your opponent placed. The meta is deep. A well-chosen counter can beat a team worth twice your power level. A bad one wastes resources and costs you the war.
Every serious player tracks counters. Most do it in spreadsheets. The problem: spreadsheets don’t travel well on mobile. You can’t search by character. You can’t attach a YouTube video of the actual fight. You can’t share a clean link with your alliance. They’re also deeply unsexy for something you’re supposed to care about.
I’d been using one for a year. I wanted to build something better.
The core of MSF Counter Craft is a counter list builder. You create a list, add defending teams — the teams you need to beat — and attach counter teams to each one, with the punch-up percentage, a strategy note, and optionally a YouTube link to a recorded fight. Lists can be public or private. Public lists show up in a discovery feed. Every list gets a shareable URL that doesn’t change even if you rename the list later. You can also embed any public list with an iframe.
On top of that: a full character database. 380+ playable MSF characters with portraits, stats at Level 110 Gear Tier 21, and full ability descriptions. The data syncs weekly from Scopely’s API via a GitHub Actions pipeline — no manual updates needed.
Mobile-first, not mobile-adapted. Most web tools for MSF were clearly designed on desktop and then squeezed into mobile. I designed for thumb reach first. The character picker, the dialogs, the team cards — all designed for one-handed use on a 390px screen, 44px touch targets throughout.
Expandable team cards. Defending teams collapse to a header by default. Expanding reveals all counters with their stats. This lets you scan many teams quickly without losing context.
Predefined team quick-select. Typing five character names every time you add a team is tedious. I built a searchable team picker with 75 community-recognized teams, each shown with overlapping avatar strips. Select a team, all five slots populate.
Frozen share URLs. You can rename a list any time. The share URL doesn’t change. This matters because alliance members bookmark links. If the URL regenerated on every rename, those bookmarks would break silently.
Embed support. Some alliances run Discord servers with linked web dashboards. The embed feature — a copy-paste iframe snippet — lets list owners drop their counter data anywhere without giving away their Supabase credentials.
I’m a UX designer. I know what good software feels like from the outside. I know how to structure information, design interactions, and think through edge cases. I do not have years of experience writing React hooks or designing PostgreSQL schemas.
Claude Code changed that equation.
My workflow was consistent throughout: I designed the feature — what it should do, how it should behave, where the edge cases were. Claude Code figured out the implementation. We iterated, with me reviewing every change, testing in the browser, and pushing back when something felt wrong.
This wasn’t “AI wrote my app.” It was closer to having a senior developer on call who never got frustrated with my questions. I still made every product decision. I still caught the UX bugs. I still wrote the requirements. Claude Code wrote the TypeScript.
What surprised me: I got genuinely better at reading code over the course of this project. Not writing it from scratch, but reading it well enough to have opinions about structure and tradeoffs. That felt like a real skill gain, not a shortcut.
The testing discipline came from the same collaboration. 93 tests. Every major feature has coverage. I learned to think about what to test through the process of writing requirements for tests.
React 18 + TypeScript — React because it’s the default for component-heavy UIs. TypeScript because catching type errors before runtime is the difference between confidence and anxiety when you’re not a professional developer.
TanStack Query — Server state management without writing cache invalidation logic by hand. Mutations, loading states, and background refetching handled cleanly.
Supabase — PostgreSQL with a solid free tier, built-in Email OTP auth (no passwords to manage), and an API that doesn’t require me to write a backend. The data model is clean: lists → defending_teams → counters, all relational with proper foreign keys.
Tailwind CSS + shadcn/ui — Utility-first CSS meant I could design in the browser without maintaining a separate design file for every component. shadcn/ui gave me accessible, customizable primitives that matched the visual language I already had in my head.
Vite — Fast builds. That’s the whole reason.
Vercel — Same platform as this portfolio. One dashboard, one deploy pipeline, zero infrastructure decisions.
Either way, let's start with a short meeting so you get to know me even better and I you.
Let's start with "Hello there!"