Hammer Senpa.io Mod - UI Tweaks & Enhancements v2.2

UI Enhancements for Senpa.io: Draggable UI, Optimization, FX, Blur, Freeze, and Help Button

  1. // ==UserScript==
  2. // @name Hammer Senpa.io Mod - UI Tweaks & Enhancements v2.2
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.2
  5. // @description UI Enhancements for Senpa.io: Draggable UI, Optimization, FX, Blur, Freeze, and Help Button
  6. // @author Hammer
  7. // @match https://senpa.io/*
  8. // @grant GM_addStyle
  9. // ==/UserScript==
  10.  
  11. (function () {
  12. 'use strict';
  13.  
  14. // Global variables
  15. let optimizationEnabled = true;
  16. let fxOn = true;
  17. let isFrozen = false;
  18. let isBlurred = false;
  19. let isDragging = false;
  20. let offsetX, offsetY;
  21.  
  22. // Default position (bottom-right corner)
  23. const defaultPosition = { top: 'auto', left: 'auto', bottom: '20px', right: '20px' };
  24.  
  25. // Create the small GUI container (button to show/hide the menu)
  26. const smallGui = document.createElement('div');
  27. smallGui.id = 'small-gui';
  28. Object.assign(smallGui.style, {
  29. position: 'fixed',
  30. top: '50%',
  31. left: '50%',
  32. transform: 'translate(-50%, -50%)',
  33. width: '70px',
  34. height: '50px',
  35. backgroundColor: 'rgba(0, 0, 0, 0.7)',
  36. color: 'white',
  37. textAlign: 'center',
  38. fontSize: '14px',
  39. borderRadius: '5px',
  40. cursor: 'pointer',
  41. zIndex: '9999',
  42. border: '2px solid red'
  43. });
  44. smallGui.innerText = 'Mods';
  45. document.body.appendChild(smallGui);
  46.  
  47. // Create the GUI menu (hidden by default)
  48. const guiContainer = document.createElement('div');
  49. guiContainer.id = 'gui-container';
  50. Object.assign(guiContainer.style, {
  51. position: 'fixed',
  52. top: '60%',
  53. left: '50%',
  54. transform: 'translateX(-50%)',
  55. width: '250px',
  56. backgroundColor: 'rgba(0, 0, 0, 0.8)',
  57. color: 'white',
  58. padding: '20px',
  59. borderRadius: '10px',
  60. zIndex: '9999',
  61. display: 'none',
  62. fontFamily: 'Arial, sans-serif',
  63. border: '2px solid red'
  64. });
  65.  
  66. // Create the close button for the menu
  67. const closeButton = document.createElement('button');
  68. closeButton.innerText = 'X';
  69. Object.assign(closeButton.style, {
  70. backgroundColor: '#dc3545',
  71. color: 'white',
  72. border: 'none',
  73. padding: '5px',
  74. borderRadius: '50%',
  75. cursor: 'pointer',
  76. position: 'absolute',
  77. top: '10px',
  78. right: '10px'
  79. });
  80. closeButton.addEventListener('click', () => {
  81. guiContainer.style.display = 'none';
  82. });
  83.  
  84. // Create the "made by hammer" text
  85. const hammerText = document.createElement('div');
  86. hammerText.innerText = 'made by hammer <3';
  87. Object.assign(hammerText.style, {
  88. color: '#fff',
  89. fontSize: '14px',
  90. textAlign: 'center',
  91. marginTop: '20px',
  92. display: 'none'
  93. });
  94.  
  95. // Function to create toggle buttons
  96. function createToggleButton(textOn, textOff, initialState, callback) {
  97. const btn = document.createElement('button');
  98. btn.innerText = initialState ? textOff : textOn;
  99. btn.style.backgroundColor = initialState ? '#28a745' : '#dc3545';
  100. btn.style.color = 'white';
  101. btn.style.border = 'none';
  102. btn.style.padding = '10px';
  103. btn.style.borderRadius = '5px';
  104. btn.style.cursor = 'pointer';
  105. btn.style.marginBottom = '10px';
  106. btn.addEventListener('click', () => {
  107. const newState = callback();
  108. btn.innerText = newState ? textOff : textOn;
  109. btn.style.backgroundColor = newState ? '#28a745' : '#dc3545';
  110. });
  111. return btn;
  112. }
  113.  
  114. // Append elements to the GUI container
  115. guiContainer.appendChild(closeButton);
  116. guiContainer.appendChild(createToggleButton('Enable FPS Optimization', 'Disable FPS Optimization', optimizationEnabled, () => {
  117. optimizationEnabled = !optimizationEnabled;
  118. optimizationEnabled ? enableOptimization() : disableOptimization();
  119. return optimizationEnabled;
  120. }));
  121. guiContainer.appendChild(createToggleButton('Enable FX', 'Disable FX', fxOn, () => {
  122. fxOn = !fxOn;
  123. applyVisualEffects();
  124. return fxOn;
  125. }));
  126. guiContainer.appendChild(createToggleButton('Freeze on Death', 'Unfreeze on Death', isFrozen, () => {
  127. isFrozen = !isFrozen;
  128. return isFrozen;
  129. }));
  130. guiContainer.appendChild(createToggleButton('Enable Background Blur', 'Disable Background Blur', isBlurred, () => {
  131. isBlurred = !isBlurred;
  132. const canvas = document.querySelector('canvas');
  133. if (canvas) {
  134. canvas.style.filter = isBlurred ? 'blur(3px)' : 'none';
  135. }
  136. document.body.style.backdropFilter = isBlurred ? 'blur(2px)' : 'none';
  137. return isBlurred;
  138. }));
  139. guiContainer.appendChild(hammerText);
  140. document.body.appendChild(guiContainer);
  141.  
  142. // Event to toggle the menu visibility
  143. smallGui.addEventListener('click', () => {
  144. const isHidden = guiContainer.style.display === 'none';
  145. guiContainer.style.display = isHidden ? 'block' : 'none';
  146. hammerText.style.display = isHidden ? 'block' : 'none';
  147. });
  148.  
  149. // Draggable feature for the small GUI
  150. smallGui.addEventListener('mousedown', (e) => {
  151. isDragging = true;
  152. offsetX = e.clientX - parseInt(window.getComputedStyle(smallGui).left);
  153. offsetY = e.clientY - parseInt(window.getComputedStyle(smallGui).top);
  154. smallGui.style.cursor = 'grabbing';
  155. });
  156.  
  157. document.addEventListener('mousemove', (e) => {
  158. if (isDragging) {
  159. smallGui.style.left = `${e.clientX - offsetX}px`;
  160. smallGui.style.top = `${e.clientY - offsetY}px`;
  161. }
  162. });
  163.  
  164. document.addEventListener('mouseup', () => {
  165. isDragging = false;
  166. smallGui.style.cursor = 'grab';
  167. savePosition();
  168. });
  169.  
  170. // Save position of the small GUI box
  171. function savePosition() {
  172. localStorage.setItem('gui-position', JSON.stringify({
  173. left: smallGui.style.left,
  174. top: smallGui.style.top
  175. }));
  176. }
  177.  
  178. // Restore position from localStorage or set default
  179. function restorePosition() {
  180. const position = JSON.parse(localStorage.getItem('gui-position'));
  181. if (position) {
  182. smallGui.style.left = position.left;
  183. smallGui.style.top = position.top;
  184. } else {
  185. smallGui.style.top = defaultPosition.top;
  186. smallGui.style.left = defaultPosition.left;
  187. smallGui.style.bottom = defaultPosition.bottom;
  188. smallGui.style.right = defaultPosition.right;
  189. }
  190. }
  191.  
  192. // Apply visual effects like brightness, contrast, etc.
  193. function applyVisualEffects() {
  194. const canvas = document.querySelector('canvas');
  195. if (canvas) {
  196. canvas.style.filter = fxOn ? 'brightness(1.1) contrast(1.2) saturate(1.1)' : 'none';
  197. }
  198. }
  199.  
  200. // Enable FPS optimization
  201. function enableOptimization() {
  202. document.body.style.backgroundImage = 'none';
  203. document.querySelectorAll('img').forEach(img => img.src = '');
  204. const style = document.createElement('style');
  205. style.innerHTML = `
  206. * {
  207. animation: none !important;
  208. transition: none !important;
  209. box-shadow: none !important;
  210. }
  211. canvas {
  212. image-rendering: optimizeSpeed;
  213. will-change: transform;
  214. }
  215. body, html {
  216. background: #000 !important;
  217. overflow: hidden;
  218. margin: 0;
  219. padding: 0;
  220. }
  221. `;
  222. document.head.appendChild(style);
  223. document.querySelectorAll('audio').forEach(audio => audio.pause());
  224. document.querySelectorAll('.ad, .sidebar, .popup').forEach(ad => ad.remove());
  225. }
  226.  
  227. // Disable FPS optimization
  228. function disableOptimization() {
  229. const style = document.createElement('style');
  230. style.innerHTML = `
  231. * {
  232. animation: initial !important;
  233. transition: initial !important;
  234. }
  235. `;
  236. document.head.appendChild(style);
  237. }
  238.  
  239. // Freeze player on death (optional)
  240. function freezeOnDeath() {
  241. if (!isFrozen) return;
  242. const player = document.querySelector('.player');
  243. if (!player) return;
  244.  
  245. isFrozen = true;
  246. const preventMovement = e => { e.preventDefault(); e.stopPropagation(); };
  247.  
  248. document.addEventListener('keydown', preventMovement);
  249. document.addEventListener('mousemove', preventMovement);
  250. document.addEventListener('mousedown', preventMovement);
  251.  
  252. setTimeout(() => {
  253. isFrozen = false;
  254. document.removeEventListener('keydown', preventMovement);
  255. document.removeEventListener('mousemove', preventMovement);
  256. document.removeEventListener('mousedown', preventMovement);
  257. }, 3000);
  258. }
  259.  
  260. // Observer to reset position after death or when returning to the main menu
  261. const observer = new MutationObserver(() => {
  262. const middleAd = document.querySelector('.middle, .middle-panel, .ad-middle');
  263. if (middleAd) {
  264. middleAd.remove();
  265. }
  266.  
  267. const inGame = document.querySelector('.player');
  268. if (inGame) {
  269. restorePosition();
  270. }
  271. });
  272.  
  273. observer.observe(document.body, { childList: true, subtree: true });
  274.  
  275. // Check for death/game start and adjust UI accordingly
  276. setInterval(() => {
  277. const deathState = document.querySelector('.dead');
  278. if (deathState && isFrozen) {
  279. freezeOnDeath();
  280. }
  281. }, 1000);
  282.  
  283. // Apply optimization and visual effects on load
  284. if (optimizationEnabled) enableOptimization();
  285. if (fxOn) applyVisualEffects();
  286. })();