@bitmagic/cli 0.1.39 → 0.1.40

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 CHANGED
@@ -78,7 +78,7 @@ browser reloads itself on every change and the assets panel shows each generatio
78
78
  | `bitmagic check` | Typecheck (`tsc --noEmit`) against the vendored engine. Fast; does not prove the game runs. |
79
79
  | `bitmagic dev [--port <port>] [--editor-port <port>] [--no-open]` | Build, then serve everything and keep it running: `tsc --watch`, `vite` on 3010, and a **Game / Editor** view on 3011 that reloads itself when the project changes. Opens the view in your browser; `--no-open` (or `BITMAGIC_NO_OPEN=1`) skips that. The one command to leave open. See **The dev view** below. |
80
80
  | `bitmagic reload [--port <port>]` | Tell a running `bitmagic dev` to reload the browser now. For agents: run it when you finish a round of edits. Exits 0 and does nothing when no dev server is running. |
81
- | `bitmagic verify [--timeout <ms>] [--renderer webgpu\|webgl] [--fast] [--watch]` | Build, boot the game in a headless browser, click the engine's Play button like a player would, and report what broke. A game without the button passes as long as gameplay starts by itself (auto-starting genres, custom start UIs); a run where gameplay never starts fails. The settle is adaptive: the run ends as soon as the live engine proves stable gameplay (state, rendered frames, no fresh errors, player standing), with `--timeout` as the cap. The verdict includes live engine state — actual GPU backend, fps, player position, physics body count — recorded in `result.json`. `--renderer` pins the pipeline (default `webgpu`, what players run; a silent WebGPU→WebGL2 fallback **fails** the run, and `--renderer webgl` is the deliberate escape hatch). A run failing on a lost WebGL context retries once on software rendering automatically. `--fast` skips the screenshot pipeline (then there is no thumbnail candidate from this run). `--watch` keeps everything warm — incremental `tsc --watch`, one vite, one browser — and re-verifies on file change in seconds; `--fast` is the watch default (`--no-fast` restores the screenshot). Writes the artifacts the publish gate reads (see below). |
81
+ | `bitmagic verify [--timeout <ms>] [--renderer webgpu\|webgl] [--fast] [--watch]` | Build, boot the game in a headless browser, click the engine's Play button like a player would, and report what broke. A game without the button passes as long as gameplay starts by itself (auto-starting genres, custom start UIs); a run where gameplay never starts fails. The settle is adaptive: the run ends as soon as the live engine proves stable gameplay (state, rendered frames, no fresh errors, player standing), with `--timeout` as the cap. The verdict includes live engine state — actual GPU backend, fps, player position, physics body count, gameplay events (see **Gameplay events** below) — recorded in `result.json`. `--renderer` pins the pipeline (default `webgpu`, what players run; a silent WebGPU→WebGL2 fallback **fails** the run, and `--renderer webgl` is the deliberate escape hatch). A run failing on a lost WebGL context retries once on software rendering automatically. `--fast` skips the screenshot pipeline (then there is no thumbnail candidate from this run). `--watch` keeps everything warm — incremental `tsc --watch`, one vite, one browser — and re-verifies on file change in seconds; `--fast` is the watch default (`--no-fast` restores the screenshot). Writes the artifacts the publish gate reads (see below). |
82
82
  | `bitmagic build` | Bundle the game into one self-contained `.bitmagic/build/index.html`. Rarely needs to be run by hand — `publish` builds automatically when the project changed. |
83
83
  | `bitmagic publish [--visibility public\|private] [--name <name>] [--description <desc>] [--force]` | Verify-gate, build if needed, and upload straight to GCS. **Private unless `--visibility public` is passed.** |
84
84
  | `bitmagic upgrade [--engine <version>] [--force]` | Refresh vendored platform files and the CLI's own skills to the currently published engine. Refuses a dirty git tree unless `--force`. |
@@ -122,6 +122,17 @@ my-game/
122
122
  console.retry.log # the software-GL retry's console, when a lost context forced one
