@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 +27 -5
- package/dist/commands/verify.js +16 -3
- package/dist/commands/verify.js.map +1 -1
- package/dist/editor/asset-detail-panel.d.ts +22 -0
- package/dist/editor/asset-detail-panel.js +72 -0
- package/dist/editor/asset-detail-panel.js.map +1 -0
- package/dist/editor/asset-preview-page.d.ts +6 -0
- package/dist/editor/asset-preview-page.js +103 -0
- package/dist/editor/asset-preview-page.js.map +1 -0
- package/dist/editor/asset-viewer.d.ts +19 -0
- package/dist/editor/asset-viewer.js +218 -0
- package/dist/editor/asset-viewer.js.map +1 -0
- package/dist/editor/server.js +128 -0
- package/dist/editor/server.js.map +1 -1
- package/dist/editor/shell-page.js +309 -30
- package/dist/editor/shell-page.js.map +1 -1
- package/dist/scaffold/project-files.d.ts +6 -0
- package/dist/scaffold/project-files.js +5 -1
- package/dist/scaffold/project-files.js.map +1 -1
- package/dist/verify/browser.js +30 -0
- package/dist/verify/browser.js.map +1 -1
- package/dist/verify/classify.d.ts +4 -0
- package/dist/verify/classify.js +26 -0
- package/dist/verify/classify.js.map +1 -1
- package/dist/verify/events.d.ts +41 -0
- package/dist/verify/events.js +72 -0
- package/dist/verify/events.js.map +1 -0
- package/dist/verify/iterate.js +3 -1
- package/dist/verify/iterate.js.map +1 -1
- package/dist/verify/result.d.ts +5 -1
- package/dist/verify/result.js.map +1 -1
- package/dist/verify/url.d.ts +12 -0
- package/dist/verify/url.js +14 -0
- package/dist/verify/url.js.map +1 -0
- package/package.json +2 -1
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
|
|
212
|
-
once and cached in `.bitmagic/previews/` — so they cost nothing on later
|
|
213
|
-
feeds the editor's right-click **Add object** palette, which used to show
|
|
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
|
|
package/dist/commands/verify.js
CHANGED
|
@@ -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:
|
|
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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"}
|