Vibrant colours, 240 FPS cap, Unity quality boost, custom tab icon/title, and bloat removal for the Subway Surfers Unity page.
// ==UserScript==
// @name surfer
// @namespace https://greasyfork.org/
// @version 1.4
// @description Vibrant colours, 240 FPS cap, Unity quality boost, custom tab icon/title, and bloat removal for the Subway Surfers Unity page.
// @author You
// @match https://yell0wsuit.page/assets/games/subway-surfers-unity/index.html
// @match *://*/*
// @grant none
// @run-at document-star
// @license MIT
// ==/UserScript==
(function () {
'use strict';
/* ─────────────────────────────────────────────
1. VIBRANT COLORS (applies to every matched page)
───────────────────────────────────────────────*/
const SATURATION = 1.30;
const CONTRAST = 1.08;
const BRIGHTNESS = 1.02;
function injectColorFilter () {
const style = document.createElement('style');
style.id = 'ys-vibrant-filter';
style.textContent = `
html {
filter: saturate(${SATURATION}) contrast(${CONTRAST}) brightness(${BRIGHTNESS}) !important;
}
::-webkit-scrollbar { filter: none !important; }
`;
(document.head || document.documentElement).appendChild(style);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', injectColorFilter, { once: true });
} else {
injectColorFilter();
}
/* ─────────────────────────────────────────────
SUBWAY SURFERS ONLY BELOW
───────────────────────────────────────────────*/
const TARGET_PATH = '/assets/games/subway-surfers-unity/index.html';
const FPS_CAP = 240;
const FRAME_MIN_MS = 1000 / FPS_CAP;
const CUSTOM_ICON = 'https://purepng.com/public/uploads/large/purepng.com-moonmoonskyrealisticnightblack-and-white-591521584248xjtz1.png';
const CUSTOM_TITLE = 'surf';
const isSubwaySurfers =
location.hostname === 'yell0wsuit.page' &&
location.pathname === TARGET_PATH;
if (!isSubwaySurfers) return;
/* ─────────────────────────────────────────────
2. CUSTOM TAB ICON
Removes all existing favicons and injects ours.
A MutationObserver fights back if the page tries
to restore its own icon.
───────────────────────────────────────────────*/
function setFavicon () {
// Nuke every existing favicon link
document.querySelectorAll('link[rel*="icon"]').forEach(el => el.remove());
const link = document.createElement('link');
link.rel = 'icon';
link.type = 'image/png';
link.href = CUSTOM_ICON;
link.id = 'ys-custom-favicon';
document.head.appendChild(link);
}
/* ─────────────────────────────────────────────
3. CUSTOM TAB TITLE
Overwrites document.title and keeps it locked
via a property descriptor + MutationObserver.
───────────────────────────────────────────────*/
function lockTitle () {
// Override the title property so any JS assignment is intercepted
Object.defineProperty(document, 'title', {
get () { return CUSTOM_TITLE; },
set () { /* swallow any attempt to change it */ },
configurable: true,
});
document.querySelector('title') && (document.querySelector('title').textContent = CUSTOM_TITLE);
}
/* ─────────────────────────────────────────────
4. MUTATION OBSERVER — guard title & favicon
The page or Unity loader may insert new <title>
or <link rel="icon"> nodes after boot.
───────────────────────────────────────────────*/
function installHeadGuard () {
setFavicon();
lockTitle();
const observer = new MutationObserver(mutations => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (node.nodeType !== 1) continue;
// Kill any injected favicon that isn't ours
if (node.tagName === 'LINK' && node.rel && node.rel.includes('icon') && node.id !== 'ys-custom-favicon') {
node.remove();
setFavicon(); // re-ensure ours is present
}
// Kill any injected <title>
if (node.tagName === 'TITLE') {
node.textContent = CUSTOM_TITLE;
}
}
// If characterData changed on an existing title node
if (m.type === 'characterData' && m.target.parentElement && m.target.parentElement.tagName === 'TITLE') {
m.target.textContent = CUSTOM_TITLE;
}
}
});
observer.observe(document.head || document.documentElement, {
childList: true,
subtree: true,
characterData: true,
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', installHeadGuard, { once: true });
} else {
installHeadGuard();
}
/* ─────────────────────────────────────────────
5. BLOAT REMOVAL
Kills things that waste CPU/memory/network on
a game page where none of them are needed:
• Google Analytics / Tag Manager
• Facebook Pixel
• Twitter/X widgets
• Hotjar, Mixpanel, Segment, Amplitude
• Intercom, Zendesk, Drift chat widgets
• Push-notification prompts
• Autoplaying background music/video (non-canvas)
• Cookie consent banners
• Any third-party ad scripts
───────────────────────────────────────────────*/
// Block list — script src substrings to kill before they load
const BLOCKED_SCRIPT_PATTERNS = [
'google-analytics', 'googletagmanager', 'gtag',
'facebook.net', 'connect.facebook',
'platform.twitter', 'widgets.js',
'hotjar', 'mixpanel', 'segment.io', 'segment.com', 'amplitude',
'intercom', 'zendesk', 'drift.com',
'onesignal', 'pushcrew', 'pushwoosh',
'cookiebot', 'cookieconsent', 'onetrust', 'trustarc',
'doubleclick', 'googlesyndication', 'adsbygoogle',
'disqus', 'livechat', 'tawk.to',
];
// Intercept script injection via document.createElement
const _origCreateElement = document.createElement.bind(document);
document.createElement = function (tag, opts) {
const el = _origCreateElement(tag, opts);
if (tag.toLowerCase() === 'script') {
// Watch for src assignment and block if it matches
let _src = '';
Object.defineProperty(el, 'src', {
get () { return _src; },
set (val) {
if (BLOCKED_SCRIPT_PATTERNS.some(p => val.includes(p))) {
console.info('[Enhancer] Blocked bloat script:', val);
return; // drop it
}
_src = val;
el.setAttribute('src', val);
},
configurable: true,
});
}
return el;
};
// Also nuke any already-present bloat scripts / iframes on DOMContentLoaded
function removeBloatNodes () {
// Scripts
document.querySelectorAll('script[src]').forEach(s => {
if (BLOCKED_SCRIPT_PATTERNS.some(p => s.src.includes(p))) {
s.remove();
console.info('[Enhancer] Removed bloat script:', s.src);
}
});
// Iframes (ads, chat widgets, consent modals)
document.querySelectorAll('iframe').forEach(f => {
if (BLOCKED_SCRIPT_PATTERNS.some(p => (f.src || '').includes(p))) {
f.remove();
}
});
// Cookie / GDPR banners — common class/id patterns
const bannerSelectors = [
'#cookie-banner', '#cookie-notice', '#cookie-law-info-bar',
'#cookieconsent', '.cookieconsent', '.cookie-banner', '.cookie-notice',
'#onetrust-banner-sdk', '#onetrust-consent-sdk',
'#CybotCookiebotDialog', '.cc-window',
'#gdpr-cookie-notice', '.gdpr-banner',
];
bannerSelectors.forEach(sel => {
document.querySelectorAll(sel).forEach(el => el.remove());
});
// Mute / pause any <audio> or <video> elements that aren't in a canvas context
document.querySelectorAll('audio, video').forEach(media => {
if (!media.closest('canvas')) {
media.pause();
media.muted = true;
media.src = '';
}
});
}
// Run on DOM ready + again after full load (some widgets inject late)
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', removeBloatNodes, { once: true });
} else {
removeBloatNodes();
}
window.addEventListener('load', removeBloatNodes);
// Continuously prune late-injected bloat nodes
const bloatObserver = new MutationObserver(() => {
document.querySelectorAll('script[src]').forEach(s => {
if (BLOCKED_SCRIPT_PATTERNS.some(p => s.src.includes(p))) s.remove();
});
document.querySelectorAll('iframe').forEach(f => {
if (BLOCKED_SCRIPT_PATTERNS.some(p => (f.src || '').includes(p))) f.remove();
});
});
bloatObserver.observe(document.documentElement, { childList: true, subtree: true });
/* ─────────────────────────────────────────────
6. 240 FPS CAP
───────────────────────────────────────────────*/
const _raf = window.requestAnimationFrame.bind(window);
let lastTime = 0;
window.requestAnimationFrame = function (callback) {
return _raf(function (now) {
if (now - lastTime >= FRAME_MIN_MS) {
lastTime = now;
callback(now);
} else {
window.requestAnimationFrame(callback);
}
});
};
/* ─────────────────────────────────────────────
7. UNITY QUALITY + CANVAS BOOST
───────────────────────────────────────────────*/
function applyUnityQuality (instance) {
try { instance.SendMessage('Main Camera', 'SetQualityLevel', '5'); } catch (_) {}
try { instance.Module.ccall('SetQualityLevel', null, ['number'], [5]); } catch (_) {}
}
let _unityInstance = null;
Object.defineProperty(window, 'unityInstance', {
configurable: true,
get () { return _unityInstance; },
set (v) {
_unityInstance = v;
setTimeout(() => applyUnityQuality(v), 3000);
}
});
function patchCreateUnity (fn) {
return async function (...args) {
if (args[1] && typeof args[1] === 'object') {
args[1].devicePixelRatio = window.devicePixelRatio || 1;
}
const inst = await fn.apply(this, args);
setTimeout(() => applyUnityQuality(inst), 3000);
return inst;
};
}
if (typeof window.createUnityInstance === 'function') {
window.createUnityInstance = patchCreateUnity(window.createUnityInstance);
} else {
Object.defineProperty(window, 'createUnityInstance', {
configurable: true,
get () { return window._ys_createUnity; },
set (v) { window._ys_createUnity = patchCreateUnity(v); }
});
}
function boostCanvasQuality () {
document.querySelectorAll('canvas').forEach(canvas => {
const dpr = window.devicePixelRatio || 1;
if (dpr > 1 && canvas.width && canvas.height) {
canvas.width = canvas.clientWidth * dpr;
canvas.height = canvas.clientHeight * dpr;
const ctx = canvas.getContext('2d');
if (ctx) ctx.imageSmoothingEnabled = false;
}
});
}
window.addEventListener('load', () => {
boostCanvasQuality();
setTimeout(boostCanvasQuality, 5000);
});
/* ─────────────────────────────────────────────
8. SUBTLE MOTION BLUR ON A / D KEYS
Applies a very light CSS blur + horizontal
translate to <html> while A or D is held,
then smoothly eases back out on key-up.
Values are intentionally tiny so it feels
like a camera speed-line rather than lag.
───────────────────────────────────────────────*/
(function setupMotionBlur () {
const BLUR_PX = 1.4; // max blur radius in px — keep ≤ 2
const SHIFT_PX = 3; // max horizontal nudge in px
const EASE_IN_MS = 80; // ms to ramp up
const EASE_OUT_MS= 220; // ms to ease back (longer = smoother)
let blurVal = 0;
let shiftVal = 0;
let direction = 0; // -1 = left (A), +1 = right (D)
let rafId = null;
let target = 0; // 0 = off, 1 = on
const keysHeld = { a: false, d: false };
function applyFilter () {
// Direction: A nudges left (negative), D nudges right (positive)
const targetBlur = target * BLUR_PX;
const targetShift = target * SHIFT_PX * direction;
const speed = target ? (1000 / 60) / EASE_IN_MS : (1000 / 60) / EASE_OUT_MS;
blurVal += (targetBlur - blurVal) * speed;
shiftVal += (targetShift - shiftVal) * speed;
const atRest = Math.abs(blurVal) < 0.01 && Math.abs(shiftVal) < 0.01;
if (atRest && !target) {
// Fully settled — remove filter to save GPU
document.documentElement.style.setProperty('--ys-motion-blur', '');
document.documentElement.style.setProperty('--ys-motion-shift', '');
// Restore base filter without motion extras
const styleEl = document.getElementById('ys-vibrant-filter');
if (styleEl) {
styleEl.textContent = styleEl.textContent.replace(/\s*blur\([^)]*\)/g, '');
}
rafId = null;
return;
}
// Apply as an extra blur on top of the existing html filter
// We inject a <style> override so it stacks cleanly
let extra = document.getElementById('ys-motion-style');
if (!extra) {
extra = document.createElement('style');
extra.id = 'ys-motion-style';
document.head.appendChild(extra);
}
extra.textContent = `
html {
filter: saturate(${SATURATION}) contrast(${CONTRAST}) brightness(${BRIGHTNESS})
blur(${Math.max(0, blurVal).toFixed(3)}px) !important;
transform: translateX(${shiftVal.toFixed(2)}px) !important;
transition: transform 0ms !important;
}
`;
rafId = requestAnimationFrame(applyFilter);
}
function startBlur (dir) {
direction = dir;
target = 1;
if (!rafId) rafId = requestAnimationFrame(applyFilter);
}
function stopBlur () {
if (!keysHeld.a && !keysHeld.d) {
target = 0;
if (!rafId) rafId = requestAnimationFrame(applyFilter);
}
}
window.addEventListener('keydown', e => {
const key = e.key.toLowerCase();
if (key === 'a' && !keysHeld.a) { keysHeld.a = true; startBlur(-1); }
if (key === 'd' && !keysHeld.d) { keysHeld.d = true; startBlur(+1); }
});
window.addEventListener('keyup', e => {
const key = e.key.toLowerCase();
if (key === 'a') { keysHeld.a = false; stopBlur(); }
if (key === 'd') { keysHeld.d = false; stopBlur(); }
});
// Safety: clear on focus loss so blur doesn't get stuck
window.addEventListener('blur', () => {
keysHeld.a = keysHeld.d = false;
stopBlur();
});
})();
/* ─────────────────────────────────────────────
9. STARTUP BADGE
───────────────────────────────────────────────*/
window.addEventListener('load', () => {
const badge = document.createElement('div');
badge.textContent = '⚡ surf · 240 FPS · Vibrant · Ultra · Bloat-free · Motion blur';
Object.assign(badge.style, {
position: 'fixed',
bottom: '12px',
right: '12px',
zIndex: '99999',
background: 'rgba(0,0,0,0.75)',
color: '#a8ff78',
fontFamily: 'monospace',
fontSize: '12px',
padding: '6px 12px',
borderRadius: '6px',
pointerEvents: 'none',
transition: 'opacity 1s ease',
opacity: '1',
});
document.body.appendChild(badge);
setTimeout(() => { badge.style.opacity = '0'; }, 3500);
setTimeout(() => { badge.remove(); }, 4600);
});
console.info('[Enhancer v1.4] surf mode — FPS: 240 · Quality: Ultra · Bloat: blocked · Motion blur: A/D keys');
})();