123
123
  ```
124
124
 
125
+ ### Gameplay events
126
+
127
+ Verify boots the game with `?eventlog=1`, which asks the engine to run a passive gameplay-event
128
+ session (`window.__bmDebug` — see the engine's `docs/debug-namespace.md`). The run's `result.json`
129
+ then carries an `events` block: counts by type (`player-death`, `pickup`, `match-end`, …), the
130
+ counts within the first 10 seconds of gameplay, when the match ended, and the last 50 raw events.
131
+ Two signals surface as **warnings** (never failures — verify provides no input, so only
132
+ spontaneous events are judged): the player dying 3+ times in the first 10 seconds of gameplay,
133
+ and the match ending within 5 seconds of starting. A vendored engine too old to know
134
+ `?eventlog=1` yields `events: null` and no output — run `bitmagic upgrade` to get the session.
135
+
125
136
  ## Cover art
126
137
 
127
138
  `bitmagic cover` generates the game's cover from `GAME-DESIGN.md` — the same artwork the web
@@ -208,10 +219,21 @@ highlighted. One that fails disappears the same way, and says why on the termina
208
219
  choosing the arguments can act on, so it goes there rather than onto a red card beside the game.
209
220
  One whose process was killed drops off the list rather than spinning forever.
210
221
 
211
- Thumbnails are drawn by the engine on demand — images are their own preview, meshes are rendered
212
- once and cached in `.bitmagic/previews/` — so they cost nothing on later reloads. The same cache
213
- feeds the editor's right-click **Add object** palette, which used to show "No Preview" on every
214
- tile.
222
+ Thumbnails are drawn by the engine on demand — images are their own preview, meshes and voxel
223
+ assets are rendered once and cached in `.bitmagic/previews/` — so they cost nothing on later
224
+ reloads. The same cache feeds the editor's right-click **Add object** palette, which used to show
225
+ "No Preview" on every tile.
226
+
227
+ **Click a row to look at the asset properly.** A mesh or a voxel asset opens in a viewer you can
228
+ drag to turn and scroll to zoom, at full detail rather than the coarse version a 46px tile is drawn
229
+ from; an image opens as the image; a sound gets a player. Beside it is everything the row has no
230
+ room for — extent in world units, voxel count, triangle count, and the asset id, with a button to
231
+ copy it so you can paste it into a `bitmagic generate prop --asset …`. Escape closes it. The game
232
+ pauses while it is open and resumes when you close it.
233
+
234
+ The viewer is served by `bitmagic dev` itself, so it arrives with the CLI: no `bitmagic upgrade`,
235
+ and no dependency on how old the engine vendored into your project is. It does borrow one thing
236
+ from that engine — the voxel loader, so what you see is what your project's own code builds.
215
237
 
216
238
  ### Auto-reload
217
239
 
@@ -12,6 +12,7 @@ import { waitForServer } from '../verify/wait-for-server.js';
12
12
  import { computeFingerprint } from '../publish/fingerprint.js';
13
13
  import { writeVerifyRecord, decideVerifyOutcome, recordAndGateVerify } from '../verify/result.js';
14
14
  import { runVerifyWatch } from '../verify/iterate.js';
15
+ import { buildVerifyUrl } from '../verify/url.js';
15
16
  import { createOutput } from '../output.js';
16
17
  const DEFAULT_SETTLE_MS = 15_000;
17
18
  /**
@@ -103,6 +104,18 @@ function describeRunState(observations) {
103
104
  if (snapshot.physics !== null)
104
105
  parts.push(`${snapshot.physics.rigidBodyCount} bodies`);
105
106
  }
107
+ const events = observations.events;
108
+ if (events) {
109
+ // Only non-zero parts — a run with nothing to report should not say "0 deaths".
110
+ const deaths = events.totalByType['player-death'] ?? 0;
111
+ if (deaths > 0)
112
+ parts.push(`${deaths} death${deaths === 1 ? '' : 's'}`);
113
+ const pickups = events.totalByType['pickup'] ?? 0;
114
+ if (pickups > 0)
115
+ parts.push(`${pickups} pickup${pickups === 1 ? '' : 's'}`);
116
+ if (events.matchEndAtSeconds !== null)
117
+ parts.push(`match ended at ${events.matchEndAtSeconds}s`);
118
+ }
106
119
  return parts.length === 0 ? 'Run state: unobserved' : parts.join(' · ');
107
120
  }
108
121
  export const verifyCommand = defineCommand({
@@ -197,10 +210,8 @@ export const verifyCommand = defineCommand({
197
210
  // No ?autostart=1: verify clicks the engine Play button like a real player would
198
211
  // (startInteraction), which both proves the menu came up AND that gameplay starts from it.
199
212
  // Autostart bypassed the menu — a game whose Play flow was broken could still pass.
200
- // ?renderer= pins the pipeline so the verdict does not depend on a stale localStorage
201
- // preference left by whoever opened this game in a browser last.
202
213
  const checkOptions = {
203
- url: `http://localhost:${port}/?renderer=${renderer}`,
214
+ url: buildVerifyUrl(port, renderer),
204
215
  screenshotPath,
205
216
  consolePath,
206
217
  settleMs,
@@ -235,6 +246,7 @@ export const verifyCommand = defineCommand({
235
246
  renderer: observations.renderer,
236
247
  settle: observations.settle,
237
248
  snapshot: observations.snapshot,
249
+ events: observations.events,
238
250
  ...(retriedWithSoftwareGl ? { retriedWithSoftwareGl } : {}),
239
251
  });
