@bloopjs/web 0.0.102 → 0.0.103
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 +177 -50
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomBar.d.ts","sourceRoot":"","sources":["../../../src/debugui/components/BottomBar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BottomBar.d.ts","sourceRoot":"","sources":["../../../src/debugui/components/BottomBar.tsx"],"names":[],"mappings":"AAoIA,wBAAgB,SAAS,4CAuIxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadTapeDialog.d.ts","sourceRoot":"","sources":["../../../src/debugui/components/LoadTapeDialog.tsx"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,
|
|
1
|
+
{"version":3,"file":"LoadTapeDialog.d.ts","sourceRoot":"","sources":["../../../src/debugui/components/LoadTapeDialog.tsx"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,4CAsI7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TopBar.d.ts","sourceRoot":"","sources":["../../../src/debugui/components/TopBar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TopBar.d.ts","sourceRoot":"","sources":["../../../src/debugui/components/TopBar.tsx"],"names":[],"mappings":"AAGA,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,WAAW,2CAqC5D"}
|
|
@@ -3,7 +3,8 @@ type VerticalBarProps = {
|
|
|
3
3
|
max: number;
|
|
4
4
|
side: "left" | "right";
|
|
5
5
|
color?: string;
|
|
6
|
+
displayValue?: string;
|
|
6
7
|
};
|
|
7
|
-
export declare function VerticalBar({ value, max, side, color, }: VerticalBarProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function VerticalBar({ value, max, side, color, displayValue, }: VerticalBarProps): import("react/jsx-runtime").JSX.Element;
|
|
8
9
|
export {};
|
|
9
10
|
//# sourceMappingURL=VerticalBar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerticalBar.d.ts","sourceRoot":"","sources":["../../../src/debugui/components/VerticalBar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VerticalBar.d.ts","sourceRoot":"","sources":["../../../src/debugui/components/VerticalBar.tsx"],"names":[],"mappings":"AAEA,KAAK,gBAAgB,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,GAAG,EACH,IAAI,EACJ,KAAiB,EACjB,YAAY,GACb,EAAE,gBAAgB,2CAyBlB"}
|
package/dist/debugui/state.d.ts
CHANGED
|
@@ -43,9 +43,12 @@ export type DebugState = {
|
|
|
43
43
|
onSeek: Signal<((position: number) => void) | null>;
|
|
44
44
|
onLoadTape: Signal<((bytes: Uint8Array, fileName: string) => void) | null>;
|
|
45
45
|
onReplayLastTape: Signal<(() => void) | null>;
|
|
46
|
+
onReplayLastSaved: Signal<(() => void) | null>;
|
|
46
47
|
onSaveTape: Signal<(() => void) | null>;
|
|
47
48
|
lastTapeName: Signal<string | null>;
|
|
49
|
+
lastSavedTapeName: Signal<string | null>;
|
|
48
50
|
isLoadDialogOpen: Signal<boolean>;
|
|
51
|
+
onToggleRecording: Signal<(() => void) | null>;
|
|
49
52
|
};
|
|
50
53
|
export declare const debugState: DebugState;
|
|
51
54
|
/** Cycle through layout modes: off -> letterboxed -> full -> off */
|
|
@@ -64,7 +67,7 @@ export declare function resetState(): void;
|
|
|
64
67
|
export declare function wirePlaybarHandlers(app: App): void;
|
|
65
68
|
/** Set up drag-and-drop tape loading on a canvas element */
|
|
66
69
|
export declare function wireTapeDragDrop(canvas: HTMLCanvasElement, app: App): void;
|
|
67
|
-
/** Check for saved
|
|
70
|
+
/** Check for saved tapes and update signals */
|
|
68
71
|
export declare function checkForSavedTape(): Promise<void>;
|
|
69
72
|
/** Wire up tape loading handlers */
|
|
70
73
|
export declare function wireTapeLoadHandlers(app: App): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/debugui/state.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/debugui/state.ts"],"names":[],"mappings":"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"}
|
package/dist/debugui/styles.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const styles = "\n/* Reset for shadow DOM */\n* {\n box-sizing: border-box;\n}\n\n/* Mobile-first CSS variables */\n:host {\n --bar-size: 10vw;\n --bar-size-h: 10vh;\n --bar-size-h: 10dvh;\n}\n\n/* Desktop overrides */\n@media (min-width: 769px) {\n :host {\n --bar-size: 2vw;\n --bar-size-h: 2vh;\n }\n}\n\n/* Layout */\n.fullscreen {\n width: 100vw;\n height: 100vh;\n height: 100dvh;\n margin: 0;\n padding: 0;\n overflow: hidden;\n}\n\n.fullscreen .canvas-container {\n width: 100%;\n height: 100%;\n}\n\n.fullscreen canvas {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* Mobile-first: vertical scroll layout */\n.layout {\n /* Use fixed position on mobile to escape parent overflow:hidden */\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overscroll-behavior-y: contain;\n padding: 0;\n gap: 0;\n background: #1a1a1a;\n}\n\n.layout .game {\n /* Use dvh with vh fallback for mobile Safari address bar */\n height: 100vh;\n height: 100dvh;\n width: 100%;\n flex-shrink: 0;\n /* Mobile: no border radius, fullscreen game */\n border-radius: 0;\n}\n\n/* Mobile: stretch canvas to fill game area */\n.layout .game .canvas-container {\n width: 100%;\n height: 100%;\n}\n\n.layout .game .canvas-container canvas {\n width: 100%;\n height: 100%;\n max-width: none;\n max-height: none;\n display: block;\n}\n\n.layout .stats,\n.layout .logs {\n width: 100%;\n min-height: 50vh;\n min-height: 50dvh;\n padding: 1rem;\n flex-shrink: 0;\n}\n\n/* Desktop: 2x2 grid layout */\n@media (min-width: 769px) {\n .layout {\n position: static;\n display: grid;\n grid-template-areas:\n \"game stats\"\n \"logs logs\";\n grid-template-columns: calc(50% - 0.5rem) calc(50% - 0.5rem);\n grid-template-rows: calc(50% - 0.5rem) calc(50% - 0.5rem);\n gap: 1rem;\n padding: 1rem;\n height: 100%;\n overflow: hidden;\n -webkit-overflow-scrolling: auto;\n overscroll-behavior-y: auto;\n }\n\n .layout .game {\n height: auto;\n flex-shrink: initial;\n border-radius: 8px;\n }\n\n /* Desktop: restore centered canvas with constraints */\n .layout .game .canvas-container canvas {\n width: auto;\n height: auto;\n max-width: 100%;\n max-height: 100%;\n }\n\n .layout .stats,\n .layout .logs {\n min-height: auto;\n padding: 1rem;\n flex-shrink: initial;\n }\n}\n\n/* Letterboxed layout - using equal vw/vh percentages keeps game at viewport aspect ratio */\n.layout-letterboxed {\n display: grid;\n grid-template-areas:\n \"top-bar top-bar top-bar\"\n \"left-bar game right-bar\"\n \"bottom-bar bottom-bar bottom-bar\";\n grid-template-columns: var(--bar-size) 1fr var(--bar-size);\n grid-template-rows: var(--bar-size-h) 1fr var(--bar-size-h);\n width: 100vw;\n /* Use dvh with vh fallback for mobile Safari address bar */\n height: 100vh;\n height: 100dvh;\n background: #1a1a1a;\n overflow: hidden;\n overscroll-behavior: none;\n}\n\n.top-bar {\n grid-area: top-bar;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: #111;\n color: #aaa;\n font-family: monospace;\n font-size: 12px;\n padding: 0;\n}\n\n.top-bar-side-label {\n width: var(--bar-size);\n text-align: center;\n font-size: 9px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #666;\n}\n\n/* Mobile: larger top bar text */\n@media (max-width: 768px) {\n .top-bar-side-label {\n font-size: 12px;\n }\n\n .top-bar {\n font-size: 14px;\n }\n}\n\n.top-bar-center {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 24px;\n flex: 1;\n}\n\n.top-bar-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.top-bar-label {\n opacity: 0.6;\n}\n\n.top-bar-value {\n color: #fff;\n font-weight: 500;\n}\n\n.left-bar {\n grid-area: left-bar;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n background: #111;\n padding: 4px 0;\n}\n\n.right-bar {\n grid-area: right-bar;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n background: #111;\n padding: 4px 0;\n}\n\n.vertical-bar {\n width: 12px;\n flex: 1;\n background: #333;\n border-radius: 2px;\n position: relative;\n overflow: hidden;\n}\n\n.vertical-bar-fill {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: #4a9eff;\n border-radius: 2px;\n transition: height 0.1s ease-out;\n}\n\n\n.bottom-bar {\n grid-area: bottom-bar;\n display: flex;\n align-items: center;\n background: #111;\n /* Mobile-first: more padding */\n padding: 0 16px;\n gap: 12px;\n}\n\n/* Desktop: tighter padding */\n@media (min-width: 769px) {\n .bottom-bar {\n padding: 0 8px;\n gap: 8px;\n }\n}\n\n.playbar-controls {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n}\n\n/* Recording indicator - mobile: just the dot */\n.recording-indicator {\n display: flex;\n align-items: center;\n margin-right: 4px;\n}\n\n.recording-indicator .recording-label {\n display: none;\n}\n\n.recording-dot {\n width: 10px;\n height: 10px;\n background: #ff4444;\n border-radius: 50%;\n animation: recording-pulse 1s ease-in-out infinite;\n}\n\n@keyframes recording-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n}\n\n/* Replay indicator - mobile: hidden */\n.replay-indicator {\n display: none;\n}\n\n/* Desktop: full indicators with text */\n@media (min-width: 769px) {\n .recording-indicator {\n gap: 4px;\n padding: 2px 6px;\n background: rgba(255, 0, 0, 0.2);\n border: 1px solid #ff4444;\n border-radius: 3px;\n }\n\n .recording-indicator .recording-label {\n display: inline;\n color: #ff4444;\n font-size: 10px;\n font-weight: bold;\n font-family: monospace;\n }\n\n .recording-dot {\n width: 8px;\n height: 8px;\n }\n\n .replay-indicator {\n display: flex;\n align-items: center;\n padding: 2px 6px;\n background: rgba(100, 100, 255, 0.2);\n border: 1px solid #6666ff;\n border-radius: 3px;\n color: #6666ff;\n font-size: 10px;\n font-weight: bold;\n font-family: monospace;\n margin-right: 4px;\n }\n}\n\n/* Mobile-first: hide step/jump buttons */\n.playbar-btn.jump-back,\n.playbar-btn.step-back,\n.playbar-btn.step-forward,\n.playbar-btn.jump-forward {\n display: none;\n}\n\n/* Desktop: show all controls */\n@media (min-width: 769px) {\n .playbar-btn.jump-back,\n .playbar-btn.step-back,\n .playbar-btn.step-forward,\n .playbar-btn.jump-forward {\n display: flex;\n }\n}\n\n.playbar-btn {\n /* Mobile-first: larger buttons */\n width: 4vh;\n height: 4vh;\n min-width: 32px;\n min-height: 32px;\n border: none;\n outline: none;\n background: transparent;\n color: #888;\n font-size: 16px;\n cursor: pointer;\n border-radius: 2px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.15s, color 0.15s;\n position: relative;\n}\n\n/* Desktop: sized to match indicators */\n@media (min-width: 769px) {\n .playbar-btn {\n width: 24px;\n height: 24px;\n min-width: 24px;\n min-height: 24px;\n }\n\n /* Save/Load buttons need room for icon + text */\n .playbar-btn.save-tape-btn,\n .playbar-btn.load-tape-btn {\n width: auto;\n padding: 0 6px;\n gap: 4px;\n }\n}\n\n/* Mobile-first: hide button text labels, show only icons */\n.btn-label {\n display: none;\n}\n\n/* Desktop: show button text labels */\n@media (min-width: 769px) {\n .btn-label {\n display: inline;\n }\n}\n\n.playbar-btn:hover {\n background: #333;\n color: #fff;\n}\n\n.playbar-btn:hover .tooltip {\n opacity: 1;\n visibility: visible;\n}\n\n.tooltip {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: #222;\n color: #ccc;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 10px;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s;\n pointer-events: none;\n z-index: 10;\n}\n\n.tooltip-left {\n left: 0;\n transform: none;\n}\n\n.tooltip kbd {\n background: #444;\n padding: 1px 4px;\n border-radius: 2px;\n margin-left: 4px;\n font-family: monospace;\n}\n\n.seek-bar {\n flex: 1;\n /* Mobile-first: larger seek bar */\n height: 32px;\n background: #222;\n border-radius: 4px;\n position: relative;\n cursor: pointer;\n overflow: hidden;\n}\n\n/* Desktop: smaller seek bar */\n@media (min-width: 769px) {\n .seek-bar {\n height: 16px;\n }\n}\n\n.seek-bar-fill {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n background: linear-gradient(to right, #4a2070, #7b3fa0);\n border-radius: 4px;\n transition: width 0.1s ease-out;\n}\n\n.seek-bar-position {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: #fff;\n}\n\n.letterboxed-game {\n grid-area: game;\n overflow: hidden;\n}\n\n.letterboxed-game .canvas-container {\n width: 100%;\n height: 100%;\n}\n\n.letterboxed-game canvas {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n.letterboxed-game {\n position: relative;\n}\n\n.letterboxed-game.hmr-flash::after {\n content: \"\";\n position: absolute;\n inset: 0;\n pointer-events: none;\n animation: hmr-pulse 0.3s ease-out forwards;\n}\n\n@keyframes hmr-pulse {\n 0% { box-shadow: inset 0 0 0 36px #7b3fa0; }\n 100% { box-shadow: inset 0 0 0 0 #7b3fa0; }\n}\n\n.game {\n grid-area: game;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.stats {\n grid-area: stats;\n background-color: #f0f0f0;\n padding: 1rem;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.logs {\n grid-area: logs;\n background-color: #f0f0f0;\n padding: 1rem;\n border-radius: 8px;\n overflow: hidden;\n}\n\n/* Canvas container */\n.canvas-container {\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.canvas-container canvas {\n max-width: 100%;\n max-height: 100%;\n}\n\n/* Debug toggle button */\n.debug-toggle {\n position: fixed;\n bottom: 16px;\n right: 16px;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background-color: rgba(0, 0, 0, 0.5);\n color: white;\n font-size: 18px;\n cursor: pointer;\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background-color 0.2s;\n}\n\n.debug-toggle:hover {\n background-color: rgba(0, 0, 0, 0.7);\n}\n\n/* Stats panel */\n.stats-panel {\n background: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 12px;\n border-radius: 8px;\n font-family: monospace;\n font-size: 14px;\n max-width: 100%;\n overflow: hidden;\n}\n\n.stats-panel h3 {\n margin: 0 0 8px 0;\n font-size: 14px;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.stats-panel table {\n width: 100%;\n border-collapse: collapse;\n table-layout: fixed;\n}\n\n.stats-panel tr {\n border-bottom: 1px solid rgba(255, 255, 255, 0.2);\n}\n\n.stats-panel tr:last-child {\n border-bottom: none;\n}\n\n.stats-panel td {\n padding: 4px 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.stats-panel td:first-child {\n opacity: 0.7;\n width: 60%;\n}\n\n.stats-panel td:last-child {\n text-align: right;\n font-weight: 600;\n width: 40%;\n}\n\n.stats-panel p {\n margin: 0;\n opacity: 0.7;\n}\n\n/* Logs panel */\n.logs-list {\n width: 100%;\n height: 100%;\n overflow: auto;\n margin: 0;\n padding: 0;\n}\n\n.logs-list li {\n margin: 0 0 24px 0;\n list-style: none;\n}\n\n.logs-list h3 {\n font-size: 16px;\n font-weight: 500;\n margin: 0;\n}\n\n.logs-list .ws {\n color: darkolivegreen;\n}\n\n.logs-list .webrtc {\n color: darkmagenta;\n}\n\n.logs-list .rollback {\n color: darkblue;\n}\n\n.logs-list .local {\n color: #333;\n}\n\n.logs-list .content {\n font-size: 16px;\n}\n\n.logs-list p {\n margin: 4px 0;\n}\n\n.logs-list pre {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n background-color: oldlace;\n padding: 8px;\n border-radius: 4px;\n border: 1px inset lavender;\n}\n\n/* Load Tape Dialog */\n.load-tape-dialog {\n background: #1a1a1a;\n border: 1px solid #333;\n border-radius: 8px;\n padding: 0;\n color: #ccc;\n font-family: monospace;\n max-width: 320px;\n width: 90vw;\n}\n\n.load-tape-dialog::backdrop {\n background: rgba(0, 0, 0, 0.7);\n}\n\n.load-tape-dialog-content {\n padding: 16px;\n}\n\n.load-tape-dialog h3 {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #fff;\n}\n\n.drop-zone {\n border: 2px dashed #444;\n border-radius: 8px;\n padding: 32px 16px;\n text-align: center;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n}\n\n.drop-zone:hover {\n border-color: #666;\n background: #222;\n}\n\n.drop-zone.drag-over {\n border-color: #7b3fa0;\n background: rgba(123, 63, 160, 0.1);\n}\n\n.drop-zone-text {\n color: #888;\n font-size: 12px;\n line-height: 1.5;\n}\n\n.hidden-file-input {\n display: none;\n}\n\n.replay-last-btn {\n width: 100%;\n margin-top: 12px;\n padding: 8px 12px;\n background: #333;\n border: none;\n border-radius: 4px;\n color: #ccc;\n font-family: monospace;\n font-size: 12px;\n cursor: pointer;\n transition: background 0.15s;\n text-align: left;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.replay-last-btn:hover {\n background: #444;\n color: #fff;\n}\n\n.load-tape-btn {\n margin-left: 4px;\n}\n";
|
|
1
|
+
export declare const styles = "\n/* Reset for shadow DOM */\n* {\n box-sizing: border-box;\n}\n\n/* Mobile-first CSS variables */\n:host {\n --bar-size: 10vw;\n --bar-size-h: 10vh;\n --bar-size-h: 10dvh;\n}\n\n/* Desktop overrides */\n@media (min-width: 769px) {\n :host {\n --bar-size: 2vw;\n --bar-size-h: 2vh;\n }\n}\n\n/* Layout */\n.fullscreen {\n width: 100vw;\n height: 100vh;\n height: 100dvh;\n margin: 0;\n padding: 0;\n overflow: hidden;\n}\n\n.fullscreen .canvas-container {\n width: 100%;\n height: 100%;\n}\n\n.fullscreen canvas {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* Mobile-first: vertical scroll layout */\n.layout {\n /* Use fixed position on mobile to escape parent overflow:hidden */\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n overscroll-behavior-y: contain;\n padding: 0;\n gap: 0;\n background: #1a1a1a;\n}\n\n.layout .game {\n /* Use dvh with vh fallback for mobile Safari address bar */\n height: 100vh;\n height: 100dvh;\n width: 100%;\n flex-shrink: 0;\n /* Mobile: no border radius, fullscreen game */\n border-radius: 0;\n}\n\n/* Mobile: stretch canvas to fill game area */\n.layout .game .canvas-container {\n width: 100%;\n height: 100%;\n}\n\n.layout .game .canvas-container canvas {\n width: 100%;\n height: 100%;\n max-width: none;\n max-height: none;\n display: block;\n}\n\n.layout .stats,\n.layout .logs {\n width: 100%;\n min-height: 50vh;\n min-height: 50dvh;\n padding: 1rem;\n flex-shrink: 0;\n}\n\n/* Desktop: 2x2 grid layout */\n@media (min-width: 769px) {\n .layout {\n position: static;\n display: grid;\n grid-template-areas:\n \"game stats\"\n \"logs logs\";\n grid-template-columns: calc(50% - 0.5rem) calc(50% - 0.5rem);\n grid-template-rows: calc(50% - 0.5rem) calc(50% - 0.5rem);\n gap: 1rem;\n padding: 1rem;\n height: 100%;\n overflow: hidden;\n -webkit-overflow-scrolling: auto;\n overscroll-behavior-y: auto;\n }\n\n .layout .game {\n height: auto;\n flex-shrink: initial;\n border-radius: 8px;\n }\n\n /* Desktop: restore centered canvas with constraints */\n .layout .game .canvas-container canvas {\n width: auto;\n height: auto;\n max-width: 100%;\n max-height: 100%;\n }\n\n .layout .stats,\n .layout .logs {\n min-height: auto;\n padding: 1rem;\n flex-shrink: initial;\n }\n}\n\n/* Letterboxed layout - using equal vw/vh percentages keeps game at viewport aspect ratio */\n.layout-letterboxed {\n display: grid;\n grid-template-areas:\n \"top-bar top-bar top-bar\"\n \"left-bar game right-bar\"\n \"bottom-bar bottom-bar bottom-bar\";\n grid-template-columns: var(--bar-size) 1fr var(--bar-size);\n grid-template-rows: var(--bar-size-h) 1fr var(--bar-size-h);\n width: 100vw;\n /* Use dvh with vh fallback for mobile Safari address bar */\n height: 100vh;\n height: 100dvh;\n background: #1a1a1a;\n overflow: hidden;\n overscroll-behavior: none;\n}\n\n.top-bar {\n grid-area: top-bar;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: #111;\n color: #aaa;\n font-family: monospace;\n font-size: 12px;\n padding: 0;\n user-select: none;\n}\n\n.top-bar-side-label {\n width: var(--bar-size);\n text-align: center;\n font-size: 9px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #666;\n}\n\n/* Mobile: larger top bar text */\n@media (max-width: 768px) {\n .top-bar-side-label {\n font-size: 12px;\n }\n\n .top-bar {\n font-size: 14px;\n }\n}\n\n.top-bar-center {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 24px;\n flex: 1;\n}\n\n.top-bar-item {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.top-bar-label {\n opacity: 0.6;\n}\n\n.top-bar-value {\n color: #fff;\n font-weight: 500;\n}\n\n.left-bar {\n grid-area: left-bar;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n background: #111;\n padding: 4px 0;\n user-select: none;\n}\n\n.right-bar {\n grid-area: right-bar;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n background: #111;\n padding: 4px 0;\n user-select: none;\n}\n\n.vertical-bar {\n width: 12px;\n flex: 1;\n background: #333;\n border-radius: 2px;\n position: relative;\n}\n\n.vertical-bar-fill {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: #4a9eff;\n border-radius: 2px;\n transition: height 0.1s ease-out;\n}\n\n.vertical-bar-popover {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n background: #222;\n color: #ccc;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 10px;\n font-family: monospace;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s;\n pointer-events: none;\n z-index: 10;\n}\n\n.vertical-bar-popover.left {\n left: calc(100% + 8px);\n}\n\n.vertical-bar-popover.right {\n right: calc(100% + 8px);\n}\n\n.vertical-bar:hover .vertical-bar-popover {\n opacity: 1;\n visibility: visible;\n}\n\n\n.bottom-bar {\n grid-area: bottom-bar;\n display: flex;\n align-items: center;\n background: #111;\n /* Mobile-first: more padding */\n padding: 0 16px;\n gap: 12px;\n user-select: none;\n}\n\n/* Desktop: tighter padding */\n@media (min-width: 769px) {\n .bottom-bar {\n padding: 0 8px;\n gap: 8px;\n }\n}\n\n.playbar-controls {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n}\n\n/* Record button */\n.record-btn {\n color: #666;\n}\n\n.record-btn.recording {\n color: #ff4444;\n}\n\n.record-btn.recording svg {\n animation: recording-pulse 1s ease-in-out infinite;\n}\n\n@keyframes recording-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n}\n\n/* Desktop: show REC label when recording */\n@media (min-width: 769px) {\n .record-btn.recording {\n width: auto;\n padding: 0 6px;\n gap: 4px;\n background: rgba(255, 68, 68, 0.15);\n border-radius: 3px;\n }\n}\n\n/* Replay indicator - mobile: hidden */\n.replay-indicator {\n display: none;\n}\n\n/* Desktop: full indicators with text */\n@media (min-width: 769px) {\n .recording-indicator {\n gap: 4px;\n padding: 2px 6px;\n background: rgba(255, 0, 0, 0.2);\n border: 1px solid #ff4444;\n border-radius: 3px;\n }\n\n .recording-indicator .recording-label {\n display: inline;\n color: #ff4444;\n font-size: 10px;\n font-weight: bold;\n font-family: monospace;\n }\n\n .recording-dot {\n width: 8px;\n height: 8px;\n }\n\n .replay-indicator {\n display: flex;\n align-items: center;\n padding: 2px 6px;\n background: rgba(100, 100, 255, 0.2);\n border: 1px solid #6666ff;\n border-radius: 3px;\n color: #6666ff;\n font-size: 10px;\n font-weight: bold;\n font-family: monospace;\n margin-right: 4px;\n }\n}\n\n/* Mobile-first: hide step/jump buttons */\n.playbar-btn.jump-back,\n.playbar-btn.step-back,\n.playbar-btn.step-forward,\n.playbar-btn.jump-forward {\n display: none;\n}\n\n/* Desktop: show all controls */\n@media (min-width: 769px) {\n .playbar-btn.jump-back,\n .playbar-btn.step-back,\n .playbar-btn.step-forward,\n .playbar-btn.jump-forward {\n display: flex;\n }\n}\n\n.playbar-btn {\n /* Mobile-first: larger buttons */\n width: 4vh;\n height: 4vh;\n min-width: 32px;\n min-height: 32px;\n border: none;\n outline: none;\n background: transparent;\n color: #888;\n font-size: 16px;\n cursor: pointer;\n border-radius: 2px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.15s, color 0.15s;\n position: relative;\n}\n\n/* Desktop: sized to match indicators */\n@media (min-width: 769px) {\n .playbar-btn {\n width: 24px;\n height: 24px;\n min-width: 24px;\n min-height: 24px;\n }\n\n /* Save/Load buttons need room for icon + text */\n .playbar-btn.save-tape-btn,\n .playbar-btn.load-tape-btn {\n width: auto;\n padding: 0 6px;\n gap: 4px;\n }\n}\n\n/* Mobile-first: hide button text labels, show only icons */\n.btn-label {\n display: none;\n}\n\n/* Desktop: show button text labels */\n@media (min-width: 769px) {\n .btn-label {\n display: inline;\n }\n}\n\n.playbar-btn:hover {\n background: #333;\n color: #fff;\n}\n\n.playbar-btn:hover .tooltip {\n opacity: 1;\n visibility: visible;\n}\n\n.tooltip {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: #222;\n color: #ccc;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 10px;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s;\n pointer-events: none;\n z-index: 10;\n}\n\n.tooltip-left {\n left: 0;\n transform: none;\n}\n\n.tooltip kbd {\n background: #444;\n padding: 1px 4px;\n border-radius: 2px;\n margin-left: 4px;\n font-family: monospace;\n}\n\n.seek-bar {\n flex: 1;\n /* Mobile-first: larger seek bar */\n height: 32px;\n background: #222;\n border-radius: 4px;\n position: relative;\n cursor: pointer;\n overflow: hidden;\n user-select: none;\n}\n\n/* Desktop: smaller seek bar */\n@media (min-width: 769px) {\n .seek-bar {\n height: 16px;\n }\n}\n\n.seek-bar-fill {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n background: linear-gradient(to right, #4a2070, #7b3fa0);\n border-radius: 4px;\n transition: width 0.1s ease-out;\n}\n\n.seek-bar-position {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: #fff;\n}\n\n.letterboxed-game {\n grid-area: game;\n overflow: hidden;\n}\n\n.letterboxed-game .canvas-container {\n width: 100%;\n height: 100%;\n}\n\n.letterboxed-game canvas {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n.letterboxed-game {\n position: relative;\n}\n\n.letterboxed-game.hmr-flash::after {\n content: \"\";\n position: absolute;\n inset: 0;\n pointer-events: none;\n animation: hmr-pulse 0.3s ease-out forwards;\n}\n\n@keyframes hmr-pulse {\n 0% { box-shadow: inset 0 0 0 36px #7b3fa0; }\n 100% { box-shadow: inset 0 0 0 0 #7b3fa0; }\n}\n\n.game {\n grid-area: game;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.stats {\n grid-area: stats;\n background-color: #f0f0f0;\n padding: 1rem;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.logs {\n grid-area: logs;\n background-color: #f0f0f0;\n padding: 1rem;\n border-radius: 8px;\n overflow: hidden;\n}\n\n/* Canvas container */\n.canvas-container {\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.canvas-container canvas {\n max-width: 100%;\n max-height: 100%;\n}\n\n/* Debug toggle button */\n.debug-toggle {\n position: fixed;\n bottom: 16px;\n right: 16px;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background-color: rgba(0, 0, 0, 0.5);\n color: white;\n font-size: 18px;\n cursor: pointer;\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background-color 0.2s;\n}\n\n.debug-toggle:hover {\n background-color: rgba(0, 0, 0, 0.7);\n}\n\n/* Stats panel */\n.stats-panel {\n background: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 12px;\n border-radius: 8px;\n font-family: monospace;\n font-size: 14px;\n max-width: 100%;\n overflow: hidden;\n}\n\n.stats-panel h3 {\n margin: 0 0 8px 0;\n font-size: 14px;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.stats-panel table {\n width: 100%;\n border-collapse: collapse;\n table-layout: fixed;\n}\n\n.stats-panel tr {\n border-bottom: 1px solid rgba(255, 255, 255, 0.2);\n}\n\n.stats-panel tr:last-child {\n border-bottom: none;\n}\n\n.stats-panel td {\n padding: 4px 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.stats-panel td:first-child {\n opacity: 0.7;\n width: 60%;\n}\n\n.stats-panel td:last-child {\n text-align: right;\n font-weight: 600;\n width: 40%;\n}\n\n.stats-panel p {\n margin: 0;\n opacity: 0.7;\n}\n\n/* Logs panel */\n.logs-list {\n width: 100%;\n height: 100%;\n overflow: auto;\n margin: 0;\n padding: 0;\n}\n\n.logs-list li {\n margin: 0 0 24px 0;\n list-style: none;\n}\n\n.logs-list h3 {\n font-size: 16px;\n font-weight: 500;\n margin: 0;\n}\n\n.logs-list .ws {\n color: darkolivegreen;\n}\n\n.logs-list .webrtc {\n color: darkmagenta;\n}\n\n.logs-list .rollback {\n color: darkblue;\n}\n\n.logs-list .local {\n color: #333;\n}\n\n.logs-list .content {\n font-size: 16px;\n}\n\n.logs-list p {\n margin: 4px 0;\n}\n\n.logs-list pre {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n background-color: oldlace;\n padding: 8px;\n border-radius: 4px;\n border: 1px inset lavender;\n}\n\n/* Load Tape Dialog */\n.load-tape-dialog {\n background: #1a1a1a;\n border: 1px solid #333;\n border-radius: 8px;\n padding: 0;\n color: #ccc;\n font-family: monospace;\n max-width: 320px;\n width: 90vw;\n}\n\n.load-tape-dialog::backdrop {\n background: rgba(0, 0, 0, 0.7);\n}\n\n.load-tape-dialog-content {\n padding: 16px;\n}\n\n.load-tape-dialog h3 {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #fff;\n}\n\n.drop-zone {\n border: 2px dashed #444;\n border-radius: 8px;\n padding: 32px 16px;\n text-align: center;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n}\n\n.drop-zone:hover {\n border-color: #666;\n background: #222;\n}\n\n.drop-zone.drag-over {\n border-color: #7b3fa0;\n background: rgba(123, 63, 160, 0.1);\n}\n\n.drop-zone-text {\n color: #888;\n font-size: 12px;\n line-height: 1.5;\n}\n\n.hidden-file-input {\n display: none;\n}\n\n.replay-last-btn {\n width: 100%;\n margin-top: 12px;\n padding: 8px 12px;\n background: #333;\n border: none;\n border-radius: 4px;\n color: #ccc;\n font-family: monospace;\n font-size: 12px;\n cursor: pointer;\n transition: background 0.15s;\n text-align: left;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.replay-last-btn:hover {\n background: #444;\n color: #fff;\n}\n\n.load-tape-btn {\n margin-left: 4px;\n}\n";
|
|
2
2
|
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/debugui/styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/debugui/styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,klcA2yBlB,CAAC"}
|
package/dist/mod.js
CHANGED
|
@@ -1450,7 +1450,7 @@ function readTapeHeader(tape) {
|
|
|
1450
1450
|
eventCount: view.getUint16(14, true)
|
|
1451
1451
|
};
|
|
1452
1452
|
}
|
|
1453
|
-
var DEFAULT_WASM_URL = new URL("https://unpkg.com/@bloopjs/engine@0.0.
|
|
1453
|
+
var DEFAULT_WASM_URL = new URL("https://unpkg.com/@bloopjs/engine@0.0.103/wasm/bloop.wasm");
|
|
1454
1454
|
var MAX_ROLLBACK_FRAMES = 500;
|
|
1455
1455
|
var TIME_CTX_OFFSET = 0;
|
|
1456
1456
|
var INPUT_CTX_OFFSET = TIME_CTX_OFFSET + 4;
|
|
@@ -1556,6 +1556,9 @@ class Sim {
|
|
|
1556
1556
|
throw new Error(`failed to start recording, error code=${result}`);
|
|
1557
1557
|
}
|
|
1558
1558
|
}
|
|
1559
|
+
stopRecording() {
|
|
1560
|
+
this.wasm.stop_recording();
|
|
1561
|
+
}
|
|
1559
1562
|
saveTape() {
|
|
1560
1563
|
const tapeLen = this.wasm.get_tape_len();
|
|
1561
1564
|
const tapePtr = this.wasm.get_tape_ptr();
|
|
@@ -3321,7 +3324,7 @@ function readTapeHeader2(tape) {
|
|
|
3321
3324
|
eventCount: view.getUint16(14, true)
|
|
3322
3325
|
};
|
|
3323
3326
|
}
|
|
3324
|
-
var DEFAULT_WASM_URL2 = new URL("https://unpkg.com/@bloopjs/engine@0.0.
|
|
3327
|
+
var DEFAULT_WASM_URL2 = new URL("https://unpkg.com/@bloopjs/engine@0.0.103/wasm/bloop.wasm");
|
|
3325
3328
|
var TIME_CTX_OFFSET2 = 0;
|
|
3326
3329
|
var INPUT_CTX_OFFSET2 = TIME_CTX_OFFSET2 + 4;
|
|
3327
3330
|
var EVENTS_OFFSET2 = INPUT_CTX_OFFSET2 + 4;
|
|
@@ -4444,9 +4447,12 @@ var onJumpForward = d3(null);
|
|
|
4444
4447
|
var onSeek = d3(null);
|
|
4445
4448
|
var onLoadTape = d3(null);
|
|
4446
4449
|
var onReplayLastTape = d3(null);
|
|
4450
|
+
var onReplayLastSaved = d3(null);
|
|
4447
4451
|
var onSaveTape = d3(null);
|
|
4448
4452
|
var lastTapeName = d3(null);
|
|
4453
|
+
var lastSavedTapeName = d3(null);
|
|
4449
4454
|
var isLoadDialogOpen = d3(false);
|
|
4455
|
+
var onToggleRecording = d3(null);
|
|
4450
4456
|
var debugState = {
|
|
4451
4457
|
layoutMode,
|
|
4452
4458
|
isVisible: w3(() => layoutMode.value !== "off"),
|
|
@@ -4477,9 +4483,12 @@ var debugState = {
|
|
|
4477
4483
|
onSeek,
|
|
4478
4484
|
onLoadTape,
|
|
4479
4485
|
onReplayLastTape,
|
|
4486
|
+
onReplayLastSaved,
|
|
4480
4487
|
onSaveTape,
|
|
4481
4488
|
lastTapeName,
|
|
4482
|
-
|
|
4489
|
+
lastSavedTapeName,
|
|
4490
|
+
isLoadDialogOpen,
|
|
4491
|
+
onToggleRecording
|
|
4483
4492
|
};
|
|
4484
4493
|
function cycleLayout() {
|
|
4485
4494
|
const current = layoutMode.value;
|
|
@@ -4615,12 +4624,20 @@ function wirePlaybarHandlers(app) {
|
|
|
4615
4624
|
};
|
|
4616
4625
|
debugState.onSeek.value = (ratio) => {
|
|
4617
4626
|
if (app.sim.hasHistory) {
|
|
4627
|
+
app.sim.pause();
|
|
4618
4628
|
const startFrame = debugState.tapeStartFrame.value;
|
|
4619
4629
|
const frameCount = debugState.tapeFrameCount.value;
|
|
4620
4630
|
const targetFrame = startFrame + Math.floor(ratio * frameCount);
|
|
4621
4631
|
app.sim.seek(targetFrame);
|
|
4622
4632
|
}
|
|
4623
4633
|
};
|
|
4634
|
+
debugState.onToggleRecording.value = () => {
|
|
4635
|
+
if (app.sim.isRecording) {
|
|
4636
|
+
app.sim.stopRecording();
|
|
4637
|
+
} else {
|
|
4638
|
+
app.sim.record();
|
|
4639
|
+
}
|
|
4640
|
+
};
|
|
4624
4641
|
}
|
|
4625
4642
|
function wireTapeDragDrop(canvas, app) {
|
|
4626
4643
|
canvas.addEventListener("dragover", (e4) => {
|
|
@@ -4639,7 +4656,8 @@ function wireTapeDragDrop(canvas, app) {
|
|
|
4639
4656
|
}
|
|
4640
4657
|
var TAPE_DB_NAME = "bloop-debug";
|
|
4641
4658
|
var TAPE_STORE_NAME = "tapes";
|
|
4642
|
-
var
|
|
4659
|
+
var TAPE_KEY_LOADED = "last-loaded";
|
|
4660
|
+
var TAPE_KEY_SAVED = "last-saved";
|
|
4643
4661
|
function openTapeDB() {
|
|
4644
4662
|
return new Promise((resolve, reject) => {
|
|
4645
4663
|
const request = indexedDB.open(TAPE_DB_NAME, 1);
|
|
@@ -4650,21 +4668,21 @@ function openTapeDB() {
|
|
|
4650
4668
|
};
|
|
4651
4669
|
});
|
|
4652
4670
|
}
|
|
4653
|
-
async function saveTapeToStorage(bytes, fileName) {
|
|
4671
|
+
async function saveTapeToStorage(bytes, fileName, key = TAPE_KEY_LOADED) {
|
|
4654
4672
|
const db = await openTapeDB();
|
|
4655
4673
|
return new Promise((resolve, reject) => {
|
|
4656
4674
|
const tx = db.transaction(TAPE_STORE_NAME, "readwrite");
|
|
4657
|
-
tx.objectStore(TAPE_STORE_NAME).put({ bytes, fileName },
|
|
4675
|
+
tx.objectStore(TAPE_STORE_NAME).put({ bytes, fileName }, key);
|
|
4658
4676
|
tx.oncomplete = () => resolve();
|
|
4659
4677
|
tx.onerror = () => reject(tx.error);
|
|
4660
4678
|
});
|
|
4661
4679
|
}
|
|
4662
|
-
async function loadTapeFromStorage() {
|
|
4680
|
+
async function loadTapeFromStorage(key = TAPE_KEY_LOADED) {
|
|
4663
4681
|
try {
|
|
4664
4682
|
const db = await openTapeDB();
|
|
4665
4683
|
return new Promise((resolve, reject) => {
|
|
4666
4684
|
const tx = db.transaction(TAPE_STORE_NAME, "readonly");
|
|
4667
|
-
const request = tx.objectStore(TAPE_STORE_NAME).get(
|
|
4685
|
+
const request = tx.objectStore(TAPE_STORE_NAME).get(key);
|
|
4668
4686
|
request.onsuccess = () => resolve(request.result ?? null);
|
|
4669
4687
|
request.onerror = () => reject(request.error);
|
|
4670
4688
|
});
|
|
@@ -4673,32 +4691,46 @@ async function loadTapeFromStorage() {
|
|
|
4673
4691
|
}
|
|
4674
4692
|
}
|
|
4675
4693
|
async function checkForSavedTape() {
|
|
4676
|
-
const saved = await
|
|
4677
|
-
|
|
4694
|
+
const [loaded, saved] = await Promise.all([
|
|
4695
|
+
loadTapeFromStorage(TAPE_KEY_LOADED),
|
|
4696
|
+
loadTapeFromStorage(TAPE_KEY_SAVED)
|
|
4697
|
+
]);
|
|
4698
|
+
debugState.lastTapeName.value = loaded?.fileName ?? null;
|
|
4699
|
+
debugState.lastSavedTapeName.value = saved?.fileName ?? null;
|
|
4678
4700
|
}
|
|
4679
4701
|
function wireTapeLoadHandlers(app) {
|
|
4680
4702
|
debugState.onLoadTape.value = async (bytes, fileName) => {
|
|
4681
4703
|
app.loadTape(bytes);
|
|
4682
|
-
await saveTapeToStorage(bytes, fileName);
|
|
4704
|
+
await saveTapeToStorage(bytes, fileName, TAPE_KEY_LOADED);
|
|
4683
4705
|
debugState.lastTapeName.value = fileName;
|
|
4684
4706
|
debugState.isLoadDialogOpen.value = false;
|
|
4685
4707
|
};
|
|
4686
4708
|
debugState.onReplayLastTape.value = async () => {
|
|
4687
|
-
const saved = await loadTapeFromStorage();
|
|
4709
|
+
const saved = await loadTapeFromStorage(TAPE_KEY_LOADED);
|
|
4710
|
+
if (saved) {
|
|
4711
|
+
app.loadTape(saved.bytes);
|
|
4712
|
+
debugState.isLoadDialogOpen.value = false;
|
|
4713
|
+
}
|
|
4714
|
+
};
|
|
4715
|
+
debugState.onReplayLastSaved.value = async () => {
|
|
4716
|
+
const saved = await loadTapeFromStorage(TAPE_KEY_SAVED);
|
|
4688
4717
|
if (saved) {
|
|
4689
4718
|
app.loadTape(saved.bytes);
|
|
4690
4719
|
debugState.isLoadDialogOpen.value = false;
|
|
4691
4720
|
}
|
|
4692
4721
|
};
|
|
4693
|
-
debugState.onSaveTape.value = () => {
|
|
4722
|
+
debugState.onSaveTape.value = async () => {
|
|
4694
4723
|
if (!app.sim.hasHistory)
|
|
4695
4724
|
return;
|
|
4696
4725
|
const tape = app.sim.saveTape();
|
|
4726
|
+
const fileName = `tape-${Date.now()}.bloop`;
|
|
4727
|
+
await saveTapeToStorage(tape, fileName, TAPE_KEY_SAVED);
|
|
4728
|
+
debugState.lastSavedTapeName.value = fileName;
|
|
4697
4729
|
const blob = new Blob([tape], { type: "application/octet-stream" });
|
|
4698
4730
|
const url = URL.createObjectURL(blob);
|
|
4699
4731
|
const a4 = document.createElement("a");
|
|
4700
4732
|
a4.href = url;
|
|
4701
|
-
a4.download =
|
|
4733
|
+
a4.download = fileName;
|
|
4702
4734
|
a4.click();
|
|
4703
4735
|
URL.revokeObjectURL(url);
|
|
4704
4736
|
};
|
|
@@ -4982,8 +5014,14 @@ function TopBar({ leftLabel, rightLabel }) {
|
|
|
4982
5014
|
const frameNumber2 = debugState.frameNumber.value;
|
|
4983
5015
|
const rtt = debugState.netStatus.value.rtt;
|
|
4984
5016
|
const isOnline = debugState.netStatus.value.peers.length > 0;
|
|
5017
|
+
const stopPropagation = q2((e4) => {
|
|
5018
|
+
e4.stopPropagation();
|
|
5019
|
+
}, []);
|
|
4985
5020
|
return /* @__PURE__ */ u4("div", {
|
|
4986
5021
|
className: "top-bar",
|
|
5022
|
+
onMouseDown: stopPropagation,
|
|
5023
|
+
onMouseUp: stopPropagation,
|
|
5024
|
+
onClick: stopPropagation,
|
|
4987
5025
|
children: [
|
|
4988
5026
|
/* @__PURE__ */ u4("span", {
|
|
4989
5027
|
className: "top-bar-side-label",
|
|
@@ -5049,18 +5087,31 @@ function VerticalBar({
|
|
|
5049
5087
|
value,
|
|
5050
5088
|
max,
|
|
5051
5089
|
side,
|
|
5052
|
-
color = "#4a9eff"
|
|
5090
|
+
color = "#4a9eff",
|
|
5091
|
+
displayValue
|
|
5053
5092
|
}) {
|
|
5054
5093
|
const percentage = max > 0 ? Math.min(100, value / max * 100) : 0;
|
|
5094
|
+
const stopPropagation = q2((e4) => {
|
|
5095
|
+
e4.stopPropagation();
|
|
5096
|
+
}, []);
|
|
5055
5097
|
return /* @__PURE__ */ u4("div", {
|
|
5056
5098
|
className: `${side}-bar`,
|
|
5099
|
+
onMouseDown: stopPropagation,
|
|
5100
|
+
onMouseUp: stopPropagation,
|
|
5101
|
+
onClick: stopPropagation,
|
|
5057
5102
|
children: /* @__PURE__ */ u4("div", {
|
|
5058
5103
|
className: "vertical-bar",
|
|
5059
|
-
children:
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5104
|
+
children: [
|
|
5105
|
+
/* @__PURE__ */ u4("div", {
|
|
5106
|
+
className: "vertical-bar-fill",
|
|
5107
|
+
style: { height: `${percentage}%`, background: color }
|
|
5108
|
+
}, undefined, false, undefined, this),
|
|
5109
|
+
displayValue && /* @__PURE__ */ u4("span", {
|
|
5110
|
+
className: `vertical-bar-popover ${side}`,
|
|
5111
|
+
children: displayValue
|
|
5112
|
+
}, undefined, false, undefined, this)
|
|
5113
|
+
]
|
|
5114
|
+
}, undefined, true, undefined, this)
|
|
5064
5115
|
}, undefined, false, undefined, this);
|
|
5065
5116
|
}
|
|
5066
5117
|
|
|
@@ -5070,7 +5121,6 @@ function LoadTapeDialog() {
|
|
|
5070
5121
|
const fileInputRef = A2(null);
|
|
5071
5122
|
const [isDragOver, setIsDragOver] = d2(false);
|
|
5072
5123
|
const isOpen = debugState.isLoadDialogOpen.value;
|
|
5073
|
-
const lastTapeName2 = debugState.lastTapeName.value;
|
|
5074
5124
|
y2(() => {
|
|
5075
5125
|
const dialog = dialogRef.current;
|
|
5076
5126
|
if (!dialog)
|
|
@@ -5121,11 +5171,20 @@ function LoadTapeDialog() {
|
|
|
5121
5171
|
const handleReplayLast = q2(() => {
|
|
5122
5172
|
debugState.onReplayLastTape.value?.();
|
|
5123
5173
|
}, []);
|
|
5174
|
+
const handleReplayLastSaved = q2(() => {
|
|
5175
|
+
debugState.onReplayLastSaved.value?.();
|
|
5176
|
+
}, []);
|
|
5177
|
+
const handleDialogClick = q2((e4) => {
|
|
5178
|
+
if (e4.target === e4.currentTarget) {
|
|
5179
|
+
debugState.isLoadDialogOpen.value = false;
|
|
5180
|
+
}
|
|
5181
|
+
}, []);
|
|
5124
5182
|
return /* @__PURE__ */ u4("dialog", {
|
|
5125
5183
|
ref: dialogRef,
|
|
5126
5184
|
className: "load-tape-dialog",
|
|
5127
5185
|
onClose: handleClose,
|
|
5128
|
-
|
|
5186
|
+
onClick: handleDialogClick,
|
|
5187
|
+
children: isOpen && /* @__PURE__ */ u4("div", {
|
|
5129
5188
|
className: "load-tape-dialog-content",
|
|
5130
5189
|
children: [
|
|
5131
5190
|
/* @__PURE__ */ u4("h3", {
|
|
@@ -5153,12 +5212,17 @@ function LoadTapeDialog() {
|
|
|
5153
5212
|
className: "hidden-file-input",
|
|
5154
5213
|
onChange: handleFileInputChange
|
|
5155
5214
|
}, undefined, false, undefined, this),
|
|
5156
|
-
|
|
5215
|
+
debugState.lastSavedTapeName.value && /* @__PURE__ */ u4("button", {
|
|
5216
|
+
className: "replay-last-btn",
|
|
5217
|
+
onClick: handleReplayLastSaved,
|
|
5218
|
+
children: "Replay last saved tape"
|
|
5219
|
+
}, undefined, false, undefined, this),
|
|
5220
|
+
debugState.lastTapeName.value && /* @__PURE__ */ u4("button", {
|
|
5157
5221
|
className: "replay-last-btn",
|
|
5158
5222
|
onClick: handleReplayLast,
|
|
5159
5223
|
children: [
|
|
5160
|
-
"Replay last: ",
|
|
5161
|
-
|
|
5224
|
+
"Replay last loaded: ",
|
|
5225
|
+
debugState.lastTapeName.value
|
|
5162
5226
|
]
|
|
5163
5227
|
}, undefined, true, undefined, this)
|
|
5164
5228
|
]
|
|
@@ -5169,6 +5233,14 @@ function LoadTapeDialog() {
|
|
|
5169
5233
|
// src/debugui/components/BottomBar.tsx
|
|
5170
5234
|
var iconProps = { width: 14, height: 14, viewBox: "0 0 24 24", fill: "currentColor" };
|
|
5171
5235
|
var Icons = {
|
|
5236
|
+
record: /* @__PURE__ */ u4("svg", {
|
|
5237
|
+
...iconProps,
|
|
5238
|
+
children: /* @__PURE__ */ u4("circle", {
|
|
5239
|
+
cx: "12",
|
|
5240
|
+
cy: "12",
|
|
5241
|
+
r: "8"
|
|
5242
|
+
}, undefined, false, undefined, this)
|
|
5243
|
+
}, undefined, false, undefined, this),
|
|
5172
5244
|
jumpBack: /* @__PURE__ */ u4("svg", {
|
|
5173
5245
|
...iconProps,
|
|
5174
5246
|
children: /* @__PURE__ */ u4("path", {
|
|
@@ -5311,22 +5383,33 @@ function BottomBar() {
|
|
|
5311
5383
|
const handleSaveTapeClick = q2(() => {
|
|
5312
5384
|
debugState.onSaveTape.value?.();
|
|
5313
5385
|
}, []);
|
|
5386
|
+
const handleToggleRecording = q2(() => {
|
|
5387
|
+
debugState.onToggleRecording.value?.();
|
|
5388
|
+
}, []);
|
|
5389
|
+
const stopPropagation = q2((e4) => {
|
|
5390
|
+
e4.stopPropagation();
|
|
5391
|
+
}, []);
|
|
5314
5392
|
return /* @__PURE__ */ u4("div", {
|
|
5315
5393
|
className: "bottom-bar",
|
|
5394
|
+
onMouseDown: stopPropagation,
|
|
5395
|
+
onMouseUp: stopPropagation,
|
|
5396
|
+
onClick: stopPropagation,
|
|
5316
5397
|
children: [
|
|
5317
5398
|
/* @__PURE__ */ u4("div", {
|
|
5318
5399
|
className: "playbar-controls",
|
|
5319
5400
|
children: [
|
|
5320
|
-
|
|
5321
|
-
className: "recording
|
|
5322
|
-
|
|
5401
|
+
/* @__PURE__ */ u4("button", {
|
|
5402
|
+
className: `playbar-btn record-btn ${isRecording2 ? "recording" : ""}`,
|
|
5403
|
+
onClick: handleToggleRecording,
|
|
5323
5404
|
children: [
|
|
5324
|
-
|
|
5325
|
-
|
|
5405
|
+
Icons.record,
|
|
5406
|
+
isRecording2 && /* @__PURE__ */ u4("span", {
|
|
5407
|
+
className: "btn-label",
|
|
5408
|
+
children: "REC"
|
|
5326
5409
|
}, undefined, false, undefined, this),
|
|
5327
5410
|
/* @__PURE__ */ u4("span", {
|
|
5328
|
-
className: "
|
|
5329
|
-
children: "
|
|
5411
|
+
className: "tooltip tooltip-left",
|
|
5412
|
+
children: isRecording2 ? "Stop recording" : "Start recording"
|
|
5330
5413
|
}, undefined, false, undefined, this)
|
|
5331
5414
|
]
|
|
5332
5415
|
}, undefined, true, undefined, this),
|
|
@@ -5537,11 +5620,13 @@ function LetterboxedLayout({ canvas }) {
|
|
|
5537
5620
|
const hmrFlash2 = debugState.hmrFlash.value;
|
|
5538
5621
|
const leftValue = isOnline ? Math.abs(advantage) : frameTime2;
|
|
5539
5622
|
const leftMax = isOnline ? 10 : 16.67;
|
|
5540
|
-
const leftLabel = isOnline ? "
|
|
5623
|
+
const leftLabel = isOnline ? "adv" : "time";
|
|
5541
5624
|
const leftColor = isOnline ? advantage >= 0 ? "#4a9eff" : "#ff4a4a" : frameTime2 > 16.67 ? "#ff4a4a" : "#4aff4a";
|
|
5625
|
+
const leftDisplayValue = isOnline ? `${advantage >= 0 ? "+" : ""}${advantage} frames` : `${frameTime2.toFixed(1)}ms`;
|
|
5542
5626
|
const rightValue = isOnline ? 0 : snapshotSize2;
|
|
5543
5627
|
const rightMax = isOnline ? 10 : 1e4;
|
|
5544
|
-
const rightLabel = isOnline ? "
|
|
5628
|
+
const rightLabel = isOnline ? "rb" : "size";
|
|
5629
|
+
const rightDisplayValue = isOnline ? "0 frames" : snapshotSize2 >= 1000 ? `${(snapshotSize2 / 1000).toFixed(1)}kb` : `${snapshotSize2}b`;
|
|
5545
5630
|
const gameClassName = hmrFlash2 ? "letterboxed-game hmr-flash" : "letterboxed-game";
|
|
5546
5631
|
return /* @__PURE__ */ u4("main", {
|
|
5547
5632
|
className: "layout-letterboxed",
|
|
@@ -5554,7 +5639,8 @@ function LetterboxedLayout({ canvas }) {
|
|
|
5554
5639
|
value: leftValue,
|
|
5555
5640
|
max: leftMax,
|
|
5556
5641
|
side: "left",
|
|
5557
|
-
color: leftColor
|
|
5642
|
+
color: leftColor,
|
|
5643
|
+
displayValue: leftDisplayValue
|
|
5558
5644
|
}, undefined, false, undefined, this),
|
|
5559
5645
|
/* @__PURE__ */ u4("div", {
|
|
5560
5646
|
className: gameClassName,
|
|
@@ -5565,7 +5651,8 @@ function LetterboxedLayout({ canvas }) {
|
|
|
5565
5651
|
/* @__PURE__ */ u4(VerticalBar, {
|
|
5566
5652
|
value: rightValue,
|
|
5567
5653
|
max: rightMax,
|
|
5568
|
-
side: "right"
|
|
5654
|
+
side: "right",
|
|
5655
|
+
displayValue: rightDisplayValue
|
|
5569
5656
|
}, undefined, false, undefined, this),
|
|
5570
5657
|
/* @__PURE__ */ u4(BottomBar, {}, undefined, false, undefined, this)
|
|
5571
5658
|
]
|
|
@@ -5749,6 +5836,7 @@ var styles = `
|
|
|
5749
5836
|
font-family: monospace;
|
|
5750
5837
|
font-size: 12px;
|
|
5751
5838
|
padding: 0;
|
|
5839
|
+
user-select: none;
|
|
5752
5840
|
}
|
|
5753
5841
|
|
|
5754
5842
|
.top-bar-side-label {
|
|
@@ -5802,6 +5890,7 @@ var styles = `
|
|
|
5802
5890
|
justify-content: flex-end;
|
|
5803
5891
|
background: #111;
|
|
5804
5892
|
padding: 4px 0;
|
|
5893
|
+
user-select: none;
|
|
5805
5894
|
}
|
|
5806
5895
|
|
|
5807
5896
|
.right-bar {
|
|
@@ -5812,6 +5901,7 @@ var styles = `
|
|
|
5812
5901
|
justify-content: flex-end;
|
|
5813
5902
|
background: #111;
|
|
5814
5903
|
padding: 4px 0;
|
|
5904
|
+
user-select: none;
|
|
5815
5905
|
}
|
|
5816
5906
|
|
|
5817
5907
|
.vertical-bar {
|
|
@@ -5820,7 +5910,6 @@ var styles = `
|
|
|
5820
5910
|
background: #333;
|
|
5821
5911
|
border-radius: 2px;
|
|
5822
5912
|
position: relative;
|
|
5823
|
-
overflow: hidden;
|
|
5824
5913
|
}
|
|
5825
5914
|
|
|
5826
5915
|
.vertical-bar-fill {
|
|
@@ -5833,6 +5922,37 @@ var styles = `
|
|
|
5833
5922
|
transition: height 0.1s ease-out;
|
|
5834
5923
|
}
|
|
5835
5924
|
|
|
5925
|
+
.vertical-bar-popover {
|
|
5926
|
+
position: absolute;
|
|
5927
|
+
top: 50%;
|
|
5928
|
+
transform: translateY(-50%);
|
|
5929
|
+
background: #222;
|
|
5930
|
+
color: #ccc;
|
|
5931
|
+
padding: 4px 8px;
|
|
5932
|
+
border-radius: 4px;
|
|
5933
|
+
font-size: 10px;
|
|
5934
|
+
font-family: monospace;
|
|
5935
|
+
white-space: nowrap;
|
|
5936
|
+
opacity: 0;
|
|
5937
|
+
visibility: hidden;
|
|
5938
|
+
transition: opacity 0.15s;
|
|
5939
|
+
pointer-events: none;
|
|
5940
|
+
z-index: 10;
|
|
5941
|
+
}
|
|
5942
|
+
|
|
5943
|
+
.vertical-bar-popover.left {
|
|
5944
|
+
left: calc(100% + 8px);
|
|
5945
|
+
}
|
|
5946
|
+
|
|
5947
|
+
.vertical-bar-popover.right {
|
|
5948
|
+
right: calc(100% + 8px);
|
|
5949
|
+
}
|
|
5950
|
+
|
|
5951
|
+
.vertical-bar:hover .vertical-bar-popover {
|
|
5952
|
+
opacity: 1;
|
|
5953
|
+
visibility: visible;
|
|
5954
|
+
}
|
|
5955
|
+
|
|
5836
5956
|
|
|
5837
5957
|
.bottom-bar {
|
|
5838
5958
|
grid-area: bottom-bar;
|
|
@@ -5842,6 +5962,7 @@ var styles = `
|
|
|
5842
5962
|
/* Mobile-first: more padding */
|
|
5843
5963
|
padding: 0 16px;
|
|
5844
5964
|
gap: 12px;
|
|
5965
|
+
user-select: none;
|
|
5845
5966
|
}
|
|
5846
5967
|
|
|
5847
5968
|
/* Desktop: tighter padding */
|
|
@@ -5859,22 +5980,16 @@ var styles = `
|
|
|
5859
5980
|
flex-shrink: 0;
|
|
5860
5981
|
}
|
|
5861
5982
|
|
|
5862
|
-
/*
|
|
5863
|
-
.
|
|
5864
|
-
|
|
5865
|
-
align-items: center;
|
|
5866
|
-
margin-right: 4px;
|
|
5983
|
+
/* Record button */
|
|
5984
|
+
.record-btn {
|
|
5985
|
+
color: #666;
|
|
5867
5986
|
}
|
|
5868
5987
|
|
|
5869
|
-
.
|
|
5870
|
-
|
|
5988
|
+
.record-btn.recording {
|
|
5989
|
+
color: #ff4444;
|
|
5871
5990
|
}
|
|
5872
5991
|
|
|
5873
|
-
.recording
|
|
5874
|
-
width: 10px;
|
|
5875
|
-
height: 10px;
|
|
5876
|
-
background: #ff4444;
|
|
5877
|
-
border-radius: 50%;
|
|
5992
|
+
.record-btn.recording svg {
|
|
5878
5993
|
animation: recording-pulse 1s ease-in-out infinite;
|
|
5879
5994
|
}
|
|
5880
5995
|
|
|
@@ -5883,6 +5998,17 @@ var styles = `
|
|
|
5883
5998
|
50% { opacity: 0.4; }
|
|
5884
5999
|
}
|
|
5885
6000
|
|
|
6001
|
+
/* Desktop: show REC label when recording */
|
|
6002
|
+
@media (min-width: 769px) {
|
|
6003
|
+
.record-btn.recording {
|
|
6004
|
+
width: auto;
|
|
6005
|
+
padding: 0 6px;
|
|
6006
|
+
gap: 4px;
|
|
6007
|
+
background: rgba(255, 68, 68, 0.15);
|
|
6008
|
+
border-radius: 3px;
|
|
6009
|
+
}
|
|
6010
|
+
}
|
|
6011
|
+
|
|
5886
6012
|
/* Replay indicator - mobile: hidden */
|
|
5887
6013
|
.replay-indicator {
|
|
5888
6014
|
display: none;
|
|
@@ -6044,6 +6170,7 @@ var styles = `
|
|
|
6044
6170
|
position: relative;
|
|
6045
6171
|
cursor: pointer;
|
|
6046
6172
|
overflow: hidden;
|
|
6173
|
+
user-select: none;
|
|
6047
6174
|
}
|
|
6048
6175
|
|
|
6049
6176
|
/* Desktop: smaller seek bar */
|
|
@@ -7698,5 +7825,5 @@ export {
|
|
|
7698
7825
|
App
|
|
7699
7826
|
};
|
|
7700
7827
|
|
|
7701
|
-
//# debugId=
|
|
7828
|
+
//# debugId=A1466E71356AC5F764756E2164756E21
|
|
7702
7829
|
//# sourceMappingURL=mod.js.map
|