Adds an accessible in-game overlay menu with feature toggles, settings controls, and help information for Deadshot.io.
// ==UserScript==
// @name Deadshot.io Accessible Overlay Menu
// @namespace https://deadshot.io/
// @version 1.0.0
// @description Adds an accessible in-game overlay menu with feature toggles, settings controls, and help information for Deadshot.io.
// @author OpenAI
// @match *://deadshot.io/*
// @icon https://deadshot.io/favicon.ico
// @grant none
// @run-at document-idle
// ==/UserScript==
/*
==========================================================
Deadshot.io Accessible Overlay Menu
==========================================================
PURPOSE
-------
This userscript injects a lightweight, keyboard-accessible
overlay menu into Deadshot.io without modifying gameplay logic.
FEATURES
--------
- Floating menu button
- Overlay panel with:
1. Feature Toggles
2. Settings
3. Help / FAQ
- Session-based state persistence
- Accessible controls
- Keyboard navigation
- Minimal performance impact
- Safe DOM isolation
- No external libraries
IMPORTANT NOTES
----------------
- This script intentionally avoids altering game mechanics.
- All example "features" are UI/session-side placeholders.
- Uses sessionStorage so settings reset when the tab/browser closes.
- Uses defensive coding to avoid interfering with the game.
BEST PRACTICES USED
-------------------
- Wrapped in an IIFE to avoid global namespace pollution
- Uses strict mode
- Uses requestAnimationFrame-safe UI logic
- Uses passive-safe event handling where applicable
- Uses semantic buttons and ARIA labels
- Uses event delegation minimally
- Avoids excessive DOM mutation
==========================================================
*/
(function () {
'use strict';
/*
==========================================================
CONFIGURATION
==========================================================
*/
const STORAGE_KEY = 'deadshotio_overlay_menu_state';
/*
==========================================================
DEFAULT SESSION STATE
==========================================================
*/
const defaultState = {
features: {
showFPS: false,
compactMenu: false,
soundAlerts: false
},
settings: {
uiScale: 100,
opacity: 95,
customNickname: ''
}
};
/*
==========================================================
UTILITY FUNCTIONS
==========================================================
*/
/**
* Safely loads session state.
* Falls back to defaults if parsing fails.
*/
function loadState() {
try {
const stored = sessionStorage.getItem(STORAGE_KEY);
if (!stored) {
return structuredClone(defaultState);
}
return {
...structuredClone(defaultState),
...JSON.parse(stored)
};
} catch (error) {
console.warn('[Deadshot Menu] Failed to load state:', error);
return structuredClone(defaultState);
}
}
/**
* Saves current state into sessionStorage.
*/
function saveState() {
try {
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch (error) {
console.warn('[Deadshot Menu] Failed to save state:', error);
}
}
/**
* Creates an HTML element with optional properties.
*/
function createElement(tag, options = {}) {
const element = document.createElement(tag);
if (options.className) {
element.className = options.className;
}
if (options.text) {
element.textContent = options.text;
}
if (options.html) {
element.innerHTML = options.html;
}
if (options.attributes) {
Object.entries(options.attributes).forEach(([key, value]) => {
element.setAttribute(key, value);
});
}
return element;
}
/*
==========================================================
SESSION STATE
==========================================================
*/
const state = loadState();
/*
==========================================================
UI CREATION
==========================================================
*/
/**
* Injects minimal scoped CSS.
* Uses high z-index to stay visible over the game canvas.
*/
function injectStyles() {
const style = createElement('style');
style.textContent = `
#deadshot-overlay-root {
position: fixed;
top: 16px;
right: 16px;
z-index: 999999;
font-family: Arial, sans-serif;
color: #ffffff;
}
#deadshot-menu-button {
background: rgba(20, 20, 20, 0.9);
color: #fff;
border: 1px solid rgba(255,255,255,0.2);
padding: 10px 14px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
transition: background 0.2s ease;
}
#deadshot-menu-button:hover,
#deadshot-menu-button:focus {
background: rgba(50, 50, 50, 0.95);
outline: 2px solid #66b3ff;
}
#deadshot-overlay-panel {
margin-top: 10px;
width: 320px;
max-width: 90vw;
background: rgba(15, 15, 15, 0.96);
border: 1px solid rgba(255,255,255,0.15);
border-radius: 12px;
padding: 16px;
display: none;
backdrop-filter: blur(8px);
box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}
#deadshot-overlay-panel.visible {
display: block;
}
.deadshot-section {
margin-bottom: 18px;
}
.deadshot-section-title {
font-size: 15px;
font-weight: bold;
margin-bottom: 10px;
border-bottom: 1px solid rgba(255,255,255,0.1);
padding-bottom: 4px;
}
.deadshot-toggle-row,
.deadshot-setting-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
gap: 10px;
}
.deadshot-toggle-button,
.deadshot-action-button {
background: rgba(255,255,255,0.08);
color: white;
border: 1px solid rgba(255,255,255,0.15);
border-radius: 6px;
padding: 6px 10px;
cursor: pointer;
transition: background 0.2s ease;
}
.deadshot-toggle-button:hover,
.deadshot-toggle-button:focus,
.deadshot-action-button:hover,
.deadshot-action-button:focus {
background: rgba(255,255,255,0.16);
outline: 2px solid #66b3ff;
}
.deadshot-toggle-active {
background: rgba(0, 160, 80, 0.7);
}
.deadshot-help-text {
font-size: 13px;
line-height: 1.5;
color: rgba(255,255,255,0.88);
}
.deadshot-setting-value {
opacity: 0.85;
font-size: 12px;
}
@media (max-width: 600px) {
#deadshot-overlay-root {
top: 8px;
right: 8px;
}
#deadshot-overlay-panel {
width: 92vw;
}
}
`;
document.head.appendChild(style);
}
/**
* Creates the overlay UI.
*/
function createOverlayMenu() {
const root = createElement('div', {
attributes: {
id: 'deadshot-overlay-root'
}
});
/*
======================================================
MENU TOGGLE BUTTON
======================================================
*/
const menuButton = createElement('button', {
text: 'Menu',
attributes: {
id: 'deadshot-menu-button',
'aria-label': 'Open Deadshot overlay menu',
'aria-expanded': 'false',
type: 'button'
}
});
/*
======================================================
OVERLAY PANEL
======================================================
*/
const panel = createElement('div', {
attributes: {
id: 'deadshot-overlay-panel',
role: 'dialog',
'aria-label': 'Deadshot settings menu',
tabindex: '-1'
}
});
/*
======================================================
FEATURE TOGGLES SECTION
======================================================
*/
const featureSection = createElement('div', {
className: 'deadshot-section'
});
const featureTitle = createElement('div', {
className: 'deadshot-section-title',
text: 'Feature Toggles'
});
featureSection.appendChild(featureTitle);
const featureDefinitions = [
{
key: 'showFPS',
label: 'Show FPS Indicator'
},
{
key: 'compactMenu',
label: 'Compact Menu Layout'
},
{
key: 'soundAlerts',
label: 'Enable Sound Alerts'
}
];
featureDefinitions.forEach((feature) => {
const row = createElement('div', {
className: 'deadshot-toggle-row'
});
const label = createElement('span', {
text: feature.label
});
const button = createElement('button', {
className: 'deadshot-toggle-button',
text: state.features[feature.key] ? 'Enabled' : 'Disabled',
attributes: {
type: 'button',
'aria-pressed': String(state.features[feature.key])
}
});
updateToggleButtonStyle(button, state.features[feature.key]);
button.addEventListener('click', () => {
state.features[feature.key] = !state.features[feature.key];
button.textContent = state.features[feature.key]
? 'Enabled'
: 'Disabled';
button.setAttribute(
'aria-pressed',
String(state.features[feature.key])
);
updateToggleButtonStyle(
button,
state.features[feature.key]
);
saveState();
console.info(
`[Deadshot Menu] ${feature.key}:`,
state.features[feature.key]
);
});
row.appendChild(label);
row.appendChild(button);
featureSection.appendChild(row);
});
/*
======================================================
SETTINGS SECTION
======================================================
*/
const settingsSection = createElement('div', {
className: 'deadshot-section'
});
const settingsTitle = createElement('div', {
className: 'deadshot-section-title',
text: 'Settings'
});
settingsSection.appendChild(settingsTitle);
const settingsDefinitions = [
{
key: 'uiScale',
label: 'UI Scale (%)',
validator: (value) => {
const number = Number(value);
return number >= 50 && number <= 200;
},
parser: Number,
description: 'Enter a number between 50 and 200.'
},
{
key: 'opacity',
label: 'Menu Opacity (%)',
validator: (value) => {
const number = Number(value);
return number >= 30 && number <= 100;
},
parser: Number,
description: 'Enter a number between 30 and 100.'
},
{
key: 'customNickname',
label: 'Custom Nickname',
validator: (value) => value.trim().length <= 20,
parser: String,
description: 'Maximum length: 20 characters.'
}
];
settingsDefinitions.forEach((setting) => {
const row = createElement('div', {
className: 'deadshot-setting-row'
});
const labelContainer = createElement('div');
const label = createElement('div', {
text: setting.label
});
const valueDisplay = createElement('div', {
className: 'deadshot-setting-value',
text: `Current: ${state.settings[setting.key]}`
});
labelContainer.appendChild(label);
labelContainer.appendChild(valueDisplay);
const editButton = createElement('button', {
className: 'deadshot-action-button',
text: 'Edit',
attributes: {
type: 'button'
}
});
editButton.addEventListener('click', () => {
const userInput = prompt(
`${setting.description}\n\nCurrent value: ${state.settings[setting.key]}`,
state.settings[setting.key]
);
// User cancelled prompt
if (userInput === null) {
return;
}
const parsedValue = setting.parser(userInput);
if (!setting.validator(parsedValue)) {
alert('Invalid value entered.');
return;
}
/*
==============================================
CONFIRMATION FOR SENSITIVE SETTINGS
==============================================
*/
const confirmed = confirm(
`Apply new value "${parsedValue}" for "${setting.label}"?`
);
if (!confirmed) {
return;
}
state.settings[setting.key] = parsedValue;
valueDisplay.textContent =
`Current: ${state.settings[setting.key]}`;
saveState();
applyRuntimeSettings();
});
row.appendChild(labelContainer);
row.appendChild(editButton);
settingsSection.appendChild(row);
});
/*
======================================================
HELP SECTION
======================================================
*/
const helpSection = createElement('div', {
className: 'deadshot-section'
});
const helpTitle = createElement('div', {
className: 'deadshot-section-title',
text: 'Help'
});
const helpText = createElement('div', {
className: 'deadshot-help-text',
html: `
<strong>How to use:</strong><br>
• Click the Menu button to open or close the overlay.<br>
• Toggle switches enable or disable UI-side features.<br>
• Settings can be adjusted using prompts.<br>
• Values are stored only for the current session.<br><br>
<strong>Keyboard:</strong><br>
• Press ESC to close the menu.<br>
• Use TAB to navigate buttons.<br><br>
<strong>Safety:</strong><br>
• This menu avoids modifying game mechanics.<br>
• UI is isolated to minimize conflicts.
`
});
helpSection.appendChild(helpTitle);
helpSection.appendChild(helpText);
/*
======================================================
APPEND ALL SECTIONS
======================================================
*/
panel.appendChild(featureSection);
panel.appendChild(settingsSection);
panel.appendChild(helpSection);
root.appendChild(menuButton);
root.appendChild(panel);
document.body.appendChild(root);
/*
======================================================
MENU OPEN/CLOSE LOGIC
======================================================
*/
function toggleMenu(forceState = null) {
const shouldOpen =
forceState !== null
? forceState
: !panel.classList.contains('visible');
panel.classList.toggle('visible', shouldOpen);
menuButton.setAttribute(
'aria-expanded',
String(shouldOpen)
);
if (shouldOpen) {
panel.focus();
}
}
menuButton.addEventListener('click', () => {
toggleMenu();
});
/*
======================================================
KEYBOARD ACCESSIBILITY
======================================================
*/
window.addEventListener('keydown', (event) => {
// Escape closes menu
if (event.key === 'Escape') {
toggleMenu(false);
}
// Optional shortcut: Shift + M
if (event.shiftKey && event.key.toLowerCase() === 'm') {
toggleMenu();
}
});
/*
======================================================
CLICK OUTSIDE TO CLOSE
======================================================
*/
document.addEventListener('click', (event) => {
const clickedInside = root.contains(event.target);
if (!clickedInside) {
toggleMenu(false);
}
});
/*
======================================================
PREVENT MENU CLICKS FROM PROPAGATING
======================================================
*/
panel.addEventListener('click', (event) => {
event.stopPropagation();
});
menuButton.addEventListener('click', (event) => {
event.stopPropagation();
});
}
/*
==========================================================
TOGGLE BUTTON STYLE HELPER
==========================================================
*/
function updateToggleButtonStyle(button, enabled) {
button.classList.toggle('deadshot-toggle-active', enabled);
}
/*
==========================================================
APPLY RUNTIME SETTINGS
==========================================================
*/
/**
* Applies purely visual runtime settings.
* Avoids touching gameplay systems.
*/
function applyRuntimeSettings() {
const panel = document.getElementById('deadshot-overlay-panel');
if (!panel) {
return;
}
panel.style.opacity =
String(state.settings.opacity / 100);
panel.style.transform =
`scale(${state.settings.uiScale / 100})`;
}
/*
==========================================================
INITIALIZATION
==========================================================
*/
function initializeMenu() {
// Prevent duplicate injection
if (document.getElementById('deadshot-overlay-root')) {
return;
}
injectStyles();
createOverlayMenu();
applyRuntimeSettings();
console.info('[Deadshot Menu] Overlay initialized.');
}
/*
==========================================================
SAFE PAGE LOAD HANDLING
==========================================================
*/
window.addEventListener('load', () => {
// Delay slightly to avoid conflicting with
// early game initialization routines.
setTimeout(() => {
initializeMenu();
}, 1200);
});
})();