بنقرة واحدة
jgengine-verify
Scene truth is data. Invoke before verifying anything works or renders.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Scene truth is data. Invoke before verifying anything works or renders.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Main skill — intake, foundation, and routing for JGengine games.
Game-first HUDs, menus, touch controls, motion, accessibility, art direction, and visual verification.
Invoke on any mechanical leg — verify, ship, scout, sweep. Standing authorization.
Rebuild a one-model agent as orchestrator plus cheap workers. Invoke to cut cost.
Do any task in this repo AND leave the engine better than you found it. Same harvest instinct as harvest-game/harvest-full-game — but the carrier isn't a game, it's whatever task you were given (a fix, a feature, a refactor, a question, a doc pass). Complete the task, and treat every gap, friction, workaround, and doc error you hit along the way as an engine-improvement opportunity to close now or file. Invoke with the task, or nothing to have the standing gap list picked from.
| name | jgengine-verify |
| description | Scene truth is data. Invoke before verifying anything works or renders. |
A JGengine scene is derived deterministically from an environment() descriptor by pure @jgengine/core world-gen. That means "does the world render correctly" is a question about data, not pixels — and data is asserted in bun test in milliseconds, with no GPU. The browser screenshot only uniquely proves look (shader, material, color, framing), and it is the flakiest, slowest step in the repo. So verification runs in this order, and stops as soon as the cheap gates catch the bug.
bun run check-types — the change compiles across the affected packages. Type-green says nothing about whether the scene has content; it is necessary, not sufficient.bun test packages — pure game math (curves, cooldowns, spawn logic) and world content. This is where scene correctness is proven:
environment() world, a co-located <game>.world.test.ts calls summarizeEnvironment(world) (@jgengine/core/world/environmentSummary) and asserts the counts. summarizeEnvironment resolves the descriptor through the same core world-gen the renderer runs — building counts + part geometry + union bounds, terrain height stats (min/max/mean/finite) plus the resolved terrain palette (low/high/waterline), and water/vegetation/weather presence plus each structure group's resolved style + palette — plus an isEmpty flag.isEmpty), wrong building count, dropped feature, flat or NaN terrain (height.finite === false, or max === min when relief was expected), or a game left on the engine's untouched look (terrain.palette/structures[].palette still matching the default material: "grass" / style: "generic" instead of this game's own choice) — the identical-worlds bug the material/style unions exist to prevent.bun run shoot <game> --mode ui (HUD) / --mode play (full scene) — only for what the tests above cannot assert: the look. This is a final human glance you take once and open the PNG to judge (per jgengine-ui's quality bar). It is not the loop you iterate against. The HUD is responsive (HudCanvas/HudPanel scale, chip, and re-flow on phone-scale displays), so the glance includes a mobile shot alongside the desktop one — bun run shoot <game> --device mobile --mode play (and --mode ui where the HUD is the point) — confirming chips/hides land and nothing overflows a 390px viewport. --device both (desktop 1600×900 + mobile 390×844 PNGs) does both in one run; default is desktop. Implementation: system Chrome + raw CDP; page sets data-jg-capture=ready (tiny handshake, no PNG/base64 in-page); host Page.captureScreenshot writes binary to shots/. Optional --connect <port> attaches to an already-running Chrome with remote debugging.jgengine-world): sky preset day when brightness matters (dusk/night ignore sunIntensity overrides), a forward (+Z) landmark in frame, readable play-surface colors, props scaled as figures. Fix world/sky/placement before the first shoot — do not discover murk and bad framing across four screenshot loops.shoot hangs, do not re-run it in the foreground. Chrome/CDP on heavy WebGL scenes can hang, crash the GPU/tab, or emit corrupt output. Re-running the identical command is the rake this repo steps on repeatedly. If a shot hangs once: report it, fall back to the world test to prove the scene resolved, and only retry the screenshot if the user asks.summarizeEnvironment + git archaeology is how you confirm behavior — not a screenshot.fan-out skill — never check-types / bun test / shoot on the frontier model. You only judge the PNG and failing assertions.A game with a declared world exports its environment() feature and asserts on it:
// <game>/src/game/world.world.test.ts — under src/game/, never at the top of src/ (check-game-shape rejects extra files there)
import { describe, expect, test } from "bun:test";
import { summarizeEnvironment } from "@jgengine/core/world/environmentSummary";
import { world } from "../world"; // the environment() feature
describe("<game> world", () => {
const summary = summarizeEnvironment(world);
test("renders a populated scene", () => expect(summary.isEmpty).toBe(false));
test("has the expected content", () => {
expect(summary.counts.buildings).toBe(6);
expect(summary.terrain?.height.finite).toBe(true);
});
test("uses this game's own look, not the engine defaults", () => {
expect(summary.terrain?.palette.low).not.toBe("#30402c"); // untouched "grass" default
expect(summary.structures[0]?.palette.wall).not.toBe("#83766a"); // untouched "generic" default
});
});
If the game's world is biomes() / voxel() / flat() rather than environment(), summarizeEnvironment does not apply — assert on that world's own generator output (region field, voxel seed) with the same "resolve the data, assert the counts" pattern, still browserless.
For a voxel game built on @jgengine/core/world/voxelField's createVoxelField, assert on field.summary() ({ blocks, types, bounds }) the same way an environment() world asserts on summarizeEnvironment:
// <game>/src/game/world.world.test.ts — under src/game/, never at the top of src/ (check-game-shape rejects extra files there)
import { describe, expect, test } from "bun:test";
import { world } from "../world"; // the populated VoxelField
describe("<game> voxel world", () => {
const summary = world.summary();
test("renders a populated scene", () => expect(summary.blocks).toBeGreaterThan(0));
test("has the expected block types", () => {
expect(summary.types).toContain("stone");
expect(summary.bounds).not.toBeNull();
});
});
Every game ships src/preview.tsx: the default export is a static default frame (the website card), and an optional states named export (GamePreviewStates from @jgengine/react/preview) maps state keys — stage_1, game_over, normal_chest:opened — to components. State components SHOULD compose the game's real UI components (Hud, Overlays, result screens) fed with canned fixture snapshots, not a hand-drawn facsimile: a facsimile only tests the drawing, while real components with fixture state make each key a genuine render test of the UI the player sees.
Capture is bun run shoot <game> --preview <stateKey> (bare --preview or --mode preview = default frame), which drives /?game=<id>&preview=<stateKey> in the dev runner. That URL mounts only the resolved preview component — no sim, no three.js, no GamePlayerShell — so it renders in milliseconds, never hangs on WebGL, and fires the same data-jg-capture handshake. Output lands at shots/<game>-preview-<state>.png. An unknown state key fails fast with the list of available keys. Reach for --preview before --mode ui/--mode play whenever the question is "does this UI state render right" — the full-shell modes remain only for live-scene look and integration.
The numbered jgengine intake defines the observable target; this skill proves it after implementation.