@bitmagic/cli 0.1.51 → 0.1.52-dev.1

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 (40) hide show
  1. package/README.md +3 -1
  2. package/dist/browser-gl.d.ts +46 -8
  3. package/dist/browser-gl.js +54 -26
  4. package/dist/browser-gl.js.map +1 -1
  5. package/dist/cli.d.ts +18 -0
  6. package/dist/cli.js +2 -0
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/forge.d.ts +5 -0
  9. package/dist/commands/forge.js +10 -1
  10. package/dist/commands/forge.js.map +1 -1
  11. package/dist/commands/init.js +19 -12
  12. package/dist/commands/init.js.map +1 -1
  13. package/dist/commands/judge.d.ts +41 -0
  14. package/dist/commands/judge.js +209 -0
  15. package/dist/commands/judge.js.map +1 -0
  16. package/dist/commands/reset-account.js +2 -8
  17. package/dist/commands/reset-account.js.map +1 -1
  18. package/dist/commands/verify.js +3 -3
  19. package/dist/commands/verify.js.map +1 -1
  20. package/dist/judge/facts.d.ts +18 -0
  21. package/dist/judge/facts.js +165 -0
  22. package/dist/judge/facts.js.map +1 -0
  23. package/dist/judge/record.d.ts +16 -0
  24. package/dist/judge/record.js +55 -0
  25. package/dist/judge/record.js.map +1 -0
  26. package/dist/judge/stream.d.ts +36 -0
  27. package/dist/judge/stream.js +122 -0
  28. package/dist/judge/stream.js.map +1 -0
  29. package/dist/project/jobs.d.ts +1 -1
  30. package/dist/scaffold/project-files.d.ts +8 -0
  31. package/dist/scaffold/project-files.js +83 -13
  32. package/dist/scaffold/project-files.js.map +1 -1
  33. package/dist/scaffold/project.js +2 -1
  34. package/dist/scaffold/project.js.map +1 -1
  35. package/dist/verify/browser.d.ts +11 -6
  36. package/dist/verify/browser.js +31 -15
  37. package/dist/verify/browser.js.map +1 -1
  38. package/dist/verify/iterate.js +3 -3
  39. package/dist/verify/iterate.js.map +1 -1
  40. package/package.json +4 -4
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The client for `POST /api/cli/v1/judge/stream` — one vision call that grades
3
+ * the verify screenshot(s) against a rubric and returns a scorecard.
4
+ *
5
+ * Mirrors `forge/stream.ts` in shape (same SSE plumbing, same pre-stream
6
+ * status mapping, same "a truncated stream is not a confirmed failure"
7
+ * discipline), but far simpler: there is no job to resume — a judge run that
8
+ * dies is simply re-run — and the terminal payload is
9
+ * `{ success, scorecard, model, sparks }`.
10
+ */
11
+ import { type JudgeScorecard } from '@bitmagic/asset-core';
12
+ import type { Environment } from '../config/environments.js';
13
+ export interface JudgeSuccess {
14
+ success: true;
15
+ scorecard: JudgeScorecard;
16
+ model: string;
17
+ sparks: number;
18
+ }
19
+ export interface JudgeFailure {
20
+ success: false;
21
+ message: string;
22
+ sparks: number;
23
+ }
24
+ export type JudgeOutcome = JudgeSuccess | JudgeFailure;
25
+ export interface JudgeStreamDeps {
26
+ fetch: typeof globalThis.fetch;
27
+ /** Called for every progress frame the server sends (there are few). */
28
+ onProgress: (message: string) => void;
29
+ }
30
+ /**
31
+ * POSTs the rubric + screenshot(s) and consumes the SSE response. A stream
32
+ * that closes with no terminal frame is a truncated connection, not a
33
+ * confirmed failure — nothing is saved server-side, so the remedy is simply
34
+ * to run the command again.
35
+ */
36
+ export declare function requestJudge(environment: Environment, accessToken: string, body: Record<string, unknown>, deps: JudgeStreamDeps): Promise<JudgeOutcome>;
@@ -0,0 +1,122 @@
1
+ /**
2
+ * The client for `POST /api/cli/v1/judge/stream` — one vision call that grades
3
+ * the verify screenshot(s) against a rubric and returns a scorecard.
4
+ *
5
+ * Mirrors `forge/stream.ts` in shape (same SSE plumbing, same pre-stream
6
+ * status mapping, same "a truncated stream is not a confirmed failure"
7
+ * discipline), but far simpler: there is no job to resume — a judge run that
8
+ * dies is simply re-run — and the terminal payload is
9
+ * `{ success, scorecard, model, sparks }`.
10
+ */
11
+ import { judgeScorecardSchema } from '@bitmagic/asset-core';
12
+ import { CliError } from '../errors.js';
13
+ import { consumeSseStream } from '../http/sse.js';
14
+ import { isSpillConsentRefusal, sparkRefusalCode, spillConsentMessage } from '../http/spark-refusal.js';
15
+ import { apiServerHeaders } from '../telemetry/request-headers.js';
16
+ function isRecord(value) {
17
+ return typeof value === 'object' && value !== null;
18
+ }
19
+ /** Map a pre-stream error status to the message a creator can act on. */
20
+ async function toCliError(response, gameId) {
21
+ const body = await response
22
+ .json()
23
+ .then((parsed) => (isRecord(parsed) ? parsed : {}))
24
+ .catch(() => ({}));
25
+ const serverMessage = typeof body.error === 'string' && body.error.length > 0 ? body.error : null;
26
+ if (response.status === 403) {
27
+ return new CliError(serverMessage ?? `You cannot judge game "${gameId}".`);
28
+ }
29
+ if (response.status === 402) {
30
+ const code = sparkRefusalCode(body);
31
+ if (isSpillConsentRefusal(body)) {
32
+ return new CliError(spillConsentMessage('a judge run'), 1, code);
33
+ }
34
+ const { balance, required } = body;
35
+ const detail = typeof balance === 'number' && typeof required === 'number'
36
+ ? ` You have ${balance} sparks; a judge run requires at least ${required}.`
37
+ : '';
38
+ return new CliError(`Not enough sparks to run the judge.${detail}`, 1, code);
39
+ }
40
+ if (response.status === 400) {
41
+ return new CliError(serverMessage ?? 'The server rejected this judge request.');
42
+ }
43
+ return new CliError(`api-server returned HTTP ${response.status} starting the judge`
44
+ + (serverMessage ? `: ${serverMessage}.` : '.'));
45
+ }
46
+ /**
47
+ * POSTs the rubric + screenshot(s) and consumes the SSE response. A stream
48
+ * that closes with no terminal frame is a truncated connection, not a
49
+ * confirmed failure — nothing is saved server-side, so the remedy is simply
50
+ * to run the command again.
51
+ */
52
+ export async function requestJudge(environment, accessToken, body, deps) {
53
+ const gameId = typeof body.gameId === 'string' ? body.gameId : '(unknown game)';
54
+ const url = `${environment.apiUrl}/api/cli/v1/judge/stream`;
55
+ let response;
56
+ try {
57
+ response = await deps.fetch(url, {
58
+ method: 'POST',
59
+ headers: {
60
+ ...apiServerHeaders(),
61
+ Authorization: `Bearer ${accessToken}`,
62
+ Accept: 'text/event-stream',
63
+ 'Content-Type': 'application/json',
64
+ },
65
+ body: JSON.stringify(body),
66
+ });
67
+ }
68
+ catch {
69
+ throw new CliError(`Cannot reach api-server at ${environment.apiUrl}.`, 1, 'unreachable');
70
+ }
71
+ if (!response.ok) {
72
+ throw await toCliError(response, gameId);
73
+ }
74
+ if (!response.body) {
75
+ throw new CliError('The server accepted the judge request but returned no stream body.');
76
+ }
77
+ let outcome = null;
78
+ const onEvent = (event) => {
79
+ if (event.event === 'progress') {
80
+ const message = isRecord(event.data) && typeof event.data.message === 'string'
81
+ ? event.data.message
82
+ : null;
83
+ if (message !== null)
84
+ deps.onProgress(message);
85
+ return false;
86
+ }
87
+ if (event.event === 'result') {
88
+ const data = isRecord(event.data) ? event.data : {};
89
+ // Validated HERE, not trusted: `.bitmagic/judge.json` promises a
90
+ // schema-valid scorecard to whoever reads it, and the shared schema is
91
+ // exactly what makes that promise checkable on both sides of the wire.
92
+ const scorecard = judgeScorecardSchema.safeParse(data.scorecard);
93
+ if (data.success === true && scorecard.success) {
94
+ outcome = {
95
+ success: true,
96
+ scorecard: scorecard.data,
97
+ model: typeof data.model === 'string' ? data.model : '(unknown)',
98
+ sparks: typeof data.sparks === 'number' ? data.sparks : 0,
99
+ };
100
+ return true;
101
+ }
102
+ return false;
103
+ }
104
+ if (event.event === 'error') {
105
+ const data = isRecord(event.data) ? event.data : {};
106
+ outcome = {
107
+ success: false,
108
+ message: typeof data.message === 'string' ? data.message : 'The judge failed without reporting a reason.',
109
+ sparks: typeof data.sparks === 'number' ? data.sparks : 0,
110
+ };
111
+ return true;
112
+ }
113
+ return false;
114
+ };
115
+ const sawTerminal = await consumeSseStream(response.body, onEvent);
116
+ if (!sawTerminal || outcome === null) {
117
+ throw new CliError('The connection dropped before the judge finished — this is not a confirmed failure. '
118
+ + 'Nothing is saved server-side; run `bitmagic judge` again.');
119
+ }
120
+ return outcome;
121
+ }
122
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/judge/stream.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { ForgeProgressSnapshot } from '../forge/progress.js';
2
2
  import type { ForgeLayoutMap } from '@bitmagic/world-forger/pipeline/index.js';
