@bloopjs/web 0.0.56 → 0.0.57

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/mod.js CHANGED
@@ -3440,6 +3440,7 @@ __export(exports_mod, {
3440
3440
  resetState: () => resetState,
3441
3441
  removePeer: () => removePeer,
3442
3442
  debugState: () => debugState,
3443
+ cycleLayout: () => cycleLayout,
3443
3444
  clearLogs: () => clearLogs,
3444
3445
  addPeer: () => addPeer,
3445
3446
  addLog: () => addLog,
@@ -4471,7 +4472,7 @@ function useSignalEffect(i4) {
4471
4472
  }
4472
4473
 
4473
4474
  // src/debugui/state.ts
4474
- var isVisible = d2(false);
4475
+ var layoutMode = d2("off");
4475
4476
  var netStatus = d2({
4476
4477
  ourId: null,
4477
4478
  remoteId: null,
@@ -4479,16 +4480,35 @@ var netStatus = d2({
4479
4480
  peers: []
4480
4481
  });
4481
4482
  var logs = d2([]);
4483
+ var fps = d2(0);
4484
+ var frameTime = d2(0);
4485
+ var snapshotSize = d2(0);
4486
+ var frameNumber = d2(0);
4482
4487
  var debugState = {
4483
- isVisible,
4488
+ layoutMode,
4489
+ isVisible: w3(() => layoutMode.value !== "off"),
4484
4490
  netStatus,
4485
4491
  logs,
4486
4492
  peer: w3(() => netStatus.value.peers[0] ?? null),
4487
4493
  advantage: w3(() => {
4488
4494
  const peer = netStatus.value.peers[0];
4489
4495
  return peer ? peer.seq - peer.ack : null;
4490
- })
4496
+ }),
4497
+ fps,
4498
+ frameTime,
4499
+ snapshotSize,
4500
+ frameNumber
4491
4501
  };
4502
+ function cycleLayout() {
4503
+ const current = layoutMode.value;
4504
+ if (current === "off") {
4505
+ layoutMode.value = "letterboxed";
4506
+ } else if (current === "letterboxed") {
4507
+ layoutMode.value = "full";
4508
+ } else {
4509
+ layoutMode.value = "off";
4510
+ }
4511
+ }
4492
4512
  function addLog(log) {
4493
4513
  debugState.logs.value = [...debugState.logs.value, log];
4494
4514
  }
@@ -4538,7 +4558,7 @@ function clearLogs() {
4538
4558
  debugState.logs.value = [];
4539
4559
  }
4540
4560
  function resetState() {
4541
- debugState.isVisible.value = false;
4561
+ debugState.layoutMode.value = "off";
4542
4562
  debugState.logs.value = [];
4543
4563
  debugState.netStatus.value = {
4544
4564
  ourId: null,
@@ -4546,6 +4566,10 @@ function resetState() {
4546
4566
  rtt: null,
4547
4567
  peers: []
4548
4568
  };
4569
+ debugState.fps.value = 0;
4570
+ debugState.frameTime.value = 0;
4571
+ debugState.snapshotSize.value = 0;
4572
+ debugState.frameNumber.value = 0;
4549
4573
  }
4550
4574
  // ../../node_modules/preact/jsx-runtime/dist/jsxRuntime.module.js
4551
4575
  var f4 = 0;
@@ -4808,26 +4832,257 @@ function LogEntry({ log }) {
4808
4832
 
4809
4833
  // src/debugui/components/DebugToggle.tsx
4810
4834
  function DebugToggle({ hotkey = "Escape" }) {
4811
- const isVisible2 = debugState.isVisible.value;
4812
- const toggle = () => {
4813
- debugState.isVisible.value = !debugState.isVisible.value;
4814
- };
4835
+ const isVisible = debugState.isVisible.value;
4815
4836
  return /* @__PURE__ */ u4("button", {
4816
4837
  className: "debug-toggle",
4817
- onClick: toggle,
4838
+ onClick: cycleLayout,
4818
4839
  onMouseDown: (e4) => e4.stopPropagation(),
4819
4840
  onMouseUp: (e4) => e4.stopPropagation(),
4820
- title: isVisible2 ? `Hide debug (${hotkey})` : `Show debug (${hotkey})`,
4821
- children: isVisible2 ? "✕" : "⚙"
4841
+ title: isVisible ? `Hide debug (${hotkey})` : `Show debug (${hotkey})`,
4842
+ children: isVisible ? "✕" : "⚙"
4843
+ }, undefined, false, undefined, this);
4844
+ }
4845
+
4846
+ // src/debugui/components/TopBar.tsx
4847
+ function TopBar({ leftLabel, rightLabel }) {
4848
+ const fps2 = debugState.fps.value;
4849
+ const frameNumber2 = debugState.frameNumber.value;
4850
+ const rtt = debugState.netStatus.value.rtt;
4851
+ const isOnline = debugState.netStatus.value.peers.length > 0;
4852
+ return /* @__PURE__ */ u4("div", {
4853
+ className: "top-bar",
4854
+ children: [
4855
+ /* @__PURE__ */ u4("span", {
4856
+ className: "top-bar-side-label",
4857
+ children: leftLabel
4858
+ }, undefined, false, undefined, this),
4859
+ /* @__PURE__ */ u4("div", {
4860
+ className: "top-bar-center",
4861
+ children: [
4862
+ /* @__PURE__ */ u4("div", {
4863
+ className: "top-bar-item",
4864
+ children: [
4865
+ /* @__PURE__ */ u4("span", {
4866
+ className: "top-bar-label",
4867
+ children: "FPS"
4868
+ }, undefined, false, undefined, this),
4869
+ /* @__PURE__ */ u4("span", {
4870
+ className: "top-bar-value",
4871
+ children: fps2
4872
+ }, undefined, false, undefined, this)
4873
+ ]
4874
+ }, undefined, true, undefined, this),
4875
+ /* @__PURE__ */ u4("div", {
4876
+ className: "top-bar-item",
4877
+ children: [
4878
+ /* @__PURE__ */ u4("span", {
4879
+ className: "top-bar-label",
4880
+ children: "Frame"
4881
+ }, undefined, false, undefined, this),
4882
+ /* @__PURE__ */ u4("span", {
4883
+ className: "top-bar-value",
4884
+ children: frameNumber2
4885
+ }, undefined, false, undefined, this)
4886
+ ]
4887
+ }, undefined, true, undefined, this),
4888
+ isOnline && rtt !== null && /* @__PURE__ */ u4("div", {
4889
+ className: "top-bar-item",
4890
+ children: [
4891
+ /* @__PURE__ */ u4("span", {
4892
+ className: "top-bar-label",
4893
+ children: "Ping"
4894
+ }, undefined, false, undefined, this),
4895
+ /* @__PURE__ */ u4("span", {
4896
+ className: "top-bar-value",
4897
+ children: [
4898
+ rtt,
4899
+ "ms"
4900
+ ]
4901
+ }, undefined, true, undefined, this)
4902
+ ]
4903
+ }, undefined, true, undefined, this)
4904
+ ]
4905
+ }, undefined, true, undefined, this),
4906
+ /* @__PURE__ */ u4("span", {
4907
+ className: "top-bar-side-label",
4908
+ children: rightLabel
4909
+ }, undefined, false, undefined, this)
4910
+ ]
4911
+ }, undefined, true, undefined, this);
4912
+ }
4913
+
4914
+ // src/debugui/components/VerticalBar.tsx
4915
+ function VerticalBar({
4916
+ value,
4917
+ max,
4918
+ side,
4919
+ color = "#4a9eff"
4920
+ }) {
4921
+ const percentage = max > 0 ? Math.min(100, value / max * 100) : 0;
4922
+ return /* @__PURE__ */ u4("div", {
4923
+ className: `${side}-bar`,
4924
+ children: /* @__PURE__ */ u4("div", {
4925
+ className: "vertical-bar",
4926
+ children: /* @__PURE__ */ u4("div", {
4927
+ className: "vertical-bar-fill",
4928
+ style: { height: `${percentage}%`, background: color }
4929
+ }, undefined, false, undefined, this)
4930
+ }, undefined, false, undefined, this)
4822
4931
  }, undefined, false, undefined, this);
4823
4932
  }
4824
4933
 
4934
+ // src/debugui/components/BottomBar.tsx
4935
+ function BottomBar({
4936
+ tapeUtilization = 0,
4937
+ playheadPosition = 0,
4938
+ isPlaying = true
4939
+ }) {
4940
+ const handleJumpBack = () => {};
4941
+ const handleStepBack = () => {};
4942
+ const handlePlayPause = () => {};
4943
+ const handleStepForward = () => {};
4944
+ const handleJumpForward = () => {};
4945
+ const handleSeek = () => {};
4946
+ return /* @__PURE__ */ u4("div", {
4947
+ className: "bottom-bar",
4948
+ children: [
4949
+ /* @__PURE__ */ u4("div", {
4950
+ className: "playbar-controls",
4951
+ children: [
4952
+ /* @__PURE__ */ u4("button", {
4953
+ className: "playbar-btn",
4954
+ onClick: handleJumpBack,
4955
+ children: [
4956
+ "<<",
4957
+ /* @__PURE__ */ u4("span", {
4958
+ className: "tooltip tooltip-left",
4959
+ children: [
4960
+ "Jump back ",
4961
+ /* @__PURE__ */ u4("kbd", {
4962
+ children: "4"
4963
+ }, undefined, false, undefined, this)
4964
+ ]
4965
+ }, undefined, true, undefined, this)
4966
+ ]
4967
+ }, undefined, true, undefined, this),
4968
+ /* @__PURE__ */ u4("button", {
4969
+ className: "playbar-btn",
4970
+ onClick: handleStepBack,
4971
+ children: [
4972
+ "<",
4973
+ /* @__PURE__ */ u4("span", {
4974
+ className: "tooltip",
4975
+ children: [
4976
+ "Step back ",
4977
+ /* @__PURE__ */ u4("kbd", {
4978
+ children: "5"
4979
+ }, undefined, false, undefined, this)
4980
+ ]
4981
+ }, undefined, true, undefined, this)
4982
+ ]
4983
+ }, undefined, true, undefined, this),
4984
+ /* @__PURE__ */ u4("button", {
4985
+ className: "playbar-btn",
4986
+ onClick: handlePlayPause,
4987
+ children: [
4988
+ isPlaying ? "||" : ">",
4989
+ /* @__PURE__ */ u4("span", {
4990
+ className: "tooltip",
4991
+ children: [
4992
+ isPlaying ? "Pause" : "Play",
4993
+ " ",
4994
+ /* @__PURE__ */ u4("kbd", {
4995
+ children: "6"
4996
+ }, undefined, false, undefined, this)
4997
+ ]
4998
+ }, undefined, true, undefined, this)
4999
+ ]
5000
+ }, undefined, true, undefined, this),
5001
+ /* @__PURE__ */ u4("button", {
5002
+ className: "playbar-btn",
5003
+ onClick: handleStepForward,
5004
+ children: [
5005
+ ">",
5006
+ /* @__PURE__ */ u4("span", {
5007
+ className: "tooltip",
5008
+ children: [
5009
+ "Step forward ",
5010
+ /* @__PURE__ */ u4("kbd", {
5011
+ children: "7"
5012
+ }, undefined, false, undefined, this)
5013
+ ]
5014
+ }, undefined, true, undefined, this)
5015
+ ]
5016
+ }, undefined, true, undefined, this),
5017
+ /* @__PURE__ */ u4("button", {
5018
+ className: "playbar-btn",
5019
+ onClick: handleJumpForward,
5020
+ children: [
5021
+ ">>",
5022
+ /* @__PURE__ */ u4("span", {
5023
+ className: "tooltip",
5024
+ children: [
5025
+ "Jump forward ",
5026
+ /* @__PURE__ */ u4("kbd", {
5027
+ children: "8"
5028
+ }, undefined, false, undefined, this)
5029
+ ]
5030
+ }, undefined, true, undefined, this)
5031
+ ]
5032
+ }, undefined, true, undefined, this)
5033
+ ]
5034
+ }, undefined, true, undefined, this),
5035
+ /* @__PURE__ */ u4("div", {
5036
+ className: "seek-bar",
5037
+ onClick: handleSeek,
5038
+ children: [
5039
+ /* @__PURE__ */ u4("div", {
5040
+ className: "seek-bar-fill",
5041
+ style: { width: `${tapeUtilization * 100}%` }
5042
+ }, undefined, false, undefined, this),
5043
+ tapeUtilization > 0 && /* @__PURE__ */ u4("div", {
5044
+ className: "seek-bar-position",
5045
+ style: { left: `${playheadPosition * tapeUtilization * 100}%` }
5046
+ }, undefined, false, undefined, this)
5047
+ ]
5048
+ }, undefined, true, undefined, this)
5049
+ ]
5050
+ }, undefined, true, undefined, this);
5051
+ }
5052
+
4825
5053
  // src/debugui/components/Root.tsx
4826
5054
  function Root({ canvas, hotkey = "Escape" }) {
4827
- const isVisible2 = debugState.isVisible.value;
5055
+ const layoutMode2 = debugState.layoutMode.value;
5056
+ if (layoutMode2 === "off") {
5057
+ return /* @__PURE__ */ u4(k, {
5058
+ children: [
5059
+ /* @__PURE__ */ u4("main", {
5060
+ className: "fullscreen",
5061
+ children: /* @__PURE__ */ u4(GameCanvas, {
5062
+ canvas
5063
+ }, undefined, false, undefined, this)
5064
+ }, undefined, false, undefined, this),
5065
+ /* @__PURE__ */ u4(DebugToggle, {
5066
+ hotkey
5067
+ }, undefined, false, undefined, this)
5068
+ ]
5069
+ }, undefined, true, undefined, this);
5070
+ }
5071
+ if (layoutMode2 === "letterboxed") {
5072
+ return /* @__PURE__ */ u4(k, {
5073
+ children: [
5074
+ /* @__PURE__ */ u4(LetterboxedLayout, {
5075
+ canvas
5076
+ }, undefined, false, undefined, this),
5077
+ /* @__PURE__ */ u4(DebugToggle, {
5078
+ hotkey
5079
+ }, undefined, false, undefined, this)
5080
+ ]
5081
+ }, undefined, true, undefined, this);
5082
+ }
4828
5083
  return /* @__PURE__ */ u4(k, {
4829
5084
  children: [
4830
- isVisible2 ? /* @__PURE__ */ u4("main", {
5085
+ /* @__PURE__ */ u4("main", {
4831
5086
  className: "layout",
4832
5087
  children: [
4833
5088
  /* @__PURE__ */ u4("section", {
@@ -4845,14 +5100,53 @@ function Root({ canvas, hotkey = "Escape" }) {
4845
5100
  children: /* @__PURE__ */ u4(Logs, {}, undefined, false, undefined, this)
4846
5101
  }, undefined, false, undefined, this)
4847
5102
  ]
4848
- }, undefined, true, undefined, this) : /* @__PURE__ */ u4("main", {
4849
- className: "fullscreen",
5103
+ }, undefined, true, undefined, this),
5104
+ /* @__PURE__ */ u4(DebugToggle, {
5105
+ hotkey
5106
+ }, undefined, false, undefined, this)
5107
+ ]
5108
+ }, undefined, true, undefined, this);
5109
+ }
5110
+ function LetterboxedLayout({ canvas }) {
5111
+ const isOnline = debugState.netStatus.value.peers.length > 0;
5112
+ const advantage = debugState.advantage.value ?? 0;
5113
+ const frameTime2 = debugState.frameTime.value;
5114
+ const snapshotSize2 = debugState.snapshotSize.value;
5115
+ const leftValue = isOnline ? Math.abs(advantage) : frameTime2;
5116
+ const leftMax = isOnline ? 10 : 16.67;
5117
+ const leftLabel = isOnline ? "ADV" : "MS";
5118
+ const leftColor = isOnline ? advantage >= 0 ? "#4a9eff" : "#ff4a4a" : frameTime2 > 16.67 ? "#ff4a4a" : "#4aff4a";
5119
+ const rightValue = isOnline ? 0 : snapshotSize2;
5120
+ const rightMax = isOnline ? 10 : 1e4;
5121
+ const rightLabel = isOnline ? "RB" : "KB";
5122
+ return /* @__PURE__ */ u4("main", {
5123
+ className: "layout-letterboxed",
5124
+ children: [
5125
+ /* @__PURE__ */ u4(TopBar, {
5126
+ leftLabel,
5127
+ rightLabel
5128
+ }, undefined, false, undefined, this),
5129
+ /* @__PURE__ */ u4(VerticalBar, {
5130
+ value: leftValue,
5131
+ max: leftMax,
5132
+ side: "left",
5133
+ color: leftColor
5134
+ }, undefined, false, undefined, this),
5135
+ /* @__PURE__ */ u4("div", {
5136
+ className: "letterboxed-game",
4850
5137
  children: /* @__PURE__ */ u4(GameCanvas, {
4851
5138
  canvas
4852
5139
  }, undefined, false, undefined, this)
4853
5140
  }, undefined, false, undefined, this),
4854
- /* @__PURE__ */ u4(DebugToggle, {
4855
- hotkey
5141
+ /* @__PURE__ */ u4(VerticalBar, {
5142
+ value: rightValue,
5143
+ max: rightMax,
5144
+ side: "right"
5145
+ }, undefined, false, undefined, this),
5146
+ /* @__PURE__ */ u4(BottomBar, {
5147
+ tapeUtilization: 0.67,
5148
+ playheadPosition: 0.8,
5149
+ isPlaying: true
4856
5150
  }, undefined, false, undefined, this)
4857
5151
  ]
4858
5152
  }, undefined, true, undefined, this);
@@ -4881,13 +5175,24 @@ var styles = `
4881
5175
 
4882
5176
  /* Layout */
4883
5177
  .fullscreen {
4884
- width: 100%;
4885
- height: 100%;
5178
+ width: 100vw;
5179
+ height: 100vh;
4886
5180
  margin: 0;
4887
5181
  padding: 0;
4888
5182
  overflow: hidden;
4889
5183
  }
4890
5184
 
5185
+ .fullscreen .canvas-container {
5186
+ width: 100%;
5187
+ height: 100%;
5188
+ }
5189
+
5190
+ .fullscreen canvas {
5191
+ width: 100%;
5192
+ height: 100%;
5193
+ display: block;
5194
+ }
5195
+
4891
5196
  .layout {
4892
5197
  display: grid;
4893
5198
  grid-template-areas:
@@ -4901,6 +5206,225 @@ var styles = `
4901
5206
  padding: 1rem;
4902
5207
  }
4903
5208
 
5209
+ /* Letterboxed layout - using equal vw/vh percentages keeps game at viewport aspect ratio */
5210
+ .layout-letterboxed {
5211
+ display: grid;
5212
+ grid-template-areas:
5213
+ "top-bar top-bar top-bar"
5214
+ "left-bar game right-bar"
5215
+ "bottom-bar bottom-bar bottom-bar";
5216
+ grid-template-columns: 2vw 1fr 2vw;
5217
+ grid-template-rows: 2vh 1fr 2vh;
5218
+ width: 100vw;
5219
+ height: 100vh;
5220
+ background: #1a1a1a;
5221
+ overflow: hidden;
5222
+ overscroll-behavior: none;
5223
+ }
5224
+
5225
+ .top-bar {
5226
+ grid-area: top-bar;
5227
+ display: flex;
5228
+ align-items: center;
5229
+ justify-content: space-between;
5230
+ background: #111;
5231
+ color: #aaa;
5232
+ font-family: monospace;
5233
+ font-size: 12px;
5234
+ padding: 0;
5235
+ }
5236
+
5237
+ .top-bar-side-label {
5238
+ width: 2vw;
5239
+ text-align: center;
5240
+ font-size: 9px;
5241
+ text-transform: uppercase;
5242
+ letter-spacing: 0.5px;
5243
+ color: #666;
5244
+ }
5245
+
5246
+ .top-bar-center {
5247
+ display: flex;
5248
+ align-items: center;
5249
+ justify-content: center;
5250
+ gap: 24px;
5251
+ flex: 1;
5252
+ }
5253
+
5254
+ .top-bar-item {
5255
+ display: flex;
5256
+ align-items: center;
5257
+ gap: 6px;
5258
+ }
5259
+
5260
+ .top-bar-label {
5261
+ opacity: 0.6;
5262
+ }
5263
+
5264
+ .top-bar-value {
5265
+ color: #fff;
5266
+ font-weight: 500;
5267
+ }
5268
+
5269
+ .left-bar {
5270
+ grid-area: left-bar;
5271
+ display: flex;
5272
+ flex-direction: column;
5273
+ align-items: center;
5274
+ justify-content: flex-end;
5275
+ background: #111;
5276
+ padding: 4px 0;
5277
+ }
5278
+
5279
+ .right-bar {
5280
+ grid-area: right-bar;
5281
+ display: flex;
5282
+ flex-direction: column;
5283
+ align-items: center;
5284
+ justify-content: flex-end;
5285
+ background: #111;
5286
+ padding: 4px 0;
5287
+ }
5288
+
5289
+ .vertical-bar {
5290
+ width: 12px;
5291
+ flex: 1;
5292
+ background: #333;
5293
+ border-radius: 2px;
5294
+ position: relative;
5295
+ overflow: hidden;
5296
+ }
5297
+
5298
+ .vertical-bar-fill {
5299
+ position: absolute;
5300
+ bottom: 0;
5301
+ left: 0;
5302
+ right: 0;
5303
+ background: #4a9eff;
5304
+ border-radius: 2px;
5305
+ transition: height 0.1s ease-out;
5306
+ }
5307
+
5308
+
5309
+ .bottom-bar {
5310
+ grid-area: bottom-bar;
5311
+ display: flex;
5312
+ align-items: center;
5313
+ background: #111;
5314
+ padding: 0 8px;
5315
+ gap: 8px;
5316
+ }
5317
+
5318
+ .playbar-controls {
5319
+ display: flex;
5320
+ align-items: center;
5321
+ gap: 2px;
5322
+ flex-shrink: 0;
5323
+ }
5324
+
5325
+ .playbar-btn {
5326
+ width: 1.5vh;
5327
+ height: 1.5vh;
5328
+ min-width: 18px;
5329
+ min-height: 18px;
5330
+ border: none;
5331
+ background: transparent;
5332
+ color: #888;
5333
+ font-size: 10px;
5334
+ cursor: pointer;
5335
+ border-radius: 2px;
5336
+ display: flex;
5337
+ align-items: center;
5338
+ justify-content: center;
5339
+ transition: background 0.15s, color 0.15s;
5340
+ position: relative;
5341
+ }
5342
+
5343
+ .playbar-btn:hover {
5344
+ background: #333;
5345
+ color: #fff;
5346
+ }
5347
+
5348
+ .playbar-btn:hover .tooltip {
5349
+ opacity: 1;
5350
+ visibility: visible;
5351
+ }
5352
+
5353
+ .tooltip {
5354
+ position: absolute;
5355
+ bottom: calc(100% + 4px);
5356
+ left: 50%;
5357
+ transform: translateX(-50%);
5358
+ background: #222;
5359
+ color: #ccc;
5360
+ padding: 4px 8px;
5361
+ border-radius: 4px;
5362
+ font-size: 10px;
5363
+ white-space: nowrap;
5364
+ opacity: 0;
5365
+ visibility: hidden;
5366
+ transition: opacity 0.15s;
5367
+ pointer-events: none;
5368
+ z-index: 10;
5369
+ }
5370
+
5371
+ .tooltip-left {
5372
+ left: 0;
5373
+ transform: none;
5374
+ }
5375
+
5376
+ .tooltip kbd {
5377
+ background: #444;
5378
+ padding: 1px 4px;
5379
+ border-radius: 2px;
5380
+ margin-left: 4px;
5381
+ font-family: monospace;
5382
+ }
5383
+
5384
+ .seek-bar {
5385
+ flex: 1;
5386
+ height: 16px;
5387
+ background: #222;
5388
+ border-radius: 4px;
5389
+ position: relative;
5390
+ cursor: pointer;
5391
+ overflow: hidden;
5392
+ }
5393
+
5394
+ .seek-bar-fill {
5395
+ position: absolute;
5396
+ top: 0;
5397
+ left: 0;
5398
+ bottom: 0;
5399
+ background: linear-gradient(to right, #4a2070, #7b3fa0);
5400
+ border-radius: 4px;
5401
+ transition: width 0.1s ease-out;
5402
+ }
5403
+
5404
+ .seek-bar-position {
5405
+ position: absolute;
5406
+ top: 0;
5407
+ bottom: 0;
5408
+ width: 2px;
5409
+ background: #fff;
5410
+ }
5411
+
5412
+ .letterboxed-game {
5413
+ grid-area: game;
5414
+ overflow: hidden;
5415
+ }
5416
+
5417
+ .letterboxed-game .canvas-container {
5418
+ width: 100%;
5419
+ height: 100%;
5420
+ }
5421
+
5422
+ .letterboxed-game canvas {
5423
+ width: 100%;
5424
+ height: 100%;
5425
+ display: block;
5426
+ }
5427
+
4904
5428
  .game {
4905
5429
  grid-area: game;
4906
5430
  border-radius: 8px;
@@ -5087,7 +5611,7 @@ class DebugUi {
5087
5611
  const container = options.container ?? document.body;
5088
5612
  const initiallyVisible = options.initiallyVisible ?? new URLSearchParams(window.location.search).has("debug");
5089
5613
  this.#host = document.createElement("bloop-debug-ui");
5090
- this.#host.style.cssText = "display:block;width:100%;height:100%;position:absolute;top:0;left:0;";
5614
+ this.#host.style.cssText = "display:block;width:100%;height:100%;position:absolute;top:0;left:0;overflow:hidden;overscroll-behavior:none;";
5091
5615
  this.#shadow = this.#host.attachShadow({ mode: "open" });
5092
5616
  const styleEl = document.createElement("style");
5093
5617
  styleEl.textContent = styles;
@@ -5096,12 +5620,12 @@ class DebugUi {
5096
5620
  this.#mountPoint.id = "debug-root";
5097
5621
  this.#mountPoint.style.cssText = "width:100%;height:100%;";
5098
5622
  this.#shadow.appendChild(this.#mountPoint);
5099
- debugState.isVisible.value = initiallyVisible;
5623
+ debugState.layoutMode.value = initiallyVisible ? "letterboxed" : "off";
5100
5624
  this.#canvas = document.createElement("canvas");
5101
5625
  this.#render();
5102
5626
  container.appendChild(this.#host);
5103
5627
  this.#cleanup = this.#setupHotkey();
5104
- debugState.isVisible.subscribe(() => {
5628
+ debugState.layoutMode.subscribe(() => {
5105
5629
  this.#render();
5106
5630
  });
5107
5631
  }
@@ -5111,7 +5635,7 @@ class DebugUi {
5111
5635
  #setupHotkey() {
5112
5636
  const handler = (e4) => {
5113
5637
  if (e4.key === this.#hotkey) {
5114
- debugState.isVisible.value = !debugState.isVisible.value;
5638
+ cycleLayout();
5115
5639
  }
5116
5640
  };
5117
5641
  window.addEventListener("keydown", handler);
@@ -5127,7 +5651,7 @@ class DebugUi {
5127
5651
  return debugState.isVisible.value;
5128
5652
  }
5129
5653
  set isVisible(value) {
5130
- debugState.isVisible.value = value;
5654
+ debugState.layoutMode.value = value ? "letterboxed" : "off";
5131
5655
  }
5132
5656
  unmount() {
5133
5657
  this.#cleanup?.();
@@ -5259,8 +5783,29 @@ class App {
5259
5783
  }
5260
5784
  };
5261
5785
  window.addEventListener("keydown", playbarHotkeys);
5786
+ let fpsFrames = 0;
5787
+ let fpsLastTime = performance.now();
5262
5788
  const frame = () => {
5263
- this.sim.step(performance.now() - this.#now);
5789
+ const stepStart = performance.now();
5790
+ const ticks = this.sim.step(stepStart - this.#now);
5791
+ if (ticks > 0) {
5792
+ const stepEnd = performance.now();
5793
+ debugState.frameTime.value = stepEnd - stepStart;
5794
+ debugState.frameNumber.value = this.sim.time.frame;
5795
+ if (debugState.layoutMode.value === "letterboxed") {
5796
+ const bag = this.game.bag;
5797
+ if (bag) {
5798
+ debugState.snapshotSize.value = JSON.stringify(bag).length;
5799
+ }
5800
+ }
5801
+ fpsFrames++;
5802
+ const elapsed = stepEnd - fpsLastTime;
5803
+ if (elapsed >= 1000) {
5804
+ debugState.fps.value = Math.round(fpsFrames * 1000 / elapsed);
5805
+ fpsFrames = 0;
5806
+ fpsLastTime = stepEnd;
5807
+ }
5808
+ }
5264
5809
  if (!this.sim.isPaused) {
5265
5810
  try {
5266
5811
  this.afterFrame.notify(this.sim.time.frame);
@@ -5466,5 +6011,5 @@ export {
5466
6011
  App
5467
6012
  };
5468
6013
 
5469
- //# debugId=720184D07033E06D64756E2164756E21
6014
+ //# debugId=97C22D9653CE8DB864756E2164756E21
5470
6015
  //# sourceMappingURL=mod.js.map