3D PhysicsMobile-First DesignReact Three FiberRapier3D

Solo vibe coding a 600 MAU webapp

A design-engineer case study on solving physical space constraints at game nights to grow a mobile-first rolling utility from a local board game club to 600 MAU.

Role

Creator (Solo Design & Engineering)

Timeline

3 Days

Team

Solo

User Experience

Observational study was my primary user research tool, observing and interviewing approximately 60 players across multiple session environments and game systems like Dungeons & Dragons and Pathfinder. This research revealed a chronological series of physical and social constraints.

The Setup Space — Typical face-to-face game tables are heavily crowded with reference books, sheets, miniatures, and snacks.

Phase 1: The Messy Table. Face-to-face board game nights are intensely tactile but highly cluttered. Dining tables are packed flat with character sheets, pencils, rulebooks, miniatures, snack bowls, and drinks. Rolling physical dice in this space was constant chaos—dice routinely knocked over fragile miniature setups, fell off table edges, or landed in beverage cups.

The Laptop Barrier — Attempting to run digital dice and sheet utilities on laptops consumes valuable physical space and isolates players.

Phase 2: The Failed Laptop Workaround. To mitigate physical space issues, some players attempted to use laptops to manage character sheets and roll digital dice. However, this introduced a severe secondary pain point. Laptop screens created a literal social barrier, blocking line-of-sight between players and the Game Master. Additionally, open laptops consumed massive table footprints, leaving zero space for players to reach physical boards or components.

Phase 3: The Mobile-First Opportunity. This sequence of observations highlighted that the solution had to be a mobile web utility that players could lay flat on the table or hold in one hand. It needed to offer a zero-install experience with controls positioned entirely within the thumb-reach zone to prevent players from having to hold the phone with two hands or shift focus away from the game.

Playtesting & Interview Insights

Conducting interviews and playtest observations with 60 users revealed several key issues (highlighted in red below) that shifted our product and interface design:

25%
Tablet Focus

Space constraints were real. While mobile was the primary target, 25% of observed users reported also wanting to use their tablets flat on the table alongside character sheets rather than phones.

85%
DM Stalls

Slow reporting stalled gameplay. 85% of Dungeon Masters reported that players slowly adding up modifiers and reading physical dice stalled game pacing, and they recommended tools prioritizing speed.

55%
Math Friction

Bookkeeping was a massive bottleneck. 55% of players struggled with calculating modifier math quickly on the fly or keeping track of their roll history during complex encounters.

How Insights Informed the Design

Rather than building a standard desktop-oriented web layout, the playtesting insights directly shaped the physical ergonomics of the app:

  • Flat/Propped Table Ergonomics: Because 25% of users wanted to roll from tablets and many others kept their phones resting flat on the table, the interface was designed to be operated flat. Font sizes are scaled, and buttons have massive hit areas so players can operate the app from an angle without picking the device up.
  • One-Hand Thumb Reach Zone: The primary rolling controls and tray pickers are clustered at the bottom of the viewport, ensuring players can keep one hand free to hold food, cards, or reference sheets.
Thumb Reachability — Green zone highlights easy-reach thumb interactions.
User Interface Compliance — All primary rolling controls and tray pickers are anchored in the easy-reach zone.

User Interface

Procreate Inspiration: Canvas Minimalism & Tactile Gestures

To make the interface feel less like a clinical configuration form and more like a tactile, high-response instrument, I drew significant inspiration from Procreate's interaction model. Procreate successfully handles complex artistic tools on mobile devices by keeping the drawing canvas entirely clear, utilizing fluid gesture-driven overlays and slide-in panels that respect user focus and state context.

  • Zero-Friction Clear Gesture: Borrowing Procreate's iconic two-finger tap to undo, a quick double-tap anywhere on the 3D rolling canvas instantly clears all active dice and resets the board.
  • Tactile Flick-to-Roll: Instead of relying strictly on tapping a static "Roll" button, players can flick/swipe their finger directly across the 3D canvas or shake their phone (utilizing browser-native Accelerometer APIs) to toss the dice. The swipe gesture's drag direction and velocity map directly to the initial physical forces and torque applied to the 3D bodies.
  • Radial Settings Context Menu: Long-pressing a die in the tray picker invokes a radial touch dial, allowing players to customize materials, colors, or tweak quantity modifiers in a single continuous touch-drag-release sequence without leaving the canvas.

Stable Layout Principle: Zero Runtime Reflow

To eliminate cognitive friction during fast-paced play, I established a strict design rule: the application chrome must not reflow when state changes. When rolling, selected dice counts change, or errors occur, elements must not push other layout components around.

  • Persistent Control Targets: Clear/remove buttons and counts are always mounted in the DOM. When they are inactive or zero, they use CSS invisible rather than conditional rendering, preserving their exact layout footprint.
  • Fixed Cast Cells: To handle mobile viewport sizing, dice selection cells use a strict --cast-cell-size (84px on mobile, 60px on desktop) instead of adapting dynamically to viewport width, avoiding squishing.
  • Tray Isolation: The interface control tray overlays the 3D viewport instead of resizing it, guaranteeing that Three.js does not trigger expensive camera updates or canvas resize layouts during gameplay.

Mobile Scrolling Rails

To fit D4, D6, D8, D10, D12, D20, and D100 picker options inside mobile viewports, the app features a horizontal TrayActionsRail.

Through iterative commits, I optimized the horizontal scroll snapping, introduced a floating dice rail design to improve discoverability, and added logic to disable scrolling indicators when the full stack fits in the viewport, ensuring clean visual cues.

