@bloopjs/web 0.0.102 → 0.0.104
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/dist/debugui/components/BottomBar.d.ts.map +1 -1
- package/dist/debugui/components/LoadTapeDialog.d.ts.map +1 -1
- package/dist/debugui/components/TopBar.d.ts.map +1 -1
- package/dist/debugui/components/VerticalBar.d.ts +2 -1
- package/dist/debugui/components/VerticalBar.d.ts.map +1 -1
- package/dist/debugui/state.d.ts +4 -1
- package/dist/debugui/state.d.ts.map +1 -1
- package/dist/debugui/styles.d.ts +1 -1
- package/dist/debugui/styles.d.ts.map +1 -1
- package/dist/mod.js +245 -51
- package/dist/mod.js.map +11 -11
- package/package.json +3 -3
- package/src/debugui/components/BottomBar.tsx +28 -6
- package/src/debugui/components/LoadTapeDialog.tsx +55 -29
- package/src/debugui/components/Root.tsx +14 -4
- package/src/debugui/components/TopBar.tsx +11 -1
- package/src/debugui/components/VerticalBar.tsx +17 -1
- package/src/debugui/state.ts +52 -11
- package/src/debugui/styles.ts +53 -13
package/dist/mod.js
CHANGED
|
@@ -82,6 +82,8 @@ __export2(exports_engine, {
|
|
|
82
82
|
SNAPSHOT_HEADER_LEN: () => SNAPSHOT_HEADER_LEN,
|
|
83
83
|
SNAPSHOT_HEADER_ENGINE_LEN_OFFSET: () => SNAPSHOT_HEADER_ENGINE_LEN_OFFSET,
|
|
84
84
|
SCREEN_CTX_OFFSET: () => SCREEN_CTX_OFFSET,
|
|
85
|
+
RandContext: () => RandContext,
|
|
86
|
+
RAND_CTX_OFFSET: () => RAND_CTX_OFFSET,
|
|
85
87
|
PlayerInputContext: () => PlayerInputContext,
|
|
86
88
|
PLAYER_INPUTS_SIZE: () => PLAYER_INPUTS_SIZE,
|
|
87
89
|
PLAYER_INPUTS_MOUSE_CTX_OFFSET: () => PLAYER_INPUTS_MOUSE_CTX_OFFSET,
|
|
@@ -421,6 +423,7 @@ var SCREEN_CTX_HEIGHT_OFFSET = 4;
|
|
|
421
423
|
var SCREEN_CTX_PHYSICAL_WIDTH_OFFSET = 8;
|
|
422
424
|
var SCREEN_CTX_PHYSICAL_HEIGHT_OFFSET = 12;
|
|
423
425
|
var SCREEN_CTX_PIXEL_RATIO_OFFSET = 16;
|
|
426
|
+
var RAND_CTX_SEED_OFFSET = 0;
|
|
424
427
|
var MOUSE_CTX_X_OFFSET = 0;
|
|
425
428
|
var MOUSE_CTX_Y_OFFSET = 4;
|
|
426
429
|
var MOUSE_CTX_WHEEL_X_OFFSET = 8;
|
|
@@ -1354,6 +1357,57 @@ class NetContext {
|
|
|
1354
1357
|
}
|
|
1355
1358
|
}
|
|
1356
1359
|
|
|
1360
|
+
class RandContext {
|
|
1361
|
+
dataView;
|
|
1362
|
+
constructor(dataView) {
|
|
1363
|
+
this.dataView = dataView;
|
|
1364
|
+
}
|
|
1365
|
+
seed(value) {
|
|
1366
|
+
if (!this.dataView) {
|
|
1367
|
+
throw new Error("RandContext not initialized");
|
|
1368
|
+
}
|
|
1369
|
+
this.dataView.setUint32(RAND_CTX_SEED_OFFSET, value >>> 0, true);
|
|
1370
|
+
}
|
|
1371
|
+
getSeed() {
|
|
1372
|
+
if (!this.dataView) {
|
|
1373
|
+
throw new Error("RandContext not initialized");
|
|
1374
|
+
}
|
|
1375
|
+
return this.dataView.getUint32(RAND_CTX_SEED_OFFSET, true);
|
|
1376
|
+
}
|
|
1377
|
+
next() {
|
|
1378
|
+
if (!this.dataView) {
|
|
1379
|
+
throw new Error("RandContext not initialized");
|
|
1380
|
+
}
|
|
1381
|
+
let seed = this.dataView.getUint32(RAND_CTX_SEED_OFFSET, true);
|
|
1382
|
+
seed = seed + 1831565813 | 0;
|
|
1383
|
+
let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
|
|
1384
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
1385
|
+
this.dataView.setUint32(RAND_CTX_SEED_OFFSET, seed >>> 0, true);
|
|
1386
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
1387
|
+
}
|
|
1388
|
+
coinFlip() {
|
|
1389
|
+
return this.next() < 0.5;
|
|
1390
|
+
}
|
|
1391
|
+
rollDice(sides = 6) {
|
|
1392
|
+
return Math.floor(this.next() * sides) + 1;
|
|
1393
|
+
}
|
|
1394
|
+
int(min, max) {
|
|
1395
|
+
return Math.floor(this.next() * (max - min + 1)) + min;
|
|
1396
|
+
}
|
|
1397
|
+
float(min, max) {
|
|
1398
|
+
return this.next() * (max - min) + min;
|
|
1399
|
+
}
|
|
1400
|
+
shuffle(array) {
|
|
1401
|
+
for (let i = array.length - 1;i > 0; i--) {
|
|
1402
|
+
const j = Math.floor(this.next() * (i + 1));
|
|
1403
|
+
const temp = array[i];
|
|
1404
|
+
array[i] = array[j];
|
|
1405
|
+
array[j] = temp;
|
|
1406
|
+
}
|
|
1407
|
+
return array;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1357
1411
|
class ScreenContext {
|
|
1358
1412
|
dataView;
|
|
1359
1413
|
constructor(dataView) {
|
|
@@ -1450,13 +1504,14 @@ function readTapeHeader(tape) {
|
|
|
1450
1504
|
eventCount: view.getUint16(14, true)
|
|
1451
1505
|
};
|
|
1452
1506
|
}
|
|
1453
|
-
var DEFAULT_WASM_URL = new URL("https://unpkg.com/@bloopjs/engine@0.0.
|
|
1507
|
+
var DEFAULT_WASM_URL = new URL("https://unpkg.com/@bloopjs/engine@0.0.104/wasm/bloop.wasm");
|
|
1454
1508
|
var MAX_ROLLBACK_FRAMES = 500;
|
|
1455
1509
|
var TIME_CTX_OFFSET = 0;
|
|
1456
1510
|
var INPUT_CTX_OFFSET = TIME_CTX_OFFSET + 4;
|
|
1457
1511
|
var EVENTS_OFFSET = INPUT_CTX_OFFSET + 4;
|
|
1458
1512
|
var NET_CTX_OFFSET = EVENTS_OFFSET + 4;
|
|
1459
1513
|
var SCREEN_CTX_OFFSET = NET_CTX_OFFSET + 4;
|
|
1514
|
+
var RAND_CTX_OFFSET = SCREEN_CTX_OFFSET + 4;
|
|
1460
1515
|
var SNAPSHOT_HEADER_LEN = 16;
|
|
1461
1516
|
var SNAPSHOT_HEADER_USER_LEN_OFFSET = 4;
|
|
1462
1517
|
var SNAPSHOT_HEADER_ENGINE_LEN_OFFSET = 8;
|
|
@@ -1556,6 +1611,9 @@ class Sim {
|
|
|
1556
1611
|
throw new Error(`failed to start recording, error code=${result}`);
|
|
1557
1612
|
}
|
|
1558
1613
|
}
|
|
1614
|
+
stopRecording() {
|
|
1615
|
+
this.wasm.stop_recording();
|
|
1616
|
+
}
|
|
1559
1617
|
saveTape() {
|
|
1560
1618
|
const tapeLen = this.wasm.get_tape_len();
|
|
1561
1619
|
const tapePtr = this.wasm.get_tape_ptr();
|
|
@@ -1855,6 +1913,7 @@ class Bloop {
|
|
|
1855
1913
|
#systems = [];
|
|
1856
1914
|
#context;
|
|
1857
1915
|
#engineBuffer = new ArrayBuffer(0);
|
|
1916
|
+
#randSeeded = false;
|
|
1858
1917
|
static create(opts = {}) {
|
|
1859
1918
|
return new Bloop(opts, "dontCallMeDirectly");
|
|
1860
1919
|
}
|
|
@@ -1865,6 +1924,7 @@ class Bloop {
|
|
|
1865
1924
|
const inputs = new InputContext;
|
|
1866
1925
|
const net = new NetContext;
|
|
1867
1926
|
const screen = new ScreenContext;
|
|
1927
|
+
const rand = new RandContext;
|
|
1868
1928
|
this.#context = {
|
|
1869
1929
|
bag: opts.bag ?? {},
|
|
1870
1930
|
time: new TimeContext,
|
|
@@ -1872,7 +1932,8 @@ class Bloop {
|
|
|
1872
1932
|
players: new Players(inputs, net),
|
|
1873
1933
|
rawPointer: -1,
|
|
1874
1934
|
net,
|
|
1875
|
-
screen
|
|
1935
|
+
screen,
|
|
1936
|
+
rand
|
|
1876
1937
|
};
|
|
1877
1938
|
}
|
|
1878
1939
|
get bag() {
|
|
@@ -1934,6 +1995,14 @@ class Bloop {
|
|
|
1934
1995
|
if (this.#context.screen.dataView?.buffer !== this.#engineBuffer || this.#context.screen.dataView?.byteOffset !== screenCtxPtr) {
|
|
1935
1996
|
this.#context.screen.dataView = new DataView(this.#engineBuffer, screenCtxPtr);
|
|
1936
1997
|
}
|
|
1998
|
+
const randCtxPtr = dv.getUint32(RAND_CTX_OFFSET, true);
|
|
1999
|
+
if (this.#context.rand.dataView?.buffer !== this.#engineBuffer || this.#context.rand.dataView?.byteOffset !== randCtxPtr) {
|
|
2000
|
+
this.#context.rand.dataView = new DataView(this.#engineBuffer, randCtxPtr);
|
|
2001
|
+
}
|
|
2002
|
+
if (!this.#randSeeded) {
|
|
2003
|
+
this.#context.rand.seed(Date.now() & 4294967295);
|
|
2004
|
+
this.#randSeeded = true;
|
|
2005
|
+
}
|
|
1937
2006
|
},
|
|
1938
2007
|
systemsCallback: (system_handle, ptr) => {
|
|
1939
2008
|
this.hooks.setContext(ptr);
|
|
@@ -3321,12 +3390,13 @@ function readTapeHeader2(tape) {
|
|
|
3321
3390
|
eventCount: view.getUint16(14, true)
|
|
3322
3391
|
};
|
|
3323
3392
|
}
|
|
3324
|
-
var DEFAULT_WASM_URL2 = new URL("https://unpkg.com/@bloopjs/engine@0.0.
|
|
3393
|
+
var DEFAULT_WASM_URL2 = new URL("https://unpkg.com/@bloopjs/engine@0.0.104/wasm/bloop.wasm");
|
|
3325
3394
|
var TIME_CTX_OFFSET2 = 0;
|
|
3326
3395
|
var INPUT_CTX_OFFSET2 = TIME_CTX_OFFSET2 + 4;
|
|
3327
3396
|
var EVENTS_OFFSET2 = INPUT_CTX_OFFSET2 + 4;
|
|
3328
3397
|
var NET_CTX_OFFSET2 = EVENTS_OFFSET2 + 4;
|
|
3329
3398
|
var SCREEN_CTX_OFFSET2 = NET_CTX_OFFSET2 + 4;
|
|
3399
|
+
var RAND_CTX_OFFSET2 = SCREEN_CTX_OFFSET2 + 4;
|
|
3330
3400
|
|
|
3331
3401
|
// src/debugui/mod.ts
|
|
3332
3402
|
var exports_mod = {};
|
|
@@ -4444,9 +4514,12 @@ var onJumpForward = d3(null);
|
|
|
4444
4514
|
var onSeek = d3(null);
|
|
4445
4515
|
var onLoadTape = d3(null);
|
|
4446
4516
|
var onReplayLastTape = d3(null);
|
|
4517
|
+
var onReplayLastSaved = d3(null);
|
|
4447
4518
|
var onSaveTape = d3(null);
|
|
4448
4519
|
var lastTapeName = d3(null);
|
|
4520
|
+
var lastSavedTapeName = d3(null);
|
|
4449
4521
|
var isLoadDialogOpen = d3(false);
|
|
4522
|
+
var onToggleRecording = d3(null);
|
|
4450
4523
|
var debugState = {
|
|
4451
4524
|
layoutMode,
|
|
4452
4525
|
isVisible: w3(() => layoutMode.value !== "off"),
|
|
@@ -4477,9 +4550,12 @@ var debugState = {
|
|
|
4477
4550
|
onSeek,
|
|
4478
4551
|
onLoadTape,
|
|
4479
4552
|
onReplayLastTape,
|
|
4553
|
+
onReplayLastSaved,
|
|
4480
4554
|
onSaveTape,
|
|
4481
4555
|
lastTapeName,
|
|
4482
|
-
|
|
4556
|
+
lastSavedTapeName,
|
|
4557
|
+
isLoadDialogOpen,
|
|
4558
|
+
onToggleRecording
|
|
4483
4559
|
};
|
|
4484
4560
|
function cycleLayout() {
|
|
4485
4561
|
const current = layoutMode.value;
|
|
@@ -4615,12 +4691,20 @@ function wirePlaybarHandlers(app) {
|
|
|
4615
4691
|
};
|
|
4616
4692
|
debugState.onSeek.value = (ratio) => {
|
|
4617
4693
|
if (app.sim.hasHistory) {
|
|
4694
|
+
app.sim.pause();
|
|
4618
4695
|
const startFrame = debugState.tapeStartFrame.value;
|
|
4619
4696
|
const frameCount = debugState.tapeFrameCount.value;
|
|
4620
4697
|
const targetFrame = startFrame + Math.floor(ratio * frameCount);
|
|
4621
4698
|
app.sim.seek(targetFrame);
|
|
4622
4699
|
}
|
|
4623
4700
|
};
|
|
4701
|
+
debugState.onToggleRecording.value = () => {
|
|
4702
|
+
if (app.sim.isRecording) {
|
|
4703
|
+
app.sim.stopRecording();
|
|
4704
|
+
} else {
|
|
4705
|
+
app.sim.record();
|
|
4706
|
+
}
|
|
4707
|
+
};
|
|
4624
4708
|
}
|
|
4625
4709
|
function wireTapeDragDrop(canvas, app) {
|
|
4626
4710
|
canvas.addEventListener("dragover", (e4) => {
|
|
@@ -4639,7 +4723,8 @@ function wireTapeDragDrop(canvas, app) {
|
|
|
4639
4723
|
}
|
|
4640
4724
|
var TAPE_DB_NAME = "bloop-debug";
|
|
4641
4725
|
var TAPE_STORE_NAME = "tapes";
|
|
4642
|
-
var
|
|
4726
|
+
var TAPE_KEY_LOADED = "last-loaded";
|
|
4727
|
+
var TAPE_KEY_SAVED = "last-saved";
|
|
4643
4728
|
function openTapeDB() {
|
|
4644
4729
|
return new Promise((resolve, reject) => {
|
|
4645
4730
|
const request = indexedDB.open(TAPE_DB_NAME, 1);
|
|
@@ -4650,21 +4735,21 @@ function openTapeDB() {
|
|
|
4650
4735
|
};
|
|
4651
4736
|
});
|
|
4652
4737
|
}
|
|
4653
|
-
async function saveTapeToStorage(bytes, fileName) {
|
|
4738
|
+
async function saveTapeToStorage(bytes, fileName, key = TAPE_KEY_LOADED) {
|
|
4654
4739
|
const db = await openTapeDB();
|
|
4655
4740
|
return new Promise((resolve, reject) => {
|
|
4656
4741
|
const tx = db.transaction(TAPE_STORE_NAME, "readwrite");
|
|
4657
|
-
tx.objectStore(TAPE_STORE_NAME).put({ bytes, fileName },
|
|
4742
|
+
tx.objectStore(TAPE_STORE_NAME).put({ bytes, fileName }, key);
|
|
4658
4743
|
tx.oncomplete = () => resolve();
|
|
4659
4744
|
tx.onerror = () => reject(tx.error);
|
|
4660
4745
|
});
|
|
4661
4746
|
}
|
|
4662
|
-
async function loadTapeFromStorage() {
|
|
4747
|
+
async function loadTapeFromStorage(key = TAPE_KEY_LOADED) {
|
|
4663
4748
|
try {
|
|
4664
4749
|
const db = await openTapeDB();
|
|
4665
4750
|
return new Promise((resolve, reject) => {
|
|
4666
4751
|
const tx = db.transaction(TAPE_STORE_NAME, "readonly");
|
|
4667
|
-
const request = tx.objectStore(TAPE_STORE_NAME).get(
|
|
4752
|
+
const request = tx.objectStore(TAPE_STORE_NAME).get(key);
|
|
4668
4753
|
request.onsuccess = () => resolve(request.result ?? null);
|
|
4669
4754
|
request.onerror = () => reject(request.error);
|
|
4670
4755
|
});
|
|
@@ -4673,32 +4758,46 @@ async function loadTapeFromStorage() {
|
|
|
4673
4758
|
}
|
|
4674
4759
|
}
|
|
4675
4760
|
async function checkForSavedTape() {
|
|
4676
|
-
const saved = await
|
|
4677
|
-
|
|
4761
|
+
const [loaded, saved] = await Promise.all([
|
|
4762
|
+
loadTapeFromStorage(TAPE_KEY_LOADED),
|
|
4763
|
+
loadTapeFromStorage(TAPE_KEY_SAVED)
|
|
4764
|
+
]);
|
|
4765
|
+
debugState.lastTapeName.value = loaded?.fileName ?? null;
|
|
4766
|
+
debugState.lastSavedTapeName.value = saved?.fileName ?? null;
|
|
4678
4767
|
}
|
|
4679
4768
|
function wireTapeLoadHandlers(app) {
|
|
4680
4769
|
debugState.onLoadTape.value = async (bytes, fileName) => {
|
|
4681
4770
|
app.loadTape(bytes);
|
|
4682
|
-
await saveTapeToStorage(bytes, fileName);
|
|
4771
|
+
await saveTapeToStorage(bytes, fileName, TAPE_KEY_LOADED);
|
|
4683
4772
|
debugState.lastTapeName.value = fileName;
|
|
4684
4773
|
debugState.isLoadDialogOpen.value = false;
|
|
4685
4774
|
};
|
|
4686
4775
|
debugState.onReplayLastTape.value = async () => {
|
|
4687
|
-
const saved = await loadTapeFromStorage();
|
|
4776
|
+
const saved = await loadTapeFromStorage(TAPE_KEY_LOADED);
|
|
4777
|
+
if (saved) {
|
|
4778
|
+
app.loadTape(saved.bytes);
|
|
4779
|
+
debugState.isLoadDialogOpen.value = false;
|
|
4780
|
+
}
|
|
4781
|
+
};
|
|
4782
|
+
debugState.onReplayLastSaved.value = async () => {
|
|
4783
|
+
const saved = await loadTapeFromStorage(TAPE_KEY_SAVED);
|
|
4688
4784
|
if (saved) {
|
|
4689
4785
|
app.loadTape(saved.bytes);
|
|
4690
4786
|
debugState.isLoadDialogOpen.value = false;
|
|
4691
4787
|
}
|
|
4692
4788
|
};
|
|
4693
|
-
debugState.onSaveTape.value = () => {
|
|
4789
|
+
debugState.onSaveTape.value = async () => {
|
|
4694
4790
|
if (!app.sim.hasHistory)
|
|
4695
4791
|
return;
|
|
4696
4792
|
const tape = app.sim.saveTape();
|
|
4793
|
+
const fileName = `tape-${Date.now()}.bloop`;
|
|
4794
|
+
await saveTapeToStorage(tape, fileName, TAPE_KEY_SAVED);
|
|
4795
|
+
debugState.lastSavedTapeName.value = fileName;
|
|
4697
4796
|
const blob = new Blob([tape], { type: "application/octet-stream" });
|
|
4698
4797
|
const url = URL.createObjectURL(blob);
|
|
4699
4798
|
const a4 = document.createElement("a");
|
|
4700
4799
|
a4.href = url;
|
|
4701
|
-
a4.download =
|
|
4800
|
+
a4.download = fileName;
|
|
4702
4801
|
a4.click();
|
|
4703
4802
|
URL.revokeObjectURL(url);
|
|
4704
4803
|
};
|
|
@@ -4982,8 +5081,14 @@ function TopBar({ leftLabel, rightLabel }) {
|
|
|
4982
5081
|
const frameNumber2 = debugState.frameNumber.value;
|
|
4983
5082
|
const rtt = debugState.netStatus.value.rtt;
|
|
4984
5083
|
const isOnline = debugState.netStatus.value.peers.length > 0;
|
|
5084
|
+
const stopPropagation = q2((e4) => {
|
|
5085
|
+
e4.stopPropagation();
|
|
5086
|
+
}, []);
|
|
4985
5087
|
return /* @__PURE__ */ u4("div", {
|
|
4986
5088
|
className: "top-bar",
|
|
5089
|
+
onMouseDown: stopPropagation,
|
|
5090
|
+
onMouseUp: stopPropagation,
|
|
5091
|
+
onClick: stopPropagation,
|
|
4987
5092
|
children: [
|
|
4988
5093
|
/* @__PURE__ */ u4("span", {
|
|
4989
5094
|
className: "top-bar-side-label",
|
|
@@ -5049,18 +5154,31 @@ function VerticalBar({
|
|
|
5049
5154
|
value,
|
|
5050
5155
|
max,
|
|
5051
5156
|
side,
|
|
5052
|
-
color = "#4a9eff"
|
|
5157
|
+
color = "#4a9eff",
|
|
5158
|
+
displayValue
|
|
5053
5159
|
}) {
|
|
5054
5160
|
const percentage = max > 0 ? Math.min(100, value / max * 100) : 0;
|
|
5161
|
+
const stopPropagation = q2((e4) => {
|
|
5162
|
+
e4.stopPropagation();
|
|
5163
|
+
}, []);
|
|
5055
5164
|
return /* @__PURE__ */ u4("div", {
|
|
5056
5165
|
className: `${side}-bar`,
|
|
5166
|
+
onMouseDown: stopPropagation,
|
|
5167
|
+
onMouseUp: stopPropagation,
|
|
5168
|
+
onClick: stopPropagation,
|
|
5057
5169
|
children: /* @__PURE__ */ u4("div", {
|
|
5058
5170
|
className: "vertical-bar",
|
|
5059
|
-
children:
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5171
|
+
children: [
|
|
5172
|
+
/* @__PURE__ */ u4("div", {
|
|
5173
|
+
className: "vertical-bar-fill",
|
|
5174
|
+
style: { height: `${percentage}%`, background: color }
|
|
5175
|
+
}, undefined, false, undefined, this),
|
|
5176
|
+
displayValue && /* @__PURE__ */ u4("span", {
|
|
5177
|
+
className: `vertical-bar-popover ${side}`,
|
|
5178
|
+
children: displayValue
|
|
5179
|
+
}, undefined, false, undefined, this)
|
|
5180
|
+
]
|
|
5181
|
+
}, undefined, true, undefined, this)
|
|
5064
5182
|
}, undefined, false, undefined, this);
|
|
5065
5183
|
}
|
|
5066
5184
|
|
|
@@ -5070,7 +5188,6 @@ function LoadTapeDialog() {
|
|
|
5070
5188
|
const fileInputRef = A2(null);
|
|
5071
5189
|
const [isDragOver, setIsDragOver] = d2(false);
|
|
5072
5190
|
const isOpen = debugState.isLoadDialogOpen.value;
|
|
5073
|
-
const lastTapeName2 = debugState.lastTapeName.value;
|
|
5074
5191
|
y2(() => {
|
|
5075
5192
|
const dialog = dialogRef.current;
|
|
5076
5193
|
if (!dialog)
|
|
@@ -5121,11 +5238,20 @@ function LoadTapeDialog() {
|
|
|
5121
5238
|
const handleReplayLast = q2(() => {
|
|
5122
5239
|
debugState.onReplayLastTape.value?.();
|
|
5123
5240
|
}, []);
|
|
5241
|
+
const handleReplayLastSaved = q2(() => {
|
|
5242
|
+
debugState.onReplayLastSaved.value?.();
|
|
5243
|
+
}, []);
|
|
5244
|
+
const handleDialogClick = q2((e4) => {
|
|
5245
|
+
if (e4.target === e4.currentTarget) {
|
|
5246
|
+
debugState.isLoadDialogOpen.value = false;
|
|
5247
|
+
}
|
|
5248
|
+
}, []);
|
|
5124
5249
|
return /* @__PURE__ */ u4("dialog", {
|
|
5125
5250
|
ref: dialogRef,
|
|
5126
5251
|
className: "load-tape-dialog",
|
|
5127
5252
|
onClose: handleClose,
|
|
5128
|
-
|
|
5253
|
+
onClick: handleDialogClick,
|
|
5254
|
+
children: isOpen && /* @__PURE__ */ u4("div", {
|
|
5129
5255
|
className: "load-tape-dialog-content",
|
|
5130
5256
|
children: [
|
|
5131
5257
|
/* @__PURE__ */ u4("h3", {
|
|
@@ -5153,12 +5279,17 @@ function LoadTapeDialog() {
|
|
|
5153
5279
|
className: "hidden-file-input",
|
|
5154
5280
|
onChange: handleFileInputChange
|
|
5155
5281
|
}, undefined, false, undefined, this),
|
|
5156
|
-
|
|
5282
|
+
debugState.lastSavedTapeName.value && /* @__PURE__ */ u4("button", {
|
|
5283
|
+
className: "replay-last-btn",
|
|
5284
|
+
onClick: handleReplayLastSaved,
|
|
5285
|
+
children: "Replay last saved tape"
|
|
5286
|
+
}, undefined, false, undefined, this),
|
|
5287
|
+
debugState.lastTapeName.value && /* @__PURE__ */ u4("button", {
|
|
5157
5288
|
className: "replay-last-btn",
|
|
5158
5289
|
onClick: handleReplayLast,
|
|
5159
5290
|
children: [
|
|
5160
|
-
"Replay last: ",
|
|
5161
|
-
|
|
5291
|
+
"Replay last loaded: ",
|
|
5292
|
+
debugState.lastTapeName.value
|
|
5162
5293
|
]
|
|
5163
5294
|
}, undefined, true, undefined, this)
|
|
5164
5295
|
]
|
|
@@ -5169,6 +5300,14 @@ function LoadTapeDialog() {
|
|
|
5169
5300
|
// src/debugui/components/BottomBar.tsx
|
|
5170
5301
|
var iconProps = { width: 14, height: 14, viewBox: "0 0 24 24", fill: "currentColor" };
|
|
5171
5302
|
var Icons = {
|
|
5303
|
+
record: /* @__PURE__ */ u4("svg", {
|
|
5304
|
+
...iconProps,
|
|
5305
|
+
children: /* @__PURE__ */ u4("circle", {
|
|
5306
|
+
cx: "12",
|
|
5307
|
+
cy: "12",
|
|
5308
|
+
r: "8"
|
|
5309
|
+
}, undefined, false, undefined, this)
|
|
5310
|
+
}, undefined, false, undefined, this),
|
|
5172
5311
|
jumpBack: /* @__PURE__ */ u4("svg", {
|
|
5173
5312
|
...iconProps,
|
|
5174
5313
|
children: /* @__PURE__ */ u4("path", {
|
|
@@ -5311,22 +5450,33 @@ function BottomBar() {
|
|
|
5311
5450
|
const handleSaveTapeClick = q2(() => {
|
|
5312
5451
|
debugState.onSaveTape.value?.();
|
|
5313
5452
|
}, []);
|
|
5453
|
+
const handleToggleRecording = q2(() => {
|
|
5454
|
+
debugState.onToggleRecording.value?.();
|
|
5455
|
+
}, []);
|
|
5456
|
+
const stopPropagation = q2((e4) => {
|
|
5457
|
+
e4.stopPropagation();
|
|
5458
|
+
}, []);
|
|
5314
5459
|
return /* @__PURE__ */ u4("div", {
|
|
5315
5460
|
className: "bottom-bar",
|
|
5461
|
+
onMouseDown: stopPropagation,
|
|
5462
|
+
onMouseUp: stopPropagation,
|
|
5463
|
+
onClick: stopPropagation,
|
|
5316
5464
|
children: [
|
|
5317
5465
|
/* @__PURE__ */ u4("div", {
|
|
5318
5466
|
className: "playbar-controls",
|
|
5319
5467
|
children: [
|
|
5320
|
-
|
|
5321
|
-
className: "recording
|
|
5322
|
-
|
|
5468
|
+
/* @__PURE__ */ u4("button", {
|
|
5469
|
+
className: `playbar-btn record-btn ${isRecording2 ? "recording" : ""}`,
|
|
5470
|
+
onClick: handleToggleRecording,
|
|
5323
5471
|
children: [
|
|
5324
|
-
|
|
5325
|
-
|
|
5472
|
+
Icons.record,
|
|
5473
|
+
isRecording2 && /* @__PURE__ */ u4("span", {
|
|
5474
|
+
className: "btn-label",
|
|
5475
|
+
children: "REC"
|
|
5326
5476
|
}, undefined, false, undefined, this),
|
|
5327
5477
|
/* @__PURE__ */ u4("span", {
|
|
5328
|
-
className: "
|
|
5329
|
-
children: "
|
|
5478
|
+
className: "tooltip tooltip-left",
|
|
5479
|
+
children: isRecording2 ? "Stop recording" : "Start recording"
|
|
5330
5480
|
}, undefined, false, undefined, this)
|
|
5331
5481
|
]
|
|
5332
5482
|
}, undefined, true, undefined, this),
|
|
@@ -5537,11 +5687,13 @@ function LetterboxedLayout({ canvas }) {
|
|
|
5537
5687
|
const hmrFlash2 = debugState.hmrFlash.value;
|
|
5538
5688
|
const leftValue = isOnline ? Math.abs(advantage) : frameTime2;
|
|
5539
5689
|
const leftMax = isOnline ? 10 : 16.67;
|
|
5540
|
-
const leftLabel = isOnline ? "
|
|
5690
|
+
const leftLabel = isOnline ? "adv" : "time";
|
|
5541
5691
|
const leftColor = isOnline ? advantage >= 0 ? "#4a9eff" : "#ff4a4a" : frameTime2 > 16.67 ? "#ff4a4a" : "#4aff4a";
|
|
5692
|
+
const leftDisplayValue = isOnline ? `${advantage >= 0 ? "+" : ""}${advantage} frames` : `${frameTime2.toFixed(1)}ms`;
|
|
5542
5693
|
const rightValue = isOnline ? 0 : snapshotSize2;
|
|
5543
5694
|
const rightMax = isOnline ? 10 : 1e4;
|
|
5544
|
-
const rightLabel = isOnline ? "
|
|
5695
|
+
const rightLabel = isOnline ? "rb" : "size";
|
|
5696
|
+
const rightDisplayValue = isOnline ? "0 frames" : snapshotSize2 >= 1000 ? `${(snapshotSize2 / 1000).toFixed(1)}kb` : `${snapshotSize2}b`;
|
|
5545
5697
|
const gameClassName = hmrFlash2 ? "letterboxed-game hmr-flash" : "letterboxed-game";
|
|
5546
5698
|
return /* @__PURE__ */ u4("main", {
|
|
5547
5699
|
className: "layout-letterboxed",
|
|
@@ -5554,7 +5706,8 @@ function LetterboxedLayout({ canvas }) {
|
|
|
5554
5706
|
value: leftValue,
|
|
5555
5707
|
max: leftMax,
|
|
5556
5708
|
side: "left",
|
|
5557
|
-
color: leftColor
|
|
5709
|
+
color: leftColor,
|
|
5710
|
+
displayValue: leftDisplayValue
|
|
5558
5711
|
}, undefined, false, undefined, this),
|
|
5559
5712
|
/* @__PURE__ */ u4("div", {
|
|
5560
5713
|
className: gameClassName,
|
|
@@ -5565,7 +5718,8 @@ function LetterboxedLayout({ canvas }) {
|
|
|
5565
5718
|
/* @__PURE__ */ u4(VerticalBar, {
|
|
5566
5719
|
value: rightValue,
|
|
5567
5720
|
max: rightMax,
|
|
5568
|
-
side: "right"
|
|
5721
|
+
side: "right",
|
|
5722
|
+
displayValue: rightDisplayValue
|
|
5569
5723
|
}, undefined, false, undefined, this),
|
|
5570
5724
|
/* @__PURE__ */ u4(BottomBar, {}, undefined, false, undefined, this)
|
|
5571
5725
|
]
|
|
@@ -5749,6 +5903,7 @@ var styles = `
|
|
|
5749
5903
|
font-family: monospace;
|
|
5750
5904
|
font-size: 12px;
|
|
5751
5905
|
padding: 0;
|
|
5906
|
+
user-select: none;
|
|
5752
5907
|
}
|
|
5753
5908
|
|
|
5754
5909
|
.top-bar-side-label {
|
|
@@ -5802,6 +5957,7 @@ var styles = `
|
|
|
5802
5957
|
justify-content: flex-end;
|
|
5803
5958
|
background: #111;
|
|
5804
5959
|
padding: 4px 0;
|
|
5960
|
+
user-select: none;
|
|
5805
5961
|
}
|
|
5806
5962
|
|
|
5807
5963
|
.right-bar {
|
|
@@ -5812,6 +5968,7 @@ var styles = `
|
|
|
5812
5968
|
justify-content: flex-end;
|
|
5813
5969
|
background: #111;
|
|
5814
5970
|
padding: 4px 0;
|
|
5971
|
+
user-select: none;
|
|
5815
5972
|
}
|
|
5816
5973
|
|
|
5817
5974
|
.vertical-bar {
|
|
@@ -5820,7 +5977,6 @@ var styles = `
|
|
|
5820
5977
|
background: #333;
|
|
5821
5978
|
border-radius: 2px;
|
|
5822
5979
|
position: relative;
|
|
5823
|
-
overflow: hidden;
|
|
5824
5980
|
}
|
|
5825
5981
|
|
|
5826
5982
|
.vertical-bar-fill {
|
|
@@ -5833,6 +5989,37 @@ var styles = `
|
|
|
5833
5989
|
transition: height 0.1s ease-out;
|
|
5834
5990
|
}
|
|
5835
5991
|
|
|
5992
|
+
.vertical-bar-popover {
|
|
5993
|
+
position: absolute;
|
|
5994
|
+
top: 50%;
|
|
5995
|
+
transform: translateY(-50%);
|
|
5996
|
+
background: #222;
|
|
5997
|
+
color: #ccc;
|
|
5998
|
+
padding: 4px 8px;
|
|
5999
|
+
border-radius: 4px;
|
|
6000
|
+
font-size: 10px;
|
|
6001
|
+
font-family: monospace;
|
|
6002
|
+
white-space: nowrap;
|
|
6003
|
+
opacity: 0;
|
|
6004
|
+
visibility: hidden;
|
|
6005
|
+
transition: opacity 0.15s;
|
|
6006
|
+
pointer-events: none;
|
|
6007
|
+
z-index: 10;
|
|
6008
|
+
}
|
|
6009
|
+
|
|
6010
|
+
.vertical-bar-popover.left {
|
|
6011
|
+
left: calc(100% + 8px);
|
|
6012
|
+
}
|
|
6013
|
+
|
|
6014
|
+
.vertical-bar-popover.right {
|
|
6015
|
+
right: calc(100% + 8px);
|
|
6016
|
+
}
|
|
6017
|
+
|
|
6018
|
+
.vertical-bar:hover .vertical-bar-popover {
|
|
6019
|
+
opacity: 1;
|
|
6020
|
+
visibility: visible;
|
|
6021
|
+
}
|
|
6022
|
+
|
|
5836
6023
|
|
|
5837
6024
|
.bottom-bar {
|
|
5838
6025
|
grid-area: bottom-bar;
|
|
@@ -5842,6 +6029,7 @@ var styles = `
|
|
|
5842
6029
|
/* Mobile-first: more padding */
|
|
5843
6030
|
padding: 0 16px;
|
|
5844
6031
|
gap: 12px;
|
|
6032
|
+
user-select: none;
|
|
5845
6033
|
}
|
|
5846
6034
|
|
|
5847
6035
|
/* Desktop: tighter padding */
|
|
@@ -5859,22 +6047,16 @@ var styles = `
|
|
|
5859
6047
|
flex-shrink: 0;
|
|
5860
6048
|
}
|
|
5861
6049
|
|
|
5862
|
-
/*
|
|
5863
|
-
.
|
|
5864
|
-
|
|
5865
|
-
align-items: center;
|
|
5866
|
-
margin-right: 4px;
|
|
6050
|
+
/* Record button */
|
|
6051
|
+
.record-btn {
|
|
6052
|
+
color: #666;
|
|
5867
6053
|
}
|
|
5868
6054
|
|
|
5869
|
-
.
|
|
5870
|
-
|
|
6055
|
+
.record-btn.recording {
|
|
6056
|
+
color: #ff4444;
|
|
5871
6057
|
}
|
|
5872
6058
|
|
|
5873
|
-
.recording
|
|
5874
|
-
width: 10px;
|
|
5875
|
-
height: 10px;
|
|
5876
|
-
background: #ff4444;
|
|
5877
|
-
border-radius: 50%;
|
|
6059
|
+
.record-btn.recording svg {
|
|
5878
6060
|
animation: recording-pulse 1s ease-in-out infinite;
|
|
5879
6061
|
}
|
|
5880
6062
|
|
|
@@ -5883,6 +6065,17 @@ var styles = `
|
|
|
5883
6065
|
50% { opacity: 0.4; }
|
|
5884
6066
|
}
|
|
5885
6067
|
|
|
6068
|
+
/* Desktop: show REC label when recording */
|
|
6069
|
+
@media (min-width: 769px) {
|
|
6070
|
+
.record-btn.recording {
|
|
6071
|
+
width: auto;
|
|
6072
|
+
padding: 0 6px;
|
|
6073
|
+
gap: 4px;
|
|
6074
|
+
background: rgba(255, 68, 68, 0.15);
|
|
6075
|
+
border-radius: 3px;
|
|
6076
|
+
}
|
|
6077
|
+
}
|
|
6078
|
+
|
|
5886
6079
|
/* Replay indicator - mobile: hidden */
|
|
5887
6080
|
.replay-indicator {
|
|
5888
6081
|
display: none;
|
|
@@ -6044,6 +6237,7 @@ var styles = `
|
|
|
6044
6237
|
position: relative;
|
|
6045
6238
|
cursor: pointer;
|
|
6046
6239
|
overflow: hidden;
|
|
6240
|
+
user-select: none;
|
|
6047
6241
|
}
|
|
6048
6242
|
|
|
6049
6243
|
/* Desktop: smaller seek bar */
|
|
@@ -7698,5 +7892,5 @@ export {
|
|
|
7698
7892
|
App
|
|
7699
7893
|
};
|
|
7700
7894
|
|
|
7701
|
-
//# debugId=
|
|
7895
|
+
//# debugId=6B601178E41D054664756E2164756E21
|
|
7702
7896
|
//# sourceMappingURL=mod.js.map
|