Inspiration
I drew a lot of inspiration from Shop Titans: the crafting queued, customers you can haggle with, and staff and furniture tiers that compete for the same gold. The serve options (sell, undercharge, overcharge, refuse) come straight out of that idea that a sale is a decision, not a button. Where this diverges is the room itself. Shop Titans sells from a counter, and Tavern Tycoon makes you serve them, seat them, and clean up after them, so the floor is as much of a constraint as the workbench.
A tavern is also one of the few businesses where you can see the whole economy at once: someone brews it, someone serves it, someone consumes it, and finally someone cleans it. Each step handled by a different NPC: Brewer and Cook, Barkeep, Guest, and Barmaid.
Each sale improves the tavern, and each level unlocks something new. Will you usher in the golden days of the tavern?
What it does
Tavern Tycoon is a hybrid real-time and idle tavern management game, single player, portrait only, that opens from a folder on disk with no server and no network.
| System | What the player does |
|---|---|
| Crafting | Queue drinks at the still and food at the stove. One shared line, one bench per crafter, so a pie never waits behind three ales |
| Serving | Guests queue at the bar with an order bubble and a patience ring. Tap to serve, undercharge, overcharge, or refuse |
| The bar | Buy a longer counter and a second queue, and a barkeeper who catches a guest whose patience runs out: fair price to them, half the coin to you |
| Seating | The Barmaid seats guests and clears dirty seats. Her upgrade ladder sells speed, not extra staff |
| Economy | Gold, tips, happiness, an ingredient larder that can run dry, a quest board, and a Store |
| Growth | 20 player levels, four table tiers, crafter tiers, room expansions, each gated by level and paid for in gold. A carpenter calls once, at Level 6, to sell the first room, because a bay is the one purchase with no object standing in the room to tap |
| Session | A day clock with open and close, a day summary, Next Day and Start Over |
| Presentation | Generated music and sound effects from oscillators, no audio files anywhere, and a settings panel that switches either of them off |
How we built it
Built with Claude Code as the implementing hand and a human designer overruling it regularly. The rules that shaped it were set on day one, before any gameplay code, because all three are cheaper to enforce than to retrofit:
- Three.js r0.185.1, pinned exactly, copied into
vendor/. No CDN. The shipped build makes three requests, all local, zero external. - A build step from the first commit. Source lives in
src/as 57 ordinary ES modules, about 20,500 lines.npm run buildflattens them into one readable, unminified<script>block insideindex.html. Libraries are never inlined. - Portrait is a constant, not a reaction.
camera.aspectis hardcoded to $9/16$ and never recomputed from the window. A landscape window letterboxes a portrait game instead of reflowing it, which is a stronger guarantee thanscreen.orientation.lock().
Two things carried the project further than the code did.
A headless check harness. 50 suites, 2,834 individual checks, each suite in its own process so a ReferenceError in one cannot take the run down. They run behind a loader that swaps Three.js's WebGLRenderer for a shim counting draw calls, so the whole game can be booted, played and asserted on with no GPU. Several suites build a complete tavern and drive it through a day.
Simulation tools instead of opinions. throughput.mjs plays a perfect barkeeper across every room the game can be bought into, to find the point where another seat buys nothing. It found something we did not want to hear. Arrivals were a flat one every 7 seconds, so the tavern had a hard ceiling of
$$\lambda_{\max}=\tfrac{60}{7}\approx 8.57\ \text{guests/minute}$$
and the model reached 8.50 of it with one table and one Barmaid. Every bay, table tier and room bought after that was decoration: growth you could see and could not feel. So the door was rewritten to answer to the room instead,
$$t_{\text{gap}}=\operatorname{clamp}!\left(7\sqrt{\tfrac{2}{s_{\text{free}}}}\left(1+\tfrac{3}{2}\max!\left(0,\,1-\tfrac{n}{4}\right)\right),\ 2.5,\ 18\right)$$
where $s_{\text{free}}$ is free seats and $n$ is what is on the shelf: 7 seconds in the room the tutorial builds, 2.5 in a full tavern, and 17.5 with nothing to sell, which is the game handing a sold-out player time to brew. That is a question you cannot answer by feel.
The economy is written as formulae rather than tuned by nudging. A guest's happiness on being served is
$$H=\mathrm{clamp}!\left(50+p+5\,(t-1)-15\,m,\;0,\;100\right)$$
where $p\in{+10,0,-10}$ is promptness in three legible bands, $t$ is table tier, and $m$ counts dirty seats at the table. The tipping line is 50, and the chance a guest tips is the number:
$$P(\text{tip})=\begin{cases}H/100 & H\ge 50\[2pt] 0 & H<50\end{cases}\qquad \text{amount}=\operatorname{round}!\big(\text{price}\times r\times(0.5+\tfrac{H_{\text{tavern}}}{100})\big)$$
Always the list price, never the charged price, so undercharging cannot quietly cancel the goodwill it was bought with.
Every judgement call, deviation and playtest change went into buildlog.md: 126 entries across 11 days, with the reasoning and not just the outcome.
Challenges we ran into
The crafting bar was rearranged three times. A queue per crafter wanted a row of slots per crafter, which is far too much bar for one thumb. Collapsing to one queue and one bench fixed the bar and broke the kitchen: a pie behind three ales waited on a Cook standing idle. The answer was to share the line and split the hands, which meant startNext had to scan rather than shift. The front of the line is not necessarily startable, and anything skipped keeps its place, so each crafter is still strictly first in, first out.
Shrinking the room cost more than it saved. Narrowing the tavern to fit portrait broke the walking lane, both staff walks, and the entire station tier ladder. Which walls may be full height turned out to be a theorem about camera framing, not a matter of taste.
Smaller ones that each cost an evening: the HUD silently eating taps, tap and drag sharing one gesture, THREE.Clock being deprecated in r185, and a batch of unlock chimes firing under a single tap because tables are bought through a different path than everything else.
Accomplishments that we're proud of
- It is genuinely offline. One folder, opened from disk, three local requests, no network calls, no audio files, no fonts, no CDN.
- 2,834 assertions on a 3D game with no GPU in the loop, including full days played end to end in a headless process.
- The balance is derived rather than guessed. The Barmaid's clean time exists to satisfy $t_{\text{clean}} < \bar t_{\text{craft}} \approx 7\,\text{s}$, and her whole upgrade ladder, 5.0s down to 2.4s, is priced deliberately above the tables at the same levels. More seats and a slower Barmaid is this game's oldest failure mode, and a player forced to choose between them is a player who has met it.
- Day 1 is a tutorial with a voice, rewritten end to end after playtests, with the sequence living in unlock data so skipping it does not break the game's order.
- The log. 126 entries in which the reasoning survives, including the decisions that were later overturned and why the argument expired.
What we learned
- Set the awkward constraints on day one. The build step, the local vendor copy and the fixed portrait aspect all went in before a single game object existed. Every one of them would have been a rewrite later.
- A check that cannot fail is worse than no check, because it reports success. Assert against something that changes, and occasionally break the code on purpose to watch the suite notice.
- Put ordering in data, not in scripts. Prerequisites in the unlock table survive a skipped tutorial. A tutorial that teaches an order the data does not enforce teaches nothing.
- Simulate the balance question. Ten minutes writing
throughput.mjsreplaced an argument nobody could win. - Sound design is mostly subtraction. Guests arrive constantly, so the door had to go quiet. What a player needs to hear is what they did.
- Check the bytes. Line endings, coordinate frames and pixel units are the three places where a confident answer is most often about the wrong thing.
What's next for Tavern Tycoon
| Next | Why it is next |
|---|---|
| Furniture placed by hand | The tavern still grows in a fixed order because a table cannot be moved once it stands. Being able to drag one is what frees the shape |
| The Entertainer | Parked with a happiness multiplier already written into the model, waiting on animation, a stage, and a tuning pass against the tips it would move |
| More crafters | The crafting code is keyed by role, not hardcoded to a pair, so a third bench is content rather than a rewrite |
| More Barmaids | The crew code and three stations are still there. One Barmaid was a design decision, not a limitation |
| Coverage where the harness is blind | Drag highlights, dust motes, the wipe animations and every sound are things a headless suite cannot see or hear |
| A balance pass on the two top rungs | The Barmaid at 2.4 seconds and the barkeeper catching at 30% of a ring are both arithmetic rather than a measured session |
| A deeper quest pool | The pool is already larger than the board can show, which is the good problem to have |
| A second floor Inn | Plan to add a second story to the tavern where the player can clean and fix up run down rooms and rent out to guests. Players will be able to upgrade them to improve value and increase gold sales and guest happiness. |


Log in or sign up for Devpost to join the conversation.