@bitmagic/cli 0.1.59-dev.8 → 0.1.59
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 +93 -21
- package/dist/cli.d.ts +3 -3
- package/dist/commands/dev.d.ts +2 -2
- package/dist/commands/dev.js +38 -19
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/forge.d.ts +5 -4
- package/dist/commands/forge.js +46 -8
- package/dist/commands/forge.js.map +1 -1
- package/dist/commands/generate.d.ts +1 -0
- package/dist/commands/generate.js +13 -2
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.js +2 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/reload.d.ts +1 -1
- package/dist/commands/reload.js +6 -3
- package/dist/commands/reload.js.map +1 -1
- package/dist/commands/verify.js +17 -6
- package/dist/commands/verify.js.map +1 -1
- package/dist/editor/animation-preview-page.js +96 -1
- package/dist/editor/animation-preview-page.js.map +1 -1
- package/dist/editor/design.js +70 -0
- package/dist/editor/design.js.map +1 -1
- package/dist/editor/motion-panel.d.ts +1 -1
- package/dist/editor/motion-panel.js +7 -1
- package/dist/editor/motion-panel.js.map +1 -1
- package/dist/editor/motion-sink.d.ts +15 -1
- package/dist/editor/motion-sink.js +14 -1
- package/dist/editor/motion-sink.js.map +1 -1
- package/dist/editor/server.d.ts +1 -1
- package/dist/editor/server.js +31 -3
- package/dist/editor/server.js.map +1 -1
- package/dist/editor/shell-page.js +100 -7
- package/dist/editor/shell-page.js.map +1 -1
- package/dist/forge/voxelize-session.js +5 -4
- package/dist/forge/voxelize-session.js.map +1 -1
- package/dist/generate/animation-from-video.d.ts +4 -0
- package/dist/generate/animation-from-video.js +3 -0
- package/dist/generate/animation-from-video.js.map +1 -1
- package/dist/local-port.d.ts +36 -11
- package/dist/local-port.js +43 -14
- package/dist/local-port.js.map +1 -1
- package/dist/mobile/dev-cert.js +2 -1
- package/dist/mobile/dev-cert.js.map +1 -1
- package/dist/port-lane.d.ts +59 -0
- package/dist/port-lane.js +66 -0
- package/dist/port-lane.js.map +1 -0
- package/dist/project/dev-handle.d.ts +6 -1
- package/dist/project/dev-handle.js +11 -3
- package/dist/project/dev-handle.js.map +1 -1
- package/dist/scaffold/project-files.js +35 -3
- package/dist/scaffold/project-files.js.map +1 -1
- package/package.json +4 -4
|
@@ -146,6 +146,13 @@ ${BITMAGIC_CONTROLS_CSS}
|
|
|
146
146
|
#auto { display: flex; align-items: center; gap: 6px; font-size: 12px;
|
|
147
147
|
color: var(--bm-text-muted); cursor: pointer; }
|
|
148
148
|
#auto input { margin: 0; accent-color: var(--bm-aqua); }
|
|
149
|
+
/* The Published pill used to un-dim itself when a publish landed, which is how a creator learnt
|
|
150
|
+
it had finished. Behind a menu that signal would be invisible, so the trigger carries it:
|
|
151
|
+
Aquamarine, the same "something landed" this page already uses for a fresh asset row. */
|
|
152
|
+
#more { position: relative; }
|
|
153
|
+
#more.news::after { content: ''; position: absolute; top: -1px; right: -1px;
|
|
154
|
+
width: 6px; height: 6px; border-radius: 50%;
|
|
155
|
+
background: var(--bm-aqua); border: 1px solid var(--bm-surface); }
|
|
149
156
|
.banner { display: none; align-items: center; gap: 12px; flex: none; padding: 10px 16px;
|
|
150
157
|
background: var(--bm-tint-warning); border-bottom: 1px solid var(--bm-pumpkin);
|
|
151
158
|
color: var(--bm-text); }
|
|
@@ -251,11 +258,18 @@ ${BOOT_LOADER_CSS}
|
|
|
251
258
|
<input id="auto-toggle" type="checkbox" checked> Auto-reload
|
|
252
259
|
</label>
|
|
253
260
|
<span id="status"><span id="dot"></span><span id="status-text">Loading…</span></span>
|
|
254
|
-
<
|
|
255
|
-
<button id="assets-toggle" class="bm-pill" type="button" title="Show the assets in this project and what is being made">Assets</button>
|
|
256
|
-
<
|
|
257
|
-
<button id="
|
|
258
|
-
|
|
261
|
+
<span class="bm-separator-v"></span>
|
|
262
|
+
<button id="assets-toggle" class="bm-pill" type="button" aria-pressed="true" title="Show the assets in this project and what is being made">Assets</button>
|
|
263
|
+
<span class="bm-separator-v"></span>
|
|
264
|
+
<button id="shot" class="bm-pill" type="button" title="Copy the current frame to the clipboard (S)">Screenshot</button>
|
|
265
|
+
<button id="reload" class="bm-pill" type="button" title="Reload the game (R)">Reload</button>
|
|
266
|
+
<div class="bm-menu-wrap">
|
|
267
|
+
<button id="more" class="bm-icon-btn" type="button" aria-haspopup="true" aria-expanded="false" aria-label="More actions" title="More actions">⋯</button>
|
|
268
|
+
<div id="more-menu" class="bm-menu">
|
|
269
|
+
<button id="publish-toggle" class="bm-menu-item" type="button" disabled>Published…</button>
|
|
270
|
+
${recording ? ' <button id="record" class="bm-menu-item" type="button">Record gameplay…</button>\n' : ''} <button id="motion" class="bm-menu-item" type="button">Record motion…</button>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
259
273
|
</div>
|
|
260
274
|
<div id="build-banner" class="banner">
|
|
261
275
|
<span id="build-message"></span>
|
|
@@ -318,6 +332,8 @@ ${ASSET_DETAIL_HTML}
|
|
|
318
332
|
var TAB_KEY = 'bitmagic.dev.tab';
|
|
319
333
|
var AUTO_KEY = 'bitmagic.dev.autoReload';
|
|
320
334
|
var ASSETS_KEY = 'bitmagic.dev.assets';
|
|
335
|
+
// The publish the creator has already been shown, so the trigger's dot means NEW, not "exists".
|
|
336
|
+
var SEEN_PUBLISH_KEY = 'bitmagic.dev.seenPublish';
|
|
321
337
|
// Dev line only — see recordingAvailable() in recording-sink.ts. On a release build the pill and
|
|
322
338
|
// the panel are not in the document at all, so this also guards the lookups below finding null.
|
|
323
339
|
var RECORDING_ENABLED = ${recording ? 'true' : 'false'};
|
|
@@ -330,6 +346,8 @@ ${ASSET_DETAIL_HTML}
|
|
|
330
346
|
var statusText = document.getElementById('status-text');
|
|
331
347
|
var banner = document.getElementById('banner');
|
|
332
348
|
var publishToggle = document.getElementById('publish-toggle');
|
|
349
|
+
var moreButton = document.getElementById('more');
|
|
350
|
+
var moreMenu = document.getElementById('more-menu');
|
|
333
351
|
var publishOverlay = document.getElementById('publish-overlay');
|
|
334
352
|
var publishUrl = document.getElementById('publish-url');
|
|
335
353
|
var publishVisibility = document.getElementById('publish-visibility');
|
|
@@ -1121,6 +1139,9 @@ ${ASSET_DETAIL_HTML}
|
|
|
1121
1139
|
publishToggle.title = lastPublish
|
|
1122
1140
|
? 'Where this game is published'
|
|
1123
1141
|
: 'Publish the game to get a link and a QR code';
|
|
1142
|
+
// The pill used to carry this by un-dimming in the bar. Inside a menu nobody would see it, so
|
|
1143
|
+
// the trigger wears a dot until the creator has opened the menu on this particular publish.
|
|
1144
|
+
moreButton.classList.toggle('news', !!lastPublish && readPref(SEEN_PUBLISH_KEY, '') !== lastPublish.at);
|
|
1124
1145
|
if (!lastPublish && publishOverlay.classList.contains('show')) closePublish();
|
|
1125
1146
|
}
|
|
1126
1147
|
|
|
@@ -1148,7 +1169,9 @@ ${ASSET_DETAIL_HTML}
|
|
|
1148
1169
|
publishOverlay.classList.remove('show');
|
|
1149
1170
|
// Drop the image so a session that publishes repeatedly does not keep every code it drew.
|
|
1150
1171
|
publishQr.removeAttribute('src');
|
|
1151
|
-
publishToggle
|
|
1172
|
+
// Not publishToggle: it lives inside the menu, which is closed by now, and focusing a hidden
|
|
1173
|
+
// element drops focus to the body. The trigger is the thing that is still on screen.
|
|
1174
|
+
moreButton.focus();
|
|
1152
1175
|
}
|
|
1153
1176
|
|
|
1154
1177
|
/**
|
|
@@ -1895,7 +1918,14 @@ ${ASSET_DETAIL_HTML}
|
|
|
1895
1918
|
// An engine too old to ship it posts ASSET_PREVIEW_FAILED and the note explains.
|
|
1896
1919
|
assetFrame.classList.remove('hidden');
|
|
1897
1920
|
assetFrame.src = '/animation-preview?url=' + encodeURIComponent(direct)
|
|
1898
|
-
+ '&name=' + encodeURIComponent(asset.name || asset.id || 'animation')
|
|
1921
|
+
+ '&name=' + encodeURIComponent(asset.name || asset.id || 'animation')
|
|
1922
|
+
// Video-to-motion clips remember their source footage; the page shows it
|
|
1923
|
+
// with the auto-trimmed ends marked.
|
|
1924
|
+
+ (asset.sourceVideoUrl
|
|
1925
|
+
? '&video=' + encodeURIComponent(asset.sourceVideoUrl)
|
|
1926
|
+
+ '&trimStart=' + encodeURIComponent(asset.trimmedStartSeconds || 0)
|
|
1927
|
+
+ '&trimEnd=' + encodeURIComponent(asset.trimmedEndSeconds || 0)
|
|
1928
|
+
: '');
|
|
1899
1929
|
assetLoadTimer = setTimeout(function () {
|
|
1900
1930
|
showAssetNote('Still loading. If this does not clear, check the dev server output.');
|
|
1901
1931
|
}, 12000);
|
|
@@ -2039,11 +2069,35 @@ ${ASSET_DETAIL_HTML}
|
|
|
2039
2069
|
// The page had no keyboard handling at all before this, so #hq-overlay gains Escape with it.
|
|
2040
2070
|
document.addEventListener('keydown', function (event) {
|
|
2041
2071
|
if (event.key !== 'Escape') return;
|
|
2072
|
+
// Innermost first. The motion and publish dialogs were missing from this chain entirely —
|
|
2073
|
+
// they only closed on their own button or the backdrop.
|
|
2074
|
+
if (closeMore()) return;
|
|
2042
2075
|
if (closeAssetDetail()) return;
|
|
2043
2076
|
if (closeRecordingPanel()) return;
|
|
2077
|
+
if (closeMotionPanel()) return;
|
|
2078
|
+
if (publishOverlay.classList.contains('show')) { closePublish(); return; }
|
|
2044
2079
|
hqOverlay.classList.remove('show');
|
|
2045
2080
|
});
|
|
2046
2081
|
|
|
2082
|
+
/**
|
|
2083
|
+
* Reload and Screenshot are the two things pressed all session, so they get a key each.
|
|
2084
|
+
*
|
|
2085
|
+
* Bare letters, because every modifier combination worth having is the browser's (Cmd+R, Cmd+S).
|
|
2086
|
+
* That means guarding the cases where a letter is text rather than a command: a field, or a
|
|
2087
|
+
* dialog that is up. Note the game iframe is a different origin, so once the creator clicks into
|
|
2088
|
+
* the game these stop firing until they click the chrome again — nothing here can see those keys,
|
|
2089
|
+
* which is exactly why the recorder's own F9 is bound inside the engine instead.
|
|
2090
|
+
*/
|
|
2091
|
+
document.addEventListener('keydown', function (event) {
|
|
2092
|
+
if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
|
|
2093
|
+
var target = event.target;
|
|
2094
|
+
if (target && (target.isContentEditable || /^(?:INPUT|TEXTAREA|SELECT)$/.test(target.tagName))) return;
|
|
2095
|
+
if (document.querySelector('.bm-overlay.show')) return;
|
|
2096
|
+
var key = event.key.toLowerCase();
|
|
2097
|
+
if (key === 'r') { event.preventDefault(); reloadUnlessSculpting(); }
|
|
2098
|
+
else if (key === 's') { event.preventDefault(); takeScreenshot(); }
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2047
2101
|
/**
|
|
2048
2102
|
* Lend the cached thumbnails to the engine's own asset palette.
|
|
2049
2103
|
*
|
|
@@ -2091,10 +2145,36 @@ ${ASSET_DETAIL_HTML}
|
|
|
2091
2145
|
function setAssetsOpen(open) {
|
|
2092
2146
|
assetsOpen = open;
|
|
2093
2147
|
document.body.classList.toggle('assets-closed', !open);
|
|
2148
|
+
// A toggle that looks identical in both states is a button that lies about what it did.
|
|
2149
|
+
assetsToggle.classList.toggle('bm-pill--pressed', open);
|
|
2150
|
+
assetsToggle.setAttribute('aria-pressed', open ? 'true' : 'false');
|
|
2094
2151
|
writePref(ASSETS_KEY, open ? '1' : '0');
|
|
2095
2152
|
if (open) void refreshAssets();
|
|
2096
2153
|
}
|
|
2097
2154
|
|
|
2155
|
+
/**
|
|
2156
|
+
* The overflow menu.
|
|
2157
|
+
*
|
|
2158
|
+
* The bar had grown a pill per feature, and two of them were called Record. What is left in the
|
|
2159
|
+
* bar is what a creator touches in a normal session; what opens a dialog and is reached once a
|
|
2160
|
+
* week lives here, so the next feature adds a row rather than a seventh pill.
|
|
2161
|
+
*/
|
|
2162
|
+
function openMore() {
|
|
2163
|
+
moreMenu.classList.add('show');
|
|
2164
|
+
moreButton.setAttribute('aria-expanded', 'true');
|
|
2165
|
+
// Opening the menu IS seeing the publish, so the dot has done its job.
|
|
2166
|
+
if (lastPublish) writePref(SEEN_PUBLISH_KEY, lastPublish.at);
|
|
2167
|
+
moreButton.classList.remove('news');
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
/** Returns whether it was open — the Escape chain's contract, like closeRecordingPanel. */
|
|
2171
|
+
function closeMore() {
|
|
2172
|
+
if (!moreMenu.classList.contains('show')) return false;
|
|
2173
|
+
moreMenu.classList.remove('show');
|
|
2174
|
+
moreButton.setAttribute('aria-expanded', 'false');
|
|
2175
|
+
return true;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2098
2178
|
/**
|
|
2099
2179
|
* Screenshot → clipboard.
|
|
2100
2180
|
*
|
|
@@ -2300,6 +2380,19 @@ ${ASSET_DETAIL_HTML}
|
|
|
2300
2380
|
if (autoReload) banner.classList.remove('show');
|
|
2301
2381
|
});
|
|
2302
2382
|
|
|
2383
|
+
moreButton.addEventListener('click', function () {
|
|
2384
|
+
if (!closeMore()) openMore();
|
|
2385
|
+
});
|
|
2386
|
+
// One delegate for every row, present and future: a click that lands on a row's button closes
|
|
2387
|
+
// the menu, and the row's own handler opens whatever it opens.
|
|
2388
|
+
moreMenu.addEventListener('click', function (event) {
|
|
2389
|
+
if (event.target.tagName === 'BUTTON' && !event.target.disabled) closeMore();
|
|
2390
|
+
});
|
|
2391
|
+
// Anywhere outside the trigger and the menu dismisses it, the way a dropdown is expected to.
|
|
2392
|
+
document.addEventListener('click', function (event) {
|
|
2393
|
+
if (!event.target.closest || !event.target.closest('.bm-menu-wrap')) closeMore();
|
|
2394
|
+
});
|
|
2395
|
+
|
|
2303
2396
|
publishToggle.addEventListener('click', openPublish);
|
|
2304
2397
|
publishClose.addEventListener('click', closePublish);
|
|
2305
2398
|
// Click the backdrop to dismiss, like every other dialog on this page.
|
|
@@ -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,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzF,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;AAiBD,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,MAAM,OAAO,GAAG,oBAAoB,OAAO,CAAC,QAAQ,2BAA2B,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IACpH,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACpC,OAAO;;;;wBAIe,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;EAChD,kBAAkB;;EAElB,mBAAmB;EACnB,qBAAqB
|
|
1
|
+
{"version":3,"file":"shell-page.js","sourceRoot":"","sources":["../../src/editor/shell-page.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+gEtD,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqChB,CAAC;AACF,CAAC"}
|
|
@@ -30,7 +30,8 @@ import { spawn, spawnSync } from 'child_process';
|
|
|
30
30
|
import { CliError } from '../errors.js';
|
|
31
31
|
import { ForgeBrowserHost, readProjectGameData } from './browser-host.js';
|
|
32
32
|
import { startUploadProxy } from './upload-proxy.js';
|
|
33
|
-
import {
|
|
33
|
+
import { reservePortInLane, laneExhaustedMessage } from '../local-port.js';
|
|
34
|
+
import { currentPortLane } from '../port-lane.js';
|
|
34
35
|
import { projectBin } from '../project/context.js';
|
|
35
36
|
import { waitForServer } from '../verify/wait-for-server.js';
|
|
36
37
|
/** Voxelizing a dense mesh is minutes of work in the browser, not seconds. */
|
|
@@ -58,10 +59,10 @@ export function buildProject(context, log, consequence, retryHint) {
|
|
|
58
59
|
export async function withVoxelizeSession(options, body) {
|
|
59
60
|
const { context, environment, token, log, subject, retryHint } = options;
|
|
60
61
|
buildProject(context, log, `${subject} cannot be voxelized`, retryHint);
|
|
61
|
-
const
|
|
62
|
+
const lane = currentPortLane();
|
|
63
|
+
const port = await reservePortInLane(lane);
|
|
62
64
|
if (port === null) {
|
|
63
|
-
throw new CliError(
|
|
64
|
-
+ `Stop something in that range and retry.\n${retryHint}`);
|
|
65
|
+
throw new CliError(laneExhaustedMessage(lane, `Stop something in that range and retry.\n${retryHint}`));
|
|
65
66
|
}
|
|
66
67
|
const vite = projectBin(context.root, 'vite');
|
|
67
68
|
let server;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voxelize-session.js","sourceRoot":"","sources":["../../src/forge/voxelize-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAqB,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAoB,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"voxelize-session.js","sourceRoot":"","sources":["../../src/forge/voxelize-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,8 @@ export interface AnimationFromVideoRun {
|
|
|
12
12
|
model?: VideoToMotionModel;
|
|
13
13
|
loop?: boolean;
|
|
14
14
|
locomotionState?: LocomotionState;
|
|
15
|
+
/** Cut walk-to-the-camera frames off both ends (pose analysis in the Forger). */
|
|
16
|
+
autoTrim?: boolean;
|
|
15
17
|
assetId?: string;
|
|
16
18
|
}
|
|
17
19
|
export interface AnimationFromVideoDeps extends ApiDeps {
|
|
@@ -22,6 +24,8 @@ export interface AnimationFromVideoInstallResult {
|
|
|
22
24
|
motionId: string;
|
|
23
25
|
animationUrl: string;
|
|
24
26
|
durationSeconds: number;
|
|
27
|
+
trimmedStartSeconds?: number;
|
|
28
|
+
trimmedEndSeconds?: number;
|
|
25
29
|
locomotionState?: LocomotionState;
|
|
26
30
|
sparksCharged: number;
|
|
27
31
|
patchesApplied: number;
|
|
@@ -104,6 +104,7 @@ export async function generateAndInstallAnimationFromVideo(options) {
|
|
|
104
104
|
...(run.model !== undefined ? { model: run.model } : {}),
|
|
105
105
|
...(run.loop !== undefined ? { loop: run.loop } : {}),
|
|
106
106
|
...(run.locomotionState !== undefined ? { locomotionState: run.locomotionState } : {}),
|
|
107
|
+
...(run.autoTrim !== undefined ? { autoTrim: run.autoTrim } : {}),
|
|
107
108
|
...(run.assetId !== undefined ? { assetId: run.assetId } : {}),
|
|
108
109
|
};
|
|
109
110
|
deps.log('Submitting the video to Uthana video-to-motion…');
|
|
@@ -141,6 +142,8 @@ export async function generateAndInstallAnimationFromVideo(options) {
|
|
|
141
142
|
motionId,
|
|
142
143
|
animationUrl: result.animationUrl,
|
|
143
144
|
durationSeconds: result.durationSeconds,
|
|
145
|
+
...(result.trimmedStartSeconds !== undefined ? { trimmedStartSeconds: result.trimmedStartSeconds } : {}),
|
|
146
|
+
...(result.trimmedEndSeconds !== undefined ? { trimmedEndSeconds: result.trimmedEndSeconds } : {}),
|
|
144
147
|
...(run.locomotionState !== undefined ? { locomotionState: run.locomotionState } : {}),
|
|
145
148
|
sparksCharged,
|
|
146
149
|
patchesApplied: applied.applied,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animation-from-video.js","sourceRoot":"","sources":["../../src/generate/animation-from-video.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EACL,4BAA4B,EAC5B,iBAAiB,EACjB,sBAAsB,GAKvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD,sGAAsG;AACtG,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjD,MAAM,CAAC,MAAM,SAAS,GAAG,8CAA8C,CAAC;AAExE,0FAA0F;AAC1F,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,yFAAyF;AACzF,MAAM,gBAAgB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"animation-from-video.js","sourceRoot":"","sources":["../../src/generate/animation-from-video.ts"],"names":[],"mappings":"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"}
|
package/dist/local-port.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PortLane } from './port-lane.js';
|
|
1
2
|
/**
|
|
2
3
|
* The port window the platform's bucket CORS policy allowlists as an origin.
|
|
3
4
|
*
|
|
@@ -5,8 +6,14 @@
|
|
|
5
6
|
* project served on localhost is making CROSS-ORIGIN requests for them. The bucket answers with
|
|
6
7
|
* `Access-Control-Allow-Origin` only for the origins named in its CORS config — the portal and
|
|
7
8
|
* creator hosts, plus `http://localhost:3000`–`3199` (roleverse-infra,
|
|
8
|
-
* the portal-cdn terragrunt config per environment). `bitmagic dev`
|
|
9
|
-
*
|
|
9
|
+
* the portal-cdn terragrunt config per environment). Everything `bitmagic dev`, `verify`, `forge`
|
|
10
|
+
* and `generate` bind sits inside it; anything that asks the OS for an ephemeral port
|
|
11
|
+
* (`listen(0)` → 49xxx+) falls outside it.
|
|
12
|
+
*
|
|
13
|
+
* Nothing here picks a number, though. The window is split in half so a dev-line and a release-line
|
|
14
|
+
* install cannot take each other's ports (port-lane.ts), and every function below scans the LANE it
|
|
15
|
+
* is handed, never the whole window. The bounds here remain the outer limit: they are what an
|
|
16
|
+
* explicit `--port` is checked against, because a creator naming a port is entitled to either half.
|
|
10
17
|
*
|
|
11
18
|
* The failure is quiet and easy to misread. The fetch is blocked, `WorldGenerator` falls back to
|
|
12
19
|
* an empty voxel world, the level's terrain simply is not there, and the symptom is a player
|
|
@@ -24,20 +31,38 @@ export declare const CORS_ALLOWED_PORT_MAX = 3199;
|
|
|
24
31
|
* other, and being told the rule once, at the point of the mistake, beats discovering it as a
|
|
25
32
|
* terrain-less world. (The shell itself fetches nothing from the CDN, so its own check is purely
|
|
26
33
|
* that kindness.)
|
|
34
|
+
*
|
|
35
|
+
* Checked against the whole window, deliberately not against this install's lane. The lane governs
|
|
36
|
+
* where a DEFAULT drifts to, which is a question about avoiding the other install; naming a port
|
|
37
|
+
* outright is a statement that you know what is on the machine, and refusing it because the other
|
|
38
|
+
* line nominally owns that half would make the flag a suggestion for no benefit.
|
|
27
39
|
*/
|
|
28
40
|
export declare function parseLocalPort(value: string | undefined, fallback: number, flag: string): number;
|
|
29
41
|
/**
|
|
30
|
-
* A free port
|
|
42
|
+
* A free port in this install's lane, or `null` when every port in the lane is taken.
|
|
31
43
|
*
|
|
32
44
|
* Returning `null` rather than silently falling back to an ephemeral port is deliberate: the
|
|
33
45
|
* caller can then say what the consequence is, instead of the run proceeding to a level with no
|
|
34
46
|
* terrain and no explanation.
|
|
35
47
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
48
|
+
* It never spills into the other lane either, for the same class of reason. A lane is a promise
|
|
49
|
+
* that the other install's ports are still there when it starts; taking them because they happen to
|
|
50
|
+
* be free right now would break that promise at exactly the moment two installs are busiest, and
|
|
51
|
+
* quietly. A hundred held ports is a machine with a problem to report, not a lane to abandon.
|
|
52
|
+
*
|
|
53
|
+
* The scan starts at a pseudo-random offset so two concurrent runs do not both take the lane's
|
|
54
|
+
* first port and race; `tryListen` closing before the caller binds leaves a window either way,
|
|
55
|
+
* which is why callers must handle a bind failure rather than trusting this.
|
|
56
|
+
*/
|
|
57
|
+
export declare function reservePortInLane(lane: PortLane, exclude?: ReadonlySet<number>): Promise<number | null>;
|
|
58
|
+
/**
|
|
59
|
+
* What to say when a lane is full — the one message that has to explain why the numbers it names
|
|
60
|
+
* are narrower than the 3000-3199 everything else talks about.
|
|
61
|
+
*
|
|
62
|
+
* Without the second sentence this reads as a bug to anyone who knows the CDN allows two hundred
|
|
63
|
+
* ports and has just been told a hundred of them are the limit.
|
|
39
64
|
*/
|
|
40
|
-
export declare function
|
|
65
|
+
export declare function laneExhaustedMessage(lane: PortLane, remedy: string): string;
|
|
41
66
|
/** Whether this exact port is free right now. Same TOCTOU caveat as above. */
|
|
42
67
|
export declare function isPortFree(port: number): Promise<boolean>;
|
|
43
68
|
/**
|
|
@@ -45,12 +70,12 @@ export declare function isPortFree(port: number): Promise<boolean>;
|
|
|
45
70
|
*
|
|
46
71
|
* Only ever called for a port the creator did NOT ask for by name. An explicit `--port` is a
|
|
47
72
|
* request, and quietly serving somewhere else would make the flag a suggestion — those still fail
|
|
48
|
-
* loudly. The default is different: nobody chose
|
|
49
|
-
* `bitmagic dev` dying because some unrelated process holds it is a bad trade now that
|
|
50
|
-
* it as a background task whose output nobody reads.
|
|
73
|
+
* loudly. The default is different: nobody chose the lane's `gamePort`, it is just where we start
|
|
74
|
+
* looking, and `bitmagic dev` dying because some unrelated process holds it is a bad trade now that
|
|
75
|
+
* agents run it as a background task whose output nobody reads.
|
|
51
76
|
*
|
|
52
77
|
* Drifting is only safe because of two things that did not exist when these ports were fixed:
|
|
53
78
|
* `.bitmagic/dev.json` records what was actually bound (so `bitmagic reload` still finds it), and
|
|
54
79
|
* `dev` opens the browser itself (so nobody has to know the number).
|
|
55
80
|
*/
|
|
56
|
-
export declare function resolveDevPort(preferred: number, exclude?: ReadonlySet<number>): Promise<number | null>;
|
|
81
|
+
export declare function resolveDevPort(preferred: number, lane: PortLane, exclude?: ReadonlySet<number>): Promise<number | null>;
|
package/dist/local-port.js
CHANGED
|
@@ -7,8 +7,14 @@ import { CliError } from './errors.js';
|
|
|
7
7
|
* project served on localhost is making CROSS-ORIGIN requests for them. The bucket answers with
|
|
8
8
|
* `Access-Control-Allow-Origin` only for the origins named in its CORS config — the portal and
|
|
9
9
|
* creator hosts, plus `http://localhost:3000`–`3199` (roleverse-infra,
|
|
10
|
-
* the portal-cdn terragrunt config per environment). `bitmagic dev`
|
|
11
|
-
*
|
|
10
|
+
* the portal-cdn terragrunt config per environment). Everything `bitmagic dev`, `verify`, `forge`
|
|
11
|
+
* and `generate` bind sits inside it; anything that asks the OS for an ephemeral port
|
|
12
|
+
* (`listen(0)` → 49xxx+) falls outside it.
|
|
13
|
+
*
|
|
14
|
+
* Nothing here picks a number, though. The window is split in half so a dev-line and a release-line
|
|
15
|
+
* install cannot take each other's ports (port-lane.ts), and every function below scans the LANE it
|
|
16
|
+
* is handed, never the whole window. The bounds here remain the outer limit: they are what an
|
|
17
|
+
* explicit `--port` is checked against, because a creator naming a port is entitled to either half.
|
|
12
18
|
*
|
|
13
19
|
* The failure is quiet and easy to misread. The fetch is blocked, `WorldGenerator` falls back to
|
|
14
20
|
* an empty voxel world, the level's terrain simply is not there, and the symptom is a player
|
|
@@ -26,6 +32,11 @@ export const CORS_ALLOWED_PORT_MAX = 3199;
|
|
|
26
32
|
* other, and being told the rule once, at the point of the mistake, beats discovering it as a
|
|
27
33
|
* terrain-less world. (The shell itself fetches nothing from the CDN, so its own check is purely
|
|
28
34
|
* that kindness.)
|
|
35
|
+
*
|
|
36
|
+
* Checked against the whole window, deliberately not against this install's lane. The lane governs
|
|
37
|
+
* where a DEFAULT drifts to, which is a question about avoiding the other install; naming a port
|
|
38
|
+
* outright is a statement that you know what is on the machine, and refusing it because the other
|
|
39
|
+
* line nominally owns that half would make the flag a suggestion for no benefit.
|
|
29
40
|
*/
|
|
30
41
|
export function parseLocalPort(value, fallback, flag) {
|
|
31
42
|
if (value === undefined)
|
|
@@ -52,21 +63,26 @@ function tryListen(port) {
|
|
|
52
63
|
});
|
|
53
64
|
}
|
|
54
65
|
/**
|
|
55
|
-
* A free port
|
|
66
|
+
* A free port in this install's lane, or `null` when every port in the lane is taken.
|
|
56
67
|
*
|
|
57
68
|
* Returning `null` rather than silently falling back to an ephemeral port is deliberate: the
|
|
58
69
|
* caller can then say what the consequence is, instead of the run proceeding to a level with no
|
|
59
70
|
* terrain and no explanation.
|
|
60
71
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
72
|
+
* It never spills into the other lane either, for the same class of reason. A lane is a promise
|
|
73
|
+
* that the other install's ports are still there when it starts; taking them because they happen to
|
|
74
|
+
* be free right now would break that promise at exactly the moment two installs are busiest, and
|
|
75
|
+
* quietly. A hundred held ports is a machine with a problem to report, not a lane to abandon.
|
|
76
|
+
*
|
|
77
|
+
* The scan starts at a pseudo-random offset so two concurrent runs do not both take the lane's
|
|
78
|
+
* first port and race; `tryListen` closing before the caller binds leaves a window either way,
|
|
79
|
+
* which is why callers must handle a bind failure rather than trusting this.
|
|
64
80
|
*/
|
|
65
|
-
export async function
|
|
66
|
-
const span =
|
|
81
|
+
export async function reservePortInLane(lane, exclude = new Set()) {
|
|
82
|
+
const span = lane.max - lane.min + 1;
|
|
67
83
|
const start = Math.floor(Math.random() * span);
|
|
68
84
|
for (let i = 0; i < span; i += 1) {
|
|
69
|
-
const port =
|
|
85
|
+
const port = lane.min + ((start + i) % span);
|
|
70
86
|
if (exclude.has(port))
|
|
71
87
|
continue;
|
|
72
88
|
const bound = await tryListen(port);
|
|
@@ -75,6 +91,19 @@ export async function reserveCorsAllowedPort(exclude = new Set()) {
|
|
|
75
91
|
}
|
|
76
92
|
return null;
|
|
77
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* What to say when a lane is full — the one message that has to explain why the numbers it names
|
|
96
|
+
* are narrower than the 3000-3199 everything else talks about.
|
|
97
|
+
*
|
|
98
|
+
* Without the second sentence this reads as a bug to anyone who knows the CDN allows two hundred
|
|
99
|
+
* ports and has just been told a hundred of them are the limit.
|
|
100
|
+
*/
|
|
101
|
+
export function laneExhaustedMessage(lane, remedy) {
|
|
102
|
+
return (`Every port from ${lane.min} to ${lane.max} is in use. That is this CLI's half of the `
|
|
103
|
+
+ `${CORS_ALLOWED_PORT_MIN}-${CORS_ALLOWED_PORT_MAX} window the asset CDN allows as an origin — `
|
|
104
|
+
+ 'the other half is left free so a bitmagic from the other release line can run beside this '
|
|
105
|
+
+ `one. ${remedy}`);
|
|
106
|
+
}
|
|
78
107
|
/** Whether this exact port is free right now. Same TOCTOU caveat as above. */
|
|
79
108
|
export async function isPortFree(port) {
|
|
80
109
|
return (await tryListen(port)) !== null;
|
|
@@ -84,17 +113,17 @@ export async function isPortFree(port) {
|
|
|
84
113
|
*
|
|
85
114
|
* Only ever called for a port the creator did NOT ask for by name. An explicit `--port` is a
|
|
86
115
|
* request, and quietly serving somewhere else would make the flag a suggestion — those still fail
|
|
87
|
-
* loudly. The default is different: nobody chose
|
|
88
|
-
* `bitmagic dev` dying because some unrelated process holds it is a bad trade now that
|
|
89
|
-
* it as a background task whose output nobody reads.
|
|
116
|
+
* loudly. The default is different: nobody chose the lane's `gamePort`, it is just where we start
|
|
117
|
+
* looking, and `bitmagic dev` dying because some unrelated process holds it is a bad trade now that
|
|
118
|
+
* agents run it as a background task whose output nobody reads.
|
|
90
119
|
*
|
|
91
120
|
* Drifting is only safe because of two things that did not exist when these ports were fixed:
|
|
92
121
|
* `.bitmagic/dev.json` records what was actually bound (so `bitmagic reload` still finds it), and
|
|
93
122
|
* `dev` opens the browser itself (so nobody has to know the number).
|
|
94
123
|
*/
|
|
95
|
-
export async function resolveDevPort(preferred, exclude = new Set()) {
|
|
124
|
+
export async function resolveDevPort(preferred, lane, exclude = new Set()) {
|
|
96
125
|
if (!exclude.has(preferred) && await isPortFree(preferred))
|
|
97
126
|
return preferred;
|
|
98
|
-
return
|
|
127
|
+
return reservePortInLane(lane, exclude);
|
|
99
128
|
}
|
|
100
129
|
//# sourceMappingURL=local-port.js.map
|
package/dist/local-port.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-port.js","sourceRoot":"","sources":["../src/local-port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"local-port.js","sourceRoot":"","sources":["../src/local-port.ts"],"names":[],"mappings":"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"}
|
package/dist/mobile/dev-cert.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The self-signed certificate the mobile bridge serves the phone over.
|
|
3
3
|
*
|
|
4
|
-
* TLS is not decoration here. A page on `http://192.168.x.y
|
|
4
|
+
* TLS is not decoration here. A page on `http://192.168.x.y:<bridge port>` is NOT a secure context,
|
|
5
|
+
* and
|
|
5
6
|
* `navigator.gpu` is only exposed to secure contexts — so over plain http the engine's renderer
|
|
6
7
|
* pick downgrades to classic WebGL (`RendererPreference.ts`, `withoutUnavailableWebGpu`) and the
|
|
7
8
|
* one thing a real device is uniquely able to tell us about, Safari's WebGPU pipeline, is exactly
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-cert.js","sourceRoot":"","sources":["../../src/mobile/dev-cert.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dev-cert.js","sourceRoot":"","sources":["../../src/mobile/dev-cert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which half of the CDN's port window a CLI install may bind — the one thing that keeps a dev-line
|
|
3
|
+
* and a release-line `bitmagic` out of each other's way on the same machine.
|
|
4
|
+
*
|
|
5
|
+
* Both lines are published as `@bitmagic/cli` and are routinely installed side by side (see the
|
|
6
|
+
* README's `~/.bitmagic-cli/dev` / `~/.bitmagic-cli/prod` recipe). Until this existed they reached
|
|
7
|
+
* for the same numbers: `dev` started at 3010/3011/3012 and `verify`, `forge` and `generate` scanned
|
|
8
|
+
* the whole window from a random offset. Nothing crashed — a busy default drifts — but whichever
|
|
9
|
+
* install started second landed somewhere unpredictable, and `bitmagic reload` falling back to a
|
|
10
|
+
* bare 3011 could reload the OTHER install's browser tab, on a different project entirely.
|
|
11
|
+
*
|
|
12
|
+
* The split has to happen INSIDE 3000-3199 and cannot be the repo's usual `+100` offset. That
|
|
13
|
+
* window is the whole of what the asset CDN allowlists as an origin (see local-port.ts); a lane
|
|
14
|
+
* starting at 3210 would serve games whose terrain silently never loads.
|
|
15
|
+
*/
|
|
16
|
+
import { type UpdateTag } from './update/notice.js';
|
|
17
|
+
export interface PortLane {
|
|
18
|
+
/** Inclusive scan bounds. Always wholly inside CORS_ALLOWED_PORT_MIN/MAX. */
|
|
19
|
+
min: number;
|
|
20
|
+
max: number;
|
|
21
|
+
/** Where `bitmagic dev` starts looking for the vite server that serves the game. */
|
|
22
|
+
gamePort: number;
|
|
23
|
+
/** Where it starts looking for the tabbed Game/Editor shell — the URL a creator opens. */
|
|
24
|
+
editorPort: number;
|
|
25
|
+
/** Where `--mobile` starts looking for the LAN bridge. */
|
|
26
|
+
mobilePort: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The release line keeps the numbers it has always had.
|
|
30
|
+
*
|
|
31
|
+
* 3010 and 3011 are named in the README, in the docs every scaffolded project carries, and in the
|
|
32
|
+
* bookmark of anyone who has run this before. The release line is the one that must not move; the
|
|
33
|
+
* dev line is the one whose users opted into change.
|
|
34
|
+
*/
|
|
35
|
+
export declare const RELEASE_LANE: PortLane;
|
|
36
|
+
/**
|
|
37
|
+
* The dev line, one hundred up — the same last two digits, so a number still reads as "game",
|
|
38
|
+
* "shell" or "phone" at a glance and only the hundreds digit says which install printed it.
|
|
39
|
+
*
|
|
40
|
+
* The defaults sit at 3110+ rather than at the foot of the lane on purpose. A machine running this
|
|
41
|
+
* monorepo holds 3000-3002 in an unshifted checkout and 3100-3102 in a `+100` parallel clone
|
|
42
|
+
* (.env.local), which are exactly the two lanes' opening ports. The scan skips a busy port either
|
|
43
|
+
* way, but a default that never collides in the first place prints a stable number.
|
|
44
|
+
*/
|
|
45
|
+
export declare const DEV_LANE: PortLane;
|
|
46
|
+
/** The lane belonging to a published line. */
|
|
47
|
+
export declare function portLaneFor(tag: UpdateTag): PortLane;
|
|
48
|
+
/**
|
|
49
|
+
* This install's lane.
|
|
50
|
+
*
|
|
51
|
+
* Derived from the version string alone — `updateTagFor` reads a prerelease suffix as the dev line —
|
|
52
|
+
* so two installs separate with no config, no env var and nothing for anyone to set up. Note this
|
|
53
|
+
* is the install's own line, NOT the project's `BITMAGIC_ENV`: which api-server a project talks to
|
|
54
|
+
* is a different axis, and a port is a fact about the binary that bound it.
|
|
55
|
+
*
|
|
56
|
+
* An unreadable version reads as a release and gets the release lane, which is where every port was
|
|
57
|
+
* before this existed. Failing closed here keeps the numbers the docs promise.
|
|
58
|
+
*/
|
|
59
|
+
export declare function currentPortLane(version?: string): PortLane;
|