Fullscreen hitbox.io, persistent game volume, and persistent jukebox state.
// ==UserScript==
// @name QOLbox
// @namespace Violentmonkey Scripts
// @author gpt-5.4
// @version 1.1
// @description Fullscreen hitbox.io, persistent game volume, and persistent jukebox state.
// @license ISC
// @match https://hitbox.io/game2.html*
// @match https://www.hitbox.io/game2.html*
// @run-at document-start
// @inject-into page
// @grant none
// ==/UserScript==
(function () {
'use strict';
const GAME_VOLUME_KEY = 'vm.hitbox.volumePercent';
const JUKEBOX_STATE_KEY = 'vm.hitbox.jukeboxState';
const STEP_PERCENT = 5;
const DEFAULT_GAME_PERCENT = 100;
const DEFAULT_JUKEBOX_PERCENT = 50;
const GAME_CURVE_EXPONENT = 2;
const JUKEBOX_CURVE_EXPONENT = 2;
const GLOBAL_STYLE_ID = 'qolbox-dev-style';
const FALLBACK_BASE_WIDTH = 800;
const FALLBACK_BASE_HEIGHT = 500;
const MENU_FRAME_PADDING_PX = 0;
const GAMEPLAY_SAFE_TOP_PX = 0;
const GAMEPLAY_SAFE_BOTTOM_PX = 0;
const GAMEPLAY_SAFE_SIDE_PX = 0;
const FULLSCREEN_GAMEPLAY_LAYER_SELECTOR = '#pixiContainer, #singlePlayer, .singlePlayer';
const FULLSCREEN_MENU_LAYER_SELECTOR = '.replayViewer';
const FULLSCREEN_RENDER_LAYER_SELECTOR = '#pixiContainer, #singlePlayer, .singlePlayer, .replayViewer';
const FULLSCREEN_RENDER_CANVAS_SELECTOR = [
'#pixiContainer canvas',
'#singlePlayer canvas',
'.singlePlayer canvas',
'.replayViewer canvas',
].join(', ');
const FULLSCREEN_LAYOUT_TARGET_SELECTOR = [
'#appContainer',
'#relativeContainer',
'#backgroundImage',
FULLSCREEN_RENDER_LAYER_SELECTOR,
FULLSCREEN_RENDER_CANVAS_SELECTOR,
'.inGameCSS',
'.scores',
'.spectateControls',
].join(', ');
const FEATURE_PATCH_TARGET_SELECTOR = [
'.items.left',
'.items.left .item',
'.jukebox',
'.jukebox .knob.volumeContainer',
'#ytContainer',
'#ytContainer iframe',
].join(', ');
const FULLSCREEN_SETTLE_PASSES = 4;
const RESIZE_SETTLE_PASSES = 2;
const JUKEBOX_MIN_ANGLE = -40;
const JUKEBOX_MAX_ANGLE = 220;
const JUKEBOX_ARC_CENTER = 14;
const JUKEBOX_ARC_RADIUS = 12;
const JUKEBOX_WHEEL_STEP = 5;
const JUKEBOX_DRAG_SENSITIVITY = 1;
let gamePercent = loadGamePercent();
let currentGameMenuItem = null;
let originalHowlVolume = null;
let settingGameVolumeInternally = false;
let jukeboxState = loadJukeboxState();
let currentJukeboxMenuItem = null;
let activeKnobDrag = null;
let trackedPlayers = new Set();
let youTubeHookInstalled = false;
let fullscreenHooksInstalled = false;
let lastFullscreenSignature = '';
let scheduledWorkRaf = 0;
let scheduledWorkForce = false;
let scheduledWorkFeatures = false;
let scheduledWorkPasses = 0;
let fullscreenMutationObserver = null;
let fullscreenResizeObserver = null;
let observedResizeTargets = new WeakSet();
let gameReadyHookInstalled = false;
function clampPercent(value, fallback = 0) {
const numericValue = Number(value);
if (!Number.isFinite(numericValue)) {
return fallback;
}
return Math.max(0, Math.min(100, Math.round(numericValue / STEP_PERCENT) * STEP_PERCENT));
}
function clampJukeboxPercent(value) {
const numericValue = Number(value);
if (!Number.isFinite(numericValue)) {
return DEFAULT_JUKEBOX_PERCENT;
}
return Math.max(0, Math.min(100, Math.round(numericValue)));
}
function loadGamePercent() {
try {
return clampPercent(localStorage.getItem(GAME_VOLUME_KEY), DEFAULT_GAME_PERCENT);
} catch {
return DEFAULT_GAME_PERCENT;
}
}
function saveGamePercent() {
try {
localStorage.setItem(GAME_VOLUME_KEY, String(gamePercent));
} catch {
// Ignore storage failures.
}
}
function loadJukeboxState() {
const fallback = { percent: null, muted: false };
try {
const rawState = localStorage.getItem(JUKEBOX_STATE_KEY);
if (!rawState) {
return fallback;
}
const parsed = JSON.parse(rawState);
return {
percent:
parsed && parsed.percent !== null && parsed.percent !== undefined
? clampJukeboxPercent(parsed.percent)
: null,
muted: Boolean(parsed && parsed.muted),
};
} catch {
return fallback;
}
}
function saveJukeboxState() {
try {
localStorage.setItem(JUKEBOX_STATE_KEY, JSON.stringify(jukeboxState));
} catch {
// Ignore storage failures.
}
}
function percentToGameScalar(percent) {
return Math.pow(clampPercent(percent, DEFAULT_GAME_PERCENT) / 100, GAME_CURVE_EXPONENT);
}
function percentToJukeboxVolume(percent) {
return Math.round(Math.pow(clampJukeboxPercent(percent) / 100, JUKEBOX_CURVE_EXPONENT) * 100);
}
function percentToJukeboxAngle(percent) {
const normalized = clampJukeboxPercent(percent) / 100;
return JUKEBOX_MIN_ANGLE + (JUKEBOX_MAX_ANGLE - JUKEBOX_MIN_ANGLE) * normalized;
}
function angleToJukeboxPercent(angle) {
const numericAngle = Number(angle);
if (!Number.isFinite(numericAngle)) {
return DEFAULT_JUKEBOX_PERCENT;
}
const normalized =
(Math.min(JUKEBOX_MAX_ANGLE, Math.max(JUKEBOX_MIN_ANGLE, numericAngle)) - JUKEBOX_MIN_ANGLE) /
(JUKEBOX_MAX_ANGLE - JUKEBOX_MIN_ANGLE);
return clampJukeboxPercent(normalized * 100);
}
function polarToArcPoint(angle) {
const radians = ((angle + 180) * Math.PI) / 180;
return {
x: JUKEBOX_ARC_CENTER + JUKEBOX_ARC_RADIUS * Math.cos(radians),
y: JUKEBOX_ARC_CENTER + JUKEBOX_ARC_RADIUS * Math.sin(radians),
};
}
function ensureGlobalStyle() {
if (document.getElementById(GLOBAL_STYLE_ID)) {
return;
}
const style = document.createElement('style');
style.id = GLOBAL_STYLE_ID;
style.textContent = `
html,
body {
width: 100vw !important;
height: 100vh !important;
margin: 0 !important;
overflow: hidden !important;
background: #0a0a0a !important;
}
#appContainer,
#relativeContainer {
margin: 0 !important;
max-width: none !important;
max-height: none !important;
border: 0 !important;
}
#backgroundImage,
.mainMenuFancy {
position: fixed !important;
left: 0 !important;
top: 0 !important;
right: auto !important;
bottom: auto !important;
width: 100vw !important;
height: 100vh !important;
max-width: none !important;
max-height: none !important;
}
${FULLSCREEN_RENDER_LAYER_SELECTOR} {
position: absolute !important;
margin: 0 !important;
max-width: none !important;
max-height: none !important;
overflow: hidden !important;
transform: none !important;
}
${FULLSCREEN_RENDER_CANVAS_SELECTOR} {
display: block !important;
max-width: none !important;
max-height: none !important;
transform: none !important;
}
.scores {
position: absolute !important;
left: 12px !important;
top: 6px !important;
margin-top: 0 !important;
z-index: 10 !important;
}
#email,
#songcredit,
#betaLink {
display: none !important;
}
`;
(document.head || document.documentElement).appendChild(style);
}
function setImportantStyle(element, property, value) {
if (!element) {
return;
}
element.style.setProperty(property, value, 'important');
}
function getViewportSize() {
return {
width: Math.max(window.innerWidth, document.documentElement.clientWidth || 0),
height: Math.max(window.innerHeight, document.documentElement.clientHeight || 0),
};
}
function getBaseGameSize() {
const game = window.a8;
const width = Number(game && game.Xg);
const height = Number(game && game.Zg);
return {
width: Number.isFinite(width) && width > 0 ? width : FALLBACK_BASE_WIDTH,
height: Number.isFinite(height) && height > 0 ? height : FALLBACK_BASE_HEIGHT,
};
}
function isElementVisible(element) {
if (!element || !element.isConnected) {
return false;
}
const style = window.getComputedStyle(element);
if (style.display === 'none' || style.visibility === 'hidden') {
return false;
}
const rect = element.getBoundingClientRect();
return rect.width > 0 && rect.height > 0;
}
function isGameplayLayer(element) {
return Boolean(
element &&
(element.id === 'pixiContainer' ||
element.id === 'singlePlayer' ||
(element.classList && element.classList.contains('singlePlayer')))
);
}
function hasVisibleLayer(selector) {
for (const layer of document.querySelectorAll(selector)) {
if (isElementVisible(layer)) {
return true;
}
}
return false;
}
function isMenuGameplayOverlap() {
return hasVisibleLayer(FULLSCREEN_MENU_LAYER_SELECTOR) && hasVisibleLayer(FULLSCREEN_GAMEPLAY_LAYER_SELECTOR);
}
function getActiveRenderMode() {
// During the handoff into a match both layers can exist briefly.
// Keep using the menu frame until the replay/menu layer is actually gone.
if (hasVisibleLayer(FULLSCREEN_MENU_LAYER_SELECTOR)) {
return 'menu';
}
if (hasVisibleLayer(FULLSCREEN_GAMEPLAY_LAYER_SELECTOR)) {
return 'gameplay';
}
return 'menu';
}
function getModeInsets(mode, viewport) {
if (mode === 'gameplay') {
return {
left: GAMEPLAY_SAFE_SIDE_PX,
right: GAMEPLAY_SAFE_SIDE_PX,
top: GAMEPLAY_SAFE_TOP_PX,
bottom: GAMEPLAY_SAFE_BOTTOM_PX,
};
}
return {
left: MENU_FRAME_PADDING_PX,
right: MENU_FRAME_PADDING_PX,
top: MENU_FRAME_PADDING_PX,
bottom: MENU_FRAME_PADDING_PX,
};
}
function getFullscreenDimensions(viewport = getViewportSize(), mode = getActiveRenderMode()) {
const base = getBaseGameSize();
const insets = getModeInsets(mode, viewport);
const availableWidth = Math.max(1, viewport.width - insets.left - insets.right);
const availableHeight = Math.max(1, viewport.height - insets.top - insets.bottom);
const scale = Math.max(0.01, Math.min(availableWidth / base.width, availableHeight / base.height));
const width = Math.max(1, Math.round(base.width * scale));
const height = Math.max(1, Math.round(base.height * scale));
const left = insets.left + Math.max(0, Math.floor((availableWidth - width) / 2));
const top =
mode === 'gameplay'
? Math.max(insets.top, viewport.height - insets.bottom - height)
: insets.top + Math.max(0, Math.floor((availableHeight - height) / 2));
return {
viewportWidth: viewport.width,
viewportHeight: viewport.height,
baseWidth: base.width,
baseHeight: base.height,
width,
height,
scale,
left,
top,
shellLeft: 0,
shellTop: 0,
shellWidth: viewport.width,
shellHeight: viewport.height,
insets,
mode,
};
}
function getNativeUiZoom(dimensions = getFullscreenDimensions()) {
return Math.min(1, dimensions.width / 1400);
}
function getPinnedFullscreenDimensions(game = window.a8) {
return (game && game.__qolboxDevPinnedDimensions) || getFullscreenDimensions();
}
function getRelativeContainerBounds(dimensions = getFullscreenDimensions()) {
return {
left: dimensions.left,
top: dimensions.top,
width: dimensions.width,
height: dimensions.height,
};
}
function getExpectedBackingSize(dimensions = getFullscreenDimensions()) {
const pixelRatio = Math.max(1, Number(window.devicePixelRatio) || 1);
return {
width: Math.max(1, Math.round(dimensions.width * pixelRatio)),
height: Math.max(1, Math.round(dimensions.height * pixelRatio)),
};
}
function layoutRelativeHud(relativeBounds, dimensions) {
const isGameplay = dimensions.mode === 'gameplay';
for (const scorePanel of document.querySelectorAll('.scores')) {
if (isGameplay) {
setImportantStyle(scorePanel, 'position', 'fixed');
setImportantStyle(scorePanel, 'left', 'auto');
setImportantStyle(scorePanel, 'top', 'auto');
setImportantStyle(scorePanel, 'right', '16px');
setImportantStyle(scorePanel, 'bottom', '12px');
setImportantStyle(scorePanel, 'text-align', 'right');
} else {
setImportantStyle(scorePanel, 'position', 'absolute');
setImportantStyle(scorePanel, 'left', '12px');
setImportantStyle(scorePanel, 'top', '6px');
setImportantStyle(scorePanel, 'right', 'auto');
setImportantStyle(scorePanel, 'bottom', 'auto');
setImportantStyle(scorePanel, 'text-align', 'left');
}
setImportantStyle(scorePanel, 'margin-top', '0');
setImportantStyle(scorePanel, 'z-index', '10');
}
}
function enforceFullscreenLayout(dimensions = getFullscreenDimensions()) {
ensureGlobalStyle();
const menuDimensions =
dimensions.mode === 'menu' ? dimensions : getFullscreenDimensions(undefined, 'menu');
const gameplayDimensions =
dimensions.mode === 'gameplay' ? dimensions : getFullscreenDimensions(undefined, 'gameplay');
const activeDimensions = dimensions.mode === 'gameplay' ? gameplayDimensions : menuDimensions;
const relativeBounds = getRelativeContainerBounds(activeDimensions);
setImportantStyle(document.documentElement, 'overflow', 'hidden');
setImportantStyle(document.body, 'overflow', 'hidden');
setImportantStyle(document.body, 'margin', '0');
setImportantStyle(document.body, 'background-color', '#0a0a0a');
const appContainer = document.getElementById('appContainer');
if (appContainer) {
setImportantStyle(appContainer, 'position', 'fixed');
setImportantStyle(appContainer, 'left', `${activeDimensions.shellLeft}px`);
setImportantStyle(appContainer, 'top', `${activeDimensions.shellTop}px`);
setImportantStyle(appContainer, 'right', 'auto');
setImportantStyle(appContainer, 'bottom', 'auto');
setImportantStyle(appContainer, 'margin', '0');
setImportantStyle(appContainer, 'width', `${activeDimensions.shellWidth}px`);
setImportantStyle(appContainer, 'height', `${activeDimensions.shellHeight}px`);
setImportantStyle(appContainer, 'max-width', 'none');
setImportantStyle(appContainer, 'max-height', 'none');
setImportantStyle(appContainer, 'border', '0');
setImportantStyle(appContainer, 'overflow', 'hidden');
}
const relativeContainer = document.getElementById('relativeContainer');
if (relativeContainer) {
setImportantStyle(relativeContainer, 'position', 'fixed');
setImportantStyle(relativeContainer, 'left', `${relativeBounds.left}px`);
setImportantStyle(relativeContainer, 'top', `${relativeBounds.top}px`);
setImportantStyle(relativeContainer, 'right', 'auto');
setImportantStyle(relativeContainer, 'bottom', 'auto');
setImportantStyle(relativeContainer, 'margin', '0');
setImportantStyle(relativeContainer, 'width', `${relativeBounds.width}px`);
setImportantStyle(relativeContainer, 'height', `${relativeBounds.height}px`);
setImportantStyle(relativeContainer, 'overflow', 'visible');
}
const backgroundImage = document.getElementById('backgroundImage');
if (backgroundImage) {
setImportantStyle(backgroundImage, 'position', 'fixed');
setImportantStyle(backgroundImage, 'left', '0');
setImportantStyle(backgroundImage, 'top', '0');
setImportantStyle(backgroundImage, 'right', 'auto');
setImportantStyle(backgroundImage, 'bottom', 'auto');
setImportantStyle(backgroundImage, 'width', `${dimensions.viewportWidth}px`);
setImportantStyle(backgroundImage, 'height', `${dimensions.viewportHeight}px`);
}
for (const layer of document.querySelectorAll(FULLSCREEN_RENDER_LAYER_SELECTOR)) {
setImportantStyle(layer, 'position', 'absolute');
setImportantStyle(layer, 'left', `${activeDimensions.left}px`);
setImportantStyle(layer, 'top', `${activeDimensions.top}px`);
setImportantStyle(layer, 'right', 'auto');
setImportantStyle(layer, 'bottom', 'auto');
setImportantStyle(layer, 'width', `${activeDimensions.width}px`);
setImportantStyle(layer, 'height', `${activeDimensions.height}px`);
setImportantStyle(layer, 'max-width', 'none');
setImportantStyle(layer, 'max-height', 'none');
setImportantStyle(layer, 'overflow', 'hidden');
setImportantStyle(layer, 'transform', 'none');
setImportantStyle(layer, 'zoom', '1');
}
for (const canvas of document.querySelectorAll(FULLSCREEN_RENDER_CANVAS_SELECTOR)) {
setImportantStyle(canvas, 'position', 'absolute');
setImportantStyle(canvas, 'left', '0');
setImportantStyle(canvas, 'top', '0');
setImportantStyle(canvas, 'right', 'auto');
setImportantStyle(canvas, 'bottom', 'auto');
setImportantStyle(canvas, 'width', `${activeDimensions.width}px`);
setImportantStyle(canvas, 'height', `${activeDimensions.height}px`);
setImportantStyle(canvas, 'max-width', 'none');
setImportantStyle(canvas, 'max-height', 'none');
setImportantStyle(canvas, 'transform', 'none');
}
const uiZoom = String(getNativeUiZoom(activeDimensions));
for (const overlay of document.querySelectorAll('.inGameCSS')) {
setImportantStyle(overlay, 'zoom', uiZoom);
setImportantStyle(overlay, 'transform-origin', 'top left');
}
layoutRelativeHud(relativeBounds, activeDimensions);
return true;
}
function setNativeFullscreenSize(dimensions = getFullscreenDimensions()) {
const game = window.a8;
if (!game) {
return false;
}
game.__qolboxDevPinnedDimensions = dimensions;
installNativeMetricOverride(game);
game._P = dimensions.scale;
game.lg = dimensions.width;
game.ug = dimensions.height;
if ('Qp' in game) {
game.Qp = getNativeUiZoom(dimensions);
}
if (typeof game.PP === 'function') {
try {
game.PP();
} catch {
// Ignore intermediate layout failures while the game is booting.
}
}
return true;
}
function installNativeMetricOverride(game = window.a8) {
if (!game || game.__qolboxDevMetricOverrideInstalled) {
return Boolean(game);
}
const makeMetricAccessor = getter => ({
configurable: true,
enumerable: true,
get: getter,
set: () => {
// Ignore native writes and keep fullscreen metrics authoritative.
},
});
try {
Object.defineProperty(game, '_P', makeMetricAccessor(() => getPinnedFullscreenDimensions(game).scale));
Object.defineProperty(
game,
'Qp',
makeMetricAccessor(() => getNativeUiZoom(getPinnedFullscreenDimensions(game)))
);
Object.defineProperty(game, 'lg', makeMetricAccessor(() => getPinnedFullscreenDimensions(game).width));
Object.defineProperty(
game,
'ug',
makeMetricAccessor(() => getPinnedFullscreenDimensions(game).height)
);
game.__qolboxDevMetricOverrideInstalled = true;
return true;
} catch {
return false;
}
}
function installNativeFullscreenPatch() {
const game = window.a8;
if (!game) {
return false;
}
installNativeMetricOverride(game);
if (typeof game.ag === 'function' && !game.ag.__qolboxDevWrapped) {
const originalResize = game.ag;
const wrappedResize = function (...args) {
setNativeFullscreenSize(getFullscreenDimensions());
if (game.__qolboxDevRunningNativeResize) {
return originalResize.apply(this, args);
}
game.__qolboxDevRunningNativeResize = true;
try {
const result = originalResize.apply(this, args);
setNativeFullscreenSize(getFullscreenDimensions());
return result;
} finally {
game.__qolboxDevRunningNativeResize = false;
}
};
wrappedResize.__qolboxDevWrapped = true;
wrappedResize.__qolboxDevOriginal = originalResize;
game.ag = wrappedResize;
}
return true;
}
function runNativeResize(dimensions = getFullscreenDimensions()) {
const game = window.a8;
if (!game || typeof game.ag !== 'function') {
return false;
}
setNativeFullscreenSize(dimensions);
try {
game.ag.call(game, dimensions);
return true;
} catch {
return false;
}
}
function fitElementToFrame(element, dimensions = getFullscreenDimensions(), left = 0, top = 0) {
if (!element || !(element instanceof Element)) {
return;
}
setImportantStyle(element, 'position', 'absolute');
setImportantStyle(element, 'left', `${left}px`);
setImportantStyle(element, 'top', `${top}px`);
setImportantStyle(element, 'right', 'auto');
setImportantStyle(element, 'bottom', 'auto');
setImportantStyle(element, 'margin', '0');
setImportantStyle(element, 'width', `${dimensions.width}px`);
setImportantStyle(element, 'height', `${dimensions.height}px`);
setImportantStyle(element, 'max-width', 'none');
setImportantStyle(element, 'max-height', 'none');
setImportantStyle(element, 'overflow', 'hidden');
setImportantStyle(element, 'transform', 'none');
}
function getRendererHost(renderer) {
const host =
(renderer && (renderer.Tg || renderer.dg)) ||
(renderer && renderer.Ag && renderer.Ag.view && renderer.Ag.view.parentElement) ||
null;
return host instanceof Element ? host : null;
}
function getKnownRenderers() {
const renderers = [];
const seen = new Set();
function addRenderer(candidate) {
if (
!candidate ||
typeof candidate !== 'object' ||
seen.has(candidate) ||
!candidate.Bc ||
!(candidate.Ag || typeof candidate.cg === 'function')
) {
return;
}
seen.add(candidate);
renderers.push(candidate);
}
function collect(candidate) {
if (!candidate) {
return;
}
if (Array.isArray(candidate)) {
candidate.forEach(collect);
return;
}
addRenderer(candidate);
addRenderer(candidate.hb);
if (Array.isArray(candidate.hb)) {
candidate.hb.forEach(addRenderer);
}
}
collect(window.multiplayerSession);
collect(window.A4);
collect(window.a8 && window.a8.II);
return renderers;
}
function resizeKnownRenderers(dimensions = getFullscreenDimensions()) {
const pixelRatio = Math.max(1, Number(window.devicePixelRatio) || 1);
for (const renderer of getKnownRenderers()) {
const frameWidth = Math.max(1, Math.round(dimensions.width));
const frameHeight = Math.max(1, Math.round(dimensions.height));
renderer.Bc.wc = frameWidth;
renderer.Bc.mc = frameHeight;
if (renderer.Ag && typeof renderer.Ag === 'object') {
if ('autoDensity' in renderer.Ag) {
renderer.Ag.autoDensity = true;
}
if (typeof renderer.Ag.resolution === 'number') {
renderer.Ag.resolution = pixelRatio;
}
if (renderer.Ag.options && typeof renderer.Ag.options === 'object') {
renderer.Ag.options.autoDensity = true;
renderer.Ag.options.resolution = pixelRatio;
}
}
try {
if (typeof renderer.cg === 'function') {
renderer.cg(frameWidth, frameHeight);
} else if (renderer.Ag && typeof renderer.Ag.resize === 'function') {
renderer.Ag.resize(frameWidth, frameHeight);
}
} catch {
// Ignore incomplete renderers while the scene is rebuilding.
}
fitElementToFrame(getRendererHost(renderer), dimensions, dimensions.left, dimensions.top);
if (renderer.Ag && renderer.Ag.view) {
const view = renderer.Ag.view;
setImportantStyle(view, 'position', 'absolute');
setImportantStyle(view, 'left', '0');
setImportantStyle(view, 'top', '0');
setImportantStyle(view, 'right', 'auto');
setImportantStyle(view, 'bottom', 'auto');
setImportantStyle(view, 'width', `${frameWidth}px`);
setImportantStyle(view, 'height', `${frameHeight}px`);
setImportantStyle(view, 'max-width', 'none');
setImportantStyle(view, 'max-height', 'none');
setImportantStyle(view, 'transform', 'none');
fitElementToFrame(view.parentElement, dimensions, dimensions.left, dimensions.top);
}
}
}
function getActiveRenderCanvas(mode = getActiveRenderMode()) {
const selector =
mode === 'gameplay' ? FULLSCREEN_GAMEPLAY_LAYER_SELECTOR : FULLSCREEN_MENU_LAYER_SELECTOR;
for (const layer of document.querySelectorAll(selector)) {
if (!isElementVisible(layer)) {
continue;
}
const canvas = layer.querySelector('canvas');
if (canvas) {
return canvas;
}
}
return document.querySelector(FULLSCREEN_RENDER_CANVAS_SELECTOR);
}
function getLayoutProbe() {
const appContainer = document.getElementById('appContainer');
const relativeContainer = document.getElementById('relativeContainer');
const renderLayer = getActiveRenderCanvas();
const appRect = appContainer ? appContainer.getBoundingClientRect() : null;
const relativeRect = relativeContainer ? relativeContainer.getBoundingClientRect() : null;
const renderRect = renderLayer ? renderLayer.getBoundingClientRect() : null;
const game = window.a8;
const renderers = getKnownRenderers();
return {
appWidth: appRect ? Math.round(appRect.width) : 0,
appHeight: appRect ? Math.round(appRect.height) : 0,
relativeWidth: relativeRect ? Math.round(relativeRect.width) : 0,
relativeHeight: relativeRect ? Math.round(relativeRect.height) : 0,
renderWidth: renderRect ? Math.round(renderRect.width) : 0,
renderHeight: renderRect ? Math.round(renderRect.height) : 0,
renderLeft: renderRect ? Math.round(renderRect.left) : 0,
renderTop: renderRect ? Math.round(renderRect.top) : 0,
backingWidth: renderLayer && typeof renderLayer.width === 'number' ? Math.round(renderLayer.width) : 0,
backingHeight: renderLayer && typeof renderLayer.height === 'number' ? Math.round(renderLayer.height) : 0,
rendererCount: renderers.length,
nativeWidth: Number(game && game.lg) || 0,
nativeHeight: Number(game && game.ug) || 0,
};
}
function isRenderProbeAligned(probe, dimensions) {
if (probe.renderWidth <= 0 || probe.renderHeight <= 0) {
return false;
}
const expectedBacking = getExpectedBackingSize(dimensions);
return (
Math.abs(probe.renderWidth - dimensions.width) <= 2 &&
Math.abs(probe.renderHeight - dimensions.height) <= 2 &&
Math.abs(probe.renderLeft - dimensions.left) <= 2 &&
Math.abs(probe.renderTop - dimensions.top) <= 2 &&
Math.abs(probe.backingWidth - expectedBacking.width) <= 2 &&
Math.abs(probe.backingHeight - expectedBacking.height) <= 2
);
}
function isNativeProbeAligned(probe, dimensions) {
if (probe.nativeWidth <= 0 || probe.nativeHeight <= 0) {
return false;
}
return (
Math.abs(probe.nativeWidth - dimensions.width) <= 2 &&
Math.abs(probe.nativeHeight - dimensions.height) <= 2
);
}
function buildFullscreenSignature(dimensions, probe) {
return [
dimensions.mode,
dimensions.viewportWidth,
dimensions.viewportHeight,
dimensions.width,
dimensions.height,
dimensions.left,
dimensions.top,
probe.appWidth,
probe.appHeight,
probe.relativeWidth,
probe.relativeHeight,
probe.renderWidth,
probe.renderHeight,
probe.renderLeft,
probe.renderTop,
probe.backingWidth,
probe.backingHeight,
probe.rendererCount,
probe.nativeWidth,
probe.nativeHeight,
Boolean(window.a8),
].join(':');
}
function refreshFullscreen(force = false) {
const dimensions = getFullscreenDimensions();
const probe = getLayoutProbe();
const signature = buildFullscreenSignature(dimensions, probe);
const transitionOverlap = isMenuGameplayOverlap();
enforceFullscreenLayout(dimensions);
installNativeFullscreenPatch();
setNativeFullscreenSize(dimensions);
if (
!force &&
signature === lastFullscreenSignature &&
isRenderProbeAligned(probe, dimensions) &&
isNativeProbeAligned(probe, dimensions)
) {
return false;
}
lastFullscreenSignature = signature;
const resizedNatively = runNativeResize(dimensions);
const postNativeProbe = getLayoutProbe();
if (!transitionOverlap && (!resizedNatively || !isRenderProbeAligned(postNativeProbe, dimensions))) {
resizeKnownRenderers(dimensions);
}
enforceFullscreenLayout(dimensions);
lastFullscreenSignature = buildFullscreenSignature(dimensions, getLayoutProbe());
return true;
}
function matchesElementOrDescendant(node, selector) {
if (!(node instanceof Element)) {
return false;
}
return node.matches(selector) || Boolean(node.querySelector(selector));
}
function mutationTouchesSelector(record, selector) {
if (record.target instanceof Element && record.target.matches(selector)) {
return true;
}
for (const node of record.addedNodes) {
if (matchesElementOrDescendant(node, selector)) {
return true;
}
}
for (const node of record.removedNodes) {
if (matchesElementOrDescendant(node, selector)) {
return true;
}
}
return false;
}
function observeResizeTarget(element) {
if (!fullscreenResizeObserver || !(element instanceof Element) || observedResizeTargets.has(element)) {
return;
}
observedResizeTargets.add(element);
fullscreenResizeObserver.observe(element);
}
function refreshObservedResizeTargets() {
observeResizeTarget(document.documentElement);
observeResizeTarget(document.body);
observeResizeTarget(document.getElementById('appContainer'));
observeResizeTarget(document.getElementById('relativeContainer'));
observeResizeTarget(document.getElementById('backgroundImage'));
for (const element of document.querySelectorAll(FULLSCREEN_RENDER_LAYER_SELECTOR)) {
observeResizeTarget(element);
}
for (const element of document.querySelectorAll(FULLSCREEN_RENDER_CANVAS_SELECTOR)) {
observeResizeTarget(element);
}
}
function applyPersistentFeatures() {
hookHowlPrototype();
patchGameVolumeMenu();
hookYouTubePlayer();
patchJukeboxMenu();
patchJukeboxKnob();
applyJukeboxState();
}
// Coalesce DOM churn into one layout pass per frame instead of polling.
function scheduleUiWork({ force = false, features = false, passes = 1 } = {}) {
scheduledWorkForce = scheduledWorkForce || force;
scheduledWorkFeatures = scheduledWorkFeatures || features;
scheduledWorkPasses = Math.max(scheduledWorkPasses, Math.max(1, passes));
if (scheduledWorkRaf) {
return;
}
scheduledWorkRaf = window.requestAnimationFrame(() => {
scheduledWorkRaf = 0;
const shouldForce = scheduledWorkForce;
const shouldPatchFeatures = scheduledWorkFeatures;
const remainingPasses = scheduledWorkPasses;
scheduledWorkForce = false;
scheduledWorkFeatures = false;
scheduledWorkPasses = 0;
ensureGlobalStyle();
installFullscreenHooks();
if (shouldPatchFeatures) {
applyPersistentFeatures();
}
refreshFullscreen(shouldForce);
refreshObservedResizeTargets();
if (remainingPasses > 1) {
scheduleUiWork({ force: true, passes: remainingPasses - 1 });
}
});
}
function installGameReadyHook() {
if (gameReadyHookInstalled) {
return;
}
gameReadyHookInstalled = true;
if (window.a8) {
scheduleUiWork({ force: true, passes: FULLSCREEN_SETTLE_PASSES });
return;
}
try {
let pendingGame = null;
Object.defineProperty(window, 'a8', {
configurable: true,
enumerable: true,
get() {
return pendingGame;
},
set(value) {
pendingGame = value;
Object.defineProperty(window, 'a8', {
configurable: true,
enumerable: true,
writable: true,
value,
});
scheduleUiWork({ force: true, passes: FULLSCREEN_SETTLE_PASSES });
},
});
} catch {
// Fall back to the DOM observers if the native game object can't be trapped.
}
}
function installFullscreenHooks() {
if (fullscreenHooksInstalled) {
return;
}
fullscreenHooksInstalled = true;
installGameReadyHook();
window.addEventListener('resize', () => scheduleUiWork({ force: true, passes: RESIZE_SETTLE_PASSES }), true);
window.addEventListener(
'orientationchange',
() => scheduleUiWork({ force: true, passes: RESIZE_SETTLE_PASSES }),
true
);
window.addEventListener(
'load',
() => scheduleUiWork({ force: true, features: true, passes: FULLSCREEN_SETTLE_PASSES }),
true
);
window.addEventListener(
'pageshow',
() => scheduleUiWork({ force: true, features: true, passes: RESIZE_SETTLE_PASSES }),
true
);
document.addEventListener(
'visibilitychange',
() => {
if (!document.hidden) {
scheduleUiWork({ force: true, features: true, passes: RESIZE_SETTLE_PASSES });
}
},
true
);
document.addEventListener(
'fullscreenchange',
() => scheduleUiWork({ force: true, passes: RESIZE_SETTLE_PASSES }),
true
);
fullscreenMutationObserver = new MutationObserver(records => {
let needsLayout = false;
let needsFeatures = false;
for (const record of records) {
if (!needsLayout && mutationTouchesSelector(record, FULLSCREEN_LAYOUT_TARGET_SELECTOR)) {
needsLayout = true;
}
if (!needsFeatures && mutationTouchesSelector(record, FEATURE_PATCH_TARGET_SELECTOR)) {
needsFeatures = true;
}
if (needsLayout && needsFeatures) {
break;
}
}
if (needsLayout || needsFeatures) {
scheduleUiWork({
force: needsLayout,
features: needsFeatures,
passes: needsLayout ? FULLSCREEN_SETTLE_PASSES : 1,
});
}
});
fullscreenMutationObserver.observe(document.documentElement, {
subtree: true,
childList: true,
attributes: true,
attributeFilter: ['class', 'style', 'id'],
});
if ('ResizeObserver' in window && typeof window.ResizeObserver === 'function') {
fullscreenResizeObserver = new window.ResizeObserver(() => {
scheduleUiWork({ force: true, passes: 1 });
});
refreshObservedResizeTargets();
}
}
function findGameVolumeItem() {
const candidates = document.querySelectorAll('.items.left .item, .item');
for (const candidate of candidates) {
if (/^Volume:\s*\d+%$/.test(candidate.textContent.trim())) {
return candidate;
}
}
return null;
}
function updateGameVolumeText() {
if (!currentGameMenuItem || !currentGameMenuItem.isConnected) {
currentGameMenuItem = findGameVolumeItem();
}
if (!currentGameMenuItem) {
return;
}
currentGameMenuItem.textContent = `Volume: ${gamePercent}%`;
currentGameMenuItem.title = 'Scroll to adjust by 5%, left-click up, right-click down';
currentGameMenuItem.style.cursor = 'ns-resize';
currentGameMenuItem.style.userSelect = 'none';
}
function applyGameVolume() {
updateGameVolumeText();
if (!window.Howler || !Array.isArray(window.Howler._howls) || !originalHowlVolume) {
return;
}
settingGameVolumeInternally = true;
try {
for (const howl of window.Howler._howls) {
if (!howl || typeof howl !== 'object') {
continue;
}
if (typeof howl.__qolboxDevBaseVolume !== 'number') {
const initialVolume = Number(howl._volume);
howl.__qolboxDevBaseVolume = Number.isFinite(initialVolume) ? initialVolume : 1;
}
originalHowlVolume.call(howl, howl.__qolboxDevBaseVolume * percentToGameScalar(gamePercent));
}
} finally {
settingGameVolumeInternally = false;
}
}
function setGamePercent(nextPercent) {
gamePercent = clampPercent(nextPercent, DEFAULT_GAME_PERCENT);
saveGamePercent();
applyGameVolume();
}
function patchGameVolumeMenu() {
const item = findGameVolumeItem();
if (!item) {
return false;
}
currentGameMenuItem = item;
if (!item.dataset.qolboxDevGameVolumePatched) {
item.dataset.qolboxDevGameVolumePatched = 'true';
item.addEventListener(
'click',
event => {
event.preventDefault();
event.stopImmediatePropagation();
setGamePercent(gamePercent + STEP_PERCENT);
},
true
);
item.addEventListener(
'contextmenu',
event => {
event.preventDefault();
event.stopImmediatePropagation();
setGamePercent(gamePercent - STEP_PERCENT);
},
true
);
item.addEventListener(
'wheel',
event => {
event.preventDefault();
event.stopImmediatePropagation();
setGamePercent(gamePercent + (event.deltaY < 0 ? STEP_PERCENT : -STEP_PERCENT));
},
{ passive: false, capture: true }
);
}
updateGameVolumeText();
return true;
}
function hookHowlPrototype() {
const HowlCtor = window.Howl;
if (!HowlCtor || !HowlCtor.prototype || typeof HowlCtor.prototype.volume !== 'function') {
return false;
}
if (HowlCtor.prototype.volume.__qolboxDevWrapped) {
return true;
}
originalHowlVolume = HowlCtor.prototype.volume;
function wrappedVolume(value, ...rest) {
if (arguments.length === 0) {
if (typeof this.__qolboxDevBaseVolume === 'number') {
return this.__qolboxDevBaseVolume;
}
return originalHowlVolume.call(this);
}
if (typeof value === 'number' && !settingGameVolumeInternally) {
this.__qolboxDevBaseVolume = value;
return originalHowlVolume.call(this, value * percentToGameScalar(gamePercent), ...rest);
}
return originalHowlVolume.call(this, value, ...rest);
}
wrappedVolume.__qolboxDevWrapped = true;
HowlCtor.prototype.volume = wrappedVolume;
applyGameVolume();
return true;
}
function findSettingsContainer() {
return document.querySelector('.items.left');
}
function findChangeControlsItem(container) {
if (!container) {
return null;
}
for (const item of container.querySelectorAll('.item')) {
if (item.textContent.trim() === 'Change Controls') {
return item;
}
}
return null;
}
function getJukeboxMenuLabel() {
return jukeboxState.muted ? 'Unmute Jukebox' : 'Mute Jukebox';
}
function updateJukeboxMenuItem() {
if (!currentJukeboxMenuItem || !currentJukeboxMenuItem.isConnected) {
return;
}
currentJukeboxMenuItem.textContent = getJukeboxMenuLabel();
currentJukeboxMenuItem.title = 'Remember the lobby radio mute state';
}
function patchJukeboxMenu() {
const container = findSettingsContainer();
if (!container) {
return false;
}
let item = container.querySelector('.item[data-qolbox-dev-jukebox-menu="true"]');
if (!item) {
item = document.createElement('div');
item.className = 'item';
item.dataset.qolboxDevJukeboxMenu = 'true';
item.addEventListener(
'click',
event => {
event.preventDefault();
event.stopImmediatePropagation();
toggleJukeboxMute();
},
true
);
const beforeItem = findChangeControlsItem(container);
if (beforeItem) {
container.insertBefore(item, beforeItem);
} else {
container.appendChild(item);
}
}
currentJukeboxMenuItem = item;
updateJukeboxMenuItem();
return true;
}
function findJukeboxKnob() {
return document.querySelector('.jukebox .knob.volumeContainer');
}
function ensureJukeboxPercent(knob) {
if (jukeboxState.percent !== null) {
return;
}
const bar = knob ? knob.querySelector('.barSVG') : null;
const transform = bar ? bar.style.transform || window.getComputedStyle(bar).transform : '';
const match = typeof transform === 'string' ? transform.match(/rotate\((-?\d+(?:\.\d+)?)deg\)/i) : null;
jukeboxState.percent = angleToJukeboxPercent(match ? Number(match[1]) : DEFAULT_JUKEBOX_PERCENT);
saveJukeboxState();
}
function updateJukeboxKnobAccessibility(knob, percent = null) {
if (!knob) {
return;
}
const effectivePercent = jukeboxState.muted
? 0
: clampJukeboxPercent(percent ?? jukeboxState.percent ?? DEFAULT_JUKEBOX_PERCENT);
knob.setAttribute('aria-label', 'Jukebox volume');
knob.setAttribute('aria-valuemin', '0');
knob.setAttribute('aria-valuemax', '100');
knob.setAttribute('aria-valuenow', String(effectivePercent));
knob.setAttribute('aria-valuetext', jukeboxState.muted ? `Muted (${effectivePercent}%)` : `${effectivePercent}%`);
}
function setKnobVisual(knob, percent) {
if (!knob) {
return;
}
const angle = percentToJukeboxAngle(percent);
const bar = knob.querySelector('.barSVG');
const arcPath = knob.querySelector('.arcSVG path');
if (bar) {
bar.style.transform = `rotate(${angle}deg)`;
}
if (arcPath) {
const startPoint = polarToArcPoint(JUKEBOX_MIN_ANGLE);
const endPoint = polarToArcPoint(angle);
const sweepDegrees = Math.max(0, angle - JUKEBOX_MIN_ANGLE);
const largeArcFlag = sweepDegrees > 180 ? 1 : 0;
arcPath.setAttribute(
'd',
`M ${startPoint.x} ${startPoint.y} A ${JUKEBOX_ARC_RADIUS} ${JUKEBOX_ARC_RADIUS} 0 ${largeArcFlag} 1 ${endPoint.x} ${endPoint.y}`
);
}
updateJukeboxKnobAccessibility(knob, percent);
}
function applyJukeboxStateToKnob(knob) {
if (!knob || activeKnobDrag) {
return;
}
ensureJukeboxPercent(knob);
setKnobVisual(knob, jukeboxState.muted ? 0 : jukeboxState.percent);
}
function trackPlayer(player) {
if (!player || typeof player.setVolume !== 'function') {
return;
}
trackedPlayers.add(player);
}
function discoverPlayers() {
const yt = window.YT;
if (!yt || typeof yt.get !== 'function') {
return;
}
for (const candidate of document.querySelectorAll('#ytContainer [id], #ytContainer iframe[id]')) {
if (!candidate.id) {
continue;
}
try {
const player = yt.get(candidate.id);
if (player && typeof player.setVolume === 'function') {
trackPlayer(player);
}
} catch {
// Ignore unresolved ids.
}
}
}
function applyJukeboxStateToPlayer(player) {
if (!player || typeof player.setVolume !== 'function') {
trackedPlayers.delete(player);
return;
}
ensureJukeboxPercent(findJukeboxKnob());
try {
if (jukeboxState.muted) {
if (typeof player.unMute === 'function') {
player.unMute();
}
player.setVolume(0);
if (typeof player.mute === 'function') {
player.mute();
}
} else {
if (typeof player.unMute === 'function') {
player.unMute();
}
player.setVolume(percentToJukeboxVolume(jukeboxState.percent));
}
} catch {
trackedPlayers.delete(player);
}
}
function applyJukeboxState() {
const knob = findJukeboxKnob();
applyJukeboxStateToKnob(knob);
discoverPlayers();
for (const player of Array.from(trackedPlayers)) {
applyJukeboxStateToPlayer(player);
}
}
function hookYouTubePlayer() {
const yt = window.YT;
if (!yt || typeof yt.Player !== 'function') {
return false;
}
if (youTubeHookInstalled || yt.Player.__qolboxDevWrapped) {
youTubeHookInstalled = true;
discoverPlayers();
return true;
}
const OriginalPlayer = yt.Player;
function WrappedPlayer(...args) {
const instance = new OriginalPlayer(...args);
trackPlayer(instance);
window.setTimeout(() => {
applyJukeboxStateToPlayer(instance);
}, 0);
return instance;
}
Object.setPrototypeOf(WrappedPlayer, OriginalPlayer);
WrappedPlayer.prototype = OriginalPlayer.prototype;
WrappedPlayer.__qolboxDevWrapped = true;
yt.Player = WrappedPlayer;
youTubeHookInstalled = true;
discoverPlayers();
return true;
}
function setJukeboxPercent(nextPercent) {
jukeboxState.percent = clampJukeboxPercent(nextPercent);
jukeboxState.muted = false;
saveJukeboxState();
updateJukeboxMenuItem();
setKnobVisual(findJukeboxKnob(), jukeboxState.percent);
applyJukeboxState();
}
function toggleJukeboxMute() {
ensureJukeboxPercent(findJukeboxKnob());
jukeboxState.muted = !jukeboxState.muted;
saveJukeboxState();
updateJukeboxMenuItem();
applyJukeboxState();
}
function getKnobPercentFromPointer(event) {
if (!activeKnobDrag) {
return DEFAULT_JUKEBOX_PERCENT;
}
const deltaY = activeKnobDrag.startY - event.clientY;
return clampJukeboxPercent(activeKnobDrag.startPercent + deltaY * JUKEBOX_DRAG_SENSITIVITY);
}
function onKnobPointerMove(event) {
if (!activeKnobDrag) {
return;
}
event.preventDefault();
setJukeboxPercent(getKnobPercentFromPointer(event));
}
function endKnobDrag() {
activeKnobDrag = null;
}
function patchGlobalKnobListeners() {
if (window.__qolboxDevJukeboxGlobalsPatched) {
return;
}
window.__qolboxDevJukeboxGlobalsPatched = true;
window.addEventListener('pointermove', onKnobPointerMove, true);
window.addEventListener('mousemove', onKnobPointerMove, true);
window.addEventListener('pointerup', endKnobDrag, true);
window.addEventListener('mouseup', endKnobDrag, true);
window.addEventListener('blur', endKnobDrag, true);
}
function patchJukeboxKnob() {
const knob = findJukeboxKnob();
if (!knob) {
return false;
}
patchGlobalKnobListeners();
ensureJukeboxPercent(knob);
applyJukeboxStateToKnob(knob);
if (!knob.dataset.qolboxDevJukeboxPatched) {
knob.dataset.qolboxDevJukeboxPatched = 'true';
knob.title = 'Scroll or drag to adjust the jukebox volume';
knob.style.touchAction = 'none';
knob.addEventListener(
'pointerdown',
event => {
event.preventDefault();
event.stopPropagation();
if (typeof knob.setPointerCapture === 'function' && event.pointerId !== undefined) {
try {
knob.setPointerCapture(event.pointerId);
} catch {
// Ignore pointer capture failures.
}
}
if (jukeboxState.muted) {
jukeboxState.muted = false;
saveJukeboxState();
updateJukeboxMenuItem();
applyJukeboxState();
}
activeKnobDrag = {
startY: event.clientY,
startPercent: jukeboxState.percent ?? DEFAULT_JUKEBOX_PERCENT,
};
onKnobPointerMove(event);
},
true
);
knob.addEventListener(
'wheel',
event => {
event.preventDefault();
event.stopPropagation();
ensureJukeboxPercent(knob);
const currentPercent = jukeboxState.muted ? 0 : jukeboxState.percent;
setJukeboxPercent(currentPercent + (event.deltaY < 0 ? JUKEBOX_WHEEL_STEP : -JUKEBOX_WHEEL_STEP));
},
{ passive: false }
);
}
return true;
}
ensureGlobalStyle();
installFullscreenHooks();
scheduleUiWork({ force: true, features: true, passes: FULLSCREEN_SETTLE_PASSES });
if (document.readyState === 'loading') {
document.addEventListener(
'DOMContentLoaded',
() => scheduleUiWork({ force: true, features: true, passes: FULLSCREEN_SETTLE_PASSES }),
{ once: true }
);
} else {
scheduleUiWork({ force: true, features: true, passes: FULLSCREEN_SETTLE_PASSES });
}
})();