Skip to content

Instantly share code, notes, and snippets.

@Domiii
Last active December 20, 2025 16:44
Show Gist options
  • Select an option

  • Save Domiii/52cf49d780ec8c9f01771973c36197af to your computer and use it in GitHub Desktop.

Select an option

Save Domiii/52cf49d780ec8c9f01771973c36197af to your computer and use it in GitHub Desktop.
This script types for you automatically on www.typingclub.com: 1. Open the website 2. Blaze past the tutorials 3. Go into a level 4. Open Console 5. Paste the script and press ENTER
/**
* This script types for you automatically on www.typingclub.com:
* 1. Open the website
* 2. Blaze past the tutorials
* 3. Go into a level
* 4. Open Console
* 5. Paste the script and press ENTER
*/
// NOTE: When delay (in ms between two strokes) is too low, the site might bug out and the result page will not be shown
const minDelay = 60;
const maxDelay = 60;
const keyOverrides = {
[String.fromCharCode(160)]: ' ' // convert hardspace to normal space
};
function getTargetCharacters() {
const els = Array.from(document.querySelectorAll('.token span.token_unit'));
const chrs = els
.map(el => {
// get letter to type from each letter DOM element
if (el.firstChild?.classList?.contains('_enter')) {
// special case: ENTER
return '\n';
}
let text = el.textContent[0];
return text;
})
.map(c => keyOverrides.hasOwnProperty(c) ? keyOverrides[c] : c); // convert special characters
return chrs;
}
function recordKey(chr) {
// send it straight to the internal API
window.core.record_keydown_time(chr);
}
function sleep(ms) {
return new Promise(r => setTimeout(r, ms));
}
async function autoPlay(finish) {
const chrs = getTargetCharacters();
for (let i = 0; i < chrs.length - (!finish); ++i) {
const c = chrs[i];
recordKey(c);
//console.log(c, c.charCodeAt());
await sleep(Math.random() * (maxDelay - minDelay) + minDelay);
}
}
// ############################################################################################################
// old utilities
// ############################################################################################################
// /**
// * @see https://stackoverflow.com/questions/8942678/keyboardevent-in-chrome-keycode-is-0/12522752#12522752
// */
// function simulateKey(chr, el) {
// _simulateKey(chr, 'keydown', el);
// _simulateKey(chr, 'keypress', el);
// }
// function _simulateKey(chr, type, el) {
// var eventObj = document.createEventObject ?
// document.createEventObject() : document.createEvent("Events");
// if (eventObj.initEvent) {
// eventObj.initEvent(type || "keydown", true, true);
// }
// let keyCode = chr.charCodeAt(0);
// eventObj.key = chr[0];
// eventObj.keyCode = keyCode;
// eventObj.which = keyCode;
// eventObj.isTrusted = true;
// el = el || document.body;
// // console.log(keyCode, eventObj);
// el.dispatchEvent ? el.dispatchEvent(eventObj) : el.fireEvent("onkeydown", eventObj);
// }
// document.addEventListener("keydown", function (e) {
// console.log('down', e);
// });
// document.addEventListener("keypress", function (e) {
// console.log('press', e);
// });
//$($('.menu-btn')[0].parentNode).prepend('<button onclick=\'simulateKeyPress("c")\'>sim</button>');
// simulateKey('a', $('input')[0]);
// ############################################################################################################
// go!
// ############################################################################################################
autoPlay(true);
@mamad13861386
Copy link

why is not working for me

@Anonimus1231234
Copy link

why is not working for me

show the error, let me see if I found the solution

@zane2342
Copy link

zane2342 commented Nov 28, 2025 via email

@zane2342
Copy link

zane2342 commented Nov 29, 2025 via email

@zane2342
Copy link

zane2342 commented Nov 29, 2025 via email

@piink72
Copy link

piink72 commented Dec 1, 2025

has anyone found the solution????

@zane2342
Copy link

