@bitmagic/cli 0.1.52-dev.10 → 0.1.52-dev.12

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 (75) hide show
  1. package/README.md +44 -8
  2. package/dist/assets/add.js +2 -1
  3. package/dist/assets/add.js.map +1 -1
  4. package/dist/assets/voxelize-glb.d.ts +17 -1
  5. package/dist/assets/voxelize-glb.js +43 -19
  6. package/dist/assets/voxelize-glb.js.map +1 -1
  7. package/dist/cli.d.ts +8 -0
  8. package/dist/cli.js +6 -6
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/generate.js +36 -67
  11. package/dist/commands/generate.js.map +1 -1
  12. package/dist/commands/judge.d.ts +5 -0
  13. package/dist/commands/judge.js +28 -7
  14. package/dist/commands/judge.js.map +1 -1
  15. package/dist/commands/levels.d.ts +10 -17
  16. package/dist/commands/levels.js +48 -48
  17. package/dist/commands/levels.js.map +1 -1
  18. package/dist/commands/publish.d.ts +6 -1
  19. package/dist/commands/publish.js +29 -15
  20. package/dist/commands/publish.js.map +1 -1
  21. package/dist/commands/verify.d.ts +4 -0
  22. package/dist/commands/verify.js +94 -51
  23. package/dist/commands/verify.js.map +1 -1
  24. package/dist/editor/journal.js +13 -7
  25. package/dist/editor/journal.js.map +1 -1
  26. package/dist/generate/model.d.ts +8 -2
  27. package/dist/generate/model.js +69 -21
  28. package/dist/generate/model.js.map +1 -1
  29. package/dist/generate/prop.d.ts +2 -0
  30. package/dist/generate/prop.js +1 -1
  31. package/dist/generate/prop.js.map +1 -1
  32. package/dist/judge/record.d.ts +3 -0
  33. package/dist/judge/record.js +3 -0
  34. package/dist/judge/record.js.map +1 -1
  35. package/dist/levels/registry.d.ts +5 -2
  36. package/dist/levels/registry.js +32 -27
  37. package/dist/levels/registry.js.map +1 -1
  38. package/dist/project/jobs.js +16 -20
  39. package/dist/project/jobs.js.map +1 -1
  40. package/dist/project/platform-declaration.d.ts +51 -0
  41. package/dist/project/platform-declaration.js +81 -0
  42. package/dist/project/platform-declaration.js.map +1 -0
  43. package/dist/publish/platform.d.ts +4 -8
  44. package/dist/publish/platform.js +19 -53
  45. package/dist/publish/platform.js.map +1 -1
  46. package/dist/scaffold/project-files.js +19 -5
  47. package/dist/scaffold/project-files.js.map +1 -1
  48. package/dist/verify/artifacts.d.ts +19 -0
  49. package/dist/verify/artifacts.js +34 -0
  50. package/dist/verify/artifacts.js.map +1 -0
  51. package/dist/verify/browser.d.ts +10 -0
  52. package/dist/verify/browser.js +79 -9
  53. package/dist/verify/browser.js.map +1 -1
  54. package/dist/verify/classify.d.ts +37 -1
  55. package/dist/verify/classify.js +66 -2
  56. package/dist/verify/classify.js.map +1 -1
  57. package/dist/verify/device.d.ts +43 -0
  58. package/dist/verify/device.js +59 -0
  59. package/dist/verify/device.js.map +1 -0
  60. package/dist/verify/iterate.d.ts +21 -2
  61. package/dist/verify/iterate.js +43 -36
  62. package/dist/verify/iterate.js.map +1 -1
  63. package/dist/verify/mobile-parity.d.ts +42 -0
  64. package/dist/verify/mobile-parity.js +84 -0
  65. package/dist/verify/mobile-parity.js.map +1 -0
  66. package/dist/verify/platform.d.ts +47 -0
  67. package/dist/verify/platform.js +89 -0
  68. package/dist/verify/platform.js.map +1 -0
  69. package/dist/verify/result.d.ts +90 -6
  70. package/dist/verify/result.js +89 -10
  71. package/dist/verify/result.js.map +1 -1
  72. package/dist/verify/url.d.ts +9 -1
  73. package/dist/verify/url.js +10 -2
  74. package/dist/verify/url.js.map +1 -1
  75. package/package.json +4 -4
