Inspiration

I've spent years running modded Minecraft servers for my friends, and every new pack started the same way: an hour of picking mods, then an evening of crashes. The mods were never the hard part. The hard part was everything around them. Which loader are we on, Fabric, Forge, Quilt, or NeoForge? Does this mod support our exact game version? Which library mods does it quietly depend on? Will these two even launch together?

One wrong pick and the game dies on startup with a log that means nothing to most players. My friends who were new to mods usually gave up before they ever got in game. I wanted a tool where you pick the mods you love and it makes them work together. That's Full Hearts: you pick, it resolves, verifies, and hands you one file you import and launch.

What it does

  • Adds every dependency. A missing library mod is the most common startup crash. Full Hearts follows each mod's full dependency chain and pulls in what it needs, resolved for your loader and version.
  • Checks compatibility for real. Every mod gets resolved to a concrete build for your loader and version. Anything with no matching file gets dropped. A known-bad list catches combinations that crash even when their public metadata says they're fine.
  • Matches server to client. It builds a server mod set from the same loadout you play on, at the same versions, and leaves client-only mods off the server. No more version mismatch on join.
  • Migrates packs. Point a loadout at a different Minecraft version or loader and it re-resolves every mod, then tells you what couldn't come along.
  • Exports one .mrpack. It imports straight into the Modrinth App, Prism, or ATLauncher.
  • Helps beginners. An optional quiz builds a starter pack from how you like to play. There's also a beta "describe your dream game" assistant. No account is needed, and everything stays in your browser.

How I built it

Full Hearts is a Next.js (App Router) + TypeScript app. I kept the frontend and a serverless API proxy in one project. The architecture follows a few strict rules:

  • One module touches the network. The API route (app/api/mods) is the only place that does network I/O. It proxies and caches requests to Modrinth, and also to CurseForge when an API key is present. Without a key, it falls back to Modrinth only, so development was never blocked.
  • Source adapters normalize Modrinth and CurseForge JSON into a single Mod shape, so the rest of the app never cares where data came from.
  • A hand-curated catalog. Mods the quiz can suggest are reviewed and tagged by hand, with a reason template explaining why each one earns its spot. The proxy enriches those entries with volatile live fields like versions, files, and downloads.
  • A pure, unit-tested scoring engine (lib/recommend). It has no I/O and no React. Quiz answers become a preference profile $\mathbf{p}$ over tags, and each candidate mod $m$ is ranked with deterministic weighted tag scoring:

$$ \text{score}(m) = \sum_{t \in T} w_t \, p_t \, \mathbb{1}[\,t \in \text{tags}(m)\,] $$

Because the score is just a sum of matched tags, every recommendation comes with a human-readable reason.

  • Dependency resolution as graph closure. For a selected set $S$, a loader $\ell$, and a version $v$, the final pack is the transitive closure of required dependencies:

$$ \text{Pack}(S) = \bigcup_{k \ge 0} D_{\ell,v}^{\,k}(S) $$

Here $D_{\ell,v}$ maps each mod to the required dependencies of its matching build. Mods with no build for $(\ell, v)$, or that appear on the known-bad list, get dropped and reported.

  • Storage with no backend state. Collections live in localStorage, and sharing works by encoding a collection into the URL hash.
  • Testing with Vitest, especially for the scoring engine and resolver.

Challenges I ran into

  • Metadata lies. A mod can claim support for a loader and version and still crash on launch. Trusting the API wasn't enough, so I built the known-bad list to block combinations I'd confirmed break.
  • Client vs. server sides. Getting a server set that exactly matches the client, minus client-only mods like shaders and minimaps, meant carefully tracking each mod's side requirements across sources that describe them differently.
  • Explainability vs. "smart." I considered ML and vector similarity for recommendations, but those are hard to explain and hard to
Share this project:

Updates