zane2342 commented Dec 1, 2025 via email

@Anonimus1231234
Copy link

has anyone found the solution? I think it dosen't work anymore, probably we need to make another code

@ethanmccc
Copy link

someone pls make a new code

@DonMarmolejo727
Copy link

ยฟAlguien ha encontrado la soluciรณn? Creo que ya no funciona, probablemente necesitemos hacer otro cรณdigo

https://github.com/DonMarmolejo727/TypingClub-Extractor.git

Hello brother, try using this code that was developed by a great team of programmers.

@DonMarmolejo727
Copy link

Que alguien cree un cรณdigo nuevo, por favor

Alright bro, check out my repository :)

@ThunderCoding456
Copy link

ThunderCoding456 commented Dec 6, 2025 via email

@Anonimus1231234
Copy link

someone pls make a new code

Yeah we need one, pls someone make one

@zane2342
Copy link

zane2342 commented Dec 7, 2025 via email

@nayfujii
Copy link

nayfujii commented Dec 7, 2025

Hey I was using your code and it stopped working is there anyway you could help fix or update it?
hereโ€™s a screenshot of what Iโ€™m seeing
Image 12-7-25 at 13 11

@zane2342
Copy link

zane2342 commented Dec 7, 2025 via email

@zane2342
Copy link

zane2342 commented Dec 7, 2025 via email

@Anonimus1231234
Copy link

Anonimus1231234 commented Dec 11, 2025

Did you or someone find the solution??? Im trying to fix it but this is a little more difficult and I can't find a solution

@zane2342
Copy link

zane2342 commented Dec 12, 2025 via email

@Anonimus1231234
Copy link

Yeah np just asking C:

@zane2342
Copy link

zane2342 commented Dec 12, 2025 via email

@zane2342
Copy link

zane2342 commented Dec 12, 2025 via email

@DeadHnd
Copy link

DeadHnd commented Dec 15, 2025

maybe cuz its not your code? Wowie.

@CuteDogJay
Copy link

CuteDogJay commented Dec 15, 2025 via email

@zane2342
Copy link

zane2342 commented Dec 15, 2025 via email

@hello212231
Copy link

can any one share the new code pls

@zane2342
Copy link

zane2342 commented Dec 16, 2025 via email

@comoxyOG
Copy link