@@ -0,0 +1,51 @@
1
+ /**
2
+ * What a project's work copy DECLARES about the platform it is for: `primaryPlatform` at the top
3
+ * level of `src/work/game.json`, and `worldProfileData.mobileOrientation`.
4
+ *
5
+ * One reader, because two commands now act on the same two fields and must never disagree about
6
+ * them. `bitmagic publish` syncs them to the catalogue (`publish/platform.ts`), and `bitmagic
7
+ * verify` / `bitmagic judge` use them to decide which platform to BOOT and whether a mobile
8
+ * parity gap is a warning or a failure. A second copy of this parse would drift the day one of
9
+ * those files moves.
10
+ *
11
+ * This module reports what the files SAY and nothing about what to do with it: a value that is
12
+ * present but unusable lands in `rejected` rather than in a sentence, because "leaving the stored
13
+ * platform alone" and "verifying on the desktop viewport instead" are different consequences of
14
+ * the same bad value and only the caller knows which one applies.
15
+ *
16
+ * Best effort throughout: a missing, unreadable or malformed file means "the project declares
17
+ * nothing", never an error. A declaration must not be able to fail a command whose real work
18
+ * succeeded.
19
+ */
20
+ export type PrimaryPlatform = 'desktop' | 'mobile';
21
+ export type MobileOrientation = 'portrait' | 'landscape';
22
+ export interface PlatformDeclaration {
23
+ /**
24
+ * `undefined` means the project declares nothing, which is NOT the same as declaring
25
+ * 'desktop': publish's catalogue columns are sticky, so "says nothing" must leave the stored
26
+ * value alone while "says desktop" must overwrite it. Verify treats both as desktop, but it
27
+ * has to be able to tell them apart to explain WHY it picked a platform.
28
+ */
29
+ primaryPlatform?: PrimaryPlatform;
30
+ mobileOrientation?: MobileOrientation;
31
+ /** Whether either work-copy file could be read at all. */
32
+ workCopyReadable: boolean;
33
+ /** Values that were present but not one of the accepted ones, verbatim, for the caller's message. */
34
+ rejected: {
35
+ primaryPlatform?: unknown;
36
+ mobileOrientation?: unknown;
37
+ };
38
+ }
39
+ /**
40
+ * Parse the platform declaration out of `src/work/`.
41
+ *
42
+ * `mobileOrientation` resolves world.json first, game.json second, matching the web lane's own
43
+ * resolution (`game-storage-backend.ts`'s `getListingFieldsSync`). Note this is the OPPOSITE
44
+ * order to `readFaviconOverride` in publish/favicon.ts, which reads game.json first — the
45
+ * favicon override's home is game.json, the orientation's is world.json, and neither order is a
46
+ * house style.
47
+ *
48
+ * The legacy `mainPlatform` spelling is NOT honoured: it predates the CLI lane entirely, so no
49
+ * project this reads can carry it.
50
+ */
51
+ export declare function readPlatformDeclaration(root: string): PlatformDeclaration;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * What a project's work copy DECLARES about the platform it is for: `primaryPlatform` at the top
3
+ * level of `src/work/game.json`, and `worldProfileData.mobileOrientation`.
4
+ *
5
+ * One reader, because two commands now act on the same two fields and must never disagree about
6
+ * them. `bitmagic publish` syncs them to the catalogue (`publish/platform.ts`), and `bitmagic
7
+ * verify` / `bitmagic judge` use them to decide which platform to BOOT and whether a mobile
8
+ * parity gap is a warning or a failure. A second copy of this parse would drift the day one of
9
+ * those files moves.
10
+ *
11
+ * This module reports what the files SAY and nothing about what to do with it: a value that is
12
+ * present but unusable lands in `rejected` rather than in a sentence, because "leaving the stored
13
+ * platform alone" and "verifying on the desktop viewport instead" are different consequences of
14
+ * the same bad value and only the caller knows which one applies.
15
+ *
16
+ * Best effort throughout: a missing, unreadable or malformed file means "the project declares
17
+ * nothing", never an error. A declaration must not be able to fail a command whose real work
18
+ * succeeded.
19
+ */
20
+ import * as fs from 'node:fs';
21
+ import * as path from 'node:path';
22
+ import { aliasSourceDir } from '../scaffold/aliases.js';
23
+ /**
24
+ * Parse the platform declaration out of `src/work/`.
25
+ *
26
+ * `mobileOrientation` resolves world.json first, game.json second, matching the web lane's own
27
+ * resolution (`game-storage-backend.ts`'s `getListingFieldsSync`). Note this is the OPPOSITE
28
+ * order to `readFaviconOverride` in publish/favicon.ts, which reads game.json first — the
29
+ * favicon override's home is game.json, the orientation's is world.json, and neither order is a
30
+ * house style.
31
+ *
32
+ * The legacy `mainPlatform` spelling is NOT honoured: it predates the CLI lane entirely, so no
33
+ * project this reads can carry it.
34
+ */
35
+ export function readPlatformDeclaration(root) {
36
+ const workDir = path.join(root, aliasSourceDir('work'));
37
+ const game = readJsonObject(path.join(workDir, 'game.json'));
38
+ const world = readJsonObject(path.join(workDir, 'world.json'));
39
+ const declaration = {
40
+ workCopyReadable: game !== null || world !== null,
41
+ rejected: {},
42
+ };
43
+ const declared = game?.primaryPlatform;
44
+ if (declared === 'desktop' || declared === 'mobile') {
45
+ declaration.primaryPlatform = declared;
46
+ }
47
+ else if (declared !== undefined) {
48
+ declaration.rejected.primaryPlatform = declared;
49
+ }
50
+ const orientation = worldProfileValue(world, 'mobileOrientation')
51
+ ?? worldProfileValue(game, 'mobileOrientation');
52
+ if (orientation === 'portrait' || orientation === 'landscape') {
53
+ declaration.mobileOrientation = orientation;
54
+ }
55
+ else if (orientation !== undefined) {
56
+ declaration.rejected.mobileOrientation = orientation;
57
+ }
58
+ return declaration;
59
+ }
60
+ /** Parse one work-copy JSON file, or null when it is missing, unreadable or not an object. */
61
+ function readJsonObject(filePath) {
62
+ let parsed;
63
+ try {
64
+ if (!fs.existsSync(filePath))
65
+ return null;
66
+ parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
72
+ ? parsed
73
+ : null;
74
+ }
75
+ function worldProfileValue(source, key) {
76
+ const profile = source?.worldProfileData;
77
+ if (typeof profile !== 'object' || profile === null || Array.isArray(profile))
78
+ return undefined;
79
+ return profile[key];
80
+ }
81
+ //# sourceMappingURL=platform-declaration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-declaration.js","sourceRoot":"","sources":["../../src/project/platform-declaration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAuBxD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;IAE/D,MAAM,WAAW,GAAwB;QACvC,gBAAgB,EAAE,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI;QACjD,QAAQ,EAAE,EAAE;KACb,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,EAAE,eAAe,CAAC;IACvC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACpD,WAAW,CAAC,eAAe,GAAG,QAAQ,CAAC;IACzC,CAAC;SAAM,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,WAAW,CAAC,QAAQ,CAAC,eAAe,GAAG,QAAQ,CAAC;IAClD,CAAC;IAED,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,CAAC;WAC5D,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;IAClD,IAAI,WAAW,KAAK,UAAU,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;QAC9D,WAAW,CAAC,iBAAiB,GAAG,WAAW,CAAC;IAC9C,CAAC;SAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QACrC,WAAW,CAAC,QAAQ,CAAC,iBAAiB,GAAG,WAAW,CAAC;IACvD,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,8FAA8F;AAC9F,SAAS,cAAc,CAAC,QAAgB;IACtC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAC5E,CAAC,CAAE,MAAkC;QACrC,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAsC,EAAE,GAAW;IAC5E,MAAM,OAAO,GAAG,MAAM,EAAE,gBAAgB,CAAC;IACzC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAChG,OAAQ,OAAmC,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC"}
@@ -15,6 +15,10 @@ export interface PlatformIndicatorsResult {
15
15
  * game is FOR (`primaryPlatform`, top level of game.json) and, for a phone game that only makes
16
16
  * sense one way up, `worldProfileData.mobileOrientation`.
17
17
  *
18
+ * The parse itself lives in `project/platform-declaration.ts`, shared with `bitmagic verify`,
19
+ * which boots the platform the same two fields declare. What stays HERE is the wire semantics,
20
+ * which are publish's alone.
21
+ *
18
22
  * The project files are the source of truth, exactly as they are in the web lane — the columns
19
23
  * are "indicators synced from game.json at publish, like `genre`" (migration 048). So a value
20
24
  * changed anywhere else is reverted by the creator's next publish, and the way to make a game
@@ -31,14 +35,6 @@ export interface PlatformIndicatorsResult {
31
35
  * the key instead would make an orientation impossible to remove from here. Only a work copy
32
36
  * neither of whose files can be read omits the key.
33
37
  *
34
- * world.json wins over game.json for the orientation, matching the web lane's own resolution
35
- * (`game-storage-backend.ts`'s `getListingFieldsSync`). Note this is the OPPOSITE order to
36
- * `readFaviconOverride` in favicon.ts, which reads game.json first — the favicon override's home
37
- * is game.json, the orientation's is world.json, and neither order is a house style.
38
- *
39
- * The legacy `mainPlatform` spelling is NOT honoured: it predates the CLI lane entirely, so no
40
- * project this reads can carry it.
41
- *
42
38
  * Best effort throughout, like `readFaviconOverride`: a missing, unreadable or malformed file
43
39
  * means "the project declares nothing", never an error. A catalog indicator must not be able to
44
40
  * fail a publish whose bundle is already uploaded.
@@ -1,11 +1,13 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import { aliasSourceDir } from '../scaffold/aliases.js';
1
+ import { readPlatformDeclaration } from '../project/platform-declaration.js';
4
2
  /**
5
3
  * The platform indicators a publish syncs from the project's own work copy: which platform the
6
4
  * game is FOR (`primaryPlatform`, top level of game.json) and, for a phone game that only makes
7
5
  * sense one way up, `worldProfileData.mobileOrientation`.
8
6
  *
7
+ * The parse itself lives in `project/platform-declaration.ts`, shared with `bitmagic verify`,
8
+ * which boots the platform the same two fields declare. What stays HERE is the wire semantics,
9
+ * which are publish's alone.
10
+ *
9
11
  * The project files are the source of truth, exactly as they are in the web lane — the columns
10
12
  * are "indicators synced from game.json at publish, like `genre`" (migration 048). So a value
11
13
  * changed anywhere else is reverted by the creator's next publish, and the way to make a game
@@ -22,44 +24,29 @@ import { aliasSourceDir } from '../scaffold/aliases.js';
22
24
  * the key instead would make an orientation impossible to remove from here. Only a work copy
23
25
  * neither of whose files can be read omits the key.
24
26
  *
25
- * world.json wins over game.json for the orientation, matching the web lane's own resolution
26
- * (`game-storage-backend.ts`'s `getListingFieldsSync`). Note this is the OPPOSITE order to
27
- * `readFaviconOverride` in favicon.ts, which reads game.json first — the favicon override's home
28
- * is game.json, the orientation's is world.json, and neither order is a house style.
29
- *
30
- * The legacy `mainPlatform` spelling is NOT honoured: it predates the CLI lane entirely, so no
31
- * project this reads can carry it.
32
- *
33
27
  * Best effort throughout, like `readFaviconOverride`: a missing, unreadable or malformed file
34
28
  * means "the project declares nothing", never an error. A catalog indicator must not be able to
35
29
  * fail a publish whose bundle is already uploaded.
36
30
  */
37
31
  export function readPlatformIndicators(root) {
38
- const workDir = path.join(root, aliasSourceDir('work'));
39
- const game = readJsonObject(path.join(workDir, 'game.json'));
40
- const world = readJsonObject(path.join(workDir, 'world.json'));
32
+ const declaration = readPlatformDeclaration(root);
41
33
  const fields = {};
42
34
  const notes = [];
43
- const declared = game?.primaryPlatform;
44
- if (declared === 'desktop' || declared === 'mobile') {
45
- fields.primaryPlatform = declared;
35
+ if (declaration.primaryPlatform !== undefined) {
36
+ fields.primaryPlatform = declaration.primaryPlatform;
37
+ }
38
+ if (declaration.workCopyReadable) {
39
+ // Explicit null when the work copy is readable but declares nothing — see the doc comment.
40
+ fields.mobileOrientation = declaration.mobileOrientation ?? null;
46
41
  }
47
- else if (declared !== undefined) {
48
- notes.push(`game.json primaryPlatform ${JSON.stringify(declared)} is not "desktop" or "mobile" — ` +
49
- 'leaving the stored platform alone.');
42
+ const { rejected } = declaration;
43
+ if ('primaryPlatform' in rejected) {
44
+ notes.push(`game.json primaryPlatform ${JSON.stringify(rejected.primaryPlatform)} is not "desktop" `
45
+ + 'or "mobile" — leaving the stored platform alone.');
50
46
  }
51
- if (world !== null || game !== null) {
52
- const orientation = worldProfileValue(world, 'mobileOrientation') ?? worldProfileValue(game, 'mobileOrientation');
53
- if (orientation === 'portrait' || orientation === 'landscape') {
54
- fields.mobileOrientation = orientation;
55
- }
56
- else {
57
- if (orientation !== undefined) {
58
- notes.push(`worldProfileData.mobileOrientation ${JSON.stringify(orientation)} is not "portrait" ` +
59
- 'or "landscape" — publishing with no orientation lock.');
60
- }
61
- fields.mobileOrientation = null;
62
- }
47
+ if ('mobileOrientation' in rejected) {
48
+ notes.push(`worldProfileData.mobileOrientation ${JSON.stringify(rejected.mobileOrientation)} is not `
49
+ + '"portrait" or "landscape" — publishing with no orientation lock.');
63
50
  }
64
51
  if (fields.primaryPlatform === 'mobile') {
65
52
  notes.push(fields.mobileOrientation
@@ -68,25 +55,4 @@ export function readPlatformIndicators(root) {
68
55
  }
69
56
  return { fields, notes };
70
57
  }
71
- /** Parse one work-copy JSON file, or null when it is missing, unreadable or not an object. */
72
- function readJsonObject(filePath) {
73
- let parsed;
74
- try {
75
- if (!fs.existsSync(filePath))
76
- return null;
77
- parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
78
- }
79
- catch {
80
- return null;
81
- }
82
- return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
83
- ? parsed
84
- : null;
85
- }
86
- function worldProfileValue(source, key) {
87
- const profile = source?.worldProfileData;
88
- if (typeof profile !== 'object' || profile === null || Array.isArray(profile))
89
- return undefined;
90
- return profile[key];
91
- }
92
58
  //# sourceMappingURL=platform.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/publish/platform.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/publish/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAgB7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,WAAW,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IAElD,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,WAAW,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QAC9C,MAAM,CAAC,eAAe,GAAG,WAAW,CAAC,eAAe,CAAC;IACvD,CAAC;IAED,IAAI,WAAW,CAAC,gBAAgB,EAAE,CAAC;QACjC,2FAA2F;QAC3F,MAAM,CAAC,iBAAiB,GAAG,WAAW,CAAC,iBAAiB,IAAI,IAAI,CAAC;IACnE,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC;IACjC,IAAI,iBAAiB,IAAI,QAAQ,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CACR,6BAA6B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,oBAAoB;cACrF,kDAAkD,CACvD,CAAC;IACJ,CAAC;IACD,IAAI,mBAAmB,IAAI,QAAQ,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CACR,sCAAsC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,UAAU;cACtF,kEAAkE,CACvE,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CACR,MAAM,CAAC,iBAAiB;YACtB,CAAC,CAAC,yCAAyC,MAAM,CAAC,iBAAiB,GAAG;YACtE,CAAC,CAAC,6BAA6B,CAClC,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC"}
@@ -647,11 +647,17 @@ are configured in **code** — there is no panel for them.
647
647
  …)\` for a gameplay action. The first strands phone players and the engine logs a
648
648
  \`[mobile-parity]\` error on game start; the raw listener strands them **silently** — the parity
649
649
  check cannot see a listener that never went through the engine.
650
+ - **\`bitmagic verify\` enforces this.** Every run reports the parity gaps, naming the key and the
651
+ system that registered it — a warning normally, and a **failure** on a game whose
652
+ \`primaryPlatform\` is \`mobile\`. \`bitmagic verify --platform mobile\` goes further and boots
653
+ the game as a phone: touch controls, phone viewport, the engine's real mobile branch.
650
654
  - **Say which platform the game is for.** \`"primaryPlatform": "mobile"\` at the top level of
651
655
  \`src/work/game.json\` is what bitmagic.ai catalogs it as, and \`bitmagic publish\` sends it —
652
- editing that file is the only way to set it. For a game that only works one way up, add
653
- \`"mobileOrientation": "portrait"\` (or \`"landscape"\`) to \`worldProfileData\` in
654
- \`src/work/world.json\`; published mobile builds lock to it.
656
+ editing that file is the only way to set it. It also decides what \`verify\` boots and \`judge\`
657
+ grades by default, so setting it is how a phone game gets checked as one. For a game that only
658
+ works one way up, add \`"mobileOrientation": "portrait"\` (or \`"landscape"\`) to
659
+ \`worldProfileData\` in \`src/work/world.json\`; published mobile builds lock to it, and the
660
+ mobile verify run turns the phone the same way.
655
661
 
656
662
  Details — button slots, icons, the joystick, the parity check: \`engine/agent-docs/control-system.md\`.
657
663
 
@@ -661,6 +667,7 @@ Details — button slots, icons, the joystick, the parity check: \`engine/agent-
661
667
  bitmagic check # typecheck against the vendored engine
662
668
  bitmagic reload # tell the open browser you have finished a round of edits
663
669
  bitmagic verify # boot the game in a real browser and report what broke
670
+ bitmagic verify --platform mobile # boot it as a phone: touch controls, phone viewport
664
671
  bitmagic judge # grade the verify screenshot against a quality rubric (paid, cheap)
665
672
  \`\`\`
666
673
 
@@ -751,7 +758,8 @@ bitmagic publish # verify-gate, build if needed, and ship to bitmagic.ai
751
758
  Follow this order; \`publish\` enforces it and refuses otherwise:
752
759
 
753
760
  1. Run \`bitmagic verify\` and get it passing. It writes \`.bitmagic/verify/result.json\`,
754
- \`.bitmagic/verify/screenshot.png\` and \`.bitmagic/verify/console.log\`.
761
+ \`.bitmagic/verify/screenshot.png\` and \`.bitmagic/verify/console.log\` — or the
762
+ \`.mobile\`-suffixed names when the run was a phone one.
755
763
 
756
764
  The publish thumbnail is \`.bitmagic/cover.webp\` when \`bitmagic cover\` has produced one, and
757
765
  that screenshot otherwise. The output names which one it used.
@@ -1005,7 +1013,8 @@ that I would otherwise have defaulted differently.
1005
1013
 
1006
1014
  ## Platform
1007
1015
  \`primaryPlatform\` in \`game.json\` — \`desktop\` or \`mobile\`. Plus \`worldProfileData.mobileOrientation\`
1008
- in \`world.json\` when the game only works one way up.
1016
+ in \`world.json\` when the game only works one way up. If \`mobile\`: every action needs a touch
1017
+ button, and \`bitmagic verify\` fails the run otherwise.
1009
1018
 
1010
1019
  ## Slice 1 — the smallest playable thing
1011
1020
  - Core verb: the ONE thing the player does
@@ -1468,6 +1477,7 @@ description: Use after finishing a milestone — a mechanics-plan slice shipped,
1468
1477
  bitmagic verify # first: captures the screenshot the judge grades (no --fast)
1469
1478
  bitmagic judge # one vision-model call; prints a scorecard, exits 0
1470
1479
  bitmagic judge --genre platformer # sharpen the rubric: platformer, racing, shooter, combat, driving, tower-defense
1480
+ bitmagic judge --platform mobile # grade the phone frame: touch-HUD legibility, thumb reach, portrait framing
1471
1481
  bitmagic judge --min-score 7 # exit 4 when the overall score is below the bar
1472
1482
  bitmagic judge --json # the scorecard as one JSON document on stdout
1473
1483
  \`\`\`
@@ -1478,6 +1488,10 @@ model and prints back four dimension scores (visual-quality, readability, design
1478
1488
  and at most three findings — each naming what to change, most severe first. The scorecard is also
1479
1489
  written to \`.bitmagic/judge.json\`.
1480
1490
 
1491
+ A mobile-primary game is graded on its phone frame by default — the one
1492
+ \`bitmagic verify --platform mobile\` captured — with the rubric re-pointed at what a phone player
1493
+ sees. Pass \`--platform desktop\` to grade the other one.
1494
+
1481
1495
  It is paid (sparks, roughly the cost of one small model call) and deliberate — which is why it is
1482
1496
  a command you run, not something verify does for you.
1483
1497
 
@@ -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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"}
@@ -0,0 +1,19 @@
1
+ import type { VerifyPlatform } from './platform.js';
2
+ export interface VerifyArtifactPaths {
3
+ /** The publish thumbnail candidate on desktop. Not written by a `--fast` run. */
4
+ screenshotPath: string;
5
+ consolePath: string;
6
+ /** Where the automatic software-GL re-run's console goes, so the first run's evidence survives. */
7
+ retryConsolePath: string;
8
+ }
9
+ export declare function verifyArtifactPaths(artifactDir: string, platform: VerifyPlatform): VerifyArtifactPaths;
10
+ export declare const VERIFY_PLATFORMS: VerifyPlatform[];
11
+ /**
12
+ * Every screenshot any platform could write.
13
+ *
14
+ * A run deletes the ones it is not going to produce, extending the rule `--fast` already follows:
15
+ * a stale screenshot beside a fresh `result.json` is worse than none, because publish would ship
16
+ * a picture of some earlier state of the game — and after this change "earlier state" includes
17
+ * "the other platform, from an older run".
18
+ */
19
+ export declare function allVerifyScreenshotPaths(artifactDir: string): string[];
@@ -0,0 +1,34 @@
1
+ /**
2
+ * What a verify run writes, per platform.
3
+ *
4
+ * One place, because a `both` run writes two of everything and the desktop names are a contract
5
+ * with two other commands: `bitmagic publish` reads `screenshot.png` as its thumbnail fallback
6
+ * and `bitmagic judge` grades it. Desktop therefore keeps exactly the names it has always had,
7
+ * and mobile infixes `.mobile` before the extension.
8
+ *
9
+ * A per-platform CONSOLE log is not cosmetic. Without it a `both` run would overwrite the desktop
10
+ * console — by far the most useful artifact when something breaks — with the mobile one, and the
11
+ * run would look like it only ever booted a phone.
12
+ */
13
+ import * as path from 'path';
14
+ export function verifyArtifactPaths(artifactDir, platform) {
15
+ const suffix = platform === 'mobile' ? '.mobile' : '';
16
+ return {
17
+ screenshotPath: path.join(artifactDir, `screenshot${suffix}.png`),
18
+ consolePath: path.join(artifactDir, `console${suffix}.log`),
19
+ retryConsolePath: path.join(artifactDir, `console.retry${suffix}.log`),
20
+ };
21
+ }
22
+ export const VERIFY_PLATFORMS = ['desktop', 'mobile'];
23
+ /**
24
+ * Every screenshot any platform could write.
25
+ *
26
+ * A run deletes the ones it is not going to produce, extending the rule `--fast` already follows:
27
+ * a stale screenshot beside a fresh `result.json` is worse than none, because publish would ship
28
+ * a picture of some earlier state of the game — and after this change "earlier state" includes
29
+ * "the other platform, from an older run".
30
+ */
31
+ export function allVerifyScreenshotPaths(artifactDir) {
32
+ return VERIFY_PLATFORMS.map((platform) => verifyArtifactPaths(artifactDir, platform).screenshotPath);
33
+ }
34
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/verify/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAW7B,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,QAAwB;IAExB,MAAM,MAAM,GAAG,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,OAAO;QACL,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,MAAM,MAAM,CAAC;QACjE,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,MAAM,MAAM,CAAC;QAC3D,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,MAAM,MAAM,CAAC;KACvE,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAqB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAExE;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAAmB;IAC1D,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC;AACvG,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { type BrowserLaunchPlan, type RendererChoice } from '../browser-gl.js';
2
2
  import { type VerifyObservations } from './classify.js';
3
+ import type { VerifyDeviceOptions } from './device.js';
3
4
  export interface StartInteractionOptions {
4
5
  /** Selector for the engine Play button. Its label is localizable and per-game overridable, so
5
6
  * never match by text. */
@@ -56,6 +57,15 @@ export interface HeadlessCheckOptions {
56
57
  * `browserGlArgs(process.env)`. `--mute-audio` is always added here, not by callers.
57
58
  */
58
59
  launch?: BrowserLaunchPlan;
60
+ /**
61
+ * Emulate a phone for this check — viewport, screen, deviceScaleFactor, `isMobile` and
62
+ * `hasTouch` from `verify/device.ts`. Absent means the desktop 1280x720 context, byte-identical
63
+ * to what every run did before this existed, which is what `publish`'s smoke check keeps using.
64
+ *
65
+ * Pair it with a `?platform=mobile` URL: this side makes the BROWSER a phone, that side makes
66
+ * the ENGINE take its mobile branch, and only both together verify what a player gets.
67
+ */
68
+ device?: VerifyDeviceOptions;
59
69
  /**
60
70
  * Capture the screenshot and measure its pixels (default true). `bitmagic verify --fast`
61
71
  * turns this off for the inner loop: `screenshotBytes`/`canvasFrame` come back null and