Skip to content

Instantly share code, notes, and snippets.

@adasThePro
Last active October 9, 2025 15:52
Show Gist options
  • Save adasThePro/1453a2c8ed66c30f3e447dbe70884cdb to your computer and use it in GitHub Desktop.
Save adasThePro/1453a2c8ed66c30f3e447dbe70884cdb to your computer and use it in GitHub Desktop.
Cheat for neal.fun's Not-a-Robot game to jump to any level directly.

Not-a-Robot Level Navigator

A userscript for neal.fun's Not-a-Robot game that allows you to jump to any level directly.

Installation

Install a userscript manager:

Method 1: Direct URL Installation

  1. For Violentmonkey users:
    • Click the Violentmonkey extension icon
    • Click the "+" button to create new script
    • Select "Install from URL"
    • Paste: bit.ly/nnarc and click "Ok"
    • Click "Install" to install the script

Method 2: Manual Installation

  1. Copy the script content from not-a-robot-cheat.js

  2. In your userscript manager:

    • Tampermonkey: Click the extension icon → "Create a new script"
    • Violentmonkey: Click the extension icon → "+" button
  3. Replace the default content with the copied script code

  4. Save the script (Ctrl+S)

Usage

Opening the Level Navigator

Once installed, visit neal.fun/not-a-robot and you'll see:

  1. Levels Button: A new "Levels" button appears instead of reset button
  2. Click the button or press L to open the level navigator

Level Navigator Interface

The navigator shows:

  • Current Level: Your progress and completion percentage
  • Quick Navigation: Previous/Next level buttons
  • Jump to Level: Input field to jump to any specific level (1-48)

Keyboard Shortcuts

Shortcut Action
L Toggle the level navigator
Ctrl + / Show/hide keyboard shortcuts help
Shift + Go to previous level
Shift + Go to next level
Esc Close any open menu
Enter Jump to level (when input is focused)

Quick Navigation

  • Previous/Next Buttons: Navigate one level at a time
  • Jump to Level: Enter any level number (1-48) and click "Jump" or press Enter

Compatibility

  • Tampermonkey (Chrome, Firefox, Edge, Safari, Edge Mobile, Firefox Mobile)
  • Violentmonkey (Chrome, Firefox, Edge, Edge Mobile, Firefox Mobile)

Privacy

  • No external requests - Script runs entirely locally
  • No data collection - Your progress stays on your device
  • Open source - All code is visible and auditable
  • Minimal permissions - Only accesses the game page
