@bitmagic/cli 0.1.52-dev.7 → 0.1.52-dev.9
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 +40 -0
- package/dist/bin.js +25 -0
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +13 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/levels.d.ts +33 -0
- package/dist/commands/levels.js +241 -0
- package/dist/commands/levels.js.map +1 -0
- package/dist/editor/journal.d.ts +17 -1
- package/dist/editor/journal.js +2 -0
- package/dist/editor/journal.js.map +1 -1
- package/dist/editor/server.js +75 -92
- package/dist/editor/server.js.map +1 -1
- package/dist/editor/shell-page.js +119 -114
- package/dist/editor/shell-page.js.map +1 -1
- package/dist/editor/voxel-save.js +8 -12
- package/dist/editor/voxel-save.js.map +1 -1
- package/dist/generate/prop.d.ts +52 -4
- package/dist/generate/prop.js +167 -46
- package/dist/generate/prop.js.map +1 -1
- package/dist/generate/stream.d.ts +7 -0
- package/dist/generate/stream.js +2 -1
- package/dist/generate/stream.js.map +1 -1
- package/dist/levels/registry.d.ts +88 -0
- package/dist/levels/registry.js +309 -0
- package/dist/levels/registry.js.map +1 -0
- package/dist/messages/check.d.ts +30 -0
- package/dist/messages/check.js +119 -0
- package/dist/messages/check.js.map +1 -0
- package/dist/messages/notice.d.ts +58 -0
- package/dist/messages/notice.js +54 -0
- package/dist/messages/notice.js.map +1 -0
- package/dist/messages/refresh.d.ts +19 -0
- package/dist/messages/refresh.js +42 -0
- package/dist/messages/refresh.js.map +1 -0
- package/dist/scaffold/project-files.js +3 -1
- package/dist/scaffold/project-files.js.map +1 -1
- package/package.json +4 -4
|
@@ -370,6 +370,24 @@ ${ASSET_DETAIL_HTML}
|
|
|
370
370
|
if (frame.contentWindow) frame.contentWindow.postMessage(message, '*');
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
+
/**
|
|
374
|
+
* POST JSON to the sidecar and read its JSON answer.
|
|
375
|
+
*
|
|
376
|
+
* Every endpoint replies { ok, ... }, and an HTTP failure means the same thing to this page as an
|
|
377
|
+
* ok:false body, so the two are folded into one flag rather than re-checked at every call site.
|
|
378
|
+
* Rejects only when the request never landed or the answer was not JSON, which the callers that
|
|
379
|
+
* can say something useful about it catch.
|
|
380
|
+
*/
|
|
381
|
+
async function postJson(path, body) {
|
|
382
|
+
var response = await fetch(path, {
|
|
383
|
+
method: 'POST',
|
|
384
|
+
headers: { 'Content-Type': 'application/json' },
|
|
385
|
+
body: JSON.stringify(body)
|
|
386
|
+
});
|
|
387
|
+
var result = await response.json();
|
|
388
|
+
return { ok: response.ok && result.ok === true, result: result };
|
|
389
|
+
}
|
|
390
|
+
|
|
373
391
|
/**
|
|
374
392
|
* What this host can do, for the editor's feature detection (game/src/editor/EditorHost.ts).
|
|
375
393
|
*
|
|
@@ -391,27 +409,21 @@ ${ASSET_DETAIL_HTML}
|
|
|
391
409
|
});
|
|
392
410
|
}
|
|
393
411
|
|
|
394
|
-
/** Write the URL the engine just uploaded terrain to into src/work/world.json. */
|
|
395
412
|
/**
|
|
396
413
|
* Persist an object voxel sculpt. Mirrors recordTerrainSave: the bytes are already in storage,
|
|
397
414
|
* only the record crosses this boundary.
|
|
398
415
|
*/
|
|
399
416
|
async function recordVoxelSave(message) {
|
|
400
417
|
try {
|
|
401
|
-
var
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
body: JSON.stringify({
|
|
405
|
-
asset: message.asset,
|
|
406
|
-
environmentObjects: message.environmentObjects || []
|
|
407
|
-
})
|
|
418
|
+
var saved = await postJson('/api/editor/voxel-saved', {
|
|
419
|
+
asset: message.asset,
|
|
420
|
+
environmentObjects: message.environmentObjects || []
|
|
408
421
|
});
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
setStatus('error', result.error || 'Voxel edit could not be saved');
|
|
422
|
+
if (!saved.ok) {
|
|
423
|
+
setStatus('error', saved.result.error || 'Voxel edit could not be saved');
|
|
412
424
|
return;
|
|
413
425
|
}
|
|
414
|
-
lastKnownMtime = result.worldMtimeMs || lastKnownMtime;
|
|
426
|
+
lastKnownMtime = saved.result.worldMtimeMs || lastKnownMtime;
|
|
415
427
|
lastLocalEditAt = Date.now();
|
|
416
428
|
setStatus('saved', 'Voxel edit saved to world.json');
|
|
417
429
|
} catch (error) {
|
|
@@ -419,17 +431,13 @@ ${ASSET_DETAIL_HTML}
|
|
|
419
431
|
}
|
|
420
432
|
}
|
|
421
433
|
|
|
434
|
+
/** Write the URL the engine just uploaded terrain to into src/work/world.json. */
|
|
422
435
|
async function recordTerrainSave(voxelUrl) {
|
|
423
436
|
if (!voxelUrl) return;
|
|
424
437
|
try {
|
|
425
|
-
var
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
body: JSON.stringify({ voxelUrl: voxelUrl })
|
|
429
|
-
});
|
|
430
|
-
var result = await response.json();
|
|
431
|
-
if (!response.ok || result.ok !== true) throw new Error(result.error || 'save failed');
|
|
432
|
-
lastKnownMtime = result.worldMtimeMs || lastKnownMtime;
|
|
438
|
+
var saved = await postJson('/api/editor/terrain-saved', { voxelUrl: voxelUrl });
|
|
439
|
+
if (!saved.ok) throw new Error(saved.result.error || 'save failed');
|
|
440
|
+
lastKnownMtime = saved.result.worldMtimeMs || lastKnownMtime;
|
|
433
441
|
setStatus('saved', 'Terrain saved to world.json');
|
|
434
442
|
} catch (error) {
|
|
435
443
|
// The bytes ARE uploaded — only the one-line reference failed to land. Say so precisely, so
|
|
@@ -508,11 +516,8 @@ ${ASSET_DETAIL_HTML}
|
|
|
508
516
|
case 'EDITOR_JOURNAL_EVENT':
|
|
509
517
|
// Terrain and voxel saves, which the journal's world.json diff cannot see — and their
|
|
510
518
|
// failures, which change no file at all.
|
|
511
|
-
void
|
|
512
|
-
|
|
513
|
-
headers: { 'Content-Type': 'application/json' },
|
|
514
|
-
body: JSON.stringify(message)
|
|
515
|
-
}).catch(function () { /* the journal is a convenience; never break the editor for it */ });
|
|
519
|
+
void postJson('/api/editor/journal', message)
|
|
520
|
+
.catch(function () { /* the journal is a convenience; never break the editor for it */ });
|
|
516
521
|
break;
|
|
517
522
|
|
|
518
523
|
case 'VOXEL_ASSET_SAVED':
|
|
@@ -623,13 +628,11 @@ ${ASSET_DETAIL_HTML}
|
|
|
623
628
|
if (!hqAsset) return;
|
|
624
629
|
var prompt = hqPrompt.value.trim();
|
|
625
630
|
if (prompt === '') { hqPrompt.focus(); return; }
|
|
626
|
-
var
|
|
627
|
-
|
|
628
|
-
headers: { 'Content-Type': 'application/json' },
|
|
629
|
-
body: JSON.stringify({ assetId: hqAsset.id, assetName: hqAsset.name, prompt: prompt })
|
|
631
|
+
var saved = await postJson('/api/editor/hq-request', {
|
|
632
|
+
assetId: hqAsset.id, assetName: hqAsset.name, prompt: prompt
|
|
630
633
|
});
|
|
631
|
-
var result =
|
|
632
|
-
if (!
|
|
634
|
+
var result = saved.result;
|
|
635
|
+
if (!saved.ok) {
|
|
633
636
|
setStatus('error', result.error || 'Could not record the request');
|
|
634
637
|
closeHqDialog();
|
|
635
638
|
return;
|
|
@@ -911,13 +914,11 @@ ${ASSET_DETAIL_HTML}
|
|
|
911
914
|
saving = true;
|
|
912
915
|
setStatus('saving', 'Saving…');
|
|
913
916
|
try {
|
|
914
|
-
var
|
|
915
|
-
|
|
916
|
-
headers: { 'Content-Type': 'application/json' },
|
|
917
|
-
body: JSON.stringify({ changes: changes, status: status, markersDirty: markersDirty })
|
|
917
|
+
var saved = await postJson('/api/scene/save', {
|
|
918
|
+
changes: changes, status: status, markersDirty: markersDirty
|
|
918
919
|
});
|
|
919
|
-
var result =
|
|
920
|
-
if (!
|
|
920
|
+
var result = saved.result;
|
|
921
|
+
if (!saved.ok) {
|
|
921
922
|
setStatus('error', result.error || 'Save failed');
|
|
922
923
|
return;
|
|
923
924
|
}
|
|
@@ -934,7 +935,6 @@ ${ASSET_DETAIL_HTML}
|
|
|
934
935
|
}
|
|
935
936
|
}
|
|
936
937
|
|
|
937
|
-
|
|
938
938
|
/**
|
|
939
939
|
* The pre-SSE way of noticing an agent's edit, kept as the fallback for a dropped stream.
|
|
940
940
|
*
|
|
@@ -1022,12 +1022,21 @@ ${ASSET_DETAIL_HTML}
|
|
|
1022
1022
|
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
1023
1023
|
}
|
|
1024
1024
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1025
|
+
/**
|
|
1026
|
+
* A span of time in the panel's vocabulary: seconds under a minute, then minutes and seconds.
|
|
1027
|
+
* One formatter for a step's duration and a job's elapsed time alike, so two rows of the same
|
|
1028
|
+
* forge cannot count in different shapes. '' for anything that is not a real duration.
|
|
1029
|
+
*/
|
|
1030
|
+
function formatDuration(ms) {
|
|
1031
|
+
if (typeof ms !== 'number' || !isFinite(ms) || ms < 0) return '';
|
|
1032
|
+
var seconds = Math.round(ms / 1000);
|
|
1029
1033
|
if (seconds < 60) return seconds + 's';
|
|
1030
|
-
return Math.floor(seconds / 60) + 'm ' + (seconds % 60) + 's';
|
|
1034
|
+
return Math.floor(seconds / 60) + 'm ' + String(seconds % 60).padStart(2, '0') + 's';
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/** How long ago an ISO timestamp was. */
|
|
1038
|
+
function formatElapsed(since) {
|
|
1039
|
+
return formatDuration(Date.now() - Date.parse(since));
|
|
1031
1040
|
}
|
|
1032
1041
|
|
|
1033
1042
|
/** When an asset was made, or 0 for the ones that came with the template. */
|
|
@@ -1054,6 +1063,13 @@ ${ASSET_DETAIL_HTML}
|
|
|
1054
1063
|
return dated.concat(undated);
|
|
1055
1064
|
}
|
|
1056
1065
|
|
|
1066
|
+
/** A membership lookup over a list of asset ids — what '/api/assets' answers with its previews. */
|
|
1067
|
+
function idSet(ids) {
|
|
1068
|
+
var set = {};
|
|
1069
|
+
for (var i = 0; i < ids.length; i++) set[ids[i]] = true;
|
|
1070
|
+
return set;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1057
1073
|
function el(tag, className, text) {
|
|
1058
1074
|
var node = document.createElement(tag);
|
|
1059
1075
|
if (className) node.className = className;
|
|
@@ -1063,14 +1079,6 @@ ${ASSET_DETAIL_HTML}
|
|
|
1063
1079
|
return node;
|
|
1064
1080
|
}
|
|
1065
1081
|
|
|
1066
|
-
/** A step duration, in the same vocabulary as formatElapsed but from milliseconds. */
|
|
1067
|
-
function formatDuration(ms) {
|
|
1068
|
-
if (typeof ms !== 'number' || !isFinite(ms) || ms < 0) return '';
|
|
1069
|
-
var seconds = Math.round(ms / 1000);
|
|
1070
|
-
if (seconds < 60) return seconds + 's';
|
|
1071
|
-
return Math.floor(seconds / 60) + 'm ' + String(seconds % 60).padStart(2, '0') + 's';
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
1082
|
function formatCount(value) {
|
|
1075
1083
|
return typeof value === 'number' && isFinite(value) ? value.toLocaleString() : '';
|
|
1076
1084
|
}
|
|
@@ -1223,6 +1231,28 @@ ${ASSET_DETAIL_HTML}
|
|
|
1223
1231
|
return row;
|
|
1224
1232
|
}
|
|
1225
1233
|
|
|
1234
|
+
var MAX_VXL_PREVIEW_BYTES = 8 * 1024 * 1024;
|
|
1235
|
+
|
|
1236
|
+
/** The mesh route: the asset itself, or the GLB a voxelized one was baked from. */
|
|
1237
|
+
function glbJobFor(asset) {
|
|
1238
|
+
var glb = asset.sourceGlbUrl || asset.url;
|
|
1239
|
+
// Double-escaped because this whole page is a template literal: a single backslash is consumed
|
|
1240
|
+
// by the literal, and the browser would receive the invalid regex /.(glb|gltf)(?|$)/.
|
|
1241
|
+
if (typeof glb !== 'string' || !/\\.(glb|gltf)(\\?|$)/i.test(glb)) return null;
|
|
1242
|
+
return { kind: 'glb', url: glb };
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
/** The voxel route, for assets small enough to be worth shipping through a postMessage. */
|
|
1246
|
+
function vxlJobFor(asset) {
|
|
1247
|
+
var url = asset.url;
|
|
1248
|
+
if (typeof url !== 'string' || !/\\.vxl(\\?|$)/i.test(url)) return null;
|
|
1249
|
+
// The voxel message carries the FILE, so this one costs a fetch and a structured clone of the
|
|
1250
|
+
// whole thing. The templates' files are 0.5-2.5 KB; a multi-megabyte one is a hitch on the
|
|
1251
|
+
// render thread in exchange for a 46px tile, and the glyph is the better trade.
|
|
1252
|
+
if (typeof asset.size === 'number' && asset.size > MAX_VXL_PREVIEW_BYTES) return null;
|
|
1253
|
+
return { kind: 'vxl', url: url };
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1226
1256
|
/**
|
|
1227
1257
|
* How the engine should draw this asset's thumbnail, or null when there is nothing to draw.
|
|
1228
1258
|
*
|
|
@@ -1240,20 +1270,8 @@ ${ASSET_DETAIL_HTML}
|
|
|
1240
1270
|
* An asset with neither — a sound, an animation, a level — keeps its glyph, which is the honest
|
|
1241
1271
|
* answer for something with no appearance.
|
|
1242
1272
|
*/
|
|
1243
|
-
var MAX_VXL_PREVIEW_BYTES = 8 * 1024 * 1024;
|
|
1244
|
-
|
|
1245
1273
|
function previewJobFor(asset) {
|
|
1246
|
-
|
|
1247
|
-
// Double-escaped because this whole page is a template literal: a single backslash is consumed
|
|
1248
|
-
// by the literal, and the browser would receive the invalid regex /.(glb|gltf)(?|$)/.
|
|
1249
|
-
if (typeof glb === 'string' && /\\.(glb|gltf)(\\?|$)/i.test(glb)) return { kind: 'glb', url: glb };
|
|
1250
|
-
var url = asset.url;
|
|
1251
|
-
if (typeof url !== 'string' || !/\\.vxl(\\?|$)/i.test(url)) return null;
|
|
1252
|
-
// The voxel message carries the FILE, so this one costs a fetch and a structured clone of the
|
|
1253
|
-
// whole thing. The templates' files are 0.5-2.5 KB; a multi-megabyte one is a hitch on the
|
|
1254
|
-
// render thread in exchange for a 46px tile, and the glyph is the better trade.
|
|
1255
|
-
if (typeof asset.size === 'number' && asset.size > MAX_VXL_PREVIEW_BYTES) return null;
|
|
1256
|
-
return { kind: 'vxl', url: url };
|
|
1274
|
+
return glbJobFor(asset) || vxlJobFor(asset);
|
|
1257
1275
|
}
|
|
1258
1276
|
|
|
1259
1277
|
function assetRow(asset, isFresh, hasPreview) {
|
|
@@ -1317,30 +1335,26 @@ ${ASSET_DETAIL_HTML}
|
|
|
1317
1335
|
|
|
1318
1336
|
function renderAssets(assets, jobs, previews) {
|
|
1319
1337
|
var sorted = sortAssets(assets);
|
|
1320
|
-
var cached =
|
|
1321
|
-
for (var p = 0; p < previews.length; p++) cached[previews[p]] = true;
|
|
1338
|
+
var cached = idSet(previews);
|
|
1322
1339
|
|
|
1323
1340
|
assetsJobs.textContent = '';
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
var ids = {};
|
|
1327
|
-
|
|
1328
|
-
for
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
signature.push(sorted[i].id + (cached[sorted[i].id] ? '*' : ''));
|
|
1333
|
-
}
|
|
1334
|
-
var joined = signature.join(',');
|
|
1341
|
+
jobs.forEach(function (job) { assetsJobs.appendChild(jobRow(job)); });
|
|
1342
|
+
|
|
1343
|
+
var ids = idSet(sorted.map(function (asset) { return asset.id; }));
|
|
1344
|
+
// The preview state is part of the signature: a thumbnail landing is a change worth redrawing
|
|
1345
|
+
// for, and it is the only one that alters a row without altering the asset set.
|
|
1346
|
+
var signature = sorted.map(function (asset) {
|
|
1347
|
+
return asset.id + (cached[asset.id] ? '*' : '');
|
|
1348
|
+
}).join(',');
|
|
1335
1349
|
|
|
1336
|
-
if (
|
|
1350
|
+
if (signature !== lastAssetSignature) {
|
|
1337
1351
|
assetsList.textContent = '';
|
|
1338
|
-
|
|
1339
|
-
var fresh = seenAssetIds !== null && !seenAssetIds[
|
|
1340
|
-
assetsList.appendChild(assetRow(
|
|
1341
|
-
}
|
|
1352
|
+
sorted.forEach(function (asset) {
|
|
1353
|
+
var fresh = seenAssetIds !== null && !seenAssetIds[asset.id];
|
|
1354
|
+
assetsList.appendChild(assetRow(asset, fresh, cached[asset.id] === true));
|
|
1355
|
+
});
|
|
1342
1356
|
seenAssetIds = ids;
|
|
1343
|
-
lastAssetSignature =
|
|
1357
|
+
lastAssetSignature = signature;
|
|
1344
1358
|
}
|
|
1345
1359
|
|
|
1346
1360
|
lastJobs = jobs;
|
|
@@ -1446,12 +1460,10 @@ ${ASSET_DETAIL_HTML}
|
|
|
1446
1460
|
continue;
|
|
1447
1461
|
}
|
|
1448
1462
|
|
|
1449
|
-
var saved = await (
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
})).json();
|
|
1454
|
-
if (saved.stored === true) stored += 1;
|
|
1463
|
+
var saved = await postJson('/api/assets/preview', {
|
|
1464
|
+
assetId: asset.id, image: response.previewBase64
|
|
1465
|
+
});
|
|
1466
|
+
if (saved.result.stored === true) stored += 1;
|
|
1455
1467
|
}
|
|
1456
1468
|
} catch (error) {
|
|
1457
1469
|
// A thumbnail is a decoration; losing the queue must not take the panel with it.
|
|
@@ -1510,8 +1522,8 @@ ${ASSET_DETAIL_HTML}
|
|
|
1510
1522
|
var assetReturnFocus = null;
|
|
1511
1523
|
var assetLoadTimer = null;
|
|
1512
1524
|
|
|
1513
|
-
var IMAGE_TYPES = { image:
|
|
1514
|
-
var AUDIO_TYPES = { audio:
|
|
1525
|
+
var IMAGE_TYPES = { image: true, skybox: true };
|
|
1526
|
+
var AUDIO_TYPES = { audio: true, sound: true, 'sound-effect': true };
|
|
1515
1527
|
|
|
1516
1528
|
/**
|
|
1517
1529
|
* What the VIEWER should load — which is not always what the thumbnail drew.
|
|
@@ -1521,14 +1533,7 @@ ${ASSET_DETAIL_HTML}
|
|
|
1521
1533
|
* shows the asset: a .vxl is drawn as voxels even when the mesh it was baked from is on record.
|
|
1522
1534
|
*/
|
|
1523
1535
|
function detailJobFor(asset) {
|
|
1524
|
-
|
|
1525
|
-
if (typeof url === 'string' && /\\.vxl(\\?|$)/i.test(url)) {
|
|
1526
|
-
if (typeof asset.size === 'number' && asset.size > MAX_VXL_PREVIEW_BYTES) return null;
|
|
1527
|
-
return { kind: 'vxl', url: url };
|
|
1528
|
-
}
|
|
1529
|
-
var glb = asset.sourceGlbUrl || url;
|
|
1530
|
-
if (typeof glb === 'string' && /\\.(glb|gltf)(\\?|$)/i.test(glb)) return { kind: 'glb', url: glb };
|
|
1531
|
-
return null;
|
|
1536
|
+
return vxlJobFor(asset) || glbJobFor(asset);
|
|
1532
1537
|
}
|
|
1533
1538
|
|
|
1534
1539
|
function fact(term, value) {
|
|
@@ -1563,22 +1568,24 @@ ${ASSET_DETAIL_HTML}
|
|
|
1563
1568
|
fact('Voxels', typeof asset.voxelCount === 'number' ? String(asset.voxelCount) : '');
|
|
1564
1569
|
fact('Id', asset.id || '');
|
|
1565
1570
|
|
|
1566
|
-
assetNote.
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
assetAudio.classList.add('hidden');
|
|
1570
|
-
assetResetButton.classList.add('hidden');
|
|
1571
|
+
[assetNote, assetFrame, assetImage, assetAudio, assetResetButton].forEach(function (node) {
|
|
1572
|
+
node.classList.add('hidden');
|
|
1573
|
+
});
|
|
1571
1574
|
if (assetLoadTimer) clearTimeout(assetLoadTimer);
|
|
1572
1575
|
|
|
1573
1576
|
var type = String(asset.type || '').toLowerCase();
|
|
1574
1577
|
var job = detailJobFor(asset);
|
|
1578
|
+
// The asset's own file, for the types a browser can show without a renderer.
|
|
1579
|
+
var direct = typeof asset.url === 'string' ? asset.url : '';
|
|
1575
1580
|
|
|
1576
|
-
|
|
1581
|
+
// '=== true' rather than a truthy read: a type of 'constructor' would otherwise find
|
|
1582
|
+
// Object.prototype's own property and pass for an image.
|
|
1583
|
+
if (IMAGE_TYPES[type] === true && direct) {
|
|
1577
1584
|
// An image is already the thing. Loading a 3D viewer to show a picture would be theatre.
|
|
1578
|
-
assetImage.src =
|
|
1585
|
+
assetImage.src = direct;
|
|
1579
1586
|
assetImage.classList.remove('hidden');
|
|
1580
|
-
} else if (AUDIO_TYPES[type] ===
|
|
1581
|
-
assetAudio.src =
|
|
1587
|
+
} else if (AUDIO_TYPES[type] === true && direct) {
|
|
1588
|
+
assetAudio.src = direct;
|
|
1582
1589
|
assetAudio.classList.remove('hidden');
|
|
1583
1590
|
} else if (job !== null) {
|
|
1584
1591
|
assetResetButton.classList.remove('hidden');
|
|
@@ -1695,14 +1702,12 @@ ${ASSET_DETAIL_HTML}
|
|
|
1695
1702
|
* into the creator's file.
|
|
1696
1703
|
*/
|
|
1697
1704
|
function withThumbnails(assets, previews) {
|
|
1698
|
-
var cached =
|
|
1699
|
-
for (var i = 0; i < previews.length; i++) cached[previews[i]] = true;
|
|
1705
|
+
var cached = idSet(previews);
|
|
1700
1706
|
return assets.map(function (asset) {
|
|
1701
1707
|
if (asset.screenshotUrl || !cached[asset.id]) return asset;
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
return copy;
|
|
1708
|
+
return Object.assign({}, asset, {
|
|
1709
|
+
screenshotUrl: SHELL_ORIGIN + '/api/assets/preview/' + encodeURIComponent(asset.id) + '.png'
|
|
1710
|
+
});
|
|
1706
1711
|
});
|
|
1707
1712
|
}
|
|
1708
1713
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EACL,qBAAqB,EAAE,kBAAkB,GAC1C,MAAM,qDAAqD,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE7F,oGAAoG;AACpG,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;;;;;;;;;;;;GAYG;AACH,SAAS,sBAAsB;IAC7B,OAAO;QACL,6BAA6B,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,GAAG;QACjE,iCAAiC,qBAAqB,CAAC,QAAQ,EAAE,GAAG;QACpE,8BAA8B,kBAAkB,CAAC,QAAQ,EAAE,GAAG;KAC/D,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjB,CAAC;AAED;;;;;;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;EAChD,kBAAkB;;EAElB,mBAAmB;EACnB,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsHrB,gBAAgB;EAChB,eAAe;;;;;;uBAMM,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8B/C,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;EAyBhB,iBAAiB;;;;mBAIA,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;kBACxB,gBAAgB;yBACT,qBAAqB;2BACnB,gBAAgB;;IAEvC,sBAAsB,EAAE
|
|
1
|
+
{"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAomD3B,CAAC;AACF,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isJsonObject } from '../project/world-json.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/** Match an array item by its `id`, the predicate every write below uses. Mirrors `save.ts`. */
|
|
3
|
+
function byId(id) {
|
|
4
|
+
return (item) => isJsonObject(item) && item.id === id;
|
|
4
5
|
}
|
|
5
6
|
/**
|
|
6
7
|
* Returns null when there is nothing safe to write.
|
|
@@ -14,32 +15,27 @@ export function buildVoxelSaveModifications(payload, world) {
|
|
|
14
15
|
if (!isJsonObject(asset) || typeof asset.id !== 'string' || asset.id === '')
|
|
15
16
|
return null;
|
|
16
17
|
const assetId = asset.id;
|
|
17
|
-
const
|
|
18
|
+
const isThisAsset = byId(assetId);
|
|
19
|
+
const existing = (Array.isArray(world.assets) ? world.assets : []).some(isThisAsset);
|
|
18
20
|
const modifications = [existing
|
|
19
21
|
? {
|
|
20
22
|
type: 'updateRoot',
|
|
21
23
|
path: ['assets'],
|
|
22
|
-
predicate:
|
|
24
|
+
predicate: isThisAsset,
|
|
23
25
|
// Field by field, so anything the agent added since LOAD_GAME survives. See the header.
|
|
24
26
|
value: (item) => ({ ...(isJsonObject(item) ? item : {}), ...asset }),
|
|
25
27
|
}
|
|
26
|
-
: {
|
|
27
|
-
type: 'upsertRoot',
|
|
28
|
-
path: ['assets'],
|
|
29
|
-
predicate: (item) => isJsonObject(item) && item.id === assetId,
|
|
30
|
-
value: asset,
|
|
31
|
-
}];
|
|
28
|
+
: { type: 'upsertRoot', path: ['assets'], predicate: isThisAsset, value: asset }];
|
|
32
29
|
// Instances the save minted. Upserted by id rather than pushed, so a retry of the same save does
|
|
33
30
|
// not leave two copies of one object standing in the same place.
|
|
34
31
|
const instances = Array.isArray(payload.environmentObjects) ? payload.environmentObjects : [];
|
|
35
32
|
for (const instance of instances) {
|
|
36
33
|
if (!isJsonObject(instance) || typeof instance.id !== 'string' || instance.id === '')
|
|
37
34
|
continue;
|
|
38
|
-
const instanceId = instance.id;
|
|
39
35
|
modifications.push({
|
|
40
36
|
type: 'upsertRoot',
|
|
41
37
|
path: ['environmentObjects'],
|
|
42
|
-
predicate: (
|
|
38
|
+
predicate: byId(instance.id),
|
|
43
39
|
value: instance,
|
|
44
40
|
});
|
|
45
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voxel-save.js","sourceRoot":"","sources":["../../src/editor/voxel-save.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,YAAY,EAAmB,MAAM,0BAA0B,CAAC;AAkBzE,SAAS,
|
|
1
|
+
{"version":3,"file":"voxel-save.js","sourceRoot":"","sources":["../../src/editor/voxel-save.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,YAAY,EAAmB,MAAM,0BAA0B,CAAC;AAkBzE,gGAAgG;AAChG,SAAS,IAAI,CAAC,EAAU;IACtB,OAAO,CAAC,IAAa,EAAW,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;AAC1E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAyB,EACzB,KAAiB;IAEjB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACzF,MAAM,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC;IAEzB,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACrF,MAAM,aAAa,GAA4B,CAAC,QAAQ;YACtD,CAAC,CAAC;gBACA,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,CAAC,QAAQ,CAAC;gBAChB,SAAS,EAAE,WAAW;gBACtB,wFAAwF;gBACxF,KAAK,EAAE,CAAC,IAAa,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;aAC9E;YACD,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAEpF,iGAAiG;IACjG,iEAAiE;IACjE,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9F,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,EAAE,KAAK,QAAQ,IAAI,QAAQ,CAAC,EAAE,KAAK,EAAE;YAAE,SAAS;QAC/F,aAAa,CAAC,IAAI,CAAC;YACjB,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,CAAC,oBAAoB,CAAC;YAC5B,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,aAAa;QACb,OAAO;QACP,SAAS,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;QACrF,MAAM,EAAE,QAAQ;KACjB,CAAC;AACJ,CAAC"}
|
package/dist/generate/prop.d.ts
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
import type { Environment } from '../config/environments.js';
|
|
2
|
+
import { withVoxelizeSession } from '../forge/voxelize-session.js';
|
|
2
3
|
import type { ProjectContext } from '../project/context.js';
|
|
4
|
+
/**
|
|
5
|
+
* What the bake was handed: a mesh to voxelize, or a voxel master to compile.
|
|
6
|
+
*
|
|
7
|
+
* A union rather than two optional URLs because exactly one is always true, and the error messages
|
|
8
|
+
* differ in the only part that matters — what was kept and how to retry with it.
|
|
9
|
+
*/
|
|
10
|
+
export type PropSource = {
|
|
11
|
+
kind: 'glb';
|
|
12
|
+
glbUrl: string;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'master';
|
|
15
|
+
masterUrl: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Whether this project's engine can bake a voxel master.
|
|
19
|
+
*
|
|
20
|
+
* A capability probe, not a version comparison. `withVoxelizeSession` runs the project's OWN
|
|
21
|
+
* vendored engine, and `CREATE_ASSET_FROM_VXL_MASTER` only exists in engines from 2026-08-02 —
|
|
22
|
+
* but the failure mode of guessing wrong is what makes this worth checking rather than trying:
|
|
23
|
+
* an engine with no handler for a message does not answer, so the request stalls for the full
|
|
24
|
+
* VOXELIZE_TIMEOUT_MS (10 minutes) and then again on the retry, after which the paid generation
|
|
25
|
+
* is thrown away. Reading a version string is the indirect way to ask; the file is the answer.
|
|
26
|
+
*
|
|
27
|
+
* `engine` resolves to `engine/engine` — see scaffold/aliases.ts.
|
|
28
|
+
*/
|
|
29
|
+
export declare function engineSupportsVxlMaster(projectRoot: string): boolean;
|
|
3
30
|
interface FitBox {
|
|
4
31
|
x: number;
|
|
5
32
|
z: number;
|
|
@@ -11,8 +38,14 @@ export interface PropVoxelizeOptions {
|
|
|
11
38
|
token: string;
|
|
12
39
|
assetId: string;
|
|
13
40
|
prompt: string;
|
|
14
|
-
|
|
41
|
+
source: PropSource;
|
|
15
42
|
log: (message: string) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Injected by tests so the bake runs without Chrome, matching the `voxelize` seam
|
|
45
|
+
* `generateAndInstallModel` already has. Without it none of the routing, capability or fallback
|
|
46
|
+
* logic below can be covered at all — every path ends in a real browser.
|
|
47
|
+
*/
|
|
48
|
+
session?: typeof withVoxelizeSession;
|
|
16
49
|
}
|
|
17
50
|
export interface GenerateAndInstallOptions {
|
|
18
51
|
context: ProjectContext;
|
|
@@ -24,7 +57,24 @@ export interface GenerateAndInstallOptions {
|
|
|
24
57
|
glbUrl?: string;
|
|
25
58
|
fetchImpl?: typeof globalThis.fetch;
|
|
26
59
|
log: (message: string) => void;
|
|
60
|
+
/** See PropVoxelizeOptions.session. */
|
|
61
|
+
session?: typeof withVoxelizeSession;
|
|
27
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* What the asset was made from, reported so callers do not have to guess.
|
|
65
|
+
*
|
|
66
|
+
* Two fields rather than one, because both end up in machine-readable output — the `--json`
|
|
67
|
+
* document and the editor's journal — and a voxel master reported under `glbUrl` would tell an
|
|
68
|
+
* agent there is a mesh to retry with when there is not, on the one path whose whole point is
|
|
69
|
+
* that no mesh exists.
|
|
70
|
+
*/
|
|
71
|
+
export type PropSourceResult = {
|
|
72
|
+
glbUrl: string;
|
|
73
|
+
masterUrl?: undefined;
|
|
74
|
+
} | {
|
|
75
|
+
masterUrl: string;
|
|
76
|
+
glbUrl?: undefined;
|
|
77
|
+
};
|
|
28
78
|
export interface PropVoxelizeResult {
|
|
29
79
|
assetId: string;
|
|
30
80
|
assetName: string;
|
|
@@ -58,9 +108,7 @@ export declare function shouldFillInterior(fitBox: FitBox): boolean;
|
|
|
58
108
|
* Everything the caller must resolve first (project, environment, token) is a parameter, so this
|
|
59
109
|
* stays free of CLI output plumbing and of how the token was obtained.
|
|
60
110
|
*/
|
|
61
|
-
export declare function generateAndInstallProp(options: GenerateAndInstallOptions): Promise<PropVoxelizeResult &
|
|
62
|
-
glbUrl: string;
|
|
63
|
-
}>;
|
|
111
|
+
export declare function generateAndInstallProp(options: GenerateAndInstallOptions): Promise<PropVoxelizeResult & PropSourceResult>;
|
|
64
112
|
/**
|
|
65
113
|
* Steps 2 and 3. Split from the command so the browser work is callable directly on a retry that
|
|
66
114
|
* already has a GLB, and so the command file stays about flags and output.
|