Commit Graph
14 Commits
Author SHA1 Message Date
jcoffey-dev f387e26acf Point the repository URLs at their new owner
These moved from the Coffey-Labs org to jcoffey-dev, where they belong.
GitHub redirects a transferred repository, so nothing was broken by
leaving them -- but a source link that lands via a redirect is still
naming an owner that no longer holds the code, and the redirect only
lasts as long as nobody creates a repository of the same name in the
old place.

Only the seven repositories that actually moved are rewritten. Every
other Coffey-Labs URL is left alone: ihasmail, cairnobs and the rest
are still there.
2026-09-10 09:34:04 -07:00
Coffey Labs b71e1f6292 Merge pull request #2 from Coffey-Labs/back-to-the-arcade-and-seo
A way back out, and the tags a crawler reads
2026-09-08 22:52:31 -07:00
jcoffey-dev ad6860448a A way back out, and the tags a crawler reads
The same two gaps the wumpus had, closed the same way, because they are the
same site.

The way back sits leftmost in the footer, next to SOURCE, and the arrow is a
pseudo-element so it can be the right arrow for the skin: a chevron on the
remaster, and the two ASCII characters the Atari's character set actually had
on the 1979 one. Absolute rather than "/", because this game is served from a
subdirectory in production and from the root in development -- the relative
answer is right in one of those and points at the game itself in the other.

The head gains canonical, Open Graph, Twitter and robots, plus VideoGame and
BreadcrumbList structured data. Canonical is not boilerplate here: the
container falls back to index.html for anything under /lemonade/, so without it
/lemonade/anything-at-all is a separate indexable page with the same content.

The preview image is served by the site rather than added here. Every pixel of
this game is SVG drawn in code and there are no artwork files; a social card is
not part of the game, and it belongs with the deployment.

A noscript block describes the game and links onwards rather than leaving an
empty div for a reader without scripts.

Build clean.
2026-09-08 22:52:17 -07:00
Coffey Labs 06011e1368 Merge pull request #1 from Coffey-Labs/board-moves-out
Move the board out to the service every game shares
2026-09-08 22:34:08 -07:00
jcoffey-dev 931c2dc299 Move the board out to the service every game shares
The leaderboard started in this repository because when it was written there
was one game. It was already being treated as shared -- games.jcoffey.dev
calls it "the shared leaderboard" in its compose file and nginx proxies it at
a site-wide /api/ rather than under /lemonade/ -- but it was still this game's
code, and the second game would have meant a second container, a second volume
and a second database to back up for every game after that.

It lives in https://github.com/Coffey-Labs/games-scores now, which is its own
repository rather than either game's. A shared board belongs to no game, and
leaving it here would have made every future game depend on the lemonade stand
for its leaderboard.

What changes here is smaller than the diff suggests. server/ goes, and with it
scripts/dev-all.mjs and two package scripts. The client names the game on every
call and is otherwise untouched: rows still come back as assets, days, glasses
and broke, because the shared service hands each game its own field names back.

Nothing about the deployed board moves. The volume keeps its name, the rows are
migrated in place on first boot, and the original table is kept alongside as
scores_lemonade_v1 rather than dropped -- it is the only copy of a board real
people are on. Bundles already in browsers keep working too: a post with no
game at all is treated as this one, deliberately, until this build has been out
long enough that nobody is running the old one.

Build clean.
2026-09-08 22:33:51 -07:00
jcoffey-dev 87474ad5ec Say plainly that there is no player limit, and stop one classroom hitting it
The README heading read 'Two people, two browsers', which sounds like a
cap. It is not one: the server holds no game state at all, so any number
of people play independent games and the server only ever sees a
finished score. The only real cap is four to a game, and that is a
keyboard sharing the same stand rather than anything technical.

Checking that turned up a case where it would not have been true. A
classroom, an office or a household all arrive from one address, and the
submission limit of thirty an hour was low enough that a class finishing
together would have started losing scores to a 429. Raised to 120 and
verified with a burst of 130: the first 120 land, the rest are refused.
What actually keeps rubbish off the board is the plausibility check, not
this limit.
2026-09-08 17:58:40 -07:00
jcoffey-dev f2e084ef7a Split the site out, and offer the source the licence requires
The hub page and the games.jcoffey.dev deployment move to their own
private repository; this one keeps only the game, its leaderboard and a
generic compose that runs both anywhere. No deployment details remain
here, and no site references.

