pandatype

Scripts for pandatype

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

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

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

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

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

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

Advertisement:

// ==UserScript==
// @name pandatype
// @namespace http://tampermonkey.net/
// @version 0.72
// @description Scripts for pandatype
// @author kryptonite
// @match https://pandatype.org/*
// @match https://www.pandatype.org/*
// @grant GM_addStyle
// @run-at document-start
// ==/UserScript==

(function() {
        'use strict';

        // 1. Base CSS Style Sheet
        const glassThemeCSS=`:root {
            --glass-bg: rgba(0, 0, 0, .18);
            --glass-border: rgba(255, 255, 255, .08);
            --glass-hover: rgba(255, 159, 47, .35);
            --glass-radius: 24px;
            --blur: 14px;
            --shadow: 0 10px 30px rgba(0, 0, 0, .35);
            --text: #fff;
        }

        html,
        body {
            overscroll-behavior: none;
        }

        body {
            color: var(--text);
            font: 20px "Trebuchet MS", sans-serif;
            text-align: center;
            overflow-x: hidden;
            background: center / cover fixed no-repeat;
            scrollbar-width: none;
            -ms-overflow-style: none;
        }

        body::-webkit-scrollbar {
            display: none;
        }

        a {
            color: inherit;
            text-decoration: none;
        }

        hr {
            margin: 48px;
            border: 0;
            border-top: 2px solid rgba(255, 255, 255, .15);
        }

        /* Glass Components */

        nav,
        .navbar,
        .blurrer {
            background: var(--glass-bg);
            border: 1px solid var(--glass-border);
            border-radius: var(--glass-radius);
            backdrop-filter: blur(var(--blur));
            -webkit-backdrop-filter: blur(var(--blur));
            box-shadow: var(--shadow);
            transition: .25s ease;
        }

        .fancy,
        nav a {
            display: inline-block;
            padding: 10px 14px;
            border-radius: 16px;
            cursor: pointer;
            transition: .2s ease;
        }

        .fancy:hover,
        nav a:hover {
            background: var(--glass-hover);
            text-shadow: 0 0 8px rgba(255, 255, 255, .4);
        }

        /* Background Panel */

        #bg-uploader-panel {
            position: fixed;
            bottom: 20px;
            left: 20px;
            z-index: 999999;
            display: flex;
            align-items: center;
            font: 13px sans-serif;
        }

        #bg-uploader-gear {
            width: 36px;
            height: 36px;
            display: grid;
            place-items: center;
            border-radius: 50%;
            cursor: pointer;
            background: rgba(0, 0, 0, .6);
            backdrop-filter: blur(10px);
            box-shadow: var(--shadow);
            transition: transform .3s;
        }

        #bg-uploader-panel:hover #bg-uploader-gear {
            transform: rotate(90deg);
        }

        #bg-uploader-menu {
            display: none;
            flex-direction: column;
            gap: 10px;
            width: 210px;
            margin-left: 10px;
            padding: 14px;
            border-radius: 16px;
            background: rgba(0, 0, 0, .8);
            border: 1px solid var(--glass-border);
            backdrop-filter: blur(var(--blur));
            box-shadow: var(--shadow);
        }

        #bg-uploader-panel:hover #bg-uploader-menu {
            display: flex;
        }

        body.pt-tape #passageBox {
            overflow: hidden !important;
            height: 100px !important;
        }

        body.pt-tape #passageInner {
            white-space: nowrap !important;
            display: inline-block !important;
            width: max-content !important;
            font-size: 27px !important;
            padding: 20px !important;
            will-change: transform;
        }

        body.pt-tape .ch {
            display: inline-block !important;
        }

        body.pt-tape .ch.space {
            width: .6em !important;
        }

        .bg-btn {
            padding: 7px;
            border: 0;
            border-radius: 8px;
            cursor: pointer;
            color: #fff;
            background: rgba(255, 255, 255, .15);
            transition: background .2s;
        }

        .bg-btn:hover {
            background: var(--glass-hover);
        }

        .discord-btn {
            display: block;
            background: rgba(88, 101, 242, .25);
            border: 1px dashed rgba(88, 101, 242, .45);
        }

        .discord-btn:hover {
            background: rgba(88, 101, 242, .5);
        }

        /* Toggle */

        .switch-container {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-top: 8px;
            padding-top: 8px;
            border-top: 1px solid rgba(255, 255, 255, .1);
        }

        .switch-label-block {
            display: flex;
            flex-direction: column;
        }

        .credits-tag {
            font-size: 9px;
            color: rgba(255, 255, 255, .5);
        }

        .toggle-switch {
            position: relative;
            width: 34px;
            height: 20px;
        }

        .toggle-switch input {
            display: none;
        }

        .slider {
            position: absolute;
            inset: 0;
            cursor: pointer;
            border-radius: 20px;
            background: rgba(255, 255, 255, .2);
            transition: .25s;
        }

        .slider::before {
            content: "";
            position: absolute;
            left: 3px;
            bottom: 3px;
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: #fff;
            transition: .25s;
        }

        input:checked + .slider {
            background: #ff9f2f;
        }

        input:checked + .slider::before {
            transform: translateX(14px);
        }

        `;

        if (typeof GM_addStyle !=='undefined') {
            GM_addStyle(glassThemeCSS);
        }

        else {
            const style=document.createElement('style');
            style.textContent=glassThemeCSS;
            document.head.appendChild(style);
        }

        // 2. Auto-Reloader Script Engine

        const DELAY_MS=0.369;

        let autoReloadEnabled=localStorage.getItem("pt_auto_reload") !=="false";

        let tapeModeEnabled=localStorage.getItem("pt_tape_mode") !=="false";

        let tapeRAF=0;
        let tapeOffset=0;
        let currentPassage="";
        let handledButton=null;

        let passageBox=null;
        let passageInner=null;
        let lastTransform="";

        function getPassageElements() {
            const box=document.getElementById("passageBox");
            const inner=document.getElementById("passageInner");

            if (box !==passageBox) {
                passageBox=box;
            }

            if (inner !==passageInner) {
                passageInner=inner;
            }
        }

        function setupPassage() {

            getPassageElements();

            if ( !passageInner) {
                return;
            }

            const text=passageInner.textContent;

            if (text===currentPassage) {
                return;
            }

            currentPassage=text;

            passageInner.querySelectorAll(".ch").forEach(ch=> {

                    if (ch.textContent===" " || ch.textContent==="") {

                        ch.classList.add("space");
                        ch.innerHTML=" ";

                    }

                });

        }

        function updateTape() {

            const box=document.getElementById("passageBox");
            const inner=document.getElementById("passageInner");
            const current=document.querySelector(".ch.current");

            if (!box || !inner || !current) return;

            const target=box.clientWidth * 0.48 -
                  current.offsetLeft -
                  current.clientWidth / 2;

            const delta = target - tapeOffset;

            if (Math.abs(delta) < 0.01) return;

            tapeOffset+=delta * 0.15;

            inner.style.transform=`translateX(${tapeOffset}px)`;
        }

        function tapeLoop() {
            if ( !tapeModeEnabled) {
                tapeRAF=0; return;
            }

            setupPassage();
            updateTape(); tapeRAF=requestAnimationFrame(tapeLoop);
        }

        function startTape() {
            getPassageElements(); document.body.classList.add("pt-tape");

            currentPassage=""; tapeOffset=0; lastTransform=""; setupPassage(); const current=document.querySelector(".ch.current"); if (passageBox && passageInner && current) {
                tapeOffset=passageBox.clientWidth * 0.42 - current.offsetLeft - current.clientWidth / 2; lastTransform=`translateX(${tapeOffset}px)`;
            passageInner.style.transform=lastTransform;
        }

        if ( !tapeRAF) {
            tapeLoop();
        }
    }

    function stopTape() {
        document.body.classList.remove("pt-tape"); cancelAnimationFrame(tapeRAF);

        tapeRAF=0; tapeOffset=0; currentPassage=""; lastTransform=""; if (passageInner) {
            passageInner.style.transform="";
        }
    }

    const observer=new MutationObserver(()=> {

            if ( !autoReloadEnabled) {
                return;
            }

            const btn=document.getElementById("raceAgainBtn");

            if (btn===handledButton) {
                return;
            }

            handledButton=btn;

            if ( !btn) {
                return;
            }

            requestAnimationFrame(()=> {

                    if (btn.isConnected && !btn.disabled) {
                        btn.click();
                    }

                });

        });

    // 3. Background State & Control Panel UI Injection
    function initThemeEngine() {
        const savedBg=localStorage.getItem('pt_custom_bg');

        if (savedBg) {
            document.body.style.backgroundImage=`url("${savedBg}")`;
        }

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

    if (tapeModeEnabled) {
        startTape();
    }

    if (document.getElementById('bg-uploader-panel')) return;

    const panel=document.createElement('div');
    panel.id='bg-uploader-panel';

    const gear=document.createElement('div');
    gear.id='bg-uploader-gear';

    gear.innerHTML=` <svg xmlns="http://www.w3.org/2000/svg"
    width="22"
    height="22"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    stroke-width="2"
    stroke-linecap="round"
    stroke-linejoin="round" > <circle cx="12" cy="12" r="3" /> <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0
 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9A1.65 1.65 0 0 0 10 3.09V3a2 2 0 1 1 4 0v.09A1.65 1.65 0 0 0 15 4.6h.08a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9v.08A1.65 1.65 0 0 0 20.91 10H21a2 2 0 1 1 0 4h-.09A1.65 1.65 0 0 0 19.4 15z"
 /> < /svg>`;

    const menu=document.createElement('div');
    menu.id='bg-uploader-menu';

    const label=document.createElement('span');
    label.style.fontWeight='bold';
    label.style.color='#ff9f2f';

    // File Uploader Elements (Images)
    const fileInput=document.createElement('input');
    fileInput.type='file';
    fileInput.accept='.png, .jpg, .jpeg';
    fileInput.style.display='none';

    const uploadBtn=document.createElement('button');
    uploadBtn.className='bg-btn';
    uploadBtn.textContent='📁 Upload Background';
    uploadBtn.onclick=()=> fileInput.click();

    // Remove Background button
    const resetBtn=document.createElement('button');
    resetBtn.className='bg-btn';
    resetBtn.style.background='rgba(239, 68, 68, 0.25)';
    resetBtn.textContent='❌ Remove Background';

    resetBtn.onclick=()=> {
        localStorage.removeItem('pt_custom_bg');
        document.body.style.backgroundImage='none';
    }

    ;

    // File loading pipeline logic
    const processFile=(file)=> {
        if ( !file) return;
        const reader=new FileReader();

        reader.onload=(event)=> {
            const base64Data=event.target.result;

            try {
                localStorage.setItem('pt_custom_bg', base64Data);
                document.body.style.backgroundImage=`url("${base64Data}")`;
            }

            catch (error) {
                alert("This file is too large for storage.");
            }
        }

        ;
        reader.readAsDataURL(file);
    }

    ;

    fileInput.onchange=(e)=> processFile(e.target.files[0]);

    // Auto Reloader Toggle Element
    const switchContainer=document.createElement('div');
    switchContainer.className='switch-container';

    const labelBlock=document.createElement('div');
    labelBlock.className='switch-label-block';

    const switchText=document.createElement('span');
    switchText.style.fontWeight='bold';
    switchText.style.color='#ffffff';
    switchText.textContent='Reloader';
    labelBlock.appendChild(switchText);

    const toggleLabel=document.createElement('label');
    toggleLabel.className='toggle-switch';

    const toggleInput=document.createElement('input');
    toggleInput.type='checkbox';
    toggleInput.checked=autoReloadEnabled;

    toggleInput.addEventListener('change', e=> {

            autoReloadEnabled=e.target.checked;

            localStorage.setItem('pt_auto_reload',
                String(autoReloadEnabled));

            console.log(`[PandaTree] Auto Reload $ {
                    autoReloadEnabled ? "Enabled" : "Disabled"
                }

                `);

        });

    const sliderSpan=document.createElement('span');
    sliderSpan.className='slider';

    toggleLabel.appendChild(toggleInput);
    toggleLabel.appendChild(sliderSpan);
    switchContainer.appendChild(labelBlock);
    switchContainer.appendChild(toggleLabel);

    // Assembly
    menu.appendChild(label);
    menu.appendChild(uploadBtn);
    menu.appendChild(resetBtn);
    menu.appendChild(switchContainer);

    // Tape Mode Toggle
    const tapeContainer=document.createElement('div');
    tapeContainer.className='switch-container';

    const tapeLabelBlock=document.createElement('div');
    tapeLabelBlock.className='switch-label-block';

    const tapeText=document.createElement('span');
    tapeText.style.fontWeight='bold';
    tapeText.style.color='#ffffff';
    tapeText.textContent='Tape Mode';

    tapeLabelBlock.appendChild(tapeText);

    const tapeToggleLabel=document.createElement('label');
    tapeToggleLabel.className='toggle-switch';

    const tapeToggleInput=document.createElement('input');
    tapeToggleInput.type='checkbox';
    tapeToggleInput.checked=tapeModeEnabled;

    tapeToggleInput.addEventListener("change", e=> {

            tapeModeEnabled=e.target.checked;

            localStorage.setItem("pt_tape_mode",
                tapeModeEnabled);

            if (tapeModeEnabled) {
                startTape();
            }

            else {
                stopTape();
            }

        });

    const tapeSlider=document.createElement('span');
    tapeSlider.className='slider';

    tapeToggleLabel.appendChild(tapeToggleInput);
    tapeToggleLabel.appendChild(tapeSlider);

    tapeContainer.appendChild(tapeLabelBlock);
    tapeContainer.appendChild(tapeToggleLabel);

    menu.appendChild(tapeContainer);

    panel.appendChild(gear);
    panel.appendChild(menu);

    document.body.appendChild(panel);
}

if (document.readyState==='loading') {
    document.addEventListener('DOMContentLoaded', initThemeEngine);
}

else {
    initThemeEngine();
}
})();