Lemonade Stand: browser recreation of the Atari 8-bit BASIC game

Faithful day loop - weather report, cost of lemonade rising over the
summer, glasses/signs/price decisions, thunderstorms, heat waves and
street crews - with the $$ LEMONSVILLE DAILY FINANCIAL REPORT $$ laid
out the way it printed.

The simulation is kept out of React so a season can be run headlessly:
a careful player compounds $2.00 into roughly $22 over twelve days,
while an all-in player goes broke about seven times in ten.

Weather scenes are pixel rectangles in SVG and the music is a small
chiptune engine on the Web Audio API, so there are no binary assets.
The screen is locked to a 4:3 tube and never scrolls.
This commit is contained in:
2026-09-08 15:23:46 -07:00
commit 5f8ad511f0
32 changed files with 3913 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
# Lemonade Stand
A browser recreation of the Atari 8-bit BASIC classic — the one you typed in,
ran on a TV, and lost two dollars to on a cloudy day.
React + TypeScript + Vite. No art assets and no audio files: the weather is
drawn as pixel rectangles in SVG, and the music is generated by a small
chiptune engine built on the Web Audio API.
## Playing
```
npm install
npm run dev
```
One to four players share the keyboard, hot-seat style. Each morning you see
the weather, then decide three things: how many glasses to make, how many
15-cent signs to put up, and what to charge. Then the town votes with its
pocket money.
- Lemonade costs 2 cents a glass on days 12, 4 cents through day 7, and
5 cents after that.
- Everything you make is made *today*. Unsold glasses are poured away.
- A hot, dry day brings a bigger crowd that will pay more. A heat wave is
better still.
- A cloudy day can turn into a thunderstorm, and a thunderstorm ruins every
glass you made.
- Street crews close the road now and then, and they tend to stay for a
second day.
- Signs work, but with sharp diminishing returns — the fourth one barely
earns its 15 cents.
You are broke when you cannot afford a single glass. Otherwise the summer runs
as long as you like; **RETIRE** closes the books and shows the standings.
## How it is put together
```
src/
game/ pure simulation - no React, no DOM
constants.ts costs, weather profiles, the demand curve
engine.ts rolls each day and settles the takings
reducer.ts the day/turn state machine
rng.ts seeded mulberry32, so a run can be replayed
audio/
synth.ts pulse-wave voices, noise percussion, look-ahead sequencer
tunes.ts the title, trading and closing themes
components/ the screens, and the CRT they are drawn on
```
The simulation is deliberately kept out of React: `engine.ts` takes a player, a
decision and a day and hands back a `DayResult`. That is what makes it possible
to run a few hundred seasons in a script and check that a careful player grows
their two dollars while a reckless one goes broke about seven times in ten.
### The demand curve
The original BASIC listing is not reproduced line for line. `constants.ts`
holds a reconstruction tuned to behave the way the game plays: cheap lemonade
sells out, sales fall to nothing once the price stops being a bargain, heat
lifts both the crowd and the price people will tolerate, and signs help a lot
at first and hardly at all later.
### The television
An Atari 800 fed a 4:3 television, and a television has no scrollbar. The tube
is locked to 4:3 and everything inside it is sized in container units, so the
picture stays in proportion at any size. If a page ever did come out taller
than the tube, `Fit` scales it down rather than clipping or scrolling it.
## Sound
Audio starts on the first click or key press, as browsers require. Two pulse
voices, a triangle bass and filtered white noise for percussion, driven by a
scheduler that queues notes 200 ms ahead so the music does not stutter when
React re-renders. `MUSIC` and `SOUND` toggle independently.