Keyboard Wizard - Text Effects

Effect Color Trace Sound

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         Keyboard Wizard - Text Effects
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  Effect Color Trace Sound
// @author       Mustafa Hakan
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // Ayarlar
    const CFG = {
        effect: GM_getValue('kb_effect', 'fire'),
        hidePass: GM_getValue('kb_hidepass', true),
        sound: GM_getValue('kb_sound', true),
        trail: GM_getValue('kb_trail', true),
        particles: GM_getValue('kb_particles', true)
    };

    const EFFECTS = {
        fire: { name: '🔥 Ateş', color: '#ff4500', glow: '#ff8c00', trail: ['🔥','✨','💥'], sound: 'crackle' },
        ice: { name: '❄️ Buz', color: '#00d4ff', glow: '#87ceeb', trail: ['❄️','💎','✨'], sound: 'chime' },
        neon: { name: '💜 Neon', color: '#ff00ff', glow: '#ff69b4', trail: ['💜','💗','✨'], sound: 'buzz' },
        matrix: { name: '💚 Matrix', color: '#00ff41', glow: '#00cc33', trail: ['💚','⌨️','💻'], sound: 'type' },
        gold: { name: '👑 Altın', color: '#ffd700', glow: '#ffec8b', trail: ['👑','💰','✨'], sound: 'coin' },
        rainbow: { name: '🌈 Gökkuşağı', color: 'rainbow', glow: '#fff', trail: ['🌈','🎨','✨'], sound: 'magic' },
        shadow: { name: '🌑 Gölge', color: '#333', glow: '#000', trail: ['🌑','🖤','💨'], sound: 'whisper' },
        magic: { name: '🔮 Sihir', color: '#a855f7', glow: '#c084fc', trail: ['🔮','⭐','💫'], sound: 'sparkle' }
    };

    let activeEffect = EFFECTS[CFG.effect] || EFFECTS.fire;
    let audioCtx = null;
    let styleElement = null;

    // ---------- TEK STİL ETİKETİ ----------
    function updateStyles() {
        if (!styleElement) {
            styleElement = document.createElement('style');
            styleElement.id = 'kb-main-style';
            document.head.appendChild(styleElement);
        }
        const color = activeEffect.color === 'rainbow' ? '#fff' : activeEffect.color;
        const glow = activeEffect.glow;
        styleElement.textContent = `
            input:focus, textarea:focus, [contenteditable="true"]:focus {
                caret-color: ${color} !important;
                text-shadow: 0 0 5px ${glow} !important;
                transition: text-shadow 0.3s !important;
            }
            input[type="password"]:focus {
                letter-spacing: 3px !important;
                font-family: monospace !important;
            }
            ::selection {
                background: ${color}44 !important;
                color: ${color} !important;
            }
            ${activeEffect.color === 'rainbow' ? `
            .kb-rainbow-focus:focus {
                animation: kbRainbowText 2s linear infinite !important;
            }
            ` : ''}
            @keyframes kbSlideIn {
                from { opacity: 0; transform: translateX(20px); }
                to { opacity: 1; transform: translateX(0); }
            }
            @keyframes kbFloat {
                0%,100% { transform: translateY(0); }
                50% { transform: translateY(-6px); }
            }
            @keyframes kbRainbowText {
                0% { text-shadow: 0 0 5px #ff0000; }
                16% { text-shadow: 0 0 5px #ff7700; }
                33% { text-shadow: 0 0 5px #ffff00; }
                50% { text-shadow: 0 0 5px #00ff00; }
                66% { text-shadow: 0 0 5px #0077ff; }
                83% { text-shadow: 0 0 5px #8b00ff; }
                100% { text-shadow: 0 0 5px #ff0000; }
            }
        `;
    }

    // ---------- SES ----------
    function initAudio() {
        if (audioCtx) return;
        try {
            audioCtx = new (window.AudioContext || window.webkitAudioContext)();
            if (audioCtx.state === 'suspended') {
                const resume = () => {
                    audioCtx.resume();
                    document.removeEventListener('click', resume);
                    document.removeEventListener('keydown', resume);
                };
                document.addEventListener('click', resume);
                document.addEventListener('keydown', resume);
            }
        } catch(e) { /* sessizce başarısız */ }
    }

    function playSound(type) {
        if (!CFG.sound || !audioCtx || audioCtx.state !== 'running') return;
        try {
            const osc = audioCtx.createOscillator();
            const gain = audioCtx.createGain();
            gain.gain.setValueAtTime(0.02, audioCtx.currentTime);
            gain.gain.exponentialRampToValueAtTime(0.0001, audioCtx.currentTime + 0.1);
            switch(type) {
                case 'crackle': osc.type = 'sawtooth'; osc.frequency.setValueAtTime(100 + Math.random()*200, audioCtx.currentTime); break;
                case 'chime': osc.type = 'sine'; osc.frequency.setValueAtTime(800 + Math.random()*400, audioCtx.currentTime); break;
                case 'buzz': osc.type = 'square'; osc.frequency.setValueAtTime(60 + Math.random()*30, audioCtx.currentTime); break;
                case 'type': osc.type = 'triangle'; osc.frequency.setValueAtTime(300 + Math.random()*200, audioCtx.currentTime); break;
                case 'coin': osc.type = 'sine'; osc.frequency.setValueAtTime(1000 + Math.random()*500, audioCtx.currentTime); break;
                case 'magic': osc.type = 'sine'; osc.frequency.setValueAtTime(400 + Math.random()*600, audioCtx.currentTime); osc.frequency.linearRampToValueAtTime(1200, audioCtx.currentTime + 0.1); break;
                case 'sparkle': osc.type = 'triangle'; osc.frequency.setValueAtTime(1500 + Math.random()*1000, audioCtx.currentTime); break;
                case 'whisper': osc.type = 'sine'; osc.frequency.setValueAtTime(80 + Math.random()*40, audioCtx.currentTime); gain.gain.setValueAtTime(0.01, audioCtx.currentTime); break;
                default: osc.type = 'sine'; osc.frequency.setValueAtTime(500, audioCtx.currentTime);
            }
            osc.connect(gain);
            gain.connect(audioCtx.destination);
            osc.start();
            osc.stop(audioCtx.currentTime + 0.1);
        } catch(e) {}
    }

    // ---------- İZ VE PARÇACIK ----------
    function spawnTrail(x, y) {
        if (!CFG.trail) return;
        const emoji = activeEffect.trail[Math.floor(Math.random() * activeEffect.trail.length)];
        const el = document.createElement('span');
        el.textContent = emoji;
        Object.assign(el.style, {
            position: 'fixed', left: x+'px', top: y+'px', pointerEvents: 'none',
            zIndex: '2147483647', fontSize: (12 + Math.random()*16)+'px',
            opacity: '1', transition: 'all 0.8s ease-out'
        });
        document.body.appendChild(el);
        requestAnimationFrame(() => {
            el.style.transform = `translate(${(Math.random()-0.5)*60}px, ${-30-Math.random()*40}px) rotate(${(Math.random()-0.5)*40}deg)`;
            el.style.opacity = '0';
        });
        setTimeout(() => el.remove(), 800);
    }

    function spawnParticle(x, y) {
        if (!CFG.particles || activeEffect.color !== 'rainbow') return;
        const colors = ['#ff0000','#ff7700','#ffff00','#00ff00','#0077ff','#8b00ff'];
        const color = colors[Math.floor(Math.random() * colors.length)];
        const particle = document.createElement('div');
        Object.assign(particle.style, {
            position: 'fixed', left: x+'px', top: y+'px', pointerEvents: 'none',
            zIndex: '2147483646', width: '6px', height: '6px', background: color,
            borderRadius: '50%', boxShadow: `0 0 10px ${color}, 0 0 20px ${color}`,
            transition: 'all 0.6s ease-out'
        });
        document.body.appendChild(particle);
        requestAnimationFrame(() => {
            particle.style.transform = `translate(${(Math.random()-0.5)*80}px, -${20+Math.random()*40}px) scale(0)`;
            particle.style.opacity = '0';
        });
        setTimeout(() => particle.remove(), 600);
    }

    // ---------- İMLEÇ POZİSYONU ----------
    function getCursorPosition() {
        try {
            const sel = window.getSelection();
            if (sel && sel.rangeCount > 0) {
                const rect = sel.getRangeAt(0).getBoundingClientRect();
                if (rect) return { x: rect.right, y: rect.top };
            }
        } catch(e) {}
        return null;
    }

    // ---------- TUŞ OLAYI ----------
    function onKeyDown(e) {
        if (e.target.closest('#kb-panel')) return;
        if (CFG.hidePass && e.target.type === 'password') {
            e.target.style.fontFamily = 'monospace';
            e.target.style.letterSpacing = '2px';
            e.target.style.textShadow = `0 0 8px ${activeEffect.glow}`;
        }
        const pos = getCursorPosition();
        if (pos && e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey) {
            spawnTrail(pos.x, pos.y);
            if (CFG.sound) playSound(activeEffect.sound);
            spawnParticle(pos.x, pos.y);
        }
    }

    // ---------- PANEL VE BUTON (OLAY DELEGASYONU) ----------
    function createPanel() {
        if (document.getElementById('kb-panel')) return;

        const panel = document.createElement('div');
        panel.id = 'kb-panel';
        Object.assign(panel.style, {
            position: 'fixed', bottom: '100px', right: '30px', background: 'rgba(15,15,20,0.95)',
            border: `2px solid ${activeEffect.color}`, borderRadius: '16px', padding: '15px',
            zIndex: '2147483645', font: '13px system-ui', color: '#fff', minWidth: '220px',
            backdropFilter: 'blur(20px)', boxShadow: `0 15px 40px rgba(0,0,0,0.7), 0 0 20px ${activeEffect.glow}`,
            animation: 'kbSlideIn 0.3s ease-out'
        });

        // Başlık
        const title = document.createElement('div');
        title.textContent = '🧙 Klavye Büyücüsü';
        Object.assign(title.style, { fontWeight: '700', marginBottom: '10px', color: activeEffect.color });
        panel.appendChild(title);

        // Buton kabı (olay delegasyonu için)
        const btnContainer = document.createElement('div');
        btnContainer.style.cssText = 'display: flex; flex-direction: column; gap: 5px;';
        for (const [key, eff] of Object.entries(EFFECTS)) {
            const btn = document.createElement('button');
            btn.textContent = eff.name;
            btn.setAttribute('data-effect', key);
            Object.assign(btn.style, {
                padding: '10px', borderRadius: '10px', border: `1px solid ${CFG.effect === key ? eff.color : '#444'}`,
                background: CFG.effect === key ? eff.color+'22' : '#222', color: eff.color,
                cursor: 'pointer', transition: '0.2s', textAlign: 'left', font: '13px system-ui'
            });
            // Hover efektleri (döngü içinde ama sorunsuz)
            btn.addEventListener('mouseenter', () => { if (CFG.effect !== key) btn.style.background = '#333'; });
            btn.addEventListener('mouseleave', () => { if (CFG.effect !== key) btn.style.background = '#222'; });
            btnContainer.appendChild(btn);
        }
        panel.appendChild(btnContainer);

        // Olay delegasyonu: buton tıklamalarını yakala
        btnContainer.addEventListener('click', (e) => {
            const btn = e.target.closest('button[data-effect]');
            if (!btn) return;
            const newEffect = btn.dataset.effect;
            if (newEffect === CFG.effect) return;
            CFG.effect = newEffect;
            activeEffect = EFFECTS[newEffect];
            GM_setValue('kb_effect', newEffect);
            updateStyles();
            updateUI();
            panel.remove();
            createPanel(); // yeniden oluştur
        });

        // Ayarlar (checkbokslar)
        const opts = document.createElement('div');
        opts.style.cssText = 'margin-top: 10px; display: flex; flex-direction: column; gap: 6px; color: #aaa; font-size: 11px;';

        const createCheck = (label, cfgKey, storageKey) => {
            const labelEl = document.createElement('label');
            labelEl.style.cssText = 'display: flex; justify-content: space-between; align-items: center;';
            const input = document.createElement('input');
            input.type = 'checkbox';
            input.checked = CFG[cfgKey];
            input.addEventListener('change', (e) => {
                CFG[cfgKey] = e.target.checked;
                GM_setValue(storageKey, e.target.checked);
                if (storageKey === 'kb_sound' && e.target.checked && !audioCtx) initAudio();
            });
            labelEl.appendChild(document.createTextNode(label));
            labelEl.appendChild(input);
            return labelEl;
        };

        opts.appendChild(createCheck('🔒 Şifre Gizleme', 'hidePass', 'kb_hidepass'));
        opts.appendChild(createCheck('🔊 Ses Efekti', 'sound', 'kb_sound'));
        opts.appendChild(createCheck('✨ İz Efekti', 'trail', 'kb_trail'));
        opts.appendChild(createCheck('💫 Parçacık', 'particles', 'kb_particles'));
        panel.appendChild(opts);

        const closeBtn = document.createElement('button');
        closeBtn.textContent = 'Kapat';
        Object.assign(closeBtn.style, {
            marginTop: '10px', width: '100%', padding: '8px', borderRadius: '8px',
            border: '1px solid #444', background: '#222', color: '#888', cursor: 'pointer'
        });
        closeBtn.addEventListener('click', () => panel.remove());
        panel.appendChild(closeBtn);

        document.body.appendChild(panel);
    }

    // ---------- TETİKLEYİCİ DÜĞME ----------
    function createTrigger() {
        if (document.getElementById('kb-trigger')) return;
        const btn = document.createElement('div');
        btn.id = 'kb-trigger';
        btn.textContent = '🧙';
        Object.assign(btn.style, {
            position: 'fixed', bottom: '30px', right: '30px', width: '45px', height: '45px',
            background: activeEffect.color === 'rainbow' ? '#333' : activeEffect.color+'22',
            border: `2px solid ${activeEffect.color}`, borderRadius: '50%',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontSize: '22px', cursor: 'pointer', zIndex: '2147483644',
            boxShadow: `0 0 15px ${activeEffect.glow}`, transition: '0.3s',
            animation: 'kbFloat 3s ease-in-out infinite'
        });
        btn.addEventListener('click', () => {
            if (document.getElementById('kb-panel')) {
                document.getElementById('kb-panel').remove();
            } else {
                if (CFG.sound && !audioCtx) initAudio();
                createPanel();
            }
        });
        btn.addEventListener('mouseenter', () => { btn.style.transform = 'scale(1.15)'; });
        btn.addEventListener('mouseleave', () => { btn.style.transform = 'scale(1)'; });
        document.body.appendChild(btn);
    }

    // ---------- ARABİRİM GÜNCELLEME ----------
    function updateUI() {
        const trigger = document.getElementById('kb-trigger');
        if (trigger) {
            trigger.style.borderColor = activeEffect.color;
            trigger.style.boxShadow = `0 0 15px ${activeEffect.glow}`;
            trigger.style.background = activeEffect.color === 'rainbow' ? '#333' : activeEffect.color+'22';
        }
        const panel = document.getElementById('kb-panel');
        if (panel) {
            panel.style.borderColor = activeEffect.color;
            panel.style.boxShadow = `0 15px 40px rgba(0,0,0,0.7), 0 0 20px ${activeEffect.glow}`;
            const title = panel.querySelector('div:first-child');
            if (title) title.style.color = activeEffect.color;
            // Butonların border ve background güncellemesi (opsiyonel)
            const btns = panel.querySelectorAll('button[data-effect]');
            btns.forEach(btn => {
                const key = btn.dataset.effect;
                const eff = EFFECTS[key];
                if (key === CFG.effect) {
                    btn.style.border = `1px solid ${eff.color}`;
                    btn.style.background = eff.color+'22';
                } else {
                    btn.style.border = '1px solid #444';
                    btn.style.background = '#222';
                }
            });
        }
    }

    // ---------- GÖKKUŞAĞI ODAK YÖNETİMİ ----------
    function initRainbowFocus() {
        if (activeEffect.color !== 'rainbow') return;
        const addClass = (e) => {
            if (e.target.matches('input, textarea, [contenteditable="true"]')) {
                e.target.classList.add('kb-rainbow-focus');
            }
        };
        const removeClass = (e) => {
            if (e.target.matches('input, textarea, [contenteditable="true"]')) {
                e.target.classList.remove('kb-rainbow-focus');
            }
        };
        document.addEventListener('focusin', addClass);
        document.addEventListener('focusout', removeClass);
    }

    // ---------- BAŞLAT ----------
    function init() {
        updateStyles();
        createTrigger();
        document.addEventListener('keydown', onKeyDown);
        initRainbowFocus();
        if (CFG.sound) initAudio();
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => setTimeout(init, 500));
    } else {
        setTimeout(init, 500);
    }
})();