@bitmagic/cli 0.1.38 → 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.
Files changed (52) hide show
  1. package/README.md +59 -12
  2. package/dist/auth/subscribe-flow.d.ts +59 -0
  3. package/dist/auth/subscribe-flow.js +102 -0
  4. package/dist/auth/subscribe-flow.js.map +1 -0
  5. package/dist/cli.d.ts +14 -0
  6. package/dist/cli.js +2 -0
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/login.js +27 -7
  9. package/dist/commands/login.js.map +1 -1
  10. package/dist/commands/subscribe.d.ts +14 -0
  11. package/dist/commands/subscribe.js +60 -0
  12. package/dist/commands/subscribe.js.map +1 -0
  13. package/dist/commands/verify.js +16 -3
  14. package/dist/commands/verify.js.map +1 -1
  15. package/dist/commands/whoami.d.ts +10 -14
  16. package/dist/commands/whoami.js +17 -12
  17. package/dist/commands/whoami.js.map +1 -1
  18. package/dist/editor/asset-detail-panel.d.ts +22 -0
  19. package/dist/editor/asset-detail-panel.js +72 -0
  20. package/dist/editor/asset-detail-panel.js.map +1 -0
  21. package/dist/editor/asset-preview-page.d.ts +6 -0
  22. package/dist/editor/asset-preview-page.js +103 -0
  23. package/dist/editor/asset-preview-page.js.map +1 -0
  24. package/dist/editor/asset-viewer.d.ts +19 -0
  25. package/dist/editor/asset-viewer.js +218 -0
  26. package/dist/editor/asset-viewer.js.map +1 -0
  27. package/dist/editor/server.js +128 -0
  28. package/dist/editor/server.js.map +1 -1
  29. package/dist/editor/shell-page.js +309 -30
  30. package/dist/editor/shell-page.js.map +1 -1
  31. package/dist/http/client.d.ts +10 -0
  32. package/dist/http/client.js +38 -3
  33. package/dist/http/client.js.map +1 -1
  34. package/dist/scaffold/project-files.d.ts +6 -0
  35. package/dist/scaffold/project-files.js +9 -3
  36. package/dist/scaffold/project-files.js.map +1 -1
  37. package/dist/verify/browser.js +30 -0
  38. package/dist/verify/browser.js.map +1 -1
  39. package/dist/verify/classify.d.ts +4 -0
  40. package/dist/verify/classify.js +26 -0
  41. package/dist/verify/classify.js.map +1 -1
  42. package/dist/verify/events.d.ts +41 -0
  43. package/dist/verify/events.js +72 -0
  44. package/dist/verify/events.js.map +1 -0
  45. package/dist/verify/iterate.js +3 -1
  46. package/dist/verify/iterate.js.map +1 -1
  47. package/dist/verify/result.d.ts +5 -1
  48. package/dist/verify/result.js.map +1 -1
  49. package/dist/verify/url.d.ts +12 -0
  50. package/dist/verify/url.js +14 -0
  51. package/dist/verify/url.js.map +1 -0
  52. package/package.json +2 -1
@@ -48,6 +48,7 @@
48
48
  * nothing. Polling `CHECK_SCENE_CHANGES` is what the Creator does too, just on tab switch
49
49
  * instead of on a timer, and it covers drags, deletes, adds and inspector edits with one path.
50
50
  */
51
+ import { ASSET_DETAIL_CSS, ASSET_DETAIL_HTML } from './asset-detail-panel.js';
51
52
  /** How often the shell asks the engine whether anything changed. A `Set` read; effectively free. */
52
53
  const POLL_INTERVAL_MS = 500;
