Skip to main content
Back to Canvas
Project2026Product EngineerNext.jsFrontendData PipelineGame ToolsLocalization

Shipping a Shareable Risk of Rain 2 Item Browser

Offline-first Next.js helper that lets players browse 233 items, curate presets, and share them via URL-only links without a backend.

I wanted a faster way to build and share RoR2 loadouts without ending up with “half in a wiki tab, half in a Discord message you’ll never find.” So I built an offline-first browser for all 233 entries (items + equipment): dense grid, local presets, share-by-URL only, no backend. Dark/light + English/zh-CN so it works on desktop and mobile.

The grid is high density on purpose;browse by shape and color, not by reading. Rarity tinting does most of the work. Sticky filter bar, search on names + descriptions, multi-select rarity chips. Hover = quick info, double-click (or tap on mobile) = details; on touch I use a bottom sheet because hover is useless there. Presets live in a persistent bottom dock so you’re always one action from save or clear; on desktop you can drag items in/out. Preset panel lets you rename, load, delete, share; more “editing a playlist” than “managing files.”

The main grid and filter bar

Sharing

Sharing was the constraint I cared about: no backend, so a preset is just a URL. First ID in share=..., the rest as empty query keys so the link survives chat apps mangling the query string. Opening a share link doesn’t overwrite your current selection: it opens a preview of what the app can resolve (and what it can’t, if the dataset changed or the link is junk). You choose to import into local presets. After that we strip share from the URL and dedupe IDs so refresh doesn’t re-run the flow.

Fast hover details for quick verification

Saved presets list with load/share actions

Previewing a shared preset before importing

Locale, data & stack

Locale: ?lang= when present, else browser language, URL kept in sync. Share links don’t lock language so you’re not forcing your locale on whoever you send it to. zh-CN copy lives in /public/data/items.zh-CN.overrides.json, merged at runtime with cache: "no-store" so I can fix copy without rebuilding. Theme via next-themes; hover stuff is behind pointer: fine so touch doesn’t get broken hints.

Data comes from the wiki. npm run fetch-items pulls the Lua modules, runs them with fengari, normalizes into one dataset;strips color tags and stack templates, stabilizes IDs (internalName where possible, eq: prefix for equipment), drops empty descriptions. Icons from category crawls + MediaWiki search fallbacks; pipeline writes items-assets.json and items.json. Runs at Vercel build time so we stay in sync with the wiki.

Tech: Next.js App Router, home wrapped in <Suspense> so useSearchParams CSR doesn’t leak. DnD is @dnd-kit/core with an overlay, dialogs/sheets/tooltips are Radix, presets = small localStorage helper. Rarity colors and glow are centralized so the grid, dock, and drag overlay don’t feel like separate widgets.

Net result: most actions are a couple of clicks, everything lives in the bundle + localStorage, and you can share a loadout without an account. If I extend it, I’d add optional link shortening, better handling for modded items, and a “copy as text” export for pasting into guides or Discord.