@cassiomc1/forgeloop 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/.cursor/rules/project-loop.mdc +18 -0
  2. package/.forgeloop/.gitignore +2 -0
  3. package/.github/copilot-instructions.md +16 -0
  4. package/AGENTS.md +16 -0
  5. package/AGENT_COMPATIBILITY.md +147 -0
  6. package/CLAUDE.md +14 -0
  7. package/CONTRACT_COVERAGE.md +27 -0
  8. package/DELEGATION_PROTOCOL.md +91 -0
  9. package/ENG/accessibility-eng.md +155 -0
  10. package/ENG/clean-code-eng.md +223 -0
  11. package/ENG/design-code-eng.md +511 -0
  12. package/ENG/games-code-design-web-eng.md +751 -0
  13. package/ENG/perf-code-eng.md +441 -0
  14. package/ENG/premium-sites-studio-eng.md +320 -0
  15. package/ENG/sec-code-eng.md +706 -0
  16. package/ENG/test-code-eng.md +257 -0
  17. package/EXECUTION_STATE.md +107 -0
  18. package/GUIDE_ROUTER.md +274 -0
  19. package/LICENSE +21 -0
  20. package/LICENSE-DOCS.md +13 -0
  21. package/LOOP_ENGINEERING.md +551 -0
  22. package/LOOP_SYSTEM_DESIGN.md +394 -0
  23. package/ORCHESTRATOR_INTEGRATION.md +106 -0
  24. package/PROJECT_PROFILE.md +124 -0
  25. package/QUALITY_SCORECARD.md +54 -0
  26. package/README.md +492 -0
  27. package/TERMINOLOGY.md +21 -0
  28. package/THIRD_PARTY_NOTICES.md +129 -0
  29. package/THREAT_MODEL.md +35 -0
  30. package/package.json +51 -0
  31. package/schemas/delegated-result.schema.json +33 -0
  32. package/schemas/evidence.schema.json +15 -0
  33. package/schemas/execution-receipt.schema.json +46 -0
  34. package/schemas/routing-input.schema.json +17 -0
  35. package/schemas/routing-result.schema.json +17 -0
  36. package/schemas/task-brief.schema.json +24 -0
  37. package/schemas/work-state.schema.json +46 -0
  38. package/src/cli.js +341 -0
  39. package/src/commands/clear-state.js +11 -0
  40. package/src/commands/doctor.js +165 -0
  41. package/src/commands/init.js +42 -0
  42. package/src/commands/inspect.js +17 -0
  43. package/src/commands/route.js +32 -0
  44. package/src/commands/status.js +29 -0
  45. package/src/commands/update.js +109 -0
  46. package/src/commands/validate-protocol.js +133 -0
  47. package/src/commands/validate-receipt.js +19 -0
  48. package/src/commands/validate-state.js +30 -0
  49. package/src/core/agent-support.js +89 -0
  50. package/src/core/conformance.js +133 -0
  51. package/src/core/delegation.js +283 -0
  52. package/src/core/evidence.js +56 -0
  53. package/src/core/filesystem.js +122 -0
  54. package/src/core/inspect.js +115 -0
  55. package/src/core/json-safety.js +54 -0
  56. package/src/core/manifest.js +75 -0
  57. package/src/core/protocol.js +81 -0
  58. package/src/core/receipt.js +129 -0
  59. package/src/core/repository.js +19 -0
  60. package/src/core/router.js +296 -0
  61. package/src/core/schema-validation.js +179 -0
  62. package/src/core/templates.js +56 -0
  63. package/src/core/work-state.js +471 -0