3
3
  /** Which command is running. Shown as-is in the dev view, so these are creator-facing words. */
4
- export type JobKind = 'skybox' | 'sound' | 'image' | 'character' | 'animation' | 'prop' | 'vehicle' | 'forge' | 'cover' | 'hq';
4
+ export type JobKind = 'skybox' | 'sound' | 'image' | 'character' | 'animation' | 'prop' | 'vehicle' | 'forge' | 'cover' | 'hq' | 'judge';
5
5
  export interface JobRecord {
6
6
  jobId: string;
7
7
  kind: JobKind;
@@ -125,6 +125,14 @@ export declare function renderGenerateSkill(): string;
125
125
  * check first can say "this will take most of what is left" before it burns it.
126
126
  */
127
127
  export declare function renderUsageSkill(): string;
128
+ /**
129
+ * `.claude/skills/judging-quality/SKILL.md` — when and how to run `bitmagic judge`.
130
+ *
131
+ * The point the skill has to land is the discipline, not the mechanics: judge after milestones,
132
+ * fix the findings, confirm once, stop. An agent that loops on the judge is spending the
133
+ * creator's sparks on reassurance.
134
+ */
135
+ export declare function renderJudgeSkill(): string;
128
136
  /**
129
137
  * `GAME-DESIGN.md` — the project's design document, and the input `bitmagic cover` builds its
130
138
  * image prompt from. The web lane's Planning Mode writes a file of the same name for the same
@@ -83,12 +83,23 @@ function esmUrl(name) {
83
83
  return `https://esm.sh/${name}@${pinnedVersion(name)}`;
84
84
  }
85
85
  /**
86
- * The three.js release every `three*` import map entry below resolves to. Named once because
87
- * the entries repeat it eight times, including four times inside the `three` shim, and a bump
86
+ * The three.js CDN base every `three*` import map entry below is built from. Named once because
87
+ * the entries restate it a dozen times over, four of them inside the `three` shim, and a bump
88
88
  * that updates some copies but not others splits the engine across two module instances — the
89
89
  * exact failure the comments below describe.
90
90
  */
91
- const THREE_VERSION = pinnedVersion('three');
91
+ const THREE_CDN = esmUrl('three');
92
+ /**
93
+ * esm.sh's `*` build of the same release. Only the addon entries use it — the note on them in
94
+ * `CDN_IMPORTS` says why, and why nothing else may.
95
+ */
96
+ const THREE_CDN_EXTERNAL = `https://esm.sh/*three@${pinnedVersion('three')}`;
97
+ /**
98
+ * The ONE webgpu build both `three` (through the shim) and `three/webgpu` resolve to. Derived
99
+ * from a single constant rather than written twice, because the two being byte-identical is what
100
+ * keeps them one module instance — see the shim below.
101
+ */
102
+ const THREE_WEBGPU = `${THREE_CDN}/webgpu`;
92
103
  /**
93
104
  * `three` resolves to a shim, not straight to the webgpu build. r185's three.webgpu.js exports
94
105
  * neither `UniformsUtils` (which every classic postprocessing pass imports from `three`) nor
@@ -101,10 +112,10 @@ const THREE_VERSION = pinnedVersion('three');
101
112
  */
102
113
  const THREE_SHIM = [
103
114
  'data:text/javascript,',
104
- `export*from'https://esm.sh/three@${THREE_VERSION}/webgpu';`,
105
- `export{UniformsUtils}from'https://esm.sh/three@${THREE_VERSION}/src/renderers/shaders/UniformsUtils.js';`,
106
- `export{ShaderLib}from'https://esm.sh/three@${THREE_VERSION}/src/renderers/shaders/ShaderLib.js';`,
107
- `export{UniformsLib}from'https://esm.sh/three@${THREE_VERSION}/src/renderers/shaders/UniformsLib.js'`,
115
+ `export*from'${THREE_WEBGPU}';`,
116
+ `export{UniformsUtils}from'${THREE_CDN}/src/renderers/shaders/UniformsUtils.js';`,
117
+ `export{ShaderLib}from'${THREE_CDN}/src/renderers/shaders/ShaderLib.js';`,
118
+ `export{UniformsLib}from'${THREE_CDN}/src/renderers/shaders/UniformsLib.js'`,
108
119
  ].join('');
109
120
  /**
110
121
  * Resolved in the browser from a CDN, not from node_modules — see the design's import-map note.
@@ -117,17 +128,17 @@ export const CDN_IMPORTS = {
117
128
  // builds (core + webgpu) they are two, and r185's LightsNode then fails to recognise lights
118
129
  // built by the other instance — the scene renders unlit. Keep in step with game/index.html.
119
130
  three: THREE_SHIM,
120
- 'three/webgpu': `https://esm.sh/three@${THREE_VERSION}/webgpu`,
121
- 'three/tsl': `https://esm.sh/three@${THREE_VERSION}/tsl`,
131
+ 'three/webgpu': THREE_WEBGPU,
132
+ 'three/tsl': `${THREE_CDN}/tsl`,
122
133
  // The addon entries use esm.sh's `*` build, which keeps `three` a BARE specifier so addons
123
134
  // resolve back through this map. Plain esm.sh inlines its own copy of three, which shares no
124
135
  // module with the webgpu build: GLTFLoader then hands back Meshes from a second Mesh class and
125
136
  // the engine's `instanceof THREE.Mesh` scans find nothing. Same one-instance rule as above.
126
137
  // The classic WebGL addons are not excepted — the shim, not a pinned inlined-three build, is
127
138
  // what gives them the UniformsUtils / ShaderLib / UniformsLib they import from bare `three`.
128
- 'three/addons/': `https://esm.sh/*three@${THREE_VERSION}/addons/`,
129
- 'three/examples/jsm/': `https://esm.sh/*three@${THREE_VERSION}/examples/jsm/`,
130
- 'three/': `https://esm.sh/three@${THREE_VERSION}/`,
139
+ 'three/addons/': `${THREE_CDN_EXTERNAL}/addons/`,
140
+ 'three/examples/jsm/': `${THREE_CDN_EXTERNAL}/examples/jsm/`,
141
+ 'three/': `${THREE_CDN}/`,
131
142
  '@dimforge/rapier3d-compat': esmUrl('@dimforge/rapier3d-compat'),
132
143
  '@dimforge/rapier2d-compat': esmUrl('@dimforge/rapier2d-compat'),
133
144
  i18next: esmUrl('i18next'),
@@ -628,6 +639,7 @@ the two yaw conventions differ. Guessing produces code that compiles and moves t
628
639
  bitmagic check # typecheck against the vendored engine
629
640
  bitmagic reload # tell the open browser you have finished a round of edits
630
641
  bitmagic verify # boot the game in a real browser and report what broke
642
+ bitmagic judge # grade the verify screenshot against a quality rubric (paid, cheap)
631
643
  \`\`\`
632
644
 
633
645
  (\`bitmagic dev\` belongs at the START of the session — see the top of this file.)
@@ -646,6 +658,12 @@ compile that dies on load — a missing asset, a bad \`world.json\` value, a nul
646
658
  \`bitmagic verify\` after a change you cannot eyeball: it loads the game in a headless browser and
647
659
  fails with what actually broke, leaving a console log and a screenshot in \`.bitmagic/verify/\`.
648
660
 
661
+ **\`verify\` passing does not mean the game is good.** You built this game, so you are the wrong
662
+ judge of it. After each milestone run \`bitmagic verify\` (not \`--fast\`), then \`bitmagic judge\`:
663
+ a separate vision model grades the screenshot against \`GAME-DESIGN.md\` and prints at most three
664
+ concrete findings (also written to \`.bitmagic/judge.json\`). Fix the ones worth fixing, confirm
665
+ with one re-run, then move on — **never loop on the judge**. See the \`judging-quality/\` skill.
666
+
649
667
  ## The human may be moving objects too
650
668
 
651
669
  \`bitmagic dev\` serves one page with two tabs — **Game**, where the owner plays, and **Editor**,
@@ -1343,6 +1361,56 @@ game or prompt — the ledger records what was charged, not which change asked f
1343
1361
  per-invoice view, the plan page on the web is the source of truth.
1344
1362
  `;
1345
1363
  }
1364
+ /**
1365
+ * `.claude/skills/judging-quality/SKILL.md` — when and how to run `bitmagic judge`.
1366
+ *
1367
+ * The point the skill has to land is the discipline, not the mechanics: judge after milestones,
1368
+ * fix the findings, confirm once, stop. An agent that loops on the judge is spending the
1369
+ * creator's sparks on reassurance.
1370
+ */
1371
+ export function renderJudgeSkill() {
1372
+ return `---
1373
+ name: judging-quality
1374
+ description: Use after finishing a milestone — a mechanics-plan slice shipped, a level forged, a visual pass done — to get an independent quality verdict on the running game, or when asked whether the game looks good, what to polish next, or to review the game's quality.
1375
+ ---
1376
+
1377
+ # Judging the game's quality
1378
+
1379
+ \`\`\`bash
1380
+ bitmagic verify # first: captures the screenshot the judge grades (no --fast)
1381
+ bitmagic judge # one vision-model call; prints a scorecard, exits 0
1382
+ bitmagic judge --genre platformer # sharpen the rubric: platformer, racing, shooter, combat, driving, tower-defense
1383
+ bitmagic judge --min-score 7 # exit 4 when the overall score is below the bar
1384
+ bitmagic judge --json # the scorecard as one JSON document on stdout
1385
+ \`\`\`
1386
+
1387
+ You built this game, so you are the wrong judge of it. \`bitmagic judge\` sends the screenshot
1388
+ \`bitmagic verify\` captured, plus a rubric built from \`GAME-DESIGN.md\`, to a separate vision
1389
+ model and prints back four dimension scores (visual-quality, readability, design-fidelity, polish)
1390
+ and at most three findings — each naming what to change, most severe first. The scorecard is also
1391
+ written to \`.bitmagic/judge.json\`.
1392
+
1393
+ It is paid (sparks, roughly the cost of one small model call) and deliberate — which is why it is
1394
+ a command you run, not something verify does for you.
1395
+
1396
+ ## The loop, and where it stops
1397
+
1398
+ 1. Finish the milestone. Run \`bitmagic verify\` — the judge grades verify's screenshot, so a
1399
+ stale one gets you a verdict on the game you had yesterday (the command warns when so).
1400
+ 2. Run \`bitmagic judge\`. Read the findings.
1401
+ 3. Fix the ones worth fixing — they name the object or region and the change.
1402
+ 4. Re-run \`verify\`, then \`judge\` once to confirm the fixes landed.
1403
+ 5. **Stop.** Whatever the score now says, move on to the next milestone. Never run the judge a
1404
+ third time on the same milestone, and never chase a number — the findings are the product, the
1405
+ score is context.
1406
+
1407
+ ## When it refuses
1408
+
1409
+ - **No screenshot** — run \`bitmagic verify\` first, without \`--fast\` (which skips screenshots).
1410
+ - **Not enough sparks / spending not approved** — report it to the creator; see the
1411
+ \`checking-usage\` skill. Never enable spending yourself.
1412
+ `;
1413
+ }
1346
1414
  /**
1347
1415
  * `GAME-DESIGN.md` — the project's design document, and the input `bitmagic cover` builds its
1348
1416
  * image prompt from. The web lane's Planning Mode writes a file of the same name for the same
@@ -1394,7 +1462,8 @@ project root for the guidance an agent should read before editing this game.
1394
1462
 
1395
1463
  ## Which of these are yours
1396
1464
 
1397
- \`planning-a-game/\`, \`finding-engine-apis/\`, \`generating-assets/\`, \`checking-usage/\` — and
1465
+ \`planning-a-game/\`, \`finding-engine-apis/\`, \`generating-assets/\`, \`checking-usage/\`,
1466
+ \`judging-quality/\` — and
1398
1467
  this README — are shipped by the Bitmagic CLI and **re-rendered by \`bitmagic upgrade\`**. They
1399
1468
  describe what the CLI and the engine can do, so they have to stay current with both; edits to them
1400
1469
  are lost on the next upgrade.
@@ -1405,6 +1474,7 @@ are lost on the next upgrade.
1405
1474
  | \`finding-engine-apis/\` | you need an engine API and do not know its name or signature, or \`bitmagic check\` cannot resolve a symbol |
1406
1475
  | \`generating-assets/\` | the game needs a skybox, sound, image, character, animation or vehicle |
1407
1476
  | \`checking-usage/\` | asked what sparks were spent on, how much Pro allowance is left, or whether there is enough left to keep generating |
1477
+ | \`judging-quality/\` | a milestone is done and the game deserves an independent quality verdict — \`bitmagic judge\` |
1408
1478
 
1409
1479
  Every other directory here is yours. \`upgrade\` never opens a skill it does not ship, and never
1410
1480
  deletes anything under \`.claude/\`. Put project-specific guidance in a skill of your own, or in
@@ -1 +1 @@
1
- {"version":3,"file":"project-files.js","sourceRoot":"","sources":["../../src/scaffold/project-files.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project-files.js","sourceRoot":"","sources":["../../src/scaffold/project-files.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { CliError } from '../errors.js';
4
4
  import { aliasSourceDir } from './aliases.js';
5
- import { renderPackageJson, renderTsconfig, renderIndexHtml, renderViteConfig, renderVitePublishConfig, renderGitignore, renderBitmagicJson, renderAgentsMd, renderGameDesignMd, renderClaudeMd, renderSkillsReadme, renderGenerateSkill, renderPlanningSkill, renderEngineApiSkill, renderUsageSkill, } from './project-files.js';
5
+ import { renderPackageJson, renderTsconfig, renderIndexHtml, renderViteConfig, renderVitePublishConfig, renderGitignore, renderBitmagicJson, renderAgentsMd, renderGameDesignMd, renderClaudeMd, renderJudgeSkill, renderSkillsReadme, renderGenerateSkill, renderPlanningSkill, renderEngineApiSkill, renderUsageSkill, } from './project-files.js';
6
6
  import { hashAgentsMd } from './agents-md.js';
7
7
  import { CLAUDE_SETTINGS_FILE, renderClaudeSettings } from './claude-settings.js';
8
8
  /**
@@ -160,6 +160,7 @@ export const PLATFORM_GENERATED_FILES = [
160
160
  ['.claude/skills/planning-a-game/SKILL.md', renderPlanningSkill],
161
161
  ['.claude/skills/finding-engine-apis/SKILL.md', renderEngineApiSkill],
162
162
  ['.claude/skills/checking-usage/SKILL.md', renderUsageSkill],
163
+ ['.claude/skills/judging-quality/SKILL.md', renderJudgeSkill],
163
164
  ];
164
165
  /**
165
166
  * Every template the downloaded bundle carries, in index order.
@@ -1 +1 @@
1
- {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/scaffold/project.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/scaffold/project.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type RendererChoice } from '../browser-gl.js';
1
+ import { type BrowserLaunchPlan, type RendererChoice } from '../browser-gl.js';
2
2
  import { type VerifyObservations } from './classify.js';
3
3
  export interface StartInteractionOptions {
4
4
  /** Selector for the engine Play button. Its label is localizable and per-game overridable, so
@@ -46,11 +46,16 @@ export interface HeadlessCheckOptions {
46
46
  */
47
47
  requestedRenderer?: RendererChoice;
48
48
  /**
49
- * Chrome launch args. Defaults to `browserGlArgs(process.env)` callers that boot a specific
50
- * renderer pass `browserRendererArgs(...)` instead, and the software-GL retry passes the
51
- * software set. `--mute-audio` is always added here, not by callers.
49
+ * How to launch Chrome: headless or headed, and with which args. Callers that boot a specific
50
+ * renderer pass a `browserLaunchPlan(...)` (the software-GL retry passes a
51
+ * `softwareGlLaunchPlan(...)`); the headed variant only ever happens for WebGPU on a Linux
52
+ * machine with a display, where headless Chrome either screenshots black or never yields a
53
+ * WebGPU adapter (see browser-gl.ts).
54
+ *
55
+ * Optional so `publish`'s smoke check keeps launching exactly as before: headless with
56
+ * `browserGlArgs(process.env)`. `--mute-audio` is always added here, not by callers.
52
57
  */
53
- browserArgs?: string[];
58
+ launch?: BrowserLaunchPlan;
54
59
  /**
55
60
  * Capture the screenshot and measure its pixels (default true). `bitmagic verify --fast`
56
61
  * turns this off for the inner loop: `screenshotBytes`/`canvasFrame` come back null and
@@ -75,7 +80,7 @@ export declare function runHeadlessCheck(options: HeadlessCheckOptions): Promise
75
80
  export declare class VerifyBrowserSession {
76
81
  private readonly browser;
77
82
  private constructor();
78
- static launch(browserArgs?: string[]): Promise<VerifyBrowserSession>;
83
+ static launch(plan?: BrowserLaunchPlan): Promise<VerifyBrowserSession>;
79
84
  close(): Promise<void>;
80
85
  check(options: HeadlessCheckOptions): Promise<VerifyObservations>;
81
86
  }
@@ -16,7 +16,7 @@ export const DEFAULT_START_INTERACTION = {
16
16
  * browser rather than a downloaded one, so installing the CLI stays a small, fast npm install.
17
17
  */
18
18
  export async function runHeadlessCheck(options) {
19
- const session = await VerifyBrowserSession.launch(options.browserArgs);
19
+ const session = await VerifyBrowserSession.launch(options.launch);
20
20
  try {
21
21
  return await session.check(options);
22
22
  }
@@ -37,7 +37,8 @@ export class VerifyBrowserSession {
37
37
  constructor(browser) {
38
38
  this.browser = browser;
39
39
  }
40
- static async launch(browserArgs) {
40
+ static async launch(plan) {
41
+ const { headless, args } = plan ?? { headless: true, args: browserGlArgs(process.env) };
41
42
  try {
42
43
  // `--mute-audio` because headless Chrome still plays sound through the machine's speakers:
43
44
  // without it every verify run blares the game's music and effects at whoever is sitting
@@ -45,9 +46,9 @@ export class VerifyBrowserSession {
45
46
  // on a machine with a perfectly good GPU, and a run that should take seconds crawls
46
47
  // (browser-gl.ts).
47
48
  return new VerifyBrowserSession(await chromium.launch({
48
- headless: true,
49
+ headless,
49
50
  channel: 'chrome',
50
- args: ['--mute-audio', ...(browserArgs ?? browserGlArgs(process.env))],
51
+ args: ['--mute-audio', ...args],
51
52
  }));
52
53
  }
53
54
  catch {
@@ -108,9 +109,10 @@ export class VerifyBrowserSession {
108
109
  // Same probe either way; only the frame it runs in differs. A missing child frame leaves
109
110
  // `target` null, which classifies as "no canvas" — correct, because a harness whose iframe
110
111
  // never loaded (a download, a 404) is exactly the failure this mode exists to catch.
111
- const target = options.probeFrameUrlIncludes === undefined
112
+ const frameUrlIncludes = options.probeFrameUrlIncludes;
113
+ const target = frameUrlIncludes === undefined
112
114
  ? page
113
- : page.frames().find((frame) => frame.url().includes(options.probeFrameUrlIncludes)) ?? null;
115
+ : page.frames().find((frame) => frame.url().includes(frameUrlIncludes)) ?? null;
114
116
  const canvas = target === null ? null : await target.evaluate(() => {
115
117
  // This callback runs inside the browser Playwright drives, not in the CLI's Node process,
116
118
  // so `document` is a real global there even though the CLI's eslint config declares no
@@ -155,12 +157,15 @@ export class VerifyBrowserSession {
155
157
  : target === null
156
158
  ? { requested: options.requestedRenderer, rendererType: null, backend: null }
157
159
  : await probeRenderer(target, options.requestedRenderer);
158
- const snapshot = options.startInteraction === undefined || target === null
160
+ // The engine probes below belong to verify's questions only, and need something to probe:
161
+ // no start interaction (publish's smoke check) or no frame leaves them unobserved.
162
+ const engineTarget = options.startInteraction === undefined ? null : target;
163
+ const snapshot = engineTarget === null
159
164
  ? undefined
160
- : await captureStateSnapshot(target, settleSamples);
161
- const events = options.startInteraction === undefined || target === null
165
+ : await captureStateSnapshot(engineTarget, settleSamples);
166
+ const events = engineTarget === null
162
167
  ? undefined
163
- : deriveEventsObservation(await captureEventTrace(target));
168
+ : deriveEventsObservation(await captureEventTrace(engineTarget));
164
169
  let start;
165
170
  if (options.startInteraction !== undefined && interaction !== null) {
166
171
  start = {
@@ -237,6 +242,13 @@ async function adaptiveSettle(page, consoleLines, maxMs) {
237
242
  }
238
243
  }
239
244
  }
245
+ /** What a settle sample carries when the page could not be asked at all. */
246
+ const UNOBSERVED_PROBE = {
247
+ frameCount: null,
248
+ gameState: null,
249
+ hasStarted: null,
250
+ playerY: null,
251
+ };
240
252
  /**
241
253
  * One poll of the live page. Every probe is feature-detected and the whole evaluate is wrapped
242
254
  * twice (in the page and out here): a page that cannot answer yields nulls, which
@@ -245,7 +257,6 @@ async function adaptiveSettle(page, consoleLines, maxMs) {
245
257
  */
246
258
  async function takeSettleSample(page, atMs, consoleLines) {
247
259
  const errorEventCount = consoleLines.filter((line) => line.startsWith('error:') || line.includes(RESPAWN_LINE)).length;
248
- const unobserved = { frameCount: null, gameState: null, hasStarted: null, playerY: null };
249
260
  try {
250
261
  const probed = await page.evaluate((flag) => {
251
262
  /* eslint-disable no-undef -- browser-side callback, see the canvas probe above. */
@@ -274,14 +285,14 @@ async function takeSettleSample(page, atMs, consoleLines) {
274
285
  return { frameCount, gameState, hasStarted, playerY };
275
286
  }
276
287
  catch {
277
- return { frameCount: null, gameState: null, hasStarted: null, playerY: null };
288
+ return null;
278
289
  }
279
290
  /* eslint-enable no-undef */
280
291
  }, FRAME_COUNT_FLAG);
281
- return { atMs, errorEventCount, ...probed };
292
+ return { atMs, errorEventCount, ...(probed ?? UNOBSERVED_PROBE) };
282
293
  }
283
294
  catch {
284
- return { atMs, errorEventCount, ...unobserved };
295
+ return { atMs, errorEventCount, ...UNOBSERVED_PROBE };
285
296
  }
286
297
  }
287
298
  /**
@@ -505,7 +516,12 @@ async function measureCanvasFrame(page, screenshot, rect) {
505
516
  const surface = document.createElement('canvas');
506
517
  surface.width = width;
507
518
  surface.height = height;
508
- const ctx = surface.getContext('2d');
519
+ // `willReadFrequently` is not a performance hint here — it is what makes this measurement
520
+ // work at all in the headed WebGPU mode (browser-gl.ts): with GPU compositing on, an
521
+ // accelerated 2D canvas `getImageData` reads back zeros on the same driver stacks that
522
+ // motivated that mode, and this flag forces the software canvas whose CPU readback the
523
+ // doc comment above already promises.
524
+ const ctx = surface.getContext('2d', { willReadFrequently: true });
509
525
  if (!ctx)
510
526
  return null;
511
527
  ctx.drawImage(image, left, top, width, height, 0, 0, width, height);