53
54
  /**
@@ -121,6 +122,8 @@ export function renderEditorShell(options) {
121
122
  #assets-head .count { margin-left: auto; color: #6a6a7a; letter-spacing: 0; }
122
123
  #assets-empty { padding: 14px 10px; color: #6a6a7a; }
123
124
  .row { display: flex; gap: 9px; padding: 8px 10px; border-bottom: 1px solid #1e1e26; }
125
+ .row.clickable { cursor: pointer; }
126
+ .row.clickable:hover, .row.clickable:focus-visible { background: #1b1b23; outline: none; }
124
127
  .row .thumb { width: 46px; height: 46px; flex: none; border-radius: 4px; background: #1e1e26;
125
128
  display: flex; align-items: center; justify-content: center; font-size: 18px;
126
129
  color: #55556a; overflow: hidden; }
@@ -177,6 +180,7 @@ export function renderEditorShell(options) {
177
180
  background: #101014; border: 1px solid #26262e; }
178
181
  #hq-note.show { display: block; }
179
182
  #hq-note code { display: block; margin-top: 6px; color: #9fd0a8; word-break: break-all; }
183
+ ${ASSET_DETAIL_CSS}
180
184
  </style>
181
185
  </head>
182
186
  <body>
@@ -235,6 +239,7 @@ export function renderEditorShell(options) {
235
239
  </div>
236
240
  </div>
237
241
  </div>
242
+ ${ASSET_DETAIL_HTML}
238
243
  <script>
239
244
  (function () {
240
245
  'use strict';
@@ -330,6 +335,13 @@ export function renderEditorShell(options) {
330
335
  var message = event.data;
331
336
  if (!message || typeof message.type !== 'string') return;
332
337
 
338
+ // The asset overlay's viewer is a second sender on this window. Its replies are routed by
339
+ // source, before the waiter list below gets to match anything on type alone.
340
+ if (assetFrame && event.source === assetFrame.contentWindow) {
341
+ onAssetPreviewMessage(message);
342
+ return;
343
+ }
344
+
333
345
  waiters = waiters.filter(function (waiter) {
334
346
  if (waiter.type !== message.type) return true;
335
347
  clearTimeout(waiter.timer);
@@ -938,23 +950,51 @@ export function renderEditorShell(options) {
938
950
  }
939
951
 
940
952
  /**
941
- * The URL the engine should draw a thumbnail from, or null when there is nothing to draw.
953
+ * How the engine should draw this asset's thumbnail, or null when there is nothing to draw.
954
+ *
955
+ * 'sourceGlbUrl' before 'url' because many CLI-lane meshes are voxelized: 'url' is then a .vxl,
956
+ * and the GLB the forger started from renders in one message with nothing to fetch here.
957
+ *
958
+ * A .vxl with NO GLB source used to fall through to a glyph, and that was most of the panel —
959
+ * across the sampled project worlds it is 153 such assets against 144 with a GLB source, and
960
+ * every fresh project starts in the bad half: templates/standard-3d ships nine assets, all vxl,
961
+ * none with a sourceGlbUrl or a screenshotUrl. So the whole assets panel of a new project was
962
+ * grey boxes. Those now go the voxel route, which the engine has been able to draw the entire
963
+ * time (VoxelMessageHandlers.handleGenerateVoxelPreview) and which the web Creator has used since
964
+ * before this lane existed.
942
965
  *
943
- * 'sourceGlbUrl' before 'url' because most CLI-lane meshes are voxelized: 'url' is then a .vxl,
944
- * which the GLB preview renderer cannot read, while 'sourceGlbUrl' is the original the forger or
945
- * the generator started from. An asset with neither — a sound, an animation, a level — keeps its
946
- * glyph, which is the honest answer for something with no appearance.
966
+ * An asset with neither a sound, an animation, a level keeps its glyph, which is the honest
967
+ * answer for something with no appearance.
947
968
  */
