// ==UserScript==
// @name Nitro Type Race Enhancements
// @namespace https://www.youtube.com/@InternetTyper
// @version 1.12.6
// @license MIT
// @description Rainbow mode, customizable colors, custmoizable zoom on the race text via slider, custmizable font, and customizable auto reload and delay BUILT IN, as well as "perfect nitros" TW: Perfect Nitros does NOT work whenever you use the rainbow text option. Subscribe To Internet Typer Plz?
// @author InternetTyper
// @match https://www.nitrotype.com/*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
"use strict";
const fontLink = document.createElement("link");
fontLink.href = "https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@700&family=Fira+Code:wght@700&family=JetBrains+Mono:wght@700&display=swap";
fontLink.rel = "stylesheet";
document.head.appendChild(fontLink);
let raceTextColor = localStorage.getItem("raceTextColor") || "#67d802";
let raceBackgroundColor = localStorage.getItem("raceBackgroundColor") || "#1d1e23";
let autoReloadMS = parseInt(localStorage.getItem("autoReloadMS"), 10) || 475;
let perfectNitrosEnabled = localStorage.getItem("perfectNitrosEnabled");
if (perfectNitrosEnabled === null) {
perfectNitrosEnabled = "true";
localStorage.setItem("perfectNitrosEnabled", "true");
}
let autoReloadEnabled = localStorage.getItem("autoReloadEnabled");
if (autoReloadEnabled === null) {
autoReloadEnabled = "true";
localStorage.setItem("autoReloadEnabled", "true");
}
let animatedGradientTextEnabled = localStorage.getItem("animatedGradientTextEnabled");
if (animatedGradientTextEnabled === null) {
animatedGradientTextEnabled = "false";
localStorage.setItem("animatedGradientTextEnabled", "false");
}
let raceTextZoom = parseInt(localStorage.getItem("raceTextZoom"), 10) || 28;
let raceFont = localStorage.getItem("raceFont") || "Roboto Mono";
let customRaceSettingsEnabled = localStorage.getItem("customRaceSettingsEnabled");
if (customRaceSettingsEnabled === null) {
customRaceSettingsEnabled = "true";
localStorage.setItem("customRaceSettingsEnabled", "true");
}
function updateRaceBoxStyle() {
let styleEl = document.getElementById("raceBoxStyle");
if (!styleEl) {
styleEl = document.createElement("style");
styleEl.id = "raceBoxStyle";
document.head.appendChild(styleEl);
}
if (customRaceSettingsEnabled === "true") {
styleEl.textContent = `
.dash-copyContainer {
background: ${raceBackgroundColor} !important;
-webkit-box-shadow: 0px 1px 157px 10px rgba(0,0,0,0.78) !important;
box-shadow: 0px 1px 157px 10px rgba(0,0,0,0.78) !important;
border-radius: 5px !important;
flex: 1 !important;
overflow: hidden !important;
padding: 15px !important;
display: flex !important;
}
.dash-copy {
color: ${raceTextColor} !important;
font-family: "${raceFont}", "Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace !important;
font-size: ${raceTextZoom}px !important;
font-weight: 700 !important;
}
::selection {
background-color: #1976c6;
color: white;
}
`;
} else {
styleEl.textContent = "";
}
}
updateRaceBoxStyle();
function updateAnimatedGradientText() {
let styleEl = document.getElementById("animatedGradientTextStyle");
if (!styleEl) {
styleEl = document.createElement("style");
styleEl.id = "animatedGradientTextStyle";
document.head.appendChild(styleEl);
}
if (animatedGradientTextEnabled === "true") {
styleEl.textContent = `
.dash-word {
text-align: center;
text-decoration: underline;
font-size: 32px;
font-family: monospace;
letter-spacing: 5px;
background: linear-gradient(to left, #f00, orange, yellow, #09ec09, #9898b9, #a783c1, violet);
background-repeat: repeat;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: animated_text 6s ease-in-out infinite;
background-size: 400% 100%;
}
@keyframes animated_text {
0%,100% { background-position: 0 0; }
50% { background-position: 100% 0; }
}
.dash-copyContainer {
background: #1d1e23;
box-shadow: 0 1px 157px 10px rgba(0, 0, 0, 0.78);
}
.dash-letter.is-correct.is-typed {
opacity: 0;
}
`;
} else {
styleEl.textContent = "";
}
}
updateAnimatedGradientText();
const nitrosOptions = {
highlightColor: 'white',
intervalMs: 100
};
function perfectNitrosClient() {
if (document.body.contains(document.querySelector('.dash-letter'))) {
clearInterval(perfectNitrosIntervalId);
let wordList = [];
for (let wordElem of document.getElementsByClassName('dash-word')) {
wordList.push(wordElem.textContent.replace(/\s/g, ''));
}
let largestWords = [];
for (let word of wordList) {
if (typeof largestWords[0] === 'undefined' || largestWords[0].length === word.length) {
largestWords.push(word);
}
if (word.length > largestWords[0].length) {
largestWords = [word];
}
}
Array.prototype.indexesOf = function(value) {
let indexes = [];
for (let i = this.length - 1; i >= 0; i--) {
if (this[i] === value) {
indexes.unshift(i);
}
}
return indexes;
};
let largestWordIndexes = [];
for (let text of wordList.values()) {
if (largestWords.includes(text)) {
largestWordIndexes.push(wordList.indexesOf(text));
}
}
largestWordIndexes = [...new Set(largestWordIndexes.flat())];
for (let idx of largestWordIndexes) {
document.getElementsByClassName('dash-word')[idx].style.backgroundColor = nitrosOptions.highlightColor;
}
}
}
let perfectNitrosIntervalId = null;
function startPerfectNitros() {
if (!perfectNitrosIntervalId) {
perfectNitrosIntervalId = setInterval(perfectNitrosClient, nitrosOptions.intervalMs);
console.info("Perfect Nitros Activated.");
}
}
function stopPerfectNitros() {
if (perfectNitrosIntervalId) {
clearInterval(perfectNitrosIntervalId);
perfectNitrosIntervalId = null;
console.info("Perfect Nitros Deactivated.");
}
}
if (perfectNitrosEnabled === "true") {
startPerfectNitros();
} else {
stopPerfectNitros();
}
const raceResultObserver = new MutationObserver(mutations => {
for (const mutation of mutations) {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1 && node.classList.contains("race-results")) {
if (autoReloadEnabled === "true") {
console.info(`Race results detected. Reloading in ${autoReloadMS} ms.`);
setTimeout(() => location.reload(), autoReloadMS);
} else {
console.info("Race results detected but auto reload is disabled.");
}
raceResultObserver.disconnect();
}
});
}
});
raceResultObserver.observe(document.body, { childList: true, subtree: true });
const settingsGUI = document.createElement("div");
settingsGUI.id = "customSettingsGUI";
settingsGUI.style.position = "fixed";
settingsGUI.style.top = "20px";
settingsGUI.style.left = "20px";
settingsGUI.style.background = "rgba(0, 0, 0, 0.85)";
settingsGUI.style.border = "1px solid #fff";
settingsGUI.style.borderRadius = "5px";
settingsGUI.style.color = "#fff";
settingsGUI.style.fontFamily = "Arial, sans-serif";
settingsGUI.style.zIndex = "1001";
function updateSettingsGuiStyle() {
settingsGUI.style.boxShadow = "0 0 10px 2px " + raceTextColor;
settingsGUI.style.width = "300px";
settingsGUI.style.padding = "10px";
}
updateSettingsGuiStyle();
settingsGUI.innerHTML = `
<div id="customSettingsHeader" style="cursor:move; text-align:center; font-size:20px; font-weight:bold; margin-bottom:10px;">
Race Enhancements
</div>
<div style="margin-bottom:10px;">
<label>Custom Race Settings Enabled: </label>
<input type="checkbox" id="customRaceSettingsCheckbox" ${customRaceSettingsEnabled === "true" ? "checked" : ""}>
<br>
<label>Auto Reload Enabled: </label>
<input type="checkbox" id="autoReloadCheckbox" ${autoReloadEnabled === "true" ? "checked" : ""}>
<br>
<label>Perfect Nitros Enabled: </label>
<input type="checkbox" id="perfectNitrosCheckbox" ${perfectNitrosEnabled === "true" ? "checked" : ""}>
<br>
<label>RAINBOW Text: </label>
<input type="checkbox" id="animatedGradientTextCheckbox" ${animatedGradientTextEnabled === "true" ? "checked" : ""}>
</div>
<div style="margin-bottom:10px;">
<label>Race Text Color: </label>
<input type="color" id="raceTextColorInput" value="${raceTextColor}">
<label>Race Background Color: </label>
<input type="color" id="raceBackgroundColorInput" value="${raceBackgroundColor}">
</div>
<div style="margin-bottom:10px;">
<label>Race Text Zoom (px): </label>
<input type="range" id="raceTextZoomInput" min="20" max="60" step="1" value="${raceTextZoom}">
<span id="raceTextZoomDisplay">${raceTextZoom}</span>px
</div>
<div style="margin-bottom:10px;">
<label style="color: #fff;">Auto Reload Delay (ms): </label>
<input type="number" id="autoReloadInput" value="${autoReloadMS}" style="width:80px; color: black; background-color: #fff;">
<label>Race Font: </label>
<select id="raceFontSelect" style="color: black; background-color: #fff;">
<option value="Roboto Mono" ${raceFont === "Roboto Mono" ? "selected" : ""}>Roboto Mono</option>
<option value="Fira Code" ${raceFont === "Fira Code" ? "selected" : ""}>Fira Code</option>
<option value="JetBrains Mono" ${raceFont === "JetBrains Mono" ? "selected" : ""}>JetBrains Mono</option>
</select>
</div>
<div style="font-size:12px; margin-top:5px; text-align:center;">
Press Ctrl+Q to toggle this panel
</div>
<div style="font-size:18px; margin-top:5px; margin-bottom:0; text-align:center;">
Created by <a href="https://www.youtube.com/@InternetTyper" target="_blank" style="color: ${raceTextColor}; text-decoration: underline;">@InternetTyper on YouTube</a>
</div>
`;
document.body.appendChild(settingsGUI);
let savedVisibility = localStorage.getItem("settingsGUIVisible");
settingsGUI.style.display = (savedVisibility === "none") ? "none" : "block";
function autoSaveSettings() {
customRaceSettingsEnabled = document.getElementById("customRaceSettingsCheckbox").checked ? "true" : "false";
autoReloadEnabled = document.getElementById("autoReloadCheckbox").checked ? "true" : "false";
perfectNitrosEnabled = document.getElementById("perfectNitrosCheckbox").checked ? "true" : "false";
animatedGradientTextEnabled = document.getElementById("animatedGradientTextCheckbox").checked ? "true" : "false";
raceTextColor = document.getElementById("raceTextColorInput").value;
raceBackgroundColor = document.getElementById("raceBackgroundColorInput").value;
raceTextZoom = parseInt(document.getElementById("raceTextZoomInput").value, 10) || 28;
autoReloadMS = parseInt(document.getElementById("autoReloadInput").value, 10) || 475;
raceFont = document.getElementById("raceFontSelect").value;
localStorage.setItem("customRaceSettingsEnabled", customRaceSettingsEnabled);
localStorage.setItem("raceTextColor", raceTextColor);
localStorage.setItem("raceBackgroundColor", raceBackgroundColor);
localStorage.setItem("raceTextZoom", raceTextZoom);
localStorage.setItem("autoReloadMS", autoReloadMS);
localStorage.setItem("perfectNitrosEnabled", perfectNitrosEnabled);
localStorage.setItem("autoReloadEnabled", autoReloadEnabled);
localStorage.setItem("animatedGradientTextEnabled", animatedGradientTextEnabled);
localStorage.setItem("raceFont", raceFont);
updateRaceBoxStyle();
updateSettingsGuiStyle();
updateAnimatedGradientText();
if (perfectNitrosEnabled === "true") {
startPerfectNitros();
} else {
stopPerfectNitros();
}
console.info("Settings autosaved.");
}
document.getElementById("customRaceSettingsCheckbox").addEventListener("change", autoSaveSettings);
document.getElementById("autoReloadCheckbox").addEventListener("change", autoSaveSettings);
document.getElementById("perfectNitrosCheckbox").addEventListener("change", autoSaveSettings);
document.getElementById("animatedGradientTextCheckbox").addEventListener("change", autoSaveSettings);
document.getElementById("raceTextColorInput").addEventListener("change", autoSaveSettings);
document.getElementById("raceBackgroundColorInput").addEventListener("change", autoSaveSettings);
document.getElementById("raceTextZoomInput").addEventListener("input", function() {
document.getElementById("raceTextZoomDisplay").textContent = this.value;
autoSaveSettings();
});
document.getElementById("autoReloadInput").addEventListener("change", autoSaveSettings);
document.getElementById("raceFontSelect").addEventListener("change", autoSaveSettings);
function makeDraggable(el) {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
const header = document.getElementById("customSettingsHeader");
(header || el).onmousedown = dragMouseDown;
function dragMouseDown(e) {
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
el.style.top = (el.offsetTop - pos2) + "px";
el.style.left = (el.offsetLeft - pos1) + "px";
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
localStorage.setItem("settingsGUIPos", JSON.stringify({ top: el.style.top, left: el.style.left }));
}
}
const savedPos = localStorage.getItem("settingsGUIPos");
if (savedPos) {
try {
const { top, left } = JSON.parse(savedPos);
settingsGUI.style.top = top;
settingsGUI.style.left = left;
} catch(e) {}
}
makeDraggable(settingsGUI);
document.addEventListener("keydown", e => {
if (e.ctrlKey && e.key.toLowerCase() === "q") {
if (settingsGUI.style.display === "none") {
settingsGUI.style.display = "block";
localStorage.setItem("settingsGUIVisible", "block");
} else {
settingsGUI.style.display = "none";
localStorage.setItem("settingsGUIVisible", "none");
}
}
});
})();