MonkeyType AutoTyper Bot

Combines the working V6.2 engine with V6.6 features and anti-cheat bypass.

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         MonkeyType AutoTyper Bot
// @namespace    https://greasyfork.org/users/1546585
// @version      6.9
// @description  Combines the working V6.2 engine with V6.6 features and anti-cheat bypass.
// @author       greedism
// @match        *://monkeytype.com/*
// @run-at       document-end
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    "use strict";

    class AutoTyper {
        constructor() {
            this.isTyping = false;
            this.timeoutId = null;
            this.isHidden = false;
            this.wpmHistory = [];
            this.stats = { charsTyped: 0, errors: 0, startTime: null };
            
            this.loadSettings();
            this.init();
        }

        loadSettings() {
            // grab saved stuff, or use defaults if first time
            const sWpm = localStorage.getItem('mt-bot-wpm');
            const sAcc = localStorage.getItem('mt-bot-acc');
            const sDelay = localStorage.getItem('mt-bot-delay');
            
            this.config = {
                accuracy: sAcc ? parseFloat(sAcc) : 0.97,
                wpm: sWpm ? parseInt(sWpm) : 80,
                startDelay: sDelay ? parseInt(sDelay) : 500,
                humanMode: true
            };
        }

        init() {
            this.createGUI();
            this.makeDraggable(document.getElementById('monkeytype-autotyper-gui'));
            console.log("MT-Bot: Engine V6.9 Ready.");
        }

        getNextCharacter() {
            const word = document.querySelector(".word.active");
            if (!word) return " ";
            // loop through letters to find the one without a status class
            const letters = word.children;
            for (let i = 0; i < letters.length; i++) {
                if (letters[i].className === "" || letters[i].classList.contains("letter")) {
                    return letters[i].textContent;
                }
            }
            return " ";
        }

        pressKey(k) {
            const input = document.getElementById("wordsInput");
            if (!input) return;

            const evInit = {
                key: k,
                code: k === " " ? "Space" : `Key${k.toUpperCase()}`,
                bubbles: true,
                cancelable: true,
                composed: true,
                which: k.charCodeAt(0),
                keyCode: k.charCodeAt(0)
            };

            input.dispatchEvent(new KeyboardEvent('keydown', evInit));
            
            // update the hidden input field so monkeytype sees it
            if (k !== " ") {
                input.value += k;
            } else {
                input.value = "";
            }

            input.dispatchEvent(new InputEvent('input', { 
                inputType: 'insertText', 
                data: k, 
                bubbles: true 
            }));
            
            input.dispatchEvent(new KeyboardEvent('keyup', evInit));
        }

        getHumanDelay(base, char) {
            const sd = base * 0.25;
            const u1 = Math.random();
            const u2 = Math.random();
            // normal distribution randomizer
            const z = Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2);
            let d = base + z * sd;

            // Speed up common bigrams - feels more like a real typist
            const common = ['th', 'he', 'in', 'er', 'an', 're', 'on', 'at', 'nd'];
            if (common.includes((this.lastChar || '') + char)) {
                d *= 0.62; 
            }

            // Random micro-pause (distraction/stumble simulation)
            if (Math.random() < 0.012) {
                d += (Math.random() * 250) + 150;
            }

            // Fatigue logic: slow down slightly as the test goes on
            const fatigue = 1 + (this.stats.charsTyped / 2200); 
            d *= fatigue;

            if (char === " ") d += (Math.random() * 140) + 45;

            this.lastChar = char;
            return Math.max(d, 24); 
        }

        typeCharacter() {
            if (!this.canType()) { this.stopTyping(); return; }
            
            const char = this.getNextCharacter();
            this.stats.charsTyped++;

            // Mistake Simulation
            if (Math.random() > this.config.accuracy) {
                this.stats.errors++;
                const chars = "abcdefghijklmnopqrstuvwxyz";
                const wrong = chars.charAt(Math.floor(Math.random() * chars.length));
                
                this.pressKey(wrong);
                
                // human-like reaction time to realize a mistake happened
                this.timeoutId = setTimeout(() => {
                    this.pressKey("Backspace");
                    this.timeoutId = setTimeout(() => this.typeCharacter(), this.getHumanDelay(115, char));
                }, 90 + Math.random() * 110);
                return;
            } else {
                this.pressKey(char);
            }

            let bDelay = (60000 / (this.config.wpm * 5));
            let finalD = this.config.humanMode ? this.getHumanDelay(bDelay, char) : bDelay;

            this.updateStats();
            this.timeoutId = setTimeout(() => this.typeCharacter(), finalD);
        }

        toggleTyping() {
            const btn = document.getElementById('mainStartBtn');
            if (!this.isTyping) {
                this.updateStatusText('Preparing...', '#e2b714');
                setTimeout(() => {
                    this.isTyping = true;
                    this.wpmHistory = [];
                    this.stats = { charsTyped: 0, errors: 0, startTime: Date.now() };
                    btn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><rect x="4" y="4" width="16" height="16" rx="2"></rect></svg> STOP`;
                    btn.style.color = "#ff4444";
                    this.typeCharacter();
                }, this.config.startDelay);
            } else {
                this.stopTyping();
            }
        }

        stopTyping() {
            this.isTyping = false;
            clearTimeout(this.timeoutId);
            const btn = document.getElementById('mainStartBtn');
            if (btn) {
                btn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg> START`;
                btn.style.color = "#fff";
            }
            this.updateStatusText('Ready', '#444');
        }

        updateStats() {
            const diff = (Date.now() - this.stats.startTime) / 1000;
            const wpm = Math.round((this.stats.charsTyped / 5) / (diff / 60)) || 0;
            document.getElementById('w-val').innerText = wpm;
            
            if (Math.floor(diff) > this.wpmHistory.length) {
                this.wpmHistory.push(wpm);
                if (this.wpmHistory.length > 25) this.wpmHistory.shift();
                this.drawGraph();
            }
            this.updateStatusText('<span class="pulse">●</span> Typing...', '#fff');
        }

        drawGraph() {
            const svg = document.getElementById('wpm-graph');
            if (!svg || this.wpmHistory.length < 2) return;
            const max = Math.max(...this.wpmHistory, 150);
            const pts = this.wpmHistory.map((w, i) => `${(i / (this.wpmHistory.length - 1)) * 240},${40 - (w / max) * 40}`).join(' ');
            svg.innerHTML = `<polyline points="${pts}" fill="none" stroke="#e2b714" stroke-width="2" stroke-linejoin="round" />`;
        }

        updateStatusText(t, c) { 
            const s = document.getElementById('status');
            if (s) { s.innerHTML = t; s.style.color = c; }
        }

        canType() { return !!document.querySelector('.word.active'); }

        makeDraggable(el) {
            let p1 = 0, p2 = 0, p3 = 0, p4 = 0;
            const h = document.getElementById('gui-header');
            h.onmousedown = (e) => {
                if (e.target.tagName === 'BUTTON' || e.target.tagName === 'INPUT') return;
                p3 = e.clientX; p4 = e.clientY;
                document.onmouseup = () => { document.onmouseup = null; document.onmousemove = null; };
                document.onmousemove = (ev) => {
                    p1 = p3 - ev.clientX; p2 = p4 - ev.clientY;
                    p3 = ev.clientX; p4 = ev.clientY;
                    el.style.top = (el.offsetTop - p2) + "px"; 
                    el.style.left = (el.offsetLeft - p1) + "px";
                    el.style.bottom = "auto"; el.style.right = "auto";
                };
            };
        }

        createGUI() {
            const gui = document.createElement('div');
            gui.id = 'monkeytype-autotyper-gui';
            gui.style.cssText = `position:fixed;top:100px;right:20px;width:280px;background:rgba(10,10,10,0.98);border:1px solid #222;border-radius:12px;color:#fff;font-family:'Lexend Deca',sans-serif;z-index:100000;backdrop-filter:blur(10px);box-shadow:0 10px 40px #000;`;

            gui.innerHTML = `
                <div id="gui-header" style="padding:12px;background:#111;border-radius:12px 12px 0 0;cursor:move;display:flex;justify-content:space-between;border-bottom:1px solid #222;font-size:11px;color:#e2b714;font-weight:bold;align-items:center;">
                    <span>MONKEY BOT STEALTH V6.9</span>
                    <button id="hideBtn" style="background:none;border:none;color:#444;cursor:pointer;font-size:9px;">HIDE</button>
                </div>
                <div style="padding:15px;">
                    <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:15px;">
                        <div class="stat-card">WPM <b id="w-val">0</b></div>
                        <div class="stat-card">ACC <b id="a-val">${Math.round(this.config.accuracy*100)}%</b></div>
                    </div>
                    
                    <div class="ctrl">
                        <label>Target WPM: <span id="v-wpm">${this.config.wpm}</span></label>
                        <input type="range" id="s-wpm" min="10" max="350" value="${this.config.wpm}">
                    </div>

                    <div class="ctrl">
                        <label>Start Delay:</label>
                        <div style="display:flex;gap:5px;margin-top:5px;">
                            <button class="d-btn ${this.config.startDelay === 0 ? 'active' : ''}" data-ms="0">Instant</button>
                            <button class="d-btn ${this.config.startDelay === 500 ? 'active' : ''}" data-ms="500">Normal</button>
                            <button class="d-btn ${this.config.startDelay === 2000 ? 'active' : ''}" data-ms="2000">Slow</button>
                        </div>
                    </div>

                    <button id="mainStartBtn"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg> START</button>
                    
                    <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px;">
                        <button id="exportBtn" class="sec-btn">EXPORT</button>
                        <button id="importBtn" class="sec-btn">IMPORT</button>
                    </div>

                    <div style="background:#000; border: 1px solid #111; border-radius: 8px; height: 40px; margin-top: 15px; position:relative; overflow:hidden;">
                        <svg id="wpm-graph" width="240" height="40" style="position:absolute;left:5px;"></svg>
                    </div>

                    <div id="status" style="text-align:center;font-size:10px;color:#444;margin-top:10px;">Ready</div>
                </div>
                <style>
                    .stat-card { background:#000; padding:10px; border-radius:8px; border:1px solid #1a1a1a; text-align:center; font-size:10px; color:#555; }
                    .stat-card b { display:block; font-size:16px; color:#fff; }
                    .ctrl { margin-bottom:12px; }
                    .ctrl label { font-size:10px; color:#888; display:flex; justify-content:space-between; }
                    .ctrl label span { color:#e2b714; }
                    input[type=range] { width:100%; accent-color:#e2b714; }
                    #mainStartBtn { width:100%; background:#111; color:#fff; border:1px solid #333; padding:10px; border-radius:8px; font-weight:bold; cursor:pointer; display:flex; align-items:center; justify-content:center; gap:8px; }
                    .sec-btn { background:#080808; border:1px solid #222; color:#666; padding:6px; border-radius:6px; cursor:pointer; font-size:9px; font-weight:bold; }
                    .d-btn { flex:1; background:#111; border:1px solid #222; color:#555; font-size:9px; padding:6px; border-radius:4px; cursor:pointer; }
                    .d-btn.active { border-color:#e2b714; color:#fff; }
                    .pulse { color:#ff4444; animation: blink 1s infinite; }
                    @keyframes blink { 50% { opacity: 0; } }
                </style>
            `;

            const tab = document.createElement('div');
            tab.id = 'mt-restore-tab'; 
            tab.innerHTML = 'BOT';
            tab.style.cssText = `position:fixed;top:50%;right:0;transform:translateY(-50%);background:#e2b714;color:#000;padding:15px 8px;border-radius:10px 0 0 10px;cursor:pointer;font-size:10px;font-weight:900;writing-mode:vertical-rl;display:none;z-index:100000;`;

            document.body.appendChild(gui);
            document.body.appendChild(tab);

            // Click handlers
            document.getElementById('mainStartBtn').onclick = () => this.toggleTyping();
            document.getElementById('hideBtn').onclick = () => { gui.style.display='none'; tab.style.display='flex'; };
            tab.onclick = () => { gui.style.display='block'; tab.style.display='none'; };
            document.getElementById('exportBtn').onclick = () => this.exportConfig();
            document.getElementById('importBtn').onclick = () => this.importConfig();
            
            document.getElementById('s-wpm').oninput = (e) => {
                this.config.wpm = e.target.value;
                document.getElementById('v-wpm').innerText = e.target.value;
                localStorage.setItem('mt-bot-wpm', e.target.value);
            };

            document.querySelectorAll('.d-btn').forEach(btn => {
                btn.onclick = () => {
                    this.config.startDelay = parseInt(btn.dataset.ms);
                    document.querySelectorAll('.d-btn').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    localStorage.setItem('mt-bot-delay', btn.dataset.ms);
                };
            });
        }

        exportConfig() {
            const data = JSON.stringify({ wpm: this.config.wpm, acc: this.config.accuracy });
            navigator.clipboard.writeText(data).then(() => {
                this.updateStatusText('Copied!', '#e2b714');
            });
        }

        importConfig() {
            const raw = prompt("Paste JSON Config:");
            if (raw) {
                try {
                    const parsed = JSON.parse(raw);
                    this.config.wpm = parsed.wpm; 
                    this.config.accuracy = parsed.acc;
                    localStorage.setItem('mt-bot-wpm', parsed.wpm); 
                    localStorage.setItem('mt-bot-acc', parsed.acc);
                    location.reload();
                } catch(e) { alert("Invalid JSON!"); }
            }
        }
    }

    // Startup
    new AutoTyper();
})();