Instant Dice Presets

To resolve playtest bookkeeping struggles (55% users struggling with manual math) and GM stalls, we implemented a dedicated Dice Presets Manager. Players can save complex formulas (e.g., D&D Wizard Fireball 8d6, Warhammer Attack 10d6, Pathfinder Initiative 1d20+5) to quickly jump between rolling contexts and games. This maintains steady pacing and automates calculations instantly.

Dice Presets — Dedicated slots for saving custom modifier formulas to speed up reporting.

Tablet Landscape Interface Layout

To accommodate the 25% of playtesters wanting to roll from tablets, we built a responsive wide-screen layout mode. In landscape orientation, the canvas is side-by-side with a persistent settings drawer. This creates a clean, split-screen desktop-like experience on iPad, displaying character statistics and math modifier histories concurrently with the active 3D tray.

Accessibility & Keyboard Support

Accessibility was built into the foundation rather than treated as a checklist item.

Roving Keyboard Focus: To support players using external keyboards, adaptive switches, or controllers, I implemented a custom roving focus system (useCastGridRovingFocus and RovingFocusList). Buttons and dice tiles are managed dynamically, allowing users to navigate through selection cards and roll trays using arrow keys, rather than tabs.

Text-Size Scaling: Low-light environments are common at board game nights. The settings panel includes a dedicated text sizing preference (Small, Large, Maximum) that scales interface labels globally, aiding legibility.

Screen Reader Announcements: The roll breakdown utilizes ARIA live regions (aria-live="polite") to instantly announce the final roll total and modifiers, allowing visually impaired players to participate seamlessly.

Performance Tuning & “No 3D Mode”

A key design-engineering constraint was managing battery consumption during extended sessions.

To address this, I implemented a dedicated No 3D Mode bypass. Enabling this option disables the WebGL renderer and Rapier3D physics entirely. Roll calculations are completed instantly in JavaScript and displayed via simple, styled text cards.

When 3D is active, the app supports Graphics Quality Tiers (Low, Medium, High). Low-quality mode reduces shadow resolutions, disables anti-aliasing, and caps the physics engine step rate, ensuring older devices can roll without overheating.

Additionally, local session state is cached in IndexedDB (via idb-keyval) alongside a local session service to allow offline PWA support, ensuring rolls are stored and functional even during poor cellular coverage in game rooms.

Tech Stack

The project utilizes a high-performance React frontend coupled with WebGL physics and a serverless Supabase backend:

Frontend Architecture
React 19 · TypeScript · Vite · Tailwind v4

Modern React stack utilizing Tailwind CSS v4's compiler for styling. Roving focus and accessibility are built using Radix UI primitives.

3D Physics Simulation
React Three Fiber · Rapier3D · WASM

WebGL rendering driven by Three.js. Realistic rigid-body physics collisions are calculated via a Rapier3D WebAssembly instance, copied during post-installation.

State Management
Zustand · idb-keyval

Zustand handles global dice tray counts, modifiers, roll results, and settings. IndexedDB handles local session backups to guarantee offline support.

Monetization & Backend
Supabase · Vercel · Stripe API

Supabase Postgres database handles user accounts, purchases, and settings sync. Vercel Serverless Functions process Stripe payment webhooks for custom dice skins.

Desktop Layout — Wide viewport showcasing settings panel, graphics toggles, and roll histories

Product Decisions

Product success depended on key decisions around distribution, monetization, and organic viral growth.

Distribution: PWA Webapp Over Native Stores

To maximize adoption in a social, physical game setting, I opted to build a Progressive Web App (PWA) distributed directly via the web rather than native iOS or Android app stores. During a game night, the loop and friction of navigating to an app store, authenticating, and downloading a native app acts as a massive barrier to spontaneous adoption.

By offering a lightweight, zero-install mobile website that players can run instantly with a URL or QR code, the tool fits seamlessly into the game setup. Making it a PWA allows players to optionally "Add to Home Screen" to run it in a clean, borderless window. Since other tabletop utilities (like character managers or rule lookups) are web-based, web distribution aligns with the players' existing digital habits.

Monetization: Micro-SKUs & Donations over Ads

When evaluating monetization, I rejected banner/interstitial ads entirely. Ads disrupt the flow and immersion of tabletop gaming sessions, leading to a cheap, annoying user experience that drives players away.

Instead, I observed that players who enjoyed the utility were highly willing to support the project via voluntary donations (Ko-fi tips of $5 or $10). Because the donation conversion rate was healthy, it supported a clean, ad-free experience.

To complement donations, I introduced super micro-SKUs: 49-cent cosmetic custom dice skins (Royale Purple, Lava Swirl, Malachite, etc.). Because it was extremely low effort for me to model and render new skins in Blender, this cosmetic personalization model allowed high-margin, low-complexity monetization without introducing user friction.

Growth Loops: Organic Posts, Game Clubs, & GM Champions

Growth was completely organic and hyper-focused. Rather than investing in paid advertisements, users were acquired through targeted organic posts in board gaming and roleplaying subreddits and Discord channels.

To bridge the physical-to-digital gap, I distributed physical cards with printed QR codes in local games clubs and cafes. Players could scan the code and roll immediately without leaving their seats.

Additionally, by targeting Game Masters (GMs) and convincing them to recommend the app to their tables—often because it solved the slow reporting and math stalling issues—we established a natural word-of-mouth referral network. GMs acted as micro-influencers, introducing the tool to 4 to 6 new players per campaign.