A SOURCE link now sits on every screen. AGPL section 13 entitles anyone
playing this over a network to the source of what they are playing, and
a link in the footer is how that offer gets made.
2026-09-08 17:34:51 -07:00
jcoffey-dev 6db47b338e Explain every condition, and write the whole script in our own voice
The instructions only ever covered the weather. They are now four pages:
what you decide, how signs and spoilage work, what the sky does, and
what the street does - the fair and the rival included, with each
condition named and what it does to your day spelled out.

Every passage that was reproduced from the original has been rewritten:
the welcome, the ledger heading, the thunderstorm, the road works, the
heat wave, the bankruptcy line and the cost announcements. A project
released under copyleft has no business licensing words it did not
write, and now it does not have to. NOTICE.md records what changed and
why, and narrows the borrowed material to the town's name and the
ledger's labels - neither of which is a copyright question.

Shortening the ledger heading also fixes the pill that was wrapping to
two lines in the remaster.

Checked in both skins: all four pages fit the tube at full size, with
room to spare.
2026-09-08 16:23:05 -07:00
jcoffey-dev 8a5d0cb6df Shared leaderboard, a games hub, AGPL, and two new street conditions
The high score table moves out of the browser and into a service, so
every player is on one board. It is a Node process with SQLite, no build
step and no native modules - node:sqlite ships with the runtime and Node
runs the TypeScript directly.

Everything in a request is treated as hostile: names forced to a
printable subset, every number range-checked, and scores refused if they
could not have happened in the days claimed. Bodies capped, submissions
rate limited per address. It still cannot prove a score is real, and
server/README.md says so plainly rather than implying otherwise.

The game degrades properly without it: the board says it cannot reach
town, posting happens behind the closing standings, and play is
untouched.

Deployment is three containers behind the host's nginx - the hub at /,
the game at /lemonade/, the scores service at /api/ - so the game keeps
its own container and a second game is just another service.

Licensing: AGPL-3.0-or-later, Affero because the leaderboard is a network
service. NOTICE.md credits Bob Jamison and Charlie Kellner, records that
this is clean-room work, and is honest about the one thing it is not:
some on-screen wording is quoted from the original and cannot be
licensed by us.

The street can now get better as well as worse. The summer fair brings
the town out and lifts what they will pay; a rival on the next corner
takes a share and lingers. Both show in the art and in the crowd. Over
500 seasons a player who reads the briefing survives every time and
finishes around $25.80; one who ignores it goes broke 70% of the time.
2026-09-08 16:17:47 -07:00
jcoffey-dev 7fcb863771 Remaster: cel-shaded skin, a crowd that tracks trade, and a funk band
Two skins over one game. 1979 is the machine as it was; the remaster is
the same rules in cel-shaded vector art with a modern palette. The
simulation is untouched - only the paint differs - and the toggle sits
under the set.

The street is now driven by the game. Before prices are in, the number
of people walking on comes from the forecast; afterwards it comes from
the glasses that actually sold, so the report shows the crowd you
earned. A heat wave has them fanning themselves; a downpour leaves one
figure hurrying past under an umbrella.

Selling no longer snaps straight to the books. The stand trades for a
few seconds first, tally climbing and till filling, which is where that
crowd animation pays off. Skippable.

The synth grew a kit (pitched-sine kick, snare with body, hats), a
sweeping resonant lowpass for the bass, chords and a shuffle - enough
for a funk band. The chiptunes stay for the 1979 skin.

Boot is now a cassette load, which doubles as the gesture browsers
require before audio will play.

Fixes found on the way: the picture scaled about its centre while flex
auto-margins collapsed to zero on overflow, which pushed the report's
buttons off the bottom; and the validation line moved the button when
it appeared, so it is now reserved and faded. Sibling tabs in one
browser also keep their score tables in step.
2026-09-08 15:59:52 -07:00
jcoffey-dev 175589223a Drop the high score wipe; scores leave only by being beaten
The table was clearable behind a confirm. It should not be: a stand
earns its place and loses it only to a better summer, so the control
and clearScores() are gone and the screen says so.
2026-09-08 15:32:31 -07:00
jcoffey-dev 71cbb02353 Add a persistent high score table
Retiring writes each player's closing balance to a top-ten table in
localStorage, reachable from the title screen and the standings, with
the summer just finished picked out in yellow.

Stored rows are user-editable, so every field is validated on load and
malformed entries are dropped. Storage being unavailable is a normal
case, not an error: the game plays on with an empty table.

Also stops the status line claiming DAY 00 on screens that have no day.
2026-09-08 15:29:35 -07:00
jcoffey-dev 08b2cc5391 Drop two helpers nothing calls 2026-09-08 15:24:01 -07:00
jcoffey-dev 5f8ad511f0 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.
2026-09-08 15:23:46 -07:00