240
252
  recordAndGateVerify(artifactDir, outcome, { consolePath, ...(fast ? {} : { screenshotPath }) }, {
@@ -255,6 +267,7 @@ export const verifyCommand = defineCommand({
255
267
  retriedWithSoftwareGl: outcome.record.retriedWithSoftwareGl,
256
268
  settle: outcome.record.settle,
257
269
  snapshot: outcome.record.snapshot,
270
+ events: outcome.record.events,
258
271
  artifactDir,
259
272
  consolePath,
260
273
  screenshotPath: fast ? undefined : screenshotPath,
@@ -1 +1 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The asset overlay's CSS and markup, composed into `shell-page.ts`.
3
+ *
4
+ * Split out for one reason: that file is the busiest in the package — it grew past 1400 lines and
5
+ * two sessions have added panel features to it in a day. Its style and its markup are the parts
6
+ * that carry no closure state, so they can leave without threading anything across a boundary. The
7
+ * overlay's behaviour stays inline there, because it needs `postFlat`, `await_`, `loaded`,
8
+ * `gameState` and `GAME_URL` from the enclosing IIFE.
9
+ *
10
+ * Same template-literal rules as its host: **no backticks**, and a backslash in a regex has to be
11
+ * doubled to survive the literal.
12
+ */
13
+ /** Styles for `#asset-overlay`, appended to the shell's stylesheet. */
14
+ export declare const ASSET_DETAIL_CSS = "\n /* Modelled on #hq-overlay, deliberately: the dev view has one modal idiom and this is it. */\n #asset-overlay { display: none; position: fixed; inset: 0; background: rgba(8,8,12,.78);\n align-items: center; justify-content: center; z-index: 11; }\n #asset-overlay.show { display: flex; }\n #asset-dialog { display: flex; width: min(1100px, 94vw); height: min(760px, 88vh);\n background: #17171d; border: 1px solid #34343f; border-radius: 8px;\n overflow: hidden; }\n /* The viewer takes the room. Everything else is a caption. */\n #asset-view { flex: 1; min-width: 0; position: relative; background: #1e293b; }\n #asset-view iframe { display: block; width: 100%; height: 100%; border: 0; }\n #asset-view img { display: block; width: 100%; height: 100%; object-fit: contain;\n background: #101014; }\n #asset-view audio { position: absolute; left: 50%; top: 50%; width: min(420px, 80%);\n transform: translate(-50%, -50%); }\n #asset-note { position: absolute; inset: auto 0 0 0; padding: 10px 12px; background: #101014e6;\n color: #e0938e; font-size: 12px; }\n #asset-note.hidden, #asset-view > .hidden { display: none; }\n #asset-meta { width: 268px; flex: none; padding: 14px; overflow-y: auto;\n border-left: 1px solid #26262e; }\n #asset-meta h2 { margin: 0 0 2px; font-size: 15px; word-break: break-word; }\n #asset-meta .sub { color: #6a6a7a; font-size: 11px; margin-bottom: 12px; }\n #asset-facts { display: grid; grid-template-columns: auto 1fr; gap: 4px 10px; font-size: 12px; }\n #asset-facts dt { color: #6a6a7a; }\n #asset-facts dd { margin: 0; color: #d9d9e2; word-break: break-word; }\n #asset-facts dd.mono { font-family: ui-monospace, monospace; font-size: 11px; }\n #asset-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }\n #asset-close { margin-left: auto; }\n";
15
+ /**
16
+ * The overlay itself.
17
+ *
18
+ * `<audio controls>` rather than a play button of our own: the web Creator withholds native
19
+ * controls because its player sits in a 46px row, and here there is a whole dialog. A creator
20
+ * checking a sound effect wants the scrubber.
21
+ */
22
+ export declare const ASSET_DETAIL_HTML = "\n <div id=\"asset-overlay\">\n <div id=\"asset-dialog\">\n <div id=\"asset-view\">\n <iframe id=\"asset-frame\" class=\"hidden\" title=\"Asset preview\"></iframe>\n <img id=\"asset-image\" class=\"hidden\" alt=\"\">\n <audio id=\"asset-audio\" class=\"hidden\" controls preload=\"none\"></audio>\n <div id=\"asset-note\" class=\"hidden\"></div>\n </div>\n <aside id=\"asset-meta\">\n <h2 id=\"asset-name\"></h2>\n <div class=\"sub\" id=\"asset-sub\"></div>\n <dl id=\"asset-facts\"></dl>\n <div id=\"asset-actions\">\n <button id=\"asset-reset\" type=\"button\" title=\"Back to the angle the thumbnail uses\">Reset view</button>\n <button id=\"asset-copy\" type=\"button\" title=\"Copy this asset's id\">Copy id</button>\n <button id=\"asset-close\" type=\"button\">Close</button>\n </div>\n </aside>\n </div>\n </div>\n";
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The asset overlay's CSS and markup, composed into `shell-page.ts`.
3
+ *
4
+ * Split out for one reason: that file is the busiest in the package — it grew past 1400 lines and
5
+ * two sessions have added panel features to it in a day. Its style and its markup are the parts
6
+ * that carry no closure state, so they can leave without threading anything across a boundary. The
7
+ * overlay's behaviour stays inline there, because it needs `postFlat`, `await_`, `loaded`,
8
+ * `gameState` and `GAME_URL` from the enclosing IIFE.
9
+ *
10
+ * Same template-literal rules as its host: **no backticks**, and a backslash in a regex has to be
11
+ * doubled to survive the literal.
12
+ */
13
+ /** Styles for `#asset-overlay`, appended to the shell's stylesheet. */
14
+ export const ASSET_DETAIL_CSS = `
15
+ /* Modelled on #hq-overlay, deliberately: the dev view has one modal idiom and this is it. */
16
+ #asset-overlay { display: none; position: fixed; inset: 0; background: rgba(8,8,12,.78);
17
+ align-items: center; justify-content: center; z-index: 11; }
18
+ #asset-overlay.show { display: flex; }
19
+ #asset-dialog { display: flex; width: min(1100px, 94vw); height: min(760px, 88vh);
20
+ background: #17171d; border: 1px solid #34343f; border-radius: 8px;
21
+ overflow: hidden; }
22
+ /* The viewer takes the room. Everything else is a caption. */
23
+ #asset-view { flex: 1; min-width: 0; position: relative; background: #1e293b; }
24
+ #asset-view iframe { display: block; width: 100%; height: 100%; border: 0; }
25
+ #asset-view img { display: block; width: 100%; height: 100%; object-fit: contain;
26
+ background: #101014; }
27
+ #asset-view audio { position: absolute; left: 50%; top: 50%; width: min(420px, 80%);
28
+ transform: translate(-50%, -50%); }
29
+ #asset-note { position: absolute; inset: auto 0 0 0; padding: 10px 12px; background: #101014e6;
30
+ color: #e0938e; font-size: 12px; }
31
+ #asset-note.hidden, #asset-view > .hidden { display: none; }
32
+ #asset-meta { width: 268px; flex: none; padding: 14px; overflow-y: auto;
33
+ border-left: 1px solid #26262e; }
34
+ #asset-meta h2 { margin: 0 0 2px; font-size: 15px; word-break: break-word; }
35
+ #asset-meta .sub { color: #6a6a7a; font-size: 11px; margin-bottom: 12px; }
36
+ #asset-facts { display: grid; grid-template-columns: auto 1fr; gap: 4px 10px; font-size: 12px; }
37
+ #asset-facts dt { color: #6a6a7a; }
38
+ #asset-facts dd { margin: 0; color: #d9d9e2; word-break: break-word; }
39
+ #asset-facts dd.mono { font-family: ui-monospace, monospace; font-size: 11px; }
40
+ #asset-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
41
+ #asset-close { margin-left: auto; }
42
+ `;
43
+ /**
44
+ * The overlay itself.
45
+ *
46
+ * `<audio controls>` rather than a play button of our own: the web Creator withholds native
47
+ * controls because its player sits in a 46px row, and here there is a whole dialog. A creator
48
+ * checking a sound effect wants the scrubber.
49
+ */
50
+ export const ASSET_DETAIL_HTML = `
51
+ <div id="asset-overlay">
52
+ <div id="asset-dialog">
53
+ <div id="asset-view">
54
+ <iframe id="asset-frame" class="hidden" title="Asset preview"></iframe>
55
+ <img id="asset-image" class="hidden" alt="">
56
+ <audio id="asset-audio" class="hidden" controls preload="none"></audio>
57
+ <div id="asset-note" class="hidden"></div>
58
+ </div>
59
+ <aside id="asset-meta">
60
+ <h2 id="asset-name"></h2>
61
+ <div class="sub" id="asset-sub"></div>
62
+ <dl id="asset-facts"></dl>
63
+ <div id="asset-actions">
64
+ <button id="asset-reset" type="button" title="Back to the angle the thumbnail uses">Reset view</button>
65
+ <button id="asset-copy" type="button" title="Copy this asset's id">Copy id</button>
66
+ <button id="asset-close" type="button">Close</button>
67
+ </div>
68
+ </aside>
69
+ </div>
70
+ </div>
71
+ `;
72
+ //# sourceMappingURL=asset-detail-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-detail-panel.js","sourceRoot":"","sources":["../../src/editor/asset-detail-panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,uEAAuE;AACvE,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B/B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBhC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface AssetPreviewPageOptions {
2
+ /** Port vite serves the project on — where the engine modules come from. Never hardcoded: a
3
+ * default port drifts inside 3000–3199 when it is taken. */
4
+ gamePort: number;
5
+ }
6
+ export declare function renderAssetPreviewPage(options: AssetPreviewPageOptions): string;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * The page that hosts `asset-viewer.ts`, served by the sidecar at `/asset-preview`.
3
+ *
4
+ * Two things here are load-bearing.
5
+ *
6
+ * **The import map is generated, not transcribed.** `three` and its addons come from the same
7
+ * `CDN_IMPORTS` a scaffolded `index.html` is built from, and the `engine/` prefixes from the same
8
+ * `importMapEntries()` — with the project's vite origin in front, because those modules live on the
9
+ * other port. The repo already maintains five copies of this map by hand and has a contract test
10
+ * guarding them precisely because a partial update once broke every page; a sixth copy is a
11
+ * liability, and this is the way to have the map without having a copy of it.
12
+ *
13
+ * **The engine prefixes point at the game's origin.** Vite's default `server.cors.origin` is
14
+ * `defaultAllowedOrigins`, which matches any `localhost`/`127.0.0.1` port, so a page served from
15
+ * the sidecar may import modules from the project's vite server with no configuration anywhere. It
16
+ * matters that they come from the *project* rather than from this package: the voxel decoder must
17
+ * be the one the creator's own engine writes files with.
18
+ */
19
+ import { CDN_IMPORTS } from '../scaffold/project-files.js';
20
+ import { importMapEntries } from '../scaffold/aliases.js';
21
+ /** Attribute- and script-safe: these land inside a `<script type="importmap">` block. */
22
+ function importMapFor(gamePort) {
23
+ const origin = `http://localhost:${gamePort}`;
24
+ const engine = Object.fromEntries(Object.entries(importMapEntries()).map(([name, target]) => [name, `${origin}${target}`]));
25
+ return { ...CDN_IMPORTS, ...engine };
26
+ }
27
+ export function renderAssetPreviewPage(options) {
28
+ const imports = JSON.stringify({ imports: importMapFor(options.gamePort) }, null, 4);
29
+ return `<!DOCTYPE html>
30
+ <html lang="en">
31
+ <head>
32
+ <meta charset="utf-8">
33
+ <title>Asset preview</title>
34
+ <style>
35
+ html, body { margin: 0; height: 100%; background: #1e293b; overflow: hidden;
36
+ font: 12px/1.5 system-ui, -apple-system, sans-serif; color: #c8c8d4; }
37
+ #stage { position: absolute; inset: 0; }
38
+ #stage canvas { display: block; width: 100%; height: 100%; }
39
+ /* Sits over the canvas rather than beside it: the dialog gives this iframe every pixel, and a
40
+ status line that reserved space would shrink the thing being looked at. */
41
+ #status { position: absolute; left: 0; right: 0; top: 0; padding: 10px 12px;
42
+ background: linear-gradient(#1e293bcc, #1e293b00); pointer-events: none; }
43
+ #status.failed { color: #e0938e; }
44
+ #hint { position: absolute; left: 12px; bottom: 10px; color: #7d8595; pointer-events: none; }
45
+ #hint.hidden, #status.hidden { display: none; }
46
+ </style>
47
+ </head>
48
+ <body>
49
+ <div id="stage"></div>
50
+ <div id="status">Loading…</div>
51
+ <div id="hint" class="hidden">Drag to turn · scroll to zoom</div>
52
+
53
+ <script type="importmap">
54
+ ${imports}
55
+ </script>
56
+
57
+ <script type="module">
58
+ import { startAssetViewer } from '/asset-viewer.js';
59
+
60
+ var params = new URLSearchParams(window.location.search);
61
+ var status = document.getElementById('status');
62
+ var hint = document.getElementById('hint');
63
+
64
+ /**
65
+ * The parent is the dev view's shell on the sidecar's own origin, so this is same-origin and the
66
+ * message is only a convenience. It is still the shell's signal that the viewer works: no READY
67
+ * within a few seconds and it swaps this iframe for the cached thumbnail, which is what a project
68
+ * whose engine cannot serve the voxel modules falls back to.
69
+ */
70
+ function tell(message) {
71
+ try { window.parent.postMessage(message, window.location.origin); } catch (error) { /* detached */ }
72
+ }
73
+
74
+ try {
75
+ var viewer = await startAssetViewer({
76
+ container: document.getElementById('stage'),
77
+ url: params.get('url') || '',
78
+ kind: params.get('kind') === 'vxl' ? 'vxl' : 'glb',
79
+ sourceEndpoint: '/api/assets/source',
80
+ });
81
+ status.classList.add('hidden');
82
+ hint.classList.remove('hidden');
83
+ tell({ type: 'ASSET_PREVIEW_READY', triangles: viewer.triangles });
84
+ window.addEventListener('message', function (event) {
85
+ if (event.origin === window.location.origin && event.data && event.data.type === 'RESET_VIEW') {
86
+ viewer.resetView();
87
+ }
88
+ });
89
+ // Nothing else holds this: the shell drops the whole iframe on close, and pagehide is what runs
90
+ // when it does. Without it the GPU keeps the context until the collector gets round to it.
91
+ window.addEventListener('pagehide', function () { viewer.dispose(); });
92
+ } catch (error) {
93
+ var reason = error && error.message ? error.message : String(error);
94
+ status.textContent = reason;
95
+ status.classList.add('failed');
96
+ tell({ type: 'ASSET_PREVIEW_FAILED', error: reason });
97
+ }
98
+ </script>
99
+ </body>
100
+ </html>
101
+ `;
102
+ }
103
+ //# sourceMappingURL=asset-preview-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-preview-page.js","sourceRoot":"","sources":["../../src/editor/asset-preview-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAQ1D,yFAAyF;AACzF,SAAS,YAAY,CAAC,QAAgB;IACpC,MAAM,MAAM,GAAG,oBAAoB,QAAQ,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAC/B,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CACzF,CAAC;IACF,OAAO,EAAE,GAAG,WAAW,EAAE,GAAG,MAAM,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAgC;IACrE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACrF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;EAyBP,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CR,CAAC;AACF,CAAC"}
@@ -0,0 +1,19 @@
1
+ /** What the panel knows about an asset, reduced to what there is to draw. */
2
+ export type AssetViewerKind = 'glb' | 'vxl';
3
+ export interface AssetViewerOptions {
4
+ /** The element to fill. Sized by CSS; the viewer follows it. */
5
+ container: HTMLElement;
6
+ /** The GLB or VXL to show. For `vxl` this is fetched through the sidecar, not directly. */
7
+ url: string;
8
+ kind: AssetViewerKind;
9
+ /** Where to fetch bytes from, so the caller can point this at its own origin. */
10
+ sourceEndpoint: string;
11
+ }
12
+ export interface AssetViewerHandle {
13
+ /** Back to the angle the thumbnail was rendered at. */
14
+ resetView(): void;
15
+ /** Triangles in the loaded object — the one number that says "this is a heavy asset". */
16
+ readonly triangles: number;
17
+ dispose(): void;
18
+ }
19
+ export declare function startAssetViewer(options: AssetViewerOptions): Promise<AssetViewerHandle>;
@@ -0,0 +1,218 @@
1
+ /**
2
+ * The orbitable asset viewer the dev view opens when a creator clicks a row in the assets panel.
3
+ *
4
+ * ── Why this is browser code living in `cli/src` ─────────────────────────────────────────────
5
+ *
6
+ * The obvious home is `game/`, next to the engine's own preview renderers, served as a standalone
7
+ * page the way `game/animation-preview.html` already is. That route was designed and rejected on
8
+ * distribution, not on rendering:
9
+ *
10
+ * - The engine tarball ships `game/src/**`, `game/agent-docs`, `sw-cache-buster.js` and
11
+ * `templates` — and **no `game/*.html`**. A page under `game/` can never reach a scaffolded
12
+ * project; it would have to be hand-retyped as a second copy inside `scaffold/project-files.ts`,
13
+ * with nothing comparing the two.
14
+ * - A module under `game/src/debug/` reaches projects only through a nightly tarball plus
15
+ * `bitmagic upgrade` — which refuses a dirty git tree and replaces `engine/` wholesale. That
16
+ * asks a creator to commit their work and take a full engine bump in order to look at a tree.
17
+ *
18
+ * `editor/server.ts`'s own header already states the principle this follows: `bitmagic dev` ships
19
+ * its own shell and its own endpoints, so an old project gets the new view by upgrading the CLI
20
+ * alone. This file is that — served from `dist/` by the sidecar at `/asset-viewer.js`.
21
+ *
22
+ * Unlike `shell-page.ts`, which is a string and therefore invisible to tsc, this is real
23
+ * TypeScript: it is type-checked and linted with the rest of the package. `cli/tsconfig.json`
24
+ * already carries `lib: ["DOM"]` for exactly this kind of file.
25
+ *
26
+ * ── The one import map, and why `three` must be the engine's `three` ─────────────────────────
27
+ *
28
+ * Bare specifiers here (`three`, `three/examples/jsm/…`, and the two `engine/…` modules the voxel
29
+ * path pulls) are resolved by the import map on the page that loads this — generated in
30
+ * `asset-preview-page.ts` from the same `CDN_IMPORTS` a scaffolded `index.html` uses, with the
31
+ * `engine/` prefixes pointed at the project's own vite server.
32
+ *
33
+ * That sharing is not tidiness. `three` resolves to the WEBGPU build, and r185 matches lights to
34
+ * materials by class identity: a viewer that pulled the classic build while the engine modules
35
+ * pulled the webgpu one would produce two module instances and render every voxel mesh unlit. So
36
+ * this file imports `three` exactly as the engine does — including taking `WebGLRenderer` from its
37
+ * own module, because the webgpu build does not export one.
38
+ */
39
+ import * as THREE from 'three';
40
+ import { WebGLRenderer } from 'three/src/renderers/WebGLRenderer.js';
41
+ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
42
+ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
43
+ /**
44
+ * The framing every Bitmagic thumbnail uses: 30° above the horizon, 45° around Y, at 2.8 × the
45
+ * bounding sphere's radius.
46
+ *
47
+ * Copied deliberately from `GlbPreviewRenderer` and `VoxelPreviewRenderer`, which both use it, so
48
+ * the overlay opens on exactly the picture the creator clicked and only then lets them move. A
49
+ * viewer that opened on some other angle would read as a different asset for the first second.
50
+ */
51
+ const CAMERA_ELEVATION = Math.PI / 6;
52
+ const CAMERA_AZIMUTH = Math.PI / 4;
53
+ const CAMERA_DISTANCE_FACTOR = 2 * 1.4;
54
+ /** The engine's preview lighting, so a mesh looks the same here as it does in its tile. */
55
+ function addPreviewLights(scene) {
56
+ scene.add(new THREE.AmbientLight(0xffffff, 1.2));
57
+ const key = new THREE.DirectionalLight(0xffffff, 1.5);
58
+ key.position.set(5, 10, 7);
59
+ scene.add(key);
60
+ const fill = new THREE.DirectionalLight(0xffffff, 0.8);
61
+ fill.position.set(-3, 2, -5);
62
+ scene.add(fill);
63
+ }
64
+ function asMesh(object) {
65
+ const candidate = object;
66
+ return candidate.isMesh === true ? candidate : null;
67
+ }
68
+ function disposeMaterial(material) {
69
+ for (const value of Object.values(material)) {
70
+ const texture = value;
71
+ if (texture !== null && typeof texture === 'object' && texture.isTexture === true) {
72
+ texture.dispose?.();
73
+ }
74
+ }
75
+ material.dispose?.();
76
+ }
77
+ /** Recursively release geometries, materials and textures. A viewer opened and closed twenty times
78
+ * in a session must not leave a mesh on the GPU each time. */
79
+ function disposeObjectTree(root) {
80
+ root.traverse((object) => {
81
+ const mesh = asMesh(object);
82
+ if (mesh === null)
83
+ return;
84
+ mesh.geometry?.dispose?.();
85
+ const material = mesh.material;
86
+ if (Array.isArray(material)) {
87
+ for (const entry of material)
88
+ disposeMaterial(entry);
89
+ }
90
+ else if (material) {
91
+ disposeMaterial(material);
92
+ }
93
+ });
94
+ }
95
+ function countTriangles(root) {
96
+ let triangles = 0;
97
+ root.traverse((object) => {
98
+ const mesh = asMesh(object);
99
+ if (mesh === null || !mesh.geometry)
100
+ return;
101
+ const index = mesh.geometry.getIndex?.();
102
+ const position = mesh.geometry.getAttribute?.('position');
103
+ if (index)
104
+ triangles += index.count / 3;
105
+ else if (position)
106
+ triangles += position.count / 3;
107
+ });
108
+ return Math.round(triangles);
109
+ }
110
+ /**
111
+ * Specifier held in a variable on purpose: a literal would make tsc try to resolve a module that
112
+ * only exists on the other origin at runtime. The import map on the page resolves it.
113
+ */
114
+ const VOXEL_OBJECT_MODULE = 'engine/VoxelObject.js';
115
+ async function loadGlb(url) {
116
+ const gltf = await new GLTFLoader().loadAsync(url);
117
+ gltf.scene.updateMatrixWorld(true);
118
+ return gltf.scene;
119
+ }
120
+ /**
121
+ * Build the voxel asset at FULL detail — deliberately not what the thumbnail does.
122
+ *
123
+ * `VoxelPreviewRenderer` renders the coarsest baked LOD for v3 files, and its comment explains
124
+ * why: building LOD0 for every asset would stall the live game for seconds each while the panel
125
+ * backfills tiles. Here there is exactly one asset, the creator asked to look at it, and the whole
126
+ * point is to see it properly — which is what `loadFromFile` gives.
127
+ *
128
+ * No material conversion is needed even though the engine runs on WebGPU: `RendererType` defaults
129
+ * to `'webgl'` and only `GameEngine` ever changes it, so a document that never boots the engine —
130
+ * this one — gets classic materials from the shared voxel factory already.
131
+ */
132
+ async function loadVxl(bytes) {
133
+ const module = await import(VOXEL_OBJECT_MODULE);
134
+ const object = new module.VoxelObject({ shadows: false });
135
+ const bounds = await object.loadFromFile(bytes);
136
+ if (bounds === null)
137
+ throw new Error('That voxel file has no geometry in it.');
138
+ return object;
139
+ }
140
+ /** Fetch through the sidecar rather than the asset host, so no CORS policy is in the way. */
141
+ async function fetchBytes(sourceEndpoint, url) {
142
+ const response = await fetch(`${sourceEndpoint}?url=${encodeURIComponent(url)}`);
143
+ if (!response.ok) {
144
+ const detail = await response.json().catch(() => null);
145
+ throw new Error(detail?.error ?? `The dev server answered ${response.status}`);
146
+ }
147
+ return response.arrayBuffer();
148
+ }
149
+ export async function startAssetViewer(options) {
150
+ const { container, url, kind, sourceEndpoint } = options;
151
+ const object = kind === 'vxl'
152
+ ? await loadVxl(await fetchBytes(sourceEndpoint, url))
153
+ : await loadGlb(url);
154
+ const scene = new THREE.Scene();
155
+ // The same slate the thumbnails are rendered on, so the tile and the overlay match.
156
+ scene.background = new THREE.Color(0x1e293b);
157
+ addPreviewLights(scene);
158
+ scene.add(object);
159
+ const renderer = new WebGLRenderer({ antialias: true });
160
+ renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
161
+ renderer.setSize(Math.max(container.clientWidth, 1), Math.max(container.clientHeight, 1));
162
+ renderer.outputColorSpace = THREE.SRGBColorSpace;
163
+ container.appendChild(renderer.domElement);
164
+ const sphere = new THREE.Box3().setFromObject(object).getBoundingSphere(new THREE.Sphere());
165
+ const radius = sphere.radius > 0 ? sphere.radius : 1;
166
+ const distance = radius * CAMERA_DISTANCE_FACTOR;
167
+ const camera = new THREE.PerspectiveCamera(45, Math.max(container.clientWidth, 1) / Math.max(container.clientHeight, 1), distance * 0.01, distance * 10);
168
+ const center = sphere.center;
169
+ const framed = new THREE.Vector3(center.x + Math.cos(CAMERA_AZIMUTH) * Math.cos(CAMERA_ELEVATION) * distance, center.y + Math.sin(CAMERA_ELEVATION) * distance, center.z + Math.sin(CAMERA_AZIMUTH) * Math.cos(CAMERA_ELEVATION) * distance);
170
+ camera.position.copy(framed);
171
+ camera.lookAt(center);
172
+ const controls = new OrbitControls(camera, renderer.domElement);
173
+ controls.target.copy(center);
174
+ controls.enableDamping = true;
175
+ // Bounded by the asset's own size rather than by constants: a 0.5 m prop and a 200 m level both
176
+ // have to be reachable with the same scroll wheel.
177
+ controls.minDistance = radius * 0.4;
178
+ controls.maxDistance = radius * 20;
179
+ controls.update();
180
+ // The container, not the window: this viewer lives in a dialog that resizes on its own.
181
+ const resize = new ResizeObserver(() => {
182
+ const width = Math.max(container.clientWidth, 1);
183
+ const height = Math.max(container.clientHeight, 1);
184
+ camera.aspect = width / height;
185
+ camera.updateProjectionMatrix();
186
+ renderer.setSize(width, height);
187
+ });
188
+ resize.observe(container);
189
+ let frame = 0;
190
+ const tick = () => {
191
+ frame = requestAnimationFrame(tick);
192
+ controls.update();
193
+ renderer.render(scene, camera);
194
+ };
195
+ tick();
196
+ return {
197
+ triangles: countTriangles(object),
198
+ resetView() {
199
+ camera.position.copy(framed);
200
+ controls.target.copy(center);
201
+ controls.update();
202
+ },
203
+ dispose() {
204
+ cancelAnimationFrame(frame);
205
+ resize.disconnect();
206
+ controls.dispose();
207
+ scene.remove(object);
208
+ disposeObjectTree(object);
209
+ renderer.dispose();
210
+ // Hand the GPU back rather than waiting for the collector. The game is running in the next
211
+ // iframe over, and browsers drop the OLDEST context when the cap is reached — which would be
212
+ // the creator's game, not this decoration.
213
+ renderer.forceContextLoss();
214
+ renderer.domElement.remove();
215
+ },
216
+ };
217
+ }
218
+ //# sourceMappingURL=asset-viewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-viewer.js","sourceRoot":"","sources":["../../src/editor/asset-viewer.ts"],"names":[],"mappings":"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"}