948
- function previewSourceFor(asset) {
949
- var url = asset.sourceGlbUrl || asset.url;
950
- if (typeof url !== 'string' || url === '') return null;
969
+ var MAX_VXL_PREVIEW_BYTES = 8 * 1024 * 1024;
970
+
971
+ function previewJobFor(asset) {
972
+ var glb = asset.sourceGlbUrl || asset.url;
951
973
  // Double-escaped because this whole page is a template literal: a single backslash is consumed
952
974
  // by the literal, and the browser would receive the invalid regex /.(glb|gltf)(?|$)/.
953
- return /\\.(glb|gltf)(\\?|$)/i.test(url) ? url : null;
975
+ if (typeof glb === 'string' && /\\.(glb|gltf)(\\?|$)/i.test(glb)) return { kind: 'glb', url: glb };
976
+ var url = asset.url;
977
+ if (typeof url !== 'string' || !/\\.vxl(\\?|$)/i.test(url)) return null;
978
+ // The voxel message carries the FILE, so this one costs a fetch and a structured clone of the
979
+ // whole thing. The templates' files are 0.5-2.5 KB; a multi-megabyte one is a hitch on the
980
+ // render thread in exchange for a 46px tile, and the glyph is the better trade.
981
+ if (typeof asset.size === 'number' && asset.size > MAX_VXL_PREVIEW_BYTES) return null;
982
+ return { kind: 'vxl', url: url };
954
983
  }
955
984
 
956
985
  function assetRow(asset, isFresh, hasPreview) {
957
- var row = el('div', 'row' + (isFresh ? ' fresh' : ''));
986
+ var row = el('div', 'row clickable' + (isFresh ? ' fresh' : ''));
987
+ // A row is a button: the panel is a list of things you can look at. Job rows deliberately are
988
+ // not — there is nothing to show for an asset that does not exist yet.
989
+ row.setAttribute('role', 'button');
990
+ row.setAttribute('tabindex', '0');
991
+ row.title = 'Open a preview of this asset';
992
+ row.addEventListener('click', function () { openAssetDetail(asset, hasPreview); });
993
+ row.addEventListener('keydown', function (event) {
994
+ if (event.key !== 'Enter' && event.key !== ' ') return;
995
+ event.preventDefault();
996
+ openAssetDetail(asset, hasPreview);
997
+ });
958
998
  var thumb = el('div', 'thumb');
959
999
  var type = String(asset.type || '').toLowerCase();
960
1000
  if (type === 'image' && typeof asset.url === 'string' && asset.url !== '') {
@@ -972,7 +1012,7 @@ export function renderEditorShell(options) {
972
1012
  thumb.appendChild(cached);
973
1013
  } else {
974
1014
  thumb.appendChild(el('span', '', glyphFor(asset.type)));
975
- if (previewSourceFor(asset) !== null) queuePreview(asset);
1015
+ if (previewJobFor(asset) !== null) queuePreview(asset);
976
1016
  }
977
1017
  row.appendChild(thumb);
978
1018
 
@@ -1035,26 +1075,71 @@ export function renderEditorShell(options) {
1035
1075
  }
1036
1076
 
1037
1077
  /**
1038
- * Ask the game to draw the thumbnails the cache is missing — one at a time, and never twice for
1078
+ * Ask the game to draw the thumbnails the cache is missing — one at a time, and at most twice for
1039
1079
  * the same asset in one session.
1040
1080
  *
1041
- * Serial on purpose. Each render is a GLB fetch and a draw in the SAME renderer the creator is
1042
- * playing in, and a forged city has hundreds of assets: firing them all at once would stutter the
1043
- * game to decorate a side panel. 'attempted' covers the failures too, so an asset whose GLB 404s
1044
- * is asked for once rather than on every render pass forever.
1081
+ * Serial on purpose. Each render is a fetch and a draw in the SAME renderer the creator is playing
1082
+ * in, and a forged city has hundreds of assets: firing them all at once would stutter the game to
1083
+ * decorate a side panel.
1084
+ *
1085
+ * Two rather than one attempt, and the second is not defensive padding. GENERATE_VOXEL_PREVIEW is
1086
+ * in the engine's REQUIRES_GAME_LOADED set (the GLB one is not), so a request arriving while a
1087
+ * game is loading is QUEUED and silently never answered. Marked attempted-once, that asset would
1088
+ * keep its glyph for the rest of the session; the retry costs one extra message and the cap keeps
1089
+ * a genuinely broken asset from asking forever.
1045
1090
  */
1091
+ var MAX_PREVIEW_ATTEMPTS = 2;
1046
1092
  var previewQueue = [];
1047
- var previewAttempted = {};
1093
+ var previewAttempts = {};
1048
1094
  var previewRunning = false;
1049
1095
  var previewRequestId = 0;
1050
1096
 
1051
1097
  function queuePreview(asset) {
1052
- if (previewAttempted[asset.id]) return;
1053
- previewAttempted[asset.id] = true;
1098
+ var attempts = previewAttempts[asset.id] || 0;
1099
+ if (attempts >= MAX_PREVIEW_ATTEMPTS) return;
1100
+ previewAttempts[asset.id] = attempts + 1;
1054
1101
  previewQueue.push(asset);
1055
1102
  void drainPreviewQueue();
1056
1103
  }
1057
1104
 
1105
+ /**
1106
+ * Both preview messages use the FLAT envelope and both are answered by requestId, so neither can
1107
+ * go through the request() helper — it matches on type alone.
1108
+ */
1109
+ function requestGlbPreview(url, requestId) {
1110
+ postFlat({ type: 'GENERATE_GLB_PREVIEW', requestId: requestId, glbUrl: url });
1111
+ return await_('GLB_PREVIEW_RESPONSE', 15000);
1112
+ }
1113
+
1114
+ /**
1115
+ * The voxel counterpart, ported from the web Creator's useAssetsEditor.requestVoxelPreview.
1116
+ *
1117
+ * The bytes come through the sidecar rather than straight from the asset host: this message
1118
+ * carries the file itself, and a browser fetch would make voxel thumbnails depend on that host's
1119
+ * CORS headers — see /api/assets/source.
1120
+ */
1121
+ async function requestVoxelPreview(url, requestId) {
1122
+ var bytes;
1123
+ try {
1124
+ var source = await fetch('/api/assets/source?url=' + encodeURIComponent(url));
1125
+ if (!source.ok) throw new Error('sidecar answered ' + source.status);
1126
+ bytes = new Uint8Array(await source.arrayBuffer());
1127
+ } catch (error) {
1128
+ // Worth a line: without one, an asset the sidecar cannot reach is a grey tile with no reason.
1129
+ console.warn('[bitmagic dev] no voxel preview for ' + url, error);
1130
+ return null;
1131
+ }
1132
+ postFlat({
1133
+ type: 'GENERATE_VOXEL_PREVIEW',
1134
+ requestId: requestId,
1135
+ // A plain number array, which is what the engine handler reads (new Uint8Array(data.vxlData)).
1136
+ // Not an ArrayBuffer: this page ships with the CLI and talks to whatever engine the project
1137
+ // has vendored, so the wire shape has to keep working against older ones.
1138
+ vxlData: Array.prototype.slice.call(bytes)
1139
+ });
1140
+ return await_('VOXEL_PREVIEW_RESPONSE', 15000);
1141
+ }
1142
+
1058
1143
  async function drainPreviewQueue() {
1059
1144
  if (previewRunning) return;
1060
1145
  previewRunning = true;
@@ -1065,20 +1150,24 @@ export function renderEditorShell(options) {
1065
1150
  // pass rather than being dropped — refreshAssets re-queues on every render.
1066
1151
  if (!loaded) return;
1067
1152
  var asset = previewQueue.shift();
1068
- var source = previewSourceFor(asset);
1069
- if (source === null) continue;
1153
+ var job = previewJobFor(asset);
1154
+ if (job === null) continue;
1070
1155
 
1071
1156
  previewRequestId += 1;
1072
- // Deliberately not the request() helper: this message uses the FLAT envelope, and the reply
1073
- // has to be matched on requestId (below) rather than on type alone.
1074
1157
  var requestId = 'preview-' + previewRequestId;
1075
- postFlat({ type: 'GENERATE_GLB_PREVIEW', requestId: requestId, glbUrl: source });
1076
- var response = await await_('GLB_PREVIEW_RESPONSE', 15000);
1077
- // Verified rather than assumed: a late answer from a request that already timed out would
1078
- // otherwise be cached under the NEXT asset's id, which is a wrong picture rather than a
1079
- // missing one much the worse failure.
1080
- if (!response || response.requestId !== requestId) continue;
1081
- if (!response.success || !response.previewBase64) continue;
1158
+ var response = job.kind === 'vxl'
1159
+ ? await requestVoxelPreview(job.url, requestId)
1160
+ : await requestGlbPreview(job.url, requestId);
1161
+
1162
+ // The requestId is verified rather than assumed: a late answer from a request that already
1163
+ // timed out would otherwise be cached under the NEXT asset's id, which is a wrong picture
1164
+ // rather than a missing one — much the worse failure.
1165
+ if (!response || response.requestId !== requestId || !response.success || !response.previewBase64) {
1166
+ // Back of the queue, behind everything else, and only while attempts remain. This is the
1167
+ // path a request swallowed by REQUIRES_GAME_LOADED takes.
1168
+ queuePreview(asset);
1169
+ continue;
1170
+ }
1082
1171
 
1083
1172
  var saved = await (await fetch('/api/assets/preview', {
1084
1173
  method: 'POST',
@@ -1126,6 +1215,196 @@ export function renderEditorShell(options) {
1126
1215
  }, 1000);
1127
1216
  }
1128
1217
 
1218
+ /**
1219
+ * The asset overlay — everything a 46px tile cannot show.
1220
+ *
1221
+ * The viewer itself is an iframe onto '/asset-preview', which the dev sidecar serves from this
1222
+ * same origin. It is not part of the game: the game keeps its own WebGL context in the frame
1223
+ * behind this dialog, and the two never share a renderer.
1224
+ */
1225
+ var assetOverlay = document.getElementById('asset-overlay');
1226
+ var assetFrame = document.getElementById('asset-frame');
1227
+ var assetImage = document.getElementById('asset-image');
1228
+ var assetAudio = document.getElementById('asset-audio');
1229
+ var assetNote = document.getElementById('asset-note');
1230
+ var assetFacts = document.getElementById('asset-facts');
1231
+ var assetResetButton = document.getElementById('asset-reset');
1232
+ var assetPausedByOverlay = false;
1233
+ var assetReturnFocus = null;
1234
+ var assetLoadTimer = null;
1235
+
1236
+ var IMAGE_TYPES = { image: 1, skybox: 1 };
1237
+ var AUDIO_TYPES = { audio: 1, sound: 1, 'sound-effect': 1 };
1238
+
1239
+ /**
1240
+ * What the VIEWER should load — which is not always what the thumbnail drew.
1241
+ *
1242
+ * previewJobFor prefers a voxelized asset's GLB source, because one message with no fetch is the
1243
+ * cheaper way to fill a 46px tile. Here the creator has asked to look at a specific asset, so it
1244
+ * shows the asset: a .vxl is drawn as voxels even when the mesh it was baked from is on record.
1245
+ */
1246
+ function detailJobFor(asset) {
1247
+ var url = asset.url;
1248
+ if (typeof url === 'string' && /\\.vxl(\\?|$)/i.test(url)) {
1249
+ if (typeof asset.size === 'number' && asset.size > MAX_VXL_PREVIEW_BYTES) return null;
1250
+ return { kind: 'vxl', url: url };
1251
+ }
1252
+ var glb = asset.sourceGlbUrl || url;
1253
+ if (typeof glb === 'string' && /\\.(glb|gltf)(\\?|$)/i.test(glb)) return { kind: 'glb', url: glb };
1254
+ return null;
1255
+ }
1256
+
1257
+ function fact(term, value) {
1258
+ if (!value) return;
1259
+ assetFacts.appendChild(el('dt', '', term));
1260
+ assetFacts.appendChild(el('dd', term === 'Id' ? 'mono' : '', value));
1261
+ }
1262
+
1263
+ /** Extent in world units, which is the number that says whether a prop is door-sized. */
1264
+ function dimensionsOf(asset) {
1265
+ var box = asset.boundingBox;
1266
+ if (!box || typeof box.minX !== 'number') return '';
1267
+ var round = function (n) { return Math.round(n * 10) / 10; };
1268
+ return round(box.maxX - box.minX) + ' × ' + round(box.maxY - box.minY) + ' × ' + round(box.maxZ - box.minZ);
1269
+ }
1270
+
1271
+ function showAssetNote(text) {
1272
+ assetNote.textContent = text;
1273
+ assetNote.classList.remove('hidden');
1274
+ }
1275
+
1276
+ function openAssetDetail(asset, hasPreview) {
1277
+ assetReturnFocus = document.activeElement;
1278
+ document.getElementById('asset-name').textContent = asset.name || asset.id || 'unnamed';
1279
+ document.getElementById('asset-sub').textContent =
1280
+ (asset.hqGeneratedAt ? 'High quality · ' : asset.placeholder === true ? 'Placeholder · ' : '')
1281
+ + (asset.type || 'unknown');
1282
+
1283
+ assetFacts.textContent = '';
1284
+ fact('Size', formatSize(asset.size));
1285
+ fact('Extent', dimensionsOf(asset));
1286
+ fact('Voxels', typeof asset.voxelCount === 'number' ? String(asset.voxelCount) : '');
1287
+ fact('Id', asset.id || '');
1288
+
1289
+ assetNote.classList.add('hidden');
1290
+ assetFrame.classList.add('hidden');
1291
+ assetImage.classList.add('hidden');
1292
+ assetAudio.classList.add('hidden');
1293
+ assetResetButton.classList.add('hidden');
1294
+ if (assetLoadTimer) clearTimeout(assetLoadTimer);
1295
+
1296
+ var type = String(asset.type || '').toLowerCase();
1297
+ var job = detailJobFor(asset);
1298
+
1299
+ if (IMAGE_TYPES[type] === 1 && typeof asset.url === 'string' && asset.url !== '') {
1300
+ // An image is already the thing. Loading a 3D viewer to show a picture would be theatre.
1301
+ assetImage.src = asset.url;
1302
+ assetImage.classList.remove('hidden');
1303
+ } else if (AUDIO_TYPES[type] === 1 && typeof asset.url === 'string' && asset.url !== '') {
1304
+ assetAudio.src = asset.url;
1305
+ assetAudio.classList.remove('hidden');
1306
+ } else if (job !== null) {
1307
+ assetResetButton.classList.remove('hidden');
1308
+ assetFrame.classList.remove('hidden');
1309
+ assetFrame.src = '/asset-preview?kind=' + job.kind + '&url=' + encodeURIComponent(job.url);
1310
+ // Not a deadline for the load — a big mesh over a slow CDN legitimately takes a while, and
1311
+ // replacing a working viewer with an apology would be worse than waiting. This only speaks
1312
+ // when the page has said nothing at all, which is what a module graph that failed to load
1313
+ // looks like: the page's own catch reports every error it can see, and cannot report that.
1314
+ assetLoadTimer = setTimeout(function () {
1315
+ showAssetNote('Still loading. If this does not clear, check the dev server output.');
1316
+ }, 12000);
1317
+ } else {
1318
+ showAssetThumbnailFallback(asset, hasPreview,
1319
+ 'There is nothing to draw for this asset type — it has no mesh and no picture.');
1320
+ }
1321
+
1322
+ assetOverlay.classList.add('show');
1323
+ document.getElementById('asset-close').focus();
1324
+
1325
+ // The game is a WebGL context and a physics step running behind a dialog nobody is looking at.
1326
+ // The Editor tab is already paused by applyTab, so this only fires on the Game tab.
1327
+ if (activeTab === 'game' && gameState === 'playing') {
1328
+ post('SET_PAUSE', { paused: true });
1329
+ assetPausedByOverlay = true;
1330
+ }
1331
+ }
1332
+
1333
+ /** When the viewer cannot show it, show the tile that was already rendered, and say why. */
1334
+ function showAssetThumbnailFallback(asset, hasPreview, reason) {
1335
+ assetFrame.classList.add('hidden');
1336
+ assetResetButton.classList.add('hidden');
1337
+ if (hasPreview) {
1338
+ assetImage.src = '/api/assets/preview/' + encodeURIComponent(asset.id) + '.png';
1339
+ assetImage.classList.remove('hidden');
1340
+ }
1341
+ showAssetNote(reason);
1342
+ }
1343
+
1344
+ function closeAssetDetail() {
1345
+ if (!assetOverlay.classList.contains('show')) return false;
1346
+ assetOverlay.classList.remove('show');
1347
+ if (assetLoadTimer) clearTimeout(assetLoadTimer);
1348
+ // about:blank rather than hiding it: an idle iframe would hold a WebGL context and a render
1349
+ // loop for the rest of the session, next to the game that needs both.
1350
+ assetFrame.src = 'about:blank';
1351
+ assetImage.removeAttribute('src');
1352
+ assetAudio.pause();
1353
+ assetAudio.removeAttribute('src');
1354
+ if (assetPausedByOverlay) {
1355
+ post('SET_PAUSE', { paused: false });
1356
+ assetPausedByOverlay = false;
1357
+ }
1358
+ if (assetReturnFocus && assetReturnFocus.focus) assetReturnFocus.focus();
1359
+ assetReturnFocus = null;
1360
+ return true;
1361
+ }
1362
+
1363
+ /**
1364
+ * Replies from the preview iframe, matched by SOURCE rather than by type.
1365
+ *
1366
+ * The message listener below resolves its waiters on type alone, so a second sender on this
1367
+ * window could answer a request meant for the game. Today their vocabularies do not overlap;
1368
+ * this is what keeps that from being a silent bug the day one of them gains a name the other
1369
+ * already uses.
1370
+ */
1371
+ function onAssetPreviewMessage(message) {
1372
+ if (message.type === 'ASSET_PREVIEW_READY') {
1373
+ if (assetLoadTimer) clearTimeout(assetLoadTimer);
1374
+ assetNote.classList.add('hidden');
1375
+ if (typeof message.triangles === 'number' && message.triangles > 0) {
1376
+ fact('Triangles', message.triangles.toLocaleString());
1377
+ }
1378
+ } else if (message.type === 'ASSET_PREVIEW_FAILED') {
1379
+ if (assetLoadTimer) clearTimeout(assetLoadTimer);
1380
+ assetFrame.src = 'about:blank';
1381
+ showAssetNote(message.error || 'The preview could not be loaded.');
1382
+ }
1383
+ }
1384
+
1385
+ assetResetButton.addEventListener('click', function () {
1386
+ if (assetFrame.contentWindow) {
1387
+ assetFrame.contentWindow.postMessage({ type: 'RESET_VIEW' }, window.location.origin);
1388
+ }
1389
+ });
1390
+ document.getElementById('asset-copy').addEventListener('click', function () {
1391
+ var id = assetFacts.querySelector('dd.mono');
1392
+ if (id && navigator.clipboard) void navigator.clipboard.writeText(id.textContent);
1393
+ });
1394
+ document.getElementById('asset-close').addEventListener('click', closeAssetDetail);
1395
+ assetOverlay.addEventListener('mousedown', function (event) {
1396
+ // mousedown, not click: a drag that starts inside the viewer and ends on the backdrop is a
1397
+ // creator turning the model, not a creator dismissing the dialog.
1398
+ if (event.target === assetOverlay) closeAssetDetail();
1399
+ });
1400
+
1401
+ // The page had no keyboard handling at all before this, so #hq-overlay gains Escape with it.
1402
+ document.addEventListener('keydown', function (event) {
1403
+ if (event.key !== 'Escape') return;
1404
+ if (closeAssetDetail()) return;
1405
+ hqOverlay.classList.remove('show');
1406
+ });
1407
+
1129
1408
  /**
1130
1409
  * Lend the cached thumbnails to the engine's own asset palette.
1131
1410
  *
@@ -1 +1 @@
1
- {"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,oGAAoG;AACpG,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC,kGAAkG;AAClG,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AASD,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,MAAM,OAAO,GAAG,oBAAoB,OAAO,CAAC,QAAQ,2BAA2B,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IACpH,OAAO;;;;wBAIe,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBA8G3B,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAwD9B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;kBACxB,gBAAgB;yBACT,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgnC7C,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE9E,oGAAoG;AACpG,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC,kGAAkG;AAClG,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AASD,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,MAAM,OAAO,GAAG,oBAAoB,OAAO,CAAC,QAAQ,2BAA2B,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IACpH,OAAO;;;;wBAIe,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2GhD,gBAAgB;;;;;;uBAMK,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqD/C,iBAAiB;;;;mBAIA,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;kBACxB,gBAAgB;yBACT,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAk4C7C,CAAC;AACF,CAAC"}
@@ -2,5 +2,15 @@ import type { Environment } from '../config/environments.js';
2
2
  export interface ApiDeps {
3
3
  fetch: typeof globalThis.fetch;
4
4
  }
5
+ type FetchResponse = Awaited<ReturnType<typeof globalThis.fetch>>;
6
+ /**
7
+ * PURE-ish: turn a 403 into the sentence that actually helps.
8
+ *
9
+ * Falls back to the generic wording whenever the body is missing, unparseable
10
+ * or from an older api-server — a CLI that throws while explaining a refusal
11
+ * would be worse than one that explains it vaguely.
12
+ */
13
+ export declare function proRefusalMessage(response: FetchResponse): Promise<string>;
5
14
  export declare function apiGet<T>(environment: Environment, path: string, accessToken: string, deps: ApiDeps): Promise<T>;
6
15
  export declare function apiPost<T>(environment: Environment, path: string, accessToken: string, body: unknown, deps: ApiDeps): Promise<T>;
16
+ export {};
@@ -1,4 +1,33 @@
1
1
  import { CliError } from '../errors.js';
2
+ /** '2026-08-03T00:00:00.000Z' -> '2026-08-03'; anything unparseable is dropped. */
3
+ function refusalDate(iso) {
4
+ if (typeof iso !== 'string' || iso.length < 10)
5
+ return null;
6
+ return Number.isNaN(new Date(iso).getTime()) ? null : iso.slice(0, 10);
7
+ }
8
+ /**
9
+ * PURE-ish: turn a 403 into the sentence that actually helps.
10
+ *
11
+ * Falls back to the generic wording whenever the body is missing, unparseable
12
+ * or from an older api-server — a CLI that throws while explaining a refusal
13
+ * would be worse than one that explains it vaguely.
14
+ */
15
+ export async function proRefusalMessage(response) {
16
+ let body = {};
17
+ try {
18
+ body = (await response.json());
19
+ }
20
+ catch {
21
+ // Keep the generic message.
22
+ }
23
+ if (body.code === 'pro_expired') {
24
+ const ended = refusalDate(body.proUntil);
25
+ return (`Your Bitmagic Pro subscription ${ended ? `ended on ${ended}` : 'has ended'}. ` +
26
+ 'Run `bitmagic subscribe` to start it again — your games and projects are untouched.');
27
+ }
28
+ return ('The Bitmagic CLI requires an active Bitmagic Pro subscription. ' +
29
+ 'Run `bitmagic subscribe` to start one.');
30
+ }
2
31
  /**
3
32
  * Shared status handling for every api-server call: the transport-failure/error-status split,
4
33
  * and the 401/403/503/other mapping. `apiGet` and `apiPost` differ only in the fetch `init` they
@@ -21,9 +50,15 @@ async function request(environment, path, accessToken, deps, init) {
21
50
  throw new CliError('Your session has expired. Run `bitmagic login`.');
22
51
  }
23
52
  if (response.status === 403) {
24
- throw new CliError('Your account is authenticated but is not entitled to the Bitmagic CLI. The CLI ' +
25
- 'requires an active Bitmagic Pro subscription, which you can start from your plan ' +
26
- 'page, or the Admin role, which a Bitmagic admin can grant.');
53
+ // The gate is Bitmagic Pro and nothing else, and `subscribe` is a command
54
+ // that finishes the job so name it rather than describing a web page the
55
+ // creator would have to go find.
56
+ //
57
+ // Read the body: api-server distinguishes a lapsed subscription from one
58
+ // that never existed, and telling a returning customer to "start one"
59
+ // reads as though their year of paying never happened — it sends them
60
+ // hunting for a problem with their account instead of renewing.
61
+ throw new CliError(await proRefusalMessage(response));
27
62
  }
28
63
  if (response.status === 503) {
29
64
  throw new CliError(`api-server reported this feature is unavailable in the "${environment.name}" environment.`);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/http/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAaxC;;;;GAIG;AACH,KAAK,UAAU,OAAO,CACpB,WAAwB,EACxB,IAAY,EACZ,WAAmB,EACnB,IAAa,EACb,IAA4C;IAE5C,MAAM,GAAG,GAAG,GAAG,WAAW,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;IAE3C,IAAI,QAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,gFAAgF;QAChF,MAAM,IAAI,QAAQ,CAAC,8BAA8B,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;IACtC,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,QAAQ,CAAC,iDAAiD,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,QAAQ,CAChB,iFAAiF;YAC/E,mFAAmF;YACnF,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,QAAQ,CAChB,2DAA2D,WAAW,CAAC,IAAI,gBAAgB,CAC5F,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,QAAQ,CAAC,4BAA4B,QAAQ,CAAC,MAAM,QAAQ,IAAI,GAAG,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,WAAwB,EACxB,IAAY,EACZ,WAAmB,EACnB,IAAa;IAEb,OAAO,OAAO,CAAI,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE;QACtD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;KAChF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,WAAwB,EACxB,IAAY,EACZ,WAAmB,EACnB,IAAa,EACb,IAAa;IAEb,OAAO,OAAO,CAAI,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE;QACtD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,WAAW,EAAE;YACtC,MAAM,EAAE,kBAAkB;YAC1B,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/http/client.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,12 @@ export declare const DEPENDENCIES: {
17
17
  three: string;
18
18
  };
19
19
  export declare const DEV_DEPENDENCIES: Record<string, string>;
20
+ /** Resolved in the browser from a CDN, not from node_modules — see the design's import-map note. */
21
+ /**
22
+ * Exported so the dev view's asset-preview page builds its map from this one definition rather
23
+ * than a sixth hand-typed copy. See `editor/asset-preview-page.ts`.
24
+ */
25
+ export declare const CDN_IMPORTS: Record<string, string>;
20
26
  export declare function renderPackageJson(name: string): string;
21
27
  export declare function renderTsconfig(): string;
22
28
  export declare function renderIndexHtml(): string;
@@ -71,7 +71,11 @@ const THREE_SHIM = [
71
71
  `export{UniformsLib}from'https://esm.sh/three@${THREE_VERSION}/src/renderers/shaders/UniformsLib.js'`,
72
72
  ].join('');
73
73
  /** Resolved in the browser from a CDN, not from node_modules — see the design's import-map note. */
74
- const CDN_IMPORTS = {
74
+ /**
75
+ * Exported so the dev view's asset-preview page builds its map from this one definition rather
76
+ * than a sixth hand-typed copy. See `editor/asset-preview-page.ts`.
77
+ */
78
+ export const CDN_IMPORTS = {
75
79
  // `three` and `three/webgpu` are ONE module instance (see THREE_SHIM). Pointed at separate
76
80
  // builds (core + webgpu) they are two, and r185's LightsNode then fails to recognise lights
77
81
  // built by the other instance — the scene renders unlit. Keep in step with game/index.html.
@@ -1125,7 +1129,8 @@ running before you start implementing rather than after.
1125
1129
  - **Not logged in** — run \`bitmagic login\`.
1126
1130
  - **Does not own the game** — \`bitmagic.json\`'s \`gameId\` points at someone else's game; nothing
1127
1131
  was generated and \`world.json\` is untouched.
1128
- - **Insufficient balance** — the message names what was required. A shorter animation costs less.
1132
+ - **Insufficient balance** — the message names what was required. That is the Pro allowance plus
1133
+ any purchased sparks; \`bitmagic usage\` shows which is short and when the allowance resets.
1129
1134
 
1130
1135
  Every failure before the asset arrives leaves \`world.json\` unchanged, and the command says so
1131
1136
  explicitly. You never need to guess whether a failed generation half-applied.
@@ -1186,7 +1191,8 @@ request needs several generations, tell the human before starting, not after.
1186
1191
  ## When it refuses
1187
1192
 
1188
1193
  - **Not logged in** — run \`bitmagic login\`.
1189
- - **Not entitled** — the CLI needs an active Bitmagic Pro subscription or the Admin role.
1194
+ - **Not entitled** — the CLI needs an active Bitmagic Pro subscription. \`bitmagic subscribe\`
1195
+ starts one.
1190
1196
 
1191
1197
  ## What it does not show
1192
1198
 
@@ -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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"}