// Typing Club Automator - AUTO START
(function() {
'use strict';

if (window.typingClubBot) {
    console.log('Bot already running! Close it first with: window.typingClubBot.close()');
    return;
}

console.log('๐Ÿš€ Loading Typing Club Bot...');

const gui = document.createElement('div');
gui.id = 'typing-bot-gui';
gui.style.cssText = `
    position: fixed;
    top: 20px;
    right: 20px;
    width: 340px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: 15px;
    box-shadow: 0 10px 40px rgba(0,0,0,0.5);
    z-index: 2147483647;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    color: white;
`;

gui.innerHTML = `
    <div style="padding: 15px 20px; border-bottom: 1px solid rgba(255,255,255,0.2); display: flex; justify-content: space-between; align-items: center; cursor: move;" id="bot-header">
        <div style="font-weight: 700; font-size: 16px;">๐ŸŽฏ Typing Club Bot</div>
        <button id="bot-close" style="background: rgba(255,255,255,0.2); border: none; color: white; width: 28px; height: 28px; border-radius: 50%; cursor: pointer; font-size: 18px;">ร—</button>
    </div>
    
    <div style="padding: 20px;">
        <div style="background: rgba(255,255,255,0.1); padding: 10px; border-radius: 8px; font-size: 11px; margin-bottom: 10px;">
            <strong style="display: block; margin-bottom: 5px;">๐Ÿ“ Detected:</strong>
            <span id="level-info">Waiting...</span>
        </div>
        
        <div style="margin-bottom: 18px;">
            <label style="display: block; font-size: 12px; font-weight: 600; margin-bottom: 8px; text-transform: uppercase;">Speed</label>
            <div style="background: rgba(255,255,255,0.15); padding: 12px; border-radius: 10px;">
                <input type="range" id="speed-slider" min="30" max="190" value="70" style="width: 100%; margin: 8px 0; cursor: pointer;">
                <div style="text-align: center; font-size: 20px; font-weight: 700; margin-top: 5px;"><span id="speed-value">70</span> WPM</div>
            </div>
        </div>
        
        <div style="margin-bottom: 18px;">
            <label style="display: block; font-size: 12px; font-weight: 600; margin-bottom: 8px; text-transform: uppercase;">Accuracy</label>
            <div style="background: rgba(255,255,255,0.15); padding: 12px; border-radius: 10px;">
                <input type="range" id="accuracy-slider" min="92" max="100" value="97" style="width: 100%; margin: 8px 0; cursor: pointer;">
                <div style="text-align: center; font-size: 20px; font-weight: 700; margin-top: 5px;"><span id="accuracy-value">97</span>%</div>
            </div>
        </div>
        
        <div style="display: flex; align-items: center; gap: 10px; background: rgba(255,255,255,0.15); padding: 12px; border-radius: 10px; margin-bottom: 10px;">
            <input type="checkbox" id="auto-advance" checked style="width: 20px; height: 20px; cursor: pointer;">
            <label for="auto-advance" style="cursor: pointer; flex: 1; font-size: 14px;">Auto-advance</label>
        </div>
        
        <button id="start-btn" style="width: 100%; padding: 12px; border: none; border-radius: 10px; font-size: 14px; font-weight: 700; cursor: pointer; text-transform: uppercase; background: #10ac84; color: white; margin-bottom: 10px;">โ–ถ Start Bot</button>
        <button id="stop-btn" disabled style="width: 100%; padding: 12px; border: none; border-radius: 10px; font-size: 14px; font-weight: 700; cursor: pointer; text-transform: uppercase; background: #ff6b6b; color: white; margin-bottom: 10px; opacity: 0.5;">โน Stop</button>
        
        <div id="status" style="background: rgba(255,255,255,0.15); padding: 12px; border-radius: 10px; text-align: center; font-size: 13px; font-weight: 600; margin-top: 15px;">Ready</div>
        
        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 15px;">
            <div style="background: rgba(255,255,255,0.15); padding: 10px 8px; border-radius: 8px; text-align: center;">
                <div style="font-size: 18px; font-weight: 700;" id="chars-typed">0</div>
                <div style="font-size: 9px; opacity: 0.8; margin-top: 3px;">CHARS</div>
            </div>
            <div style="background: rgba(255,255,255,0.15); padding: 10px 8px; border-radius: 8px; text-align: center;">
                <div style="font-size: 18px; font-weight: 700;" id="levels-completed">0</div>
                <div style="font-size: 9px; opacity: 0.8; margin-top: 3px;">LEVELS</div>
            </div>
        </div>
    </div>
`;

document.body.appendChild(gui);

const speedSlider = document.getElementById('speed-slider');
const speedValue = document.getElementById('speed-value');
const accuracySlider = document.getElementById('accuracy-slider');
const accuracyValue = document.getElementById('accuracy-value');
const autoAdvance = document.getElementById('auto-advance');
const startBtn = document.getElementById('start-btn');
const stopBtn = document.getElementById('stop-btn');
const status = document.getElementById('status');
const levelInfo = document.getElementById('level-info');
const charsTypedEl = document.getElementById('chars-typed');
const levelsCompletedEl = document.getElementById('levels-completed');
const closeBtn = document.getElementById('bot-close');
const header = document.getElementById('bot-header');

let botRunning = false;
let charsTypedCount = 0;
let levelsCompleted = 0;

speedSlider.addEventListener('input', (e) => speedValue.textContent = e.target.value);
accuracySlider.addEventListener('input', (e) => accuracyValue.textContent = e.target.value);

// Draggable
let isDragging = false;
let currentX, currentY, initialX, initialY;

header.addEventListener('mousedown', (e) => {
    initialX = e.clientX - gui.offsetLeft;
    initialY = e.clientY - gui.offsetTop;
    isDragging = true;
});

document.addEventListener('mousemove', (e) => {
    if (isDragging) {
        e.preventDefault();
        currentX = e.clientX - initialX;
        currentY = e.clientY - initialY;
        gui.style.left = currentX + 'px';
        gui.style.top = currentY + 'px';
        gui.style.right = 'auto';
    }
});

document.addEventListener('mouseup', () => isDragging = false);

function detectLevel() {
    // Try to find typing text
    const typable = document.querySelector('div.typable');
    if (typable && typable.textContent) {
        const text = typable.textContent.trim().replace(/\s+/g, ' ');
        levelInfo.textContent = `${text.length} chars detected`;
        return { text, type: 'typing' };
    }
    
    // Check for games - look for game container or canvas
    const gameContainer = document.querySelector('.game-container, .game-canvas, canvas, #game, [class*="game"]');
    if (gameContainer) {
        levelInfo.textContent = 'Game detected';
        return { text: null, type: 'game' };
    }
    
    return { text: null, type: null };
}

function typeChar(char, field) {
    const keyCode = char.charCodeAt(0);
    let code = 'Unidentified';
    let shiftKey = false;
    
    // Map special characters properly
    const specialChars = {
        ' ': { code: 'Space', keyCode: 32 },
        '"': { code: 'Quote', keyCode: 222, shiftKey: true },
        "'": { code: 'Quote', keyCode: 222, shiftKey: false },
        ',': { code: 'Comma', keyCode: 188 },
        '.': { code: 'Period', keyCode: 190 },
        '!': { code: 'Digit1', keyCode: 49, shiftKey: true },
        '?': { code: 'Slash', keyCode: 191, shiftKey: true },
        ':': { code: 'Semicolon', keyCode: 186, shiftKey: true },
        ';': { code: 'Semicolon', keyCode: 186 },
        '-': { code: 'Minus', keyCode: 189 },
        '(': { code: 'Digit9', keyCode: 57, shiftKey: true },
        ')': { code: 'Digit0', keyCode: 48, shiftKey: true }
    };
    
    if (specialChars[char]) {
        code = specialChars[char].code;
        shiftKey = specialChars[char].shiftKey || false;
    } else if (/[a-z]/.test(char)) {
        code = `Key${char.toUpperCase()}`;
        shiftKey = false;
    } else if (/[A-Z]/.test(char)) {
        code = `Key${char}`;
        shiftKey = true;
    } else if (/[0-9]/.test(char)) {
        code = `Digit${char}`;
        shiftKey = false;
    }
    
    const opts = {
        key: char,
        code: code,
        keyCode: keyCode,
        which: keyCode,
        shiftKey: shiftKey,
        bubbles: true,
        cancelable: true,
        view: window
    };
    
    field.dispatchEvent(new KeyboardEvent('keydown', opts));
    field.dispatchEvent(new KeyboardEvent('keypress', opts));
    field.value += char;
    field.dispatchEvent(new Event('input', { bubbles: true }));
    field.dispatchEvent(new Event('change', { bubbles: true }));
    field.dispatchEvent(new KeyboardEvent('keyup', opts));
}

async function processLevel() {
    if (!botRunning) return;
    
    const level = detectLevel();
    
    if (!level.text && level.type !== 'game') {
        status.textContent = 'โš ๏ธ No text or game found';
        console.log('โŒ Could not find text or game');
        stopBot();
        return;
    }
    
    // Handle games
    if (level.type === 'game') {
        console.log('๐ŸŽฎ Game detected, auto-playing...');
        status.textContent = '๐ŸŽฎ Playing game...';
        
        // Wait for game to load
        await new Promise(r => setTimeout(r, 2000));
        
        // Spam keys that games commonly use
        const gameKeys = ['Space', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Enter', 'KeyW', 'KeyA', 'KeyS', 'KeyD'];
        
        for (let i = 0; i < 50; i++) {
            if (!botRunning) return;
            
            // Press random game key
            const randomKey = gameKeys[Math.floor(Math.random() * gameKeys.length)];
            const keyOpts = {
                key: randomKey.includes('Arrow') || randomKey.includes('Space') ? randomKey.replace('Arrow', '').replace('Key', '') : randomKey.replace('Key', '').toLowerCase(),
                code: randomKey,
                keyCode: randomKey === 'Space' ? 32 : randomKey.includes('Arrow') ? (randomKey === 'ArrowUp' ? 38 : randomKey === 'ArrowDown' ? 40 : randomKey === 'ArrowLeft' ? 37 : 39) : randomKey.charCodeAt(3),
                bubbles: true,
                cancelable: true,
                view: window
            };
            
            document.dispatchEvent(new KeyboardEvent('keydown', keyOpts));
            document.dispatchEvent(new KeyboardEvent('keyup', keyOpts));
            
            // Also click randomly on screen
            if (i % 5 === 0) {
                const x = Math.random() * window.innerWidth;
                const y = Math.random() * window.innerHeight;
                const el = document.elementFromPoint(x, y);
                if (el && !el.closest('#typing-bot-gui')) {
                    el.click();
                }
            }
            
            await new Promise(r => setTimeout(r, 100));
        }
        
        console.log('๐ŸŽฎ Game sequence complete');
        status.textContent = 'โœ… Game complete!';
        
        if (autoAdvance.checked) {
            await new Promise(r => setTimeout(r, 6000));
            
            // Click to advance
            document.body.click();
            const clickables = document.querySelectorAll('button, .btn, [role="button"]');
            clickables.forEach(el => {
                if (el.offsetParent !== null && !el.closest('#typing-bot-gui')) {
                    el.click();
                }
            });
            
            await new Promise(r => setTimeout(r, 1000));
            if (botRunning) processLevel();
        } else {
            stopBot();
        }
        return;
    }
    
    // Handle typing (existing code)
    const text = level.text;
    console.log('๐Ÿ“ Text:', text);
    status.textContent = '๐Ÿ‘† Starting lesson...';
    
    // Try multiple ways to trigger the lesson
    // Method 1: Click the typing area
    const typingArea = document.querySelector('.tpmodes, .typable, .inview');
    if (typingArea) {
        console.log('Clicking typing area...');
        typingArea.click();
    }
    
    // Method 2: Click anywhere on body
    document.body.click();
    
    // Method 3: Press a key to trigger
    document.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', keyCode: 32, bubbles: true }));
    
    await new Promise(r => setTimeout(r, 500));
    
    // Find the input field (might take a moment to appear)
    let input = null;
    for (let attempt = 0; attempt < 30; attempt++) {
        const allInputs = document.querySelectorAll('input[type="text"]');
        console.log(`Attempt ${attempt}: Found ${allInputs.length} inputs`);
        
        for (const inp of allInputs) {
            console.log('  Input:', {
                visible: inp.offsetParent !== null,
                ariaHidden: inp.getAttribute('aria-hidden'),
                style: inp.style.cssText
            });
            
            // Accept ANY text input, even if hidden or aria-hidden
            if (inp.type === 'text') {
                input = inp;
                console.log('โœ… Using this input!');
                break;
            }
        }
        
        if (input) break;
        await new Promise(r => setTimeout(r, 100));
    }
    
    if (!input) {
        status.textContent = 'โš ๏ธ Input not found';
        console.log('โŒ No input field found at all');
        stopBot();
        return;
    }
    
    console.log('๐Ÿš€ Typing...');
    input.value = '';
    input.focus();
    await new Promise(r => setTimeout(r, 100));
    
    const wpm = parseInt(speedSlider.value);
    const accuracy = parseInt(accuracySlider.value);
    const baseDelay = 60000 / (wpm * 5);
    
    status.textContent = `โŒจ๏ธ Typing...`;
    
    for (let i = 0; i < text.length; i++) {
        if (!botRunning) return;
        
        const char = text[i];
        const shouldError = Math.random() * 100 > accuracy;
        
        if (shouldError && /[a-z]/i.test(char)) {
            const wrong = String.fromCharCode(char.charCodeAt(0) + (Math.random() > 0.5 ? 1 : -1));
            typeChar(wrong, input);
            await new Promise(r => setTimeout(r, baseDelay * 0.5));
            input.value = input.value.slice(0, -1);
            await new Promise(r => setTimeout(r, baseDelay * 0.3));
        }
        
        typeChar(char, input);
        
        charsTypedCount++;
        charsTypedEl.textContent = charsTypedCount;
        
        let delay = baseDelay * (0.8 + Math.random() * 0.4);
        if (['.', '!', '?'].includes(char)) delay *= 2;
        else if (char === ' ') delay *= 1.3;
        
        await new Promise(r => setTimeout(r, delay));
    }
    
    console.log('โœ… Complete!');
    levelsCompleted++;
    levelsCompletedEl.textContent = levelsCompleted;
    status.textContent = 'โœ… Complete! Waiting...';
    
    if (autoAdvance.checked) {
        // Wait 6 seconds for level to finish processing
        await new Promise(r => setTimeout(r, 6000));
        
        // ONE TIME: Spam Enter on everything
        console.log('Pressing Enter to advance...');
        const enterOpts = {
            key: 'Enter',
            code: 'Enter',
            keyCode: 13,
            which: 13,
            bubbles: true,
            cancelable: true,
            view: window
        };
        
        // Fire on document, input, and body
        document.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
        document.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
        document.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
        
        if (input) {
            input.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
            input.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
            input.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
        }
        
        document.body.dispatchEvent(new KeyboardEvent('keydown', enterOpts));
        document.body.dispatchEvent(new KeyboardEvent('keypress', enterOpts));
        document.body.dispatchEvent(new KeyboardEvent('keyup', enterOpts));
        
        // ONE TIME: Click everything
        console.log('Clicking to advance...');
        document.body.click();
        
        // Click center of screen
        const centerX = window.innerWidth / 2;
        const centerY = window.innerHeight / 2;
        const centerEl = document.elementFromPoint(centerX, centerY);
        if (centerEl && !centerEl.closest('#typing-bot-gui')) {
            centerEl.click();
        }
        
        // Click all buttons
        const clickables = document.querySelectorAll('button, .btn, [role="button"], div[onclick], a');
        clickables.forEach(el => {
            if (el.offsetParent !== null && !el.closest('#typing-bot-gui')) {
                el.click();
            }
        });
        
        // Wait then restart
        await new Promise(r => setTimeout(r, 1000));
        if (botRunning) processLevel();
    } else {
        stopBot();
    }
}

function startBot() {
    botRunning = true;
    startBtn.disabled = true;
    stopBtn.disabled = false;
    stopBtn.style.opacity = '1';
    console.log('๐Ÿค– Bot started');
    processLevel();
}

function stopBot() {
    botRunning = false;
    startBtn.disabled = false;
    stopBtn.disabled = true;
    stopBtn.style.opacity = '0.5';
    status.textContent = 'โน Stopped';
}

function closeBot() {
    stopBot();
    gui.remove();
    window.typingClubBot = null;
}

startBtn.addEventListener('click', startBot);
stopBtn.addEventListener('click', stopBot);
closeBtn.addEventListener('click', closeBtn);

window.typingClubBot = { start: startBot, stop: stopBot, close: closeBot };

setTimeout(detectLevel, 500);
console.log('โœ… Bot loaded! Just click Start Bot.');

})();

@zane2342
Copy link

zane2342 commented Dec 20, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment