// ==UserScript==
// @name NitroType Perfect Nitros with SFB Highlighting (QWERTY, DVORAK, COLEMAK)
// @namespace https://greasyfork.org/users/1331131-tensorflow-dvorak
// @version 2.5.1
// @description Highlights the largest words, single-finger bigrams (SFBs), and custom words/phrases for QWERTY, DVORAK, or COLEMAK layouts. Adds custom color coding for hand-specific characters like 'b' and 'y'.
// @author Ray Adams/Nate Dogg, Modified by TensorFlow - Dvorak
// @match https://www.nitrotype.com/race
// @match https://www.nitrotype.com/race/*
// @run-at document-end
// @grant none
// @license MIT
// ==/UserScript==
(() => {
// CHANGE THIS to 'QWERTY', 'DVORAK' or 'COLEMAK'
const keyboardLayout = 'QWERTY';
const options = {
highlightColor: '#1b1c25',
wordHighlightColor: '#5b048a',
singleFingerBigramColor: '#403dae',
redForRightHand: 'red',
blueForLeftHand: 'blue',
intervalMs: 100
};
// Custom wordlist for highlighting (add words or phrases you aim to type differently here)
const customWords = new Set(['number', "you're"]);
// SFBs for different keyboard layouts (remove bigrams you don't want to work on)
const SFBs = new Map([
['QWERTY', ['ed', 'de', 'fr', 'rf', 'gt', 'tg', 'bv', 'vb', 'ju', 'uj', 'ki', 'ik', 'nm', 'mn', 'nu', 'un']],
['DVORAK', ['pu', 'up', 'ui', 'iu', 'pi', 'ip', 'je', 'ej']],
['COLEMAK', ['']]
]);
// Define different layouts.
const layoutKeys = {
QWERTY: {
leftHand: 'qwertasdfgzxcvb',
rightHand: 'yuiophjklmn',
targetChars: ['b'] // 'b' is typed by either hand and will be color coded based on which hand should be used. Red = right Blue = Left.
},
DVORAK: {
leftHand: 'aoeuqjkxiyp',
rightHand: 'dhtsnfgcrlbmwvz',
targetChars: ['x']
},
COLEMAK: {
leftHand: 'qwfpbjluyarst',
rightHand: 'neiohjkxvmzcdg',
targetChars: ['b']
}
};
const client = () => {
const dashLetters = document.querySelector('.dash-letter');
if (dashLetters) {
clearInterval(intervalId);
// Get all words from the race
const wordList = [...document.getElementsByClassName('dash-word')].map(word => word.textContent.replace(/\s/g, ''));
// Find the largest words
const maxLength = Math.max(...wordList.map(word => word.length));
const largestWords = wordList.filter(word => word.length === maxLength);
// Highlight largest words and bigrams
wordList.forEach((word, index) => {
const wordElement = document.getElementsByClassName('dash-word')[index];
// Highlight largest words
if (largestWords.includes(word)) {
wordElement.style.backgroundColor = options.highlightColor;
}
// Highlight custom words/phrases
highlightCustomWords(wordElement);
// Highlight single-finger bigrams
highlightSingleFingerBigrams(wordElement);
// Highlight specific target chars if followed by the same hand's character
highlightTargetCharsWithSameHand(wordElement, keyboardLayout);
});
}
};
const highlightCustomWords = (wordElement) => {
const text = wordElement.textContent.toLowerCase();
// Loop over each word or phrase in the custom wordlist
customWords.forEach(word => {
const startIndex = text.indexOf(word.toLowerCase());
if (startIndex !== -1) {
for (let i = 0; i < word.length; i++) {
wordElement.querySelector(`.dash-letter:nth-child(${startIndex + i + 1})`).style.color = options.wordHighlightColor;
}
}
});
};
const highlightSingleFingerBigrams = (wordElement) => {
const text = wordElement.textContent;
// Loop over the text and highlight single-finger bigrams
for (let i = 0; i < text.length - 1; i++) {
const bigram = text[i] + text[i + 1];
if (SFBs.get(keyboardLayout).includes(bigram)) {
wordElement.querySelector(`.dash-letter:nth-child(${i + 1})`).style.color = options.singleFingerBigramColor;
wordElement.querySelector(`.dash-letter:nth-child(${i + 2})`).style.color = options.singleFingerBigramColor;
i++;
}
}
};
const highlightTargetCharsWithSameHand = (wordElement, layout) => {
const { leftHand, rightHand, targetChars } = layoutKeys[layout];
const text = wordElement.textContent.toLowerCase();
// Check if target characters are followed by the same hand
for (let i = 0; i < text.length - 1; i++) {
const currentChar = text[i];
const nextChar = text[i + 1];
if (targetChars.includes(currentChar)) {
if (leftHand.includes(currentChar) && leftHand.includes(nextChar)) {
// Highlight target char to suggest typing with the right hand
wordElement.querySelector(`.dash-letter:nth-child(${i + 1})`).style.color = options.redForRightHand;
} else if (rightHand.includes(currentChar) && rightHand.includes(nextChar)) {
// Highlight target char to suggest typing with the left hand
wordElement.querySelector(`.dash-letter:nth-child(${i + 1})`).style.color = options.blueForLeftHand;
}
}
}
};
const intervalId = setInterval(client, options.intervalMs);
})();