From d83f2155eb4147fbd68ac9d970098517f233fae6 Mon Sep 17 00:00:00 2001 From: NoisemakerJon <139656120+Noisemaker111@users.noreply.github.com> Date: Fri, 23 Oct 2026 22:51:03 -0400 Subject: [PATCH 1/2] A drive step can aim: moveMouse, look and aimAt move the real crosshair Proved on Scrap Signal: firing at the spawn crosshair leaves the staged Foreman at 217/420, a 300px look puts the crosshair on it, and the same hold drops it to 208. --- .claude/skills/jgengine-verify/SKILL.md | 1 + .../src/templates/captureArgs.test.ts | 26 +++ .../jgengine/src/templates/captureArgs.ts | 33 ++- .../jgengine/src/templates/driveAim.test.ts | 133 +++++++++++ packages/jgengine/src/templates/driveAim.ts | 209 ++++++++++++++++++ packages/jgengine/src/templates/gameFiles.ts | 21 ++ scripts/drive-dev.ts | 26 +++ 7 files changed, 446 insertions(+), 3 deletions(-) create mode 100644 packages/jgengine/src/templates/driveAim.test.ts create mode 100644 packages/jgengine/src/templates/driveAim.ts diff --git a/.claude/skills/jgengine-verify/SKILL.md b/.claude/skills/jgengine-verify/SKILL.md index 5b92935b6..4db5b741d 100644 --- a/.claude/skills/jgengine-verify/SKILL.md +++ b/.claude/skills/jgengine-verify/SKILL.md @@ -41,6 +41,7 @@ Classify each acceptance claim before scheduling proof. A plan that uses screens - `GameHost` publishes declared `capture.probe` as `window.__jgProbe` after game initialization and staging. Reads use the live context; replacement/unmount retires the hook. An absent or throwing probe supplies no progress evidence. - Placeholder-vs-authored: `debug_snapshot().probes.fallbacks` reports which render seams resolved to fallbacks (green ground, primitive actors, proxy scatter) and why — a non-empty count proves content is unauthored/misconfigured rather than an intended placeholder. `probes.textureErrors` (`{ url, count }[]`) is its twin for the failure `fallbacks` cannot see: a model that resolves but whose GLB textures 404 — a non-empty list is a visibly-broken (untextured) scene, treat it exactly like a model fallback. - Portable `drive --click-at x,y` sends trusted native left-click input to a canvas or control in CSS viewport pixels. Steps preserve argument order; coordinates must be finite, nonnegative and strictly inside the selected device or overridden viewport (mobile DPR does not multiply them). Use the game’s visible world target; coordinate clicking does not project an entity id, run a game command directly, or advance fixed simulation time. Older project-owned `scripts/drive.mjs` keep their installed behavior; update the scaffold harness to use this option. +- Aiming in a step file: `{ "moveMouse": [x, y] }` hovers the pointer at viewport pixels, `{ "look": [dx, dy] }` turns a pointer-locked view by that mouse movement (the step takes pointer lock on the play canvas inside a CDP user gesture, so it never fires the weapon), and `{ "aimAt": "" }` turns until the target's `{x,y}` projection sits on the crosshair within `tolerancePx` (default 6), measuring the page's own response instead of assuming a sensitivity. A shooter proof asserts the arrival every time — a shot before the aim that leaves `capture.probe` health flat, then a shot after it that drops it — because "fired six taps" proves only that the trigger works. - A route a proof needs once belongs in `/proofs/flows/.json`, not copied into every proof: `bun run drive --flow ` runs it, `--flows` lists each name with its step count and asserts, and `{ "flow": "" }` includes it (4 levels deep, a repeated name is a cycle). A flow asserts arrival — the match started, N units present — because a flow that only clicks proves nothing. Every step prints one line and `--log ` writes JSONL, so a failed run names the step, the expected and actual value, and stops before the next screenshot. - UI-flow logic (a command/intent handler, not its pixels): drive it canvas-free with `createHeadlessRunner(...).ui.invoke("intent.name", input)`, then assert the resulting reactive state off `ctx` (store, stats, scene). No renderer, no pointer simulation — leave pixels to `shoot`; prove the logic headlessly. - Play itself, as a script: `bun run simulate