Browsergamesuites vereisen toestands- en invoerbewijs, niet alleen speelbare routes
Statische browsergames kunnen overtuigend lijken zodra elke game een speelbare route heeft, maar een route bewijst niet dat de spelregels, invoer, lokale opslag en browserinteractie samen werken. Deze studie onderzoekt de workspace alexandrai-games als een zes-game Astro/Vitest-casus. Ik combineerde broninspectie, AlexandrAI-grafiekonderzoek, officiële framework- en webplatformdocumentatie, softwaretestliteratuur en drie lokale verificatiecommando’s. De checkout bevat zes games, zes pure logic-modules, zes game Body-componenten, zes game-specifieke i18n-modules en een gedeelde shell met negen locales. Vitest rapporteerde zes geslaagde testbestanden en zevenenzeventig geslaagde tests; de Astro-build genereerde zevenenzestig statische pagina’s; astro check rapporteerde vierenvijftig bestanden zonder errors, warnings of hints. De bijdrage is een State-Input-Route-Persistence evidence chain: een suiteclaim moet worden beperkt door de zwakste werkelijk uitgevoerde laag. Voor deze casus is de state-laag sterker dan de route-laag, maar browser-E2E en toegankelijkheidsinteractie blijven expliciete open gates. Deze begrenzing maakt de releaseclaim toetsbaar.
Inleiding
Een browsergamecatalogus kan al volwassen lijken wanneer elke titel een route, een titel en een knop heeft. Voor kwaliteitsbewijs is dat te weinig. Een route bewijst dat een pagina gebouwd kan worden; zij bewijst niet dat een mijnenveld veilig opent, een slang niet achteruit kan keren, een woordspel dubbele letters correct telt, of dat keyboard- en touchinvoer dezelfde intentie aan de staatmachine doorgeven.
De onderzochte workspace heeft precies dit spanningsveld. `alexandrai-games` is een Astro/Vitest-site met scripts voor test, build en typecheck [[cite:pkgJson]]. De gamecatalogus wordt automatisch uit game-indexmodules opgebouwd [[cite:gamesTs]], en de routes worden via Astro’s statische routepatroon gegenereerd [[cite:defaultRoute,localizedRoute,astroRouting]]. Dat is een sterke routeclaim, maar geen volledige gameplayclaim.
De onderzoeksvraag is daarom: hoe moet een statische browsergamesuite kwaliteit bewijzen wanneer speelbare routes kunnen bestaan zonder uitgevoerd bewijs voor state, invoer, persistentie en browserinteractie? Het antwoord is geen extra telling van pagina’s, maar een bewijsmodel waarin elke laag apart wordt geverifieerd en de suiteclaim door de zwakste laag wordt begrensd.
Deze vraag is vooral relevant voor kleine “time-killer” games. Zulke games hebben vaak geen server, database of accountstroom; de kwetsbare plekken zitten juist in lokale regels. Een 2048-variant faalt wanneer mergevolgorde verkeerd is. Een woordspel faalt wanneer duplicate letters te ruim worden toegekend. Een mijnenveger faalt wanneer first-click safety alleen in copy bestaat. De betrouwbaarheidsclaim is dus lokaal en interactief tegelijk: pure functies zijn de beste plek om spelregels te bewijzen, maar de browser is de enige plek waar invoer, rendering en opslag samenkomen.
Daarom hanteert dit paper een strengere noemer dan “aantal games”. Een game telt niet als even sterk bewezen omdat zij naast vijf andere games in dezelfde build staat. Elke titel heeft eigen invarianten, eigen UI-risico’s en eigen opslag- of scoregedrag. De suiteclaim is pas eerlijk wanneer zij die verschillen behoudt: een sterk getest Word Guess compenseert geen onbewezen swipepad in Snake, en een succesvolle Astro-build compenseert geen ongeteste localStorage-fallback.
Methode
De studie is een workspace-gestuurde conceptuele synthese. De primaire corpusbestanden waren `package.json`, de game registry, i18n, input, storage, SEO, de twee game-routebestanden, `llms.txt`, zes game-testbestanden en representatieve pure state-modules. Alle lokale paden zijn in dit paper als `workspace:alexandrai-games/...` weergegeven om machine-specifieke details te vermijden.
De verificatie bestond uit drie commando’s in de projectroot: `npm test`, `npm run build` en `npm run typecheck`. Vitest is geschikt als directe testlaag voor geëxporteerde functies en `.test`-bestanden [[cite:vitestGuide]], terwijl Astro in statische modus vereist dat dynamische routes hun paden vooraf leveren via `getStaticPaths()` [[cite:astroRouting]].
Voor de externe lens gebruikte ik drie soorten bronnen: frameworkdocumentatie voor Astro, Vitest en Playwright; webplatformbronnen voor keyboard, touch en Web Storage; en testliteratuur over model-based testing, property-based testing en geautomatiseerde game-testing [[cite:mbtTaxonomy,quickCheck,gameAgentTesting]]. AlexandrAI-grafiekonderzoek leverde drie grensbronnen op: een workspace-inventory, een enkelvoudige rock-paper-scissors guide en een eerder paper over static utility accountability [[cite:priorWorkspaceInventory,priorRpsGuide,priorStaticUtility]].
De inclusieregel was conservatief: een bron werd alleen als eindreferentie gebruikt wanneer zij een concrete laag van de evidence chain ondersteunde. Body-componenten, layoutbestanden en algemene SEO-bronnen zijn wel gescreend, maar niet allemaal geciteerd, omdat zij geen extra bewijs leveren voor de centrale state-input-route-persistence claim. Omgekeerd zijn Playwright en de agent-based game-testing paper juist opgenomen als beperkende bronnen: zij tonen welke bewijslaag ontbreekt wanneer alleen unit tests en static build worden uitgevoerd [[cite:playwrightIntro,gameAgentTesting]].
De lokale testtelling is niet afgeleid uit de Vitest-samenvatting alleen. Ik telde daarnaast de `it(...)`-blokken per game-testbestand om te voorkomen dat een passing totaal de verdeling tussen spellen maskeert. Die verdeling is analytisch belangrijk: Minesweeper en Word Guess hebben de meeste edge-case tests, terwijl Memory Match een kleiner maar duidelijker combinatorisch contract heeft. De tellingen zijn dus geen kwaliteitsranglijst, maar een kaart van waar state-invariant bewijs geconcentreerd is.
Voor de synthese zijn claims in drie typen gecodeerd. Factual claims verwijzen naar een bronbestand of commando-output, zoals de zevenenzestig gebouwde pagina’s of de negen locales. Inference claims combineren meerdere bronnen, bijvoorbeeld dat routebewijs sterker wordt wanneer `getStaticPaths()` en build-output samen worden gelezen. Limiting claims gebruiken bronnen als Playwright en agent-based game-testing om te voorkomen dat de lokale verificatie breder wordt geïnterpreteerd dan zij is. Deze scheiding is belangrijk omdat een paper over softwarekwaliteit gemakkelijk van “werkt in deze laag” naar “werkt voor gebruikers” glijdt.
De studie gebruikt geen geheime of productiedata. Alle kwantitatieve waarden komen uit inspecteerbare bestanden of commando-output: zes gamefolders, zes testbestanden, zevenenzeventig tests, negen locales, vierenvijftig typecheck-bestanden en zevenenzestig buildpagina’s. Waar externe literatuur conceptueel wordt gebruikt, bijvoorbeeld model-based testing en property-oriented testing, wordt dat niet voorgesteld als iets wat de repository al implementeert [[cite:mbtTaxonomy,quickCheck]].
E suite = min(E state , E input , E route , E persistence , E browser )
Vergelijking (1) is het centrale codeerschema. Een suite mag alleen zo sterk worden geclaimd als de zwakste bewezen laag. In deze casus zijn state-, route-, build- en typechecklagen uitgevoerd; de browserlaag is beredeneerd maar niet met Playwright of vergelijkbare E2E-tests uitgevoerd [[cite:playwrightIntro]].
Resultaten
De eerste uitkomst is dat de routeoppervlakte reproduceerbaar maar niet handmatig gecureerd is. De registry gebruikt `import.meta.glob` om game-metadata uit game-indexmodules te verzamelen [[cite:gamesTs]]. De standaard route maakt paden uit game Body-modules; de gelokaliseerde route combineert alle niet-Engelse locales met elke slug [[cite:defaultRoute,localizedRoute]]. De build bevestigde dat dit model op 2026-06-30 zevenenzestig pagina’s opleverde [[cite:buildRun]].
De tweede uitkomst is dat de state-laag aanzienlijk sterker is dan een route-only claim. De tests tellen tien cases voor 2048, vijftien voor Block Drop, zeven voor Memory Match, zeventien voor Minesweeper, tien voor Snake en achttien voor Word Guess. Samen rapporteerde Vitest zevenenzeventig geslaagde tests in zes testbestanden [[cite:testRun]].
De derde uitkomst is dat invoer en persistentie als eigen lagen moeten worden behandeld. `input.ts` vertaalt Arrow/WASD, touch-swipe en knoppen naar directionele intenties [[cite:inputTs]]. MDN definieert `KeyboardEvent.key` als de waarde van de ingedrukte toets en Touch Events als het web-API-model voor touchpunten [[cite:mdnKeyboard,mdnTouch]]. WCAG 2.2 maakt keyboard-operabiliteit bovendien een basale toegankelijkheidsclaim [[cite:wcagKeyboard]]. Deze bronnen maken duidelijk dat invoer niet alleen een UI-detail is; het is een controlelaag.
`store.ts` bewaart scores in `localStorage`, met try/catch-fallbacks wanneer storage niet beschikbaar is [[cite:storeTs]]. MDN beschrijft `localStorage` als origin-scoped opslag die over browsersessies heen bewaard blijft, en de WHATWG-standaard definieert de Web Storage API inclusief privacy- en securitysecties [[cite:mdnLocalStorage,whatwgStorage]]. Daardoor is persistentie een afzonderlijke claim: “scores blijven lokaal” moet storagegedrag en failure handling omvatten, niet alleen marketingtekst.
Een vierde uitkomst is dat discovery en structured metadata aanwezig zijn, maar niet de spelkwaliteit dragen. `llms.txt` wordt uit de registry gegenereerd en waarschuwt agents dat het ophalen van een game-URL HTML/JS oplevert, geen speelsessie [[cite:llmsTxt]]. `seo.ts` kan VideoGame- en FAQ-achtige JSON-LD uit lokale metadata vormen [[cite:seoTs]]. Deze laag is nuttig voor vindbaarheid en agent-navigatie, maar zij is downstream van state en input: correcte metadata kan een kapotte state-machine niet repareren.
Op spelniveau is de bewijskwaliteit het duidelijkst waar de tests domeinspecifieke fouten voorkomen. Voor 2048 beschermt de non-double-merge test tegen een klassieke fout waarbij vier gelijke tegels in één beweging tot één tegel zouden kunnen instorten [[cite:test2048]]. Voor Block Drop voorkomt collision- en rotation-dekking dat stukken buiten het bord of door gevulde cellen bewegen [[cite:testBlockDrop]]. Voor Word Guess zijn dubbele lettertellingen expliciet getest, een edge case die met alleen “correct/present/absent” voorbeelden makkelijk fout blijft [[cite:testWordGuess]].
Minesweeper illustreert het verschil tussen voorbeeldtests en structurele invarianten. De suite controleert niet alleen dat een bord “ongeveer” mijnen heeft, maar telt exact het aantal mijnen, verbiedt mijnen op de veilige cel en haar acht buren, rekent adjacency opnieuw na, en test flood-fill gedrag op vaste kaarten [[cite:testMinesweeper]]. Dat zijn rule-level oracles: de test kent de spelregel en kan een fout aanwijzen zonder dat een mens eerst op de pagina hoeft te klikken.
Snake illustreert een andere klasse: temporele state. De tests controleren dat de kop één cel beweegt, dat de state als nieuw object terugkomt, dat 180-graden omkering wordt geweigerd, dat eten lengte en score verhoogt, en dat muur- en zelfbotsing `dead` zetten [[cite:srcSnake,testSnake]]. Deze dekking is waardevol omdat ze de frame-loop abstraheert: het spel hoeft niet te renderen om de kernregel “volgende tick produceert geldige state” te bewijzen.
Memory Match laat zien dat niet elke game veel tests nodig heeft om een duidelijke stateclaim te hebben. Het relevante contract is klein: een deck bevat elke waarde precies tweemaal, shuffle behoudt de multiset en muteert de input niet, en een match is alleen waar voor gelijke waarden op verschillende indexen [[cite:testMemory]]. De keten voorkomt dat deze kleinere testset verkeerd wordt gelezen als lagere kwaliteit; de juiste vraag is of de tests het domeincontract dekken.
Discussie
De evidence chain verandert de interpretatie van de verificatieresultaten. `npm test` bewijst veel over spelregels, omdat de tests direct pure statefuncties aanspreken [[cite:test2048,testBlockDrop,testMemory,testMinesweeper,testSnake,testWordGuess]]. `npm run build` bewijst dat routegeneratie en prerendering werken [[cite:buildRun]]. `npm run typecheck` bewijst dat Astro/TypeScript geen statische diagnostiek rapporteert [[cite:typecheckRun]]. Geen van deze drie bewijst echter dat een gebruiker via Chromium, Firefox of WebKit elk spel kan spelen.
Die beperking is geen formaliteit. Playwright positioneert rendered browserinteractie als een end-to-end testlaag voor moderne webapps en meerdere engines [[cite:playwrightIntro]]. De game-testing literatuur benadrukt bovendien dat games lastig te automatiseren zijn met traditionele algoritmen en soms agent- of modelgestuurde exploratie nodig hebben [[cite:gameAgentTesting]]. Voor kleine browsergames is agent-based testing mogelijk zwaarder dan nodig, maar het onderliggende punt blijft: statefuncties en routes zijn noodzakelijke, geen voldoende, suitebewijzen.
Model-based testing en property-based testing geven twee realistische uitbreidingsrichtingen. Een model-based laag zou bijvoorbeeld toestanden voor “actief stuk”, “vergrendeld stuk”, “volle rij” en “game over” genereren voor Block Drop, of open/flagged/hidden cellen voor Minesweeper [[cite:mbtTaxonomy]]. Een property-based laag zou willekeurige maar geldige state-sequenties maken en invarianten controleren, zoals behoud van kaartparen in Memory Match of scoremonotoniciteit in Snake; QuickCheck is hier een historische referentie voor het testen van properties in plaats van alleen voorbeelden [[cite:quickCheck]].
Toch zou zo’n uitbreiding niet alle gaten sluiten. Een property kan aantonen dat `move(grid,"left")` geen tegel verliest, maar niet dat het scherm na een swipe de juiste gridanimatie toont. Een model kan aantonen dat een mine nooit in de safe-neighborhood ligt, maar niet dat focus management, pointer target size of screen-reader tekst goed is. Daarom blijft de voorgestelde keten meerlagig: state-tests reduceren regelrisico, E2E-tests reduceren integratierisico, en accessibility-tests reduceren bedieningsrisico.
Vergeleken met eerder archivewerk is de bijdrage smal maar nieuw. De workspace-inventory labelde `alexandrai-games` alleen als Astro/Vitest site en hield purpose-documentatie open [[cite:priorWorkspaceInventory]]. De rock-paper-scissors guide behandelde één klein spel [[cite:priorRpsGuide]]. Het static-utility paper leverde een algemeen pure-logic-accountability model [[cite:priorStaticUtility]]. Dit paper vertaalt die gedachte naar spelregels, invoer, persistentie en browser-play als afzonderlijke kwaliteitslagen.
Operationeel suggereert dit een release-notatie die minder spectaculair maar preciezer is. Een changelogregel zou niet alleen “six games built” moeten zeggen, maar per gate rapporteren: state tests passed, static routes built, typecheck clean, input paths browser-tested, storage fallback tested, accessibility keyboard path tested. Daarmee wordt het zichtbaar wanneer een nieuw spel alleen een pagina toevoegt, maar nog geen invariant- of invoerbewijs heeft.
De evidence chain is ook nuttig voor prioritering. De eerstvolgende investering hoeft niet per se “meer unit tests” te zijn; zij moet de zwakste laag optillen. In deze checkout is dat browser-play. Een kleine Playwright-suite met één happy path per game, één keyboard-only path voor directionele games, één touch of pointer path waar relevant, en één localStorage fallbackscenario zou de totale suiteclaim meer verbeteren dan tien extra voorbeeldtests in een al goed gedekte pure module [[cite:playwrightIntro]].
Tegelijk blijft de state-laag de goedkoopste plaats om regressies vroeg te vangen. Nieuwe spellen zouden daarom met een minimumcontract kunnen starten: één pure state module, één testbestand, één Body component, één i18n module, registry-discovery via metadata, en een route die door build-output zichtbaar wordt. Pas daarna moet de browserlaag bewijzen dat de route werkelijk speelbaar is. Dit houdt de ontwikkelworkflow klein zonder route-aanwezigheid te verwarren met kwaliteitsbewijs.
Beperkingen
Deze studie is geen gebruikersstudie, geen volledige accessibility audit en geen performancebenchmark. Zij gebruikt lokale broninspectie en lokale commando-output als punt-in-tijd bewijs op 2026-06-30. De testtelling is reproduceerbaar uit `it(...)`-blokken, maar de semantische waarde van elke test is handmatig gecodeerd.
Een tweede beperking is dat alleen representatieve pure modules volledig in de tekst worden besproken. De Body-componenten zijn gescreend maar niet als primair bewijs geciteerd, omdat de centrale vraag niet “is er UI-code?” was, maar “welke laag is werkelijk uitgevoerd?” Voor een release-gate zou de volgende iteratie rendered browserflows, keyboard-only paths, touch gestures, localStorage failure modes en screenshot/visual regressions moeten toevoegen.
Een derde beperking is dat het paper geen uitspraak doet over spelbalans of plezier. Een game kan correct en toegankelijk zijn maar nog steeds saai, te makkelijk of visueel zwak. Die dimensies vragen andere methoden: playtesting, analytics, interaction design review en eventueel performanceprofielen. De hier voorgestelde keten is dus een kwaliteitsvloer voor juistheid en bedienbaarheid, geen volledige productevaluatie.
Een vierde beperking is dat externe literatuur vooral als lens dient. De repository gebruikt geen formele model-based testing tool en geen QuickCheck-achtige generator. De literatuur ondersteunt de keuze om state en properties als aparte bewijsobjecten te behandelen, maar de huidige resultaten blijven concrete workspace-resultaten: Vitest-tests, Astro-build en Astro-check. Dat onderscheid voorkomt dat conceptuele bronnen als empirisch bewijs voor de checkout worden gelezen.
Conclusie
Een statische browsergamesuite heeft meer nodig dan speelbare routes. In `alexandrai-games` is de state-laag goed onderbouwd: zes testbestanden, zevenenzeventig geslaagde Vitest-tests en expliciete invarianten voor merge, collision, flood fill, scoring, daily words en snake movement. De route- en typechecklagen zijn eveneens actueel uitgevoerd. De invoer- en persistentielagen zijn bronmatig plausibel, maar verdienen browsertests. De browser-playlaag blijft de zwakste niet-uitgevoerde gate.
De praktische conclusie is dat de site niet moet rapporteren “zes games zijn goed” alleen omdat zevenenzestig pagina’s bouwen. Zij kan wel sterker en preciezer rapporteren: zes games hebben pure state-logic met geslaagde unit tests; routes en locales bouwen; input en localStorage hebben gedeelde helpers; browser-E2E moet nog als afzonderlijke release-gate worden uitgevoerd. Dat is een kleinere claim, maar een betrouwbaardere kwaliteitsclaim.
De belangrijkste ontwerpregel is daarom eenvoudig: voeg een game pas aan de suiteclaim toe op het niveau dat werkelijk bewezen is. Een nieuw spel met alleen een Body-component heeft routebewijs. Een spel met pure functies en tests heeft statebewijs. Een spel met keyboard, touch, storage en browserflows heeft speelbewijs. Door die labels gescheiden te houden, kan een kleine browsergamesite snel groeien zonder haar kwaliteitsclaims groter te maken dan haar evidence chain.