Runefall
A web-store for a Hytale server.
Introduction
Runefall was a production webstore and website for a Hytale game server that a friend and I launched shortly after the game's early-access release on January 13th, 2026. I was the sole developer on the project, responsible for the full web platform, from research and UX/UI design through implementation, payments, database architecture, and integration with the game server, as well as the custom server plugin that connected the two systems. I also handled deployment and maintained the platform after launch.
The idea grew out of years spent in the Minecraft server community, hosting and moderating. When Hytale was announced, we knew we wanted to bring something to the community as soon as it released. Runefall was that something: a store where players could support the server and unlock in-game cosmetics, ranks, and items.
Design
When starting a new project, I like to research what's already working. I took a lot of inspiration from the official Hytale website to resonate better with the playerbase.
This was the first design my friend and I came up with, and due to the time constraint, we decided to commit to it fully and see how far we could take it. The following screenshots show the entire website.
For the implementation, I used Shadcn as a component library, which I modified extensively to fit the fantasy branding. I also relied heavily on motion.dev (formerly Framer Motion) to bring the interface to life.
Since Motion was new to me, one of my goals was to learn how to use animation to reinforce the interface rather than distract from it. I used it across almost every page, including page transitions, component interactions, and visual feedback, but deliberately restrained the amount added so it wouldn't feel obnoxious or hurt performance. It was my first time using the library, but I'm happy with how it balanced the fantasy aesthetic against usability.
Technology
For this project I relied on Next.js. I've used the framework for a while, and it let me get a first working version up quickly.
PostgreSQL, hosted on Neon, served as the central source of truth for users, purchases, subscriptions, and pending rewards. Prisma provided a type-safe database layer and made it easier to model the relationships between users, products, and transactions.
For payments, I used Stripe, my first time integrating it, and a genuinely great learning experience. Payment infrastructure had always intimidated me, but building this gave me a lot more confidence as a web developer. The flow looks like this:
Rather than trusting the client-side checkout result, all fulfillment is driven off Stripe's webhook events. This keeps a malicious or interrupted client from being able to fake a successful purchase.
For authentication, since Runefall's audience was primarily gamers, I prioritized Discord OAuth as a familiar, low-friction login method, alongside Google OAuth and passwordless email login (a magic link sent to the user's inbox that logs them in on click). For transactional and login emails, I used Resend with nodemailer.
Technical Challenges
The part of this project that gave me the biggest challenge was granting rewards in-game to the player who purchased them. The webstore and the game server were two independent systems, and a purchase could happen while the player was offline.
Rank subscriptions. When a user buys a rank, checkout runs in Stripe's subscription mode (with prorated upgrades between ranks). On checkout.session.completed, a Subscription row is created and synced to the player's LuckPerms group on the game server. Later Stripe events keep this in sync: a failed invoice removes the group and marks the subscription past-due, a successful renewal re-adds it, switching ranks swaps groups, and cancellation removes the row and the group.
Crate keys (one-time items). These were single-use "Keys" that opened "Crates" containing cosmetics. The original problem was that if a player wasn't online at the moment of purchase, the game server had no player to grant the item to. I solved this by building a dedicated server plugin that could queue and grant rewards regardless of whether the player was online. A pending-reward row is written to the database before the grant command is sent to the game server (via a Pterodactyl-hosted console command), so if anything crashes mid-delivery, the reward is retryable rather than silently lost. Failed deliveries (server offline, rate-limited, etc.) back off and retry automatically, with a scheduled job periodically retrying anything still due.
A further complication: if a player had never joined the server before purchasing, we had no UUID to associate the reward with. To handle this, the system temporarily stored their username as a fallback identifier. The next time they logged in, the plugin resolved their UUID and migrated any pending rewards to it, which became the canonical identifier for all future deliveries.
What I'd improve. Looking back, the reward system is solid for the common cases: duplicate webhook deliveries and repeated cron runs can't double-grant crate keys, thanks to database uniqueness constraints and checking for existing records before granting. But a few edge cases would need hardening for a larger-scale version. LuckPerms rank grants and removals aren't retried if that call fails, which could leave a paying user without their rank (or, on cancellation, with a rank that never gets removed) until manually caught. I'd also make webhook handling explicitly idempotent at the database level rather than relying on unique-constraint errors, and add a "processing" state to prevent two overlapping retry jobs from ever sending the same command twice. None of these caused issues during Runefall's runtime, but they're the kind of gaps I'd want to close before running something at real scale.
Deployment
The Next.js application was deployed on Railway, which redeployed automatically on every merge to main. PostgreSQL was hosted on Neon. I managed environment variables and secrets, DNS, and SSL myself, and handled all post-launch maintenance and monitoring.
Outcome
The server was online for about a month. In that time, roughly 40 users registered on the website, and we saw a peak of around 70 concurrent players in-game. The store processed 30 payments from 15 unique customers (7 of whom bought more than once), for €378.67 in gross revenue, or €357.34 after fees. Against total monthly costs of €302 (the bulk of it server hosting), that left a net profit of around €54.
Player counts dwindled through the month. Initially we assumed this reflected on the server itself, but after talking to other server owners, we found the same drop-off was happening broadly: Hytale's early-access release simply didn't yet have enough content to hold a large player base long-term. At the end of January, we decided to shut the server down, with a short sunset period for the remaining players.
Conclusion
We didn't get rich, and the server didn't run for long, but I built and operated a real production application: real users, real payments, real infrastructure, and a real decision to shut it down when the numbers said to. Working under a tight deadline, with paying customers and direct feedback, taught me more about building software for a business than any tutorial or school project had. I'm glad I got to experience it end to end.