@@ -0,0 +1,751 @@
1
+ ---
2
+ name: games-code-design-web-eng
3
+ language: en
4
+ description: "Architecture, design, testing, and operation of 2D, 3D, and procedural web games."
5
+ version: "2026.09"
6
+ last-reviewed: "2026-08-10"
7
+ ---
8
+
9
+ # Web Game Development Guide — 2D, 3D, and Procedural Systems
10
+
11
+ > Practical instructions for designing, implementing, testing, shipping, and operating 2D and 3D games for the web. Use this document as a reference for AI coding agents and developers. Prefer measured, data-driven decisions, progressive enhancement, graceful degradation, and deterministic behavior over framework defaults or platform assumptions.
12
+ >
13
+ > **Related documents**: for general code structure, naming, dependency injection, and debugging, see [`clean-code-eng.md`](./clean-code-eng.md). For test strategy and tools such as Vitest and Playwright, see [`test-code-eng.md`](./test-code-eng.md). For browser security, CSP, dependency scanning, and multiplayer threat models, see [`sec-code-eng.md`](./sec-code-eng.md). For budgets, profiling, WebAssembly, PWA, CDN, and device performance, see [`perf-code-eng.md`](./perf-code-eng.md). For visual direction, UX, motion, and responsive design, see [`design-code-eng.md`](./design-code-eng.md). For WCAG 2.2-oriented implementation, assistive technology, and manual testing, see [`accessibility-eng.md`](./accessibility-eng.md). For HTML-based gameplay trailers, devlogs, and demos, see [HyperFrames](https://hyperframes.heygen.com). This guide focuses on game architecture and delivery; it does not replace those documents.
14
+ >
15
+ > **Tooling policy**: identify the stack, the stage, and the applicable checks; prefer an already available equivalent that produces compatible evidence. Ask for authorization before installing a tool or changing the environment. If no safe equivalent exists, record the required check as blocked and never claim that it passed. Do not install merely optional resources.
16
+
17
+ ## How to use this guide (mandatory process)
18
+
19
+ 1. Define the target devices, browsers, input methods, network model, visual style, game modes, and performance budget.
20
+ 2. Choose the smallest rendering and game framework that satisfies the design: Canvas/Phaser/PixiJS for most 2D games; Three.js/Babylon.js/PlayCanvas for 3D; Godot Web export when the project benefits from Godot's editor and engine workflow.
21
+ 3. Design the simulation independently from rendering and UI. Establish a fixed-step or explicitly documented timing model before adding content.
22
+ 4. Treat content as data. Use procedural/data-driven generation whenever the content is variable, repeatable, large, streamed, or easy to describe with rules and constraints.
23
+ 5. Define deterministic seeds, injectable random sources, generation stages, validation, versioning, and fallbacks before implementing procedural content.
24
+ 6. Build a low-end fallback path before adding optional graphics, WebGPU, multiplayer enhancements, or WebAssembly.
25
+ 7. Measure a production build on real desktop and mobile browsers, run automated tests and CI checks, and complete the review checklist before release.
26
+
27
+ The phrase **“always develop procedurally”** is an engineering instruction, not a requirement to replace every artist, designer, or writer. It means: default to procedural and data-driven systems where they improve scale, variation, reproducibility, streaming, or iteration; explicitly document an exception when authored content is the better tool.
28
+
29
+ ---
30
+
31
+ ## Principles
32
+
33
+ - **Simulation first**: rendering, audio, networking, input, and UI observe or submit commands to the simulation; they do not silently change game rules.
34
+ - **Determinism by design**: the same seed, algorithm version, input sequence, and initial state must produce the same result wherever deterministic replay is promised.
35
+ - **Progressive enhancement**: start with a playable Canvas/WebGL-compatible path, then enable WebGPU, richer effects, workers, WASM, and higher-resolution assets when supported and affordable.
36
+ - **Data over branching code**: represent entities, levels, tuning, encounters, recipes, and rules as validated data rather than large conditionals or duplicated scenes.
37
+ - **Critical content always has a safe path**: generated content must be validated and must have an authored or simpler fallback when failure would block onboarding, accessibility, progression, or recovery.
38
+ - **Main-thread discipline**: never allow asset decoding, world generation, serialization, pathfinding, or garbage-heavy work to cause avoidable frame stalls.
39
+ - **Server authority for competitive games**: the browser is a rendering/input client and must never be the sole authority for score, inventory, damage, matchmaking, or permissions.
40
+ - **Accessible by default**: keyboard, touch, gamepad, screen-reader-visible status, reduced motion, color-independent signals, and readable UI are game features, not post-processing.
41
+ - **Measure before optimizing**: profile release builds on representative devices and record the trade-off behind each optimization.
42
+
43
+ ---
44
+
45
+ ## Choose the platform and technology
46
+
47
+ ### Rendering and game frameworks
48
+
49
+ | Need | Recommended starting point | Notes |
50
+ | --- | --- | --- |
51
+ | Small 2D game or custom renderer | **HTML Canvas** (`CanvasRenderingContext2D`) | Minimal dependency surface; implement batching, camera transforms, culling, and asset management yourself. |
52
+ | 2D game with scenes, input, physics integration, and tooling | **Phaser** | Strong fit for browser-first 2D games; use its scene lifecycle and loaders without coupling all domain rules to scenes. |
53
+ | 2D renderer/UI layer for a custom engine | **PixiJS** | High-performance WebGL/WebGPU-capable rendering layer; provide your own simulation, scene model, and gameplay systems. |
54
+ | 3D library with a flexible rendering and scene API | **Three.js** | Good for custom 3D experiences; own the application architecture, asset lifecycle, and fallback policy. |
55
+ | Full 3D engine with physics, tooling, and WebGL/WebGPU paths | **Babylon.js** | Suitable for larger 3D games and interactive scenes; keep engine-specific code behind adapters where portability matters. |
56
+ | Browser-based 3D editor and deployment workflow | **PlayCanvas** | Useful when collaborative web tooling and a browser-native editor are priorities; validate runtime and hosting constraints early. |
57
+ | Existing Godot project or editor-driven production | **Godot Web export** | Export to Web and test HTML5/Web requirements, threading, memory, input, audio, and browser limitations on target devices. |
58
+ | Maximum control or a lightweight prototype | Canvas + TypeScript | Keep the renderer replaceable so WebGL/WebGPU or a framework can be introduced without rewriting the simulation. |
59
+
60
+ Use **WebGL** as the broad compatibility baseline for accelerated rendering. Detect and use **WebGPU** for supported devices when it provides a measured benefit, but keep a WebGL or Canvas fallback. Do not make WebGPU the only path unless the product explicitly accepts its browser, device, and embedded-context support matrix.
61
+
62
+ For a new browser-first project, **TypeScript + Vite** is a strong default: strict types, fast development feedback, explicit asset imports, and a small production build. Vite is a build tool, not a game engine; keep the simulation independent of Vite and expose a predictable `npm run build` and `npm run preview` workflow.
63
+
64
+ ### A practical selection rule
65
+
66
+ - Choose **Canvas 2D** for low-complexity 2D scenes, pixel art, board games, or custom renderers where a DOM UI is also important.
67
+ - Choose **Phaser** when a complete 2D game framework reduces implementation risk.
68
+ - Choose **PixiJS** when rendering flexibility matters more than a built-in game architecture.
69
+ - Choose **Three.js**, **Babylon.js**, or **PlayCanvas** for 3D; compare physics, editor needs, asset workflow, WebGPU maturity, team familiarity, and bundle/runtime cost rather than choosing by popularity alone.
70
+ - Choose **Godot Web export** when the existing project, editor workflow, and engine features outweigh export constraints.
71
+ - Choose **WebAssembly** only for measured CPU-bound code or when sharing a mature native/Rust library is valuable; it is not an automatic performance upgrade.
72
+
73
+ ---
74
+
75
+ ## Architecture and game loop
76
+
77
+ ### Module boundaries
78
+
79
+ Keep these modules separately testable:
80
+
81
+ - `core`: time, deterministic PRNG, entity identifiers, math, commands, events, and serialization.
82
+ - `simulation`: world state, rules, collisions, physics integration, AI, progression, and win/loss conditions.
83
+ - `generation`: seed handling, staged generation, rules, constraints, validation, and chunk streaming.
84
+ - `rendering`: Canvas, WebGL, WebGPU, or engine adapter; it reads a render snapshot and owns GPU resources.
85
+ - `input`: keyboard, pointer, touch, `Gamepad`, and `Pointer Lock` adapters that emit normalized commands.
86
+ - `audio`: `AudioContext`, music, effects, voice, spatial audio, mute, and visibility handling.
87
+ - `assets`: manifests, loading, decoding, caching, versioning, eviction, and fallback assets.
88
+ - `network`: WebSockets/WebRTC transport, protocol validation, snapshots, reconciliation, and reconnect behavior.
89
+ - `presentation`: menus, HUD, settings, accessibility text, and non-gameplay DOM.
90
+
91
+ Do not let a rendering callback become the only place where gameplay state is updated. The same simulation should be runnable in a headless test or server process when practical.
92
+
93
+ ### Fixed-step simulation with an accumulator
94
+
95
+ Use a fixed simulation step for physics, deterministic replays, and network prediction. Render at the display rate and interpolate between simulation states when appropriate.
96
+
97
+ The TypeScript-shaped pseudocode below assumes `simulation`, `input`, `network`, `telemetry`, and `session` adapters; their project contracts must expose the named operations and be tested.
98
+
99
+ ```ts
100
+ type Clock = {
101
+ previousMs: number;
102
+ accumulatorMs: number;
103
+ };
104
+ type Snapshot = { tick: number; state: unknown };
105
+ type ResyncFailureReason = 'request_failed' | 'snapshot_rejected' | 'network_disconnected';
106
+
107
+ const stepMs = 1000 / 60;
108
+ const maxFrameMs = 250;
109
+ const maxStepsPerFrame = 5;
110
+ const clock: Clock = { previousMs: performance.now(), accumulatorMs: 0 };
111
+ let resyncPending = false;
112
+
113
+ function clearSimulationDebt(): void {
114
+ clock.accumulatorMs = 0;
115
+ }
116
+
117
+ function enterSafeReconnect(reason: ResyncFailureReason): void {
118
+ telemetry.record('resync_failed', { reason });
119
+ clearSimulationDebt();
120
+ resyncPending = true;
121
+ simulation.pausePrediction();
122
+ network.reconnectOrReturnToSafeMenu();
123
+ }
124
+
125
+ function requestAuthoritativeResync(): void {
126
+ clearSimulationDebt();
127
+ simulation.pausePrediction();
128
+ if (resyncPending) return; // one request while a snapshot is pending
129
+
130
+ resyncPending = true;
131
+ try {
132
+ network.requestAuthoritativeResync();
133
+ } catch {
134
+ enterSafeReconnect('request_failed');
135
+ }
136
+ }
137
+
138
+ network.onAuthoritativeSnapshot((snapshot: Snapshot) => {
139
+ try {
140
+ simulation.applyAuthoritativeSnapshot(snapshot.state);
141
+ input.discardPredictedCommandsThrough(snapshot.tick);
142
+ clearSimulationDebt();
143
+ resyncPending = false;
144
+ simulation.resumePrediction();
145
+ } catch {
146
+ enterSafeReconnect('snapshot_rejected');
147
+ }
148
+ });
149
+ network.onResyncError(() => enterSafeReconnect('request_failed'));
150
+ network.onDisconnect(() => enterSafeReconnect('network_disconnected'));
151
+
152
+ function frame(nowMs: number): void {
153
+ const elapsedMs = Math.min(nowMs - clock.previousMs, maxFrameMs);
154
+ clock.previousMs = nowMs;
155
+ clock.accumulatorMs += elapsedMs;
156
+
157
+ if (session.isMultiplayer && resyncPending) {
158
+ clearSimulationDebt(); // every pending frame keeps alpha at 0
159
+ simulation.pausePrediction();
160
+ renderer.render(simulation.createRenderSnapshot(0)); // confirmed snapshot and safe reconnect UI
161
+ requestAnimationFrame(frame);
162
+ return;
163
+ }
164
+
165
+ let steps = 0;
166
+ while (clock.accumulatorMs >= stepMs && steps < maxStepsPerFrame) {
167
+ simulation.step(stepMs / 1000, input.consumeForStep());
168
+ clock.accumulatorMs -= stepMs;
169
+ steps += 1;
170
+ }
171
+
172
+ if (clock.accumulatorMs >= stepMs) {
173
+ telemetry.record('slow_frame', { pendingMs: clock.accumulatorMs, steps });
174
+ if (session.isMultiplayer) {
175
+ requestAuthoritativeResync();
176
+ } else {
177
+ clock.accumulatorMs = Math.min(clock.accumulatorMs, stepMs);
178
+ }
179
+ }
180
+
181
+ const alpha = clock.accumulatorMs / stepMs;
182
+ renderer.render(simulation.createRenderSnapshot(alpha));
183
+ requestAnimationFrame(frame);
184
+ }
185
+
186
+ requestAnimationFrame(frame);
187
+ ```
188
+
189
+ Rules:
190
+
191
+ - Clamp elapsed time to avoid a spiral of death after a tab is suspended.
192
+ - Define `maxStepsPerFrame` explicitly and never catch up without a bound. If the limit is reached, record a `slow_frame` telemetry/event with pending time and available cause, then follow a documented local recovery policy (for example, discard debt above one step) or request an authoritative snapshot/resync in multiplayer. While waiting for that snapshot, cap or clear local debt to keep `alpha <= 1` and deduplicate the pending request.
193
+ - `resyncPending` must be explicit state: set it before sending the request, pause simulation/prediction, and clear debt on **every** pending frame; render only the last confirmed snapshot and a safe reconnect UI. When the snapshot arrives, apply/reconcile state, discard predicted commands already covered by its tick, clear debt, and only then clear the flag and resume prediction. An error, disconnect, or reconciliation failure must keep simulation paused and trigger reconnect or a safe return; `alpha` must never exceed `1`.
194
+ - For `resync_failed`, record only a stable, enumerated `reason`, such as `request_failed`, `snapshot_rejected`, or `network_disconnected`; callbacks and `catch` blocks map to those codes without sending exceptions, payloads, or raw values to telemetry.
195
+ - Pause or reduce work when `document.visibilityState !== 'visible'`, but preserve required network/session behavior.
196
+ - Never use wall-clock time for gameplay rules that must be replayable. Inject a clock into systems that need real time.
197
+ - Use interpolation only for presentation; never feed interpolated render positions back into authoritative simulation state.
198
+ - Prefer command/event boundaries (`MovePlayer`, `FireWeapon`, `UseItem`) over direct mutation from UI handlers.
199
+
200
+ ### ECS and data-oriented design
201
+
202
+ Use an Entity-Component-System (ECS) or a data-oriented layout when the game has many similar entities, frequent queries, streaming worlds, or measured bottlenecks.
203
+
204
+ - Keep components as plain data: position, velocity, health, collider, renderable, lifetime, and tags.
205
+ - Make systems operate on focused component sets, in a documented order.
206
+ - Store hot numeric data in contiguous arrays or typed arrays when profiling demonstrates cache, allocation, or iteration benefits.
207
+ - Use stable entity IDs/generations so destroyed entities cannot be accidentally addressed.
208
+ - Separate hot simulation data from cold metadata, debug labels, and editor-only data.
209
+ - Do not adopt a complex ECS solely because it is fashionable; a small explicit world model is often clearer for a small game.
210
+ - Preserve deterministic system ordering and avoid iteration over unordered object keys in deterministic paths.
211
+
212
+ ---
213
+
214
+ ## Procedural and data-driven generation (mandatory policy)
215
+
216
+ ### Default decision
217
+
218
+ Whenever appropriate, use procedural/data-driven generation for terrain, dungeons, rooms, item rolls, enemy waves, foliage, particles, quests, loot tables, test fixtures, localization variants, and streaming content. “Appropriate” means the content benefits from variation, scale, replayability, runtime assembly, compression, or designer-controlled rules.
219
+
220
+ Do not implement random generation through scattered calls to `Math.random()`. Every generated result must be attributable to an explicit seed and an injectable PRNG.
221
+
222
+ ### Required generation contract
223
+
224
+ Every procedural feature must define:
225
+
226
+ - `seed`: the user/session/world seed, represented as a stable string or integer and shown in debug tools when useful.
227
+ - `algorithmVersion`: an explicit version such as `caves-v3`; changing the algorithm must not silently change existing worlds.
228
+ - `prng`: an injectable deterministic generator with separate streams for independent domains such as terrain, loot, and decoration.
229
+ - `inputs`: normalized configuration, difficulty, biome, player progression, and neighboring chunk information.
230
+ - `output`: a serializable intermediate representation or data object before rendering.
231
+ - `validation`: structural, gameplay, reachability, budget, and safety checks.
232
+ - `fallback`: authored, cached, simplified, or previously validated content for critical failures.
233
+
234
+ Use a small interface so tests and tools can inject a known source:
235
+
236
+ ```ts
237
+ export interface Prng {
238
+ next(): number; // [0, 1)
239
+ int(minInclusive: number, maxExclusive: number): number;
240
+ fork(label: string): Prng;
241
+ }
242
+
243
+ export interface GenerationContext {
244
+ seed: string;
245
+ algorithmVersion: string;
246
+ chunk: { x: number; y: number; size: number };
247
+ prng: Prng;
248
+ }
249
+ ```
250
+
251
+ Do not promise cross-language bit-for-bit determinism unless the PRNG, integer widths, floating-point operations, serialization, and algorithm are specified and tested. For client/server games, server-generated results or compact generation inputs are authoritative.
252
+
253
+ ### Staged generation
254
+
255
+ Break generation into deterministic, inspectable stages instead of one opaque function:
256
+
257
+ 1. **Normalize** configuration and derive a stable chunk/feature key.
258
+ 2. **Plan** topology, biome, room graph, encounter budget, or spawn points.
259
+ 3. **Carve/assemble** geometry and gameplay regions.
260
+ 4. **Place** required objectives, entrances, exits, resources, and authored landmarks.
261
+ 5. **Decorate** optional visuals, foliage, particles, and variation.
262
+ 6. **Validate** constraints and repair or reject invalid output.
263
+ 7. **Bake/cache** a versioned representation if regeneration would be expensive.
264
+ 8. **Stream** the result into the active world and release distant chunks.
265
+
266
+ Each stage should be independently testable and should consume a named PRNG fork rather than depending on how many random calls a previous stage happened to make.
267
+
268
+ ### Streaming, chunks, rules, and constraints
269
+
270
+ - Derive chunks from stable coordinates and the world seed so they can be generated in any order.
271
+ - Add a one-chunk border or equivalent neighbor context when rules depend on adjacent tiles.
272
+ - Generate a bounded radius around the player, prioritize visible/required chunks, and cancel stale work.
273
+ - Use Web Workers for expensive generation when it can be serialized safely; transfer typed arrays rather than cloning large object graphs.
274
+ - Define hard constraints: connectivity, minimum spawn distance, valid navigation, resource availability, difficulty bounds, collision-free placement, and memory limits.
275
+ - Define soft constraints with scores and a bounded repair strategy; do not loop indefinitely searching for a perfect result.
276
+ - Validate before exposing content to players. If validation fails, retry with a documented derived seed or use the fallback.
277
+ - Keep generation independent from frame timing. A slow device must receive the same valid chunk, not a different random result.
278
+
279
+ ### Reproducibility and versioning
280
+
281
+ - Persist `seed`, `algorithmVersion`, generator configuration, and relevant content/schema versions in saves, replays, bug reports, and multiplayer session metadata.
282
+ - Add a debug command or URL/query parameter to load a seed and stage output.
283
+ - Capture failed seeds as regression fixtures.
284
+ - Never silently migrate an existing world to a new algorithm. Provide a migration, pin the old generator, or explicitly invalidate/rebuild the world.
285
+ - Version generated asset manifests and cache keys with the generator and content versions.
286
+ - Use golden snapshots only for stable intermediate representations; avoid brittle screenshots as the sole proof of procedural correctness.
287
+
288
+ ### When not to use procedural generation
289
+
290
+ Do **not** use procedural generation as the default for:
291
+
292
+ - Critical onboarding, tutorials, first-run UX, recovery flows, or accessibility instructions where clarity and predictability are required.
293
+ - Directed narrative beats, authored pacing, cinematics, puzzles with deliberate solutions, and emotionally important set pieces.
294
+ - Competitive maps or encounters where fairness requires exact sightlines, spawn positions, and balance guarantees unless the generator is formally constrained and validated.
295
+ - Legal, safety, monetization, or compliance-critical text and interactions.
296
+ - Small content sets where authoring is cheaper, more expressive, and easier to review.
297
+ - Any content that cannot be validated or safely replaced when generation fails.
298
+
299
+ ### Combining authored and procedural content
300
+
301
+ Use a hybrid approach:
302
+
303
+ - Author the critical spine: tutorial, entrances, exits, narrative landmarks, accessibility routes, guaranteed rewards, and recovery points.
304
+ - Generate the connective tissue: layout variations, optional rooms, enemy composition within budgets, decorations, side paths, and replayable rewards.
305
+ - Expose generator parameters and constraints to designers rather than requiring code changes for every tuning pass.
306
+ - Reserve authored landmarks with stable IDs and place them through deterministic anchors or sockets.
307
+ - Test authored guarantees after procedural assembly: a generated level must preserve the required route, objective, pacing envelope, and fallback affordances.
308
+ - Record which content was authored, generated, repaired, or replaced so debugging and support can explain what happened.
309
+
310
+ ### Procedural generation tests
311
+
312
+ - Use property-based tests with **fast-check** or an equivalent tool to generate seeds, configurations, chunk coordinates, and edge cases.
313
+ - Assert invariants rather than only expected pictures: termination, bounds, connectivity, no invalid overlaps, deterministic replay, resource guarantees, and memory limits.
314
+ - Run a fixed corpus of adversarial seeds and newly discovered failure seeds in CI.
315
+ - Test the same seed repeatedly, in different chunk/request orders, after save/load, and with generation cancellation/retry.
316
+ - Test algorithm-version compatibility and migration behavior.
317
+ - Test fallback content by forcing PRNG failure, invalid configuration, worker failure, timeout, corrupted cache, and validation rejection.
318
+
319
+ ---
320
+
321
+ ## Input, camera, physics, and interaction
322
+
323
+ ### Input
324
+
325
+ Normalize all devices into actions rather than letting gameplay systems inspect DOM events directly.
326
+
327
+ - Support keyboard and pointer for desktop, touch with visible controls for mobile, `Gamepad` for controllers, and `Pointer Lock` for first-person or camera-heavy games when appropriate.
328
+ - Define action maps (`move`, `aim`, `primary`, `secondary`, `pause`, `fullscreen`) and allow rebinding.
329
+ - Track pressed, just-pressed, released, analog value, and device source per simulation step.
330
+ - Use `KeyboardEvent.code` for physical layout-stable bindings and expose a localized label for the UI.
331
+ - Treat `pointerdown`/touch as user gestures when requesting fullscreen or starting `AudioContext`; never assume autoplay is allowed.
332
+ - Provide an escape path from `Pointer Lock`, a visible cursor/crosshair state, and a non-pointer alternative.
333
+ - Prevent browser defaults only on the canvas/game region and only when the action is captured; do not break page scrolling or assistive technology.
334
+ - Support `touch-action` deliberately, large touch targets, safe-area insets, and orientation changes.
335
+ - Handle Gamepad connection/disconnection, unstable indices, dead zones, remapping, optional vibration, and differing layouts; show the detected device rather than assuming button `0` always has the same role.
336
+ - Handle `pointerlockchange`, `pointerlockerror`, Escape, and focus loss; request Pointer Lock only after an explicit gesture and retain a drag/touch alternative.
337
+ - Clear pressed keys on focus/visibility loss and make camera smoothing, shake reduction, resize, and device-pixel-ratio behavior configurable.
338
+
339
+ ### Camera and coordinate spaces
340
+
341
+ Document world, camera, screen, and UI coordinate spaces. Centralize transforms and test them at different device pixel ratios, zoom levels, and viewport sizes. Clamp camera movement to playable bounds and avoid using CSS scaling as a substitute for rendering at a correct internal resolution.
342
+
343
+ ### Physics
344
+
345
+ - Choose a physics engine that matches the game: simple deterministic AABB/circle tests, an engine such as Matter.js for 2D, or a 3D physics integration such as Rapier when needed.
346
+ - Use fixed-step physics and explicit units; document meters/pixels, gravity, collision layers, masks, and solver iterations.
347
+ - Keep collision geometry simpler than visual geometry and generate collision data from validated assets or data.
348
+ - Avoid tunneling with continuous collision detection or swept tests for fast bodies.
349
+ - Do not make physics engine state the only save/replay format; serialize domain state explicitly.
350
+ - Validate third-party physics behavior under the target browser/WASM path and decide whether deterministic lockstep is actually supported.
351
+ - Never trust client collision for authoritative decisions; validate movement, range, cadence, area of effect, and allowed transitions on the server. Test high speed, stacked bodies, boundaries, moving platforms, teleport, pause, rollback/reconnect, and extreme scales.
352
+
353
+ ---
354
+
355
+ ## Assets, scenes, and content pipeline
356
+
357
+ - Maintain a versioned asset manifest containing URLs, hashes, origin/provenance, license, attribution, type, dimensions, compression, dependencies, and fallback assets. Attribution must identify the rights holder and any required text or destination when applicable.
358
+ - Load a small boot scene first; show progress and allow the user to understand what is loading.
359
+ - Prefer `WebP`/`AVIF` where supported, compressed texture formats when the renderer supports them, and appropriately sized atlases rather than many tiny requests.
360
+ - Use sprite sheets/atlases, mesh simplification, texture compression, mipmaps, LODs, and instancing based on profiling.
361
+ - For 3D, standardize on a tested interchange format such as `glTF`/`GLB`; validate materials, animations, skeletons, coordinate conventions, and texture limits in CI.
362
+ - Use `ImageBitmap`, workers, streaming, and incremental decoding where supported, with a non-worker fallback.
363
+ - Dispose GPU resources, object URLs, audio buffers, and worker data when scenes or chunks are removed.
364
+ - Do not trust asset metadata or downloaded content. Validate type, size, schema, and origin; see [`sec-code-eng.md`](./sec-code-eng.md) for supply-chain and browser security rules.
365
+ - Make asset cache keys include the build/content version so a PWA does not combine incompatible code and data.
366
+ - Generate distribution notices from the manifest and ship them with every game distribution; do not treat a license field as sufficient if the required attribution is absent.
367
+ - Preload in phases (boot shell, first scene, nearby content, optional content) and expose real progress rather than a fake bar; release GPU resources, object URLs, audio buffers, and worker data when scenes or chunks leave memory.
368
+
369
+ ---
370
+
371
+ ## Audio with Web Audio
372
+
373
+ Use **Web Audio** and `AudioContext` for game audio that needs mixing, effects, volume groups, spatialization, or precise scheduling.
374
+
375
+ - Create/resume `AudioContext` in response to a clear user gesture and expose a mute/volume control before playing nonessential audio.
376
+ - Separate master, music, effects, voice, and accessibility buses; persist user preferences without storing secrets.
377
+ - Use pooled short sound effects, decoded buffers for frequently played sounds, and streaming media for long music where appropriate.
378
+ - Handle `visibilitychange`, device changes, suspended contexts, and mobile interruptions.
379
+ - Use spatial audio only where it improves play; provide volume, subtitles, visual cues, and non-audio feedback for important events.
380
+ - Never make audio required to understand a critical instruction or state.
381
+ - Test latency, autoplay restrictions, Bluetooth/headphone changes, Safari behavior, and low-memory devices.
382
+
383
+ ---
384
+
385
+ ## 2D and 3D rendering rules
386
+
387
+ ### HTML Canvas and WebGL
388
+
389
+ - Size the backing buffer using CSS dimensions and `devicePixelRatio`, capped by a configurable maximum to avoid mobile GPU/memory exhaustion.
390
+ - Clear, batch, sort, cull, and reuse draw resources; avoid creating objects or textures inside the frame loop.
391
+ - Use offscreen canvases or `OffscreenCanvas` only with a tested fallback and a clear transfer/lifecycle model.
392
+ - Handle context loss (`webglcontextlost`/`webglcontextrestored`) by rebuilding GPU resources and preserving CPU-side state.
393
+ - Use WebGL extensions only after feature detection and keep a baseline path without optional extensions.
394
+
395
+ ### WebGPU with WebGL/Canvas fallback
396
+
397
+ - Feature-detect `navigator.gpu`, adapter/device creation, required limits, and required features; do not infer support from the user agent.
398
+ - Keep renderer selection behind an interface such as `Renderer`, with WebGPU, WebGL, and Canvas implementations where the product needs all three.
399
+ - Request only required WebGPU features and limits; handle device loss and allocation failure.
400
+ - Keep shader/material assets versioned and validate them during build or startup.
401
+ - If WebGPU initialization fails, times out, or exceeds the budget, fall back without losing the game state. Log a diagnostic reason without exposing sensitive data.
402
+ - Test WebGPU on Chromium, Firefox where enabled/supported, Safari, and mobile devices separately; feature availability changes by browser and OS.
403
+
404
+ ### 3D-specific guidance
405
+
406
+ - Use frustum culling, occlusion strategy, LODs, instancing, texture budgets, compressed textures, and a bounded post-processing pipeline.
407
+ - Prefer baked lighting or simple lighting on low-end devices; make shadows, bloom, SSAO, reflections, and particles optional quality tiers.
408
+ - Pause or reduce rendering when the canvas is not visible through `IntersectionObserver` or page visibility state.
409
+ - Provide a 2D/static/image or low-fidelity fallback for unsupported graphics paths, reduced motion, low power, and initialization failure.
410
+ - Avoid using 3D merely as decoration. It must improve play, comprehension, or the product's purpose enough to justify its download and battery cost.
411
+
412
+ ---
413
+
414
+ ## Multiplayer: WebSockets and WebRTC
415
+
416
+ ### Choose the transport
417
+
418
+ - Use **WebSockets** for authoritative client/server messages, lobbies, matchmaking, snapshots, chat, and games where the server must control state.
419
+ - Use **WebRTC** data channels for peer-to-peer or low-latency media/data when the product can operate a signaling service and handle NAT traversal through STUN/TURN. Do not assume peer-to-peer means trusted or cheaper.
420
+ - Use HTTP/fetch for account, configuration, content manifests, and non-real-time operations.
421
+
422
+ ### Multiplayer architecture
423
+
424
+ - Define a versioned protocol with schemas, message sizes, sequence numbers, timestamps/ticks, acknowledgements where needed, and explicit disconnect/reconnect states.
425
+ - Validate every inbound message on the server and enforce rate, payload, frequency, and state-transition limits.
426
+ - Apply backpressure: bound queued messages, input frequency, payload size, synchronized entities, and messages per second; disconnect or degrade abusive clients rather than allowing unbounded work.
427
+ - Prefer server-authoritative simulation for competitive or persistent state. The client may predict local movement and interpolate snapshots, but the server resolves truth.
428
+ - Use client-side prediction, reconciliation, snapshot interpolation, interest management, and delta compression only after measuring latency and bandwidth.
429
+ - Make generated worlds reproducible from versioned seeds/algorithms, but do not trust a client-provided seed or generated result for rewards or competitive outcomes.
430
+ - Design reconnect, duplicate messages, late messages, clock drift, tab suspension, packet loss, and server restart behavior explicitly.
431
+ - Avoid sending the entire world to every client. Stream authorized chunks/entities and remove stale subscriptions.
432
+ - Protect matchmaking, chat, invites, and session tokens with the rules in [`sec-code-eng.md`](./sec-code-eng.md); WebSockets and WebRTC are not authorization boundaries.
433
+
434
+ ### Multiplayer testing
435
+
436
+ Test deterministic simulation, protocol compatibility, malformed messages, packet loss, reordering, duplication, latency, jitter, disconnects, reconnects, clock differences, multiple players in one chunk, and server overload. Add a headless bot/load test before a public launch.
437
+
438
+ ---
439
+
440
+ ## WebAssembly, Rust, C++, and Emscripten
441
+
442
+ Use **WebAssembly** for a measured CPU-bound path, a mature native library, deterministic simulation shared between client/server, or code that benefits from Rust/C++ ownership and existing tests.
443
+
444
+ - **Rust**: use `wasm-bindgen` or a suitable Rust-to-WASM toolchain; keep the JS/WASM boundary coarse and explicit, and minimize repeated string/object copies.
445
+ - **C++**: use **Emscripten** when porting an existing C++ engine/library; audit filesystem, threading, exception, memory, and Web API assumptions in the Web build.
446
+ - Keep DOM, browser permissions, networking policy, and accessibility in TypeScript/JavaScript or explicit adapters; do not hide browser behavior inside an opaque native port.
447
+ - Prefer typed arrays and bulk calls over per-entity JS↔WASM calls.
448
+ - Measure download, compile, instantiate, memory, worker, and copy costs—not only inner-loop CPU time.
449
+ - Provide a JavaScript/TypeScript fallback for unsupported or failed WASM initialization when the feature is not critical.
450
+ - Use COOP/COEP and cross-origin isolation only when required by the chosen threading/shared-memory path, and verify that CDN, iframe, analytics, and third-party resources remain compatible.
451
+ - Version the WASM binary and generated bindings; run native and Web tests against the same fixtures when behavior should match.
452
+ - Serve `.wasm` with the correct MIME type, effective Brotli/gzip compression, and hash-based caching. Do not instantiate a large module on the critical path when the game can boot without it; initialize it progressively or on demand.
453
+
454
+ ---
455
+
456
+ ## Accessibility and inclusive game UX
457
+
458
+ Canvas pixels are not a sufficient accessibility API. Build a semantic DOM layer for menus, settings, dialogs, status, inventory, objectives, and essential instructions.
459
+
460
+ - Provide keyboard navigation, visible focus, remappable controls, and an input alternative for every essential action.
461
+ - Support `prefers-reduced-motion`, reduced flashing, pause controls, and a setting to disable camera shake, parallax, and nonessential effects.
462
+ - Do not communicate essential state through color, sound, vibration, or motion alone; combine text, shape, pattern, or a semantic status message.
463
+ - Provide captions/subtitles, text alternatives for important audio, readable contrast, scalable UI, and a high-contrast option when appropriate.
464
+ - Ensure pointer capture and `Pointer Lock` can be exited with a documented keyboard action.
465
+ - Use ARIA carefully on the DOM interface (`role="status"`, labels, live regions); do not attempt to make every animated sprite individually focusable.
466
+ - Make touch targets large enough, support landscape/portrait changes, and avoid controls hidden behind browser or device safe areas.
467
+ - Test with keyboard-only navigation, screen readers, zoom, reduced motion, high contrast, color-vision simulation, touch, gamepad, and a low-power device.
468
+ - Use `axe-core` only for the semantic DOM layer. Canvas/WebGL and gameplay require manual smoke flows for keyboard, assistive technology, zoom, and the game flow; automation finds only a subset of issues and does not prove conformance.
469
+ - Include accessibility acceptance criteria in content and procedural-generation validation: a generated level must preserve a reachable route, readable landmarks, and required fallback cues.
470
+
471
+ ---
472
+
473
+ ## Security and privacy
474
+
475
+ Game clients are untrusted. Apply [`sec-code-eng.md`](./sec-code-eng.md) and additionally:
476
+
477
+ - Never trust client-side scores, inventory, currency, damage, cooldowns, generated loot, collision claims, or permission checks.
478
+ - Validate and authorize WebSocket/WebRTC messages server-side; enforce message size, rate, session, and state limits.
479
+ - Use HTTPS, secure authentication/session handling, restrictive CSP, explicit CORS, and SRI for third-party CDN scripts where applicable.
480
+ - Do not put private API keys, signing secrets, admin capabilities, or authoritative rules only in the bundle. Obfuscation is not a security boundary.
481
+ - Treat imported mods, custom maps, save files, replay files, and generated content as untrusted data. Parse with schemas and bounded resource limits; never `eval` content.
482
+ - Avoid XSS in chat, player names, clan content, generated text, and debug URLs. Escape DOM output and sanitize only when rich text is truly required.
483
+ - Use short-lived, scoped tokens and never place sensitive tokens in URLs, logs, or `localStorage` when safer cookie/session designs are available.
484
+ - Minimize telemetry and disclose collection. Do not send raw input, microphone/camera data, or identifiers unless needed and consented.
485
+ - Pin/lock dependencies, scan npm/WASM/native assets, review CDN changes, and protect publish credentials in CI.
486
+
487
+ ---
488
+
489
+ ## Performance budgets and compatibility
490
+
491
+ ### Suggested game budgets
492
+
493
+ Set project-specific values, then enforce them in release builds. Initial targets may include:
494
+
495
+ - 60 FPS where the design requires it, with a documented 30 FPS low-end tier; avoid relying only on average FPS.
496
+ - Frame-time budget of `16.67ms` at 60 FPS, including simulation, rendering, input, audio, and browser overhead.
497
+ - No avoidable long task over `50ms` during active play; generation and loading must be staged or moved off the main thread.
498
+ - A bounded initial download, decoded texture memory, GPU memory, entity count, active audio voices, and worker count.
499
+ - Measured cold start, time to first input, time to playable state, memory after 10–30 minutes, battery/thermal behavior, and network usage.
500
+
501
+ Use Chrome DevTools Performance/Memory, Firefox Performance, Safari Web Inspector, Lighthouse for the surrounding web shell, the browser GPU tools, and engine profilers. Compare p50/p95 frame time and long frames, not only a headline FPS number.
502
+
503
+ ### Browser and device matrix
504
+
505
+ Test the actual release build on every browser and device in the documented
506
+ support contract. For a cross-browser game, begin with this default matrix:
507
+
508
+ - Chromium-based desktop and Android browser.
509
+ - Firefox desktop/Android where supported.
510
+ - Safari on macOS and iOS/iPadOS.
511
+ - A modest Android device and an older supported iPhone/iPad.
512
+ - Keyboard/mouse, touch, and at least one `Gamepad` where controller support is promised.
513
+ - Different `devicePixelRatio` values, viewport sizes, orientation, reduced motion, low power, background/foreground transitions, and slow/unstable networks.
514
+
515
+ Use feature detection and capability tiers, not user-agent branching. Check `Can I Use` and vendor documentation for WebGPU, WebGL, `OffscreenCanvas`, Web Audio, `Gamepad`, `Pointer Lock`, WebSockets, WebRTC, service workers, and storage. Document unsupported features and the fallback behavior.
516
+
517
+ ### Mobile rules
518
+
519
+ - Avoid forcing maximum resolution; cap internal render scale and expose quality tiers.
520
+ - Respect battery, thermal throttling, memory pressure, safe-area insets, and browser UI changes.
521
+ - Pause or throttle inactive tabs and release distant chunks/assets.
522
+ - Use touch UI with visible controls; do not require hover, right-click, or precise pointer movement.
523
+ - Test iOS Safari gesture/fullscreen/audio behavior separately; mobile browsers are not miniature desktop browsers.
524
+
525
+ ---
526
+
527
+ ## PWA and CDN deployment
528
+
529
+ ### PWA
530
+
531
+ Use a **Progressive Web App (PWA)** when offline launch, installability, or a reliable return experience benefits the game.
532
+
533
+ - Provide a valid web app manifest with name, icons, `start_url`, `display`, theme/background colors, and orientation only when justified.
534
+ - Register a service worker with a deliberate strategy: precache only the boot shell and critical assets; use runtime caching for versioned immutable content; use network-first or no-cache for accounts, multiplayer, and mutable state.
535
+ - Version the cache name and app/content manifest together. On update, notify the player and do not mix an old JavaScript shell with incompatible generated data or assets.
536
+ - Implement offline/poor-network states and a predictable recovery path when a cache is incomplete or corrupted.
537
+ - Never cache secrets, personalized responses, or authoritative multiplayer state as if they were immutable public assets.
538
+ - Test install, update while playing, rollback/recovery, storage quota exhaustion, private browsing, offline boot, and service-worker failure.
539
+ - Store local saves in IndexedDB or an appropriate mechanism, with a versioned schema, migrations, quota handling, optional export/import, and a fallback when storage is unavailable. Do not rely on `localStorage` for large, critical, or sensitive saves.
540
+
541
+ ### CDN and static hosting
542
+
543
+ - Serve immutable hashed JS, WASM, textures, audio, and 3D assets with long-lived `Cache-Control`; serve the HTML shell and manifests with a revalidation policy that allows updates.
544
+ - Enable Brotli/gzip for text and WASM where effective, HTTP/2 or HTTP/3, TLS, range requests for large resources when supported, and correct MIME types.
545
+ - Configure CORS intentionally for WebGL textures, WASM, workers, fonts, and `glTF` dependencies.
546
+ - Use a CDN close to players, but keep an origin or fallback deployment and monitor cache misses, errors, bandwidth, and regional availability.
547
+ - Upload source maps privately or restrict access; do not expose secrets through source maps or build-time environment variables.
548
+ - Use SRI for external CDN scripts and lock versions. Prefer bundling critical dependencies when supply-chain and availability risk outweigh CDN benefits.
549
+ - If using cross-origin isolation for WASM threads, configure `Cross-Origin-Opener-Policy` and `Cross-Origin-Embedder-Policy` deliberately and test every embedded/third-party resource.
550
+ - Deploy atomically: a manifest must point to one consistent asset version, and new HTML must never reference hashes that are not yet available on the CDN.
551
+
552
+ ---
553
+
554
+ ## Testing strategy
555
+
556
+ Follow the testing pyramid from [`test-code-eng.md`](./test-code-eng.md), with additional game-specific layers:
557
+
558
+ - **Pure unit tests**: math, collision helpers, state reducers, PRNG, command parsing, serialization, cooldowns, scoring rules, and accessibility preference logic.
559
+ - **Simulation tests**: fixed-step runs, deterministic replays, save/load, pause/resume, system ordering, physics boundaries, and server/client reconciliation.
560
+ - **Procedural property tests**: seeds/configurations/chunks satisfy invariants, terminate, remain bounded, preserve guarantees, and reproduce across request order.
561
+ - **Asset/content tests**: schema validation, missing dependencies, corrupted files, dimensions, texture/material limits, localization completeness, and fallback availability.
562
+ - **Renderer tests**: WebGL/WebGPU/Canvas capability detection, context/device loss, resize/DPR, shader/material failure, and renderer fallback. Keep most gameplay tests headless.
563
+ - **Input/audio tests**: action mapping, rebinding, keyboard/touch/gamepad normalization, pointer-lock exit, autoplay rejection, mute, visibility changes, and captions.
564
+ - **Network tests**: protocol schemas, malformed messages, ordering, reconnect, prediction/reconciliation, rate limiting, and compatibility across protocol versions.
565
+ - **E2E tests**: use **Playwright** for boot, menu, settings, keyboard/touch smoke flows, save/reload, fallback rendering, and a small multiplayer smoke test. Do not make every test depend on timing-sensitive animation.
566
+ - **Visual regression**: use fixed seeds, fixed viewport/DPR, stable fonts/assets, and `toHaveScreenshot()` only for selected deterministic scenes.
567
+ - **Performance tests**: release build startup, frame-time budgets, long tasks, memory growth, asset loading, and representative low-end device runs.
568
+ - **Accessibility tests**: `axe-core` only for the semantic DOM; manual smoke flows for keyboard, assistive technology, zoom, and the game flow; focus checks, contrast, reduced motion, captions, and generated-level accessibility guarantees. Automation does not prove conformance.
569
+
570
+ For TypeScript/Vite, a practical baseline is **Vitest** for unit/integration tests, **fast-check** for property-based generation tests, and **Playwright** for E2E/visual testing. Use `npm run lint`, `npm run format -- --check`, `npm run test`, `npm run test:e2e`, and `npm run build` when those scripts exist; document the project's exact commands in `README.md` and `CLAUDE.md`/`AGENTS.md`.
571
+
572
+ Never use uncontrolled randomness, real sleeps, system time, network availability, or test order as hidden inputs. Inject them or use fakes.
573
+
574
+ ---
575
+
576
+ ## CI/CD and release gates
577
+
578
+ Every push/PR should run, at minimum:
579
+
580
+ 1. Install from the lockfile (`npm ci` for npm projects).
581
+ 2. Typecheck (`npm run typecheck` or the project's equivalent).
582
+ 3. Lint and formatting checks (`npm run lint`, `npm run format -- --check`).
583
+ 4. Unit/integration/property tests with coverage (`npm run test -- --coverage` when configured).
584
+ 5. Asset/schema/content validation, including the hash, origin/provenance, license, and attribution fields for every manifest item; generate notices and verify they accompany the distribution, as well as procedural seed corpus and fallbacks.
585
+ 6. Production build (`npm run build`) and a served smoke test (`npm run preview` in a bounded CI job or an equivalent static server).
586
+ 7. Playwright Chromium/Firefox/WebKit smoke tests where CI capacity permits.
587
+ 8. Accessibility and Lighthouse CI checks for the shell and critical routes.
588
+ 9. Dependency/SCA, SAST, secret, license, and WASM/native artifact scans according to [`sec-code-eng.md`](./sec-code-eng.md).
589
+ 10. Bundle, initial download, asset, and performance budget checks; fail or require an explicit review when budgets regress.
590
+
591
+ Use a release artifact with hashed assets, a versioned manifest, source-map handling, and a rollback plan. Deploy to staging first, run real-browser smoke tests, then publish gradually when the product's risk warrants it. Keep generator versions, seeds, content manifests, and protocol versions traceable to the deployed commit.
592
+
593
+ ---
594
+
595
+ ## Instruction template for `CLAUDE.md` / `AGENTS.md`
596
+
597
+ ```md
598
+ ## Web Game Development
599
+
600
+ - Target supported browsers and devices explicitly. Use feature detection and capability tiers; never assume WebGPU, WebGL, audio autoplay, gamepad, Pointer Lock, WebAssembly, service workers, or WebRTC are available.
601
+ - Keep simulation independent from rendering, DOM UI, audio, networking, and engine adapters. Use a fixed-step simulation when physics, replays, or deterministic networking require it.
602
+ - Choose the smallest suitable stack: Canvas/Phaser/PixiJS for 2D; Three.js/Babylon.js/PlayCanvas for 3D; Godot Web export when its editor/engine workflow is justified; TypeScript + Vite for browser-first builds.
603
+ - Use WebGPU only through feature detection and always provide a tested WebGL or Canvas fallback when the product supports those devices.
604
+
605
+ ## Procedural and Data-Driven Generation
606
+
607
+ - Interpret “always develop procedurally” as: use procedural/data-driven generation whenever it improves variation, scale, replayability, streaming, compression, or iteration. Do not use it for critical UX, authored narrative, deliberate puzzles, compliance content, or content that cannot be validated safely.
608
+ - Every generated feature has an explicit seed, injectable PRNG, algorithmVersion, normalized inputs, staged pipeline, constraints, validation, and a fallback.
609
+ - Never call Math.random() inside generation or simulation. Use named/forked deterministic PRNG streams and claim cross-runtime bit-for-bit determinism only when PRNG, integer width, floating point, serialization, and algorithm are specified and tested; client/server authority remains with the server or its compact generation inputs.
610
+ - Generate in deterministic stages: normalize, plan, assemble, place guarantees, decorate, validate, cache, and stream. Use chunks with stable coordinate keys and cancel stale work.
611
+ - Persist seed, generator/algorithm version, configuration, content/schema versions, and relevant protocol versions in saves, replays, bug reports, and multiplayer metadata.
612
+ - Author critical routes, onboarding, narrative landmarks, accessibility paths, and recovery content; use procedural systems for bounded variation around those authored guarantees.
613
+ - Validate generated output before showing it to players. Retry with a documented derived seed or use authored/simplified/cached fallback content on failure.
614
+ - Add property-based tests, deterministic replay tests, adversarial seed fixtures, cross-order chunk tests, migration tests, and forced-failure fallback tests.
615
+
616
+ ## Runtime and Assets
617
+
618
+ - Use an accumulator/fixed-step loop, clamp elapsed time, set `maxStepsPerFrame`, and never update gameplay only from a renderer callback. At the cap, record `slow_frame` and apply local recovery or authoritative resync; never use unlimited catch-up. `resyncPending` must deduplicate the request, pause simulation/prediction, clear debt on every pending frame, and only resume after applying/reconciling the snapshot; error/disconnect goes to reconnect or a safe screen.
619
+ - Normalize keyboard, pointer, touch, Gamepad, and Pointer Lock into remappable actions. Provide keyboard/touch alternatives and an escape path from pointer capture. Prevent defaults only in the game region when the action is consumed, preserving page scrolling and assistive technology.
620
+ - Use Web Audio only after a user gesture, with mute/volume buses, captions/visual cues for important events, and mobile interruption handling.
621
+ - Version and validate asset manifests, including hash, origin/provenance, license, and attribution. Generate notices that ship with the distribution; use compressed, appropriately sized textures/audio/GLB assets, dispose resources, and include fallbacks.
622
+ - Validate GLB/glTF materials, animations, skeletons, coordinates, and texture limits in CI; serve WASM with correct MIME/compression/hash caching and defer large noncritical initialization.
623
+ - Move generation, parsing, and other CPU-heavy work to Web Workers or WebAssembly only after measuring; keep JS↔WASM calls coarse and provide a fallback when practical.
624
+
625
+ ## Accessibility, Security, and Multiplayer
626
+
627
+ - Provide a semantic DOM UI for menus, HUD status, settings, objectives, captions, and essential instructions. Support keyboard navigation, visible focus, reduced motion, readable contrast, color-independent state, scalable UI, and touch targets. Run `axe-core` only on the DOM layer, then manually smoke keyboard, assistive technology, zoom, and the game flow; automation does not prove conformance.
628
+ - Treat the browser as untrusted. Server-authorize scores, inventory, damage, progression, generated loot, and permissions; validate every WebSockets/WebRTC message and apply rate/size limits.
629
+ - Follow [`sec-code-eng.md`](./sec-code-eng.md): HTTPS, restrictive CSP, explicit CORS, safe sessions, dependency scanning, no secrets in the bundle, schema validation for saves/mods/chat, and no unsafe HTML evaluation.
630
+ - Escape chat, names, generated text, and debug URLs at the DOM boundary; sanitize rich text only when necessary. Use short-lived, scoped tokens outside URLs, logs, and `localStorage` when a safer cookie/session design is available.
631
+ - Use WebSockets for authoritative client/server state and WebRTC only with explicit signaling, STUN/TURN, abuse controls, and a trust model. Design reconnect, ordering, loss, prediction, and protocol versioning.
632
+
633
+ ## Validation and Release
634
+
635
+ - Required checks: `npm ci`, typecheck, `npm run lint`, `npm run format -- --check`, unit/property tests, asset validation, `npm run build`, Playwright smoke tests, accessibility checks, SCA/SAST/secrets/license/WASM-native scans, and performance/bundle budgets.
636
+ - Use Vitest, fast-check, and Playwright for TypeScript/Vite projects unless the repository documents an equivalent.
637
+ - Test release builds on every documented browser/device target; for a
638
+ cross-browser game, include Chromium, Firefox, Safari, Android, iOS/iPadOS,
639
+ modest hardware, different DPR/orientations, reduced motion, low power,
640
+ offline/poor networks, and renderer fallback paths.
641
+ - For PWA/CDN deployments, version service-worker caches and manifests together; cache immutable hashed assets, never cache secrets, test updates/rollback/offline recovery, use versioned/migrated/quota-aware saves with export/import and a storage fallback instead of `localStorage` for large, critical, or sensitive data, configure CORS/SRI/COOP/COEP deliberately, and deploy HTML/manifests/assets atomically.
642
+ - Measure frame time, long tasks, startup, memory, network, and battery before claiming a performance improvement.
643
+ ```
644
+
645
+ ---
646
+
647
+ ## Web game review checklist
648
+
649
+ ### Architecture and simulation
650
+
651
+ - [ ] Target browsers, devices, inputs, network model, quality tiers, and budgets are documented.
652
+ - [ ] Simulation is independent from rendering, DOM, audio, and transport adapters.
653
+ - [ ] Timing model is fixed-step or explicitly justified; elapsed time is clamped and catch-up work is bounded.
654
+ - [ ] `maxStepsPerFrame`, `slow_frame` telemetry, and the recovery/resync policy at the cap are explicit; there is no unlimited catch-up. `resyncPending` deduplicates requests, pauses simulation/prediction, clears debt on every pending frame, and resumes only after snapshot reconciliation; error/disconnect reaches reconnect or a safe screen and `alpha <= 1`.
655
+ - [ ] ECS/data-oriented design is used only where it improves clarity or measured hot paths.
656
+ - [ ] Renderer selection supports the documented WebGPU/WebGL/Canvas fallback policy.
657
+
658
+ ### Procedural/data-driven content
659
+
660
+ - [ ] Appropriate variable/streamed/replayable content uses data-driven/procedural systems.
661
+ - [ ] Every generator has a deterministic seed, injectable PRNG, named streams, and an `algorithmVersion`.
662
+ - [ ] Cross-runtime bit-for-bit determinism is claimed only with specified/tested PRNG, integer width, floating point, serialization, and algorithm; client/server authority remains with the server or its compact generation inputs.
663
+ - [ ] Generation is staged, chunk-aware, bounded, cancellable, and independent of request/frame timing.
664
+ - [ ] Rules, hard/soft constraints, validation, repair limits, and critical guarantees are explicit.
665
+ - [ ] Seed, algorithm, content/schema versions, and configuration are reproducible in saves/replays/bug reports.
666
+ - [ ] Authored content covers onboarding, directed narrative, critical UX, required routes, and recovery paths.
667
+ - [ ] Generated failures have tested authored, cached, simplified, or previously validated fallbacks.
668
+ - [ ] Property-based tests, adversarial seeds, deterministic replays, migration tests, and forced-failure tests run in CI.
669
+
670
+ ### Input, physics, assets, and audio
671
+
672
+ - [ ] Keyboard, pointer, touch, Gamepad, and Pointer Lock behavior is normalized and remappable as applicable.
673
+ - [ ] Browser defaults are captured only in the game region for consumed actions; page scrolling and assistive technology remain functional.
674
+ - [ ] Every essential action has an accessible alternative; pointer capture can be exited.
675
+ - [ ] Physics uses documented units, fixed steps, collision layers, and validated/simple collision geometry.
676
+ - [ ] Asset manifests are versioned and validated for hash, origin/provenance, license, and attribution; generated notices ship with the distribution; assets are compressed, appropriately sized, and disposable; missing assets have fallbacks.
677
+ - [ ] GLB/glTF materials, animations, skeletons, coordinates, and texture limits are validated in CI; GPU resources, object URLs, audio buffers, and worker data are released with scenes/chunks; WASM MIME/compression/hash caching and deferred noncritical initialization are verified.
678
+ - [ ] Web Audio handles user gestures, autoplay rejection, mute, volume groups, captions/visual cues, visibility, and mobile interruptions.
679
+ - [ ] WebGL context loss and WebGPU device loss are handled without losing CPU-side game state.
680
+
681
+ ### Accessibility and security
682
+
683
+ - [ ] Menus, HUD status, settings, objectives, and critical instructions have a semantic DOM representation.
684
+ - [ ] Keyboard focus, contrast, reduced motion, captions, scalable UI, touch targets, and color-independent feedback are tested; `axe-core` covers only the DOM and manual smoke covers keyboard, assistive technology, zoom, and the game flow. Automation is not treated as proof of conformance.
685
+ - [ ] Client data is never trusted for authority; WebSockets/WebRTC messages are authenticated, authorized, schema-validated, and rate-limited.
686
+ - [ ] CSP, HTTPS, CORS, SRI, dependency scanning, secret handling, save/mod/chat validation, and safe DOM output are configured.
687
+ - [ ] Chat, names, generated text, and debug URLs are protected from XSS; short-lived, scoped tokens do not appear in URLs, logs, or `localStorage` when a safer cookie/session design exists.
688
+ - [ ] Telemetry is minimized, documented, and free of unnecessary personal or sensitive data.
689
+
690
+ ### Multiplayer and compatibility
691
+
692
+ - [ ] Transport choice is justified: WebSockets for authoritative server state, WebRTC only with signaling/STUN/TURN and an explicit trust model.
693
+ - [ ] Protocol versions, sequencing, reconnect, duplication, loss, jitter, prediction, reconciliation, and server authority are tested.
694
+ - [ ] Browser feature detection and capability tiers cover only capabilities
695
+ that the documented support contract includes or the project uses (for
696
+ example WebGPU/WebGL, Web Audio, Pointer Lock, Gamepad, WebAssembly, PWA,
697
+ WebSockets, and WebRTC); each supported capability has a documented fallback
698
+ or an explicit support-boundary decision.
699
+ - [ ] Release builds have evidence for every documented browser/device target;
700
+ cross-browser games include desktop Chromium/Firefox/Safari, Android,
701
+ iOS/iPadOS, modest devices, touch/gamepad, different DPR/orientations, and
702
+ low-power conditions.
703
+
704
+ ### Performance, testing, CI, and deployment
705
+
706
+ - [ ] Frame-time/long-task, startup, memory, network, battery, bundle, texture/audio, and worker budgets are measured on representative devices.
707
+ - [ ] Vitest/unit, property-based, simulation, asset, renderer, accessibility, Playwright E2E, and selected visual regression tests exist.
708
+ - [ ] CI runs typecheck, lint, formatting, tests, seed corpus, asset validation, production build, smoke tests, accessibility, SCA/SAST/secrets/license/WASM-native scans, and budget checks.
709
+ - [ ] PWA service-worker caches, manifests, updates, offline recovery, quota failure, and rollback are tested; saves use a versioned schema, migrations, quota handling, optional export/import, and a storage fallback, without `localStorage` for large, critical, or sensitive data.
710
+ - [ ] Deployment is atomic: HTML, manifest, and asset hashes reference a consistent version already available on the CDN.
711
+ - [ ] CDN uses hashed immutable assets, correct MIME/CORS, compression, cache policy, SRI for external scripts, and a rollback plan.
712
+ - [ ] Generator versions, seeds, content manifests, protocol versions, and release commit are traceable in production diagnostics.
713
+ - [ ] A versioned, hashed artifact passes staging, real-browser smoke, and gradual rollout when appropriate; release commit, generator, seeds, manifest, and protocol are traceable.
714
+
715
+ ---
716
+
717
+ ## Sources and references
718
+
719
+ - HTML Canvas: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API
720
+ - WebGL: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API
721
+ - WebGPU: https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API
722
+ - WebGPU specification: https://www.w3.org/TR/webgpu/
723
+ - Phaser: https://phaser.io/
724
+ - PixiJS: https://pixijs.com/
725
+ - Three.js: https://threejs.org/
726
+ - Babylon.js: https://www.babylonjs.com/
727
+ - PlayCanvas: https://playcanvas.com/
728
+ - Godot Web export: https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html
729
+ - TypeScript: https://www.typescriptlang.org/
730
+ - Vite: https://vite.dev/
731
+ - Web Audio API: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
732
+ - Gamepad API: https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API
733
+ - Pointer Lock API: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API
734
+ - WebSockets API: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
735
+ - WebRTC API: https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API
736
+ - WebAssembly: https://webassembly.org/
737
+ - Rust and WebAssembly: https://rustwasm.github.io/docs/book/
738
+ - Emscripten: https://emscripten.org/
739
+ - Progressive Web Apps: https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps
740
+ - Service Worker API: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
741
+ - web.dev — Ready Player Web: https://web.dev/articles/ready-player-web
742
+ - Web performance: https://web.dev/performance/
743
+ - Can I Use: https://caniuse.com/
744
+ - Vitest: https://vitest.dev/
745
+ - fast-check: https://fast-check.dev/
746
+ - Playwright: https://playwright.dev/
747
+ - axe-core: https://github.com/dequelabs/axe-core
748
+ - WCAG 2.2: https://www.w3.org/TR/WCAG22/
749
+ - Game Accessibility Guidelines (complementary community guidance, not a standard and not a replacement for WCAG): https://gameaccessibilityguidelines.com/
750
+ - OWASP Cheat Sheet Series: https://cheatsheetseries.owasp.org/
751
+ - MDN Web Docs — Web APIs: https://developer.mozilla.org/en-US/docs/Web/API