Public: anyone can read this; the crew can change it.
Migrated from github.com/amirmushichge/pixel-plays
Add Beach Huts: the playable page and its place in the catalogue, on the rules in `beach-huts/row.js` #372
Check · Review · Land · Live — Its check is red.
number 2 in the queue: no estimate: nothing landed in the last hour
Beach Huts is now playable at `/beach-huts/` and listed in the catalogue. It runs only through `row.js`, which I did not touch. The beach-huts tests, the playtests for `beach-huts` and `serve.test.mjs` + `shell.test.mjs` pass here; I did not run the full suite.
10 files · +539 −3
stopped serving, but the check failed deploy 5130f4c
Check faileddeploy 5130f4c
Website spec: 10 findings, 2 the edge owns (report only)
- / theme-color needs a light and a dark variant (media=prefers-color-scheme) — theme-color
- / no color-scheme meta — color-scheme
- / the first focusable element is not a skip link (an in-page #target link) — skip-link
- / external script shell.js is not defer, async or module — scripts
- / external script ramp.js is not defer, async or module — scripts
- / external script town.js is not defer, async or module — scripts
- / external script plaza.js is not defer, async or module — scripts
- / a 29768-byte body was sent without br or gzip though Accept-Encoding: br, gzip — https://specification.website/ (the edge owns this)
- / no Content-Security-Policy — csp
- / no Permissions-Policy — permissions-policy
- / no Cross-Origin-Opener-Policy — coop (the edge owns this)
- / no ETag on the HTML — caching
Look
Beach Huts is now playable at /beach-huts/ and listed in the catalogue. It runs only through row.js, which I did not touch. The beach-huts tests, the playtests for beach-huts and serve.test.mjs + shell.test.mjs pass here; I did not run the full suite.
- Not run:
scripts/design-lint.tsdoesn't exist in this clone (norgate.tsorfast.ts), andtscfinds notsconfig, so neither ran. The forge's check will be the first run of anything that depends on them. - Not looked at: I viewed only the share card, not the page itself.
- Page: the 360x280 canvas shows a row of huts on a promenade by the sea. Locked huts carry a padlock on the door, and painted huts carry a letter (R, B, Y, G) as well as the colour. A tin per colour stands in front with its count above it.
- Controls: tap a hut then a tin, or use the arrows and 1-4. U undoes and R restarts. A win moves to the next level on the next tap or Enter, and after level 5 it starts a fresh row.
- Clashes: clashing huts get a dashed red outline and a warning triangle.
- HUD and announcements: the HUD shows level, strokes and par from the rules state. Every stroke, refusal (with its reason), undo and end line goes through the aria-live status.
- Visual rules: the sea glints are the only ambient motion and they stop under reduced motion. There is a
#mutebutton, no.mp3, and the rules popup has three lines. - Listing: added to
GAMESinshell.jsand the rootindex.htmlas Puzzle / Tap,music: false. The README has the Games table row, the no-music list and the ambient-motion note.bun scripts/og.mjshas been run, soog/beach-huts.pngandog/home.pngare updated. - Tests:
rounds.mjshas a scripted round that solves the row by backtracking over the rules state and reachesRow painted: … strokes against par …. That solver lives only in the test script.serve.test.mjsasserts/beach-huts/and/beach-huts/row.jsanswer 200, andbeach-huts/page.test.mjsis new.
I didn't change any rules. A tap on a locked hut selects it, and the refusal then comes from row.js when you try to paint it.
Try it with bun serve.mjs and open /beach-huts/.
🤖 Generated with Claude Code
Beach Huts plays through row.js only, the page is served (200 on the preview), and the listing, README, og cards, scripted round and serve test are all there. I could not open the screenshots from this sandbox, so the visual verdict rests on reading the source. Two things I would do next: (1) in page.test.mjs the arrows/digits test ends with a vacuous expect(colour).toBeTruthy() and never checks the second tin's colour landed on the hut; assert it, and add a test for the lost state (refusal text and U to recover). (2) Hut tap boxes are a fixed 24px wide; at level 5 the row is the widest, so check on a 360px phone that neighbouring boxes do not overlap and that each is comfortably thumb-sized, widening or staggering them if not.
Approved. The page drives the game only through BeachHuts (paint, undo, clashes, start). Locked huts carry a padlock bitmap and painted huts a letter, so neither relies on colour. Clashes get a dashed outline and a warning triangle. Every stroke, refusal and end line goes through the polite live region. The page has a mute button, no mp3, a three-line rules popup and ambient motion held still under reduced motion. The preview serves /beach-huts/ and row.js with 200. Not checked: the clone lacks 6da49a46cbb1, so I read the full diff rather than the delta, and I could not open the forge screenshots from my sandbox. Next: (1) Non-blocking: the 360px layout has not been looked at. Check that the #line status text does not overlap the mute button and that the 44px tin hit area is easy to reach with a thumb. (2) Non-blocking: tapping a locked hut selects it and the refusal only comes when you paint. Say up front when a locked hut is selected, e.g. "locked, cannot be painted".
Beach Huts is now a playable page at beach-huts/index.html, built on the rules in beach-huts/row.js and listed in the catalogue. I made no code change this turn. The preview deploy failed, but I couldn't find a failure in the code.
- What the log showed: it was cut off in the middle of the per-game playtests, at
sled-run. No test in the visible part had failed. - What I ran locally: the full
bun testpasses (1991 tests across 134 files, 0 failures, about 340 s). That includes all 6 Beach Huts playtests and its own 16 tests. - Likely cause: the deploy hit a time or resource limit, since
playtest.test.mjsalone takes about 240 s. I haven't confirmed that, because I only had the truncated log. - What I pushed: an empty commit,
7a87984, to trigger a new preview deploy. If it fails again, the full log should name the cause.
What the pull contains
beach-huts/index.htmlandbeach-huts/page.test.mjs(the page and its test).- A catalogue entry in the root
index.html, plusshell.js,rounds.mjsandserve.test.mjs. - The social-preview images
og/beach-huts.pngandog/home.png, and aREADME.mdupdate.
To try it, run bun serve.mjs and open /beach-huts/. The preview is at https://pixel-plays--372--forge-trevato-apps.open-platform.sh.
Approved. The earlier head is not in the clone, so I read the whole change. The preview answers 200 at /beach-huts/. The game runs only through the row.js export, and the page and its tests follow the repo pattern. Padlocks and R/B/Y/G letters carry the meaning without colour. Clashes get a dashed outline and a warning triangle. Every stroke, refusal and undo goes through the aria-live status. Keyboard play works (arrows, 1-4, U, R, Enter for the next level) and tap play works. Reduced motion holds the sea glints still. Non-blocking: 1) tins and huts are canvas-only, so a visible button row for the tins would help low-vision touch users. 2) Selecting a locked hut by tap is allowed, but the refusal only comes when a tin is tapped, so say it at selection too.
This pull adds Beach Huts: the playable page beach-huts/index.html, its page test, its card, and its entries in the catalogue, shell.js and rounds.mjs. The latest push also fixes the preview deploy failure. I haven't run the full suite, and I haven't seen the new deploy's result.
The failure. The deploy stopped the test run for using 2.0 CPU cores for 30 seconds against a limit of 2. It stopped in soapbox-derby/page.test.mjs. The run had just passed all of Beach Huts' own tests. A single bun test process can use over a core on its own, because JavaScriptCore runs background threads for GC marking and JIT.
The fix. forge.json now runs the tests as env BUN_JSC_numberOfGCMarkers=1 BUN_JSC_useConcurrentJIT=0 BUN_JSC_useConcurrentGC=0 bun test. No test changed. I measured one page test file before and after:
| CPU time | Wall time | |
|---|---|---|
| Before | 1.14 s | 0.68 s |
| After | 0.74 s | 0.81 s |
CPU time now sits at or below wall time, so the run stays near one core. The cost is a slightly slower wall time. The README now explains the setting.
Not done. I didn't change the tests or trim the suite, since the problem was the thread count, not the amount of work. The 600-second deploy limit still applies, and the last full local run took 340 seconds.
Check.
- Whether the
envprefix works depends on the forge running the test command through a shell orenv. If the deploy rejects it, the log will say so. - The next deploy shows whether the limit is now met. If it still trips, the next step is to split the heavy page tests.
Beach Huts is playable on the preview (/beach-huts/ answers 200), drives the game only through row.js, announces strokes, refusals and the end line through the live region, marks locked huts with a padlock and clashes with a dashed outline plus a warning triangle, and gives each paint a letter. Tests cover the page, the scripted round and serve. Since my last review the only change is forge.json running tests with the JSC single-thread env, plus a README note; the earlier asks stand met. Next two things: (1) Non-blocking: the forge.json test-runner change is unrelated to the game; land it separately next time so a game pull stays a game pull. (2) Non-blocking: a tap on a locked hut selects it and only refuses on paint; refuse at selection for quicker feedback on a phone.
This pull adds Beach Huts: its playable page at beach-huts/index.html, its entry in the catalogue and home page, and the rules in beach-huts/row.js. It also adds beach-huts/page.test.mjs, a social image og/beach-huts.png, and the README and serve.test.mjs entries.
This push. The last preview deploy log was cut off mid-suite, in the playtests, which I read as the deploy's time limit. I haven't seen it fail on a test. The scripted rounds in rounds.mjs read only the HUD text, but each frame still painted its picture, and the painting was most of their cost. playRound now calls stopDrawing() first, so rounds skip the painting. I made the same change earlier to playtest.test.mjs. forge.json still runs bun test with one GC marker and no concurrent JIT or GC.
Checked here.
bun x tsc --noEmitshows no errors.- The Beach Huts playtests pass: 6 of 6 under
-t "beach-huts". - A run of
playtest.test.mjs,beach-hutsandcoconut-shytogether ran 525 tests: 523 passed and 2 failed. I saw only one of the two failures, stained-glass's "stay within 15 s" budget test, which fails when the game's other tests don't run first. I didn't confirm that cause for either failure. - I did not run the full suite here, so the deploy may still run out of time. The forge runs the full check on this push.
Not done. I left every other game's playtest alone.
To try it, open /beach-huts/ on the preview.
🤖 Generated with Claude Code
Beach Huts is now playable at
/beach-huts/and listed in the catalogue. It runs only throughrow.js, which I did not touch. The beach-huts tests, the playtests forbeach-hutsandserve.test.mjs+shell.test.mjspass here; I did not run the full suite.scripts/design-lint.tsdoesn't exist in this clone (norgate.tsorfast.ts), andtscfinds notsconfig, so neither ran. The forge's check will be the first run of anything that depends on them.#mutebutton, no.mp3, and the rules popup has three lines.GAMESinshell.jsand the rootindex.htmlas Puzzle / Tap,music: false. The README has the Games table row, the no-music list and the ambient-motion note.bun scripts/og.mjshas been run, soog/beach-huts.pngandog/home.pngare updated.rounds.mjshas a scripted round that solves the row by backtracking over the rules state and reachesRow painted: … strokes against par …. That solver lives only in the test script.serve.test.mjsasserts/beach-huts/and/beach-huts/row.jsanswer 200, andbeach-huts/page.test.mjsis new.I didn't change any rules. A tap on a locked hut selects it, and the refusal then comes from
row.jswhen you try to paint it.Try it with
bun serve.mjsand open/beach-huts/.🤖 Generated with Claude Code
Closes #367