# Feedback comparison

Serve the repository and open [`/authoring/game-feel-lab/`](index.html). The two panes show the same deterministic six-second authored sequence through `createActorPresentation`, `drawPresentedActor`, `drawActiveTrail`, `drawTrailImpactFront` and `drawCapturePulse` from the game. No simulation, production binding, saved preference or replay is changed.

The reference enables all accents. The comparison independently controls capture pulses, actor motion accents and the moving trail packet. Reduced effects applies to both panes and begins with the browser's reduced-motion preference. It removes decoration without hiding the live line, cutting head, threat marker, contact ring, secured territory or stun state. The actor toggle removes banking, tails and moving surface parts; position, heading, collision cue and status are retained. Capture and stun are separate authored cues, not a claim that capture stuns enemies.

Play repeats exactly 360 authored ticks at 60 ticks/second. Pause, frame step, restart, cue buttons and the timeline support comparison at the same instant. Seeking uses cached frames built from fixed steps through the production sampler, so it does not bypass heading history with a large time delta. Leaving or hiding the page pauses playback, cancels the preview RAF and aborts any measurement. A BFCache return creates only one loop and requires Play; stale measurement completion cannot update the restored page. Terminal departure disposes the loop and listeners. The fixture starts paused and uses the shared Field Kit fonts.

Draw-cost measurement is opt-in and bounded to 20 warmups and 120 timed two-pane draws, yielding between cohorts. It uses `performance.now()` around Canvas drawing only; frame preparation and DOM updates are outside the timing. Median and p95 are local draw-call observations, not actual FPS, whole-game performance or device certification. The separate `width × height × 4` figure estimates two canvas pixel surfaces, not application, decoded-asset or GPU memory.

Dark pixel art remains the default. Explicitly choosing **Synevyr · licensed photograph** asynchronously loads the untouched local original and its [provenance record](../library/real-world-references/synevyr-lake-rafts.json): Jan Pešula (Sapfan), [Wikimedia Commons source](https://commons.wikimedia.org/wiki/File:Synevyr_Lake_rafts.jpg), [CC0](https://creativecommons.org/publicdomain/zero/1.0/). This photograph is a licensed authoring example, not a production mission or binding. Both panes contain-fit the whole image with letterboxing through secured cells only; unrevealed cells, pixel actors and essential cues remain. The original bytes are neither cropped nor rewritten. Attribution remains visible while selected.

Loading reports status immediately and retains the prior view until decoding succeeds; failure restores the selection to that view. The loader verifies source byte count and SHA-256 against provenance before decoding, then checks decoded dimensions. Changing the selection or leaving the page aborts pending work and closes decoded bitmaps, including late completions. Returning stays paused and requires explicit photo selection again. The photograph's decoded RGBA estimate (63,489,024 bytes) is shown separately from the canvas estimate and excludes decoder/browser/GPU copies. Draw timing excludes fetch/decode and names the background actually measured.

Run `node --test game/test/game-feel-lab.test.mjs` for fixed-tick/reset, layer independence, essential-cue, input-preservation, measurement-budget, lifecycle and photograph-selection checks. Browser review and human playtesting remain separate evidence. This fixture does not establish a full level's readability, enjoyment, audio/haptic behavior, campaign retention or public-release acceptance.
