04 · Playtest service: headless browser #6
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
cmoriarty/trog#6
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Run the web game (Phaser default) in a headless browser; capture screenshots, console output, and video. Results feed graph gates and the studio vitals pane.
Adapt from
agentic-game-dev/playtest— the web-native target should make this simpler than the Löve setup it replaces.Playtest service: headless browserto 04 · Playtest service: headless browser04 complete — playtest service is live
Docs:
docs/playtest.md· service:playtest/in this repo · fixture: trog-games/playtest-fixtureThe web target made it much simpler, as the ticket predicted
The predecessor ran LÖVE under Xvfb, injected input with xdotool, and grabbed frames with ffmpeg's x11grab. Playwright does screenshots, console capture, real input events, and video natively, so all of that apparatus is gone. What I kept from the old service is its good judgment: the strict input-script validator (a script that silently skips a bad step produces screenshots of the wrong state) and the passive/scripted split.
Why it's a gate, not a screenshot service
A broken web game still "loads" — the old runner would report success and attach a picture of an empty canvas. Every run now judges:
loaded,no_page_errors,no_console_errors,no_failed_requests(404 sprite = invisible player),page_responsive, andrendered_something(final-frame pixel variety — a one-color canvas is the classic silent failure).Two things I deliberately did NOT gate:
page_responsiveis a floor, not proof the game runs. I caught this by reading my own broken fixture's result: it scored 60fps while rendering one flat color, because the injected requestAnimationFrame probe keeps ticking even when the game's loop never starts. I renamed the check rather than let it imply something false.motionis reported, never gated. Pixel change between first and last screenshot is a useful signal (0.0 next to a passing run deserves a look), but a static menu or turn-based board must not fail a gate for holding still.Also found by using it
A scripted run's screenshot showed
keys: -— because the shot lands after the key is released, which answers the wrong question for a movement test. Added{"key": "right", "hold": 1.2, "shot": "holding right"}to capture mid-hold; verified the screenshot then readskeys: ArrowRight.The standing fixture (both directions)
trog-games/playtest-fixtureholds a real canvas game and a broken sentinel that fails the way real games do: 404 script → ReferenceError → dead loop → one-color canvas.If the sentinel ever passes, the gates regressed — that's why a game that's broken on purpose is worth keeping.
Wiring
Standing CPU service (SwiftShader GL — never competes for a card, like the analyzer), built from this repo per the vendoring decision.
POST /playteston the orchestrator,trog playtest <game>, and atrog test playtesttier in the quick suite. Verdicts key to the game's HEAD commit — same staleness contract as asset critiques, so a playtest result can't outlive the build it judged. Screenshots and video serve from/output/playtest/<date>/<run>/. 117 tests green.Known gap, deliberately deferred: the runner serves static files, so a project with
package.jsonand no built entry gets a 422 telling it to commitdist/. Wire a build step when the framework choice settles in the studio tickets (#7).Ready to close.