@bitmagic/cli 0.1.52-dev.0 → 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.
- package/README.md +3 -1
- package/dist/browser-gl.d.ts +46 -8
- package/dist/browser-gl.js +54 -26
- package/dist/browser-gl.js.map +1 -1
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/forge.d.ts +5 -0
- package/dist/commands/forge.js +10 -1
- package/dist/commands/forge.js.map +1 -1
- package/dist/commands/init.js +19 -12
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/judge.d.ts +41 -0
- package/dist/commands/judge.js +209 -0
- package/dist/commands/judge.js.map +1 -0
- package/dist/commands/reset-account.js +2 -8
- package/dist/commands/reset-account.js.map +1 -1
- package/dist/commands/verify.js +3 -3
- package/dist/commands/verify.js.map +1 -1
- package/dist/judge/facts.d.ts +18 -0
- package/dist/judge/facts.js +165 -0
- package/dist/judge/facts.js.map +1 -0
- package/dist/judge/record.d.ts +16 -0
- package/dist/judge/record.js +55 -0
- package/dist/judge/record.js.map +1 -0
- package/dist/judge/stream.d.ts +36 -0
- package/dist/judge/stream.js +122 -0
- package/dist/judge/stream.js.map +1 -0
- package/dist/project/jobs.d.ts +1 -1
- package/dist/scaffold/project-files.d.ts +8 -0
- package/dist/scaffold/project-files.js +83 -13
- package/dist/scaffold/project-files.js.map +1 -1
- package/dist/scaffold/project.js +2 -1
- package/dist/scaffold/project.js.map +1 -1
- package/dist/verify/browser.d.ts +11 -6
- package/dist/verify/browser.js +31 -15
- package/dist/verify/browser.js.map +1 -1
- package/dist/verify/iterate.js +3 -3
- package/dist/verify/iterate.js.map +1 -1
- 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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"}
|
package/dist/project/jobs.d.ts
CHANGED
|
@@ -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
|
|
87
|
-
* the entries
|
|
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
|
|
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'
|
|
105
|
-
`export{UniformsUtils}from'
|
|
106
|
-
`export{ShaderLib}from'
|
|
107
|
-
`export{UniformsLib}from'
|
|
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':
|
|
121
|
-
'three/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/':
|
|
129
|
-
'three/examples/jsm/':
|
|
130
|
-
'three/':
|
|
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
|
|
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":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKjF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;IAkBnC,CAAC;AAEL;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,2BAA2B,EAAE,SAAS;IACtC,2BAA2B,EAAE,SAAS;IACtC,kBAAkB,EAAE,QAAQ;IAC5B,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,kCAAkC,EAAE,QAAQ;IAC5C,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,UAAU;IACjB,4FAA4F;IAC5F,6FAA6F;IAC7F,4CAA4C;CACZ,CAAC;AAEnC,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,aAAa,EAAE,UAAU;IACzB,cAAc,EAAE,UAAU;IAC1B,8FAA8F;IAC9F,cAAc,EAAE,QAAQ;IACxB,4FAA4F;IAC5F,mFAAmF;IACnF,eAAe,EAAE,SAAS;IAC1B,UAAU,EAAE,QAAQ;IACpB,IAAI,EAAE,QAAQ;IACd,wBAAwB,EAAE,QAAQ;CACnC,CAAC;AAEF,qEAAqE;AACrE,SAAS,aAAa,CAAC,IAA+B;IACpD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,SAAS,MAAM,CAAC,IAA+B;IAC7C,OAAO,kBAAkB,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,
|
|
1
|
+
{"version":3,"file":"project-files.js","sourceRoot":"","sources":["../../src/scaffold/project-files.ts"],"names":[],"mappings":"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"}
|
package/dist/scaffold/project.js
CHANGED
|
@@ -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":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAelF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,aAAa,CAAC,CAAC;AAEhE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,MAAM;CACP,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,YAAY,CAAC,CAAC;AAErD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;AAEhF;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CAAC,kBAA0B,EAAE,SAAiB;IACrF,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,sBAAsB,EAAE,GAAG,uBAAuB,CAAC,EAAE,CAAC;QAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;QACpD,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,kBAA0B,EAAE,IAAY;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,CAAC;IACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,YAAoB,EAAE,QAAgB;IACnF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC/C,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAkC;IACrE,CAAC,eAAe,EAAE,cAAc,CAAC;IACjC,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IACpC,CAAC,wBAAwB,EAAE,uBAAuB,CAAC;IACnD,CAAC,YAAY,EAAE,eAAe,CAAC;IAC/B,CAAC,0BAA0B,EAAE,kBAAkB,CAAC;IAChD,CAAC,2CAA2C,EAAE,mBAAmB,CAAC;IAClE,CAAC,yCAAyC,EAAE,mBAAmB,CAAC;IAChE,CAAC,6CAA6C,EAAE,oBAAoB,CAAC;IACrE,CAAC,wCAAwC,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/scaffold/project.ts"],"names":[],"mappings":"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"}
|
package/dist/verify/browser.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
50
|
-
* renderer pass `
|
|
51
|
-
*
|
|
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
|
-
|
|
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(
|
|
83
|
+
static launch(plan?: BrowserLaunchPlan): Promise<VerifyBrowserSession>;
|
|
79
84
|
close(): Promise<void>;
|
|
80
85
|
check(options: HeadlessCheckOptions): Promise<VerifyObservations>;
|
|
81
86
|
}
|
package/dist/verify/browser.js
CHANGED
|
@@ -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.
|
|
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(
|
|
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
|
|
49
|
+
headless,
|
|
49
50
|
channel: 'chrome',
|
|
50
|
-
args: ['--mute-audio', ...
|
|
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
|
|
112
|
+
const frameUrlIncludes = options.probeFrameUrlIncludes;
|
|
113
|
+
const target = frameUrlIncludes === undefined
|
|
112
114
|
? page
|
|
113
|
-
: page.frames().find((frame) => frame.url().includes(
|
|
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
|
-
|
|
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(
|
|
161
|
-
const events =
|
|
165
|
+
: await captureStateSnapshot(engineTarget, settleSamples);
|
|
166
|
+
const events = engineTarget === null
|
|
162
167
|
? undefined
|
|
163
|
-
: deriveEventsObservation(await captureEventTrace(
|
|
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
|
|
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, ...
|
|
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
|
-
|
|
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);
|