// ==UserScript==
// @name Nitro Monkey | NT Theme
// @namespace https://greasyfork.org/users/1331131-tensorflow-dvorak
// @version 2024-10-20
// @description Custom Nitro Type Theme w/ Font-Size, Height Sliders, and Cursor Customization
// @author TensorFlow - Dvorak
// @match *://*.nitrotype.com/race
// @match *://*.nitrotype.com/race/*
// @license MIT
// @grant none
// ==/UserScript==
(function () {
const dynamicStyle = document.createElement("style");
document.head.appendChild(dynamicStyle);
let currentCursorType = localStorage.getItem("cursorType") || "line";
let currentCursorSpeed = localStorage.getItem("cursorSpeed") || "medium";
function updateStyles() {
dynamicStyle.innerHTML = `
${generateCursorStyle(currentCursorType, currentCursorSpeed)}
${generateFontSizeStyle(localStorage.getItem("dashFontSize") || "40")}
`;
}
function generateCursorStyle(cursorType, cursorSpeed) {
let cursorSize = "2px";
let cursorHeight = "1.2em";
let animationDuration = "1s";
let cursorTopOffset = "0.2em";
let cursorColor = "#00FF7F";
let cursorTransform = "";
if (cursorType === "block") {
cursorSize = "0.7em";
cursorHeight = "1.1em";
cursorTopOffset = "0";
cursorColor = "#0075ff42";
cursorTransform = "translateY(0.3em)";
} else if (cursorType === "line") {
cursorSize = "2px";
cursorHeight = "1.2em";
cursorColor = "#0075ff";
} else {
cursorSize = "0";
}
if (cursorSpeed === "slow") {
animationDuration = "1.5s";
} else if (cursorSpeed === "fast") {
animationDuration = "0.5s";
}
return `
.dash-letter {
color: #acaaff;
}
.dash-letter.is-waiting {
position: relative;
color: #acaaff;
background-color: #1c99f400;
}
.dash-letter.is-waiting::after {
content: '';
display: inline-block;
width: ${cursorSize};
height: ${cursorHeight};
background-color: ${cursorColor};
animation: blink ${animationDuration} step-end infinite;
position: absolute;
top: ${cursorTopOffset};
left: 0;
transform: ${cursorTransform};
}
.dash-letter.is-incorrect {
color: red;
background: #ffffff00;
position: relative;
}
.dash-letter.is-incorrect::after {
content: '';
display: inline-block;
width: ${cursorSize};
height: ${cursorHeight};
background-color: rgba(255, 0, 0, 0.5);
animation: blink ${animationDuration} step-end infinite;
position: absolute;
top: ${cursorTopOffset};
left: 0;
transform: ${cursorTransform};
}
@keyframes blink {
50% { opacity: 0; }
}
`;
}
function generateFontSizeStyle(fontSize) {
return `
#root {
background-color: #060516;
}
.dash-copy {
font-size: ${fontSize}px !important;
}
.dash-copyContainer {
background: linear-gradient(to bottom, rgba(6, 5, 22, 0.9) 65%, rgba(6, 5, 22, 0.87) 70%, #060516 100%);
border-radius: 5px;
box-shadow: 0 1px 10px rgba(2, 2, 2, 0.14);
flex: 1;
overflow: hidden;
padding: 15px;
width: 100%;
display: flex;
}
.dash-side, .dash-actions, .dash-nitros {
display: none;
}
.dash:before {
height: min-content;
}
.structure-footer {
display: flex;
padding-top: 2rem;
}
.race-results {
background-color: #060516;
}
.raceResults--default {
background: #060516;
}
.raceResults-rewards {
background: #0c0b18;
}
.raceResults-dailyChallenges {
background: #0c0b18;
}
.g-b--7of12 {
background: #060516;
}
.footer-nav {
background: #0c0b18;
}
.nav-list {
background: #0c0b18;
}
.nav {
background: #0c0b18;
border-bottom: 1px solid #14141b;
}
.btn--primary {
background: #403dae;
}
.btn--primary:hover {
background: #8a1bdf;
}
.btn--secondary {
background: #5b048a;
}
.btn--secondary:hover {
background: #8d11d0;
}
.gridTable--raceResults .gridTable-cell {
background: #0c0b18;
}
.gridTable-cell {
background: #0c0b18;
}
.dashShield-layer {
display: none;
}
.dash-center {
background: #06051687;
}
.nt-stats-right-section {
background: #060516;
}
.nt-stats-daily-challenges {
background: #060516;
}
.nt-stats-body {
background: #0c0b18;
}
`;
}
const dashElement = document.querySelector(".dash");
const container = document.querySelector(".structure-content div");
if (dashElement) {
const displayContainer = document.createElement("div");
displayContainer.style.display = "flex";
displayContainer.style.gap = "2rem";
displayContainer.style.marginTop = "10px";
displayContainer.style.fontSize = "20px";
displayContainer.style.color = "#6864f6";
displayContainer.style.background = "rgba(6, 5, 22, 0.8)";
displayContainer.style.padding = "10px";
displayContainer.style.borderRadius = "5px";
displayContainer.style.zIndex = "9999";
displayContainer.innerHTML = `
<div>WPM: 0 <span id="targetWPMValue" style="margin-left: 10px;">Target WPM: 100</span></div>
<div>
<label for="targetWPM" style="margin-right: 10px;">Target WPM:</label>
<button id="decreaseWPM" style="margin-right: 5px;">-</button>
<input type="number" id="targetWPM" min="50" max="200" value="100" readonly>
<button id="increaseWPM" style="margin-left: 5px;">+</button>
</div>
<div>Accuracy: 0%</div>
<div>
<label for="cursorType" style="margin-right: 10px;">Cursor Type:</label>
<button id="cursorTypeButton">${
currentCursorType.charAt(0).toUpperCase() + currentCursorType.slice(1)
}</button>
</div>
<div>
<label for="cursorSpeed" style="margin-right: 10px;">Cursor Speed:</label>
<button id="cursorSpeedButton">${
currentCursorSpeed.charAt(0).toUpperCase() +
currentCursorSpeed.slice(1)
}</button>
</div>
`;
container.appendChild(displayContainer);
const wpmDisplay = displayContainer.querySelector("div:nth-child(1)");
const targetWPMValueDisplay =
displayContainer.querySelector("#targetWPMValue");
const accuracyDisplay = displayContainer.querySelector("div:nth-child(3)");
const targetWPMInput = displayContainer.querySelector("#targetWPM");
const increaseWPMButton = displayContainer.querySelector("#increaseWPM");
const decreaseWPMButton = displayContainer.querySelector("#decreaseWPM");
const cursorTypeButton =
displayContainer.querySelector("#cursorTypeButton");
const cursorSpeedButton =
displayContainer.querySelector("#cursorSpeedButton");
const savedTargetWPM = localStorage.getItem("targetWPM") || "100";
targetWPMInput.value = savedTargetWPM;
targetWPMValueDisplay.textContent = `Target WPM: ${savedTargetWPM}`;
function updateTargetWPM(value) {
const targetWPM = Math.max(50, Math.min(200, parseInt(value, 10)));
targetWPMInput.value = targetWPM;
targetWPMValueDisplay.textContent = `Target WPM: ${targetWPM}`;
localStorage.setItem("targetWPM", targetWPM);
}
increaseWPMButton.addEventListener("click", function () {
updateTargetWPM(parseInt(targetWPMInput.value, 10) + 5);
});
decreaseWPMButton.addEventListener("click", function () {
updateTargetWPM(parseInt(targetWPMInput.value, 10) - 5);
});
const cursorTypes = ["none", "block", "line"];
const cursorSpeeds = ["slow", "medium", "fast"];
cursorTypeButton.addEventListener("click", function () {
let currentIndex = cursorTypes.indexOf(currentCursorType);
currentCursorType = cursorTypes[(currentIndex + 1) % cursorTypes.length];
cursorTypeButton.textContent =
currentCursorType.charAt(0).toUpperCase() + currentCursorType.slice(1);
localStorage.setItem("cursorType", currentCursorType);
updateStyles();
});
cursorSpeedButton.addEventListener("click", function () {
let currentIndex = cursorSpeeds.indexOf(currentCursorSpeed);
currentCursorSpeed =
cursorSpeeds[(currentIndex + 1) % cursorSpeeds.length];
cursorSpeedButton.textContent =
currentCursorSpeed.charAt(0).toUpperCase() +
currentCursorSpeed.slice(1);
localStorage.setItem("cursorSpeed", currentCursorSpeed);
updateStyles();
});
const fetchStats = () => {
const wpmElement = document.querySelector(
".dash-metrics .list-item:nth-child(1) .g-b--8of12 .h4"
);
const accuracyElement = document.querySelector(
".dash-metrics .list-item:nth-child(2) .g-b--8of12 .h4"
);
const targetWPM = parseInt(localStorage.getItem("targetWPM"), 10) || 100;
const green = "#00FF7F";
const yellow = "#FFD700";
const red = "red";
if (wpmElement) {
const wpmValue = parseInt(wpmElement.textContent, 10) || 0;
if (wpmValue >= targetWPM - 5 && wpmValue <= targetWPM + 5) {
wpmDisplay.style.color = green;
} else if (wpmValue < targetWPM - 10) {
wpmDisplay.style.color = red;
} else if (wpmValue < targetWPM - 5) {
wpmDisplay.style.color = yellow;
} else if (wpmValue > targetWPM + 5) {
wpmDisplay.style.color = "blue";
}
wpmDisplay.innerHTML = `WPM: ${wpmValue} <span id="targetWPMValue" style="margin-left: 10px;">Target WPM: ${targetWPM}</span>`;
}
if (accuracyElement) {
const accuracyValue = parseFloat(accuracyElement.textContent) || 0;
if (accuracyValue < 94) {
accuracyDisplay.style.color = red;
} else if (accuracyValue >= 94 && accuracyValue < 96) {
accuracyDisplay.style.color = yellow;
} else {
accuracyDisplay.style.color = green;
}
accuracyDisplay.textContent = `Accuracy: ${accuracyValue}%`;
}
};
// Height slider
const heightLabel = document.createElement("label");
heightLabel.textContent = "Adjust Height:";
heightLabel.style.color = "#00FF7F";
heightLabel.style.display = "block";
heightLabel.style.marginTop = "10px";
const heightSlider = document.createElement("input");
heightSlider.type = "range";
heightSlider.min = "100";
heightSlider.max = "1000";
const savedHeight = localStorage.getItem("dashHeight") || "500";
dashElement.style.height = `${savedHeight}px`;
heightSlider.value = savedHeight;
heightSlider.style.width = "100%";
heightSlider.style.marginTop = "5px";
heightSlider.style.cursor = "pointer";
container.appendChild(heightLabel);
container.appendChild(heightSlider);
heightSlider.addEventListener("input", function () {
const heightValue = heightSlider.value;
dashElement.style.height = `${heightValue}px`;
localStorage.setItem("dashHeight", heightValue);
});
// Font size slider
const fontSizeLabel = document.createElement("label");
fontSizeLabel.textContent = "Adjust Font Size:";
fontSizeLabel.style.color = "#00FF7F";
fontSizeLabel.style.display = "block";
fontSizeLabel.style.marginTop = "10px";
const fontSizeSlider = document.createElement("input");
fontSizeSlider.type = "range";
fontSizeSlider.min = "20";
fontSizeSlider.max = "80";
fontSizeSlider.value = localStorage.getItem("dashFontSize") || "40";
fontSizeSlider.style.width = "100%";
fontSizeSlider.style.marginTop = "5px";
fontSizeSlider.style.cursor = "pointer";
container.appendChild(fontSizeLabel);
container.appendChild(fontSizeSlider);
fontSizeSlider.addEventListener("input", function () {
const newFontSize = fontSizeSlider.value;
localStorage.setItem("dashFontSize", newFontSize);
updateStyles();
});
setInterval(fetchStats, 100);
updateStyles();
}
setInterval(() => {
const experimentDiv = document.querySelector('.experiment');
const lastSlider = container.querySelector('input[type="range"]:last-of-type');
if (experimentDiv && lastSlider) {
const experimentParent = experimentDiv.parentElement;
if (experimentParent !== lastSlider.parentElement) {
lastSlider.parentElement.appendChild(experimentDiv);
}
}
}, 500);
// Retain scroll position
window.addEventListener('beforeunload', () => {
localStorage.setItem('scrollPosition', window.scrollY);
});
window.addEventListener('load', () => {
setTimeout(() => {
const scrollPosition = localStorage.getItem('scrollPosition');
if (scrollPosition) {
console.log('Restoring scroll position');
window.scrollTo(0, parseInt(scrollPosition, 10));
}
}, 1000);
});
})();