@bitmagic/cli 0.1.64-dev.1 → 0.1.64-dev.2
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.
|
@@ -16,12 +16,17 @@
|
|
|
16
16
|
* The surface, the pills and the modal backdrop come from `design.ts` (`.bm-overlay`,
|
|
17
17
|
* `.bm-dialog`, `.bm-pill`); only what is specific to this dialog's layout lives here.
|
|
18
18
|
*/
|
|
19
|
-
export declare const ASSET_DETAIL_CSS = "\n /* Above #hq-overlay, which sits at 10 \u2014 a preview opened from a row must cover it. */\n #asset-overlay { z-index: 11; }\n #asset-dialog { display: flex; width: min(1100px, 94vw); height: min(760px, 88vh);\n overflow: hidden; }\n /* The viewer takes the room. Everything else is a caption. The near-black ground is the\n brand's: a creation is the only thing on this surface that carries colour. */\n #asset-view { flex: 1; min-width: 0; position: relative; background: var(--bm-bg); }\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: var(--bm-bg); }\n #asset-view audio { position: absolute; left: 50%; top: 50%; width: min(420px, 80%);\n transform: translate(-50%, -50%); }\n /* A note here is always a failure or a wait that has gone on too long \u2014 the negative accent. */\n #asset-note { position: absolute; inset: auto 0 0 0; padding: 10px 12px;\n background: var(--bm-scrim); color: var(--bm-pink-hover); font-size: 12px; }\n #asset-note.hidden, #asset-view > .hidden { display: none; }\n /* Wide enough for the action pills to sit on one row (wrapping to two once Edit voxels shows):\n uppercase tracked labels are wider than the sentence-case ones this panel used to have. */\n #asset-meta { width: 360px; flex: none; padding: 16px; overflow-y: auto;\n border-left: 1px solid var(--bm-border-muted); }\n #asset-meta h2 { margin: 0 0 4px; word-break: break-word; }\n #asset-meta .sub { color: var(--bm-text-dim); font-size: 12px; margin-bottom: 16px; }\n #asset-facts { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; font-size: 12px; }\n #asset-facts dt { color: var(--bm-text-dim); }\n #asset-facts dd { margin: 0; color: var(--bm-text); word-break: break-word; }\n #asset-facts dd.mono { font-family: var(--bm-font-mono); }\n #asset-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }\n /* The .hidden rules above are scoped to the viewer side; the actions row needs its own. */\n #asset-actions .hidden { display: none; }\n #asset-close { margin-left: auto; }\n";
|
|
19
|
+
export declare const ASSET_DETAIL_CSS = "\n /* Above #hq-overlay, which sits at 10 \u2014 a preview opened from a row must cover it. */\n #asset-overlay { z-index: 11; }\n #asset-dialog { display: flex; width: min(1100px, 94vw); height: min(760px, 88vh);\n overflow: hidden; }\n /* The viewer takes the room. Everything else is a caption. The near-black ground is the\n brand's: a creation is the only thing on this surface that carries colour. */\n #asset-view { flex: 1; min-width: 0; position: relative; background: var(--bm-bg); }\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: var(--bm-bg); }\n #asset-view audio { position: absolute; left: 50%; top: 50%; width: min(420px, 80%);\n transform: translate(-50%, -50%); }\n /* Fitted rather than filled, like the image rule above: a generated clip is 16:9 by default but\n follows its first frame when one was given, so the dialog cannot assume a shape. */\n #asset-view video { display: block; width: 100%; height: 100%; object-fit: contain;\n background: var(--bm-bg); }\n /* A note here is always a failure or a wait that has gone on too long \u2014 the negative accent. */\n #asset-note { position: absolute; inset: auto 0 0 0; padding: 10px 12px;\n background: var(--bm-scrim); color: var(--bm-pink-hover); font-size: 12px; }\n #asset-note.hidden, #asset-view > .hidden { display: none; }\n /* Wide enough for the action pills to sit on one row (wrapping to two once Edit voxels shows):\n uppercase tracked labels are wider than the sentence-case ones this panel used to have. */\n #asset-meta { width: 360px; flex: none; padding: 16px; overflow-y: auto;\n border-left: 1px solid var(--bm-border-muted); }\n #asset-meta h2 { margin: 0 0 4px; word-break: break-word; }\n #asset-meta .sub { color: var(--bm-text-dim); font-size: 12px; margin-bottom: 16px; }\n #asset-facts { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; font-size: 12px; }\n #asset-facts dt { color: var(--bm-text-dim); }\n #asset-facts dd { margin: 0; color: var(--bm-text); word-break: break-word; }\n #asset-facts dd.mono { font-family: var(--bm-font-mono); }\n #asset-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }\n /* The .hidden rules above are scoped to the viewer side; the actions row needs its own. */\n #asset-actions .hidden { display: none; }\n #asset-close { margin-left: auto; }\n";
|
|
20
20
|
/**
|
|
21
21
|
* The overlay itself.
|
|
22
22
|
*
|
|
23
23
|
* `<audio controls>` rather than a play button of our own: the web Creator withholds native
|
|
24
24
|
* controls because its player sits in a 46px row, and here there is a whole dialog. A creator
|
|
25
|
-
* checking a sound effect wants the scrubber.
|
|
25
|
+
* checking a sound effect wants the scrubber. `<video controls>` is here for the same reason —
|
|
26
|
+
* a cutscene is watched, scrubbed and watched again.
|
|
27
|
+
*
|
|
28
|
+
* `preload="metadata"` on the video, not `none`: the dialog is opened BY a click on the row, so
|
|
29
|
+
* the creator has already asked for it, and a poster frame beats a black rectangle. Muted is
|
|
30
|
+
* deliberately absent — a generated clip may carry audio and this is where you would check.
|
|
26
31
|
*/
|
|
27
|
-
export declare const ASSET_DETAIL_HTML = "\n <div id=\"asset-overlay\" class=\"bm-overlay\">\n <div id=\"asset-dialog\" class=\"bm-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-edit-voxels\" class=\"bm-pill bm-pill--primary hidden\" type=\"button\" title=\"Open the 3D voxel editor: add, delete and recolor voxels, and set which ones glow\">Edit voxels</button>\n <button id=\"asset-reset\" class=\"bm-pill\" type=\"button\" title=\"Back to the angle the thumbnail uses\">Reset view</button>\n <button id=\"asset-copy\" class=\"bm-pill\" type=\"button\" title=\"Copy this asset's id\">Copy id</button>\n <button id=\"asset-close\" class=\"bm-pill bm-pill--ghost\" type=\"button\">Close</button>\n </div>\n </aside>\n </div>\n </div>\n";
|
|
32
|
+
export declare const ASSET_DETAIL_HTML = "\n <div id=\"asset-overlay\" class=\"bm-overlay\">\n <div id=\"asset-dialog\" class=\"bm-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 <video id=\"asset-video\" class=\"hidden\" controls playsinline preload=\"metadata\"></video>\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-edit-voxels\" class=\"bm-pill bm-pill--primary hidden\" type=\"button\" title=\"Open the 3D voxel editor: add, delete and recolor voxels, and set which ones glow\">Edit voxels</button>\n <button id=\"asset-reset\" class=\"bm-pill\" type=\"button\" title=\"Back to the angle the thumbnail uses\">Reset view</button>\n <button id=\"asset-copy\" class=\"bm-pill\" type=\"button\" title=\"Copy this asset's id\">Copy id</button>\n <button id=\"asset-close\" class=\"bm-pill bm-pill--ghost\" type=\"button\">Close</button>\n </div>\n </aside>\n </div>\n </div>\n";
|
|
@@ -29,6 +29,10 @@ export const ASSET_DETAIL_CSS = `
|
|
|
29
29
|
background: var(--bm-bg); }
|
|
30
30
|
#asset-view audio { position: absolute; left: 50%; top: 50%; width: min(420px, 80%);
|
|
31
31
|
transform: translate(-50%, -50%); }
|
|
32
|
+
/* Fitted rather than filled, like the image rule above: a generated clip is 16:9 by default but
|
|
33
|
+
follows its first frame when one was given, so the dialog cannot assume a shape. */
|
|
34
|
+
#asset-view video { display: block; width: 100%; height: 100%; object-fit: contain;
|
|
35
|
+
background: var(--bm-bg); }
|
|
32
36
|
/* A note here is always a failure or a wait that has gone on too long — the negative accent. */
|
|
33
37
|
#asset-note { position: absolute; inset: auto 0 0 0; padding: 10px 12px;
|
|
34
38
|
background: var(--bm-scrim); color: var(--bm-pink-hover); font-size: 12px; }
|
|
@@ -53,7 +57,12 @@ export const ASSET_DETAIL_CSS = `
|
|
|
53
57
|
*
|
|
54
58
|
* `<audio controls>` rather than a play button of our own: the web Creator withholds native
|
|
55
59
|
* controls because its player sits in a 46px row, and here there is a whole dialog. A creator
|
|
56
|
-
* checking a sound effect wants the scrubber.
|
|
60
|
+
* checking a sound effect wants the scrubber. `<video controls>` is here for the same reason —
|
|
61
|
+
* a cutscene is watched, scrubbed and watched again.
|
|
62
|
+
*
|
|
63
|
+
* `preload="metadata"` on the video, not `none`: the dialog is opened BY a click on the row, so
|
|
64
|
+
* the creator has already asked for it, and a poster frame beats a black rectangle. Muted is
|
|
65
|
+
* deliberately absent — a generated clip may carry audio and this is where you would check.
|
|
57
66
|
*/
|
|
58
67
|
export const ASSET_DETAIL_HTML = `
|
|
59
68
|
<div id="asset-overlay" class="bm-overlay">
|
|
@@ -62,6 +71,7 @@ export const ASSET_DETAIL_HTML = `
|
|
|
62
71
|
<iframe id="asset-frame" class="hidden" title="Asset preview"></iframe>
|
|
63
72
|
<img id="asset-image" class="hidden" alt="">
|
|
64
73
|
<audio id="asset-audio" class="hidden" controls preload="none"></audio>
|
|
74
|
+
<video id="asset-video" class="hidden" controls playsinline preload="metadata"></video>
|
|
65
75
|
<div id="asset-note" class="hidden"></div>
|
|
66
76
|
</div>
|
|
67
77
|
<aside id="asset-meta">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-detail-panel.js","sourceRoot":"","sources":["../../src/editor/asset-detail-panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG
|
|
1
|
+
{"version":3,"file":"asset-detail-panel.js","sourceRoot":"","sources":["../../src/editor/asset-detail-panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmC/B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBhC,CAAC"}
|
|
@@ -1374,6 +1374,7 @@ ${ASSET_DETAIL_HTML}
|
|
|
1374
1374
|
image: '🖼', skybox: '🖼',
|
|
1375
1375
|
glb: '🧊', gltf: '🧊', 'polygon-mesh': '🧊', vxl: '🧊', voxels: '🧊',
|
|
1376
1376
|
animation: '🏃', 'animation-video': '🎥', audio: '🔊', sound: '🔊', 'sound-effect': '🔊', music: '🎵',
|
|
1377
|
+
video: '🎬',
|
|
1377
1378
|
vwld: '🗺', spz: '✨'
|
|
1378
1379
|
};
|
|
1379
1380
|
|
|
@@ -1614,6 +1615,21 @@ ${ASSET_DETAIL_HTML}
|
|
|
1614
1615
|
|
|
1615
1616
|
var MAX_VXL_PREVIEW_BYTES = 8 * 1024 * 1024;
|
|
1616
1617
|
|
|
1618
|
+
/**
|
|
1619
|
+
* Which of a clip's two renditions to play.
|
|
1620
|
+
*
|
|
1621
|
+
* The forger stores every clip twice, and the VP9 sibling is the one worth fetching where the
|
|
1622
|
+
* browser takes it: same picture, ~6x smaller (757 KB against 4.5 MB on a measured 5 s 720p
|
|
1623
|
+
* clip), and bitmagic dev drives Chrome, which decodes VP9 natively. canPlayType only
|
|
1624
|
+
* promises the codec, never the file, so every caller keeps the mp4 as the fallback.
|
|
1625
|
+
*/
|
|
1626
|
+
function videoSourceFor(asset) {
|
|
1627
|
+
var mp4 = typeof asset.url === 'string' ? asset.url : '';
|
|
1628
|
+
var webm = typeof asset.webmUrl === 'string' ? asset.webmUrl : '';
|
|
1629
|
+
if (webm === '') return mp4;
|
|
1630
|
+
return document.createElement('video').canPlayType('video/webm; codecs="vp9"') ? webm : mp4;
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1617
1633
|
/** The mesh route: the asset itself, or the GLB a voxelized one was baked from. */
|
|
1618
1634
|
function glbJobFor(asset) {
|
|
1619
1635
|
var glb = asset.sourceGlbUrl || asset.url;
|
|
@@ -1634,6 +1650,18 @@ ${ASSET_DETAIL_HTML}
|
|
|
1634
1650
|
return { kind: 'vxl', url: url };
|
|
1635
1651
|
}
|
|
1636
1652
|
|
|
1653
|
+
/**
|
|
1654
|
+
* The clip route. Unlike its two neighbours this one is NOT drawn by the engine — see
|
|
1655
|
+
* grabVideoPoster. It is listed as a job anyway so a video row goes through the same queue,
|
|
1656
|
+
* the same disk cache and the same hasPreview path every other tile already uses.
|
|
1657
|
+
*/
|
|
1658
|
+
function videoJobFor(asset) {
|
|
1659
|
+
if (String(asset.type || '').toLowerCase() !== 'video') return null;
|
|
1660
|
+
var url = videoSourceFor(asset);
|
|
1661
|
+
if (typeof url !== 'string' || !/\\.(mp4|webm)(\\?|$)/i.test(url)) return null;
|
|
1662
|
+
return { kind: 'video', url: url };
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1637
1665
|
/**
|
|
1638
1666
|
* How the engine should draw this asset's thumbnail, or null when there is nothing to draw.
|
|
1639
1667
|
*
|
|
@@ -1652,7 +1680,7 @@ ${ASSET_DETAIL_HTML}
|
|
|
1652
1680
|
* answer for something with no appearance.
|
|
1653
1681
|
*/
|
|
1654
1682
|
function previewJobFor(asset) {
|
|
1655
|
-
return glbJobFor(asset) || vxlJobFor(asset);
|
|
1683
|
+
return glbJobFor(asset) || vxlJobFor(asset) || videoJobFor(asset);
|
|
1656
1684
|
}
|
|
1657
1685
|
|
|
1658
1686
|
function assetRow(asset, isFresh, hasPreview) {
|
|
@@ -1812,6 +1840,61 @@ ${ASSET_DETAIL_HTML}
|
|
|
1812
1840
|
return await_('VOXEL_PREVIEW_RESPONSE', 15000);
|
|
1813
1841
|
}
|
|
1814
1842
|
|
|
1843
|
+
/** A poster is a thumbnail, not a frame grab for keeps: 256px on the long edge. */
|
|
1844
|
+
var POSTER_MAX_EDGE = 256;
|
|
1845
|
+
|
|
1846
|
+
/**
|
|
1847
|
+
* A clip's poster, drawn HERE rather than by the engine — a video is not a mesh, and this page
|
|
1848
|
+
* can already decode one. Answers in the same shape the two engine renderers do, so the queue
|
|
1849
|
+
* below does not care which drew it.
|
|
1850
|
+
*
|
|
1851
|
+
* The canvas does not taint: the asset host serves 'access-control-allow-origin: *' (checked
|
|
1852
|
+
* against a stored clip), which is what 'crossOrigin' here asks it to honour. Without that
|
|
1853
|
+
* attribute the draw would succeed and toDataURL would throw.
|
|
1854
|
+
*
|
|
1855
|
+
* Seeks a tenth of the way in rather than taking frame zero — a generated clip often opens on a
|
|
1856
|
+
* fade from black, and a black tile is the thing this whole preview cache exists to avoid.
|
|
1857
|
+
*/
|
|
1858
|
+
function grabVideoPoster(url, requestId) {
|
|
1859
|
+
return new Promise(function (resolve) {
|
|
1860
|
+
var probe = document.createElement('video');
|
|
1861
|
+
var settled = false;
|
|
1862
|
+
var timer = null;
|
|
1863
|
+
function finish(previewBase64) {
|
|
1864
|
+
if (settled) return;
|
|
1865
|
+
settled = true;
|
|
1866
|
+
if (timer) clearTimeout(timer);
|
|
1867
|
+
probe.removeAttribute('src');
|
|
1868
|
+
resolve({ requestId: requestId, success: previewBase64 !== '', previewBase64: previewBase64 });
|
|
1869
|
+
}
|
|
1870
|
+
timer = setTimeout(function () { finish(''); }, 15000);
|
|
1871
|
+
probe.crossOrigin = 'anonymous';
|
|
1872
|
+
probe.muted = true;
|
|
1873
|
+
probe.preload = 'auto';
|
|
1874
|
+
probe.addEventListener('error', function () { finish(''); });
|
|
1875
|
+
probe.addEventListener('loadeddata', function () {
|
|
1876
|
+
probe.currentTime = Math.min(1, (probe.duration || 1) * 0.1);
|
|
1877
|
+
});
|
|
1878
|
+
probe.addEventListener('seeked', function () {
|
|
1879
|
+
try {
|
|
1880
|
+
var width = probe.videoWidth;
|
|
1881
|
+
var height = probe.videoHeight;
|
|
1882
|
+
if (!width || !height) { finish(''); return; }
|
|
1883
|
+
var scale = Math.min(1, POSTER_MAX_EDGE / Math.max(width, height));
|
|
1884
|
+
var canvas = document.createElement('canvas');
|
|
1885
|
+
canvas.width = Math.max(1, Math.round(width * scale));
|
|
1886
|
+
canvas.height = Math.max(1, Math.round(height * scale));
|
|
1887
|
+
canvas.getContext('2d').drawImage(probe, 0, 0, canvas.width, canvas.height);
|
|
1888
|
+
finish(canvas.toDataURL('image/png'));
|
|
1889
|
+
} catch (error) {
|
|
1890
|
+
// A tainted canvas or a codec the browser will not decode. Neither is worth a retry.
|
|
1891
|
+
finish('');
|
|
1892
|
+
}
|
|
1893
|
+
});
|
|
1894
|
+
probe.src = url;
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1815
1898
|
async function drainPreviewQueue() {
|
|
1816
1899
|
if (previewRunning) return;
|
|
1817
1900
|
previewRunning = true;
|
|
@@ -1819,17 +1902,21 @@ ${ASSET_DETAIL_HTML}
|
|
|
1819
1902
|
try {
|
|
1820
1903
|
while (previewQueue.length > 0) {
|
|
1821
1904
|
// The engine can only draw once it exists. Anything queued before then waits for the next
|
|
1822
|
-
// pass rather than being dropped — refreshAssets re-queues on every render.
|
|
1823
|
-
|
|
1905
|
+
// pass rather than being dropped — refreshAssets re-queues on every render. A clip's
|
|
1906
|
+
// poster is drawn in this page, so it is the one kind that does not wait.
|
|
1907
|
+
var next = previewJobFor(previewQueue[0]);
|
|
1908
|
+
if (!loaded && next !== null && next.kind !== 'video') return;
|
|
1824
1909
|
var asset = previewQueue.shift();
|
|
1825
|
-
var job =
|
|
1910
|
+
var job = next;
|
|
1826
1911
|
if (job === null) continue;
|
|
1827
1912
|
|
|
1828
1913
|
previewRequestId += 1;
|
|
1829
1914
|
var requestId = 'preview-' + previewRequestId;
|
|
1830
|
-
var response = job.kind === '
|
|
1831
|
-
? await
|
|
1832
|
-
:
|
|
1915
|
+
var response = job.kind === 'video'
|
|
1916
|
+
? await grabVideoPoster(job.url, requestId)
|
|
1917
|
+
: job.kind === 'vxl'
|
|
1918
|
+
? await requestVoxelPreview(job.url, requestId)
|
|
1919
|
+
: await requestGlbPreview(job.url, requestId);
|
|
1833
1920
|
|
|
1834
1921
|
// The requestId is verified rather than assumed: a late answer from a request that already
|
|
1835
1922
|
// timed out would otherwise be cached under the NEXT asset's id, which is a wrong picture
|
|
@@ -1896,6 +1983,7 @@ ${ASSET_DETAIL_HTML}
|
|
|
1896
1983
|
var assetFrame = document.getElementById('asset-frame');
|
|
1897
1984
|
var assetImage = document.getElementById('asset-image');
|
|
1898
1985
|
var assetAudio = document.getElementById('asset-audio');
|
|
1986
|
+
var assetVideo = document.getElementById('asset-video');
|
|
1899
1987
|
var assetNote = document.getElementById('asset-note');
|
|
1900
1988
|
var assetFacts = document.getElementById('asset-facts');
|
|
1901
1989
|
var assetResetButton = document.getElementById('asset-reset');
|
|
@@ -1907,6 +1995,9 @@ ${ASSET_DETAIL_HTML}
|
|
|
1907
1995
|
|
|
1908
1996
|
var IMAGE_TYPES = { image: true, skybox: true };
|
|
1909
1997
|
var AUDIO_TYPES = { audio: true, sound: true, 'sound-effect': true };
|
|
1998
|
+
// Only one member today, but the same shape as its neighbours — and the same '=== true'
|
|
1999
|
+
// read, so a type of 'constructor' cannot find Object.prototype's own property and pass.
|
|
2000
|
+
var VIDEO_TYPES = { video: true };
|
|
1910
2001
|
|
|
1911
2002
|
/**
|
|
1912
2003
|
* What the VIEWER should load — which is not always what the thumbnail drew.
|
|
@@ -1952,6 +2043,10 @@ ${ASSET_DETAIL_HTML}
|
|
|
1952
2043
|
|
|
1953
2044
|
assetFacts.textContent = '';
|
|
1954
2045
|
fact('Size', formatSize(asset.size));
|
|
2046
|
+
fact('Length', typeof asset.durationSeconds === 'number' && asset.durationSeconds > 0
|
|
2047
|
+
? asset.durationSeconds.toFixed(1) + 's' : '');
|
|
2048
|
+
fact('Frame', typeof asset.width === 'number' && typeof asset.height === 'number'
|
|
2049
|
+
? asset.width + ' × ' + asset.height : '');
|
|
1955
2050
|
fact('Extent', dimensionsOf(asset));
|
|
1956
2051
|
fact('Voxels', typeof asset.voxelCount === 'number' ? String(asset.voxelCount) : '');
|
|
1957
2052
|
fact('Id', asset.id || '');
|
|
@@ -1975,6 +2070,16 @@ ${ASSET_DETAIL_HTML}
|
|
|
1975
2070
|
} else if (AUDIO_TYPES[type] === true && direct) {
|
|
1976
2071
|
assetAudio.src = direct;
|
|
1977
2072
|
assetAudio.classList.remove('hidden');
|
|
2073
|
+
} else if (VIDEO_TYPES[type] === true && direct) {
|
|
2074
|
+
// A clip is already the thing, like an image — no renderer, no iframe. The mp4 is wired to
|
|
2075
|
+
// the error event rather than left to chance: canPlayType answers for the codec, and a
|
|
2076
|
+
// WebM that fails for any other reason would otherwise be a black rectangle with no sound.
|
|
2077
|
+
assetVideo.onerror = function () {
|
|
2078
|
+
if (assetVideo.getAttribute('src') === direct) return;
|
|
2079
|
+
assetVideo.src = direct;
|
|
2080
|
+
};
|
|
2081
|
+
assetVideo.src = videoSourceFor(asset);
|
|
2082
|
+
assetVideo.classList.remove('hidden');
|
|
1978
2083
|
} else if (type === 'animation' && direct) {
|
|
1979
2084
|
// The clip plays on the engine's own block character — /animation-preview imports the
|
|
1980
2085
|
// project's debug/AnimationPreview.js, the module behind the Creator's clip preview.
|
|
@@ -2041,6 +2146,11 @@ ${ASSET_DETAIL_HTML}
|
|
|
2041
2146
|
assetImage.removeAttribute('src');
|
|
2042
2147
|
assetAudio.pause();
|
|
2043
2148
|
assetAudio.removeAttribute('src');
|
|
2149
|
+
// Same reason the iframe goes to about:blank: a dialog nobody is looking at must not keep
|
|
2150
|
+
// decoding video next to the game that wants the GPU.
|
|
2151
|
+
assetVideo.pause();
|
|
2152
|
+
assetVideo.onerror = null;
|
|
2153
|
+
assetVideo.removeAttribute('src');
|
|
2044
2154
|
if (assetPausedByOverlay) {
|
|
2045
2155
|
post('SET_PAUSE', { paused: false });
|
|
2046
2156
|
assetPausedByOverlay = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"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;;;;;;0BAQF,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA42BvC,oBAAoB
|
|
1
|
+
{"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"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;;;;;;0BAQF,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA42BvC,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+0C1C,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmChB,CAAC;AACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitmagic/cli",
|
|
3
|
-
"version": "0.1.64-dev.
|
|
3
|
+
"version": "0.1.64-dev.2",
|
|
4
4
|
"description": "Build Bitmagic games from your own agent tool",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "Bitmagic Oy",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"playwright-core": "^1.59.1",
|
|
26
26
|
"tar": "^7.4.3",
|
|
27
27
|
"ws": "^8.21.3",
|
|
28
|
-
"@bitmagic/
|
|
29
|
-
"@bitmagic/
|
|
30
|
-
"@bitmagic/
|
|
28
|
+
"@bitmagic/world-forger": "0.1.24-dev.2",
|
|
29
|
+
"@bitmagic/animation-forger": "0.1.19-dev.2",
|
|
30
|
+
"@bitmagic/asset-core": "0.2.19-dev.2"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@eslint/js": "^9.38.0",
|