// ==UserScript==
// @name Not-a-Robot Level Navigator
// @version 1.4.1
// @description Cheat for neal.fun's Not-a-Robot game to jump to any level directly.
// @author Adas
// @match https://neal.fun/not-a-robot/
// @grant none
// @tag cheat
// @homepageURL https://gist.github.com/adasThePro/1453a2c8ed66c30f3e447dbe70884cdb#file-readme-md
// @source https://gist.github.com/adasThePro/1453a2c8ed66c30f3e447dbe70884cdb#file-not-a-robot-cheat-js
// @updateURL https://gist.githubusercontent.com/adasThePro/1453a2c8ed66c30f3e447dbe70884cdb/raw/meta.js
// @downloadURL https://gist.githubusercontent.com/adasThePro/1453a2c8ed66c30f3e447dbe70884cdb/raw/not-a-robot-cheat.js
// @supportURL https://t.me/Woopes
// ==/UserScript==
// ==UserScript==
// @name Not-a-Robot Level Navigator
// @version 1.4.1
// @description Cheat for neal.fun's Not-a-Robot game to jump to any level directly.
// @author Adas
// @match https://neal.fun/not-a-robot/
// @grant none
// @tag cheat
// @homepageURL https://gist.github.com/adasThePro/1453a2c8ed66c30f3e447dbe70884cdb#file-readme-md
// @source https://gist.github.com/adasThePro/1453a2c8ed66c30f3e447dbe70884cdb#file-not-a-robot-cheat-js
// @updateURL https://gist.githubusercontent.com/adasThePro/1453a2c8ed66c30f3e447dbe70884cdb/raw/meta.js
// @downloadURL https://gist.githubusercontent.com/adasThePro/1453a2c8ed66c30f3e447dbe70884cdb/raw/not-a-robot-cheat.js
// @supportURL https://t.me/Woopes
// ==/UserScript==
(function () {
'use strict';
if (window.levelNavigatorInitialized) return;
window.levelNavigatorInitialized = true;
const CONFIG = {
VERSION: '1.4.1',
LEVEL_RANGE: { MIN: 1, MAX: 48 },
STORAGE_KEY: 'not-a-robot-level',
SHORTCUTS: {
TOGGLE_NAVIGATOR: 'KeyL',
SHOW_SHORTCUTS: 'Slash',
PREVIOUS_LEVEL: 'ArrowLeft',
NEXT_LEVEL: 'ArrowRight'
},
SELECTORS: {
RESET_BUTTON: '.reset',
CHEAT_BUTTON: '.level-nav-btn',
FOOTER_TEXT: '.site-footer-text',
SITE_LEVEL: '.site-level span',
NAV_NOTIFICATION: '.nav-notification',
LEVEL_NAV_OVERLAY: '.level-nav-overlay',
SHORTCUTS_MENU_OVERLAY: '.shortcuts-menu-overlay'
},
COLORS: {
PRIMARY: '#3b82f6',
PRIMARY_HOVER: '#2563eb',
SUCCESS: '#10b981',
SUCCESS_HOVER: '#059669',
DANGER: '#ef4444',
DANGER_HOVER: '#dc2626',
GRAY_50: '#f9fafb',
GRAY_100: '#f3f4f6',
GRAY_200: '#e5e7eb',
GRAY_300: '#d1d5db',
GRAY_400: '#9ca3af',
GRAY_500: '#6b7280',
GRAY_600: '#4b5563',
GRAY_700: '#374151',
GRAY_800: '#1f2937',
GRAY_900: '#111827',
WHITE: '#ffffff'
},
TIMING: {
BUTTON_CHECK_INTERVAL: 200,
MAX_ATTEMPTS: 30,
INITIAL_DELAY: 300,
NOTIFICATION_DURATION: 2500,
ANIMATION_DURATION: 200
}
};
/* ----------------- Utilities ----------------- */
class DOMUtils {
static _fragmentCache = new Map();
static createElement(tag, className = '', styles = {}, attributes = {}) {
const el = document.createElement(tag);
if (className) el.className = className;
if (Object.keys(styles).length) Object.assign(el.style, styles);
if (Object.keys(attributes).length) {
for (const [k, v] of Object.entries(attributes)) el.setAttribute(k, v);
}
return el;
}
static safeRemove(el) {
el?.remove();
}
static queryOrCache(selector) {
return document.querySelector(selector);
}
static createFragment(html) {
if (this._fragmentCache.has(html)) return this._fragmentCache.get(html).cloneNode(true);
const template = document.createElement('template');
template.innerHTML = html;
const fragment = template.content.cloneNode(true);
this._fragmentCache.set(html, fragment);
return fragment.cloneNode(true);
}
}
class Validator {
static validateLevel(value) {
const level = parseInt(value, 10);
const { MIN, MAX } = CONFIG.LEVEL_RANGE;
if (isNaN(level)) return { isValid: false, errorMessage: 'Please enter a valid number' };
if (level < MIN || level > MAX) return { isValid: false, errorMessage: `Level must be between ${MIN} and ${MAX}` };
return { isValid: true, level };
}
}
class StorageManager {
static _cachedLevel = null;
static _isStorageAvailable = null;
static _checkStorageAvailability() {
if (this._isStorageAvailable !== null) return this._isStorageAvailable;
try {
const test = '__storage_test__';
localStorage.setItem(test, test);
localStorage.removeItem(test);
this._isStorageAvailable = true;
} catch {
this._isStorageAvailable = false;
}
return this._isStorageAvailable;
}
static setLevel(level) {
if (!this._checkStorageAvailability()) {
throw new Error('Storage unavailable. Check browser settings.');
}
const value = String(level - 1);
localStorage.setItem(CONFIG.STORAGE_KEY, value);
this._cachedLevel = level;
}
static getLevel() {
if (this._cachedLevel !== null) return this._cachedLevel;
if (!this._checkStorageAvailability()) return 1;
const stored = localStorage.getItem(CONFIG.STORAGE_KEY);
const level = stored ? parseInt(stored, 10) + 1 : 1;
this._cachedLevel = level;
return level;
}
static getCurrentLevelFromDOM() {
const el = DOMUtils.queryOrCache(CONFIG.SELECTORS.SITE_LEVEL);
if (el) {
const match = el.textContent.match(/Level\s*(\d+)/i);
if (match) {
const level = parseInt(match[1], 10);
this._cachedLevel = level;
return level;
}
}
return this.getLevel();
}
static clearCache() {
this._cachedLevel = null;
}
}
class NotificationManager {
static _currentNotification = null;
static _timeoutId = null;
static show(message, type = 'info') {
if (this._currentNotification) {
clearTimeout(this._timeoutId);
DOMUtils.safeRemove(this._currentNotification);
}
const bgColors = {
info: CONFIG.COLORS.GRAY_800,
success: CONFIG.COLORS.SUCCESS,
error: CONFIG.COLORS.DANGER
};
const n = DOMUtils.createElement('div', 'nav-notification', {
position: 'fixed',
bottom: '20px',
left: '50%',
transform: 'translateX(-50%) translateY(100%)',
background: bgColors[type],
color: CONFIG.COLORS.WHITE,
padding: '12px 16px',
borderRadius: '8px',
fontSize: '14px',
fontFamily: 'Segoe UI, system-ui, -apple-system, sans-serif',
zIndex: '1000000',
boxShadow: '0 8px 16px rgba(0,0,0,0.2)',
transition: `transform ${CONFIG.TIMING.ANIMATION_DURATION}ms ease-out`,
maxWidth: '320px',
wordWrap: 'break-word',
border: '1px solid rgba(255,255,255,0.1)',
willChange: 'transform'
});
n.textContent = message;
document.body.appendChild(n);
this._currentNotification = n;
requestAnimationFrame(() => {
n.style.transform = 'translateX(-50%) translateY(0)';
});
this._timeoutId = setTimeout(() => this._hide(n), CONFIG.TIMING.NOTIFICATION_DURATION);
}
static _hide(notification) {
if (!notification.parentNode) return;
notification.style.transform = 'translateX(-50%) translateY(100%)';
setTimeout(() => {
DOMUtils.safeRemove(notification);
if (this._currentNotification === notification) {
this._currentNotification = null;
}
}, CONFIG.TIMING.ANIMATION_DURATION);
}
}
/* ----------------- Level Navigator ----------------- */
class LevelNavigator {
constructor() {
this.currentOverlay = null;
this.shortcutsMenuOverlay = null;
this.levelsEscapeHandler = null;
this.shortcutsEscapeHandler = null;
this.isInitialized = false;
this._installShortcuts();
}
_installShortcuts() {
const handler = (e) => {
if (e.repeat) return;
const { code, ctrlKey, shiftKey, altKey } = e;
const sc = CONFIG.SHORTCUTS;
const tag = e.target.tagName;
const isInputElement = tag === 'INPUT' || tag === 'TEXTAREA' || e.target.isContentEditable;
const shortcuts = {
[`${sc.TOGGLE_NAVIGATOR}:false:false:false`]: () => this.toggleLevelDialog(),
[`${sc.SHOW_SHORTCUTS}:true:false:false`]: () => this.toggleShortcutsMenu(),
[`${sc.PREVIOUS_LEVEL}:false:true:false`]: () => this.navigateToLevel(-1),
[`${sc.NEXT_LEVEL}:false:true:false`]: () => this.navigateToLevel(1)
};
const key = `${code}:${ctrlKey}:${shiftKey}:${altKey}`;
const action = shortcuts[key];
if (action) {
const isNavigationShortcut = code === sc.PREVIOUS_LEVEL || code === sc.NEXT_LEVEL;
const hasModifiers = ctrlKey || shiftKey || altKey;
if (isInputElement && !hasModifiers && !isNavigationShortcut) {
return;
}
e.preventDefault();
e.stopPropagation();
action();
}
};
document.addEventListener('keydown', handler, { passive: false });
}
toggleLevelDialog() {
if (this.currentOverlay) this.closeDialog();
else this.showLevelDialog();
}
showLevelDialog() {
if (this.currentOverlay) return;
const overlay = this._createOverlay((evt) => {
if (evt.target === overlay) this.closeDialog();
});
const dialog = this._createDialog();
overlay.appendChild(dialog);
document.body.appendChild(overlay);
this.currentOverlay = overlay;
requestAnimationFrame(() => {
overlay.style.opacity = '1';
dialog.style.transform = 'scale(1)';
});
const input = dialog.querySelector('input[type="number"]');
}
_createOverlay(onClick) {
const overlay = DOMUtils.createElement('div', 'level-nav-overlay', {
position: 'fixed',
top: '0',
left: '0',
width: '100vw',
height: '100vh',
background: 'rgba(0,0,0,0.6)',
zIndex: '999999',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '16px',
boxSizing: 'border-box',
opacity: '0',
transition: 'opacity 0.2s ease'
});
overlay.addEventListener('click', onClick);
this.levelsEscapeHandler = (e) => {
if (e.key === 'Escape') {
e.stopPropagation();
this.closeDialog();
}
};
document.addEventListener('keydown', this.levelsEscapeHandler);
return overlay;
}
_createDialog() {
const dialog = DOMUtils.createElement('div', 'level-nav-dialog', {
background: CONFIG.COLORS.WHITE,
borderRadius: '12px',
padding: '24px',
boxShadow: '0 20px 25px rgba(0,0,0,0.08)',
fontFamily: 'system-ui, -apple-system, sans-serif',
width: '100%',
maxWidth: '420px',
maxHeight: '90vh',
overflowY: 'auto',
transform: 'scale(0.95)',
transition: `transform ${CONFIG.TIMING.ANIMATION_DURATION}ms ease`,
position: 'relative',
willChange: 'transform'
});
const fragment = document.createDocumentFragment();
const closeButton = this._createCloseButton();
closeButton.setAttribute('aria-label', 'Close levels dialog');
fragment.appendChild(closeButton);
fragment.appendChild(this._createHeader());
fragment.appendChild(this._createCurrentLevelSection());
fragment.appendChild(this._createNavigationSection());
fragment.appendChild(this._createJumpSection());
fragment.appendChild(this._createFooter());
dialog.appendChild(fragment);
return dialog;
}
_createHeader() {
const header = DOMUtils.createElement('div', '', {
marginBottom: '18px',
textAlign: 'center',
position: 'relative'
});
const title = DOMUtils.createElement('h2', '', {
margin: '0 0 8px 0',
color: CONFIG.COLORS.GRAY_900,
fontSize: '20px',
fontWeight: '600'
});
title.textContent = 'Levels';
const infoButton = DOMUtils.createElement('button', '', {
position: 'absolute',
top: '0',
left: '0',
background: CONFIG.COLORS.GRAY_100,
border: `1px solid ${CONFIG.COLORS.GRAY_200}`,
borderRadius: '50%',
width: '28px',
height: '28px',
fontSize: '14px',
fontWeight: 'bold',
color: CONFIG.COLORS.GRAY_600,
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'all 0.15s ease',
zIndex: '5',
pointerEvents: 'auto'
}, { type: 'button', 'aria-label': 'Show keyboard shortcuts' });
infoButton.textContent = '?';
infoButton.addEventListener('mouseenter', () => {
infoButton.style.backgroundColor = CONFIG.COLORS.GRAY_200;
infoButton.style.borderColor = CONFIG.COLORS.GRAY_300;
});
infoButton.addEventListener('mouseleave', () => {
infoButton.style.backgroundColor = CONFIG.COLORS.GRAY_100;
infoButton.style.borderColor = CONFIG.COLORS.GRAY_200;
});
infoButton.addEventListener('click', () => this.toggleShortcutsMenu());
header.appendChild(title);
header.appendChild(infoButton);
return header;
}
_createCurrentLevelSection() {
const section = DOMUtils.createElement('div', '', {
background: `linear-gradient(135deg, ${CONFIG.COLORS.PRIMARY}08, ${CONFIG.COLORS.SUCCESS}08)`,
border: `1px solid ${CONFIG.COLORS.GRAY_200}`,
borderRadius: '12px',
padding: '18px',
marginBottom: '18px',
textAlign: 'center'
});
const label = DOMUtils.createElement('div', '', {
fontSize: '12px',
color: CONFIG.COLORS.GRAY_500,
marginBottom: '8px',
textTransform: 'uppercase',
letterSpacing: '0.8px',
fontWeight: '600'
});
label.textContent = 'Current Level';
const currentLevel = DOMUtils.createElement('div', '', {
fontSize: '36px',
fontWeight: '700',
color: CONFIG.COLORS.PRIMARY,
marginBottom: '4px'
});
const cur = StorageManager.getCurrentLevelFromDOM();
currentLevel.textContent = cur;
const progress = DOMUtils.createElement('div', '', {
fontSize: '13px',
color: CONFIG.COLORS.GRAY_600
});
const percentage = Math.round((cur / CONFIG.LEVEL_RANGE.MAX) * 100);
progress.textContent = `${percentage}% complete (${cur}/${CONFIG.LEVEL_RANGE.MAX})`;
section.appendChild(label);
section.appendChild(currentLevel);
section.appendChild(progress);
return section;
}
_createNavigationSection() {
const section = DOMUtils.createElement('div', '', { marginBottom: '18px' });
const title = DOMUtils.createElement('h3', '', {
margin: '0 0 12px 0',
fontSize: '16px',
fontWeight: '600',
color: CONFIG.COLORS.GRAY_800,
display: 'flex',
alignItems: 'center',
gap: '6px'
});
title.innerHTML = '⚡ Quick Navigation';
const navGrid = DOMUtils.createElement('div', '', {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: '10px'
});
const cur = StorageManager.getCurrentLevelFromDOM();
const prevBtn = this._createNavButton('← Previous', 'previous', () => this.navigateToLevel(-1));
const nextBtn = this._createNavButton('Next →', 'next', () => this.navigateToLevel(1));
if (cur <= 1) {
prevBtn.disabled = true;
Object.assign(prevBtn.style, { opacity: '0.45', cursor: 'not-allowed' });
}
if (cur >= CONFIG.LEVEL_RANGE.MAX) {
nextBtn.disabled = true;
Object.assign(nextBtn.style, { opacity: '0.45', cursor: 'not-allowed' });
}
navGrid.appendChild(prevBtn);
navGrid.appendChild(nextBtn);
section.appendChild(title);
section.appendChild(navGrid);
return section;
}
_createNavButton(text, type, onClick) {
const isPrev = type === 'previous';
const base = isPrev ? CONFIG.COLORS.GRAY_600 : CONFIG.COLORS.SUCCESS;
const hover = isPrev ? CONFIG.COLORS.GRAY_700 : CONFIG.COLORS.SUCCESS_HOVER;
const btn = DOMUtils.createElement('button', '', {
padding: '12px 14px',
fontSize: '14px',
fontFamily: 'system-ui, -apple-system, sans-serif',
fontWeight: '600',
border: `2px solid ${base}`,
borderRadius: '10px',
cursor: 'pointer',
transition: 'all 0.14s ease',
outline: 'none',
background: 'transparent',
color: base,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '6px',
minHeight: '44px'
}, { type: 'button' });
btn.textContent = text;
btn.addEventListener('mouseenter', () => {
if (btn.disabled) return;
btn.style.backgroundColor = base;
btn.style.color = CONFIG.COLORS.WHITE;
btn.style.transform = 'translateY(-2px)';
btn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.12)';
});
btn.addEventListener('mouseleave', () => {
if (btn.disabled) return;
btn.style.backgroundColor = 'transparent';
btn.style.color = base;
btn.style.transform = 'translateY(0)';
btn.style.boxShadow = 'none';
});
btn.addEventListener('focus', () => {
btn.style.outline = `2px solid ${base}`;
btn.style.outlineOffset = '2px';
});
btn.addEventListener('blur', () => (btn.style.outline = 'none'));
btn.addEventListener('click', (e) => {
e.preventDefault();
onClick();
});
return btn;
}
_createCloseButton() {
const btn = DOMUtils.createElement('button', '', {
position: 'absolute',
top: '12px',
right: '12px',
background: 'transparent',
border: 'none',
fontSize: '20px',
cursor: 'pointer',
color: CONFIG.COLORS.GRAY_400,
width: '36px',
height: '36px',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'all 0.12s ease',
padding: '0',
zIndex: '10',
pointerEvents: 'auto'
}, { type: 'button' });
btn.innerHTML = '×';
btn.addEventListener('mouseenter', () => {
btn.style.color = CONFIG.COLORS.GRAY_600;
btn.style.backgroundColor = CONFIG.COLORS.GRAY_100;
});
btn.addEventListener('mouseleave', () => {
btn.style.color = CONFIG.COLORS.GRAY_400;
btn.style.backgroundColor = 'transparent';
});
btn.addEventListener('click', () => this.closeDialog());
return btn;
}
_createJumpSection() {
const section = DOMUtils.createElement('div', '', {});
const title = DOMUtils.createElement('h3', '', {
margin: '0 0 12px 0',
fontSize: '16px',
fontWeight: '600',
color: CONFIG.COLORS.GRAY_800,
display: 'flex',
alignItems: 'center',
gap: '6px'
});
title.innerHTML = '🚀 Jump to Level';
const inputGroup = DOMUtils.createElement('div', '', {
display: 'flex',
gap: '10px',
alignItems: 'stretch'
});
const input = DOMUtils.createElement('input', '', {
width: '100%',
padding: '12px 14px',
border: `2px solid ${CONFIG.COLORS.GRAY_300}`,
borderRadius: '10px',
fontSize: '16px',
fontFamily: 'system-ui, -apple-system, sans-serif',
outline: 'none',
transition: 'border-color 0.12s ease',
boxSizing: 'border-box'
}, {
type: 'number',
min: CONFIG.LEVEL_RANGE.MIN.toString(),
max: CONFIG.LEVEL_RANGE.MAX.toString(),
placeholder: `Enter level (1-${CONFIG.LEVEL_RANGE.MAX})`
});
input.addEventListener('focus', () => (input.style.borderColor = CONFIG.COLORS.PRIMARY));
input.addEventListener('blur', () => (input.style.borderColor = CONFIG.COLORS.GRAY_300));
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
this.handleJumpToLevel();
}
});
const jumpButton = DOMUtils.createElement('button', '', {
padding: '12px 16px',
fontSize: '14px',
fontFamily: 'system-ui, -apple-system, sans-serif',
fontWeight: '600',
border: 'none',
borderRadius: '10px',
cursor: 'pointer',
transition: 'all 0.12s ease',
outline: 'none',
background: CONFIG.COLORS.PRIMARY,
color: CONFIG.COLORS.WHITE,
whiteSpace: 'nowrap'
}, { type: 'button' });
jumpButton.textContent = 'Jump';
jumpButton.addEventListener('mouseenter', () => (jumpButton.style.backgroundColor = CONFIG.COLORS.PRIMARY_HOVER));
jumpButton.addEventListener('mouseleave', () => (jumpButton.style.backgroundColor = CONFIG.COLORS.PRIMARY));
jumpButton.addEventListener('click', (e) => {
e.preventDefault();
this.handleJumpToLevel();
});
inputGroup.appendChild(input);
inputGroup.appendChild(jumpButton);
section.appendChild(title);
section.appendChild(inputGroup);
return section;
}
_createFooter() {
const footerHtml = `
<div style="
margin: 16px -24px -24px -24px;
padding: 12px 24px;
border-top: 1px solid ${CONFIG.COLORS.GRAY_200};
text-align: center;
background: linear-gradient(135deg, ${CONFIG.COLORS.GRAY_50}, ${CONFIG.COLORS.WHITE});
border-radius: 0 0 12px 12px;
">
<div style="
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
flex-wrap: wrap;
">
<span style="
font-size: 11px;
color: ${CONFIG.COLORS.GRAY_500};
font-family: Segoe UI, system-ui, -apple-system, sans-serif;
font-weight: 500;
">v${CONFIG.VERSION}</span>
<span style="color: ${CONFIG.COLORS.GRAY_300}; font-size: 11px;">•</span>
<span style="
font-size: 11px;
color: ${CONFIG.COLORS.GRAY_500};
font-family: Segoe UI, system-ui, -apple-system, sans-serif;
font-weight: 500;
">© ${new Date().getFullYear()} Adas</span>
</div>
</div>
`;
return DOMUtils.createFragment(footerHtml).firstElementChild;
}
navigateToLevel(direction) {
const current = StorageManager.getCurrentLevelFromDOM();
const target = current + direction;
const v = Validator.validateLevel(target);
if (!v.isValid) {
NotificationManager.show(v.errorMessage, 'error');
return;
}
try {
StorageManager.setLevel(v.level);
if (this.currentOverlay) this.closeDialog();
NotificationManager.show(`Jumping to Level ${v.level}`, 'success');
setTimeout(() => this.reloadPage(), 600);
} catch (err) {
NotificationManager.show(err.message, 'error');
}
}
handleJumpToLevel() {
const input = this.currentOverlay?.querySelector('input[type="number"]');
if (!input) return;
const v = Validator.validateLevel(input.value);
if (!v.isValid) {
NotificationManager.show(v.errorMessage, 'error');
input.focus();
return;
}
try {
StorageManager.setLevel(v.level);
this.closeDialog();
NotificationManager.show(`Jumping to Level ${v.level}`, 'success');
setTimeout(() => this.reloadPage(), 600);
} catch (err) {
NotificationManager.show(err.message, 'error');
}
}
closeDialog() {
if (!this.currentOverlay) return;
if (this.levelsEscapeHandler) {
document.removeEventListener('keydown', this.levelsEscapeHandler);
this.levelsEscapeHandler = null;
}
const dialog = this.currentOverlay.querySelector('.level-nav-dialog');
this.currentOverlay.style.opacity = '0';
if (dialog) dialog.style.transform = 'scale(0.95)';
setTimeout(() => {
DOMUtils.safeRemove(this.currentOverlay);
this.currentOverlay = null;
}, 180);
}
toggleShortcutsMenu() {
if (this.shortcutsMenuOverlay) this.closeShortcutsMenu();
else this.showShortcutsMenu();
}
showShortcutsMenu() {
if (this.shortcutsMenuOverlay) return;
const overlay = this._createShortcutsOverlay();
const menu = this._createShortcutsMenu();
overlay.appendChild(menu);
document.body.appendChild(overlay);
this.shortcutsMenuOverlay = overlay;
requestAnimationFrame(() => {
overlay.style.opacity = '1';
menu.style.transform = 'scale(1)';
});
}
_createShortcutsOverlay() {
const overlay = DOMUtils.createElement('div', 'shortcuts-menu-overlay', {
position: 'fixed',
top: '0',
left: '0',
width: '100vw',
height: '100vh',
background: 'rgba(0,0,0,0.6)',
zIndex: '1000000',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '16px',
boxSizing: 'border-box',
opacity: '0',
transition: 'opacity 0.18s ease'
});
overlay.addEventListener('click', (e) => {
if (e.target === overlay) this.closeShortcutsMenu();
});
this.shortcutsEscapeHandler = (e) => {
if (e.key === 'Escape' || (e.code === 'Slash' && e.ctrlKey && !e.repeat)) {
e.stopPropagation();
this.closeShortcutsMenu();
}
};
document.addEventListener('keydown', this.shortcutsEscapeHandler);
return overlay;
}
_createShortcutsMenu() {
const menu = DOMUtils.createElement('div', 'shortcuts-menu', {
background: CONFIG.COLORS.WHITE,
borderRadius: '12px',
padding: '24px',
boxShadow: '0 20px 25px rgba(0,0,0,0.08)',
fontFamily: 'system-ui, -apple-system, sans-serif',
width: '100%',
maxWidth: '400px',
transform: 'scale(0.95)',
transition: `transform ${CONFIG.TIMING.ANIMATION_DURATION}ms ease`,
position: 'relative',
willChange: 'transform'
});
const header = DOMUtils.createElement('div', '', { marginBottom: '20px', textAlign: 'center' });
const title = DOMUtils.createElement('h2', '', {
margin: '0 0 8px 0',
color: CONFIG.COLORS.GRAY_900,
fontSize: '18px',
fontWeight: '600'
});
title.textContent = 'Shortcuts';
const closeButton = DOMUtils.createElement('button', '', {
position: 'absolute',
top: '12px',
right: '12px',
background: 'transparent',
border: 'none',
fontSize: '20px',
cursor: 'pointer',
color: CONFIG.COLORS.GRAY_400,
width: '36px',
height: '36px',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'all 0.12s ease',
padding: '0'
}, { type: 'button', 'aria-label': 'Close shortcuts menu' });
closeButton.innerHTML = '×';
closeButton.addEventListener('mouseenter', () => {
closeButton.style.color = CONFIG.COLORS.GRAY_600;
closeButton.style.backgroundColor = CONFIG.COLORS.GRAY_100;
});
closeButton.addEventListener('mouseleave', () => {
closeButton.style.color = CONFIG.COLORS.GRAY_400;
closeButton.style.backgroundColor = 'transparent';
});
closeButton.addEventListener('click', () => this.closeShortcutsMenu());
const createKbd = (txt) => {
const k = DOMUtils.createElement('kbd', '', {
padding: '4px 8px',
background: CONFIG.COLORS.GRAY_100,
borderRadius: '4px',
fontSize: '12px',
fontFamily: 'monospace',
border: `1px solid ${CONFIG.COLORS.GRAY_200}`,
minWidth: '32px',
textAlign: 'center',
display: 'inline-block'
});
k.textContent = txt;
return k;
};
const shortcuts = [
{ keys: ['L'], description: 'Toggle Levels menu' },
{ keys: ['Ctrl', '/'], description: 'Show/Hide this shortcuts menu' },
{ keys: ['Shift', '←'], description: 'Previous Level' },
{ keys: ['Shift', '→'], description: 'Next Level' },
{ keys: ['Esc'], description: 'Close any open menu' }
];
const list = DOMUtils.createElement('div', '', { display: 'flex', flexDirection: 'column', gap: '12px' });
shortcuts.forEach((sc) => {
const row = DOMUtils.createElement('div', '', { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 0' });
const keysContainer = DOMUtils.createElement('div', '', { display: 'flex', alignItems: 'center', gap: '6px' });
sc.keys.forEach((key, idx) => {
if (idx > 0) {
const plus = DOMUtils.createElement('span', '', { color: CONFIG.COLORS.GRAY_400, fontSize: '12px', margin: '0 2px' });
plus.textContent = '+';
keysContainer.appendChild(plus);
}
keysContainer.appendChild(createKbd(key));
});
const desc = DOMUtils.createElement('span', '', { fontSize: '14px', color: CONFIG.COLORS.GRAY_700, flex: '1', textAlign: 'right', marginLeft: '16px' });
desc.textContent = sc.description;
row.appendChild(keysContainer);
row.appendChild(desc);
list.appendChild(row);
});
const footer = DOMUtils.createElement('div', '', {
marginTop: '20px',
paddingTop: '12px',
borderTop: `1px solid ${CONFIG.COLORS.GRAY_200}`,
textAlign: 'center',
background: `linear-gradient(135deg, ${CONFIG.COLORS.GRAY_50}, ${CONFIG.COLORS.WHITE})`,
borderRadius: '0 0 12px 12px',
margin: '20px -24px -24px -24px',
padding: '12px 24px'
});
const container = DOMUtils.createElement('div', '', {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '4px',
flexWrap: 'wrap'
});
const versionText = DOMUtils.createElement('span', '', {
fontSize: '11px',
color: CONFIG.COLORS.GRAY_500,
fontFamily: 'Segoe UI, system-ui, -apple-system, sans-serif',
fontWeight: '500'
});
versionText.textContent = `v${CONFIG.VERSION}`;
const separator = DOMUtils.createElement('span', '', {
color: CONFIG.COLORS.GRAY_300,
fontSize: '11px'
});
separator.textContent = '•';
const copyrightText = DOMUtils.createElement('span', '', {
fontSize: '11px',
color: CONFIG.COLORS.GRAY_500,
fontFamily: 'Segoe UI, system-ui, -apple-system, sans-serif',
fontWeight: '500'
});
copyrightText.textContent = `© ${new Date().getFullYear()} Adas`;
container.appendChild(versionText);
container.appendChild(separator);
container.appendChild(copyrightText);
footer.appendChild(container);
header.appendChild(title);
menu.appendChild(closeButton);
menu.appendChild(header);
menu.appendChild(list);
menu.appendChild(footer);
return menu;
}
closeShortcutsMenu() {
if (!this.shortcutsMenuOverlay) return;
if (this.shortcutsEscapeHandler) {
document.removeEventListener('keydown', this.shortcutsEscapeHandler);
this.shortcutsEscapeHandler = null;
}
const menu = this.shortcutsMenuOverlay.querySelector('.shortcuts-menu');
this.shortcutsMenuOverlay.style.opacity = '0';
if (menu) menu.style.transform = 'scale(0.95)';
setTimeout(() => {
DOMUtils.safeRemove(this.shortcutsMenuOverlay);
this.shortcutsMenuOverlay = null;
}, 160);
}
createNavigationButton() {
const btn = DOMUtils.createElement('button', 'level-nav-btn', {
background: CONFIG.COLORS.WHITE,
cursor: 'pointer',
padding: '10px 16px',
color: CONFIG.COLORS.GRAY_700,
fontSize: '14px',
fontFamily: 'system-ui, -apple-system, sans-serif',
fontWeight: '500',
border: `1px solid ${CONFIG.COLORS.GRAY_300}`,
borderRadius: '8px',
transition: 'all 0.15s ease',
outline: 'none',
display: 'flex',
alignItems: 'center',
gap: '6px'
}, { type: 'button', 'aria-label': 'Open level navigator' });
btn.textContent = 'Levels';
btn.addEventListener('mouseenter', () => {
btn.style.backgroundColor = CONFIG.COLORS.GRAY_50;
btn.style.borderColor = CONFIG.COLORS.GRAY_400;
btn.style.transform = 'translateY(-1px)';
});
btn.addEventListener('mouseleave', () => {
btn.style.backgroundColor = CONFIG.COLORS.WHITE;
btn.style.borderColor = CONFIG.COLORS.GRAY_300;
btn.style.transform = 'translateY(0)';
});
btn.addEventListener('focus', () => {
btn.style.outline = `2px solid ${CONFIG.COLORS.PRIMARY}`;
btn.style.outlineOffset = '2px';
});
btn.addEventListener('blur', () => (btn.style.outline = 'none'));
btn.addEventListener('click', () => this.toggleLevelDialog());
return btn;
}
integrateButton() {
const resetButton = document.querySelector(CONFIG.SELECTORS.RESET_BUTTON);
const navButton = this.createNavigationButton();
if (resetButton && resetButton.parentNode) {
try {
const wrapper = DOMUtils.createElement('div', 'nav-button-wrapper', {
display: 'inline-flex',
alignItems: 'center'
});
wrapper.appendChild(navButton);
resetButton.parentNode.replaceChild(wrapper, resetButton);
Object.assign(navButton.style, { background: 'transparent', border: 'none', borderRadius: '0', color: '#191919', fontSize: '15px' });
this.isInitialized = true;
return true;
} catch (err) {
console.warn('Level Navigator: failed to replace reset button, falling back to footer insertion', err);
}
}
const footerText = document.querySelector(CONFIG.SELECTORS.FOOTER_TEXT);
if (!footerText || document.querySelector(CONFIG.SELECTORS.CHEAT_BUTTON)) return false;
const parent = footerText.parentNode;
if (!parent) return false;
const wrapper = DOMUtils.createElement('div', 'nav-button-wrapper', {
display: 'flex',
alignItems: 'center',
marginRight: '12px'
});
wrapper.appendChild(navButton);
try {
parent.insertBefore(wrapper, footerText);
const computed = window.getComputedStyle(parent);
if (computed.display === 'block') {
parent.style.display = 'flex';
parent.style.justifyContent = 'space-between';
parent.style.alignItems = 'center';
}
} catch (err) {
parent.appendChild(wrapper);
}
Object.assign(navButton.style, { background: 'transparent', border: 'none', borderRadius: '0', color: '#191919', fontSize: '15px' });
this.isInitialized = true;
return true;
}
reloadPage() {
window.location.reload();
}
}
/* ---------------- Orchestrator ---------------- */
class App {
constructor() {
this.navigator = new LevelNavigator();
this.attempts = 0;
}
initialize() {
setTimeout(() => this._tryIntegrate(), CONFIG.TIMING.INITIAL_DELAY);
}
_tryIntegrate() {
const tryFn = () => {
if (this.attempts >= CONFIG.TIMING.MAX_ATTEMPTS) {
console.warn('Level Navigator: Failed to initialize after maximum attempts');
return;
}
if (this.navigator.integrateButton()) {
console.log('Level Navigator: Initialized');
const welcomeKey = 'levelNavWelcomeShown';
if (!sessionStorage.getItem(welcomeKey)) {
sessionStorage.setItem(welcomeKey, 'true');
setTimeout(() => {
NotificationManager.show('Level navigator initialized! Press L to toggle, Ctrl+/ for shortcuts');
}, CONFIG.TIMING.NOTIFICATION_DURATION);
}
return;
}
this.attempts++;
setTimeout(tryFn, CONFIG.TIMING.BUTTON_CHECK_INTERVAL);
};
tryFn();
}
}
const app = new App();
app.initialize();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment